MediaWiki:DonationForm.js: Difference between revisions

From Donate
Jump to navigation Jump to search
Content deleted Content added
renaming form from paypalcontribution to donateForm
No edit summary
 
(95 intermediate revisions by the same user not shown)
Line 1:
/* jshint strict:false */
/** MediaWiki:DonationForm.js - loaded on all donation forms
* TODO: lots of cleanup
Line 6 ⟶ 7:
 
donationForm.loadedTime = Date.now();
donationForm.extraData = {};
 
'vw' : window.innerWidth,
// Don't offer recurring at all in these countries
'vh' : window.innerHeight
donationForm.noRecurringCountries = [ 'AR' ]; // is this still needed?
};
 
donationForm.noRecurringPaypalCountries = [ 'CL', 'CO', 'PE', 'UY', 'BR' ];
 
donationForm.maxUSD = 25000;
 
donationForm.maxUSD = 12000;
donationForm.minimums = {
/*/ From https://github.com/wikimedia/wikimedia-fundraising-SmashPig/blob/master/PaymentData/ReferenceData/CurrencyRates.php */
'ADF'// :Updated 5.65,2024-01-19
'ADPADF' : 1436.08,
'ADP' : 154,
'AED' : 3.67,
'AFA' : 7368,
'AFN' : 7368,
'ALL' : 10994,
'AMD' : 477388,
'ANG' : 1.79,
'AOA' : 278828,
'AON' : 278828,
'ATSARS' : 12366,
'AUDATS' : 1.3913,
'AWGAUD' : 1.7852,
'AZMAWG' : 84861.79,
'AZM' : 8500,
'AZN' : 1.7,
'BAM' : 1.6981,
'BBD' : 2,
'BDT' : 83109,
'BEF' : 3537,
'BGL' : 1.6981,
'BGN' : 1.6981,
'BHD' : 0.3837452802080547,
'BIF' : 17482826,
'BMD' : 1,
'BND' : 1.3834,
'BOB' : 6.873,
'BRL' : 4.95,
'BSD' : 1,
'BTN' : 7283,
'BWP' : 1114,
'BYR' : 2103532900,
'BZD' : 1.9897,
'CAD' : 1.3236,
'CDF' : 15732611,
'CHF' : 0.9887620362389075,
'CNYCLP' : 6.83880,
'CRCCNY' : 5727.17,
'COP' : 3970,
'CRC' : 520,
'CUC' : 1,
'CUP' : 25,
'CVE' : 95102,
'CYP' : 0.5154264835979874,
'CZK' : 2223,
'DEM' : 1.6981,
'DJF' : 178,
'DKK' : 6.4291,
'DOP' : 5056,
'DZD' : 118134,
'ECS' : 24094,
'EEK' : 1315,
'EGP' : 1831,
'ESP' : 143154,
'ETB' : 2756,
'EUR' : 0.8792716976971251,
'FIM' : 5.1251,
'FJD' : 2.122,
'FKP' : 0.7879581971718638,
'FRF' : 56.6508,
'GBP' : 0.7879581971718638,
'GEL' : 2.5264,
'GHC' : 47467120114,
'GHS' : 4.7512,
'GIP' : 0.7879581971718638,
'GMD' : 4867,
'GNF' : 89838522,
'GRD' : 294316,
'GTQ' : 7.564,
'GYD' : 204200,
'HKD' : 7.8581,
'HNL' : 24,
'HRK' : 6.499,
'HTG' : 68131,
'HUF' : 282355,
'IDR' : 1496615593,
'IEP' : 0.6873020553251391,
'ILS' : 3.6171,
'IQDINR' : 117810,
'IQD' : 1292,
'IRR' : 42000,
'ISK' : 109140,
'ITL' : 16691795,
'JMD' : 136154,
'JOD' : 0.7170900000000001,
'JPY' : 112146,
'KES' : 100153,
'KGS' : 6989,
'KHR' : 40254051,
'KMF' : 424456,
'KPW' : 135,
'KRW' : 11201313,
'KWD' : 0.3130762164728865,
'KYD' : 0.8483333299999999,
'KZT' : 369456,
'LAK' : 839320577,
'LBP' : 150815000,
'LKR' : 162325,
'LRD' : 154187,
'LSL' : 1519,
'LTL' : 23.982,
'LUF' : 3537,
'LVL' : 0.6165161862283304,
'LYD' : 14.378,
'MAD' : 9.3910,
'MDL' : 1718,
'MGA' : 33114549,
'MGF' : 9150,
'MKD' : 5357,
'MMK' : 15292080,
'MNT' : 24602620,
'MOP' : 8.0804,
'MRO' : 357392,
'MTL' : 0.3739803398213759,
'MUR' : 3343,
'MVR' : 15,
'MWK' : 7171674,
'MYRMXN' : 4.1517,
'MZMMYR' : 597544.68,
'MZNMZM' : 6063200,
'NADMZN' : 1563,
'NGNNAD' : 35919,
'NIONGN' : 32791,
'NLGNIO' : 1.936,
'NOKNLG' : 82.404,
'NPRNOK' : 11411,
'NZDNPR' : 1.52132,
'OMRNZD' : 01.3963,
'OMR' : 0.38381212511836,
'PAB' : 1,
'PEN' : 3.374,
'PGK' : 3.2664,
'PHP' : 5456,
'PKR' : 123283,
'PLN' : 34.7202,
'PTE' : 173186,
'PYG' : 57637244,
'QAR' : 3.5764,
'ROL' : 3988946063,
'RON' : 34.9961,
'RSD' : 101108,
'RUB' : 6890,
'RWF' : 8621237,
'SAR' : 3.75,
'SBD' : 78.635,
'SCR' : 13,
'SDD' : 179559800,
'SDG' : 18598,
'SDP' : 2261,
'SEK' : 9.0810,
'SGD' : 1.3834,
'SHP' : 0.7879581971718638,
'SIT' : 207222,
'SKK' : 2628,
'SLL' : 843019750,
'SOS' : 542562,
'SRD' : 7.4137,
'SRG' : 740837356,
'STD' : 2107022552,
'SVC' : 8.75,
'SYP' : 215513,
'SZL' : 1519,
'THB' : 3336,
'TJS' : 9.3611,
'TMM' : 1705016750,
'TMT' : 3.4135,
'TND' : 23.7611,
'TOP' : 2.2932,
'TRL' : 662922329009007,
'TRY' : 6.6329,
'TTD' : 6.6465,
'TWD' : 31,
'TZS' : 22812498,
'UAH' : 2837,
'UGX' : 37493784,
'USD' : 1,
'UZSUYU' : 778039,
'VEBUZS' : 605084113612302,
'VEFVEB' : 60508413553825326,
'VNDVEF' : 231503553825,
'VUVVND' : 11124259,
'WSTVUV' : 2.64112,
'XAFWST' : 5652.68,
'XAF' : 608,
'XAG' : 0.043725386677957,
'XAU' : 0.000504038919286,
'XCD' : 2.7,
'XOFXEU' : 5650.92716976971251,
'XPFXOF' : 103608,
'XPD' : 0.001025937507186,
'XPF' : 111,
'XPT' : 0.001084078572954,
'YER' : 250,
'YUN' : 101108,
'ZAR' : 1519,
'ZMK' : 5176,
'ZWD' : 373,
/* Astropay currencies have higher minimums - 1.50 USD */
'ARS' : 58.5,
'BRL' : 6.23,
'CLP' : 1035,
'COP' : 4640,
'MXN' : 28.5,
'INR' : 108
};
 
/* Localize the amount errors. Call when initialising form. */
donationForm.localizeErrors = function() {
var formcurrency = documentdonationForm.forms['donateForm'];currency,
minAmount = donationForm.minimums[ currency ],
var currency = form.currency_code.value;
var minAmount locale = donationForm.minimums[getLocale( currencymw.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 );
});
 
Line 227 ⟶ 240:
 
$('.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() {
Line 250 ⟶ 264:
var hpcSet = mw.util.getParamValue('hpcSet');
 
var currency = $("input[name='currency_code']")donationForm.val()currency;
var language = mw.config.get('wgUserLanguagewgPageContentLanguage');
 
// 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 ] ],
[ 7550, [ 50, 75, 100, 150200, 250 300, 500, 750, 1000750 ] ],
[ 100 75, [ 75, 100, 150, 250, 500, 750, 1000, 2500 ] ],
[ 150100, [ 150100, 200 150, 300 250, 500, 750, 1000, 2000 2500 ] ],
[ 200150, [ 150, 200, 300, 500, 750, 1000, 2500, 50002000 ] ],
[ 500200, [ 200, 300, 500, 750, 1000, 2500, 5000, 7500, 100005000 ] ],
[ 1000 500, [ 1000 500, 2000 750, 3000 1000, 4000 2500, 5000, 7500, 10000 ] ],
[ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ],
[ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ]
],
'2incvar'"midtier2018" : [
[ 0, [ 13, 5, 10, 15, 20, 30, 50, 100 ] ],
[ 35, [ 3, 5, 10, 20, 35, 50, 75100, 150 ] ],
[ 610, [ 610, 10 15, 20, 35, 50, 75100, 100 150 ] ],
[ 1015, [ 1015, 15 20, 25, 50 35, 75 50, 100, 125 150 ] ],
[ 1320, [ 1320, 20 25, 35, 50, 75, 100, 125 150 ] ],
[ 1625, [ 1635, 25, 50, 75, 100, 150, 200 250, 500 ] ],
[ 2035, [ 2050, 35 75, 50100, 75150, 125 250, 150 350, 200 500 ] ],
[ 2350, [ 2375, 35100, 50150, 75200, 125 250, 175 350, 250 500 ] ],
[ 2675, [ 26100, 35150, 50200, 75300, 125 400, 175 500, 2501000 ] ],
[ 30100, [ 30150, 40200, 50250, 75300, 125 400, 175 500, 2501000 ] ],
[ 35150, [ 35200, 45250, 50300, 100 400, 125 500, 1751000, 2502500 ] ],
[ 40200, [ 40500, 50750, 751000, 1002000, 1503500, 2505000, 3007500 ] ],
[ 45500, [ 45750, 501000, 751500, 1002500, 1505000, 2507500, 50010000 ] ],
[ 501000, [ 501000, 602000, 1003000, 1254000, 1755000, 2507500, 50010000 ] ],
[ 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 ] ]
]
},
'BRL'"EUR" : [ // also used for GBP
[ 0, [ 15 2, 25 5, 50 10, 75 20, 100 25, 150 35, 300 50 ] ],
[ 25 5, [ 25 5, 35 10, 50 15, 75 20, 100 35, 200 50, 300100 ] ],
[ 3010, [ 3010, 50 15, 75 20, 100 25, 150 35, 300 50, 500100 ] ],
[ 5015, [ 5015, 75 20, 100 25, 150 35, 225 50, 300 75, 500100 ] ],
[ 5020, [ 5020, 100 25, 150 35, 225 50, 300 75, 400100, 500150 ] ],
[ 7525, [ 7525, 125 30, 200 40, 250 50, 300 75, 400100, 500150 ] ],
[ 100 35, [ 100 35, 150 50, 225 75, 300 100, 500200, 750300, 1000 500 ] ],
[ 100 50, [ 100 50, 150 75, 225 100, 300 200, 500300, 1000 500, 1500 750 ] ],
[ 100 75, [ 75, 100, 150, 300 250, 500, 1000, 1500750, 30001000 ] ],
[ 250100, [ 250100, 500 150, 750 250, 1000 500, 1500 750, 30001000, 50002500 ] ],
[ 500150, [ 500150, 1000 200, 2000 300, 3000 500, 4000 750, 50001000, 10000 2000 ] ],
[ 1000 200, [ 1000 200, 2500 300, 5000 500, 7500 750, 10000 1000, 12500 2500, 15000 5000 ] ],
[ 1000 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000, 12500, 15000 ] ],
[ 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 ] ],
Line 449 ⟶ 333:
[ 10000, [ 10000, 25000, 50000, 75000, 100000, 150000, 200000 ] ]
],
'"SEK'" : [
[ 0, [ 2030, 50100, 100150, 200, 300500, 500750, 1000 ] ],
[ 3050, [ 30, 50, 100, 150, 200, 300, 500750, 1000 ] ],
[ 50, [ 50, 100, 150, 200, 300, 500, 1000 ] ],
[ 200, [ 50, 100, 200, 300, 500, 750, 1000 ] ]
]
Line 458 ⟶ 341:
radioAmountsData.AUD = radioAmountsData.USD;
radioAmountsData.CAD = radioAmountsData.USD;
radioAmountsData.GBP = radioAmountsData.USD;
radioAmountsData.NZD = radioAmountsData.USD;
 
radioAmountsData.EUR = 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 ] ],
Line 474 ⟶ 357:
[ 200, [ 100, 200, 300 ] ]
],
'"JPY'" : [
[ 0, [ 300, 500, 1000 ] ],
[ 3, [ 500, 1000, 1500 ] ],
Line 483 ⟶ 366:
[ 100, [ 5000, 10000, 15000 ] ]
],
'"SEK'" : [
[ 0, [ 20, 50, 100 ] ],
[ 3, [ 30, 50, 100 ] ],
Line 524 ⟶ 407:
};
 
var format;
if ( formats[currency] ) {
var format = formats[currency][language] || formats[currency]["'default"'] || formats[currency] || '\t';
} else {
format = '\t';
}
 
// Radio button amounts
Line 596 ⟶ 484:
/* 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
Line 628 ⟶ 516:
'BE' : 'vmaj',
'ES' : 'vmaj',
'FR' : 'CBvmavma', // Adyen - Carte Bancaire was removed
'IT' : 'vmaj',
'LU' : 'vmaj',
Line 635 ⟶ 523:
'PT' : 'vmaj',
'SK' : 'vmaj',
'GR' : 'vma',
// Others
'CZ' : 'vmad',
'DK' : 'vma',
'HU' : 'vma',
Line 646 ⟶ 536:
'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');
}
}
Line 655 ⟶ 547:
/* 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('');
$('input[name="amountGiven"]').val('');
}
 
/* -- Moved from Template:2012FR/Form-section/Processing/Default -- */
/**
* Validate form, and ifprep itmost looksof goodthe submit to paymentsparameters
*
* @param {string} paymentMethod - method e.g. 'cc', 'paypal'
* @param {string} paymentSubMethod - submethod e.g. 'rtbt_ideal' (a submethod of 'rtbt')
Line 677 ⟶ 568:
*/
donationForm.redirectPayment = function( paymentMethod, paymentSubMethod, skipAmountValidation ) {
 
var form = document.forms['donateForm']; // we should really change this some day
 
if ( donationForm.validate( skipAmountValidation ) ) {
 
ifvar (typeof paymentSubMethodparams == 'undefined') {};
paymentSubMethod = '';
}
var paymentsURL = 'https://payments.wikimedia.org/index.php/Special:GatewayFormChooser';
 
formparams.actioncurrency = paymentsURLdonationForm.currency;
params.country = donationForm.country;
 
// Overrides for specific cc gateways
if (typeof paymentSubMethod == 'undefined') {
if ( paymentSubMethodpaymentMethod === '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' ) {
// Temporary fix for https://phabricator.wikimedia.org/T254274#6188493
if ( paymentMethod == params.gateway = 'ccastropay' ) {;
form.gateway.value = 'ingenico';
}
 
//if Adyen( overridepaymentSubMethod for) cc{
params.payment_submethod = paymentSubMethod;
if ( paymentMethod === 'cc-adyen' ) {
paymentMethod = 'cc';
form.payment_method.value = 'cc';
form.gateway.value = 'adyen';
form.ffname.value = 'adyen';
}
// dLocal override for cc
if ( paymentMethod === 'cc-dlocal' ) {
paymentMethod = 'cc';
form.payment_method.value = 'cc';
form.gateway.value = 'astropay';
}
 
var frequency = $("'input[name='"frequency'"]:checked"').val();
if ( frequency !== 'monthly' ) {
frequencyparams.recurring = 'onetime'false;
form.recurring.value = 'false';
} else {
formparams.recurring.value = 'true';
}
 
params.uselang = mw.config.get('wgPageContentLanguage'); // see T281285 for why not wgUserLanguage
form.payment_method.value = paymentMethod;
form.payment_submethod.value = paymentSubMethod;
 
if ( params.uselang === 'pt' && params.country === 'BR' ) {
var full_dotted_payment_method = paymentMethod;
if ( form params.recurring.valueuselang == 'truept-br' ) {;
full_dotted_payment_method = 'r' + full_dotted_payment_method;
}
if ( paymentSubMethodparams.uselang )=== {'es' &&
( params.country === 'AR' || params.country === 'CL' ||
full_dotted_payment_method = form.payment_method.value + '.' + paymentSubMethod;
params.country === 'CO' || params.country === 'MX' ||
params.country === 'PE' || params.country === 'UY' ||
params.country === 'US' )
) {
params.uselang = 'es-419';
}
 
var amount = donationForm.getAmount();
// PTF - TODO: clean up form so we only use 'amount' and not 'amountGiven'
if ( $('#ptf-checkbox').prop('checked') ) {
var amount1amount = amount + donationForm.getAmountcalculateFee( amount );
document.getElementById('input_amount_other').checked = true;
form.amountGiven.value = amount1 + donationForm.calculateFee( amount1 );
donationForm.extraData.ptf = 1;
}
params.amount = amount;
 
// Email optin
donationForm.extraData.time = Math.round( (Date.now() - donationForm.loadedTime)/1000 );
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
}
 
form.utm_medium.value if =( mw.util.getParamValue( 'utm_mediumpym_variant' ); ) {
form.utm_campaign params.valuevariant = mw.util.getParamValue( 'utm_campaignpym_variant' );
}
form.utm_source.value = donationForm.buildUtmSource() + '.' + full_dotted_payment_method;
if ( params.recurring && params.variant && params.variant.match( /monthlyConvert/ ) ) {
form.utm_key.value = donationForm.buildUtmKey( donationForm.extraData );
// 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 );
}
 
form.method = 'GET';
form.submit();
} else {
donationForm.extraData.validateError = 1; // Flag they had an error, even if fixed later
Line 758 ⟶ 657:
 
/**
* Build afinal utm_sourcetracking valueparameters, includingand thesubmit landingto page info.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.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, '');
}
 
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 wmf_source value, including the landing page info.
*
* Own function so it can be overriden for weird tests
* Note this doesn't include payment method, that's added in redirectPayment method
*
* @returnparam {stringObject} utm_sourceparams
* @return {string} wmf_source
*/
donationForm.buildUtmSourcebuildTrackingSource = function( params ) {
 
var utm_sourcewmf_source = mw.util.getParamValue( 'utm_sourcewmf_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 */
Line 778 ⟶ 727:
 
/* The landing page info, separated by ~. This mostly exists for legacy reasons */
utm_sourcewmf_source += getParam( 'template' , 'Lp-layout' , 'default' ) + '~';
utm_sourcewmf_source += getParam( 'appeal-template' , 'Appeal-template-' , 'default' ) + '~';
utm_sourcewmf_source += getParam( 'appeal' , 'Appeal-' , 'default' ) + '~';
utm_sourcewmf_source += getParam( 'form-template' , 'Form-template-' , 'default' ) + '~';
utm_sourcewmf_source += getParam( 'form-countryspecific', 'Form-countryspecific-', 'control' );
 
wmf_source += '.' + fullDottedPaymentMethod;
return utm_source;
 
return wmf_source;
 
};
 
/**
* Build a string for utm_keywmf_key from extra tracking data
*
* @param {Object} data
* @return {string} utm_keywmf_key
*/
donationForm.buildUtmKeybuildTrackingKey = function(data) {
var existingKey = mw.util.getParamValue( 'wmf_key' ) || mw.util.getParamValue( 'utm_key' ),
var dataArray = [];
dataArray = [];
 
if ( existingKey ) {
dataArray.push( existingKey );
}
for (var key in data) {
if (data.hasOwnProperty(key)) {
Line 801 ⟶ 757:
}
}
return dataArray.join('.~');
};
 
/* Return amount selected or input */
donationForm.getAmount = function() {
var form = document.forms['.donateForm'];,
var amount = null;
donationForm.extraData.otherAmt = 0;
 
Line 814 ⟶ 770:
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 ) {
if ( form.input_amount_other_box.value !== '' ) {
var otherAmountamount = donationForm.parseOtherAmount( form.input_amount_other_box.value );
otherAmount = otherAmount.replace(/[,.](\d)$/, '\:$10');
otherAmount = otherAmount.replace(/[,.](\d)(\d)$/, '\:$1$2');
otherAmount = otherAmount.replace(/[\$£€¥,.]/g, '');
otherAmount = otherAmount.replace(/:/, '.');
form.amountGiven.value = otherAmount; // TODO: change this
amount = otherAmount;
donationForm.extraData.otherAmt = 1;
}
 
amount =return parseFloat(amount);
 
};
if ( isNaN(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;
}
 
};
 
 
/**
Line 848 ⟶ 815:
 
var error = false;
var form = document.forms['.donateForm'];
 
// Reset all errors
Line 859 ⟶ 826:
 
if ( form.opt_in ) {
if ( $("'input[name='"opt_in'"]:checked"').val() === undefined ) {
$('#error-optin').show();
error = true;
Line 876 ⟶ 843:
donationForm.validateAmount = function() {
 
var form = document.forms['donateForm'];
var amount = donationForm.getAmount();
var minAmount = donationForm.minimums[ donationForm.currency ] || 1;
var currency = form.currency_code.value;
var minAmount = donationForm.minimums[ currency ] || 1;
 
if ( amount === null || isNaN(amount) || amount <= 0 || amount < minAmount ) {
Line 907 ⟶ 872:
 
donationForm.updateFeeDisplay = function() {
var feeAmountselectedAmount = donationForm.calculateFee( donationForm.getAmount() );,
feeAmount = donationForm.calculateFee( selectedAmount ),
if ( feeAmount % 1 !== 0 ) { // Not a whole number
minAmount = donationForm.minimums[ donationForm.currency ] || 1,
feeAmount = feeAmount.toFixed(2);
maxAmount = donationForm.maxUSD * minAmount,
} else {
feeAmountfeeText, = feeAmount.toString()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();
}
$('.ptf label span').text( feeAmount );
$('.ptf').slideDown();
};
 
Line 923 ⟶ 893:
*/
donationForm.calculateFee = function( amount ) {
 
var form = document.forms['donateForm'];
 
// Minimum fee/PTF amounts. Default is 0.35.
Line 932 ⟶ 900:
'HUF' : 100,
'ILS' : 1.2,
'INR' : 254,
'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.575,
'ARS' : 1532,
'CLP' : 250322,
'COP' : 10001385,
'PEN' : 1.2,
'MXN' : 6,
'UYUPEN' : 121.3,
'UYU' : 13.7
};
 
var feeMultiplier = 0.04,
feeMinimum = feeMinimums[ formdonationForm.currency_code.valuecurrency ] || 0.35,
feeAmount = amount * feeMultiplier;
 
if ( feeAmount < feeMinimum ) {
feeAmount = feeMinimum;
}
return parseFloat( feeAmount.toFixed(2) );
Line 964 ⟶ 933:
donationForm.initOptin = function() {
$('.optin-options').on('change', function(e) {
 
$('#error-optin').hide();
 
Line 979 ⟶ 948:
}
});
};
 
/**
* 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;
}
};
 
Line 987 ⟶ 1,220:
mw.loader.using( ['mediawiki.util'] ).done( function() {
 
var form = document.forms['.donateForm'];
 
// BlockThese typingget symbolsused in inputquite field,a otherwisefew Safari allows them and then chokesplaces
try {
// https://phabricator.wikimedia.org/T118741, https://phabricator.wikimedia.org/T173431
donationForm.currency = form.currency_code.value;
var amountOtherInput = document.getElementById('input_amount_other_box');
if} catch ( amountOtherInput error) {
amountOtherInputdonationForm.onkeypresscurrency = function(e) {'USD';
// 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;
}
};
}
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
Line 1,029 ⟶ 1,255:
 
if ( form ) {
form.utm_medium.value = mw.util.getParamValue( 'utm_medium' );
form.utm_campaign.value = mw.util.getParamValue( 'utm_campaign' );
form.utm_key.value = mw.util.getParamValue( 'utm_key' );
 
// Striphide protocolfrequency tooptions stopfor firewallsome throwing fitscountries
if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) !== -1 ) {
form.referrer.value = document.referrer.replace(/https?:\/\//i, "");
$('#frequency_onetime').prop('checked', true);
$('.frequency-options, #cancel-monthly, #donate-recurring-smallprint').hide();
}
 
if ( donationForm.noRecurringPaypalCountries.indexOf( donationForm.country ) !== -1 ) {
// hide frequency options in India, where we can only handle one-time donations
if $( form'.countrypaymentmethod-pp, .valuepaymentmethod-pp-usd' ===).addClass( 'INnot-monthly-capable' ) {;
$("#frequency_onetime").prop('checked', true);
$(".frequency-options").hide();
$("#cancel-monthly").hide();
}
 
addCardTypesClass( formdonationForm.country.value );
 
// Only show Amazon for links from Ways to give
// TODO: remove utm_source when Ways to give has been updated
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();
}
}
}
 
Line 1,050 ⟶ 1,296:
 
// Disable logo link
$("'#p-logo a"').attr(" { href",: "'#"', title: '' } );
$("#p-logo a").attr("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') ) {
&& mw.util.getParamValue('monthly') !== '0'
&& donationForm.noRecurringCountries.indexOf( donationForm.country ) === -1
) {
$('#frequency_monthly').click();
}
Line 1,073 ⟶ 1,322:
}
finally {
$('.frb-monthly-pitch, .frb-monthly-pitch-thanks').appendTo('.frequency-options');
$('.ptf').appendTo('.amount-options');
$('.optin-options').insertAfter('.amount-options');

Latest revision as of 19:20, 6 June 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.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, '');
    }

    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 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();
            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
            // TODO: remove utm_source when Ways to give has been updated
			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();
                }
            }
        }

        // 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')
            && mw.util.getParamValue('monthly') !== '0'
            && 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();
        }

    });

});