MediaWiki:DonationFormSandbox.js: Difference between revisions

From Donate
Jump to navigation Jump to search
Content deleted Content added
No edit summary
base64 decode recipient_id if needed
 
(46 intermediate revisions by 2 users not shown)
Line 7: Line 7:


donationForm.loadedTime = Date.now();
donationForm.loadedTime = Date.now();
donationForm.extraData = {
donationForm.extraData = {};
'vw' : window.innerWidth,
'vh' : window.innerHeight
};


donationForm.country = mw.util.getParamValue('country').toUpperCase();
if ( navigator.brave !== undefined ) { // T283367
try {
donationForm.extraData.brave = '1';
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
// Don't offer recurring at all in these countries
donationForm.noRecurringCountries = [ 'AR', 'CL', 'CO', 'MX', 'PE', 'UY', 'BR', 'IN' ];
donationForm.noRecurringCountries = [ 'AR', 'IN' ];


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

donationForm.minimums = {
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
'ADF' : 5.45,
// Updated 2024-07-31
'ADP' : 138,
'AED' : 3.67,
'ADF' : 6.04,
'AFA' : 77,
'ADP' : 153,
'AFN' : 77,
'AED' : 3.67,
'ALL' : 102,
'AFA' : 70,
'AMD' : 522,
'AFN' : 70,
'ANG' : 1.79,
'ALL' : 90,
'AOA' : 622,
'AMD' : 368,
'AON' : 622,
'ANG' : 1.79,
'ARS' : 90,
'AOA' : 844,
'ATS' : 11,
'AON' : 844,
'AUD' : 1.29,
'ARS' : 887,
'AWG' : 1.79,
'ATS' : 13,
'AZM' : 8500,
'AUD' : 1.5,
'AZN' : 1.7,
'AWG' : 1.79,
'BAM' : 1.63,
'AZM' : 8500,
'BBD' : 2,
'AZN' : 1.7,
'BDT' : 83,
'BAM' : 1.8,
'BEF' : 34,
'BBD' : 2,
'BGL' : 1.63,
'BDT' : 116,
'BGN' : 1.63,
'BEF' : 37,
'BHD' : 0.37503712235129,
'BGL' : 1.8,
'BIF' : 1927,
'BGN' : 1.8,
'BMD' : 1,
'BHD' : 0.37355757356689,
'BND' : 1.33,
'BIF' : 2842,
'BOB' : 6.74,
'BMD' : 1,
'BRL' : 5.62,
'BND' : 1.35,
'BSD' : 1,
'BOB' : 6.71,
'BTN' : 73,
'BRL' : 5.1,
'BWP' : 11,
'BSD' : 1,
'BYR' : 26065,
'BTN' : 83,
'BZD' : 1.97,
'BWP' : 13,
'CAD' : 1.26,
'BYR' : 32642,
'CDF' : 1975,
'BZD' : 1.98,
'CHF' : 0.92373627643191,
'CAD' : 1.36,
'CLP' : 729,
'CDF' : 2786,
'CNY' : 6.47,
'CHF' : 0.9094629289448,
'COP' : 3660,
'CLP' : 890,
'CRC' : 601,
'CNY' : 7.23,
'CUC' : 1,
'COP' : 3803,
'CUP' : 25,
'CRC' : 498,
'CVE' : 92,
'CUC' : 1,
'CYP' : 0.4866220993031,
'CUP' : 25,
'CZK' : 22,
'CVE' : 101,
'DEM' : 1.63,
'CYP' : 0.53848627984321,
'DJF' : 178,
'CZK' : 23,
'DKK' : 6.18,
'DEM' : 1.8,
'DOP' : 57,
'DJF' : 178,
'DZD' : 133,
'DKK' : 6.86,
'ECS' : 24094,
'DOP' : 58,
'EEK' : 13,
'DZD' : 133,
'EGP' : 16,
'ECS' : 24094,
'ESP' : 138,
'EEK' : 14,
'ETB' : 40,
'EGP' : 47,
'EUR' : 0.83144322027478,
'ESP' : 153,
'FIM' : 4.94,
'ETB' : 57,
'FJD' : 2.02,
'EUR' : 0.92005843390143,
'FKP' : 0.71743442231745,
'FIM' : 5.47,
'FRF' : 5.45,
'FJD' : 2.23,
'GBP' : 0.71743442231745,
'FKP' : 0.78703952551207,
'GEL' : 3.3,
'FRF' : 6.04,
'GHC' : 57159,
'GBP' : 0.78703952551207,
'GHS' : 5.72,
'GEL' : 2.71,
'GIP' : 0.71743442231745,
'GHC' : 143125,
'GMD' : 51,
'GHS' : 14,
'GNF' : 10041,
'GIP' : 0.78703952551207,
'GRD' : 283,
'GMD' : 68,
'GTQ' : 7.53,
'GNF' : 8493,
'GYD' : 201,
'GRD' : 314,
'HKD' : 7.76,
'GTQ' : 7.57,
'HNL' : 24,
'GYD' : 200,
'HRK' : 6.3,
'HKD' : 7.8,
'HTG' : 76,
'HNL' : 24,
'HUF' : 303,
'HRK' : 6.93,
'IDR' : 14279,
'HTG' : 132,
'IEP' : 0.65481474833248,
'HUF' : 355,
'ILS' : 3.3,
'IDR' : 15986,
'INR' : 73,
'IEP' : 0.72460490043714,
'IQD' : 1442,
'ILS' : 3.69,
'IRR' : 42010,
'INR' : 83,
'ISK' : 127,
'IQD' : 1290,
'ITL' : 1610,
'IRR' : 42009,
'JMD' : 149,
'ISK' : 138,
'JOD' : 0.70900000000001,
'ITL' : 1781,
'JPY' : 107,
'JMD' : 154,
'KES' : 109,
'JOD' : 0.70900000000001,
'KGS' : 85,
'JPY' : 156,
'KHR' : 4019,
'KES' : 130,
'KMF' : 409,
'KGS' : 88,
'KPW' : 135,
'KHR' : 3993,
'KRW' : 1126,
'KMF' : 453,
'KWD' : 0.30191153907257,
'KPW' : 135,
'KYD' : 0.83333299999999,
'KRW' : 1358,
'KZT' : 418,
'KWD' : 0.30629670764681,
'LAK' : 9170,
'KYD' : 0.83333299999999,
'LBP' : 1508,
'KZT' : 442,
'LKR' : 194,
'LAK' : 21103,
'LRD' : 173,
'LBP' : 89393,
'LSL' : 15,
'LKR' : 298,
'LTL' : 2.87,
'LRD' : 193,
'LUF' : 34,
'LSL' : 18,
'LVL' : 0.58434162098198,
'LTL' : 3.18,
'LYD' : 4.42,
'LUF' : 37,
'MAD' : 8.82,
'LVL' : 0.64662074757963,
'MDL' : 17,
'LYD' : 4.8,
'MGA' : 3716,
'MAD' : 9.79,
'MGF' : 9150,
'MDL' : 17,
'MKD' : 51,
'MGA' : 4379,
'MMK' : 1392,
'MGF' : 9150,
'MNT' : 2620,
'MKD' : 56,
'MOP' : 7.99,
'MMK' : 2075,
'MRO' : 357,
'MNT' : 2620,
'MTL' : 0.35693857446396,
'MOP' : 8.03,
'MUR' : 39,
'MRO' : 391,
'MVR' : 15,
'MTL' : 0.39498108567387,
'MWK' : 770,
'MUR' : 45,
'MXN' : 21,
'MVR' : 15,
'MYR' : 4.05,
'MWK' : 1720,
'MZM' : 73880,
'MXN' : 17,
'MZN' : 74,
'MYR' : 4.68,
'NAD' : 15,
'MZM' : 63200,
'NGN' : 380,
'MZN' : 63,
'NIO' : 35,
'NAD' : 18,
'NLG' : 1.83,
'NGN' : 1505,
'NOK' : 8.52,
'NIO' : 36,
'NPR' : 115,
'NLG' : 2.03,
'NZD' : 1.38,
'NOK' : 11,
'OMR' : 0.38383957365098,
'NPR' : 131,
'PAB' : 1,
'NZD' : 1.63,
'PEN' : 3.63,
'OMR' : 0.38377594841305,
'PGK' : 3.43,
'PAB' : 1,
'PHP' : 49,
'PEN' : 3.67,
'PKR' : 157,
'PGK' : 3.76,
'PLN' : 3.78,
'PHP' : 58,
'PTE' : 167,
'PKR' : 277,
'PYG' : 6541,
'PLN' : 3.91,
'QAR' : 3.61,
'PTE' : 184,
'ROL' : 40517,
'PYG' : 7355,
'RON' : 4.05,
'QAR' : 3.56,
'RSD' : 97,
'ROL' : 45713,
'RUB' : 74,
'RON' : 4.57,
'RWF' : 973,
'RSD' : 108,
'SAR' : 3.75,
'RUB' : 91,
'SBD' : 7.89,
'RWF' : 1277,
'SCR' : 20,
'SAR' : 3.75,
'SDD' : 34467,
'SBD' : 8.37,
'SDG' : 345,
'SCR' : 13,
'SDP' : 2261,
'SDD' : 59800,
'SEK' : 8.45,
'SDG' : 598,
'SGD' : 1.33,
'SDP' : 2261,
'SHP' : 0.71743442231745,
'SEK' : 11,
'SIT' : 199,
'SGD' : 1.35,
'SKK' : 25,
'SHP' : 0.78703952551207,
'SLL' : 10105,
'SIT' : 220,
'SOS' : 558,
'SKK' : 28,
'SRD' : 14,
'SLL' : 19750,
'SRG' : 14018,
'SOS' : 549,
'STD' : 20304,
'SRD' : 33,
'SVC' : 8.75,
'SRG' : 33320,
'SYP' : 513,
'STD' : 22477,
'SZL' : 15,
'SVC' : 8.75,
'THB' : 30,
'SYP' : 513,
'TJS' : 11,
'SZL' : 18,
'TMM' : 16770,
'THB' : 36,
'TMT' : 3.35,
'TJS' : 11,
'TND' : 2.69,
'TMM' : 16750,
'TOP' : 2.22,
'TMT' : 3.35,
'TRL' : 7456951,
'TND' : 3.11,
'TRY' : 7.46,
'TOP' : 2.32,
'TTD' : 6.66,
'TRL' : 32168418,
'TWD' : 28,
'TRY' : 32,
'TZS' : 2309,
'TTD' : 6.64,
'UAH' : 28,
'TWD' : 32,
'UGX' : 3641,
'TZS' : 2587,
'USD' : 1,
'UAH' : 39,
'UYU' : 43,
'UGX' : 3760,
'UZS' : 10427,
'USD' : 1,
'UYU' : 38,
'VEB' : 1.86275657102E+14,
'VEF' : 186275657102,
'UZS' : 12662,
'VND' : 22940,
'VEB' : 3651907631,
'VUV' : 112,
'VEF' : 3651908,
'WST' : 2.43,
'VND' : 25451,
'XAF' : 545,
'VUV' : 112,
'XAG' : 0.038609238198237,
'WST' : 2.67,
'XAF' : 604,
'XAU' : 0.000584537038152,
'XCD' : 2.7,
'XAG' : 0.031347411860134,
'XEU' : 0.83144322027478,
'XAU' : 0.00041128929241299,
'XOF' : 545,
'XCD' : 2.7,
'XPD' : 0.000423507866364,
'XEU' : 0.92005843390143,
'XPF' : 99,
'XOF' : 604,
'XPT' : 0.00085367167460603,
'XPD' : 0.00098009826645798,
'YER' : 250,
'XPF' : 110,
'XPT' : 0.00093444018680404,
'YUN' : 97,
'ZAR' : 15,
'YER' : 249,
'ZMK' : 5176,
'YUN' : 108,
'ZWD' : 373
'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. */
/* Localize the amount errors. Call when initialising form. */
donationForm.localizeErrors = function() {
donationForm.localizeErrors = function() {
var currency = donationForm.currency;
var currency = donationForm.currency;
var minAmount = donationForm.minimums[ currency ];
/* T287706 - round to 2 decimal places (rounding up) */
var numFormat = function( amount ) {
return Math.ceil( amount * 100 ) / 100;
};


$('.lp-error-smallamount').text( function( index, oldText ) {
$('.lp-error-smallamount').text( function( index, oldText ) {
return oldText.replace( '$1', numFormat( minAmount ) + ' ' + 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', numFormat( donationForm.maxUSD * minAmount ) )
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.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? */

// Look for 'hpc' parameter, then 'mrc'. If neither, then bail out.
var hpc = parseFloat( mw.util.getParamValue('hpc') );
if( isNaN(hpc) ) {
hpc = parseFloat( mw.util.getParamValue('mrc') );
if( isNaN(hpc) ) {
return;
}
}


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


// Look for 'hpc' parameter, then 'mrc'
var currency = donationForm.currency;
var hpc = parseFloat( mw.util.getParamValue('hpc') );
var language = mw.config.get('wgPageContentLanguage');
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' : {
'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 ] ],
[ 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 ] ]
],
'2incvar' : [
[ 0, [ 1, 5, 10, 15, 20, 30, 50 ] ],
[ 3, [ 3, 5, 10, 20, 35, 50, 75 ] ],
[ 6, [ 6, 10, 20, 35, 50, 75, 100 ] ],
[ 10, [ 10, 15, 25, 50, 75, 100, 125 ] ],
[ 13, [ 13, 20, 35, 50, 75, 100, 125 ] ],
[ 16, [ 16, 25, 50, 75, 100, 150, 200 ] ],
[ 20, [ 20, 35, 50, 75, 125, 150, 200 ] ],
[ 23, [ 23, 35, 50, 75, 125, 175, 250 ] ],
[ 26, [ 26, 35, 50, 75, 125, 175, 250 ] ],
[ 30, [ 30, 40, 50, 75, 125, 175, 250 ] ],
[ 35, [ 35, 45, 50, 100, 125, 175, 250 ] ],
[ 40, [ 40, 50, 75, 100, 150, 250, 300 ] ],
[ 45, [ 45, 50, 75, 100, 150, 250, 500 ] ],
[ 50, [ 50, 60, 100, 125, 175, 250, 500 ] ],
[ 60, [ 60, 75, 100, 125, 175, 250, 500 ] ],
[ 70, [ 70, 85, 100, 125, 175, 250, 500 ] ],
[ 80, [ 80, 100, 125, 150, 200, 300, 500 ] ],
[ 90, [ 90, 100, 125, 150, 200, 300, 500 ] ],
[ 100, [ 100, 125, 175, 250, 350, 500, 750 ] ],
[ 125, [ 125, 150, 200, 300, 500, 750, 1000 ] ],
[ 150, [ 150, 175, 250, 400, 500, 750, 1000 ] ],
[ 175, [ 175, 200, 300, 400, 500, 750, 1000 ] ],
[ 200, [ 200, 250, 300, 400, 500, 750, 1000 ] ],
],
'3incvarsv' : [
[ 0, [ 1, 5, 7.50, 10, 15, 20, 30 ] ],
[ 3, [ 3, 5, 10, 15, 20, 25, 40 ] ],
[ 6, [ 6, 10, 15, 20, 30, 40, 50 ] ],
[ 10, [ 10, 15, 20, 25, 30, 40, 50 ] ],
[ 13, [ 13, 20, 25, 35, 45, 55, 75 ] ],
[ 16, [ 16, 20, 25, 35, 45, 55, 75 ] ],
[ 20, [ 20, 25, 35, 45, 55, 75, 100 ] ],
[ 23, [ 23, 30, 37, 45, 55, 75, 100 ] ],
[ 26, [ 26, 30, 37, 45, 55, 75, 100 ] ],
[ 30, [ 30, 35, 40, 45, 55, 75, 100 ] ],
[ 35, [ 35, 40, 45, 50, 65, 75, 100 ] ],
[ 40, [ 40, 45, 50, 65, 75, 100, 125 ] ],
[ 45, [ 45, 50, 55, 65, 75, 100, 125 ] ],
[ 50, [ 50, 60, 75, 100, 125, 150, 200 ] ],
[ 60, [ 60, 70, 80, 100, 125, 150, 200 ] ],
[ 70, [ 70, 80, 100, 125, 150, 200, 250 ] ],
[ 80, [ 80, 90, 100, 125, 150, 200, 250 ] ],
[ 90, [ 90, 100, 125, 150, 200, 250, 300 ] ],
[ 100, [ 100, 110, 150, 200, 250, 300, 350 ] ],
[ 125, [ 125, 150, 200, 250, 300, 400, 500 ] ],
[ 150, [ 150, 175, 200, 250, 300, 400, 500 ] ],
[ 175, [ 175, 200, 250, 300, 400, 500, 750 ] ],
[ 200, [ 200, 250, 300, 350, 400, 500, 750 ] ],
],
'4HA7' : [
[ 0, [ 2.75, 5, 10, 20, 25, 35, 100 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 200 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 250 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 300 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 500 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 500 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 1000 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 2000 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 5000 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 7500 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 10000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 12000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 12000 ] ]
],
'5LA1' : [
[ 0, [ 1, 5, 10, 15, 20, 30, 50 ] ],
[ 3, [ 3, 5, 10, 20, 35, 50, 75 ] ],
[ 6, [ 5, 10, 20, 35, 50, 75, 100 ] ],
[ 10, [ 10, 15, 25, 50, 75, 100, 125 ] ],
[ 13, [ 10, 20, 35, 50, 75, 100, 125 ] ],
[ 16, [ 15, 25, 50, 75, 100, 150, 200 ] ],
[ 20, [ 20, 35, 50, 75, 125, 150, 200 ] ],
[ 23, [ 20, 35, 50, 75, 125, 175, 250 ] ],
[ 26, [ 25, 35, 50, 75, 125, 175, 250 ] ],
[ 30, [ 30, 40, 50, 75, 125, 175, 250 ] ],
[ 35, [ 35, 45, 50, 100, 125, 175, 300 ] ],
[ 40, [ 40, 50, 75, 100, 150, 200, 300 ] ],
[ 45, [ 45, 50, 75, 100, 150, 250, 500 ] ],
[ 50, [ 50, 75, 100, 125, 175, 250, 500 ] ],
[ 60, [ 60, 75, 100, 125, 175, 250, 500 ] ],
[ 70, [ 70, 85, 100, 125, 175, 250, 500 ] ],
[ 80, [ 80, 100, 125, 150, 200, 300, 500 ] ],
[ 90, [ 90, 100, 125, 150, 200, 300, 500 ] ],
[ 100, [ 100, 125, 175, 250, 350, 500, 750 ] ],
[ 125, [ 125, 150, 200, 300, 500, 750, 1000 ] ],
[ 150, [ 150, 200, 300, 400, 500, 750, 1000 ] ],
[ 175, [ 175, 200, 300, 400, 500, 750, 1000 ] ],
[ 200, [ 200, 225, 300, 400, 500, 750, 1000 ] ],
],
'2018control' : [
[ 0, [ 5, 10, 20, 25, 35, 50, 100 ] ],
[ 5, [ 10, 15, 20, 35, 50, 100, 150 ] ],
[ 10, [ 15, 20, 25, 35, 50, 100, 150 ] ],
[ 15, [ 20, 25, 35, 50, 75, 100, 250 ] ],
[ 20, [ 25, 35, 50, 75, 100, 150, 250 ] ],
[ 25, [ 30, 40, 50, 75, 100, 150, 250 ] ],
[ 35, [ 25, 50, 75, 100, 200, 250, 300 ] ],
[ 75, [ 25, 50, 75, 100, 200, 300, 500 ] ],
[ 100, [ 25, 50, 100, 150, 250, 500, 1000 ] ],
[ 150, [ 50, 100, 150, 200, 350, 500, 1000 ] ],
[ 200, [ 100, 150, 200, 300, 400, 500, 1000 ] ],
[ 500, [ 100, 250, 500, 750, 1000, 1500, 2000 ] ],
[ 1000, [ 500, 1000, 2000, 2500, 3000, 4000, 5000 ] ]
],
'LTLA' : [
[ 0, [ 3, 10, 15, 20, 35, 50, 100 ] ],
[ 5, [ 5, 10, 20, 35, 50, 100, 150 ] ],
[ 10, [ 10, 20, 35, 50, 75, 100, 150 ] ],
[ 15, [ 15, 25, 35, 50, 75, 100, 250 ] ],
[ 20, [ 20, 30, 50, 75, 100, 150, 250 ] ],
[ 25, [ 25, 35, 50, 75, 100, 150, 250 ] ],
[ 35, [ 25, 50, 75, 100, 200, 250, 300 ] ],
[ 75, [ 25, 50, 75, 100, 200, 300, 500 ] ],
[ 100, [ 25, 50, 100, 150, 250, 500, 1000 ] ],
[ 150, [ 50, 100, 150, 200, 350, 500, 1000 ] ],
[ 200, [ 100, 150, 200, 300, 400, 500, 1000 ] ],
[ 500, [ 100, 250, 500, 750, 1000, 1500, 2000 ] ],
[ 1000, [ 500, 1000, 2000, 2500, 3000, 4000, 5000 ] ]
],
'midtier2018' : [
[ 0, [ 3, 5, 10, 20, 30, 50, 100 ] ],
[ 5, [ 5, 10, 20, 35, 50, 100, 150 ] ],
[ 10, [ 10, 15, 20, 35, 50, 100, 150 ] ],
[ 15, [ 15, 20, 25, 35, 50, 100, 150 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 25, [ 35, 50, 75, 100, 150, 250, 500 ] ],
[ 35, [ 50, 75, 100, 150, 250, 350, 500 ] ],
[ 50, [ 75, 100, 150, 200, 250, 350, 500 ] ],
[ 75, [ 100, 150, 200, 300, 400, 500, 1000 ] ],
[ 100, [ 150, 200, 250, 300, 400, 500, 1000 ] ],
[ 150, [ 200, 250, 300, 400, 500, 1000, 2500 ] ],
[ 200, [ 500, 750, 1000, 2000, 3500, 5000, 7500 ] ],
[ 500, [ 750, 1000, 1500, 2500, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ]
],
'LT2018' : [
[ 0, [ 5, 10, 20.18, 25, 35, 50, 100 ] ],
[ 5, [ 10, 15, 20.18, 35, 50, 100, 150 ] ],
[ 10, [ 15, 20.18, 25, 35, 50, 100, 150 ] ],
[ 15, [ 20.18, 25, 35, 50, 75, 100, 250 ] ],
[ 20, [ 25, 35, 50, 75, 100, 150, 250 ] ],
[ 25, [ 30, 40, 50, 75, 100, 150, 250 ] ],
[ 35, [ 25, 50, 75, 100, 200, 250, 300 ] ],
[ 75, [ 25, 50, 75, 100, 200, 300, 500 ] ],
[ 100, [ 25, 50, 100, 150, 250, 500, 1000 ] ],
[ 150, [ 50, 100, 150, 200, 350, 500, 1000 ] ],
[ 200, [ 100, 150, 200, 300, 400, 500, 1000 ] ],
[ 500, [ 100, 250, 500, 750, 1000, 1500, 2018 ] ],
[ 1000, [ 500, 1000, 2018, 2500, 3000, 4000, 5000 ] ]
]
},
'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, [ 20, 50, 100, 200, 300, 500, 1000 ] ],
[ 30, [ 30, 50, 100, 200, 300, 500, 1000 ] ],
[ 50, [ 50, 100, 150, 200, 300, 500, 1000 ] ],
[ 200, [ 50, 100, 200, 300, 500, 750, 1000 ] ]
]
};
radioAmountsData.AUD = radioAmountsData.USD;
radioAmountsData.CAD = radioAmountsData.USD;
radioAmountsData.GBP = radioAmountsData.USD;
radioAmountsData.NZD = radioAmountsData.USD;
radioAmountsData.EUR = radioAmountsData.USD;


// If changing, please update https://docs.google.com/spreadsheets/d/1e02TsZ_bKDAS1BMVBCdyo9D7RGln_wCGnkg7IF5kU5s/edit
var appealAmountsData = {
var radioAmountsData = {
'USD' : [
"USD" : { // also used for CAD, AUD, NZD
[ 0, [ 5, 10, 20 ] ],
"default" : [
[ 10, [ 10, 20, 50 ] ],
[ 20, [ 20, 30, 50 ] ],
[ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ],
[ 35, [ 20, 30, 50 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 50, [ 20, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 75, [ 50, 75, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 100, [ 75, 100, 150 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 150, [ 75, 100, 200 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 200, [ 100, 200, 300 ] ]
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
'JPY' : [
[ 0, [ 300, 500, 1000 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 3, [ 500, 1000, 1500 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 5, [ 1000, 1500, 2000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 10, [ 1500, 2000, 5000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 20, [ 2000, 3000, 5000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 50, [ 2000, 5000, 10000 ] ],
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
],
[ 100, [ 5000, 10000, 15000 ] ]
"FY2425_E1_T11_USD" : [ // Upgrade recurring +1 for lowest ask
],
[ 0, [ 3.75, 5, 10, 20, 25, 35, 50 ] ],
'SEK' : [
[ 0, [ 20, 50, 100 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 3, [ 30, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 5, [ 50, 100, 150 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 15, [ 100, 150, 200 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 23, [ 100, 200, 300 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 38, [ 100, 200, 500 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 75, [ 100, 500, 750 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 112, [ 100, 500, 1000 ] ]
[ 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 ] ],
appealAmountsData.AUD = appealAmountsData.USD;
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
appealAmountsData.CAD = appealAmountsData.USD;
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
appealAmountsData.GBP = appealAmountsData.USD;
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
appealAmountsData.NZD = appealAmountsData.USD;
],
appealAmountsData.EUR = appealAmountsData.USD;
"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 formats = {
var currencyList = [ 'USD', 'CAD', 'AUD', 'NZD', 'GBP', 'EUR' ]; // close enough
"USD" : "$\t",
"EUR" : {
for ( let i = 0; i < currencyList.length; i++ ) {
radioAmountsData[ currencyList[i] ].MG_2024_500 = [ [ 0, [ 500, 750, 1000, 1250, 1500, 1750, 2000 ] ] ];
"en" : "€\t",
radioAmountsData[ currencyList[i] ].MG_2024_650 = [ [ 0, [ 650, 750, 1000, 1250, 1500, 1750, 2000 ] ] ];
"cy" : "€\t",
}
"ga" : "€\t",
"mt" : "€\t",
"nl" : "€ \t",
"lv" : "€ \t",
"tr" : "€ \t",
"default" : "\t €"
},
"AUD" : "$\t",
"CAD" : {
"fr" : "\t $",
"default" : "$\t"
},
"GBP" : "£\t",
"NZD" : "$\t",
"JPY" : "¥\t",
"SEK" : "\t kr",
"BRL" : "R$\t"
};


var appealAmountsData = {
var format = formats[currency][language] || formats[currency]['default'] || formats[currency] || '\t';
"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
// 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( format.replace('\t', 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( ', ');
// Build string
$('.consider-amounts').html(appealAmountString);
var appealAmountString = '';
}
for( var k = 0; k < appealAmounts.length; k++ ) {
appealAmountString += format.replace('\t', appealAmounts[k]) + ', ';
}
appealAmountString = appealAmountString.trim();

$('.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',
// Others
// Others
'DK' : 'vma',
'HU' : 'vma',
'CZ' : 'vmad',
'IL' : 'vmad', // Adyen
'DK' : 'vma',
'JP' : 'vmj',
'HU' : 'vma',
'MY' : 'vmaj',
'IL' : 'vmad', // Adyen
'NO' : 'vma',
'JP' : 'vmaj',
'PL' : 'vma',
'MY' : 'vmaj',
'RO' : 'vma',
'NO' : 'vma',
'SE' : 'vma',
'PL' : 'vma',
'UA' : 'vma', // Adyen
'RO' : 'vma',
'ZA' : 'vm'
'SE' : 'vma',
'UA' : 'vma', // Adyen
};
'ZA' : 'vm',
if ( cardTypes[country] ) {
'ZZ' : 'vmad' // For testing
$('.paymentmethod-cc').addClass('cctypes-' + cardTypes[country] );
};
}
if ( cardTypes[country] ) {
$('.paymentmethod-cc').addClass('cctypes-' + cardTypes[country] );
$('.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 681: 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;
// Overrides for specific cc gateways
params.country = donationForm.country;
if ( paymentMethod === 'cc-adyen' ) {
params.payment_method = 'cc';
params.gateway = 'adyen';
params.ffname = 'adyen';
} else if ( paymentMethod === 'cc-dlocal' ) {
params.payment_method = 'cc';
params.gateway = 'astropay';
} else {
params.payment_method = paymentMethod;
}


// Overrides for specific cc gateways
if ( paymentSubMethod ) {
if ( paymentMethod === 'cc-adyen' ) {
params.payment_submethod = paymentSubMethod;
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' ) {
var frequency = $('input[name="frequency"]:checked').val();
params.gateway = 'astropay';
if ( frequency !== 'monthly' ) {
}
params.recurring = false;
} else {
params.recurring = true;
}


if ( paymentSubMethod ) {
params.currency_code = donationForm.currency;
params.payment_submethod = paymentSubMethod;
params.country = donationForm.country;
}
params.uselang = mw.config.get('wgPageContentLanguage'); // see T281285 for why not wgUserLanguage


let frequency = donationForm.getFrequency();
if ( params.uselang === 'pt' && params.country === 'BR' ) {
if ( frequency === 'monthly' ) {
params.uselang = 'pt-br';
params.recurring = '1';
}
if ( params.uselang === 'es' &&
params.frequency_unit = 'month';
} else if ( frequency === 'annual' ) {
( params.country === 'AR' || params.country === 'CL' ||
params.recurring = '1';
params.country === 'CO' || params.country === 'MX' ||
params.frequency_unit = 'year';
params.country === 'PE' || params.country === 'UY' ||
}
params.country === 'US' )
) {
params.uselang = 'es-419';
}


params.uselang = mw.config.get('wgPageContentLanguage'); // see T281285 for why not wgUserLanguage
var amount = donationForm.getAmount();
if ( $('#ptf-checkbox').prop('checked') ) {
amount = amount + donationForm.calculateFee( amount );
donationForm.extraData.ptf = 1;
}
params.amount = amount;


if ( params.uselang === 'pt' && params.country === 'BR' ) {
// Email optin
params.uselang = 'pt-br';
if ( $('input[name="opt_in"]').length > 0 ) {
}
var opt_inValue = $('input[name="opt_in"]:checked').val();
if ( params.uselang === 'es' &&
params.opt_in = opt_inValue; // donationForm.validate() already checked it's 1 or 0
( 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();
// Default to variant = panExplain for India
if ( $('#ptf-checkbox').prop('checked') ) {
// TODO: make this default payments side - https://phabricator.wikimedia.org/T259146
if ( donationForm.country === 'IN' ) {
amount = amount + donationForm.calculateFee( amount );
donationForm.extraData.ptf = 1;
params.variant = 'panExplain';
}
}
params.amount = amount;


// Email optin
if ( mw.util.getParamValue( 'pym_variant' ) ) {
if ( $('input[name="opt_in"]').length > 0 ) {
params.variant = mw.util.getParamValue( 'pym_variant' );
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_appeal' ) ) {
}
params.appeal = mw.util.getParamValue( 'pym_appeal' );
}


if ( mw.util.getParamValue( 'pym_variant' ) ) {
// Check for monthly convert. TODO: make it possible to test JS variants
if ( mw.util.getParamValue( 'monthlyconvert' ) ) {
params.variant = mw.util.getParamValue( 'pym_variant' );
}
mc.main( params, donationForm.finalStep );
if ( params.recurring && params.variant && params.variant.match( /monthlyConvert/ ) ) {
} else {
// Post-payments monthly convert makes no sense if it's already recurring
donationForm.finalStep( params );
// Avoid things like T312905
}
delete params.variant;
}


// TODO: refactor this to a list of parameters to pass unchanged
} else {
// or just pass everything by default?
donationForm.extraData.validateError = 1; // Flag they had an error, even if fixed later
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
var recipient_id = mw.util.getParamValue( 'recipient_id' );
if ( recipient_id ) {
if ( isNaN( parseFloat( recipient_id ) ) ) {
// Lop off last 2 characters and decode base64
params.recipient_id = atob( recipient_id.slice(0, -2) );
} else {
params.recipient_id = recipient_id;
}
}


// Monthly convert
return false; // don't submit if called by a button
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
};
};


Line 770: Line 883:
donationForm.finalStep = function( params ) {
donationForm.finalStep = function( params ) {


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


// Skip form chooser for Apple Pay / Google Pay
donationForm.extraData.time = Math.round( (Date.now() - donationForm.loadedTime)/1000 );
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
// Tracking data
params.utm_medium = mw.util.getParamValue( 'utm_medium' );
if ( params.payment_method === 'venmo' ) {
url = new URL('https://payments.wikimedia.org/index.php/Special:BraintreeGateway');
params.utm_campaign = mw.util.getParamValue( 'utm_campaign' );
}
params.utm_source = donationForm.buildUtmSource( params );
params.utm_key = donationForm.buildUtmKey( donationForm.extraData );
if ( document.referrer ) { // TODO: do we need this?
// Strip protocol to stop firewall complaining
params.referrer = document.referrer.replace(/https?:\/\//i, '');
}


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


// Tracking data
if ( window.top !== window.self ) {
params.wmf_medium = mw.util.getParamValue( 'wmf_medium' ) || mw.util.getParamValue( 'utm_medium' );
// In a frame, open payments in a new tab
params.wmf_campaign = mw.util.getParamValue( 'wmf_campaign' ) || mw.util.getParamValue( 'utm_campaign' );
window.open( uri.toString() );
params.wmf_source = donationForm.buildTrackingSource( params );
} else {
params.wmf_key = donationForm.buildTrackingKey( donationForm.extraData );
window.location.href = uri.toString();
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 utm_source value, including the landing page info.
* Build a wmf_source value, including the landing page info.
*
*
* Own function so it can be overriden for weird tests
* Own function so it can be overriden for weird tests
*
*
* @param {Object} params
* @param {Object} params
* @return {string} utm_source
* @return {string} wmf_source
*/
*/
donationForm.buildUtmSource = function( params ) {
donationForm.buildTrackingSource = function( params ) {


var utm_source = mw.util.getParamValue( 'utm_source' ) + '.';
var wmf_source = mw.util.getParamValue( 'wmf_source' ) || mw.util.getParamValue( 'utm_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 */
utm_source += getParam( 'template' , 'Lp-layout' , 'default' ) + '~';
wmf_source += getParam( 'template' , 'Lp-layout' , 'default' ) + '~';
utm_source += getParam( 'appeal-template' , 'Appeal-template-' , 'default' ) + '~';
wmf_source += getParam( 'appeal-template' , 'Appeal-template-' , 'default' ) + '~';
utm_source += getParam( 'appeal' , 'Appeal-' , 'default' ) + '~';
wmf_source += getParam( 'appeal' , 'Appeal-' , 'default' ) + '~';
utm_source += getParam( 'form-template' , 'Form-template-' , 'default' ) + '~';
wmf_source += getParam( 'form-template' , 'Form-template-' , 'default' ) + '~';
utm_source += getParam( 'form-countryspecific', 'Form-countryspecific-', 'control' );
wmf_source += getParam( 'form-countryspecific', 'Form-countryspecific-', 'control' );


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


return utm_source;
return wmf_source;


};
};


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


if ( existingUtmKey ) {
if ( existingKey ) {
dataArray.push( existingUtmKey );
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 891: Line 1,017:
*/
*/
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 911: Line 1,037:
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();
$('#error-optin').show().focus();
error = true;
error = true;
} else {
} else {
$('#error-optin').hide();
$('#error-optin').hide();
}
}
}
}


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


Line 940: Line 1,066:
donationForm.validateAmount = function() {
donationForm.validateAmount = function() {


var amount = donationForm.getAmount();
var amount = donationForm.getAmount();
var minAmount = donationForm.minimums[ donationForm.currency ] || 1;


if ( amount === null || isNaN(amount) || amount <= 0 || amount < minAmount ) {
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();
$('.lp-error-smallamount').show().focus();
return false;
return false;
} else if ( amount > donationForm.maxUSD * minAmount ) {
} else if ( amount > donationForm.maxLocal ) {
$('.amount-options').addClass('lp-haserror');
$('.amount-options').addClass('lp-haserror');
$('.lp-error-bigamount').show();
$('.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;
minAmount = donationForm.minimums[ donationForm.currency ] || 1,
maxAmount = donationForm.maxUSD * minAmount,
feeText;


feeText = donationForm.formatCurrency( feeAmount );
if ( feeAmount % 1 !== 0 ) { // Not a whole number
feeText = feeAmount.toFixed(2);
} else {
feeText = feeAmount.toString();
}


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


Line 994: Line 1,126:
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' : 25,
'INR' : 4,
'JPY' : 35,
'JPY' : 35,
'MYR' : 1,
'MYR' : 1,
'NOK' : 3,
'NOK' : 3,
'PLN' : 1.35,
'PLN' : 1.35,
'RON' : 1.5,
'CZK' : 7.5,
'SEK' : 3,
'RON' : 1.5,
'UAH' : 10,
'SEK' : 3,
'ZAR' : 5,
'UAH' : 10,
'ZAR' : 5,
// Latin America
// Latin America // Updated 2024-08-22 to approx 0.35 USD equivalent
'BRL' : 2,
'ARS' : 32,
'BRL' : 1.75,
'CLP' : 255,
'ARS' : 300,
'COP' : 1300,
'CLP' : 300,
'MXN' : 7.4,
'COP' : 1400,
'PEN' : 1.3,
'MXN' : 6,
'UYU' : 15.5
'PEN' : 1.2,
'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,058: Line 1,191:
*/
*/
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;
}
}
};
};
}
}
};

/**
* Make language and country into a standard javascript Intl locale identifier
*
* Currently only used in monthlyconvert, but this could be useful
*
* @param {string} language
* @param {string} country
* @return {string} locale identifier
*/
donationForm.getLocale = function( language, country ) {
if ( language === 'en-gb' ) {
language = 'en';
}
if ( language === 'es-419' ) {
language = 'es';
}
if ( language === 'pt-br' ) {
language = 'pt';
}
return language + '-' + country;
};
};


Line 1,105: Line 1,216:
*/
*/
donationForm.shouldShowApplePay = function ( country ) {
donationForm.shouldShowApplePay = function ( country ) {
if ( location.search.match('forceApplePay') ) {
// TODO: Add country logic when we get a list from payments
return true;
if ( location.search.match('forceApplePay') ) {
}
return true;
if ( window.ApplePaySession ) {
}
if ( window.ApplePaySession ) {
if ( ApplePaySession.canMakePayments() ) {
return true;
if ( ApplePaySession.canMakePayments() ) {
}
return true;
}
}
return false;
}
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 */
/* End form functions */
Line 1,122: Line 1,405:
$(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;

// 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 ) {
var form = document.forms['donateForm'];


// hide frequency options for some countries
// These get used in quite a few places
if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) !== -1 ) {
donationForm.currency = form.currency_code.value;
$('#frequency_onetime').prop('checked', true);
donationForm.country = mw.util.getParamValue('country');
$('.frequency-options, #cancel-monthly, #donate-recurring-smallprint').hide();
}


if ( donationForm.noRecurringPaypalCountries.indexOf( donationForm.country ) !== -1 ) {
// Block typing symbols in Other field
$( '.paymentmethod-pp, .paymentmethod-pp-usd' ).addClass( 'not-monthly-capable' );
donationForm.otherInputControl( document.getElementById('input_amount_other_box') );
}


// Format amounts on buttons
// Validate amount and update fee when selected/entered
$('.amount-options').on( 'input change', function() {
$( '.amount-options li' ).each( function( index ) {
let amount = this.querySelector( 'input' ).value;
donationForm.validateAmount();
if ( amount !== 'Other' ) {
donationForm.updateFeeDisplay();
this.querySelector( 'label' ).innerText = donationForm.formatCurrency( amount );
});
}
});


addCardTypesClass( donationForm.country );
// 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();
}
});


// Only show Amazon for links from Ways to give
// But allow Enter on buttons
if (
$('.payment-method-button').keyup(function(e) {
mw.util.getParamValue( 'wmf_source' ) === 'Waystogive' ||
if (event.keyCode === 13) {
mw.util.getParamValue( 'wmf_source' ) === 'Ways_to_Give'
e.target.click();
) {
}
$('.paymentmethod-amazon').show();
});
}


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


// Venmo browser check
// hide frequency options for some countries
if ( $('.paymentmethod-venmo').length > 0 ) {
if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) !== -1 ) {
if ( !donationForm.isVenmoSupported() || donationForm.country !== 'US' ) {
$('#frequency_onetime').prop('checked', true);
$('.paymentmethod-venmo').remove();
$('.frequency-options, #cancel-monthly, #donate-recurring-smallprint').hide();
}
}
}


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


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


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


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


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


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


// Allow preselecting monthly
// Allow preselecting frequency if possible
if (
if( mw.util.getParamValue('monthly')
&& donationForm.noRecurringCountries.indexOf( donationForm.country ) === -1 ) {
donationForm.noRecurringCountries.indexOf( donationForm.country ) === -1
&& mw.util.getParamValue( 'utm_medium' ) !== 'endowment'
$('#frequency_monthly').click();
&& 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 {
$('.ptf').appendTo('.amount-options');
$('.frb-monthly-pitch, .frb-monthly-pitch-thanks').appendTo('.frequency-options');
$('.optin-options').insertAfter('.amount-options');
$('.ptf').appendTo('.amount-options');
$('.optin-options').insertAfter('.amount-options');
$('.consider-amounts').show();
$('#actual-form').show();
$('.consider-amounts').show();
$('#actual-form-loading').hide();
$('#actual-form').show();
$('#actual-form-loading').hide();
}
}


});
});


});
});

Latest revision as of 11:47, 11 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
		var recipient_id = mw.util.getParamValue( 'recipient_id' );
		if ( recipient_id ) {
		    if ( isNaN( parseFloat( recipient_id ) ) ) {
		        // Lop off last 2 characters and decode base64
		        params.recipient_id = atob( recipient_id.slice(0, -2) );
		    } else {
		        params.recipient_id = 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();
		}

	});

});