MediaWiki:DonationForm.js: Difference between revisions

From Donate
Jump to navigation Jump to search
Content deleted Content added
change INR hard minimum to 50 per phab:T307942
enable paypal recurring for Mexico: phab:T360214
 
(48 intermediate revisions by the same user not shown)
Line 7: Line 7:


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


// Don't offer recurring at all in these countries
if ( navigator.brave !== undefined ) { // T283367
donationForm.extraData.brave = '1';
donationForm.noRecurringCountries = [ 'AR' ]; // is this still needed?
}


donationForm.noRecurringPaypalCountries = [ 'CL', 'CO', 'PE', 'UY', 'BR' ];
// Don't offer recurring at all in these countries

donationForm.noRecurringCountries = [ 'AR', 'CL', 'CO', 'MX', 'PE', 'UY', 'BR', 'IN' ];
donationForm.maxUSD = 25000;


donationForm.maxUSD = 12000;
donationForm.minimums = {
donationForm.minimums = {
// From https://github.com/wikimedia/wikimedia-fundraising-SmashPig/blob/master/PaymentData/ReferenceData/CurrencyRates.php
// From https://github.com/wikimedia/wikimedia-fundraising-SmashPig/blob/master/PaymentData/ReferenceData/CurrencyRates.php
// Updated 2022-02-04
// Updated 2024-01-19
'ADF' : 5.64,
'ADF' : 6.08,
'ADP' : 143,
'ADP' : 154,
'AED' : 3.67,
'AED' : 3.67,
'AFA' : 89,
'AFA' : 68,
'AFN' : 89,
'AFN' : 68,
'ALL' : 104,
'ALL' : 94,
'AMD' : 456,
'AMD' : 388,
'ANG' : 1.79,
'ANG' : 1.79,
'AOA' : 592,
'AOA' : 828,
'AON' : 592,
'AON' : 828,
'ARS' : 99,
'ARS' : 366,
'ATS' : 12,
'ATS' : 13,
'AUD' : 1.34,
'AUD' : 1.52,
'AWG' : 1.8,
'AWG' : 1.79,
'AZM' : 8500,
'AZM' : 8500,
'AZN' : 1.7,
'AZN' : 1.7,
'BAM' : 1.68,
'BAM' : 1.81,
'BBD' : 2,
'BBD' : 2,
'BDT' : 84,
'BDT' : 109,
'BEF' : 35,
'BEF' : 37,
'BGL' : 1.68,
'BGL' : 1.81,
'BGN' : 1.68,
'BGN' : 1.81,
'BHD' : 0.37389487524886,
'BHD' : 0.37452802080547,
'BIF' : 1974,
'BIF' : 2826,
'BMD' : 1,
'BMD' : 1,
'BND' : 1.35,
'BND' : 1.34,
'BOB' : 6.73,
'BOB' : 6.73,
'BRL' : 5.61,
'BRL' : 4.95,
'BSD' : 1,
'BSD' : 1,
'BTN' : 75,
'BTN' : 83,
'BWP' : 11,
'BWP' : 14,
'BYR' : 24130,
'BYR' : 32900,
'BZD' : 1.97,
'BZD' : 1.97,
'CAD' : 1.24,
'CAD' : 1.36,
'CDF' : 1986,
'CDF' : 2611,
'CHF' : 0.91804240355267,
'CHF' : 0.87620362389075,
'CLP' : 812,
'CLP' : 880,
'CNY' : 6.38,
'CNY' : 7.17,
'COP' : 3762,
'COP' : 3970,
'CRC' : 616,
'CRC' : 520,
'CUC' : 1,
'CUC' : 1,
'CUP' : 25,
'CUP' : 25,
'CVE' : 95,
'CVE' : 102,
'CYP' : 0.50332112008272,
'CYP' : 0.54264835979874,
'CZK' : 22,
'CZK' : 23,
'DEM' : 1.68,
'DEM' : 1.81,
'DJF' : 178,
'DJF' : 178,
'DKK' : 6.4,
'DKK' : 6.91,
'DOP' : 56,
'DOP' : 56,
'DZD' : 137,
'DZD' : 134,
'ECS' : 24094,
'ECS' : 24094,
'EEK' : 13,
'EEK' : 15,
'EGP' : 16,
'EGP' : 31,
'ESP' : 143,
'ESP' : 154,
'ETB' : 47,
'ETB' : 56,
'EUR' : 0.8599751912484,
'EUR' : 0.92716976971251,
'FIM' : 5.11,
'FIM' : 5.51,
'FJD' : 2.06,
'FJD' : 2.22,
'FKP' : 0.72622003775714,
'FKP' : 0.79581971718638,
'FRF' : 5.64,
'FRF' : 6.08,
'GBP' : 0.72622003775714,
'GBP' : 0.79581971718638,
'GEL' : 3.11,
'GEL' : 2.64,
'GHC' : 60651,
'GHC' : 120114,
'GHS' : 6.07,
'GHS' : 12,
'GIP' : 0.72622003775714,
'GIP' : 0.79581971718638,
'GMD' : 52,
'GMD' : 67,
'GNF' : 9563,
'GNF' : 8522,
'GRD' : 293,
'GRD' : 316,
'GTQ' : 7.56,
'GTQ' : 7.64,
'GYD' : 201,
'GYD' : 200,
'HKD' : 7.77,
'HKD' : 7.81,
'HNL' : 24,
'HNL' : 24,
'HRK' : 6.47,
'HRK' : 6.99,
'HTG' : 98,
'HTG' : 131,
'HUF' : 314,
'HUF' : 355,
'IDR' : 14166,
'IDR' : 15593,
'IEP' : 0.67728550152036,
'IEP' : 0.73020553251391,
'ILS' : 3.2,
'ILS' : 3.71,
'INR' : 50, // T307942
'INR' : 10,
'IQD' : 1445,
'IQD' : 1292,
'IRR' : 42000,
'IRR' : 42000,
'ISK' : 129,
'ISK' : 140,
'ITL' : 1665,
'ITL' : 1795,
'JMD' : 151,
'JMD' : 154,
'JOD' : 0.70900000000001,
'JOD' : 0.70900000000001,
'JPY' : 114,
'JPY' : 146,
'KES' : 110,
'KES' : 153,
'KGS' : 85,
'KGS' : 89,
'KHR' : 4021,
'KHR' : 4051,
'KMF' : 423,
'KMF' : 456,
'KPW' : 135,
'KPW' : 135,
'KRW' : 1169,
'KRW' : 1313,
'KWD' : 0.30084989206684,
'KWD' : 0.30762164728865,
'KYD' : 0.83333299999999,
'KYD' : 0.83333299999999,
'KZT' : 424,
'KZT' : 456,
'LAK' : 10002,
'LAK' : 20577,
'LBP' : 1508,
'LBP' : 15000,
'LKR' : 200,
'LKR' : 325,
'LRD' : 158,
'LRD' : 187,
'LSL' : 15,
'LSL' : 19,
'LTL' : 2.97,
'LTL' : 3.2,
'LUF' : 35,
'LUF' : 37,
'LVL' : 0.60439400431017,
'LVL' : 0.65161862283304,
'LYD' : 4.51,
'LYD' : 4.8,
'MAD' : 8.95,
'MAD' : 10,
'MDL' : 17,
'MDL' : 18,
'MGA' : 3918,
'MGA' : 4549,
'MGF' : 9150,
'MGF' : 9150,
'MKD' : 52,
'MKD' : 57,
'MMK' : 1843,
'MMK' : 2080,
'MNT' : 2620,
'MNT' : 2620,
'MOP' : 8.01,
'MOP' : 8.04,
'MRO' : 359,
'MRO' : 392,
'MTL' : 0.36918734960296,
'MTL' : 0.39803398213759,
'MUR' : 42,
'MUR' : 43,
'MVR' : 15,
'MVR' : 15,
'MWK' : 808,
'MWK' : 1674,
'MXN' : 20,
'MXN' : 17,
'MYR' : 4.15,
'MYR' : 4.68,
'MZM' : 63200,
'MZM' : 63200,
'MZN' : 63,
'MZN' : 63,
'NAD' : 15,
'NAD' : 19,
'NGN' : 411,
'NGN' : 791,
'NIO' : 35,
'NIO' : 36,
'NLG' : 1.9,
'NLG' : 2.04,
'NOK' : 8.35,
'NOK' : 11,
'NPR' : 118,
'NPR' : 132,
'NZD' : 1.4,
'NZD' : 1.63,
'OMR' : 0.38369830294331,
'OMR' : 0.38381212511836,
'PAB' : 1,
'PAB' : 1,
'PEN' : 3.93,
'PEN' : 3.74,
'PGK' : 3.43,
'PGK' : 3.64,
'PHP' : 51,
'PHP' : 56,
'PKR' : 174,
'PKR' : 283,
'PLN' : 3.96,
'PLN' : 4.02,
'PTE' : 172,
'PTE' : 186,
'PYG' : 6799,
'PYG' : 7244,
'QAR' : 3.62,
'QAR' : 3.64,
'ROL' : 42505,
'ROL' : 46063,
'RON' : 4.25,
'RON' : 4.61,
'RSD' : 101,
'RSD' : 108,
'RUB' : 70,
'RUB' : 90,
'RWF' : 996,
'RWF' : 1237,
'SAR' : 3.75,
'SAR' : 3.75,
'SBD' : 8.01,
'SBD' : 8.35,
'SCR' : 13,
'SCR' : 13,
'SDD' : 43676,
'SDD' : 59800,
'SDG' : 437,
'SDG' : 598,
'SDP' : 2261,
'SDP' : 2261,
'SEK' : 8.59,
'SEK' : 10,
'SGD' : 1.35,
'SGD' : 1.34,
'SHP' : 0.72622003775714,
'SHP' : 0.79581971718638,
'SIT' : 206,
'SIT' : 222,
'SKK' : 26,
'SKK' : 28,
'SLL' : 10684,
'SLL' : 19750,
'SOS' : 562,
'SOS' : 562,
'SRD' : 21,
'SRD' : 37,
'SRG' : 21363,
'SRG' : 37356,
'STD' : 20826,
'STD' : 22552,
'SVC' : 8.75,
'SVC' : 8.75,
'SYP' : 513,
'SYP' : 513,
'SZL' : 15,
'SZL' : 19,
'THB' : 33,
'THB' : 36,
'TJS' : 11,
'TJS' : 11,
'TMM' : 16794,
'TMM' : 16750,
'TMT' : 3.36,
'TMT' : 3.35,
'TND' : 2.82,
'TND' : 3.11,
'TOP' : 2.19,
'TOP' : 2.32,
'TRL' : 9654942,
'TRL' : 29009007,
'TRY' : 9.65,
'TRY' : 29,
'TTD' : 6.67,
'TTD' : 6.65,
'TWD' : 28,
'TWD' : 31,
'TZS' : 2303,
'TZS' : 2498,
'UAH' : 26,
'UAH' : 37,
'UGX' : 3548,
'UGX' : 3784,
'USD' : 1,
'USD' : 1,
'UYU' : 43,
'UYU' : 39,
'UZS' : 10654,
'UZS' : 12302,
'VEB' : 420776310,
'VEB' : 3553825326,
'VEF' : 420776,
'VEF' : 3553825,
'VND' : 22710,
'VND' : 24259,
'VUV' : 112,
'VUV' : 112,
'WST' : 2.51,
'WST' : 2.68,
'XAF' : 564,
'XAF' : 608,
'XAG' : 0.04084236107244,
'XAG' : 0.043725386677957,
'XAU' : 0.00055475059827898,
'XAU' : 0.000504038919286,
'XCD' : 2.7,
'XCD' : 2.7,
'XEU' : 0.8599751912484,
'XEU' : 0.92716976971251,
'XOF' : 564,
'XOF' : 608,
'XPD' : 0.000490118884148,
'XPD' : 0.001025937507186,
'XPF' : 103,
'XPF' : 111,
'XPT' : 0.00094617370232302,
'XPT' : 0.001084078572954,
'YER' : 250,
'YER' : 250,
'YUN' : 101,
'YUN' : 108,
'ZAR' : 15,
'ZAR' : 19,
'ZMK' : 5176,
'ZMK' : 5176,
'ZWD' : 373
'ZWD' : 373
Line 224: Line 220:
/* 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 ];
minAmount = donationForm.minimums[ currency ],
locale = donationForm.getLocale( mw.config.get('wgPageContentLanguage'), donationForm.country );
/* T287706 - round to 2 decimal places (rounding up) */

var numFormat = function( amount ) {
// Round up
return Math.ceil( amount * 100 ) / 100;
minAmount = Math.ceil( minAmount * 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( minAmount, locale ) + '\xa0' + currency );
});
});


Line 244: Line 240:


$('.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.maxUSD * minAmount, locale ) )
.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, locale ) );
});
});
};
};
Line 273: Line 269:
// If changing, please update https://docs.google.com/spreadsheets/d/1e02TsZ_bKDAS1BMVBCdyo9D7RGln_wCGnkg7IF5kU5s/edit
// If changing, please update https://docs.google.com/spreadsheets/d/1e02TsZ_bKDAS1BMVBCdyo9D7RGln_wCGnkg7IF5kU5s/edit
var radioAmountsData = {
var radioAmountsData = {
'USD' : {
"USD" : { // also used for CAD, AUD, NZD
'default' : [
"default" : [
[ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ],
[ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ],
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
[ 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' : [
"midtier2018" : [
[ 0, [ 5, 10, 20.18, 25, 35, 50, 100 ] ],
[ 0, [ 3, 5, 10, 20, 30, 50, 100 ] ],
[ 5, [ 10, 15, 20.18, 35, 50, 100, 150 ] ],
[ 5, [ 5, 10, 20, 35, 50, 100, 150 ] ],
[ 10, [ 15, 20.18, 25, 35, 50, 100, 150 ] ],
[ 10, [ 10, 15, 20, 35, 50, 100, 150 ] ],
[ 15, [ 20.18, 25, 35, 50, 75, 100, 250 ] ],
[ 15, [ 15, 20, 25, 35, 50, 100, 150 ] ],
[ 20, [ 25, 35, 50, 75, 100, 150, 250 ] ],
[ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ],
[ 25, [ 30, 40, 50, 75, 100, 150, 250 ] ],
[ 25, [ 35, 50, 75, 100, 150, 250, 500 ] ],
[ 35, [ 25, 50, 75, 100, 200, 250, 300 ] ],
[ 35, [ 50, 75, 100, 150, 250, 350, 500 ] ],
[ 75, [ 25, 50, 75, 100, 200, 300, 500 ] ],
[ 50, [ 75, 100, 150, 200, 250, 350, 500 ] ],
[ 100, [ 25, 50, 100, 150, 250, 500, 1000 ] ],
[ 75, [ 100, 150, 200, 300, 400, 500, 1000 ] ],
[ 150, [ 50, 100, 150, 200, 350, 500, 1000 ] ],
[ 100, [ 150, 200, 250, 300, 400, 500, 1000 ] ],
[ 200, [ 100, 150, 200, 300, 400, 500, 1000 ] ],
[ 150, [ 200, 250, 300, 400, 500, 1000, 2500 ] ],
[ 500, [ 100, 250, 500, 750, 1000, 1500, 2018 ] ],
[ 200, [ 500, 750, 1000, 2000, 3500, 5000, 7500 ] ],
[ 1000, [ 500, 1000, 2018, 2500, 3000, 4000, 5000 ] ]
[ 500, [ 750, 1000, 1500, 2500, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ]
]
]
},
},
'JPY' : [
"EUR" : [ // also used for GBP
[ 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 ] ]
],
"JPY" : [
[ 0, [ 500, 1000, 2000, 2500, 4000, 5000, 10000 ] ],
[ 0, [ 500, 1000, 2000, 2500, 4000, 5000, 10000 ] ],
[ 1000, [ 1000, 1500, 2500, 4000, 5000, 10000, 15000 ] ],
[ 1000, [ 1000, 1500, 2500, 4000, 5000, 10000, 15000 ] ],
Line 454: Line 333:
[ 10000, [ 10000, 25000, 50000, 75000, 100000, 150000, 200000 ] ]
[ 10000, [ 10000, 25000, 50000, 75000, 100000, 150000, 200000 ] ]
],
],
'SEK' : [
"SEK" : [
[ 0, [ 20, 50, 100, 200, 300, 500, 1000 ] ],
[ 0, [ 30, 100, 150, 200, 500, 750, 1000 ] ],
[ 30, [ 30, 50, 100, 200, 300, 500, 1000 ] ],
[ 50, [ 50, 100, 150, 200, 300, 750, 1000 ] ],
[ 50, [ 50, 100, 150, 200, 300, 500, 1000 ] ],
[ 200, [ 50, 100, 200, 300, 500, 750, 1000 ] ]
[ 200, [ 50, 100, 200, 300, 500, 750, 1000 ] ]
]
]
Line 463: Line 341:
radioAmountsData.AUD = radioAmountsData.USD;
radioAmountsData.AUD = radioAmountsData.USD;
radioAmountsData.CAD = radioAmountsData.USD;
radioAmountsData.CAD = radioAmountsData.USD;
radioAmountsData.GBP = radioAmountsData.USD;
radioAmountsData.NZD = radioAmountsData.USD;
radioAmountsData.NZD = radioAmountsData.USD;

radioAmountsData.EUR = radioAmountsData.USD;
radioAmountsData.GBP = radioAmountsData.EUR;


var appealAmountsData = {
var appealAmountsData = {
'USD' : [
"USD" : [ // also used for CAD, AUD, NZD, GBP, EUR
[ 0, [ 5, 10, 20 ] ],
[ 0, [ 5, 10, 20 ] ],
[ 10, [ 10, 20, 50 ] ],
[ 10, [ 10, 20, 50 ] ],
Line 479: Line 357:
[ 200, [ 100, 200, 300 ] ]
[ 200, [ 100, 200, 300 ] ]
],
],
'JPY' : [
"JPY" : [
[ 0, [ 300, 500, 1000 ] ],
[ 0, [ 300, 500, 1000 ] ],
[ 3, [ 500, 1000, 1500 ] ],
[ 3, [ 500, 1000, 1500 ] ],
Line 488: Line 366:
[ 100, [ 5000, 10000, 15000 ] ]
[ 100, [ 5000, 10000, 15000 ] ]
],
],
'SEK' : [
"SEK" : [
[ 0, [ 20, 50, 100 ] ],
[ 0, [ 20, 50, 100 ] ],
[ 3, [ 30, 50, 100 ] ],
[ 3, [ 30, 50, 100 ] ],
Line 529: Line 407:
};
};


var format = formats[currency][language] || formats[currency]['default'] || formats[currency] || '\t';
var format;
if ( formats[currency] ) {
format = formats[currency][language] || formats[currency]['default'] || formats[currency];
} else {
format = '\t';
}


// Radio button amounts
// Radio button amounts
Line 640: Line 523:
'PT' : 'vmaj',
'PT' : 'vmaj',
'SK' : 'vmaj',
'SK' : 'vmaj',
'GR' : 'vma',
// Others
// Others
'CZ' : 'vmad',
'DK' : 'vma',
'DK' : 'vma',
'HU' : 'vma',
'HU' : 'vma',
'IL' : 'vmad', // Adyen
'IL' : 'vmad', // Adyen
'JP' : 'vmj',
'JP' : 'vmaj',
'MY' : 'vmaj',
'MY' : 'vmaj',
'NO' : 'vma',
'NO' : 'vma',
Line 656: Line 541:
if ( cardTypes[country] ) {
if ( cardTypes[country] ) {
$('.paymentmethod-cc').addClass('cctypes-' + cardTypes[country] );
$('.paymentmethod-cc').addClass('cctypes-' + cardTypes[country] );
$('.cc-text-label').addClass('sr-only');
}
}
}
}
Line 686: Line 572:


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

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


Line 694: Line 580:
params.payment_method = 'cc';
params.payment_method = 'cc';
params.gateway = 'adyen';
params.gateway = 'adyen';
params.ffname = 'adyen';
} else if ( paymentMethod === 'cc-dlocal' ) {
} else if ( paymentMethod === 'cc-dlocal' ) {
params.payment_method = 'cc';
params.payment_method = 'cc';
Line 701: Line 586:
params.payment_method = paymentMethod;
params.payment_method = paymentMethod;
}
}

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


Line 742: Line 627:
var opt_inValue = $('input[name="opt_in"]:checked').val();
var opt_inValue = $('input[name="opt_in"]:checked').val();
params.opt_in = opt_inValue; // donationForm.validate() already checked it's 1 or 0
params.opt_in = opt_inValue; // donationForm.validate() already checked it's 1 or 0
}

// Default to variant = panExplain for India
// TODO: make this default payments side - https://phabricator.wikimedia.org/T259146
if ( donationForm.country === 'IN' ) {
params.variant = 'panExplain';
}
}


Line 753: Line 632:
params.variant = 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;
}

if ( mw.util.getParamValue( 'pym_appeal' ) ) {
if ( mw.util.getParamValue( 'pym_appeal' ) ) {
params.appeal = mw.util.getParamValue( 'pym_appeal' );
params.appeal = mw.util.getParamValue( 'pym_appeal' );
}
}


// Check for monthly convert. TODO: make it possible to test JS variants
// Monthly convert
if ( mc ) { // check just in-case this wasn't loaded for some reason
if ( mw.util.getParamValue( 'monthlyconvert' ) ) {
mc.main( params, donationForm.finalStep );
mc.main( params, donationForm.finalStep );
} else {
} else {
Line 777: Line 662:
donationForm.finalStep = function( params ) {
donationForm.finalStep = function( params ) {


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


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

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


Line 871: Line 761:
/* 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;
Line 924: Line 814:


var error = false;
var error = false;
var form = document.forms['donateForm'];
var form = document.forms.donateForm;


// Reset all errors
// Reset all errors
Line 985: Line 875:
minAmount = donationForm.minimums[ donationForm.currency ] || 1,
minAmount = donationForm.minimums[ donationForm.currency ] || 1,
maxAmount = donationForm.maxUSD * minAmount,
maxAmount = donationForm.maxUSD * minAmount,
feeText;
feeText, locale;


locale = donationForm.getLocale( mw.config.get('wgPageContentLanguage'), donationForm.country );
if ( feeAmount % 1 !== 0 ) { // Not a whole number
feeText = feeAmount.toFixed(2);
feeText = donationForm.formatAmount( feeAmount, locale );
} else {
feeText = feeAmount.toString();
}


$('.ptf label span').text( feeText );
$('.ptf label span').text( feeText );
Line 1,012: Line 899:
'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,
'CZK' : 7.5,
'RON' : 1.5,
'RON' : 1.5,
'SEK' : 3,
'SEK' : 3,
'UAH' : 10,
'UAH' : 10,
'ZAR' : 5,
'ZAR' : 5,
// Latin America
// Latin America // Updated 2023-01-17 to approx 0.35 USD equivalent
'BRL' : 2,
'BRL' : 1.75,
'ARS' : 32,
'ARS' : 32,
'CLP' : 255,
'CLP' : 322,
'COP' : 1300,
'COP' : 1385,
'MXN' : 7.4,
'MXN' : 6,
'PEN' : 1.3,
'PEN' : 1.3,
'UYU' : 15.5
'UYU' : 13.7
};
};


Line 1,088: Line 976:
/**
/**
* Make language and country into a standard javascript Intl locale identifier
* 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} language
* @param {string} country
* @param {string} country
* @return {string} locale identifier
* @return {string} locale identifier e.g. en-GB
*/
*/
donationForm.getLocale = function( language, country ) {
donationForm.getLocale = function( language, country ) {
Line 1,117: Line 1,003:
*/
*/
donationForm.shouldShowApplePay = function ( country ) {
donationForm.shouldShowApplePay = function ( country ) {
// TODO: Add country logic when we get a list from payments
if ( location.search.match('forceApplePay') ) {
if ( location.search.match('forceApplePay') ) {
return true;
return true;
Line 1,129: Line 1,014:
};
};


/**
* Format an amount for a given locale
*
* 2 decimal places if it has a fractional part, 0 if not
* Note this doesn't include any currency symbol
*
* @param {number} amount
* @param {string} locale To determine correct separators
* @return {string}
*/
donationForm.formatAmount = function( amount, locale ) {
var formatterOptions, output;
if ( amount % 1 !== 0 ) { // Not a whole number
formatterOptions = { minimumFractionDigits: 2, maximumFractionDigits: 2 };
} else {
formatterOptions = {};
}
try {
output = amount.toLocaleString( locale, formatterOptions );
} catch(e) {
output = amount.toFixed(2);
}
return output;
};

/*
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,136: Line 1,219:
mw.loader.using( ['mediawiki.util'] ).done( function() {
mw.loader.using( ['mediawiki.util'] ).done( function() {


var form = document.forms['donateForm'];
var form = document.forms.donateForm;


// These get used in quite a few places
// These get used in quite a few places
try {
try {
donationForm.currency = form.currency_code.value;
donationForm.currency = form.currency_code.value;
} catch (error) {
} catch (error) {
donationForm.currency = 'USD';
donationForm.currency = 'USD';
}
}
donationForm.country = mw.util.getParamValue('country').toUpperCase();
donationForm.country = mw.util.getParamValue('country').toUpperCase();
Line 1,176: Line 1,259:
$('#frequency_onetime').prop('checked', true);
$('#frequency_onetime').prop('checked', true);
$('.frequency-options, #cancel-monthly, #donate-recurring-smallprint').hide();
$('.frequency-options, #cancel-monthly, #donate-recurring-smallprint').hide();
}

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


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

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


// Apple Pay
// Apple Pay
Line 1,184: Line 1,279:
if ( !donationForm.shouldShowApplePay( donationForm.country ) ) {
if ( !donationForm.shouldShowApplePay( donationForm.country ) ) {
$('.paymentmethod-applepay').remove();
$('.paymentmethod-applepay').remove();
}
}

// Venmo browser check
if ( $('.paymentmethod-venmo').length > 0 ) {
if ( !donationForm.isVenmoSupported() || donationForm.country !== 'US' ) {
$('.paymentmethod-venmo').remove();
}
}
}
}
Line 1,215: Line 1,317:
}
}
finally {
finally {
$('.frb-monthly-pitch, .frb-monthly-pitch-thanks').appendTo('.frequency-options');
$('.ptf').appendTo('.amount-options');
$('.ptf').appendTo('.amount-options');
$('.optin-options').insertAfter('.amount-options');
$('.optin-options').insertAfter('.amount-options');

Latest revision as of 19:14, 20 March 2024

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

var donationForm = {};

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

// Don't offer recurring at all in these countries
donationForm.noRecurringCountries = [ 'AR' ]; // is this still needed?

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

donationForm.maxUSD = 25000;

donationForm.minimums = {
    // From https://github.com/wikimedia/wikimedia-fundraising-SmashPig/blob/master/PaymentData/ReferenceData/CurrencyRates.php
    // Updated 2024-01-19
    'ADF' : 6.08,
    'ADP' : 154,
    'AED' : 3.67,
    'AFA' : 68,
    'AFN' : 68,
    'ALL' : 94,
    'AMD' : 388,
    'ANG' : 1.79,
    'AOA' : 828,
    'AON' : 828,
    'ARS' : 366,
    'ATS' : 13,
    'AUD' : 1.52,
    'AWG' : 1.79,
    'AZM' : 8500,
    'AZN' : 1.7,
    'BAM' : 1.81,
    'BBD' : 2,
    'BDT' : 109,
    'BEF' : 37,
    'BGL' : 1.81,
    'BGN' : 1.81,
    'BHD' : 0.37452802080547,
    'BIF' : 2826,
    'BMD' : 1,
    'BND' : 1.34,
    'BOB' : 6.73,
    'BRL' : 4.95,
    'BSD' : 1,
    'BTN' : 83,
    'BWP' : 14,
    'BYR' : 32900,
    'BZD' : 1.97,
    'CAD' : 1.36,
    'CDF' : 2611,
    'CHF' : 0.87620362389075,
    'CLP' : 880,
    'CNY' : 7.17,
    'COP' : 3970,
    'CRC' : 520,
    'CUC' : 1,
    'CUP' : 25,
    'CVE' : 102,
    'CYP' : 0.54264835979874,
    'CZK' : 23,
    'DEM' : 1.81,
    'DJF' : 178,
    'DKK' : 6.91,
    'DOP' : 56,
    'DZD' : 134,
    'ECS' : 24094,
    'EEK' : 15,
    'EGP' : 31,
    'ESP' : 154,
    'ETB' : 56,
    'EUR' : 0.92716976971251,
    'FIM' : 5.51,
    'FJD' : 2.22,
    'FKP' : 0.79581971718638,
    'FRF' : 6.08,
    'GBP' : 0.79581971718638,
    'GEL' : 2.64,
    'GHC' : 120114,
    'GHS' : 12,
    'GIP' : 0.79581971718638,
    'GMD' : 67,
    'GNF' : 8522,
    'GRD' : 316,
    'GTQ' : 7.64,
    'GYD' : 200,
    'HKD' : 7.81,
    'HNL' : 24,
    'HRK' : 6.99,
    'HTG' : 131,
    'HUF' : 355,
    'IDR' : 15593,
    'IEP' : 0.73020553251391,
    'ILS' : 3.71,
    'INR' : 10,
    'IQD' : 1292,
    'IRR' : 42000,
    'ISK' : 140,
    'ITL' : 1795,
    'JMD' : 154,
    'JOD' : 0.70900000000001,
    'JPY' : 146,
    'KES' : 153,
    'KGS' : 89,
    'KHR' : 4051,
    'KMF' : 456,
    'KPW' : 135,
    'KRW' : 1313,
    'KWD' : 0.30762164728865,
    'KYD' : 0.83333299999999,
    'KZT' : 456,
    'LAK' : 20577,
    'LBP' : 15000,
    'LKR' : 325,
    'LRD' : 187,
    'LSL' : 19,
    'LTL' : 3.2,
    'LUF' : 37,
    'LVL' : 0.65161862283304,
    'LYD' : 4.8,
    'MAD' : 10,
    'MDL' : 18,
    'MGA' : 4549,
    'MGF' : 9150,
    'MKD' : 57,
    'MMK' : 2080,
    'MNT' : 2620,
    'MOP' : 8.04,
    'MRO' : 392,
    'MTL' : 0.39803398213759,
    'MUR' : 43,
    'MVR' : 15,
    'MWK' : 1674,
    'MXN' : 17,
    'MYR' : 4.68,
    'MZM' : 63200,
    'MZN' : 63,
    'NAD' : 19,
    'NGN' : 791,
    'NIO' : 36,
    'NLG' : 2.04,
    'NOK' : 11,
    'NPR' : 132,
    'NZD' : 1.63,
    'OMR' : 0.38381212511836,
    'PAB' : 1,
    'PEN' : 3.74,
    'PGK' : 3.64,
    'PHP' : 56,
    'PKR' : 283,
    'PLN' : 4.02,
    'PTE' : 186,
    'PYG' : 7244,
    'QAR' : 3.64,
    'ROL' : 46063,
    'RON' : 4.61,
    'RSD' : 108,
    'RUB' : 90,
    'RWF' : 1237,
    'SAR' : 3.75,
    'SBD' : 8.35,
    'SCR' : 13,
    'SDD' : 59800,
    'SDG' : 598,
    'SDP' : 2261,
    'SEK' : 10,
    'SGD' : 1.34,
    'SHP' : 0.79581971718638,
    'SIT' : 222,
    'SKK' : 28,
    'SLL' : 19750,
    'SOS' : 562,
    'SRD' : 37,
    'SRG' : 37356,
    'STD' : 22552,
    'SVC' : 8.75,
    'SYP' : 513,
    'SZL' : 19,
    'THB' : 36,
    'TJS' : 11,
    'TMM' : 16750,
    'TMT' : 3.35,
    'TND' : 3.11,
    'TOP' : 2.32,
    'TRL' : 29009007,
    'TRY' : 29,
    'TTD' : 6.65,
    'TWD' : 31,
    'TZS' : 2498,
    'UAH' : 37,
    'UGX' : 3784,
    'USD' : 1,
    'UYU' : 39,
    'UZS' : 12302,
    'VEB' : 3553825326,
    'VEF' : 3553825,
    'VND' : 24259,
    'VUV' : 112,
    'WST' : 2.68,
    'XAF' : 608,
    'XAG' : 0.043725386677957,
    'XAU' : 0.000504038919286,
    'XCD' : 2.7,
    'XEU' : 0.92716976971251,
    'XOF' : 608,
    'XPD' : 0.001025937507186,
    'XPF' : 111,
    'XPT' : 0.001084078572954,
    'YER' : 250,
    'YUN' : 108,
    'ZAR' : 19,
    'ZMK' : 5176,
    'ZWD' : 373
};

/* Localize the amount errors. Call when initialising form. */
donationForm.localizeErrors = function() {
    var currency  = donationForm.currency,
        minAmount = donationForm.minimums[ currency ],
        locale = donationForm.getLocale( mw.config.get('wgPageContentLanguage'), donationForm.country );

    // Round up
    minAmount = Math.ceil( minAmount * 100 ) / 100;

    $('.lp-error-smallamount').text( function( index, oldText ) {
        return oldText.replace( '$1', donationForm.formatAmount( minAmount, locale ) + '\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.maxUSD * minAmount, locale ) )
                      .replace( '$2', currency )
                      .replace( '$3', 'benefactors@wikimedia.org' )
                      .replace( '$4', donationForm.formatAmount( donationForm.maxUSD, locale ) );
    });
};


function adjustHPC() {
    /* Adjust amounts based on highest previous contribution (hpc)
        or most recent contribution (mrc) parameter. Used for emails.
        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 currency = donationForm.currency;
    var language = mw.config.get('wgPageContentLanguage');

    // 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 ] ]
            ],
            "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 ] ]
            ]
        },
        "EUR" : [ // also used for GBP
            [    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 ] ]
        ],
        "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;

    radioAmountsData.GBP = radioAmountsData.EUR;

    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;

    var formats = {
        "USD" : "$\t",
        "EUR" : {
            "en" : "€\t",
            "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 format;
    if ( formats[currency] ) {
        format = formats[currency][language] || formats[currency]['default'] || formats[currency];
    } else {
        format = '\t';
    }

    // 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( format.replace('\t', radioAmounts[j]) );
        }
    }

    // Appeal amounts
    var appealAmounts = pickAmountArray( appealAmountsData, currency, hpc, hpcSet );
    if ( appealAmounts.length ) {
        // Build string
        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 ) {
    /**
     * 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;
        }

        var frequency = $('input[name="frequency"]:checked').val();
        if ( frequency !== 'monthly' ) {
            params.recurring = false;
        } else {
            params.recurring = true;
        }

        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;
        }

        if ( mw.util.getParamValue( 'pym_appeal' ) ) {
            params.appeal = mw.util.getParamValue( 'pym_appeal' );
        }

        // 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 uri = new mw.Uri('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' ) {
        uri = new mw.Uri('https://payments.wikimedia.org/index.php/Special:AdyenCheckoutGateway');
    }

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

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

    // Tracking data
    params.utm_medium   = mw.util.getParamValue( 'utm_medium' );
    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, '');
    }

    uri.extend( params );

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

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

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

    utm_source += '.' + fullDottedPaymentMethod;

    return utm_source;

};

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

    if ( existingUtmKey ) {
        dataArray.push( existingUtmKey );
    }
    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();
            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();
    var minAmount = donationForm.minimums[ donationForm.currency ] || 1;

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

};

donationForm.toggleMonthly = function(monthly) {
    if (monthly) {
        $('#form-wrapper').addClass('form-monthly');
    } else {
        $('#form-wrapper').removeClass('form-monthly');
    }
};

donationForm.updateFeeDisplay = function() {
    var selectedAmount = donationForm.getAmount(),
        feeAmount = donationForm.calculateFee( selectedAmount ),
        minAmount = donationForm.minimums[ donationForm.currency ] || 1,
        maxAmount = donationForm.maxUSD * minAmount,
        feeText, locale;

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

    $('.ptf label span').text( feeText );
    if ( selectedAmount + feeAmount <= maxAmount ) {
        $('.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 2023-01-17 to approx 0.35 USD equivalent
        'BRL' : 1.75,
        'ARS' : 32,
        'CLP' : 322,
        'COP' : 1385,
        'MXN' : 6,
        'PEN' : 1.3,
        'UYU' : 13.7
    };

    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;
            }
        };
    }
};

/**
 * 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 ) {
    if ( language === 'en-gb' ) {
        language = 'en';
    }
    if ( language === 'es-419' ) {
        language = 'es';
    }
    if ( language === 'pt-br' ) {
        language = 'pt';
    }
    return language + '-' + country;
};

/**
 * 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;
};

/**
 * Format an amount for a given locale
 *
 * 2 decimal places if it has a fractional part, 0 if not
 * Note this doesn't include any currency symbol
 *
 * @param  {number} amount
 * @param  {string} locale To determine correct separators
 * @return {string}
 */
donationForm.formatAmount = function( amount, locale ) {
    var formatterOptions, output;
    if ( amount % 1 !== 0 ) { // Not a whole number
        formatterOptions = { minimumFractionDigits: 2, maximumFractionDigits: 2 };
    } else {
        formatterOptions = {};
    }
    try {
        output = amount.toLocaleString( locale, formatterOptions );
    } catch(e) {
        output = amount.toFixed(2);
    }
    return output;
};

/*
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;

        // These get used in quite a few places
        try {
            donationForm.currency = form.currency_code.value;
        } catch (error) {
            donationForm.currency = 'USD';
        }
        donationForm.country = mw.util.getParamValue('country').toUpperCase();

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

        // Validate amount and update fee when selected/entered
        $('.amount-options').on( 'input change', function() {
            donationForm.validateAmount();
            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' );
            }

            addCardTypesClass( donationForm.country );

            // Only show Amazon for links from Ways to give
			if (
				mw.util.getParamValue( 'utm_source' ) === 'Waystogive' ||
				mw.util.getParamValue( 'utm_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();
                }
            }
        }

        // 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 monthly
        if( mw.util.getParamValue('monthly')
        && donationForm.noRecurringCountries.indexOf( donationForm.country ) === -1 ) {
            $('#frequency_monthly').click();
        }

        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();
        }

    });

});