MediaWiki:DonationForm.js: Difference between revisions

From Donate
Jump to navigation Jump to search
Content deleted Content added
just hide the errors when amount is changed
rm base64 decoding, being done in Civi now - phab:T381931
Tag: Undo
 
(8 intermediate revisions by the same user not shown)
Line 11: Line 11:
donationForm.country = mw.util.getParamValue('country').toUpperCase();
donationForm.country = mw.util.getParamValue('country').toUpperCase();
try {
try {
donationForm.currency = document.forms.donateForm.currency_code.value;
donationForm.currency = document.forms.donateForm.currency_code.value;
} catch (error) {
} catch (error) {
donationForm.currency = 'USD';
donationForm.currency = 'USD';
}
}


Line 32: Line 32:
// We don't want these for a javascript locale, so drop anything after '-'
// We don't want these for a javascript locale, so drop anything after '-'
language = language.split('-')[0];
language = language.split('-')[0];

return language + '-' + country;
return language + '-' + country;
};
};


Line 45: Line 45:


donationForm.currencyRates = {
donationForm.currencyRates = {
// From https://github.com/wikimedia/wikimedia-fundraising-SmashPig/blob/master/PaymentData/ReferenceData/CurrencyRates.php
// From https://github.com/wikimedia/wikimedia-fundraising-SmashPig/blob/master/PaymentData/ReferenceData/CurrencyRates.php
// Updated 2024-07-31
// Updated 2024-07-31
'ADF' : 6.04,
'ADF' : 6.04,
'ADP' : 153,
'ADP' : 153,
'AED' : 3.67,
'AED' : 3.67,
'AFA' : 70,
'AFA' : 70,
'AFN' : 70,
'AFN' : 70,
'ALL' : 90,
'ALL' : 90,
'AMD' : 368,
'AMD' : 368,
'ANG' : 1.79,
'ANG' : 1.79,
'AOA' : 844,
'AOA' : 844,
'AON' : 844,
'AON' : 844,
'ARS' : 887,
'ARS' : 887,
'ATS' : 13,
'ATS' : 13,
'AUD' : 1.5,
'AUD' : 1.5,
'AWG' : 1.79,
'AWG' : 1.79,
'AZM' : 8500,
'AZM' : 8500,
'AZN' : 1.7,
'AZN' : 1.7,
'BAM' : 1.8,
'BAM' : 1.8,
'BBD' : 2,
'BBD' : 2,
'BDT' : 116,
'BDT' : 116,
'BEF' : 37,
'BEF' : 37,
'BGL' : 1.8,
'BGL' : 1.8,
'BGN' : 1.8,
'BGN' : 1.8,
'BHD' : 0.37355757356689,
'BHD' : 0.37355757356689,
'BIF' : 2842,
'BIF' : 2842,
'BMD' : 1,
'BMD' : 1,
'BND' : 1.35,
'BND' : 1.35,
'BOB' : 6.71,
'BOB' : 6.71,
'BRL' : 5.1,
'BRL' : 5.1,
'BSD' : 1,
'BSD' : 1,
'BTN' : 83,
'BTN' : 83,
'BWP' : 13,
'BWP' : 13,
'BYR' : 32642,
'BYR' : 32642,
'BZD' : 1.98,
'BZD' : 1.98,
'CAD' : 1.36,
'CAD' : 1.36,
'CDF' : 2786,
'CDF' : 2786,
'CHF' : 0.9094629289448,
'CHF' : 0.9094629289448,
'CLP' : 890,
'CLP' : 890,
'CNY' : 7.23,
'CNY' : 7.23,
'COP' : 3803,
'COP' : 3803,
'CRC' : 498,
'CRC' : 498,
'CUC' : 1,
'CUC' : 1,
'CUP' : 25,
'CUP' : 25,
'CVE' : 101,
'CVE' : 101,
'CYP' : 0.53848627984321,
'CYP' : 0.53848627984321,
'CZK' : 23,
'CZK' : 23,
'DEM' : 1.8,
'DEM' : 1.8,
'DJF' : 178,
'DJF' : 178,
'DKK' : 6.86,
'DKK' : 6.86,
'DOP' : 58,
'DOP' : 58,
'DZD' : 133,
'DZD' : 133,
'ECS' : 24094,
'ECS' : 24094,
'EEK' : 14,
'EEK' : 14,
'EGP' : 47,
'EGP' : 47,
'ESP' : 153,
'ESP' : 153,
'ETB' : 57,
'ETB' : 57,
'EUR' : 0.92005843390143,
'EUR' : 0.92005843390143,
'FIM' : 5.47,
'FIM' : 5.47,
'FJD' : 2.23,
'FJD' : 2.23,
'FKP' : 0.78703952551207,
'FKP' : 0.78703952551207,
'FRF' : 6.04,
'FRF' : 6.04,
'GBP' : 0.78703952551207,
'GBP' : 0.78703952551207,
'GEL' : 2.71,
'GEL' : 2.71,
'GHC' : 143125,
'GHC' : 143125,
'GHS' : 14,
'GHS' : 14,
'GIP' : 0.78703952551207,
'GIP' : 0.78703952551207,
'GMD' : 68,
'GMD' : 68,
'GNF' : 8493,
'GNF' : 8493,
'GRD' : 314,
'GRD' : 314,
'GTQ' : 7.57,
'GTQ' : 7.57,
'GYD' : 200,
'GYD' : 200,
'HKD' : 7.8,
'HKD' : 7.8,
'HNL' : 24,
'HNL' : 24,
'HRK' : 6.93,
'HRK' : 6.93,
'HTG' : 132,
'HTG' : 132,
'HUF' : 355,
'HUF' : 355,
'IDR' : 15986,
'IDR' : 15986,
'IEP' : 0.72460490043714,
'IEP' : 0.72460490043714,
'ILS' : 3.69,
'ILS' : 3.69,
'INR' : 83,
'INR' : 83,
'IQD' : 1290,
'IQD' : 1290,
'IRR' : 42009,
'IRR' : 42009,
'ISK' : 138,
'ISK' : 138,
'ITL' : 1781,
'ITL' : 1781,
'JMD' : 154,
'JMD' : 154,
'JOD' : 0.70900000000001,
'JOD' : 0.70900000000001,
'JPY' : 156,
'JPY' : 156,
'KES' : 130,
'KES' : 130,
'KGS' : 88,
'KGS' : 88,
'KHR' : 3993,
'KHR' : 3993,
'KMF' : 453,
'KMF' : 453,
'KPW' : 135,
'KPW' : 135,
'KRW' : 1358,
'KRW' : 1358,
'KWD' : 0.30629670764681,
'KWD' : 0.30629670764681,
'KYD' : 0.83333299999999,
'KYD' : 0.83333299999999,
'KZT' : 442,
'KZT' : 442,
'LAK' : 21103,
'LAK' : 21103,
'LBP' : 89393,
'LBP' : 89393,
'LKR' : 298,
'LKR' : 298,
'LRD' : 193,
'LRD' : 193,
'LSL' : 18,
'LSL' : 18,
'LTL' : 3.18,
'LTL' : 3.18,
'LUF' : 37,
'LUF' : 37,
'LVL' : 0.64662074757963,
'LVL' : 0.64662074757963,
'LYD' : 4.8,
'LYD' : 4.8,
'MAD' : 9.79,
'MAD' : 9.79,
'MDL' : 17,
'MDL' : 17,
'MGA' : 4379,
'MGA' : 4379,
'MGF' : 9150,
'MGF' : 9150,
'MKD' : 56,
'MKD' : 56,
'MMK' : 2075,
'MMK' : 2075,
'MNT' : 2620,
'MNT' : 2620,
'MOP' : 8.03,
'MOP' : 8.03,
'MRO' : 391,
'MRO' : 391,
'MTL' : 0.39498108567387,
'MTL' : 0.39498108567387,
'MUR' : 45,
'MUR' : 45,
'MVR' : 15,
'MVR' : 15,
'MWK' : 1720,
'MWK' : 1720,
'MXN' : 17,
'MXN' : 17,
'MYR' : 4.68,
'MYR' : 4.68,
'MZM' : 63200,
'MZM' : 63200,
'MZN' : 63,
'MZN' : 63,
'NAD' : 18,
'NAD' : 18,
'NGN' : 1505,
'NGN' : 1505,
'NIO' : 36,
'NIO' : 36,
'NLG' : 2.03,
'NLG' : 2.03,
'NOK' : 11,
'NOK' : 11,
'NPR' : 131,
'NPR' : 131,
'NZD' : 1.63,
'NZD' : 1.63,
'OMR' : 0.38377594841305,
'OMR' : 0.38377594841305,
'PAB' : 1,
'PAB' : 1,
'PEN' : 3.67,
'PEN' : 3.67,
'PGK' : 3.76,
'PGK' : 3.76,
'PHP' : 58,
'PHP' : 58,
'PKR' : 277,
'PKR' : 277,
'PLN' : 3.91,
'PLN' : 3.91,
'PTE' : 184,
'PTE' : 184,
'PYG' : 7355,
'PYG' : 7355,
'QAR' : 3.56,
'QAR' : 3.56,
'ROL' : 45713,
'ROL' : 45713,
'RON' : 4.57,
'RON' : 4.57,
'RSD' : 108,
'RSD' : 108,
'RUB' : 91,
'RUB' : 91,
'RWF' : 1277,
'RWF' : 1277,
'SAR' : 3.75,
'SAR' : 3.75,
'SBD' : 8.37,
'SBD' : 8.37,
'SCR' : 13,
'SCR' : 13,
'SDD' : 59800,
'SDD' : 59800,
'SDG' : 598,
'SDG' : 598,
'SDP' : 2261,
'SDP' : 2261,
'SEK' : 11,
'SEK' : 11,
'SGD' : 1.35,
'SGD' : 1.35,
'SHP' : 0.78703952551207,
'SHP' : 0.78703952551207,
'SIT' : 220,
'SIT' : 220,
'SKK' : 28,
'SKK' : 28,
'SLL' : 19750,
'SLL' : 19750,
'SOS' : 549,
'SOS' : 549,
'SRD' : 33,
'SRD' : 33,
'SRG' : 33320,
'SRG' : 33320,
'STD' : 22477,
'STD' : 22477,
'SVC' : 8.75,
'SVC' : 8.75,
'SYP' : 513,
'SYP' : 513,
'SZL' : 18,
'SZL' : 18,
'THB' : 36,
'THB' : 36,
'TJS' : 11,
'TJS' : 11,
'TMM' : 16750,
'TMM' : 16750,
'TMT' : 3.35,
'TMT' : 3.35,
'TND' : 3.11,
'TND' : 3.11,
'TOP' : 2.32,
'TOP' : 2.32,
'TRL' : 32168418,
'TRL' : 32168418,
'TRY' : 32,
'TRY' : 32,
'TTD' : 6.64,
'TTD' : 6.64,
'TWD' : 32,
'TWD' : 32,
'TZS' : 2587,
'TZS' : 2587,
'UAH' : 39,
'UAH' : 39,
'UGX' : 3760,
'UGX' : 3760,
'USD' : 1,
'USD' : 1,
'UYU' : 38,
'UYU' : 38,
'UZS' : 12662,
'UZS' : 12662,
'VEB' : 3651907631,
'VEB' : 3651907631,
'VEF' : 3651908,
'VEF' : 3651908,
'VND' : 25451,
'VND' : 25451,
'VUV' : 112,
'VUV' : 112,
'WST' : 2.67,
'WST' : 2.67,
'XAF' : 604,
'XAF' : 604,
'XAG' : 0.031347411860134,
'XAG' : 0.031347411860134,
'XAU' : 0.00041128929241299,
'XAU' : 0.00041128929241299,
'XCD' : 2.7,
'XCD' : 2.7,
'XEU' : 0.92005843390143,
'XEU' : 0.92005843390143,
'XOF' : 604,
'XOF' : 604,
'XPD' : 0.00098009826645798,
'XPD' : 0.00098009826645798,
'XPF' : 110,
'XPF' : 110,
'XPT' : 0.00093444018680404,
'XPT' : 0.00093444018680404,
'YER' : 249,
'YER' : 249,
'YUN' : 108,
'YUN' : 108,
'ZAR' : 18,
'ZAR' : 18,
'ZMK' : 5176,
'ZMK' : 5176,
'ZWD' : 373
'ZWD' : 373
};
};


/* Amount and currency formatting */
/* Amount and currency formatting */
let formatters = {
let formatters = {
// Amounts without currency symbol
// Amounts without currency symbol
amountFraction: new Intl.NumberFormat( donationForm.locale,
amountFraction: new Intl.NumberFormat( donationForm.locale,
{ minimumFractionDigits: 2, maximumFractionDigits: 2 }
{ minimumFractionDigits: 2, maximumFractionDigits: 2 }
),
),
amountWhole: new Intl.NumberFormat( donationForm.locale,
amountWhole: new Intl.NumberFormat( donationForm.locale,
{}
{}
)
)
}
};


// currencyDisplay: 'narrowSymbol' fixes some issues like en-CO showing the ISO code
// currencyDisplay: 'narrowSymbol' fixes some issues like en-CO showing the ISO code
// but browser support is lacking, so wrap in a try/catch
// but browser support is lacking, so wrap in a try/catch
try {
try {
formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale,
formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale,
{ style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol' }
{ style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol' }
);
);
formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale,
formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale,
{ style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol', minimumFractionDigits: 0 }
{ style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol', minimumFractionDigits: 0 }
);
);
} catch(e) {
} catch(e) {
formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale,
formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale,
{ style: 'currency', currency: donationForm.currency }
{ style: 'currency', currency: donationForm.currency }
);
);
formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale,
formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale,
{ style: 'currency', currency: donationForm.currency, minimumFractionDigits: 0 }
{ style: 'currency', currency: donationForm.currency, minimumFractionDigits: 0 }
);
);
}
}


donationForm.formatCurrency = function( amount ) {
donationForm.formatCurrency = function( amount ) {
if ( amount % 1 !== 0 ) { // Not a whole number
if ( amount % 1 !== 0 ) { // Not a whole number
return formatters.currencyFraction.format( amount );
return formatters.currencyFraction.format( amount );
} else {
} else {
return formatters.currencyWhole.format( amount );
return formatters.currencyWhole.format( amount );
}
}
};
};


donationForm.formatAmount = function( amount ) {
donationForm.formatAmount = function( amount ) {
var formatterOptions, output;
var formatterOptions, output;
if ( amount % 1 !== 0 ) { // Not a whole number
if ( amount % 1 !== 0 ) { // Not a whole number
return formatters.amountFraction.format( amount );
return formatters.amountFraction.format( amount );
} else {
} else {
return formatters.amountWhole.format( amount );
return formatters.amountWhole.format( amount );
}
}
};
};


/* Localize the amount errors. Call when initialising form. */
/* Localize the amount errors. Call when initialising form. */
donationForm.localizeErrors = function() {
donationForm.localizeErrors = function() {
var currency = donationForm.currency;
var currency = donationForm.currency;


$('.lp-error-smallamount').text( function( index, oldText ) {
$('.lp-error-smallamount').text( function( index, oldText ) {
return oldText.replace( '$1', donationForm.formatAmount( donationForm.minLocal ) + '\xa0' + currency );
return oldText.replace( '$1', donationForm.formatAmount( donationForm.minLocal ) + '\xa0' + currency );
});
});


if ( currency === 'USD' ) {
if ( currency === 'USD' ) {
// we don't need to include the conversion
// we don't need to include the conversion
$('.lp-error-bigamount').text( function( index, oldText ) {
$('.lp-error-bigamount').text( function( index, oldText ) {
return oldText.replace( '($1 $2) ', '' )
return oldText.replace( '($1 $2) ', '' )
.replace( '($1 $2) ', '' );
.replace( '($1 $2) ', '' );
});
});
}
}


$('.lp-error-bigamount').text( function( index, oldText ) {
$('.lp-error-bigamount').text( function( index, oldText ) {
return oldText.replace( '$1', donationForm.formatAmount( donationForm.maxLocal ) )
return oldText.replace( '$1', donationForm.formatAmount( donationForm.maxLocal ) )
.replace( '$2', currency )
.replace( '$2', currency )
.replace( '$3', 'benefactors@wikimedia.org' )
.replace( '$3', 'benefactors@wikimedia.org' )
.replace( '$4', donationForm.formatAmount( donationForm.maxUSD ) );
.replace( '$4', donationForm.formatAmount( donationForm.maxUSD ) );
});
});
};
};




function adjustHPC() {
function adjustHPC() {
/* Adjust amounts based on highest previous contribution (hpc)
/* Adjust amounts based on highest previous contribution (hpc)
or most recent contribution (mrc) parameter. Used for emails.
or most recent contribution (mrc) parameter. Used for emails.
TODO: split data out? */
TODO: split data out? */


var hpcSet = mw.util.getParamValue('hpcSet');
var hpcSet = mw.util.getParamValue('hpcSet');


// Look for 'hpc' parameter, then 'mrc'
// Look for 'hpc' parameter, then 'mrc'
var hpc = parseFloat( mw.util.getParamValue('hpc') );
var hpc = parseFloat( mw.util.getParamValue('hpc') );
if( isNaN(hpc) ) {
if( isNaN(hpc) ) {
hpc = parseFloat( mw.util.getParamValue('mrc') );
hpc = parseFloat( mw.util.getParamValue('mrc') );
if( isNaN(hpc) ) {
if( isNaN(hpc) ) {
if ( hpcSet ) {
if ( hpcSet ) {
// Allow using hpcSet even without hpc, for MG appeals
// Allow using hpcSet even without hpc, for MG appeals
hpc = 0;
hpc = 0;
} else {
} else {
return;
return;
}
}
}
}
}
}


var currency = donationForm.currency;
var currency = donationForm.currency;


// If changing, please update https://docs.google.com/spreadsheets/d/1e02TsZ_bKDAS1BMVBCdyo9D7RGln_wCGnkg7IF5kU5s/edit
// If changing, please update https://docs.google.com/spreadsheets/d/1e02TsZ_bKDAS1BMVBCdyo9D7RGln_wCGnkg7IF5kU5s/edit
var radioAmountsData = {
var radioAmountsData = {
"USD" : { // also used for CAD, AUD, NZD
"USD" : { // also used for CAD, AUD, NZD
"default" : [
"default" : [
[ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ],
[ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
],
],
"FY2425_E1_T11_USD" : [ // Upgrade recurring +1 for lowest ask
"FY2425_E1_T11_USD" : [ // Upgrade recurring +1 for lowest ask
[ 0, [ 3.75, 5, 10, 20, 25, 35, 50 ] ],
[ 0, [ 3.75, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
],
],
"FY2425_E1_T14_USD" : [ // Upgrade recurring amount dynamically
"FY2425_E1_T14_USD" : [ // Upgrade recurring amount dynamically
[ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ],
[ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ],
[ 10, [ 2.75, 10, 15, 20, 25, 35, 50 ] ],
[ 10, [ 2.75, 10, 15, 20, 25, 35, 50 ] ],
[ 15, [ 3.50, 10, 20, 30, 50, 75, 100 ] ],
[ 15, [ 3.50, 10, 20, 30, 50, 75, 100 ] ],
[ 20, [ 3.75, 10, 25, 35, 50, 75, 100 ] ],
[ 20, [ 3.75, 10, 25, 35, 50, 75, 100 ] ],
[ 25, [ 4.50, 10, 25, 35, 50, 75, 100 ] ],
[ 25, [ 4.50, 10, 25, 35, 50, 75, 100 ] ],
[ 35, [ 6.75, 15, 30, 50, 75, 100, 150 ] ],
[ 35, [ 6.75, 15, 30, 50, 75, 100, 150 ] ],
[ 75, [ 15.75, 50, 75, 100, 200, 300, 500 ] ],
[ 75, [ 15.75, 50, 75, 100, 200, 300, 500 ] ],
[ 100, [ 24.75, 50, 75, 100, 200, 300, 500 ] ],
[ 100, [ 24.75, 50, 75, 100, 200, 300, 500 ] ],
[ 150, [ 44.75, 100, 150, 250, 500, 750, 1000 ] ],
[ 150, [ 44.75, 100, 150, 250, 500, 750, 1000 ] ],
[ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ],
[ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ],
[ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ],
[ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ],
[ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ],
[ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ],
[ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ]
[ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ]
],
],
"FY2425_E1_T21_USD" : [ // Give less reactivation amount
"FY2425_E1_T21_USD" : [ // Give less reactivation amount
[ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ],
[ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ],
[ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ]
[ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ]
],
],
// Direct Mail - fixed amounts
// Direct Mail - fixed amounts
"directmail" : [
"directmail" : [
[ 0, [ 25, 35, 50, 100, 150, 250, 300 ] ]
[ 0, [ 25, 35, 50, 100, 150, 250, 300 ] ]
],
],
"directmail250" : [
"directmail250" : [
[ 0, [ 250, 300, 500, 750, 1000, 2500, 5000 ] ]
[ 0, [ 250, 300, 500, 750, 1000, 2500, 5000 ] ]
]
]
},
},
"EUR" : {
"EUR" : {
"default" : [
"default" : [
[ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ],
[ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
],
],
"FY2425_E1_T11_EUR" : [ // Upgrade recurring +1 for lowest ask
"FY2425_E1_T11_EUR" : [ // Upgrade recurring +1 for lowest ask
[ 0, [ 3.50, 5, 10, 20, 25, 35, 50 ] ],
[ 0, [ 3.50, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
],
],
"FY2425_E1_T14_EUR" : [ // Upgrade recurring amount dynamically
"FY2425_E1_T14_EUR" : [ // Upgrade recurring amount dynamically
[ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ],
[ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ],
[ 10, [ 2.50, 10, 15, 20, 25, 35, 50 ] ],
[ 10, [ 2.50, 10, 15, 20, 25, 35, 50 ] ],
[ 15, [ 2.50, 10, 20, 30, 50, 75, 100 ] ],
[ 15, [ 2.50, 10, 20, 30, 50, 75, 100 ] ],
[ 20, [ 3.50, 10, 25, 35, 50, 75, 100 ] ],
[ 20, [ 3.50, 10, 25, 35, 50, 75, 100 ] ],
[ 25, [ 4.25, 10, 25, 35, 50, 75, 100 ] ],
[ 25, [ 4.25, 10, 25, 35, 50, 75, 100 ] ],
[ 35, [ 6.25, 15, 30, 50, 75, 100, 150 ] ],
[ 35, [ 6.25, 15, 30, 50, 75, 100, 150 ] ],
[ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ],
[ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ],
[ 100, [ 25, 50, 75, 100, 200, 300, 500 ] ],
[ 100, [ 25, 50, 75, 100, 200, 300, 500 ] ],
[ 150, [ 45, 100, 150, 250, 500, 750, 1000 ] ],
[ 150, [ 45, 100, 150, 250, 500, 750, 1000 ] ],
[ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ],
[ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ],
[ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ],
[ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ],
[ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ],
[ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ],
[ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ]
[ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ]
],
],
"FY2425_E1_T21_EUR" : [ // Give less reactivation amount
"FY2425_E1_T21_EUR" : [ // Give less reactivation amount
[ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ],
[ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ],
[ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ]
[ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ]
]
]
},
},
"GBP" : {
"GBP" : {
"default" : [
"default" : [
[ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ],
[ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
],
],
"FY2425_E1_T11_GBP" : [ // Upgrade recurring +1 for lowest ask
"FY2425_E1_T11_GBP" : [ // Upgrade recurring +1 for lowest ask
[ 0, [ 3, 5, 10, 20, 25, 35, 50 ] ],
[ 0, [ 3, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
],
],
"FY2425_E1_T14_GBP" : [ // Upgrade recurring amount dynamically
"FY2425_E1_T14_GBP" : [ // Upgrade recurring amount dynamically
[ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ],
[ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ],
[ 10, [ 2, 10, 15, 20, 25, 35, 50 ] ],
[ 10, [ 2, 10, 15, 20, 25, 35, 50 ] ],
[ 15, [ 2, 10, 20, 30, 50, 75, 100 ] ],
[ 15, [ 2, 10, 20, 30, 50, 75, 100 ] ],
[ 20, [ 3, 10, 25, 35, 50, 75, 100 ] ],
[ 20, [ 3, 10, 25, 35, 50, 75, 100 ] ],
[ 25, [ 4, 10, 25, 35, 50, 75, 100 ] ],
[ 25, [ 4, 10, 25, 35, 50, 75, 100 ] ],
[ 35, [ 6, 15, 30, 50, 75, 100, 150 ] ],
[ 35, [ 6, 15, 30, 50, 75, 100, 150 ] ],
[ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ],
[ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ],
[ 100, [ 20, 50, 75, 100, 200, 300, 500 ] ],
[ 100, [ 20, 50, 75, 100, 200, 300, 500 ] ],
[ 150, [ 40, 100, 150, 250, 500, 750, 1000 ] ],
[ 150, [ 40, 100, 150, 250, 500, 750, 1000 ] ],
[ 200, [ 45, 100, 150, 250, 500, 750, 1000 ] ],
[ 200, [ 45, 100, 150, 250, 500, 750, 1000 ] ],
[ 500, [ 125, 250, 300, 500, 750, 1000, 2000 ] ],
[ 500, [ 125, 250, 300, 500, 750, 1000, 2000 ] ],
[ 1000, [ 200, 500, 750, 1000, 2500, 5000, 10000 ] ],
[ 1000, [ 200, 500, 750, 1000, 2500, 5000, 10000 ] ],
[ 3000, [ 400, 1000, 2000, 3500, 5000, 7500, 10000 ] ]
[ 3000, [ 400, 1000, 2000, 3500, 5000, 7500, 10000 ] ]
],
],
"FY2425_E1_T21_GBP" : [ // Give less reactivation amount
"FY2425_E1_T21_GBP" : [ // Give less reactivation amount
[ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ],
[ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ],
[ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ]
[ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ]
]
]
},
},
"JPY" : [
"JPY" : [
[ 0, [ 500, 1000, 2000, 2500, 4000, 5000, 10000 ] ],
[ 0, [ 500, 1000, 2000, 2500, 4000, 5000, 10000 ] ],
[ 1000, [ 1000, 1500, 2500, 4000, 5000, 10000, 15000 ] ],
[ 1000, [ 1000, 1500, 2500, 4000, 5000, 10000, 15000 ] ],
[ 1500, [ 1500, 2000, 3000, 4000, 5000, 10000, 15000 ] ],
[ 1500, [ 1500, 2000, 3000, 4000, 5000, 10000, 15000 ] ],
[ 2000, [ 2000, 2500, 3500, 5000, 7500, 10000, 25000 ] ],
[ 2000, [ 2000, 2500, 3500, 5000, 7500, 10000, 25000 ] ],
[ 2500, [ 2500, 3500, 5000, 7500, 10000, 15000, 25000 ] ],
[ 2500, [ 2500, 3500, 5000, 7500, 10000, 15000, 25000 ] ],
[ 3000, [ 3000, 4000, 5000, 7500, 10000, 15000, 25000 ] ],
[ 3000, [ 3000, 4000, 5000, 7500, 10000, 15000, 25000 ] ],
[ 2500, [ 2500, 5000, 7500, 10000, 20000, 30000, 50000 ] ],
[ 2500, [ 2500, 5000, 7500, 10000, 20000, 30000, 50000 ] ],
[ 2500, [ 2500, 5000, 7500, 10000, 20000, 50000, 100000 ] ],
[ 2500, [ 2500, 5000, 7500, 10000, 20000, 50000, 100000 ] ],
[ 5000, [ 5000, 10000, 15000, 20000, 35000, 50000, 100000 ] ],
[ 5000, [ 5000, 10000, 15000, 20000, 35000, 50000, 100000 ] ],
[ 10000, [ 10000, 25000, 50000, 75000, 100000, 150000, 200000 ] ]
[ 10000, [ 10000, 25000, 50000, 75000, 100000, 150000, 200000 ] ]
],
],
"SEK" : [
"SEK" : [
[ 0, [ 30, 100, 150, 200, 500, 750, 1000 ] ],
[ 0, [ 30, 100, 150, 200, 500, 750, 1000 ] ],
[ 50, [ 50, 100, 150, 200, 300, 750, 1000 ] ],
[ 50, [ 50, 100, 150, 200, 300, 750, 1000 ] ],
[ 200, [ 50, 100, 200, 300, 500, 750, 1000 ] ]
[ 200, [ 50, 100, 200, 300, 500, 750, 1000 ] ]
]
]
};
};
radioAmountsData.AUD = radioAmountsData.USD;
radioAmountsData.AUD = radioAmountsData.USD;
radioAmountsData.CAD = radioAmountsData.USD;
radioAmountsData.CAD = radioAmountsData.USD;
radioAmountsData.NZD = radioAmountsData.USD;
radioAmountsData.NZD = radioAmountsData.USD;


// Major gifts appeals, hacky but this is easier than adding a load of new forms to maintain
// Major gifts appeals, hacky but this is easier than adding a load of new forms to maintain
var currencyList = [ 'USD', 'CAD', 'AUD', 'NZD', 'GBP', 'EUR' ]; // close enough
var currencyList = [ 'USD', 'CAD', 'AUD', 'NZD', 'GBP', 'EUR' ]; // close enough
for ( let i = 0; i < currencyList.length; i++ ) {
for ( let i = 0; i < currencyList.length; i++ ) {
radioAmountsData[ currencyList[i] ].MG_2024_500 = [ [ 0, [ 500, 750, 1000, 1250, 1500, 1750, 2000 ] ] ];
radioAmountsData[ currencyList[i] ].MG_2024_500 = [ [ 0, [ 500, 750, 1000, 1250, 1500, 1750, 2000 ] ] ];
radioAmountsData[ currencyList[i] ].MG_2024_650 = [ [ 0, [ 650, 750, 1000, 1250, 1500, 1750, 2000 ] ] ];
radioAmountsData[ currencyList[i] ].MG_2024_650 = [ [ 0, [ 650, 750, 1000, 1250, 1500, 1750, 2000 ] ] ];
}
}


var appealAmountsData = {
var appealAmountsData = {
"USD" : [ // also used for CAD, AUD, NZD, GBP, EUR
"USD" : [ // also used for CAD, AUD, NZD, GBP, EUR
[ 0, [ 5, 10, 20 ] ],
[ 0, [ 5, 10, 20 ] ],
[ 10, [ 10, 20, 50 ] ],
[ 10, [ 10, 20, 50 ] ],
[ 20, [ 20, 30, 50 ] ],
[ 20, [ 20, 30, 50 ] ],
[ 35, [ 20, 30, 50 ] ],
[ 35, [ 20, 30, 50 ] ],
[ 50, [ 20, 50, 100 ] ],
[ 50, [ 20, 50, 100 ] ],
[ 75, [ 50, 75, 100 ] ],
[ 75, [ 50, 75, 100 ] ],
[ 100, [ 75, 100, 150 ] ],
[ 100, [ 75, 100, 150 ] ],
[ 150, [ 75, 100, 200 ] ],
[ 150, [ 75, 100, 200 ] ],
[ 200, [ 100, 200, 300 ] ]
[ 200, [ 100, 200, 300 ] ]
],
],
"JPY" : [
"JPY" : [
[ 0, [ 300, 500, 1000 ] ],
[ 0, [ 300, 500, 1000 ] ],
[ 3, [ 500, 1000, 1500 ] ],
[ 3, [ 500, 1000, 1500 ] ],
[ 5, [ 1000, 1500, 2000 ] ],
[ 5, [ 1000, 1500, 2000 ] ],
[ 10, [ 1500, 2000, 5000 ] ],
[ 10, [ 1500, 2000, 5000 ] ],
[ 20, [ 2000, 3000, 5000 ] ],
[ 20, [ 2000, 3000, 5000 ] ],
[ 50, [ 2000, 5000, 10000 ] ],
[ 50, [ 2000, 5000, 10000 ] ],
[ 100, [ 5000, 10000, 15000 ] ]
[ 100, [ 5000, 10000, 15000 ] ]
],
],
"SEK" : [
"SEK" : [
[ 0, [ 20, 50, 100 ] ],
[ 0, [ 20, 50, 100 ] ],
[ 3, [ 30, 50, 100 ] ],
[ 3, [ 30, 50, 100 ] ],
[ 5, [ 50, 100, 150 ] ],
[ 5, [ 50, 100, 150 ] ],
[ 15, [ 100, 150, 200 ] ],
[ 15, [ 100, 150, 200 ] ],
[ 23, [ 100, 200, 300 ] ],
[ 23, [ 100, 200, 300 ] ],
[ 38, [ 100, 200, 500 ] ],
[ 38, [ 100, 200, 500 ] ],
[ 75, [ 100, 500, 750 ] ],
[ 75, [ 100, 500, 750 ] ],
[ 112, [ 100, 500, 1000 ] ]
[ 112, [ 100, 500, 1000 ] ]
]
]
};
};
appealAmountsData.AUD = appealAmountsData.USD;
appealAmountsData.AUD = appealAmountsData.USD;
appealAmountsData.CAD = appealAmountsData.USD;
appealAmountsData.CAD = appealAmountsData.USD;
appealAmountsData.GBP = appealAmountsData.USD;
appealAmountsData.GBP = appealAmountsData.USD;
appealAmountsData.NZD = appealAmountsData.USD;
appealAmountsData.NZD = appealAmountsData.USD;
appealAmountsData.EUR = appealAmountsData.USD;
appealAmountsData.EUR = appealAmountsData.USD;


// Radio button amounts
// Radio button amounts
var radioAmounts = pickAmountArray( radioAmountsData, currency, hpc, hpcSet );
var radioAmounts = pickAmountArray( radioAmountsData, currency, hpc, hpcSet );
if ( radioAmounts.length ) {
if ( radioAmounts.length ) {
// Change buttons
// Change buttons
for (var j = 0; j < radioAmounts.length; j++) {
for (var j = 0; j < radioAmounts.length; j++) {
var $radio = $("#input_amount_" + j);
var $radio = $("#input_amount_" + j);
var $label = $("label[for='input_amount_" + j + "']");
var $label = $("label[for='input_amount_" + j + "']");
$radio.val( radioAmounts[j] );
$radio.val( radioAmounts[j] );
$label.text( donationForm.formatCurrency( radioAmounts[j] ) );
$label.text( donationForm.formatCurrency( radioAmounts[j] ) );
}
}
}
}


// Appeal amounts
// Appeal amounts
var appealAmounts = pickAmountArray( appealAmountsData, currency, hpc, hpcSet );
var appealAmounts = pickAmountArray( appealAmountsData, currency, hpc, hpcSet );
if ( appealAmounts.length ) {
if ( appealAmounts.length ) {
var appealAmountString = appealAmounts.map( donationForm.formatCurrency ).join( ', ');
var appealAmountString = appealAmounts.map( donationForm.formatCurrency ).join( ', ');
$('.consider-amounts').html(appealAmountString);
$('.consider-amounts').html(appealAmountString);
}
}


}
}


function pickAmountArray( data, currency, hpc, hpcSet ) {
function pickAmountArray( data, currency, hpc, hpcSet ) {
/**
/**
* Choose the amounts for radio buttons / appeal based on hpc
* Choose the amounts for radio buttons / appeal based on hpc
* @param {Object} data
* @param {Object} data
* @param {String} currency
* @param {String} currency
* @param {Number} hpc
* @param {Number} hpc
* @param {String} hpcSet
* @param {String} hpcSet
* @return {Array} Array of amounts (as numbers)
* @return {Array} Array of amounts (as numbers)
*/
*/


var set, amounts;
var set, amounts;


if ( !(currency in data) ) {
if ( !(currency in data) ) {
return [];
return [];
}
}


if ( $.isArray(data[currency]) ) {
if ( $.isArray(data[currency]) ) {
// No variant sets
// No variant sets
set = data[currency];
set = data[currency];
} else {
} else {
// We need to go deeper. Check the variants.
// We need to go deeper. Check the variants.
if ( hpcSet in data[currency] ) {
if ( hpcSet in data[currency] ) {
set = data[currency][hpcSet];
set = data[currency][hpcSet];
} else {
} else {
set = data[currency]['default'];
set = data[currency]['default'];
}
}
}
}


// Find correct amount array for this hpc
// Find correct amount array for this hpc
for (var i = 0; i < set.length; i++) {
for (var i = 0; i < set.length; i++) {
if ( set[i][0] > hpc ) {
if ( set[i][0] > hpc ) {
break;
break;
}
}
amounts = set[i][1];
amounts = set[i][1];
}
}


return amounts;
return amounts;


}
}


function preSelect() {
function preSelect() {
/* Check for a 'preSelect' url parameter, and select that option.
/* Check for a 'preSelect' url parameter, and select that option.
If there isn't an option, add it to the "Other" box and select that */
If there isn't an option, add it to the "Other" box and select that */
var preSelectAmount = parseFloat( mw.util.getParamValue('preSelect') );
var preSelectAmount = parseFloat( mw.util.getParamValue('preSelect') );
if ( preSelectAmount > 0 ) {
if ( preSelectAmount > 0 ) {
var $preSelectOption = $('input[name="amount"][value="' + preSelectAmount + '"]');
var $preSelectOption = $('input[name="amount"][value="' + preSelectAmount + '"]');
if ( $preSelectOption.length ) {
if ( $preSelectOption.length ) {
// Select existing input
// Select existing input
$preSelectOption.prop('checked', true);
$preSelectOption.prop('checked', true);
} else {
} else {
$('#input_amount_other_box').val( preSelectAmount );
$('#input_amount_other_box').val( preSelectAmount );
$('#input_amount_other').prop('checked', true);
$('#input_amount_other').prop('checked', true);
}
}
donationForm.updateFeeDisplay();
donationForm.updateFeeDisplay();
}
}
}
}


function addCardTypesClass(country) {
function addCardTypesClass(country) {
/**
/**
* Add card types class to credit card button, so we can show correct logos
* Add card types class to credit card button, so we can show correct logos
* Banner equivalent: https://meta.wikimedia.org/wiki/MediaWiki:FundraisingBanners/LocalizeJS-2017.js
* Banner equivalent: https://meta.wikimedia.org/wiki/MediaWiki:FundraisingBanners/LocalizeJS-2017.js
* @param {String} country ISO code
* @param {String} country ISO code
*/
*/
var cardTypes = {
var cardTypes = {
// Big 6
// Big 6
'US' : 'vmad',
'US' : 'vmad',
'CA' : 'vma',
'CA' : 'vma',
'GB' : 'vmaj',
'GB' : 'vmaj',
'IE' : 'vmaj',
'IE' : 'vmaj',
'AU' : 'vmaj',
'AU' : 'vmaj',
'NZ' : 'vma',
'NZ' : 'vma',
// Euro countries
// Euro countries
'AT' : 'vmaj',
'AT' : 'vmaj',
'BE' : 'vmaj',
'BE' : 'vmaj',
'ES' : 'vmaj',
'ES' : 'vmaj',
'FR' : 'vma', // Adyen - Carte Bancaire was removed
'FR' : 'vma', // Adyen - Carte Bancaire was removed
'IT' : 'vmaj',
'IT' : 'vmaj',
'LU' : 'vmaj',
'LU' : 'vmaj',
'LV' : 'vma',
'LV' : 'vma',
'NL' : 'vmaj',
'NL' : 'vmaj',
'PT' : 'vmaj',
'PT' : 'vmaj',
'SK' : 'vmaj',
'SK' : 'vmaj',
'GR' : 'vma',
'GR' : 'vma',
// Others
// Others
'CZ' : 'vmad',
'CZ' : 'vmad',
'DK' : 'vma',
'DK' : 'vma',
'HU' : 'vma',
'HU' : 'vma',
'IL' : 'vmad', // Adyen
'IL' : 'vmad', // Adyen
'JP' : 'vmaj',
'JP' : 'vmaj',
'MY' : 'vmaj',
'MY' : 'vmaj',
'NO' : 'vma',
'NO' : 'vma',
'PL' : 'vma',
'PL' : 'vma',
'RO' : 'vma',
'RO' : 'vma',
'SE' : 'vma',
'SE' : 'vma',
'UA' : 'vma', // Adyen
'UA' : 'vma', // Adyen
'ZA' : 'vm',
'ZA' : 'vm',
'ZZ' : 'vmad' // For testing
'ZZ' : 'vmad' // For testing
};
};
if ( cardTypes[country] ) {
if ( cardTypes[country] ) {
$('.paymentmethod-cc').addClass('cctypes-' + cardTypes[country] );
$('.paymentmethod-cc').addClass('cctypes-' + cardTypes[country] );
$('.cc-text-label').addClass('sr-only');
$('.cc-text-label').addClass('sr-only');
}
}
}
}


/* Form functions */
/* Form functions */
function clearOther(box) {
function clearOther(box) {
document.getElementById('input_amount_other').checked = true;
document.getElementById('input_amount_other').checked = true;
box.value = "";
box.value = "";
}
}


function selectOther() {
function selectOther() {
document.getElementById('input_amount_other').checked = true;
document.getElementById('input_amount_other').checked = true;
}
}


function selectAmount() {
function selectAmount() {
$('#input_amount_other_box').val('');
$('#input_amount_other_box').val('');
}
}


Line 769: Line 769:
donationForm.redirectPayment = function( paymentMethod, paymentSubMethod, skipAmountValidation ) {
donationForm.redirectPayment = function( paymentMethod, paymentSubMethod, skipAmountValidation ) {


if ( donationForm.validate( skipAmountValidation ) ) {
if ( donationForm.validate( skipAmountValidation ) ) {


var params = {};
var params = {};


params.currency = donationForm.currency;
params.currency = donationForm.currency;
params.country = donationForm.country;
params.country = donationForm.country;


// Overrides for specific cc gateways
// Overrides for specific cc gateways
if ( paymentMethod === 'cc-adyen' ) {
if ( paymentMethod === 'cc-adyen' ) {
params.payment_method = 'cc';
params.payment_method = 'cc';
params.gateway = 'adyen';
params.gateway = 'adyen';
} else if ( paymentMethod === 'cc-dlocal' ) {
} else if ( paymentMethod === 'cc-dlocal' ) {
params.payment_method = 'cc';
params.payment_method = 'cc';
params.gateway = 'astropay';
params.gateway = 'astropay';
} else {
} else {
params.payment_method = paymentMethod;
params.payment_method = paymentMethod;
}
}


if ( params.payment_method === 'cc' && params.country === 'ZA' ) {
if ( params.payment_method === 'cc' && params.country === 'ZA' ) {
params.gateway = 'astropay';
params.gateway = 'astropay';
}
}


if ( paymentSubMethod ) {
if ( paymentSubMethod ) {
params.payment_submethod = paymentSubMethod;
params.payment_submethod = paymentSubMethod;
}
}


var frequency = $('input[name="frequency"]:checked').val();
let frequency = donationForm.getFrequency();
if ( frequency !== 'monthly' ) {
if ( frequency === 'monthly' ) {
params.recurring = false;
params.recurring = '1';
params.frequency_unit = 'month';
} else {
} else if ( frequency === 'annual' ) {
params.recurring = true;
params.recurring = '1';
}
params.frequency_unit = 'year';
}


params.uselang = mw.config.get('wgPageContentLanguage'); // see T281285 for why not wgUserLanguage
params.uselang = mw.config.get('wgPageContentLanguage'); // see T281285 for why not wgUserLanguage


if ( params.uselang === 'pt' && params.country === 'BR' ) {
if ( params.uselang === 'pt' && params.country === 'BR' ) {
params.uselang = 'pt-br';
params.uselang = 'pt-br';
}
}
if ( params.uselang === 'es' &&
if ( params.uselang === 'es' &&
( params.country === 'AR' || params.country === 'CL' ||
( params.country === 'AR' || params.country === 'CL' ||
params.country === 'CO' || params.country === 'MX' ||
params.country === 'CO' || params.country === 'MX' ||
params.country === 'PE' || params.country === 'UY' ||
params.country === 'PE' || params.country === 'UY' ||
params.country === 'US' )
params.country === 'US' )
) {
) {
params.uselang = 'es-419';
params.uselang = 'es-419';
}
}


var amount = donationForm.getAmount();
var amount = donationForm.getAmount();
if ( $('#ptf-checkbox').prop('checked') ) {
if ( $('#ptf-checkbox').prop('checked') ) {
amount = amount + donationForm.calculateFee( amount );
amount = amount + donationForm.calculateFee( amount );
donationForm.extraData.ptf = 1;
donationForm.extraData.ptf = 1;
}
}
params.amount = amount;
params.amount = amount;


// Email optin
// Email optin
if ( $('input[name="opt_in"]').length > 0 ) {
if ( $('input[name="opt_in"]').length > 0 ) {
var opt_inValue = $('input[name="opt_in"]:checked').val();
var opt_inValue = $('input[name="opt_in"]:checked').val();
params.opt_in = opt_inValue; // donationForm.validate() already checked it's 1 or 0
params.opt_in = opt_inValue; // donationForm.validate() already checked it's 1 or 0
}
}


if ( mw.util.getParamValue( 'pym_variant' ) ) {
if ( mw.util.getParamValue( 'pym_variant' ) ) {
params.variant = mw.util.getParamValue( 'pym_variant' );
params.variant = mw.util.getParamValue( 'pym_variant' );
}
}
if ( params.recurring && params.variant && params.variant.match( /monthlyConvert/ ) ) {
if ( params.recurring && params.variant && params.variant.match( /monthlyConvert/ ) ) {
// Post-payments monthly convert makes no sense if it's already recurring
// Post-payments monthly convert makes no sense if it's already recurring
// Avoid things like T312905
// Avoid things like T312905
delete params.variant;
delete params.variant;
}
}


// TODO: refactor this to a list of parameters to pass unchanged
if ( mw.util.getParamValue( 'pym_appeal' ) ) {
// or just pass everything by default?
params.appeal = mw.util.getParamValue( 'pym_appeal' );
if ( mw.util.getParamValue( 'pym_appeal' ) ) {
}
params.appeal = mw.util.getParamValue( 'pym_appeal' );
}
// https://phabricator.wikimedia.org/T381405
if ( mw.util.getParamValue( 'contact_id' ) ) {
params.contact_id = mw.util.getParamValue( 'contact_id' );
}
if ( mw.util.getParamValue( 'contact_hash' ) ) {
params.contact_hash = mw.util.getParamValue( 'contact_hash' );
}
// SMS
if ( mw.util.getParamValue( 'recipient_id' ) ) {
params.recipient_id = mw.util.getParamValue( 'recipient_id' );
}


// Monthly convert
// Monthly convert
if ( mc ) { // check just in-case this wasn't loaded for some reason
if ( mc ) { // check just in-case this wasn't loaded for some reason
mc.main( params, donationForm.finalStep );
mc.main( params, donationForm.finalStep );
} else {
} else {
donationForm.finalStep( params );
donationForm.finalStep( params );
}
}


} else {
} else {
donationForm.extraData.validateError = 1; // Flag they had an error, even if fixed later
donationForm.extraData.validateError = 1; // Flag they had an error, even if fixed later
}
}


return false; // don't submit if called by a button
return false; // don't submit if called by a button
};
};


Line 862: Line 877:
donationForm.finalStep = function( params ) {
donationForm.finalStep = function( params ) {


var uri = new mw.Uri('https://payments.wikimedia.org/index.php/Special:GatewayChooser');
var url = new URL('https://payments.wikimedia.org/index.php/Special:GatewayChooser');


// Skip form chooser for Apple Pay / Google Pay
// Skip form chooser for Apple Pay / Google Pay
if ( params.payment_method === 'apple' || params.payment_method === 'google' ) {
if ( params.payment_method === 'apple' || params.payment_method === 'google' ) {
uri = new mw.Uri('https://payments.wikimedia.org/index.php/Special:AdyenCheckoutGateway');
url = new URL('https://payments.wikimedia.org/index.php/Special:AdyenCheckoutGateway');
}
}


// Skip form chooser for Venmo
// Skip form chooser for Venmo
if ( params.payment_method === 'venmo' ) {
if ( params.payment_method === 'venmo' ) {
uri = new mw.Uri('https://payments.wikimedia.org/index.php/Special:BraintreeGateway');
url = new URL('https://payments.wikimedia.org/index.php/Special:BraintreeGateway');
}
}


donationForm.extraData.time = Math.round( (Date.now() - donationForm.loadedTime)/1000 );
donationForm.extraData.time = Math.round( (Date.now() - donationForm.loadedTime)/1000 );


// Tracking data
// Tracking data
params.wmf_medium = mw.util.getParamValue( 'wmf_medium' ) || mw.util.getParamValue( 'utm_medium' );
params.wmf_medium = mw.util.getParamValue( 'wmf_medium' ) || mw.util.getParamValue( 'utm_medium' );
params.wmf_campaign = mw.util.getParamValue( 'wmf_campaign' ) || mw.util.getParamValue( 'utm_campaign' );
params.wmf_campaign = mw.util.getParamValue( 'wmf_campaign' ) || mw.util.getParamValue( 'utm_campaign' );
params.wmf_source = donationForm.buildTrackingSource( params );
params.wmf_source = donationForm.buildTrackingSource( params );
params.wmf_key = donationForm.buildTrackingKey( donationForm.extraData );
params.wmf_key = donationForm.buildTrackingKey( donationForm.extraData );
if ( document.referrer ) { // TODO: do we need this?
if ( document.referrer ) { // TODO: do we need this?
// Strip protocol to stop firewall complaining
// Strip protocol to stop firewall complaining
params.referrer = document.referrer.replace(/https?:\/\//i, '');
params.referrer = document.referrer.replace(/https?:\/\//i, '');
}
}


uri.extend( params );
for ( var key of Object.keys( params ) ) {
url.searchParams.set( key, params[key] );
}


if ( window.top !== window.self ) {
if ( window.top !== window.self ) {
// In a frame, open payments in a new tab
// In a frame, open payments in a new tab
window.open( uri.toString() );
window.open( url.toString() );
} else {
} else {
window.location.href = uri.toString();
window.location.href = url.toString();
}
}
};
};


Line 906: Line 923:
donationForm.buildTrackingSource = function( params ) {
donationForm.buildTrackingSource = function( params ) {


var wmf_source = mw.util.getParamValue( 'wmf_source' ) || mw.util.getParamValue( 'utm_source' );
var wmf_source = mw.util.getParamValue( 'wmf_source' ) || mw.util.getParamValue( 'utm_source' );
wmf_source += '.';
wmf_source += '.';


var fullDottedPaymentMethod = params.payment_method;
var fullDottedPaymentMethod = params.payment_method;
if ( params.recurring ) {
if ( params.recurring ) {
fullDottedPaymentMethod = 'r' + fullDottedPaymentMethod;
fullDottedPaymentMethod = 'r' + fullDottedPaymentMethod;
}
}
if ( params.payment_submethod ) {
if ( params.payment_submethod ) {
fullDottedPaymentMethod = fullDottedPaymentMethod + '.' + params.payment_submethod;
fullDottedPaymentMethod = fullDottedPaymentMethod + '.' + params.payment_submethod;
}
}


/* Get URL parameter, but remove parts using old format. Allow fallback to a default value */
/* Get URL parameter, but remove parts using old format. Allow fallback to a default value */
var getParam = function( param, removeText, dflt ) {
var getParam = function( param, removeText, dflt ) {
if ( mw.util.getParamValue( param ) ) {
if ( mw.util.getParamValue( param ) ) {
return mw.util.getParamValue( param ).replace( removeText, '' );
return mw.util.getParamValue( param ).replace( removeText, '' );
} else {
} else {
return dflt;
return dflt;
}
}
};
};


/* The landing page info, separated by ~. This mostly exists for legacy reasons */
/* The landing page info, separated by ~. This mostly exists for legacy reasons */
wmf_source += getParam( 'template' , 'Lp-layout' , 'default' ) + '~';
wmf_source += getParam( 'template' , 'Lp-layout' , 'default' ) + '~';
wmf_source += getParam( 'appeal-template' , 'Appeal-template-' , 'default' ) + '~';
wmf_source += getParam( 'appeal-template' , 'Appeal-template-' , 'default' ) + '~';
wmf_source += getParam( 'appeal' , 'Appeal-' , 'default' ) + '~';
wmf_source += getParam( 'appeal' , 'Appeal-' , 'default' ) + '~';
wmf_source += getParam( 'form-template' , 'Form-template-' , 'default' ) + '~';
wmf_source += getParam( 'form-template' , 'Form-template-' , 'default' ) + '~';
wmf_source += getParam( 'form-countryspecific', 'Form-countryspecific-', 'control' );
wmf_source += getParam( 'form-countryspecific', 'Form-countryspecific-', 'control' );


wmf_source += '.' + fullDottedPaymentMethod;
wmf_source += '.' + fullDottedPaymentMethod;


return wmf_source;
return wmf_source;


};
};
Line 946: Line 963:
*/
*/
donationForm.buildTrackingKey = function(data) {
donationForm.buildTrackingKey = function(data) {
var existingKey = mw.util.getParamValue( 'wmf_key' ) || mw.util.getParamValue( 'utm_key' ),
var existingKey = mw.util.getParamValue( 'wmf_key' ) || mw.util.getParamValue( 'utm_key' ),
dataArray = [];
dataArray = [];


if ( existingKey ) {
if ( existingKey ) {
dataArray.push( existingKey );
dataArray.push( existingKey );
}
}
for (var key in data) {
for (var key in data) {
if (data.hasOwnProperty(key)) {
if (data.hasOwnProperty(key)) {
dataArray.push( key + '_' + data[key] );
dataArray.push( key + '_' + data[key] );
}
}
}
}
return dataArray.join('~');
return dataArray.join('~');
};
};


/* Return amount selected or input */
/* Return amount selected or input */
donationForm.getAmount = function() {
donationForm.getAmount = function() {
var form = document.forms.donateForm,
var form = document.forms.donateForm,
amount = null;
amount = null;
donationForm.extraData.otherAmt = 0;
donationForm.extraData.otherAmt = 0;


// If there are some amount radio buttons, then look for the checked one
// If there are some amount radio buttons, then look for the checked one
if ( form.amount ) {
if ( form.amount ) {
for ( var i = 0; i < form.amount.length; i++ ) {
for ( var i = 0; i < form.amount.length; i++ ) {
if ( form.amount[i].checked ) {
if ( form.amount[i].checked ) {
amount = parseFloat( form.amount[i].value );
amount = parseFloat( form.amount[i].value );
}
}
}
}
}
}
// Check the "other" amount box
// Check the "other" amount box
if ( document.getElementById('input_amount_other').checked ) {
if ( document.getElementById('input_amount_other').checked ) {
amount = donationForm.parseOtherAmount( form.input_amount_other_box.value );
amount = donationForm.parseOtherAmount( form.input_amount_other_box.value );
donationForm.extraData.otherAmt = 1;
donationForm.extraData.otherAmt = 1;
}
}


return amount;
return amount;


};
};
Line 994: Line 1,011:
*/
*/
donationForm.parseOtherAmount = function( value ) {
donationForm.parseOtherAmount = function( value ) {
var amount;
var amount;


value = value.replace(/[,.](\d)$/, '\:$10');
value = value.replace(/[,.](\d)$/, '\:$10');
value = value.replace(/[,.](\d)(\d)$/, '\:$1$2');
value = value.replace(/[,.](\d)(\d)$/, '\:$1$2');
value = value.replace(/[\$£€¥,.]/g, '');
value = value.replace(/[\$£€¥,.]/g, '');
value = value.replace(/:/, '.');
value = value.replace(/:/, '.');


amount = parseFloat( value );
amount = parseFloat( value );
if ( isNaN( amount ) ) {
if ( isNaN( amount ) ) {
return 0;
return 0;
} else {
} else {
return amount;
return amount;
}
}
};
};


Line 1,014: Line 1,031:
donationForm.validate = function( skipAmountValidation ) {
donationForm.validate = function( skipAmountValidation ) {


var error = false;
var error = false;
var form = document.forms.donateForm;
var form = document.forms.donateForm;


// Reset all errors
// Reset all errors
$('.lp-haserror').removeClass('lp-haserror');
$('.lp-haserror').removeClass('lp-haserror');
$('.lp-error').hide();
$('.lp-error').hide();


if ( !skipAmountValidation && !donationForm.validateAmount() ) {
if ( !skipAmountValidation && !donationForm.validateAmount() ) {
error = true;
error = true;
}
}


if ( form.opt_in ) {
if ( form.opt_in ) {
if ( $('input[name="opt_in"]:checked').val() === undefined ) {
if ( $('input[name="opt_in"]:checked').val() === undefined ) {
$('#error-optin').show().focus();
$('#error-optin').show().focus();
error = true;
error = true;
} else {
} else {
$('#error-optin').hide();
$('#error-optin').hide();
}
}
}
}


return !error;
return !error;
};
};


Line 1,043: Line 1,060:
donationForm.validateAmount = function() {
donationForm.validateAmount = function() {


var amount = donationForm.getAmount();
var amount = donationForm.getAmount();


if ( amount === null || isNaN(amount) || amount <= 0 || amount < donationForm.minLocal ) {
if ( amount === null || isNaN(amount) || amount <= 0 || amount < donationForm.minLocal ) {
$('.amount-options').addClass('lp-haserror');
$('.amount-options').addClass('lp-haserror');
$('.lp-error-bigamount').hide();
$('.lp-error-bigamount').hide();
$('.lp-error-smallamount').show().focus();
$('.lp-error-smallamount').show().focus();
return false;
return false;
} else if ( amount > donationForm.maxLocal ) {
} else if ( amount > donationForm.maxLocal ) {
$('.amount-options').addClass('lp-haserror');
$('.amount-options').addClass('lp-haserror');
$('.lp-error-bigamount').show().focus();
$('.lp-error-bigamount').show().focus();
return false;
return false;
} else {
} else {
$('.amount-options').removeClass('lp-haserror');
$('.amount-options').removeClass('lp-haserror');
$('.lp-error-smallamount, .lp-error-bigamount').hide();
$('.lp-error-smallamount, .lp-error-bigamount').hide();
return true;
return true;
}
}


};
};


donationForm.toggleMonthly = function(monthly) {
donationForm.getFrequency = function() {
return document.forms.donateForm.dataset.frequency || 'onetime';
if (monthly) {
};
$('#form-wrapper').addClass('form-monthly');

} else {
donationForm.setFrequency = function( frequency ) {
$('#form-wrapper').removeClass('form-monthly');
// TODO: add some validation to reject invalid frequency values
}
let form = document.forms.donateForm;

form.frequency.value = frequency; // change input
form.dataset.frequency = frequency;
};

/* Wrapper for compatibility with old forms */
donationForm.toggleMonthly = function( monthly ) {
if ( monthly ) {
donationForm.setFrequency( 'monthly' );
} else {
donationForm.setFrequency( 'onetime' );
}
};
};


donationForm.updateFeeDisplay = function() {
donationForm.updateFeeDisplay = function() {
var selectedAmount = donationForm.getAmount(),
var selectedAmount = donationForm.getAmount(),
feeAmount = donationForm.calculateFee( selectedAmount ),
feeAmount = donationForm.calculateFee( selectedAmount ),
feeText;
feeText;


feeText = donationForm.formatCurrency( feeAmount );
feeText = donationForm.formatCurrency( feeAmount );


$('.ptf label span').text( feeText );
$('.ptf label span').text( feeText );
if ( selectedAmount + feeAmount <= donationForm.maxLocal ) {
if ( selectedAmount + feeAmount <= donationForm.maxLocal ) {
$('.ptf').slideDown();
$('.ptf').slideDown();
}
}
};
};


Line 1,090: Line 1,120:
donationForm.calculateFee = function( amount ) {
donationForm.calculateFee = function( amount ) {


// Minimum fee/PTF amounts. Default is 0.35.
// Minimum fee/PTF amounts. Default is 0.35.
// Updated 2019-05-21 to approx 0.35 USD equivalent
// Updated 2019-05-21 to approx 0.35 USD equivalent
var feeMinimums = {
var feeMinimums = {
'DKK' : 2,
'DKK' : 2,
'HUF' : 100,
'HUF' : 100,
'ILS' : 1.2,
'ILS' : 1.2,
'INR' : 4,
'INR' : 4,
'JPY' : 35,
'JPY' : 35,
'MYR' : 1,
'MYR' : 1,
'NOK' : 3,
'NOK' : 3,
'PLN' : 1.35,
'PLN' : 1.35,
'CZK' : 7.5,
'CZK' : 7.5,
'RON' : 1.5,
'RON' : 1.5,
'SEK' : 3,
'SEK' : 3,
'UAH' : 10,
'UAH' : 10,
'ZAR' : 5,
'ZAR' : 5,
// Latin America // Updated 2024-08-22 to approx 0.35 USD equivalent
// Latin America // Updated 2024-08-22 to approx 0.35 USD equivalent
'BRL' : 1.75,
'BRL' : 1.75,
'ARS' : 300,
'ARS' : 300,
'CLP' : 300,
'CLP' : 300,
'COP' : 1400,
'COP' : 1400,
'MXN' : 6,
'MXN' : 6,
'PEN' : 1.2,
'PEN' : 1.2,
'UYU' : 14
'UYU' : 14
};
};


var feeMultiplier = 0.04,
var feeMultiplier = 0.04,
feeMinimum = feeMinimums[ donationForm.currency ] || 0.35,
feeMinimum = feeMinimums[ donationForm.currency ] || 0.35,
feeAmount = amount * feeMultiplier;
feeAmount = amount * feeMultiplier;


if ( feeAmount < feeMinimum ) {
if ( feeAmount < feeMinimum ) {
feeAmount = feeMinimum;
feeAmount = feeMinimum;
}
}
return parseFloat( feeAmount.toFixed(2) );
return parseFloat( feeAmount.toFixed(2) );
};
};




donationForm.initOptin = function() {
donationForm.initOptin = function() {
$('.optin-options').on('change', function(e) {
$('.optin-options').on('change', function(e) {


$('#error-optin').hide();
$('#error-optin').hide();


// Only do all this if we have translated prompts
// Only do all this if we have translated prompts
if ( $('.optin-no-prompt').data('is-translated') === 'yes' ) {
if ( $('.optin-no-prompt').data('is-translated') === 'yes' ) {
if ( e.target.id === 'optin-no' ) {
if ( e.target.id === 'optin-no' ) {
$('.optin-no-prompt').removeClass('is-positive');
$('.optin-no-prompt').removeClass('is-positive');
if ( !$('.optin-no-prompt').is(':visible') ) {
if ( !$('.optin-no-prompt').is(':visible') ) {
$('.optin-no-prompt').slideDown();
$('.optin-no-prompt').slideDown();
}
}
} else {
} else {
$('.optin-no-prompt').addClass('is-positive');
$('.optin-no-prompt').addClass('is-positive');
}
}
}
}
});
});
};
};


Line 1,155: Line 1,185:
*/
*/
donationForm.otherInputControl = function( inputElement ) {
donationForm.otherInputControl = function( inputElement ) {
if ( inputElement ) {
if ( inputElement ) {
inputElement.onkeypress = function(e) {
inputElement.onkeypress = function(e) {
// Allow special keys in Firefox
// Allow special keys in Firefox
if ((e.code == 'ArrowLeft') || (e.code == 'ArrowRight') ||
if ((e.code == 'ArrowLeft') || (e.code == 'ArrowRight') ||
(e.code == 'ArrowUp') || (e.code == 'ArrowDown') ||
(e.code == 'ArrowUp') || (e.code == 'ArrowDown') ||
(e.code == 'Delete') || (e.code == 'Backspace')) {
(e.code == 'Delete') || (e.code == 'Backspace')) {
return;
return;
}
}
var chr = String.fromCharCode(e.which);
var chr = String.fromCharCode(e.which);
if ('0123456789., '.indexOf(chr) === -1) {
if ('0123456789., '.indexOf(chr) === -1) {
return false;
return false;
}
}
};
};
}
}
};
};


Line 1,180: Line 1,210:
*/
*/
donationForm.shouldShowApplePay = function ( country ) {
donationForm.shouldShowApplePay = function ( country ) {
if ( location.search.match('forceApplePay') ) {
if ( location.search.match('forceApplePay') ) {
return true;
return true;
}
}
if ( window.ApplePaySession ) {
if ( window.ApplePaySession ) {
if ( ApplePaySession.canMakePayments() ) {
if ( ApplePaySession.canMakePayments() ) {
return true;
return true;
}
}
}
}
return false;
return false;
};
};


Line 1,197: Line 1,227:
donationForm.isVenmoSupported = function(options) {
donationForm.isVenmoSupported = function(options) {
var options = options || {
var options = options || {
allowNewBrowserTab: false,
allowNewBrowserTab: false,
allowWebviews: true,
allowWebviews: true,
allowDesktop: true,
allowDesktop: true,
allowDesktopWebLogin: true
allowDesktopWebLogin: true
};
};
var ua = window.navigator.userAgent;
var ua = window.navigator.userAgent;


var merchantAllowsReturningToNewBrowserTab,
var merchantAllowsReturningToNewBrowserTab,
merchantAllowsWebviews,
merchantAllowsWebviews,
merchantAllowsDesktopBrowsers;
merchantAllowsDesktopBrowsers;
var isMobileDevice = isAndroid() || isIos();
var isMobileDevice = isAndroid() || isIos();
var isAndroidChrome = isAndroid() && isChrome();
var isAndroidChrome = isAndroid() && isChrome();
Line 1,215: Line 1,245:
// NEXT_MAJOR_VERSION allowDesktop will default to true, but can be opted out
// NEXT_MAJOR_VERSION allowDesktop will default to true, but can be opted out
merchantAllowsDesktopBrowsers =
merchantAllowsDesktopBrowsers =
(options.allowDesktopWebLogin || options.allowDesktop) === true;
(options.allowDesktopWebLogin || options.allowDesktop) === true;
merchantAllowsReturningToNewBrowserTab = options.hasOwnProperty(
merchantAllowsReturningToNewBrowserTab = options.hasOwnProperty(
"allowNewBrowserTab"
"allowNewBrowserTab"
)
)
? options.allowNewBrowserTab
? options.allowNewBrowserTab
: true;
: true;
// NEXT_MAJOR_VERSION webviews are not supported, except for the case where
// NEXT_MAJOR_VERSION webviews are not supported, except for the case where
// the merchant themselves is presenting venmo in a webview using the deep
// the merchant themselves is presenting venmo in a webview using the deep
Line 1,228: Line 1,258:
// merchant's app via a webview.
// merchant's app via a webview.
merchantAllowsWebviews = options.hasOwnProperty("allowWebviews")
merchantAllowsWebviews = options.hasOwnProperty("allowWebviews")
? options.allowWebviews
? options.allowWebviews
: true;
: true;


if (isKnownUnsupportedMobileBrowser) {
if (isKnownUnsupportedMobileBrowser) {
return false;
return false;
}
}


if (
if (
!merchantAllowsWebviews &&
!merchantAllowsWebviews &&
(isAndroidWebview() || isIosWebview())
(isAndroidWebview() || isIosWebview())
) {
) {
return false;
return false;
}
}


if (!isMobileDevice) {
if (!isMobileDevice) {
return merchantAllowsDesktopBrowsers;
return merchantAllowsDesktopBrowsers;
}
}


if (!merchantAllowsReturningToNewBrowserTab) {
if (!merchantAllowsReturningToNewBrowserTab) {
return isMobileDeviceThatSupportsReturnToSameTab;
return isMobileDeviceThatSupportsReturnToSameTab;
}
}


Line 1,255: Line 1,285:


function isAndroid() {
function isAndroid() {
return /Android/i.test(ua);
return /Android/i.test(ua);
}
}


function isIos(checkIpadOS = true) {
function isIos(checkIpadOS = true) {
const iOsTest = /iPhone|iPod|iPad/i.test(ua);
const iOsTest = /iPhone|iPod|iPad/i.test(ua);
return checkIpadOS ? iOsTest || isIpadOS() : iOsTest;
return checkIpadOS ? iOsTest || isIpadOS() : iOsTest;
}
}


function isIpadOS() {
function isIpadOS() {
// "ontouchend" is used to determine if a browser is on an iPad, otherwise
// "ontouchend" is used to determine if a browser is on an iPad, otherwise
// user-agents for iPadOS behave/identify as a desktop browser
// user-agents for iPadOS behave/identify as a desktop browser
return /Mac|iPad/i.test(ua) && "ontouchend" in window.document;
return /Mac|iPad/i.test(ua) && "ontouchend" in window.document;
}
}


function isEdge() {
function isEdge() {
return ua.indexOf("Edge/") !== -1 || ua.indexOf("Edg/") !== -1;
return ua.indexOf("Edge/") !== -1 || ua.indexOf("Edg/") !== -1;
}
}


function isSamsung() {
function isSamsung() {
return /SamsungBrowser/i.test(ua);
return /SamsungBrowser/i.test(ua);
}
}


function isDuckDuckGo() {
function isDuckDuckGo() {
return ua.indexOf("DuckDuckGo/") !== -1;
return ua.indexOf("DuckDuckGo/") !== -1;
}
}


function isOpera() {
function isOpera() {
return (
return (
ua.indexOf("OPR/") !== -1 ||
ua.indexOf("OPR/") !== -1 ||
ua.indexOf("Opera/") !== -1 ||
ua.indexOf("Opera/") !== -1 ||
ua.indexOf("OPT/") !== -1
ua.indexOf("OPT/") !== -1
);
);
}
}


function isSilk() {
function isSilk() {
return ua.indexOf("Silk/") !== -1;
return ua.indexOf("Silk/") !== -1;
}
}


function isChrome() {
function isChrome() {
return (
return (
(ua.indexOf("Chrome") !== -1 || ua.indexOf("CriOS") !== -1) &&
(ua.indexOf("Chrome") !== -1 || ua.indexOf("CriOS") !== -1) &&
!isEdge() &&
!isEdge() &&
!isSamsung() &&
!isSamsung() &&
!isDuckDuckGo() &&
!isDuckDuckGo() &&
!isOpera() &&
!isOpera() &&
!isSilk()
!isSilk()
);
);
}
}


function isIosFirefox() {
function isIosFirefox() {
return /FxiOS/i.test(ua);
return /FxiOS/i.test(ua);
}
}


function isWebkit() {
function isWebkit() {
const webkitRegexp = /webkit/i;
const webkitRegexp = /webkit/i;
return webkitRegexp.test(ua);
return webkitRegexp.test(ua);
}
}


function isIosChrome() {
function isIosChrome() {
return ua.indexOf("CriOS") > -1;
return ua.indexOf("CriOS") > -1;
}
}


function isFacebook() {
function isFacebook() {
return ua.indexOf("FBAN") > -1;
return ua.indexOf("FBAN") > -1;
}
}


function isIosSafari() {
function isIosSafari() {
return (
return (
isIos() &&
isIos() &&
isWebkit() &&
isWebkit() &&
!isIosChrome() &&
!isIosChrome() &&
!isIosFirefox() &&
!isIosFirefox() &&
!isFacebook()
!isFacebook()
);
);
}
}


function isFacebookOwnedBrowserOnAndroid() {
function isFacebookOwnedBrowserOnAndroid() {
var e = ua.toLowerCase();
var e = ua.toLowerCase();
return -1 < e.indexOf("huawei") && -1 < e.indexOf("fban") || isAndroid() && (-1 < e.indexOf("fb_iab") || -1 < e.indexOf("instagram"));
return -1 < e.indexOf("huawei") && -1 < e.indexOf("fban") || isAndroid() && (-1 < e.indexOf("fb_iab") || -1 < e.indexOf("instagram"));
}
}


function isSamsungBrowser() {
function isSamsungBrowser() {
return /SamsungBrowser/i.test(ua);
return /SamsungBrowser/i.test(ua);
}
}


function isAndroidWebview() {
function isAndroidWebview() {
return isAndroid() && -1 < ua.toLowerCase().indexOf("wv");
return isAndroid() && -1 < ua.toLowerCase().indexOf("wv");
}
}


function isGoogleSearchApp() {
function isGoogleSearchApp() {
return /\bGSA\b/.test(ua);
return /\bGSA\b/.test(ua);
}
}


function isIosGoogleSearchApp() {
function isIosGoogleSearchApp() {
return isIos() && isGoogleSearchApp();
return isIos() && isGoogleSearchApp();
}
}


function isIosWebview() {
function isIosWebview() {
if (isIos()) {
if (isIos()) {
// The Google Search iOS app is technically a webview and doesn't support popups.
// The Google Search iOS app is technically a webview and doesn't support popups.
if (isIosGoogleSearchApp()) {
if (isIosGoogleSearchApp()) {
return true;
return true;
}
}
// Historically, a webview could be identified by the presence of AppleWebKit and _no_ presence of Safari after.
// Historically, a webview could be identified by the presence of AppleWebKit and _no_ presence of Safari after.
return /.+AppleWebKit(?!.*Safari)/i.test(ua);
return /.+AppleWebKit(?!.*Safari)/i.test(ua);
}
}
return false;
return false;
}
}
};
};
Line 1,369: Line 1,399:
$(document).ready(function() {
$(document).ready(function() {


mw.loader.using( ['mediawiki.util'] ).done( function() {
mw.loader.using( ['mediawiki.util'] ).done( function() {


var form = document.forms.donateForm;
var form = document.forms.donateForm;


// Minimum amount is usually about 1 USD
// Minimum amount is usually about 1 USD
donationForm.minLocal = donationForm.currencyRates[ donationForm.currency ];
donationForm.minLocal = donationForm.currencyRates[ donationForm.currency ];
donationForm.minLocal = Math.ceil( donationForm.minLocal * 100 ) / 100; // Round it up
donationForm.minLocal = Math.ceil( donationForm.minLocal * 100 ) / 100; // Round it up
donationForm.maxUSD = 25000;
donationForm.maxUSD = 25000;
donationForm.maxLocal = Math.floor( donationForm.currencyRates[ donationForm.currency ] * donationForm.maxUSD );
donationForm.maxLocal = Math.floor( donationForm.currencyRates[ donationForm.currency ] * donationForm.maxUSD );


// Overrides for India
// Overrides for India
if ( donationForm.currency === 'INR' ) {
if ( donationForm.currency === 'INR' ) {
donationForm.minLocal = 10;
donationForm.minLocal = 10;
// Until https://phabricator.wikimedia.org/T370583 fixed?
// Until https://phabricator.wikimedia.org/T370583 fixed?
donationForm.maxUSD = 3000;
donationForm.maxUSD = 3000;
donationForm.maxLocal = 250000;
donationForm.maxLocal = 250000;
}
}


// Block typing symbols in Other field
// Block typing symbols in Other field
donationForm.otherInputControl( document.getElementById('input_amount_other_box') );
donationForm.otherInputControl( document.getElementById('input_amount_other_box') );


// Clear errors and update fee when selected/entered
// Clear errors and update fee when selected/entered
$('.amount-options').on( 'input change', function() {
$('.amount-options').on( 'input change', function() {
// Ideally we would validate the amount, but this causes issues with focus
// Ideally we would validate the amount, but this causes issues with focus
$('.amount-options .lp-error').hide();
$('.amount-options .lp-error').hide();
donationForm.updateFeeDisplay();
donationForm.updateFeeDisplay();
});
});


// Disable submitting form with Enter key
// Disable submitting form with Enter key
$('form[name="donateForm"]').on('keypress', function(e) {
$('form[name="donateForm"]').on('keypress', function(e) {
var code = ( e.keyCode ? e.keyCode : e.which );
var code = ( e.keyCode ? e.keyCode : e.which );
if ( code == 13 ) {
if ( code == 13 ) {
e.preventDefault();
e.preventDefault();
}
}
});
});


// But allow Enter on buttons
// But allow Enter on buttons
$('.payment-method-button').keyup(function(e) {
$('.payment-method-button').keyup(function(e) {
if (event.keyCode === 13) {
if (event.keyCode === 13) {
e.target.click();
e.target.click();
}
}
});
});


if ( form ) {
if ( form ) {


// hide frequency options for some countries
// hide frequency options for some countries
if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) !== -1 ) {
if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) !== -1 ) {
$('#frequency_onetime').prop('checked', true);
$('#frequency_onetime').prop('checked', true);
$('.frequency-options, #cancel-monthly, #donate-recurring-smallprint').hide();
$('.frequency-options, #cancel-monthly, #donate-recurring-smallprint').hide();
}
}

if ( donationForm.noRecurringPaypalCountries.indexOf( donationForm.country ) !== -1 ) {
$( '.paymentmethod-pp, .paymentmethod-pp-usd' ).addClass( 'not-monthly-capable' );
}


// Format amounts on buttons
if ( donationForm.noRecurringPaypalCountries.indexOf( donationForm.country ) !== -1 ) {
$( '.amount-options li' ).each( function( index ) {
$( '.paymentmethod-pp, .paymentmethod-pp-usd' ).addClass( 'not-monthly-capable' );
let amount = this.querySelector( 'input' ).value;
}
if ( amount !== 'Other' ) {
this.querySelector( 'label' ).innerText = donationForm.formatCurrency( amount );
// Format amounts on buttons
}
$( '.amount-options li' ).each( function( index ) {
});
let amount = this.querySelector( 'input' ).value;
if ( amount !== 'Other' ) {
this.querySelector( 'label' ).innerText = donationForm.formatCurrency( amount );
}
});


addCardTypesClass( donationForm.country );
addCardTypesClass( donationForm.country );


// Only show Amazon for links from Ways to give
// Only show Amazon for links from Ways to give
if (
if (
mw.util.getParamValue( 'wmf_source' ) === 'Waystogive' ||
mw.util.getParamValue( 'wmf_source' ) === 'Waystogive' ||
Line 1,442: Line 1,472:
}
}


// Apple Pay
// Apple Pay
if ( $('.paymentmethod-applepay').length > 0 ) {
if ( $('.paymentmethod-applepay').length > 0 ) {
if ( !donationForm.shouldShowApplePay( donationForm.country ) ) {
if ( !donationForm.shouldShowApplePay( donationForm.country ) ) {
$('.paymentmethod-applepay').remove();
$('.paymentmethod-applepay').remove();
}
}
}
}


// Venmo browser check
// Venmo browser check
if ( $('.paymentmethod-venmo').length > 0 ) {
if ( $('.paymentmethod-venmo').length > 0 ) {
if ( !donationForm.isVenmoSupported() || donationForm.country !== 'US' ) {
if ( !donationForm.isVenmoSupported() || donationForm.country !== 'US' ) {
$('.paymentmethod-venmo').remove();
$('.paymentmethod-venmo').remove();
}
}
}
}
}


// Dumb hack to remove ACH for Portal test against Fundraise Up
// Links open in new tab
if ( mw.util.getParamValue( 'wmf_source' ) === 'portalBanner_en6C_2024_overlayBanner4WikiForm' ) {
$('.links-in-new-tab a').attr('target', '_blank');
$('.paymentmethod-ach').remove();
}


}
// Disable logo link
$('#p-logo a').attr( { href: '#', title: '' } );


// Links open in new tab
// These don't need to be tabbable on the landing page
$('#searchInput, .mw-jump-link').attr('tabindex', '-1');
$('.links-in-new-tab a').attr('target', '_blank');


// Disable logo link
$('.input_amount_other').click(function() {
$('#p-logo a').attr( { href: '#', title: '' } );
$('#input_amount_other_box').focus();
});


// These don't need to be tabbable on the landing page
// Allow preselecting monthly
$('#searchInput, .mw-jump-link').attr('tabindex', '-1');
if (

mw.util.getParamValue('monthly')
$('.input_amount_other').click(function() {
&& mw.util.getParamValue('monthly') !== '0'
$('#input_amount_other_box').focus();
&& donationForm.noRecurringCountries.indexOf( donationForm.country ) === -1
});
&& mw.util.getParamValue('utm_medium') !== 'endowment'

&& mw.util.getParamValue('wmf_medium') !== 'endowment'
// Allow preselecting frequency if possible
) {
if (
$('#frequency_monthly').click();
donationForm.noRecurringCountries.indexOf( donationForm.country ) === -1
}
&& mw.util.getParamValue( 'utm_medium' ) !== 'endowment'
&& mw.util.getParamValue( 'wmf_medium' ) !== 'endowment'
) {
if ( mw.util.getParamValue( 'frequency' ) ) {
donationForm.setFrequency( mw.util.getParamValue( 'frequency' ) );
} else if ( mw.util.getParamValue('monthly') && mw.util.getParamValue('monthly') !== '0' ) {
// old method with "monthly=" parameter
donationForm.setFrequency( 'monthly' );
} else {
donationForm.setFrequency( 'onetime' );
}
}


donationForm.initOptin();
donationForm.initOptin();


try {
try {
adjustHPC();
adjustHPC();
preSelect(); // Make sure to do this *after* other fiddling with values
preSelect(); // Make sure to do this *after* other fiddling with values
donationForm.localizeErrors();
donationForm.localizeErrors();
}
}
finally {
finally {
$('.frb-monthly-pitch, .frb-monthly-pitch-thanks').appendTo('.frequency-options');
$('.frb-monthly-pitch, .frb-monthly-pitch-thanks').appendTo('.frequency-options');
$('.ptf').appendTo('.amount-options');
$('.ptf').appendTo('.amount-options');
$('.optin-options').insertAfter('.amount-options');
$('.optin-options').insertAfter('.amount-options');
$('.consider-amounts').show();
$('.consider-amounts').show();
$('#actual-form').show();
$('#actual-form').show();
$('#actual-form-loading').hide();
$('#actual-form-loading').hide();
}
}


});
});


});
});

Latest revision as of 18:02, 12 December 2024

/* jshint strict:false */
/** MediaWiki:DonationForm.js - loaded on all donation forms
 * TODO: lots of cleanup
 */

var donationForm = {};

donationForm.loadedTime = Date.now();
donationForm.extraData = {};

donationForm.country = mw.util.getParamValue('country').toUpperCase();
try {
	donationForm.currency = document.forms.donateForm.currency_code.value;
} catch (error) {
	donationForm.currency = 'USD';
}

/**
 * Make language and country into a standard javascript Intl locale identifier
 *
 * @param  {string} language
 * @param  {string} country
 * @return {string} locale identifier e.g. en-GB
 */
donationForm.getLocale = function( language, country ) {
	// Sometimes in email testing links the uselang is a variable contiaining %
	// In that case fall back to English so locale code doesn't break form
	if ( language.match('%') ) {
		language = 'en';
	}
	// MediaWiki allows some language codes like en-gb, en-ca, pt-br
	// We don't want these for a javascript locale, so drop anything after '-'
	language = language.split('-')[0];

	return language + '-' + country;
};

donationForm.locale = donationForm.getLocale( mw.config.get('wgPageContentLanguage'), donationForm.country );


// Don't offer recurring at all in these countries
donationForm.noRecurringCountries = [ 'AR', 'IN' ];

donationForm.noRecurringPaypalCountries = [ 'CL', 'CO', 'PE', 'UY', 'BR' ];

donationForm.currencyRates = {
	// From https://github.com/wikimedia/wikimedia-fundraising-SmashPig/blob/master/PaymentData/ReferenceData/CurrencyRates.php
	// Updated 2024-07-31
	'ADF' : 6.04,
	'ADP' : 153,
	'AED' : 3.67,
	'AFA' : 70,
	'AFN' : 70,
	'ALL' : 90,
	'AMD' : 368,
	'ANG' : 1.79,
	'AOA' : 844,
	'AON' : 844,
	'ARS' : 887,
	'ATS' : 13,
	'AUD' : 1.5,
	'AWG' : 1.79,
	'AZM' : 8500,
	'AZN' : 1.7,
	'BAM' : 1.8,
	'BBD' : 2,
	'BDT' : 116,
	'BEF' : 37,
	'BGL' : 1.8,
	'BGN' : 1.8,
	'BHD' : 0.37355757356689,
	'BIF' : 2842,
	'BMD' : 1,
	'BND' : 1.35,
	'BOB' : 6.71,
	'BRL' : 5.1,
	'BSD' : 1,
	'BTN' : 83,
	'BWP' : 13,
	'BYR' : 32642,
	'BZD' : 1.98,
	'CAD' : 1.36,
	'CDF' : 2786,
	'CHF' : 0.9094629289448,
	'CLP' : 890,
	'CNY' : 7.23,
	'COP' : 3803,
	'CRC' : 498,
	'CUC' : 1,
	'CUP' : 25,
	'CVE' : 101,
	'CYP' : 0.53848627984321,
	'CZK' : 23,
	'DEM' : 1.8,
	'DJF' : 178,
	'DKK' : 6.86,
	'DOP' : 58,
	'DZD' : 133,
	'ECS' : 24094,
	'EEK' : 14,
	'EGP' : 47,
	'ESP' : 153,
	'ETB' : 57,
	'EUR' : 0.92005843390143,
	'FIM' : 5.47,
	'FJD' : 2.23,
	'FKP' : 0.78703952551207,
	'FRF' : 6.04,
	'GBP' : 0.78703952551207,
	'GEL' : 2.71,
	'GHC' : 143125,
	'GHS' : 14,
	'GIP' : 0.78703952551207,
	'GMD' : 68,
	'GNF' : 8493,
	'GRD' : 314,
	'GTQ' : 7.57,
	'GYD' : 200,
	'HKD' : 7.8,
	'HNL' : 24,
	'HRK' : 6.93,
	'HTG' : 132,
	'HUF' : 355,
	'IDR' : 15986,
	'IEP' : 0.72460490043714,
	'ILS' : 3.69,
	'INR' : 83,
	'IQD' : 1290,
	'IRR' : 42009,
	'ISK' : 138,
	'ITL' : 1781,
	'JMD' : 154,
	'JOD' : 0.70900000000001,
	'JPY' : 156,
	'KES' : 130,
	'KGS' : 88,
	'KHR' : 3993,
	'KMF' : 453,
	'KPW' : 135,
	'KRW' : 1358,
	'KWD' : 0.30629670764681,
	'KYD' : 0.83333299999999,
	'KZT' : 442,
	'LAK' : 21103,
	'LBP' : 89393,
	'LKR' : 298,
	'LRD' : 193,
	'LSL' : 18,
	'LTL' : 3.18,
	'LUF' : 37,
	'LVL' : 0.64662074757963,
	'LYD' : 4.8,
	'MAD' : 9.79,
	'MDL' : 17,
	'MGA' : 4379,
	'MGF' : 9150,
	'MKD' : 56,
	'MMK' : 2075,
	'MNT' : 2620,
	'MOP' : 8.03,
	'MRO' : 391,
	'MTL' : 0.39498108567387,
	'MUR' : 45,
	'MVR' : 15,
	'MWK' : 1720,
	'MXN' : 17,
	'MYR' : 4.68,
	'MZM' : 63200,
	'MZN' : 63,
	'NAD' : 18,
	'NGN' : 1505,
	'NIO' : 36,
	'NLG' : 2.03,
	'NOK' : 11,
	'NPR' : 131,
	'NZD' : 1.63,
	'OMR' : 0.38377594841305,
	'PAB' : 1,
	'PEN' : 3.67,
	'PGK' : 3.76,
	'PHP' : 58,
	'PKR' : 277,
	'PLN' : 3.91,
	'PTE' : 184,
	'PYG' : 7355,
	'QAR' : 3.56,
	'ROL' : 45713,
	'RON' : 4.57,
	'RSD' : 108,
	'RUB' : 91,
	'RWF' : 1277,
	'SAR' : 3.75,
	'SBD' : 8.37,
	'SCR' : 13,
	'SDD' : 59800,
	'SDG' : 598,
	'SDP' : 2261,
	'SEK' : 11,
	'SGD' : 1.35,
	'SHP' : 0.78703952551207,
	'SIT' : 220,
	'SKK' : 28,
	'SLL' : 19750,
	'SOS' : 549,
	'SRD' : 33,
	'SRG' : 33320,
	'STD' : 22477,
	'SVC' : 8.75,
	'SYP' : 513,
	'SZL' : 18,
	'THB' : 36,
	'TJS' : 11,
	'TMM' : 16750,
	'TMT' : 3.35,
	'TND' : 3.11,
	'TOP' : 2.32,
	'TRL' : 32168418,
	'TRY' : 32,
	'TTD' : 6.64,
	'TWD' : 32,
	'TZS' : 2587,
	'UAH' : 39,
	'UGX' : 3760,
	'USD' : 1,
	'UYU' : 38,
	'UZS' : 12662,
	'VEB' : 3651907631,
	'VEF' : 3651908,
	'VND' : 25451,
	'VUV' : 112,
	'WST' : 2.67,
	'XAF' : 604,
	'XAG' : 0.031347411860134,
	'XAU' : 0.00041128929241299,
	'XCD' : 2.7,
	'XEU' : 0.92005843390143,
	'XOF' : 604,
	'XPD' : 0.00098009826645798,
	'XPF' : 110,
	'XPT' : 0.00093444018680404,
	'YER' : 249,
	'YUN' : 108,
	'ZAR' : 18,
	'ZMK' : 5176,
	'ZWD' : 373
};

/* Amount and currency formatting */
let formatters = {
	// Amounts without currency symbol
	amountFraction: new Intl.NumberFormat( donationForm.locale,
		{ minimumFractionDigits: 2, maximumFractionDigits: 2 }
	),
	amountWhole: new Intl.NumberFormat( donationForm.locale,
		{}
	)
};

// currencyDisplay: 'narrowSymbol' fixes some issues like en-CO showing the ISO code
// but browser support is lacking, so wrap in a try/catch
try {
	formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale,
		{ style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol' }
	);
	formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale,
		{ style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol', minimumFractionDigits: 0 }
	);
} catch(e) {
	formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale,
		{ style: 'currency', currency: donationForm.currency }
	);
	formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale,
		{ style: 'currency', currency: donationForm.currency, minimumFractionDigits: 0 }
	);
}

donationForm.formatCurrency = function( amount ) {
	if ( amount % 1 !== 0 ) { // Not a whole number
		return formatters.currencyFraction.format( amount );
	} else {
		return formatters.currencyWhole.format( amount );
	}
};

donationForm.formatAmount = function( amount ) {
	var formatterOptions, output;
	if ( amount % 1 !== 0 ) { // Not a whole number
		return formatters.amountFraction.format( amount );
	} else {
		return formatters.amountWhole.format( amount );
	}
};

/* Localize the amount errors. Call when initialising form. */
donationForm.localizeErrors = function() {
	var currency = donationForm.currency;

	$('.lp-error-smallamount').text( function( index, oldText ) {
		return oldText.replace( '$1', donationForm.formatAmount( donationForm.minLocal ) + '\xa0' + currency );
	});

	if ( currency === 'USD' ) {
		// we don't need to include the conversion
		$('.lp-error-bigamount').text( function( index, oldText ) {
			return oldText.replace( '($1 $2) ', '' )
						  .replace( '($1&nbsp;$2) ', '' );
		});
	}

	$('.lp-error-bigamount').text( function( index, oldText ) {
		return oldText.replace( '$1', donationForm.formatAmount( donationForm.maxLocal ) )
					  .replace( '$2', currency )
					  .replace( '$3', 'benefactors@wikimedia.org' )
					  .replace( '$4', donationForm.formatAmount( donationForm.maxUSD ) );
	});
};


function adjustHPC() {
	/* Adjust amounts based on highest previous contribution (hpc)
		or most recent contribution (mrc) parameter. Used for emails.
		TODO: split data out? */

	var hpcSet = mw.util.getParamValue('hpcSet');

	// Look for 'hpc' parameter, then 'mrc'
	var hpc = parseFloat( mw.util.getParamValue('hpc') );
	if( isNaN(hpc) ) {
		hpc = parseFloat( mw.util.getParamValue('mrc') );
		if( isNaN(hpc) ) {
			if ( hpcSet ) {
				// Allow using hpcSet even without hpc, for MG appeals
				hpc = 0;
			} else {
				return;
			}
		}
	}

	var currency = donationForm.currency;

	// If changing, please update https://docs.google.com/spreadsheets/d/1e02TsZ_bKDAS1BMVBCdyo9D7RGln_wCGnkg7IF5kU5s/edit
	var radioAmountsData = {
		"USD" : { // also used for CAD, AUD, NZD
			"default" : [
				[    0, [ 2.75,     5,    10,    20,    25,    35,    50 ] ],
				[    5, [    5,    10,    15,    20,    35,    50,   100 ] ],
				[   10, [   10,    15,    20,    25,    35,    50,   100 ] ],
				[   15, [   15,    20,    25,    35,    50,    75,   100 ] ],
				[   20, [   20,    25,    35,    50,    75,   100,   150 ] ],
				[   25, [   25,    30,    40,    50,    75,   100,   150 ] ],
				[   35, [   35,    50,    75,   100,   200,   300,   500 ] ],
				[   50, [   50,    75,   100,   200,   300,   500,   750 ] ],
				[   75, [   75,   100,   150,   250,   500,   750,  1000 ] ],
				[  100, [  100,   150,   250,   500,   750,  1000,  2500 ] ],
				[  150, [  150,   200,   300,   500,   750,  1000,  2000 ] ],
				[  200, [  200,   300,   500,   750,  1000,  2500,  5000 ] ],
				[  500, [  500,   750,  1000,  2500,  5000,  7500, 10000 ] ],
				[ 1000, [ 1000,  2000,  3000,  4000,  5000,  7500, 10000 ] ],
				[ 3000, [ 3000,  4000,  5000,  6000,  7500, 10000, 12000 ] ]
			],
			"FY2425_E1_T11_USD" : [ // Upgrade recurring +1 for lowest ask
				[    0, [ 3.75,     5,    10,    20,    25,    35,    50 ] ],
				[    5, [    5,    10,    15,    20,    35,    50,   100 ] ],
				[   10, [   10,    15,    20,    25,    35,    50,   100 ] ],
				[   15, [   15,    20,    25,    35,    50,    75,   100 ] ],
				[   20, [   20,    25,    35,    50,    75,   100,   150 ] ],
				[   25, [   25,    30,    40,    50,    75,   100,   150 ] ],
				[   35, [   35,    50,    75,   100,   200,   300,   500 ] ],
				[   50, [   50,    75,   100,   200,   300,   500,   750 ] ],
				[   75, [   75,   100,   150,   250,   500,   750,  1000 ] ],
				[  100, [  100,   150,   250,   500,   750,  1000,  2500 ] ],
				[  150, [  150,   200,   300,   500,   750,  1000,  2000 ] ],
				[  200, [  200,   300,   500,   750,  1000,  2500,  5000 ] ],
				[  500, [  500,   750,  1000,  2500,  5000,  7500, 10000 ] ],
				[ 1000, [ 1000,  2000,  3000,  4000,  5000,  7500, 10000 ] ],
				[ 3000, [ 3000,  4000,  5000,  6000,  7500, 10000, 12000 ] ]
			],
			"FY2425_E1_T14_USD" : [ // Upgrade recurring amount dynamically
				[    0, [  2.75,    5,    10,    20,    25,    35,    50 ] ],
				[    5, [  2.75,    5,    10,    20,    25,    35,    50 ] ],
				[   10, [  2.75,   10,    15,    20,    25,    35,    50 ] ],
				[   15, [  3.50,   10,    20,    30,    50,    75,   100 ] ],
				[   20, [  3.75,   10,    25,    35,    50,    75,   100 ] ],
				[   25, [  4.50,   10,    25,    35,    50,    75,   100 ] ],
				[   35, [  6.75,   15,    30,    50,    75,   100,   150 ] ],
				[   75, [ 15.75,   50,    75,   100,   200,   300,   500 ] ],
				[  100, [ 24.75,   50,    75,   100,   200,   300,   500 ] ],
				[  150, [ 44.75,  100,   150,   250,   500,   750,  1000 ] ],
				[  200, [    50,  100,   150,   250,   500,   750,  1000 ] ],
				[  500, [   150,  250,   300,   500,   750,  1000,  2000 ] ],
				[ 1000, [   250,  500,   750,  1000,  2500,  5000, 10000 ] ],
				[ 3000, [   500, 1000,  2000,  3500,  5000,  7500, 10000 ] ]
			],
			"FY2425_E1_T21_USD" : [ // Give less reactivation amount
				[    0, [ 2.75,     5,    10,    20,    25,    35,    50 ] ],
				[    5, [ 2.75,     5,    10,    20,    25,    35,    50 ] ],
				[   10, [    5,    10,    15,    20,    35,    50,   100 ] ],
				[   15, [   10,    15,    20,    25,    35,    50,   100 ] ],
				[   20, [   15,    20,    25,    35,    50,    75,   100 ] ],
				[   25, [   20,    25,    35,    50,    75,   100,   150 ] ],
				[   35, [   25,    30,    40,    50,    75,   100,   150 ] ],
				[   75, [   35,    50,    75,   100,   200,   300,   500 ] ],
				[  100, [   75,   100,   150,   250,   500,   750,  1000 ] ],
				[  150, [  100,   150,   250,   500,   750,  1000,  2500 ] ],
				[  200, [  150,   200,   300,   500,   750,  1000,  2000 ] ],
				[  500, [  200,   300,   500,   750,  1000,  2500,  5000 ] ],
				[ 1000, [  500,   750,  1000,  2500,  5000,  7500, 10000 ] ],
				[ 3000, [ 1000,  2000,  3000,  4000,  5000,  7500, 10000 ] ]
			],
			// Direct Mail - fixed amounts
			"directmail" : [
				[    0, [   25,    35,    50,    100,  150,   250,   300 ] ]
			],
			"directmail250" : [
				[    0, [  250,   300,   500,    750, 1000,  2500,  5000 ] ]
			]
		},
		"EUR" : {
			"default" : [
				[    0, [ 2.50,     5,    10,    20,    25,    35,    50 ] ],
				[    5, [    5,    10,    15,    20,    35,    50,   100 ] ],
				[   10, [   10,    15,    20,    25,    35,    50,   100 ] ],
				[   15, [   15,    20,    25,    35,    50,    75,   100 ] ],
				[   20, [   20,    25,    35,    50,    75,   100,   150 ] ],
				[   25, [   25,    30,    40,    50,    75,   100,   150 ] ],
				[   35, [   35,    50,    75,   100,   200,   300,   500 ] ],
				[   50, [   50,    75,   100,   200,   300,   500,   750 ] ],
				[   75, [   75,   100,   150,   250,   500,   750,  1000 ] ],
				[  100, [  100,   150,   250,   500,   750,  1000,  2500 ] ],
				[  150, [  150,   200,   300,   500,   750,  1000,  2000 ] ],
				[  200, [  200,   300,   500,   750,  1000,  2500,  5000 ] ],
				[  500, [  500,   750,  1000,  2500,  5000,  7500, 10000 ] ],
				[ 1000, [ 1000,  2000,  3000,  4000,  5000,  7500, 10000 ] ],
				[ 3000, [ 3000,  4000,  5000,  6000,  7500, 10000, 12000 ] ]
			],
			"FY2425_E1_T11_EUR" : [ // Upgrade recurring +1 for lowest ask
				[    0, [ 3.50,    5,    10,    20,    25,    35,    50 ] ],
				[    5, [    5,    10,    15,    20,    35,    50,   100 ] ],
				[   10, [   10,    15,    20,    25,    35,    50,   100 ] ],
				[   15, [   15,    20,    25,    35,    50,    75,   100 ] ],
				[   20, [   20,    25,    35,    50,    75,   100,   150 ] ],
				[   25, [   25,    30,    40,    50,    75,   100,   150 ] ],
				[   35, [   35,    50,    75,   100,   200,   300,   500 ] ],
				[   50, [   50,    75,   100,   200,   300,   500,   750 ] ],
				[   75, [   75,   100,   150,   250,   500,   750,  1000 ] ],
				[  100, [  100,   150,   250,   500,   750,  1000,  2500 ] ],
				[  150, [  150,   200,   300,   500,   750,  1000,  2000 ] ],
				[  200, [  200,   300,   500,   750,  1000,  2500,  5000 ] ],
				[  500, [  500,   750,  1000,  2500,  5000,  7500, 10000 ] ],
				[ 1000, [ 1000,  2000,  3000,  4000,  5000,  7500, 10000 ] ],
				[ 3000, [ 3000,  4000,  5000,  6000,  7500, 10000, 12000 ] ]
			],
			"FY2425_E1_T14_EUR" : [ // Upgrade recurring amount dynamically
				[    0, [ 2.50,     5,    10,    20,    25,    35,    50 ] ],
				[    5, [ 2.50,     5,    10,    20,    25,    35,    50 ] ],
				[   10, [ 2.50,    10,    15,    20,    25,    35,    50 ] ],
				[   15, [ 2.50,    10,    20,    30,    50,    75,   100 ] ],
				[   20, [ 3.50,    10,    25,    35,    50,    75,   100 ] ],
				[   25, [ 4.25,    10,    25,    35,    50,    75,   100 ] ],
				[   35, [ 6.25,    15,    30,    50,    75,   100,   150 ] ],
				[   75, [   15,    50,    75,   100,   200,   300,   500 ] ],
				[  100, [   25,    50,    75,   100,   200,   300,   500 ] ],
				[  150, [   45,   100,   150,   250,   500,   750,  1000 ] ],
				[  200, [   50,   100,   150,   250,   500,   750,  1000 ] ],
				[  500, [  150,   250,   300,   500,   750,  1000,  2000 ] ],
				[ 1000, [  250,   500,   750,  1000,  2500,  5000, 10000 ] ],
				[ 3000, [  500,  1000,  2000,  3500,  5000,  7500, 10000 ] ]
			],
			"FY2425_E1_T21_EUR" : [ // Give less reactivation amount
				[    0, [ 2.50,     5,    10,    20,    25,    35,    50 ] ],
				[    5, [ 2.50,     5,    10,    20,    25,    35,    50 ] ],
				[   10, [    5,    10,    15,    20,    35,    50,   100 ] ],
				[   15, [   10,    15,    20,    25,    35,    50,   100 ] ],
				[   20, [   15,    20,    25,    35,    50,    75,   100 ] ],
				[   25, [   20,    25,    35,    50,    75,   100,   150 ] ],
				[   35, [   25,    30,    40,    50,    75,   100,   150 ] ],
				[   75, [   35,    50,    75,   100,   200,   300,   500 ] ],
				[  100, [   75,   100,   150,   250,   500,   750,  1000 ] ],
				[  150, [  100,   150,   250,   500,   750,  1000,  2500 ] ],
				[  200, [  150,   200,   300,   500,   750,  1000,  2000 ] ],
				[  500, [  200,   300,   500,   750,  1000,  2500,  5000 ] ],
				[ 1000, [  500,   750,  1000,  2500,  5000,  7500, 10000 ] ],
				[ 3000, [ 1000,  2000,  3000,  4000,  5000,  7500, 10000 ] ]
			]
		},
		"GBP" : {
			"default" : [
				[    0, [    2,     5,    10,    20,    25,    35,    50 ] ],
				[    5, [    5,    10,    15,    20,    35,    50,   100 ] ],
				[   10, [   10,    15,    20,    25,    35,    50,   100 ] ],
				[   15, [   15,    20,    25,    35,    50,    75,   100 ] ],
				[   20, [   20,    25,    35,    50,    75,   100,   150 ] ],
				[   25, [   25,    30,    40,    50,    75,   100,   150 ] ],
				[   35, [   35,    50,    75,   100,   200,   300,   500 ] ],
				[   50, [   50,    75,   100,   200,   300,   500,   750 ] ],
				[   75, [   75,   100,   150,   250,   500,   750,  1000 ] ],
				[  100, [  100,   150,   250,   500,   750,  1000,  2500 ] ],
				[  150, [  150,   200,   300,   500,   750,  1000,  2000 ] ],
				[  200, [  200,   300,   500,   750,  1000,  2500,  5000 ] ],
				[  500, [  500,   750,  1000,  2500,  5000,  7500, 10000 ] ],
				[ 1000, [ 1000,  2000,  3000,  4000,  5000,  7500, 10000 ] ],
				[ 3000, [ 3000,  4000,  5000,  6000,  7500, 10000, 12000 ] ]
			],
			"FY2425_E1_T11_GBP" : [ // Upgrade recurring +1 for lowest ask
				[    0, [    3,     5,    10,    20,    25,    35,    50 ] ],
				[    5, [    5,    10,    15,    20,    35,    50,   100 ] ],
				[   10, [   10,    15,    20,    25,    35,    50,   100 ] ],
				[   15, [   15,    20,    25,    35,    50,    75,   100 ] ],
				[   20, [   20,    25,    35,    50,    75,   100,   150 ] ],
				[   25, [   25,    30,    40,    50,    75,   100,   150 ] ],
				[   35, [   35,    50,    75,   100,   200,   300,   500 ] ],
				[   50, [   50,    75,   100,   200,   300,   500,   750 ] ],
				[   75, [   75,   100,   150,   250,   500,   750,  1000 ] ],
				[  100, [  100,   150,   250,   500,   750,  1000,  2500 ] ],
				[  150, [  150,   200,   300,   500,   750,  1000,  2000 ] ],
				[  200, [  200,   300,   500,   750,  1000,  2500,  5000 ] ],
				[  500, [  500,   750,  1000,  2500,  5000,  7500, 10000 ] ],
				[ 1000, [ 1000,  2000,  3000,  4000,  5000,  7500, 10000 ] ],
				[ 3000, [ 3000,  4000,  5000,  6000,  7500, 10000, 12000 ] ]
			],
			"FY2425_E1_T14_GBP" : [ // Upgrade recurring amount dynamically
				[    0, [    2,     5,    10,    20,    25,    35,    50 ] ],
				[    5, [    2,     5,    10,    20,    25,    35,    50 ] ],
				[   10, [    2,    10,    15,    20,    25,    35,    50 ] ],
				[   15, [    2,    10,    20,    30,    50,    75,   100 ] ],
				[   20, [    3,    10,    25,    35,    50,    75,   100 ] ],
				[   25, [    4,    10,    25,    35,    50,    75,   100 ] ],
				[   35, [    6,    15,    30,    50,    75,   100,   150 ] ],
				[   75, [   15,    50,    75,   100,   200,   300,   500 ] ],
				[  100, [   20,    50,    75,   100,   200,   300,   500 ] ],
				[  150, [   40,   100,   150,   250,   500,   750,  1000 ] ],
				[  200, [   45,   100,   150,   250,   500,   750,  1000 ] ],
				[  500, [  125,   250,   300,   500,   750,  1000,  2000 ] ],
				[ 1000, [  200,   500,   750,  1000,  2500,  5000, 10000 ] ],
				[ 3000, [  400,  1000,  2000,  3500,  5000,  7500, 10000 ] ]
			],
			"FY2425_E1_T21_GBP" : [ // Give less reactivation amount
				[    0, [    2,     5,    10,    20,    25,    35,    50 ] ],
				[    5, [    2,     5,    10,    20,    25,    35,    50 ] ],
				[   10, [    5,    10,    15,    20,    35,    50,   100 ] ],
				[   15, [   10,    15,    20,    25,    35,    50,   100 ] ],
				[   20, [   15,    20,    25,    35,    50,    75,   100 ] ],
				[   25, [   20,    25,    35,    50,    75,   100,   150 ] ],
				[   35, [   25,    30,    40,    50,    75,   100,   150 ] ],
				[   75, [   35,    50,    75,   100,   200,   300,   500 ] ],
				[  100, [   75,   100,   150,   250,   500,   750,  1000 ] ],
				[  150, [  100,   150,   250,   500,   750,  1000,  2500 ] ],
				[  200, [  150,   200,   300,   500,   750,  1000,  2000 ] ],
				[  500, [  200,   300,   500,   750,  1000,  2500,  5000 ] ],
				[ 1000, [  500,   750,  1000,  2500,  5000,  7500, 10000 ] ],
				[ 3000, [ 1000,  2000,  3000,  4000,  5000,  7500, 10000 ] ]
			]
		},
		"JPY" : [
			[     0, [   500,  1000,  2000,  2500,   4000,   5000,  10000 ] ],
			[  1000, [  1000,  1500,  2500,  4000,   5000,  10000,  15000 ] ],
			[  1500, [  1500,  2000,  3000,  4000,   5000,  10000,  15000 ] ],
			[  2000, [  2000,  2500,  3500,  5000,   7500,  10000,  25000 ] ],
			[  2500, [  2500,  3500,  5000,  7500,  10000,  15000,  25000 ] ],
			[  3000, [  3000,  4000,  5000,  7500,  10000,  15000,  25000 ] ],
			[  2500, [  2500,  5000,  7500, 10000,  20000,  30000,  50000 ] ],
			[  2500, [  2500,  5000,  7500, 10000,  20000,  50000, 100000 ] ],
			[  5000, [  5000, 10000, 15000, 20000,  35000,  50000, 100000 ] ],
			[ 10000, [ 10000, 25000, 50000, 75000, 100000, 150000, 200000 ] ]
		],
		"SEK" : [
			[   0, [ 30, 100, 150, 200, 500, 750, 1000 ] ],
			[  50, [ 50, 100, 150, 200, 300, 750, 1000 ] ],
			[ 200, [ 50, 100, 200, 300, 500, 750, 1000 ] ]
		]
	};
	radioAmountsData.AUD = radioAmountsData.USD;
	radioAmountsData.CAD = radioAmountsData.USD;
	radioAmountsData.NZD = radioAmountsData.USD;

	// Major gifts appeals, hacky but this is easier than adding a load of new forms to maintain
	var currencyList = [ 'USD', 'CAD', 'AUD', 'NZD', 'GBP', 'EUR' ]; // close enough
	for ( let i = 0; i < currencyList.length; i++ ) {
		radioAmountsData[ currencyList[i] ].MG_2024_500 = [ [ 0, [ 500, 750, 1000, 1250, 1500, 1750, 2000 ] ] ];
		radioAmountsData[ currencyList[i] ].MG_2024_650 = [ [ 0, [ 650, 750, 1000, 1250, 1500, 1750, 2000 ] ] ];
	}

	var appealAmountsData = {
		"USD" : [ // also used for CAD, AUD, NZD, GBP, EUR
			[   0, [   5,  10,  20 ] ],
			[  10, [  10,  20,  50 ] ],
			[  20, [  20,  30,  50 ] ],
			[  35, [  20,  30,  50 ] ],
			[  50, [  20,  50, 100 ] ],
			[  75, [  50,  75, 100 ] ],
			[ 100, [  75, 100, 150 ] ],
			[ 150, [  75, 100, 200 ] ],
			[ 200, [ 100, 200, 300 ] ]
		],
		"JPY" : [
			[   0, [  300,   500,  1000 ] ],
			[   3, [  500,  1000,  1500 ] ],
			[   5, [ 1000,  1500,  2000 ] ],
			[  10, [ 1500,  2000,  5000 ] ],
			[  20, [ 2000,  3000,  5000 ] ],
			[  50, [ 2000,  5000, 10000 ] ],
			[ 100, [ 5000, 10000, 15000 ] ]
		],
		"SEK" : [
			[   0, [  20,  50,  100 ] ],
			[   3, [  30,  50,  100 ] ],
			[   5, [  50, 100,  150 ] ],
			[  15, [ 100, 150,  200 ] ],
			[  23, [ 100, 200,  300 ] ],
			[  38, [ 100, 200,  500 ] ],
			[  75, [ 100, 500,  750 ] ],
			[ 112, [ 100, 500, 1000 ] ]
		]
	};
	appealAmountsData.AUD = appealAmountsData.USD;
	appealAmountsData.CAD = appealAmountsData.USD;
	appealAmountsData.GBP = appealAmountsData.USD;
	appealAmountsData.NZD = appealAmountsData.USD;
	appealAmountsData.EUR = appealAmountsData.USD;

	// Radio button amounts
	var radioAmounts = pickAmountArray( radioAmountsData, currency, hpc, hpcSet );
	if ( radioAmounts.length ) {
		// Change buttons
		for (var j = 0; j < radioAmounts.length; j++) {
			var $radio = $("#input_amount_" + j);
			var $label = $("label[for='input_amount_" + j + "']");
			$radio.val( radioAmounts[j] );
			$label.text( donationForm.formatCurrency( radioAmounts[j] ) );
		}
	}

	// Appeal amounts
	var appealAmounts = pickAmountArray( appealAmountsData, currency, hpc, hpcSet );
	if ( appealAmounts.length ) {
		var appealAmountString = appealAmounts.map( donationForm.formatCurrency ).join( ', ');
		$('.consider-amounts').html(appealAmountString);
	}

}

function pickAmountArray( data, currency, hpc, hpcSet ) {
	/**
	 * Choose the amounts for radio buttons / appeal based on hpc
	 * @param {Object} data
	 * @param {String} currency
	 * @param {Number} hpc
	 * @param {String} hpcSet
	 * @return {Array} Array of amounts (as numbers)
	 */

	var set, amounts;

	if ( !(currency in data) ) {
		return [];
	}

	if ( $.isArray(data[currency]) ) {
		// No variant sets
		set = data[currency];
	} else {
		// We need to go deeper. Check the variants.
		if ( hpcSet in data[currency] ) {
			set = data[currency][hpcSet];
		} else {
			set = data[currency]['default'];
		}
	}

	// Find correct amount array for this hpc
	for (var i = 0; i < set.length; i++) {
		if ( set[i][0] > hpc ) {
			break;
		}
		amounts = set[i][1];
	}

	return amounts;

}

function preSelect() {
	/* Check for a 'preSelect' url parameter, and select that option.
	   If there isn't an option, add it to the "Other" box and select that */
	var preSelectAmount = parseFloat( mw.util.getParamValue('preSelect') );
	if ( preSelectAmount > 0 ) {
		var $preSelectOption = $('input[name="amount"][value="' + preSelectAmount + '"]');
		if ( $preSelectOption.length ) {
			// Select existing input
			$preSelectOption.prop('checked', true);
		} else {
			$('#input_amount_other_box').val( preSelectAmount );
			$('#input_amount_other').prop('checked', true);
		}
		donationForm.updateFeeDisplay();
	}
}

function addCardTypesClass(country) {
	/**
	 * Add card types class to credit card button, so we can show correct logos
	 * Banner equivalent: https://meta.wikimedia.org/wiki/MediaWiki:FundraisingBanners/LocalizeJS-2017.js
	 * @param {String} country ISO code
	 */
	var cardTypes = {
		// Big 6
		'US' : 'vmad',
		'CA' : 'vma',
		'GB' : 'vmaj',
		'IE' : 'vmaj',
		'AU' : 'vmaj',
		'NZ' : 'vma',
		// Euro countries
		'AT' : 'vmaj',
		'BE' : 'vmaj',
		'ES' : 'vmaj',
		'FR' : 'vma', // Adyen - Carte Bancaire was removed
		'IT' : 'vmaj',
		'LU' : 'vmaj',
		'LV' : 'vma',
		'NL' : 'vmaj',
		'PT' : 'vmaj',
		'SK' : 'vmaj',
		'GR' : 'vma',
		// Others
		'CZ' : 'vmad',
		'DK' : 'vma',
		'HU' : 'vma',
		'IL' : 'vmad', // Adyen
		'JP' : 'vmaj',
		'MY' : 'vmaj',
		'NO' : 'vma',
		'PL' : 'vma',
		'RO' : 'vma',
		'SE' : 'vma',
		'UA' : 'vma', // Adyen
		'ZA' : 'vm',
		'ZZ' : 'vmad' // For testing
	};
	if ( cardTypes[country] ) {
		$('.paymentmethod-cc').addClass('cctypes-' + cardTypes[country] );
		$('.cc-text-label').addClass('sr-only');
	}
}

/* Form functions */
function clearOther(box) {
	document.getElementById('input_amount_other').checked = true;
	box.value = "";
}

function selectOther() {
	document.getElementById('input_amount_other').checked = true;
}

function selectAmount() {
	$('#input_amount_other_box').val('');
}

/* -- Moved from Template:2012FR/Form-section/Processing/Default -- */
/**
 * Validate form, and prep most of the parameters
 *
 * @param  {string} paymentMethod        - method e.g. 'cc', 'paypal'
 * @param  {string} paymentSubMethod     - submethod e.g. 'rtbt_ideal' (a submethod of 'rtbt')
 * @param  {string} skipAmountValidation - skip validating amount for PayPal forced to USD
 */
donationForm.redirectPayment = function( paymentMethod, paymentSubMethod, skipAmountValidation ) {

	if ( donationForm.validate( skipAmountValidation ) ) {

		var params = {};

		params.currency = donationForm.currency;
		params.country = donationForm.country;

		// Overrides for specific cc gateways
		if ( paymentMethod === 'cc-adyen' ) {
			params.payment_method = 'cc';
			params.gateway = 'adyen';
		} else if ( paymentMethod === 'cc-dlocal' ) {
			params.payment_method = 'cc';
			params.gateway = 'astropay';
		} else {
			params.payment_method = paymentMethod;
		}

		if ( params.payment_method === 'cc' && params.country === 'ZA' ) {
			params.gateway = 'astropay';
		}

		if ( paymentSubMethod ) {
			params.payment_submethod = paymentSubMethod;
		}

		let frequency = donationForm.getFrequency();
		if ( frequency === 'monthly' ) {
			params.recurring = '1';
			params.frequency_unit = 'month';
		} else if ( frequency === 'annual' ) {
			params.recurring = '1';
			params.frequency_unit = 'year';
		}

		params.uselang = mw.config.get('wgPageContentLanguage'); // see T281285 for why not wgUserLanguage

		if ( params.uselang === 'pt' && params.country === 'BR' ) {
			params.uselang = 'pt-br';
		}
		if ( params.uselang === 'es' &&
			( params.country === 'AR' || params.country === 'CL' ||
			  params.country === 'CO' || params.country === 'MX' ||
			  params.country === 'PE' || params.country === 'UY' ||
			  params.country === 'US' )
		) {
			params.uselang = 'es-419';
		}

		var amount = donationForm.getAmount();
		if ( $('#ptf-checkbox').prop('checked') ) {
			amount = amount + donationForm.calculateFee( amount );
			donationForm.extraData.ptf = 1;
		}
		params.amount = amount;

		// Email optin
		if ( $('input[name="opt_in"]').length > 0 ) {
			var opt_inValue = $('input[name="opt_in"]:checked').val();
			params.opt_in = opt_inValue; // donationForm.validate() already checked it's 1 or 0
		}

		if ( mw.util.getParamValue( 'pym_variant' ) ) {
			params.variant = mw.util.getParamValue( 'pym_variant' );
		}
		if ( params.recurring && params.variant && params.variant.match( /monthlyConvert/ ) ) {
			// Post-payments monthly convert makes no sense if it's already recurring
			// Avoid things like T312905
			delete params.variant;
		}

		// TODO: refactor this to a list of parameters to pass unchanged
		//		 or just pass everything by default?
		if ( mw.util.getParamValue( 'pym_appeal' ) ) {
			params.appeal = mw.util.getParamValue( 'pym_appeal' );
		}
		// https://phabricator.wikimedia.org/T381405
		if ( mw.util.getParamValue( 'contact_id' ) ) {
			params.contact_id = mw.util.getParamValue( 'contact_id' );
		}
		if ( mw.util.getParamValue( 'contact_hash' ) ) {
			params.contact_hash = mw.util.getParamValue( 'contact_hash' );
		}
		// SMS
		if ( mw.util.getParamValue( 'recipient_id' ) ) {
			params.recipient_id = mw.util.getParamValue( 'recipient_id' );
		}

		// Monthly convert
		if ( mc ) { // check just in-case this wasn't loaded for some reason
			mc.main( params, donationForm.finalStep );
		} else {
			donationForm.finalStep( params );
		}

	} else {
		donationForm.extraData.validateError = 1; // Flag they had an error, even if fixed later
	}

	return false; // don't submit if called by a button
};

/**
 * Build final tracking parameters, and submit to payments
 * @param  {Object} params
 */
donationForm.finalStep = function( params ) {

	var url = new URL('https://payments.wikimedia.org/index.php/Special:GatewayChooser');

	// Skip form chooser for Apple Pay / Google Pay
	if ( params.payment_method === 'apple' || params.payment_method === 'google' ) {
		url = new URL('https://payments.wikimedia.org/index.php/Special:AdyenCheckoutGateway');
	}

	// Skip form chooser for Venmo
	if ( params.payment_method === 'venmo' ) {
		url = new URL('https://payments.wikimedia.org/index.php/Special:BraintreeGateway');
	}

	donationForm.extraData.time = Math.round( (Date.now() - donationForm.loadedTime)/1000 );

	// Tracking data
	params.wmf_medium   = mw.util.getParamValue( 'wmf_medium' ) || mw.util.getParamValue( 'utm_medium' );
	params.wmf_campaign = mw.util.getParamValue( 'wmf_campaign' ) || mw.util.getParamValue( 'utm_campaign' );
	params.wmf_source   = donationForm.buildTrackingSource( params );
	params.wmf_key      = donationForm.buildTrackingKey( donationForm.extraData );
	if ( document.referrer ) { // TODO: do we need this?
		// Strip protocol to stop firewall complaining
		params.referrer = document.referrer.replace(/https?:\/\//i, '');
	}

	for ( var key of Object.keys( params ) ) {
		url.searchParams.set( key, params[key] );
	}

	if ( window.top !== window.self ) {
		// In a frame, open payments in a new tab
		window.open( url.toString() );
	} else {
		window.location.href = url.toString();
	}
};

/**
 * Build a wmf_source value, including the landing page info.
 *
 * Own function so it can be overriden for weird tests
 *
 * @param  {Object} params
 * @return {string} wmf_source
 */
donationForm.buildTrackingSource = function( params ) {

	var wmf_source = mw.util.getParamValue( 'wmf_source' ) || mw.util.getParamValue( 'utm_source' );
	wmf_source += '.';

	var fullDottedPaymentMethod = params.payment_method;
	if ( params.recurring ) {
		fullDottedPaymentMethod = 'r' + fullDottedPaymentMethod;
	}
	if ( params.payment_submethod ) {
		fullDottedPaymentMethod = fullDottedPaymentMethod + '.' + params.payment_submethod;
	}

	/* Get URL parameter, but remove parts using old format. Allow fallback to a default value */
	var getParam = function( param, removeText, dflt ) {
		if ( mw.util.getParamValue( param ) ) {
			return mw.util.getParamValue( param ).replace( removeText, '' );
		} else {
			return dflt;
		}
	};

	/* The landing page info, separated by ~. This mostly exists for legacy reasons */
	wmf_source += getParam( 'template'            , 'Lp-layout'            , 'default' ) + '~';
	wmf_source += getParam( 'appeal-template'     , 'Appeal-template-'     , 'default' ) + '~';
	wmf_source += getParam( 'appeal'              , 'Appeal-'              , 'default' ) + '~';
	wmf_source += getParam( 'form-template'       , 'Form-template-'       , 'default' ) + '~';
	wmf_source += getParam( 'form-countryspecific', 'Form-countryspecific-', 'control' );

	wmf_source += '.' + fullDottedPaymentMethod;

	return wmf_source;

};

/**
 * Build a string for wmf_key from extra tracking data
 *
 * @param  {Object} data
 * @return {string} wmf_key
 */
donationForm.buildTrackingKey = function(data) {
	var existingKey = mw.util.getParamValue( 'wmf_key' ) || mw.util.getParamValue( 'utm_key' ),
		dataArray = [];

	if ( existingKey ) {
		dataArray.push( existingKey );
	}
	for (var key in data) {
		if (data.hasOwnProperty(key)) {
			dataArray.push( key + '_' + data[key] );
		}
	}
	return dataArray.join('~');
};

/* Return amount selected or input */
donationForm.getAmount = function() {
	var form = document.forms.donateForm,
		amount = null;
	donationForm.extraData.otherAmt = 0;

	// If there are some amount radio buttons, then look for the checked one
	if ( form.amount ) {
		for ( var i = 0; i < form.amount.length; i++ ) {
			if ( form.amount[i].checked ) {
				amount = parseFloat( form.amount[i].value );
			}
		}
	}
	// Check the "other" amount box
	if ( document.getElementById('input_amount_other').checked ) {
		amount = donationForm.parseOtherAmount( form.input_amount_other_box.value );
		donationForm.extraData.otherAmt = 1;
	}

	return amount;

};

/**
 * Parse Other field value into amount
 *
 * Does some awful regex stuff to rm symbols and turn the string into a number
 * Remember some locales flip . & , for decimal point/thousands separator
 *
 * @param  {string} value Value of "Other" field
 * @return {float}        Float with amount, or 0 if NaN
 */
donationForm.parseOtherAmount = function( value ) {
	var amount;

	value = value.replace(/[,.](\d)$/, '\:$10');
	value = value.replace(/[,.](\d)(\d)$/, '\:$1$2');
	value = value.replace(/[\$£€¥,.]/g, '');
	value = value.replace(/:/, '.');

	amount = parseFloat( value );
	if ( isNaN( amount ) ) {
		return 0;
	} else {
		return amount;
	}
};

/**
 * Validate the form.
 */
donationForm.validate = function( skipAmountValidation ) {

	var error = false;
	var form = document.forms.donateForm;

	// Reset all errors
	$('.lp-haserror').removeClass('lp-haserror');
	$('.lp-error').hide();

	if ( !skipAmountValidation && !donationForm.validateAmount() ) {
		error = true;
	}

	if ( form.opt_in ) {
		if ( $('input[name="opt_in"]:checked').val() === undefined ) {
			$('#error-optin').show().focus();
			error = true;
		} else {
			$('#error-optin').hide();
		}
	}

	return !error;
};

/**
 * Check if selected amount is valid i.e. a positive number, between minimum and maximum.
 * If not, show an error and return false.
 */
donationForm.validateAmount = function() {

	var amount = donationForm.getAmount();

	if ( amount === null || isNaN(amount) || amount <= 0 || amount < donationForm.minLocal ) {
		$('.amount-options').addClass('lp-haserror');
		$('.lp-error-bigamount').hide();
		$('.lp-error-smallamount').show().focus();
		return false;
	} else if ( amount > donationForm.maxLocal ) {
		$('.amount-options').addClass('lp-haserror');
		$('.lp-error-bigamount').show().focus();
		return false;
	} else {
		$('.amount-options').removeClass('lp-haserror');
		$('.lp-error-smallamount, .lp-error-bigamount').hide();
		return true;
	}

};

donationForm.getFrequency = function() {
	return document.forms.donateForm.dataset.frequency || 'onetime';
};

donationForm.setFrequency = function( frequency ) {
	// TODO: add some validation to reject invalid frequency values
	let form = document.forms.donateForm;

	form.frequency.value = frequency; // change input
	form.dataset.frequency = frequency;
};

/* Wrapper for compatibility with old forms */
donationForm.toggleMonthly = function( monthly ) {
	if ( monthly ) {
		donationForm.setFrequency( 'monthly' );
	} else {
		donationForm.setFrequency( 'onetime' );
	}
};

donationForm.updateFeeDisplay = function() {
	var selectedAmount = donationForm.getAmount(),
		feeAmount = donationForm.calculateFee( selectedAmount ),
		feeText;

	feeText = donationForm.formatCurrency( feeAmount );

	$('.ptf label span').text( feeText );
	if ( selectedAmount + feeAmount <= donationForm.maxLocal ) {
		$('.ptf').slideDown();
	}
};

/**
 * Calculate approximate transaction fee on given amount
 * @param  {number} amount
 * @return {number}        Rounded to 2 decimal places
 */
donationForm.calculateFee = function( amount ) {

	// Minimum fee/PTF amounts. Default is 0.35.
	// Updated 2019-05-21 to approx 0.35 USD equivalent
	var feeMinimums = {
		'DKK' : 2,
		'HUF' : 100,
		'ILS' : 1.2,
		'INR' : 4,
		'JPY' : 35,
		'MYR' : 1,
		'NOK' : 3,
		'PLN' : 1.35,
		'CZK' : 7.5,
		'RON' : 1.5,
		'SEK' : 3,
		'UAH' : 10,
		'ZAR' : 5,
		// Latin America // Updated 2024-08-22 to approx 0.35 USD equivalent
		'BRL' : 1.75,
		'ARS' : 300,
		'CLP' : 300,
		'COP' : 1400,
		'MXN' : 6,
		'PEN' : 1.2,
		'UYU' : 14
	};

	var feeMultiplier = 0.04,
		feeMinimum = feeMinimums[ donationForm.currency ] || 0.35,
		feeAmount = amount * feeMultiplier;

	if ( feeAmount < feeMinimum ) {
		feeAmount = feeMinimum;
	}
	return parseFloat( feeAmount.toFixed(2) );
};


donationForm.initOptin = function() {
	$('.optin-options').on('change', function(e) {

		$('#error-optin').hide();

		// Only do all this if we have translated prompts
		if ( $('.optin-no-prompt').data('is-translated') === 'yes' ) {
			if ( e.target.id === 'optin-no' ) {
				$('.optin-no-prompt').removeClass('is-positive');
				if ( !$('.optin-no-prompt').is(':visible') ) {
					$('.optin-no-prompt').slideDown();
				}
			} else {
				$('.optin-no-prompt').addClass('is-positive');
			}
		}
	});
};

/**
 * Block typing letters and symbols in given input. Used for Other amount inputs
 *
 * If we don't do this, Safari allows typing them and then chokes on submit
 * https://phabricator.wikimedia.org/T118741, https://phabricator.wikimedia.org/T173431
 *
 * @param  {Element} inputElement The element to block typing on
 */
donationForm.otherInputControl = function( inputElement ) {
	if ( inputElement ) {
		inputElement.onkeypress = function(e) {
			// Allow special keys in Firefox
			if ((e.code == 'ArrowLeft') || (e.code == 'ArrowRight') ||
				(e.code == 'ArrowUp') || (e.code == 'ArrowDown') ||
				(e.code == 'Delete') || (e.code == 'Backspace')) {
				return;
			}
			var chr = String.fromCharCode(e.which);
			if ('0123456789., '.indexOf(chr) === -1) {
				return false;
			}
		};
	}
};

/**
 * Should we show Apple Pay?
 *
 * Note there is a ~500ms delay in Safari when checking, so only call this if needed
 *
 * @param  {string} country
 * @return {boolean}
 */
donationForm.shouldShowApplePay = function ( country ) {
	if ( location.search.match('forceApplePay') ) {
		return true;
	}
	if ( window.ApplePaySession ) {
		if ( ApplePaySession.canMakePayments() ) {
			return true;
		}
	}
	return false;
};

/*
Based on github:braintree/braintree-web/src/venmo/shared/supports-venmo.js
See also on meta: MediaWiki:FundraisingBanners/VenmoBrowserCheck.js
*/
donationForm.isVenmoSupported = function(options) {
  var options = options || {
	allowNewBrowserTab: false,
	allowWebviews: true,
	allowDesktop: true,
	allowDesktopWebLogin: true
  };
  var ua = window.navigator.userAgent;

  var merchantAllowsReturningToNewBrowserTab,
	merchantAllowsWebviews,
	merchantAllowsDesktopBrowsers;
  var isMobileDevice = isAndroid() || isIos();
  var isAndroidChrome = isAndroid() && isChrome();
  var isMobileDeviceThatSupportsReturnToSameTab = isIosSafari() || isAndroidChrome;
  var isKnownUnsupportedMobileBrowser = isIosChrome() || isFacebookOwnedBrowserOnAndroid() || isSamsung();

  options = options || {};
  // NEXT_MAJOR_VERSION allowDesktop will default to true, but can be opted out
  merchantAllowsDesktopBrowsers =
	(options.allowDesktopWebLogin || options.allowDesktop) === true;
  merchantAllowsReturningToNewBrowserTab = options.hasOwnProperty(
	"allowNewBrowserTab"
  )
	? options.allowNewBrowserTab
	: true;
  // NEXT_MAJOR_VERSION webviews are not supported, except for the case where
  // the merchant themselves is presenting venmo in a webview using the deep
  // link url to get back to their app. For the next major version, we should
  // just not have this option and instead require the merchant to determine
  // if the venmo button should be displayed when presenting it in the
  // merchant's app via a webview.
  merchantAllowsWebviews = options.hasOwnProperty("allowWebviews")
	? options.allowWebviews
	: true;

  if (isKnownUnsupportedMobileBrowser) {
	return false;
  }

  if (
	!merchantAllowsWebviews &&
	(isAndroidWebview() || isIosWebview())
  ) {
	return false;
  }

  if (!isMobileDevice) {
	return merchantAllowsDesktopBrowsers;
  }

  if (!merchantAllowsReturningToNewBrowserTab) {
	return isMobileDeviceThatSupportsReturnToSameTab;
  }

  return isMobileDevice;

  /* -- functions mostly from github:braintree/browser-detection library -- */

  function isAndroid() {
	return /Android/i.test(ua);
  }

  function isIos(checkIpadOS = true) {
	const iOsTest = /iPhone|iPod|iPad/i.test(ua);
	return checkIpadOS ? iOsTest || isIpadOS() : iOsTest;
  }

  function isIpadOS() {
	// "ontouchend" is used to determine if a browser is on an iPad, otherwise
	// user-agents for iPadOS behave/identify as a desktop browser
	return /Mac|iPad/i.test(ua) && "ontouchend" in window.document;
  }

  function isEdge() {
	return ua.indexOf("Edge/") !== -1 || ua.indexOf("Edg/") !== -1;
  }

  function isSamsung() {
	return /SamsungBrowser/i.test(ua);
  }

  function isDuckDuckGo() {
	return ua.indexOf("DuckDuckGo/") !== -1;
  }

  function isOpera() {
	return (
	  ua.indexOf("OPR/") !== -1 ||
	  ua.indexOf("Opera/") !== -1 ||
	  ua.indexOf("OPT/") !== -1
	);
  }

  function isSilk() {
	return ua.indexOf("Silk/") !== -1;
  }

  function isChrome() {
	return (
	  (ua.indexOf("Chrome") !== -1 || ua.indexOf("CriOS") !== -1) &&
	  !isEdge() &&
	  !isSamsung() &&
	  !isDuckDuckGo() &&
	  !isOpera() &&
	  !isSilk()
	);
  }

  function isIosFirefox() {
	return /FxiOS/i.test(ua);
  }

  function isWebkit() {
	const webkitRegexp = /webkit/i;
	return webkitRegexp.test(ua);
  }

  function isIosChrome() {
	return ua.indexOf("CriOS") > -1;
  }

  function isFacebook() {
	return ua.indexOf("FBAN") > -1;
  }

  function isIosSafari() {
	return (
	  isIos() &&
	  isWebkit() &&
	  !isIosChrome() &&
	  !isIosFirefox() &&
	  !isFacebook()
	);
  }

  function isFacebookOwnedBrowserOnAndroid() {
	var e = ua.toLowerCase();
	return -1 < e.indexOf("huawei") && -1 < e.indexOf("fban") || isAndroid() && (-1 < e.indexOf("fb_iab") || -1 < e.indexOf("instagram"));
  }

  function isSamsungBrowser() {
	return /SamsungBrowser/i.test(ua);
  }

  function isAndroidWebview() {
	return isAndroid() && -1 < ua.toLowerCase().indexOf("wv");
  }

  function isGoogleSearchApp() {
	return /\bGSA\b/.test(ua);
  }

  function isIosGoogleSearchApp() {
	return isIos() && isGoogleSearchApp();
  }

  function isIosWebview() {
	if (isIos()) {
	  // The Google Search iOS app is technically a webview and doesn't support popups.
	  if (isIosGoogleSearchApp()) {
		return true;
	  }
	  // Historically, a webview could be identified by the presence of AppleWebKit and _no_ presence of Safari after.
	  return /.+AppleWebKit(?!.*Safari)/i.test(ua);
	}
	return false;
  }
};

/* End form functions */

$(document).ready(function() {

	mw.loader.using( ['mediawiki.util'] ).done( function() {

		var form = document.forms.donateForm;

		// Minimum amount is usually about 1 USD
		donationForm.minLocal = donationForm.currencyRates[ donationForm.currency ];
		donationForm.minLocal = Math.ceil( donationForm.minLocal * 100 ) / 100; // Round it up
		donationForm.maxUSD   = 25000;
		donationForm.maxLocal = Math.floor( donationForm.currencyRates[ donationForm.currency ] * donationForm.maxUSD );

		// Overrides for India
		if ( donationForm.currency === 'INR' ) {
			donationForm.minLocal = 10;
			// Until https://phabricator.wikimedia.org/T370583 fixed?
			donationForm.maxUSD   = 3000;
			donationForm.maxLocal = 250000;
		}

		// Block typing symbols in Other field
		donationForm.otherInputControl( document.getElementById('input_amount_other_box') );

		// Clear errors and update fee when selected/entered
		$('.amount-options').on( 'input change', function() {
			// Ideally we would validate the amount, but this causes issues with focus
			$('.amount-options .lp-error').hide();
			donationForm.updateFeeDisplay();
		});

		// Disable submitting form with Enter key
		$('form[name="donateForm"]').on('keypress', function(e) {
			var code = ( e.keyCode ? e.keyCode : e.which );
			if ( code == 13 ) {
				e.preventDefault();
			}
		});

		// But allow Enter on buttons
		$('.payment-method-button').keyup(function(e) {
			if (event.keyCode === 13) {
				e.target.click();
			}
		});

		if ( form ) {

			// hide frequency options for some countries
			if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) !== -1 ) {
				$('#frequency_onetime').prop('checked', true);
				$('.frequency-options, #cancel-monthly, #donate-recurring-smallprint').hide();
			}

			if ( donationForm.noRecurringPaypalCountries.indexOf( donationForm.country ) !== -1 ) {
				$( '.paymentmethod-pp, .paymentmethod-pp-usd' ).addClass( 'not-monthly-capable' );
			}

			// Format amounts on buttons
			$( '.amount-options li' ).each( function( index ) {
				let amount = this.querySelector( 'input' ).value;
				if ( amount !== 'Other' ) {
					this.querySelector( 'label' ).innerText = donationForm.formatCurrency( amount );
				}
			});

			addCardTypesClass( donationForm.country );

			// Only show Amazon for links from Ways to give
			if (
				mw.util.getParamValue( 'wmf_source' ) === 'Waystogive' ||
				mw.util.getParamValue( 'wmf_source' ) === 'Ways_to_Give'
			) {
				$('.paymentmethod-amazon').show();
			}

			// Apple Pay
			if ( $('.paymentmethod-applepay').length > 0 ) {
				if ( !donationForm.shouldShowApplePay( donationForm.country ) ) {
					$('.paymentmethod-applepay').remove();
				}
			}

			// Venmo browser check
			if ( $('.paymentmethod-venmo').length > 0 ) {
				if ( !donationForm.isVenmoSupported() || donationForm.country !== 'US' ) {
					$('.paymentmethod-venmo').remove();
				}
			}

			// Dumb hack to remove ACH for Portal test against Fundraise Up
			if ( mw.util.getParamValue( 'wmf_source' ) === 'portalBanner_en6C_2024_overlayBanner4WikiForm' ) {
				$('.paymentmethod-ach').remove();
			}

		}

		// Links open in new tab
		$('.links-in-new-tab a').attr('target', '_blank');

		// Disable logo link
		$('#p-logo a').attr( { href: '#', title: '' } );

		// These don't need to be tabbable on the landing page
		$('#searchInput, .mw-jump-link').attr('tabindex', '-1');

		$('.input_amount_other').click(function() {
			$('#input_amount_other_box').focus();
		});

		// Allow preselecting frequency if possible
		if (
			donationForm.noRecurringCountries.indexOf( donationForm.country ) === -1
			&& mw.util.getParamValue( 'utm_medium' ) !== 'endowment'
			&& mw.util.getParamValue( 'wmf_medium' ) !== 'endowment'
		) {
			if ( mw.util.getParamValue( 'frequency' ) ) {
				donationForm.setFrequency( mw.util.getParamValue( 'frequency' ) );
			} else if ( mw.util.getParamValue('monthly') && mw.util.getParamValue('monthly') !== '0' ) {
				// old method with "monthly=" parameter
				donationForm.setFrequency( 'monthly' );
			} else {
				donationForm.setFrequency( 'onetime' );
			}
		}

		donationForm.initOptin();

		try {
			adjustHPC();
			preSelect(); // Make sure to do this *after* other fiddling with values
			donationForm.localizeErrors();
		}
		finally {
			$('.frb-monthly-pitch, .frb-monthly-pitch-thanks').appendTo('.frequency-options');
			$('.ptf').appendTo('.amount-options');
			$('.optin-options').insertAfter('.amount-options');
			$('.consider-amounts').show();
			$('#actual-form').show();
			$('#actual-form-loading').hide();
		}

	});

});