Donate donatewiki https://foundation.wikimedia.org/wiki/Home MediaWiki 1.44.0-wmf.6 first-letter Media Special Talk User User talk Donate Donate talk File File talk MediaWiki MediaWiki talk Template Template talk Help Help talk Category Category talk Campaign Campaign talk TimedText TimedText talk Module Module talk MediaWiki:DonationForm.js 8 7993 40751 40750 2024-12-10T12:28:00Z Pcoombe 5 pass recipient_id to payments 40751 javascript text/javascript /* jshint strict:false */ /** MediaWiki:DonationForm.js - loaded on all donation forms * TODO: lots of cleanup */ var donationForm = {}; donationForm.loadedTime = Date.now(); donationForm.extraData = {}; donationForm.country = mw.util.getParamValue('country').toUpperCase(); try { donationForm.currency = document.forms.donateForm.currency_code.value; } catch (error) { donationForm.currency = 'USD'; } /** * Make language and country into a standard javascript Intl locale identifier * * @param {string} language * @param {string} country * @return {string} locale identifier e.g. en-GB */ donationForm.getLocale = function( language, country ) { // Sometimes in email testing links the uselang is a variable contiaining % // In that case fall back to English so locale code doesn't break form if ( language.match('%') ) { language = 'en'; } // MediaWiki allows some language codes like en-gb, en-ca, pt-br // We don't want these for a javascript locale, so drop anything after '-' language = language.split('-')[0]; return language + '-' + country; }; donationForm.locale = donationForm.getLocale( mw.config.get('wgPageContentLanguage'), donationForm.country ); // Don't offer recurring at all in these countries donationForm.noRecurringCountries = [ 'AR', 'IN' ]; donationForm.noRecurringPaypalCountries = [ 'CL', 'CO', 'PE', 'UY', 'BR' ]; donationForm.currencyRates = { // From https://github.com/wikimedia/wikimedia-fundraising-SmashPig/blob/master/PaymentData/ReferenceData/CurrencyRates.php // Updated 2024-07-31 'ADF' : 6.04, 'ADP' : 153, 'AED' : 3.67, 'AFA' : 70, 'AFN' : 70, 'ALL' : 90, 'AMD' : 368, 'ANG' : 1.79, 'AOA' : 844, 'AON' : 844, 'ARS' : 887, 'ATS' : 13, 'AUD' : 1.5, 'AWG' : 1.79, 'AZM' : 8500, 'AZN' : 1.7, 'BAM' : 1.8, 'BBD' : 2, 'BDT' : 116, 'BEF' : 37, 'BGL' : 1.8, 'BGN' : 1.8, 'BHD' : 0.37355757356689, 'BIF' : 2842, 'BMD' : 1, 'BND' : 1.35, 'BOB' : 6.71, 'BRL' : 5.1, 'BSD' : 1, 'BTN' : 83, 'BWP' : 13, 'BYR' : 32642, 'BZD' : 1.98, 'CAD' : 1.36, 'CDF' : 2786, 'CHF' : 0.9094629289448, 'CLP' : 890, 'CNY' : 7.23, 'COP' : 3803, 'CRC' : 498, 'CUC' : 1, 'CUP' : 25, 'CVE' : 101, 'CYP' : 0.53848627984321, 'CZK' : 23, 'DEM' : 1.8, 'DJF' : 178, 'DKK' : 6.86, 'DOP' : 58, 'DZD' : 133, 'ECS' : 24094, 'EEK' : 14, 'EGP' : 47, 'ESP' : 153, 'ETB' : 57, 'EUR' : 0.92005843390143, 'FIM' : 5.47, 'FJD' : 2.23, 'FKP' : 0.78703952551207, 'FRF' : 6.04, 'GBP' : 0.78703952551207, 'GEL' : 2.71, 'GHC' : 143125, 'GHS' : 14, 'GIP' : 0.78703952551207, 'GMD' : 68, 'GNF' : 8493, 'GRD' : 314, 'GTQ' : 7.57, 'GYD' : 200, 'HKD' : 7.8, 'HNL' : 24, 'HRK' : 6.93, 'HTG' : 132, 'HUF' : 355, 'IDR' : 15986, 'IEP' : 0.72460490043714, 'ILS' : 3.69, 'INR' : 83, 'IQD' : 1290, 'IRR' : 42009, 'ISK' : 138, 'ITL' : 1781, 'JMD' : 154, 'JOD' : 0.70900000000001, 'JPY' : 156, 'KES' : 130, 'KGS' : 88, 'KHR' : 3993, 'KMF' : 453, 'KPW' : 135, 'KRW' : 1358, 'KWD' : 0.30629670764681, 'KYD' : 0.83333299999999, 'KZT' : 442, 'LAK' : 21103, 'LBP' : 89393, 'LKR' : 298, 'LRD' : 193, 'LSL' : 18, 'LTL' : 3.18, 'LUF' : 37, 'LVL' : 0.64662074757963, 'LYD' : 4.8, 'MAD' : 9.79, 'MDL' : 17, 'MGA' : 4379, 'MGF' : 9150, 'MKD' : 56, 'MMK' : 2075, 'MNT' : 2620, 'MOP' : 8.03, 'MRO' : 391, 'MTL' : 0.39498108567387, 'MUR' : 45, 'MVR' : 15, 'MWK' : 1720, 'MXN' : 17, 'MYR' : 4.68, 'MZM' : 63200, 'MZN' : 63, 'NAD' : 18, 'NGN' : 1505, 'NIO' : 36, 'NLG' : 2.03, 'NOK' : 11, 'NPR' : 131, 'NZD' : 1.63, 'OMR' : 0.38377594841305, 'PAB' : 1, 'PEN' : 3.67, 'PGK' : 3.76, 'PHP' : 58, 'PKR' : 277, 'PLN' : 3.91, 'PTE' : 184, 'PYG' : 7355, 'QAR' : 3.56, 'ROL' : 45713, 'RON' : 4.57, 'RSD' : 108, 'RUB' : 91, 'RWF' : 1277, 'SAR' : 3.75, 'SBD' : 8.37, 'SCR' : 13, 'SDD' : 59800, 'SDG' : 598, 'SDP' : 2261, 'SEK' : 11, 'SGD' : 1.35, 'SHP' : 0.78703952551207, 'SIT' : 220, 'SKK' : 28, 'SLL' : 19750, 'SOS' : 549, 'SRD' : 33, 'SRG' : 33320, 'STD' : 22477, 'SVC' : 8.75, 'SYP' : 513, 'SZL' : 18, 'THB' : 36, 'TJS' : 11, 'TMM' : 16750, 'TMT' : 3.35, 'TND' : 3.11, 'TOP' : 2.32, 'TRL' : 32168418, 'TRY' : 32, 'TTD' : 6.64, 'TWD' : 32, 'TZS' : 2587, 'UAH' : 39, 'UGX' : 3760, 'USD' : 1, 'UYU' : 38, 'UZS' : 12662, 'VEB' : 3651907631, 'VEF' : 3651908, 'VND' : 25451, 'VUV' : 112, 'WST' : 2.67, 'XAF' : 604, 'XAG' : 0.031347411860134, 'XAU' : 0.00041128929241299, 'XCD' : 2.7, 'XEU' : 0.92005843390143, 'XOF' : 604, 'XPD' : 0.00098009826645798, 'XPF' : 110, 'XPT' : 0.00093444018680404, 'YER' : 249, 'YUN' : 108, 'ZAR' : 18, 'ZMK' : 5176, 'ZWD' : 373 }; /* Amount and currency formatting */ let formatters = { // Amounts without currency symbol amountFraction: new Intl.NumberFormat( donationForm.locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 } ), amountWhole: new Intl.NumberFormat( donationForm.locale, {} ) }; // currencyDisplay: 'narrowSymbol' fixes some issues like en-CO showing the ISO code // but browser support is lacking, so wrap in a try/catch try { formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol' } ); formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol', minimumFractionDigits: 0 } ); } catch(e) { formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency } ); formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, minimumFractionDigits: 0 } ); } donationForm.formatCurrency = function( amount ) { if ( amount % 1 !== 0 ) { // Not a whole number return formatters.currencyFraction.format( amount ); } else { return formatters.currencyWhole.format( amount ); } }; donationForm.formatAmount = function( amount ) { var formatterOptions, output; if ( amount % 1 !== 0 ) { // Not a whole number return formatters.amountFraction.format( amount ); } else { return formatters.amountWhole.format( amount ); } }; /* Localize the amount errors. Call when initialising form. */ donationForm.localizeErrors = function() { var currency = donationForm.currency; $('.lp-error-smallamount').text( function( index, oldText ) { return oldText.replace( '$1', donationForm.formatAmount( donationForm.minLocal ) + '\xa0' + currency ); }); if ( currency === 'USD' ) { // we don't need to include the conversion $('.lp-error-bigamount').text( function( index, oldText ) { return oldText.replace( '($1 $2) ', '' ) .replace( '($1&nbsp;$2) ', '' ); }); } $('.lp-error-bigamount').text( function( index, oldText ) { return oldText.replace( '$1', donationForm.formatAmount( donationForm.maxLocal ) ) .replace( '$2', currency ) .replace( '$3', 'benefactors@wikimedia.org' ) .replace( '$4', donationForm.formatAmount( donationForm.maxUSD ) ); }); }; function adjustHPC() { /* Adjust amounts based on highest previous contribution (hpc) or most recent contribution (mrc) parameter. Used for emails. TODO: split data out? */ var hpcSet = mw.util.getParamValue('hpcSet'); // Look for 'hpc' parameter, then 'mrc' var hpc = parseFloat( mw.util.getParamValue('hpc') ); if( isNaN(hpc) ) { hpc = parseFloat( mw.util.getParamValue('mrc') ); if( isNaN(hpc) ) { if ( hpcSet ) { // Allow using hpcSet even without hpc, for MG appeals hpc = 0; } else { return; } } } var currency = donationForm.currency; // If changing, please update https://docs.google.com/spreadsheets/d/1e02TsZ_bKDAS1BMVBCdyo9D7RGln_wCGnkg7IF5kU5s/edit var radioAmountsData = { "USD" : { // also used for CAD, AUD, NZD "default" : [ [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_USD" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_USD" : [ // Upgrade recurring amount dynamically [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2.75, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 3.50, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3.75, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4.50, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6.75, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15.75, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 24.75, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 44.75, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_USD" : [ // Give less reactivation amount [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ], // Direct Mail - fixed amounts "directmail" : [ [ 0, [ 25, 35, 50, 100, 150, 250, 300 ] ] ], "directmail250" : [ [ 0, [ 250, 300, 500, 750, 1000, 2500, 5000 ] ] ] }, "EUR" : { "default" : [ [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_EUR" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_EUR" : [ // Upgrade recurring amount dynamically [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2.50, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 2.50, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3.50, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4.25, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6.25, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 25, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 45, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_EUR" : [ // Give less reactivation amount [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ] }, "GBP" : { "default" : [ [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_GBP" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_GBP" : [ // Upgrade recurring amount dynamically [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 2, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 20, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 40, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 45, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 125, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 200, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 400, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_GBP" : [ // Give less reactivation amount [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ] }, "JPY" : [ [ 0, [ 500, 1000, 2000, 2500, 4000, 5000, 10000 ] ], [ 1000, [ 1000, 1500, 2500, 4000, 5000, 10000, 15000 ] ], [ 1500, [ 1500, 2000, 3000, 4000, 5000, 10000, 15000 ] ], [ 2000, [ 2000, 2500, 3500, 5000, 7500, 10000, 25000 ] ], [ 2500, [ 2500, 3500, 5000, 7500, 10000, 15000, 25000 ] ], [ 3000, [ 3000, 4000, 5000, 7500, 10000, 15000, 25000 ] ], [ 2500, [ 2500, 5000, 7500, 10000, 20000, 30000, 50000 ] ], [ 2500, [ 2500, 5000, 7500, 10000, 20000, 50000, 100000 ] ], [ 5000, [ 5000, 10000, 15000, 20000, 35000, 50000, 100000 ] ], [ 10000, [ 10000, 25000, 50000, 75000, 100000, 150000, 200000 ] ] ], "SEK" : [ [ 0, [ 30, 100, 150, 200, 500, 750, 1000 ] ], [ 50, [ 50, 100, 150, 200, 300, 750, 1000 ] ], [ 200, [ 50, 100, 200, 300, 500, 750, 1000 ] ] ] }; radioAmountsData.AUD = radioAmountsData.USD; radioAmountsData.CAD = radioAmountsData.USD; radioAmountsData.NZD = radioAmountsData.USD; // Major gifts appeals, hacky but this is easier than adding a load of new forms to maintain var currencyList = [ 'USD', 'CAD', 'AUD', 'NZD', 'GBP', 'EUR' ]; // close enough for ( let i = 0; i < currencyList.length; i++ ) { radioAmountsData[ currencyList[i] ].MG_2024_500 = [ [ 0, [ 500, 750, 1000, 1250, 1500, 1750, 2000 ] ] ]; radioAmountsData[ currencyList[i] ].MG_2024_650 = [ [ 0, [ 650, 750, 1000, 1250, 1500, 1750, 2000 ] ] ]; } var appealAmountsData = { "USD" : [ // also used for CAD, AUD, NZD, GBP, EUR [ 0, [ 5, 10, 20 ] ], [ 10, [ 10, 20, 50 ] ], [ 20, [ 20, 30, 50 ] ], [ 35, [ 20, 30, 50 ] ], [ 50, [ 20, 50, 100 ] ], [ 75, [ 50, 75, 100 ] ], [ 100, [ 75, 100, 150 ] ], [ 150, [ 75, 100, 200 ] ], [ 200, [ 100, 200, 300 ] ] ], "JPY" : [ [ 0, [ 300, 500, 1000 ] ], [ 3, [ 500, 1000, 1500 ] ], [ 5, [ 1000, 1500, 2000 ] ], [ 10, [ 1500, 2000, 5000 ] ], [ 20, [ 2000, 3000, 5000 ] ], [ 50, [ 2000, 5000, 10000 ] ], [ 100, [ 5000, 10000, 15000 ] ] ], "SEK" : [ [ 0, [ 20, 50, 100 ] ], [ 3, [ 30, 50, 100 ] ], [ 5, [ 50, 100, 150 ] ], [ 15, [ 100, 150, 200 ] ], [ 23, [ 100, 200, 300 ] ], [ 38, [ 100, 200, 500 ] ], [ 75, [ 100, 500, 750 ] ], [ 112, [ 100, 500, 1000 ] ] ] }; appealAmountsData.AUD = appealAmountsData.USD; appealAmountsData.CAD = appealAmountsData.USD; appealAmountsData.GBP = appealAmountsData.USD; appealAmountsData.NZD = appealAmountsData.USD; appealAmountsData.EUR = appealAmountsData.USD; // Radio button amounts var radioAmounts = pickAmountArray( radioAmountsData, currency, hpc, hpcSet ); if ( radioAmounts.length ) { // Change buttons for (var j = 0; j < radioAmounts.length; j++) { var $radio = $("#input_amount_" + j); var $label = $("label[for='input_amount_" + j + "']"); $radio.val( radioAmounts[j] ); $label.text( donationForm.formatCurrency( radioAmounts[j] ) ); } } // Appeal amounts var appealAmounts = pickAmountArray( appealAmountsData, currency, hpc, hpcSet ); if ( appealAmounts.length ) { var appealAmountString = appealAmounts.map( donationForm.formatCurrency ).join( ', '); $('.consider-amounts').html(appealAmountString); } } function pickAmountArray( data, currency, hpc, hpcSet ) { /** * Choose the amounts for radio buttons / appeal based on hpc * @param {Object} data * @param {String} currency * @param {Number} hpc * @param {String} hpcSet * @return {Array} Array of amounts (as numbers) */ var set, amounts; if ( !(currency in data) ) { return []; } if ( $.isArray(data[currency]) ) { // No variant sets set = data[currency]; } else { // We need to go deeper. Check the variants. if ( hpcSet in data[currency] ) { set = data[currency][hpcSet]; } else { set = data[currency]['default']; } } // Find correct amount array for this hpc for (var i = 0; i < set.length; i++) { if ( set[i][0] > hpc ) { break; } amounts = set[i][1]; } return amounts; } function preSelect() { /* Check for a 'preSelect' url parameter, and select that option. If there isn't an option, add it to the "Other" box and select that */ var preSelectAmount = parseFloat( mw.util.getParamValue('preSelect') ); if ( preSelectAmount > 0 ) { var $preSelectOption = $('input[name="amount"][value="' + preSelectAmount + '"]'); if ( $preSelectOption.length ) { // Select existing input $preSelectOption.prop('checked', true); } else { $('#input_amount_other_box').val( preSelectAmount ); $('#input_amount_other').prop('checked', true); } donationForm.updateFeeDisplay(); } } function addCardTypesClass(country) { /** * Add card types class to credit card button, so we can show correct logos * Banner equivalent: https://meta.wikimedia.org/wiki/MediaWiki:FundraisingBanners/LocalizeJS-2017.js * @param {String} country ISO code */ var cardTypes = { // Big 6 'US' : 'vmad', 'CA' : 'vma', 'GB' : 'vmaj', 'IE' : 'vmaj', 'AU' : 'vmaj', 'NZ' : 'vma', // Euro countries 'AT' : 'vmaj', 'BE' : 'vmaj', 'ES' : 'vmaj', 'FR' : 'vma', // Adyen - Carte Bancaire was removed 'IT' : 'vmaj', 'LU' : 'vmaj', 'LV' : 'vma', 'NL' : 'vmaj', 'PT' : 'vmaj', 'SK' : 'vmaj', 'GR' : 'vma', // Others 'CZ' : 'vmad', 'DK' : 'vma', 'HU' : 'vma', 'IL' : 'vmad', // Adyen 'JP' : 'vmaj', 'MY' : 'vmaj', 'NO' : 'vma', 'PL' : 'vma', 'RO' : 'vma', 'SE' : 'vma', 'UA' : 'vma', // Adyen 'ZA' : 'vm', 'ZZ' : 'vmad' // For testing }; if ( cardTypes[country] ) { $('.paymentmethod-cc').addClass('cctypes-' + cardTypes[country] ); $('.cc-text-label').addClass('sr-only'); } } /* Form functions */ function clearOther(box) { document.getElementById('input_amount_other').checked = true; box.value = ""; } function selectOther() { document.getElementById('input_amount_other').checked = true; } function selectAmount() { $('#input_amount_other_box').val(''); } /* -- Moved from Template:2012FR/Form-section/Processing/Default -- */ /** * Validate form, and prep most of the parameters * * @param {string} paymentMethod - method e.g. 'cc', 'paypal' * @param {string} paymentSubMethod - submethod e.g. 'rtbt_ideal' (a submethod of 'rtbt') * @param {string} skipAmountValidation - skip validating amount for PayPal forced to USD */ donationForm.redirectPayment = function( paymentMethod, paymentSubMethod, skipAmountValidation ) { if ( donationForm.validate( skipAmountValidation ) ) { var params = {}; params.currency = donationForm.currency; params.country = donationForm.country; // Overrides for specific cc gateways if ( paymentMethod === 'cc-adyen' ) { params.payment_method = 'cc'; params.gateway = 'adyen'; } else if ( paymentMethod === 'cc-dlocal' ) { params.payment_method = 'cc'; params.gateway = 'astropay'; } else { params.payment_method = paymentMethod; } if ( params.payment_method === 'cc' && params.country === 'ZA' ) { params.gateway = 'astropay'; } if ( paymentSubMethod ) { params.payment_submethod = paymentSubMethod; } let frequency = donationForm.getFrequency(); if ( frequency === 'monthly' ) { params.recurring = '1'; params.frequency_unit = 'month'; } else if ( frequency === 'annual' ) { params.recurring = '1'; params.frequency_unit = 'year'; } params.uselang = mw.config.get('wgPageContentLanguage'); // see T281285 for why not wgUserLanguage if ( params.uselang === 'pt' && params.country === 'BR' ) { params.uselang = 'pt-br'; } if ( params.uselang === 'es' && ( params.country === 'AR' || params.country === 'CL' || params.country === 'CO' || params.country === 'MX' || params.country === 'PE' || params.country === 'UY' || params.country === 'US' ) ) { params.uselang = 'es-419'; } var amount = donationForm.getAmount(); if ( $('#ptf-checkbox').prop('checked') ) { amount = amount + donationForm.calculateFee( amount ); donationForm.extraData.ptf = 1; } params.amount = amount; // Email optin if ( $('input[name="opt_in"]').length > 0 ) { var opt_inValue = $('input[name="opt_in"]:checked').val(); params.opt_in = opt_inValue; // donationForm.validate() already checked it's 1 or 0 } if ( mw.util.getParamValue( 'pym_variant' ) ) { params.variant = mw.util.getParamValue( 'pym_variant' ); } if ( params.recurring && params.variant && params.variant.match( /monthlyConvert/ ) ) { // Post-payments monthly convert makes no sense if it's already recurring // Avoid things like T312905 delete params.variant; } // TODO: refactor this to a list of parameters to pass unchanged // or just pass everything by default? if ( mw.util.getParamValue( 'pym_appeal' ) ) { params.appeal = mw.util.getParamValue( 'pym_appeal' ); } // https://phabricator.wikimedia.org/T381405 if ( mw.util.getParamValue( 'contact_id' ) ) { params.contact_id = mw.util.getParamValue( 'contact_id' ); } if ( mw.util.getParamValue( 'contact_hash' ) ) { params.contact_hash = mw.util.getParamValue( 'contact_hash' ); } // SMS if ( mw.util.getParamValue( 'recipient_id' ) ) { params.contact_hash = mw.util.getParamValue( 'recipient_id' ); } // Monthly convert if ( mc ) { // check just in-case this wasn't loaded for some reason mc.main( params, donationForm.finalStep ); } else { donationForm.finalStep( params ); } } else { donationForm.extraData.validateError = 1; // Flag they had an error, even if fixed later } return false; // don't submit if called by a button }; /** * Build final tracking parameters, and submit to payments * @param {Object} params */ donationForm.finalStep = function( params ) { var url = new URL('https://payments.wikimedia.org/index.php/Special:GatewayChooser'); // Skip form chooser for Apple Pay / Google Pay if ( params.payment_method === 'apple' || params.payment_method === 'google' ) { url = new URL('https://payments.wikimedia.org/index.php/Special:AdyenCheckoutGateway'); } // Skip form chooser for Venmo if ( params.payment_method === 'venmo' ) { url = new URL('https://payments.wikimedia.org/index.php/Special:BraintreeGateway'); } donationForm.extraData.time = Math.round( (Date.now() - donationForm.loadedTime)/1000 ); // Tracking data params.wmf_medium = mw.util.getParamValue( 'wmf_medium' ) || mw.util.getParamValue( 'utm_medium' ); params.wmf_campaign = mw.util.getParamValue( 'wmf_campaign' ) || mw.util.getParamValue( 'utm_campaign' ); params.wmf_source = donationForm.buildTrackingSource( params ); params.wmf_key = donationForm.buildTrackingKey( donationForm.extraData ); if ( document.referrer ) { // TODO: do we need this? // Strip protocol to stop firewall complaining params.referrer = document.referrer.replace(/https?:\/\//i, ''); } for ( var key of Object.keys( params ) ) { url.searchParams.set( key, params[key] ); } if ( window.top !== window.self ) { // In a frame, open payments in a new tab window.open( url.toString() ); } else { window.location.href = url.toString(); } }; /** * Build a wmf_source value, including the landing page info. * * Own function so it can be overriden for weird tests * * @param {Object} params * @return {string} wmf_source */ donationForm.buildTrackingSource = function( params ) { var wmf_source = mw.util.getParamValue( 'wmf_source' ) || mw.util.getParamValue( 'utm_source' ); wmf_source += '.'; var fullDottedPaymentMethod = params.payment_method; if ( params.recurring ) { fullDottedPaymentMethod = 'r' + fullDottedPaymentMethod; } if ( params.payment_submethod ) { fullDottedPaymentMethod = fullDottedPaymentMethod + '.' + params.payment_submethod; } /* Get URL parameter, but remove parts using old format. Allow fallback to a default value */ var getParam = function( param, removeText, dflt ) { if ( mw.util.getParamValue( param ) ) { return mw.util.getParamValue( param ).replace( removeText, '' ); } else { return dflt; } }; /* The landing page info, separated by ~. This mostly exists for legacy reasons */ wmf_source += getParam( 'template' , 'Lp-layout' , 'default' ) + '~'; wmf_source += getParam( 'appeal-template' , 'Appeal-template-' , 'default' ) + '~'; wmf_source += getParam( 'appeal' , 'Appeal-' , 'default' ) + '~'; wmf_source += getParam( 'form-template' , 'Form-template-' , 'default' ) + '~'; wmf_source += getParam( 'form-countryspecific', 'Form-countryspecific-', 'control' ); wmf_source += '.' + fullDottedPaymentMethod; return wmf_source; }; /** * Build a string for wmf_key from extra tracking data * * @param {Object} data * @return {string} wmf_key */ donationForm.buildTrackingKey = function(data) { var existingKey = mw.util.getParamValue( 'wmf_key' ) || mw.util.getParamValue( 'utm_key' ), dataArray = []; if ( existingKey ) { dataArray.push( existingKey ); } for (var key in data) { if (data.hasOwnProperty(key)) { dataArray.push( key + '_' + data[key] ); } } return dataArray.join('~'); }; /* Return amount selected or input */ donationForm.getAmount = function() { var form = document.forms.donateForm, amount = null; donationForm.extraData.otherAmt = 0; // If there are some amount radio buttons, then look for the checked one if ( form.amount ) { for ( var i = 0; i < form.amount.length; i++ ) { if ( form.amount[i].checked ) { amount = parseFloat( form.amount[i].value ); } } } // Check the "other" amount box if ( document.getElementById('input_amount_other').checked ) { amount = donationForm.parseOtherAmount( form.input_amount_other_box.value ); donationForm.extraData.otherAmt = 1; } return amount; }; /** * Parse Other field value into amount * * Does some awful regex stuff to rm symbols and turn the string into a number * Remember some locales flip . & , for decimal point/thousands separator * * @param {string} value Value of "Other" field * @return {float} Float with amount, or 0 if NaN */ donationForm.parseOtherAmount = function( value ) { var amount; value = value.replace(/[,.](\d)$/, '\:$10'); value = value.replace(/[,.](\d)(\d)$/, '\:$1$2'); value = value.replace(/[\$£€¥,.]/g, ''); value = value.replace(/:/, '.'); amount = parseFloat( value ); if ( isNaN( amount ) ) { return 0; } else { return amount; } }; /** * Validate the form. */ donationForm.validate = function( skipAmountValidation ) { var error = false; var form = document.forms.donateForm; // Reset all errors $('.lp-haserror').removeClass('lp-haserror'); $('.lp-error').hide(); if ( !skipAmountValidation && !donationForm.validateAmount() ) { error = true; } if ( form.opt_in ) { if ( $('input[name="opt_in"]:checked').val() === undefined ) { $('#error-optin').show().focus(); error = true; } else { $('#error-optin').hide(); } } return !error; }; /** * Check if selected amount is valid i.e. a positive number, between minimum and maximum. * If not, show an error and return false. */ donationForm.validateAmount = function() { var amount = donationForm.getAmount(); if ( amount === null || isNaN(amount) || amount <= 0 || amount < donationForm.minLocal ) { $('.amount-options').addClass('lp-haserror'); $('.lp-error-bigamount').hide(); $('.lp-error-smallamount').show().focus(); return false; } else if ( amount > donationForm.maxLocal ) { $('.amount-options').addClass('lp-haserror'); $('.lp-error-bigamount').show().focus(); return false; } else { $('.amount-options').removeClass('lp-haserror'); $('.lp-error-smallamount, .lp-error-bigamount').hide(); return true; } }; donationForm.getFrequency = function() { return document.forms.donateForm.dataset.frequency || 'onetime'; }; donationForm.setFrequency = function( frequency ) { // TODO: add some validation to reject invalid frequency values let form = document.forms.donateForm; form.frequency.value = frequency; // change input form.dataset.frequency = frequency; }; /* Wrapper for compatibility with old forms */ donationForm.toggleMonthly = function( monthly ) { if ( monthly ) { donationForm.setFrequency( 'monthly' ); } else { donationForm.setFrequency( 'onetime' ); } }; donationForm.updateFeeDisplay = function() { var selectedAmount = donationForm.getAmount(), feeAmount = donationForm.calculateFee( selectedAmount ), feeText; feeText = donationForm.formatCurrency( feeAmount ); $('.ptf label span').text( feeText ); if ( selectedAmount + feeAmount <= donationForm.maxLocal ) { $('.ptf').slideDown(); } }; /** * Calculate approximate transaction fee on given amount * @param {number} amount * @return {number} Rounded to 2 decimal places */ donationForm.calculateFee = function( amount ) { // Minimum fee/PTF amounts. Default is 0.35. // Updated 2019-05-21 to approx 0.35 USD equivalent var feeMinimums = { 'DKK' : 2, 'HUF' : 100, 'ILS' : 1.2, 'INR' : 4, 'JPY' : 35, 'MYR' : 1, 'NOK' : 3, 'PLN' : 1.35, 'CZK' : 7.5, 'RON' : 1.5, 'SEK' : 3, 'UAH' : 10, 'ZAR' : 5, // Latin America // Updated 2024-08-22 to approx 0.35 USD equivalent 'BRL' : 1.75, 'ARS' : 300, 'CLP' : 300, 'COP' : 1400, 'MXN' : 6, 'PEN' : 1.2, 'UYU' : 14 }; var feeMultiplier = 0.04, feeMinimum = feeMinimums[ donationForm.currency ] || 0.35, feeAmount = amount * feeMultiplier; if ( feeAmount < feeMinimum ) { feeAmount = feeMinimum; } return parseFloat( feeAmount.toFixed(2) ); }; donationForm.initOptin = function() { $('.optin-options').on('change', function(e) { $('#error-optin').hide(); // Only do all this if we have translated prompts if ( $('.optin-no-prompt').data('is-translated') === 'yes' ) { if ( e.target.id === 'optin-no' ) { $('.optin-no-prompt').removeClass('is-positive'); if ( !$('.optin-no-prompt').is(':visible') ) { $('.optin-no-prompt').slideDown(); } } else { $('.optin-no-prompt').addClass('is-positive'); } } }); }; /** * Block typing letters and symbols in given input. Used for Other amount inputs * * If we don't do this, Safari allows typing them and then chokes on submit * https://phabricator.wikimedia.org/T118741, https://phabricator.wikimedia.org/T173431 * * @param {Element} inputElement The element to block typing on */ donationForm.otherInputControl = function( inputElement ) { if ( inputElement ) { inputElement.onkeypress = function(e) { // Allow special keys in Firefox if ((e.code == 'ArrowLeft') || (e.code == 'ArrowRight') || (e.code == 'ArrowUp') || (e.code == 'ArrowDown') || (e.code == 'Delete') || (e.code == 'Backspace')) { return; } var chr = String.fromCharCode(e.which); if ('0123456789., '.indexOf(chr) === -1) { return false; } }; } }; /** * Should we show Apple Pay? * * Note there is a ~500ms delay in Safari when checking, so only call this if needed * * @param {string} country * @return {boolean} */ donationForm.shouldShowApplePay = function ( country ) { if ( location.search.match('forceApplePay') ) { return true; } if ( window.ApplePaySession ) { if ( ApplePaySession.canMakePayments() ) { return true; } } return false; }; /* Based on github:braintree/braintree-web/src/venmo/shared/supports-venmo.js See also on meta: MediaWiki:FundraisingBanners/VenmoBrowserCheck.js */ donationForm.isVenmoSupported = function(options) { var options = options || { allowNewBrowserTab: false, allowWebviews: true, allowDesktop: true, allowDesktopWebLogin: true }; var ua = window.navigator.userAgent; var merchantAllowsReturningToNewBrowserTab, merchantAllowsWebviews, merchantAllowsDesktopBrowsers; var isMobileDevice = isAndroid() || isIos(); var isAndroidChrome = isAndroid() && isChrome(); var isMobileDeviceThatSupportsReturnToSameTab = isIosSafari() || isAndroidChrome; var isKnownUnsupportedMobileBrowser = isIosChrome() || isFacebookOwnedBrowserOnAndroid() || isSamsung(); options = options || {}; // NEXT_MAJOR_VERSION allowDesktop will default to true, but can be opted out merchantAllowsDesktopBrowsers = (options.allowDesktopWebLogin || options.allowDesktop) === true; merchantAllowsReturningToNewBrowserTab = options.hasOwnProperty( "allowNewBrowserTab" ) ? options.allowNewBrowserTab : true; // NEXT_MAJOR_VERSION webviews are not supported, except for the case where // the merchant themselves is presenting venmo in a webview using the deep // link url to get back to their app. For the next major version, we should // just not have this option and instead require the merchant to determine // if the venmo button should be displayed when presenting it in the // merchant's app via a webview. merchantAllowsWebviews = options.hasOwnProperty("allowWebviews") ? options.allowWebviews : true; if (isKnownUnsupportedMobileBrowser) { return false; } if ( !merchantAllowsWebviews && (isAndroidWebview() || isIosWebview()) ) { return false; } if (!isMobileDevice) { return merchantAllowsDesktopBrowsers; } if (!merchantAllowsReturningToNewBrowserTab) { return isMobileDeviceThatSupportsReturnToSameTab; } return isMobileDevice; /* -- functions mostly from github:braintree/browser-detection library -- */ function isAndroid() { return /Android/i.test(ua); } function isIos(checkIpadOS = true) { const iOsTest = /iPhone|iPod|iPad/i.test(ua); return checkIpadOS ? iOsTest || isIpadOS() : iOsTest; } function isIpadOS() { // "ontouchend" is used to determine if a browser is on an iPad, otherwise // user-agents for iPadOS behave/identify as a desktop browser return /Mac|iPad/i.test(ua) && "ontouchend" in window.document; } function isEdge() { return ua.indexOf("Edge/") !== -1 || ua.indexOf("Edg/") !== -1; } function isSamsung() { return /SamsungBrowser/i.test(ua); } function isDuckDuckGo() { return ua.indexOf("DuckDuckGo/") !== -1; } function isOpera() { return ( ua.indexOf("OPR/") !== -1 || ua.indexOf("Opera/") !== -1 || ua.indexOf("OPT/") !== -1 ); } function isSilk() { return ua.indexOf("Silk/") !== -1; } function isChrome() { return ( (ua.indexOf("Chrome") !== -1 || ua.indexOf("CriOS") !== -1) && !isEdge() && !isSamsung() && !isDuckDuckGo() && !isOpera() && !isSilk() ); } function isIosFirefox() { return /FxiOS/i.test(ua); } function isWebkit() { const webkitRegexp = /webkit/i; return webkitRegexp.test(ua); } function isIosChrome() { return ua.indexOf("CriOS") > -1; } function isFacebook() { return ua.indexOf("FBAN") > -1; } function isIosSafari() { return ( isIos() && isWebkit() && !isIosChrome() && !isIosFirefox() && !isFacebook() ); } function isFacebookOwnedBrowserOnAndroid() { var e = ua.toLowerCase(); return -1 < e.indexOf("huawei") && -1 < e.indexOf("fban") || isAndroid() && (-1 < e.indexOf("fb_iab") || -1 < e.indexOf("instagram")); } function isSamsungBrowser() { return /SamsungBrowser/i.test(ua); } function isAndroidWebview() { return isAndroid() && -1 < ua.toLowerCase().indexOf("wv"); } function isGoogleSearchApp() { return /\bGSA\b/.test(ua); } function isIosGoogleSearchApp() { return isIos() && isGoogleSearchApp(); } function isIosWebview() { if (isIos()) { // The Google Search iOS app is technically a webview and doesn't support popups. if (isIosGoogleSearchApp()) { return true; } // Historically, a webview could be identified by the presence of AppleWebKit and _no_ presence of Safari after. return /.+AppleWebKit(?!.*Safari)/i.test(ua); } return false; } }; /* End form functions */ $(document).ready(function() { mw.loader.using( ['mediawiki.util'] ).done( function() { var form = document.forms.donateForm; // Minimum amount is usually about 1 USD donationForm.minLocal = donationForm.currencyRates[ donationForm.currency ]; donationForm.minLocal = Math.ceil( donationForm.minLocal * 100 ) / 100; // Round it up donationForm.maxUSD = 25000; donationForm.maxLocal = Math.floor( donationForm.currencyRates[ donationForm.currency ] * donationForm.maxUSD ); // Overrides for India if ( donationForm.currency === 'INR' ) { donationForm.minLocal = 10; // Until https://phabricator.wikimedia.org/T370583 fixed? donationForm.maxUSD = 3000; donationForm.maxLocal = 250000; } // Block typing symbols in Other field donationForm.otherInputControl( document.getElementById('input_amount_other_box') ); // Clear errors and update fee when selected/entered $('.amount-options').on( 'input change', function() { // Ideally we would validate the amount, but this causes issues with focus $('.amount-options .lp-error').hide(); donationForm.updateFeeDisplay(); }); // Disable submitting form with Enter key $('form[name="donateForm"]').on('keypress', function(e) { var code = ( e.keyCode ? e.keyCode : e.which ); if ( code == 13 ) { e.preventDefault(); } }); // But allow Enter on buttons $('.payment-method-button').keyup(function(e) { if (event.keyCode === 13) { e.target.click(); } }); if ( form ) { // hide frequency options for some countries if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) !== -1 ) { $('#frequency_onetime').prop('checked', true); $('.frequency-options, #cancel-monthly, #donate-recurring-smallprint').hide(); } if ( donationForm.noRecurringPaypalCountries.indexOf( donationForm.country ) !== -1 ) { $( '.paymentmethod-pp, .paymentmethod-pp-usd' ).addClass( 'not-monthly-capable' ); } // Format amounts on buttons $( '.amount-options li' ).each( function( index ) { let amount = this.querySelector( 'input' ).value; if ( amount !== 'Other' ) { this.querySelector( 'label' ).innerText = donationForm.formatCurrency( amount ); } }); addCardTypesClass( donationForm.country ); // Only show Amazon for links from Ways to give if ( mw.util.getParamValue( 'wmf_source' ) === 'Waystogive' || mw.util.getParamValue( 'wmf_source' ) === 'Ways_to_Give' ) { $('.paymentmethod-amazon').show(); } // Apple Pay if ( $('.paymentmethod-applepay').length > 0 ) { if ( !donationForm.shouldShowApplePay( donationForm.country ) ) { $('.paymentmethod-applepay').remove(); } } // Venmo browser check if ( $('.paymentmethod-venmo').length > 0 ) { if ( !donationForm.isVenmoSupported() || donationForm.country !== 'US' ) { $('.paymentmethod-venmo').remove(); } } // Dumb hack to remove ACH for Portal test against Fundraise Up if ( mw.util.getParamValue( 'wmf_source' ) === 'portalBanner_en6C_2024_overlayBanner4WikiForm' ) { $('.paymentmethod-ach').remove(); } } // Links open in new tab $('.links-in-new-tab a').attr('target', '_blank'); // Disable logo link $('#p-logo a').attr( { href: '#', title: '' } ); // These don't need to be tabbable on the landing page $('#searchInput, .mw-jump-link').attr('tabindex', '-1'); $('.input_amount_other').click(function() { $('#input_amount_other_box').focus(); }); // Allow preselecting frequency if possible if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) === -1 && mw.util.getParamValue( 'utm_medium' ) !== 'endowment' && mw.util.getParamValue( 'wmf_medium' ) !== 'endowment' ) { if ( mw.util.getParamValue( 'frequency' ) ) { donationForm.setFrequency( mw.util.getParamValue( 'frequency' ) ); } else if ( mw.util.getParamValue('monthly') && mw.util.getParamValue('monthly') !== '0' ) { // old method with "monthly=" parameter donationForm.setFrequency( 'monthly' ); } else { donationForm.setFrequency( 'onetime' ); } } donationForm.initOptin(); try { adjustHPC(); preSelect(); // Make sure to do this *after* other fiddling with values donationForm.localizeErrors(); } finally { $('.frb-monthly-pitch, .frb-monthly-pitch-thanks').appendTo('.frequency-options'); $('.ptf').appendTo('.amount-options'); $('.optin-options').insertAfter('.amount-options'); $('.consider-amounts').show(); $('#actual-form').show(); $('#actual-form-loading').hide(); } }); }); 6ep6db0jznjlc45azofjg2h5nse8aqp 40752 40751 2024-12-10T12:28:56Z Pcoombe 5 fix 40752 javascript text/javascript /* jshint strict:false */ /** MediaWiki:DonationForm.js - loaded on all donation forms * TODO: lots of cleanup */ var donationForm = {}; donationForm.loadedTime = Date.now(); donationForm.extraData = {}; donationForm.country = mw.util.getParamValue('country').toUpperCase(); try { donationForm.currency = document.forms.donateForm.currency_code.value; } catch (error) { donationForm.currency = 'USD'; } /** * Make language and country into a standard javascript Intl locale identifier * * @param {string} language * @param {string} country * @return {string} locale identifier e.g. en-GB */ donationForm.getLocale = function( language, country ) { // Sometimes in email testing links the uselang is a variable contiaining % // In that case fall back to English so locale code doesn't break form if ( language.match('%') ) { language = 'en'; } // MediaWiki allows some language codes like en-gb, en-ca, pt-br // We don't want these for a javascript locale, so drop anything after '-' language = language.split('-')[0]; return language + '-' + country; }; donationForm.locale = donationForm.getLocale( mw.config.get('wgPageContentLanguage'), donationForm.country ); // Don't offer recurring at all in these countries donationForm.noRecurringCountries = [ 'AR', 'IN' ]; donationForm.noRecurringPaypalCountries = [ 'CL', 'CO', 'PE', 'UY', 'BR' ]; donationForm.currencyRates = { // From https://github.com/wikimedia/wikimedia-fundraising-SmashPig/blob/master/PaymentData/ReferenceData/CurrencyRates.php // Updated 2024-07-31 'ADF' : 6.04, 'ADP' : 153, 'AED' : 3.67, 'AFA' : 70, 'AFN' : 70, 'ALL' : 90, 'AMD' : 368, 'ANG' : 1.79, 'AOA' : 844, 'AON' : 844, 'ARS' : 887, 'ATS' : 13, 'AUD' : 1.5, 'AWG' : 1.79, 'AZM' : 8500, 'AZN' : 1.7, 'BAM' : 1.8, 'BBD' : 2, 'BDT' : 116, 'BEF' : 37, 'BGL' : 1.8, 'BGN' : 1.8, 'BHD' : 0.37355757356689, 'BIF' : 2842, 'BMD' : 1, 'BND' : 1.35, 'BOB' : 6.71, 'BRL' : 5.1, 'BSD' : 1, 'BTN' : 83, 'BWP' : 13, 'BYR' : 32642, 'BZD' : 1.98, 'CAD' : 1.36, 'CDF' : 2786, 'CHF' : 0.9094629289448, 'CLP' : 890, 'CNY' : 7.23, 'COP' : 3803, 'CRC' : 498, 'CUC' : 1, 'CUP' : 25, 'CVE' : 101, 'CYP' : 0.53848627984321, 'CZK' : 23, 'DEM' : 1.8, 'DJF' : 178, 'DKK' : 6.86, 'DOP' : 58, 'DZD' : 133, 'ECS' : 24094, 'EEK' : 14, 'EGP' : 47, 'ESP' : 153, 'ETB' : 57, 'EUR' : 0.92005843390143, 'FIM' : 5.47, 'FJD' : 2.23, 'FKP' : 0.78703952551207, 'FRF' : 6.04, 'GBP' : 0.78703952551207, 'GEL' : 2.71, 'GHC' : 143125, 'GHS' : 14, 'GIP' : 0.78703952551207, 'GMD' : 68, 'GNF' : 8493, 'GRD' : 314, 'GTQ' : 7.57, 'GYD' : 200, 'HKD' : 7.8, 'HNL' : 24, 'HRK' : 6.93, 'HTG' : 132, 'HUF' : 355, 'IDR' : 15986, 'IEP' : 0.72460490043714, 'ILS' : 3.69, 'INR' : 83, 'IQD' : 1290, 'IRR' : 42009, 'ISK' : 138, 'ITL' : 1781, 'JMD' : 154, 'JOD' : 0.70900000000001, 'JPY' : 156, 'KES' : 130, 'KGS' : 88, 'KHR' : 3993, 'KMF' : 453, 'KPW' : 135, 'KRW' : 1358, 'KWD' : 0.30629670764681, 'KYD' : 0.83333299999999, 'KZT' : 442, 'LAK' : 21103, 'LBP' : 89393, 'LKR' : 298, 'LRD' : 193, 'LSL' : 18, 'LTL' : 3.18, 'LUF' : 37, 'LVL' : 0.64662074757963, 'LYD' : 4.8, 'MAD' : 9.79, 'MDL' : 17, 'MGA' : 4379, 'MGF' : 9150, 'MKD' : 56, 'MMK' : 2075, 'MNT' : 2620, 'MOP' : 8.03, 'MRO' : 391, 'MTL' : 0.39498108567387, 'MUR' : 45, 'MVR' : 15, 'MWK' : 1720, 'MXN' : 17, 'MYR' : 4.68, 'MZM' : 63200, 'MZN' : 63, 'NAD' : 18, 'NGN' : 1505, 'NIO' : 36, 'NLG' : 2.03, 'NOK' : 11, 'NPR' : 131, 'NZD' : 1.63, 'OMR' : 0.38377594841305, 'PAB' : 1, 'PEN' : 3.67, 'PGK' : 3.76, 'PHP' : 58, 'PKR' : 277, 'PLN' : 3.91, 'PTE' : 184, 'PYG' : 7355, 'QAR' : 3.56, 'ROL' : 45713, 'RON' : 4.57, 'RSD' : 108, 'RUB' : 91, 'RWF' : 1277, 'SAR' : 3.75, 'SBD' : 8.37, 'SCR' : 13, 'SDD' : 59800, 'SDG' : 598, 'SDP' : 2261, 'SEK' : 11, 'SGD' : 1.35, 'SHP' : 0.78703952551207, 'SIT' : 220, 'SKK' : 28, 'SLL' : 19750, 'SOS' : 549, 'SRD' : 33, 'SRG' : 33320, 'STD' : 22477, 'SVC' : 8.75, 'SYP' : 513, 'SZL' : 18, 'THB' : 36, 'TJS' : 11, 'TMM' : 16750, 'TMT' : 3.35, 'TND' : 3.11, 'TOP' : 2.32, 'TRL' : 32168418, 'TRY' : 32, 'TTD' : 6.64, 'TWD' : 32, 'TZS' : 2587, 'UAH' : 39, 'UGX' : 3760, 'USD' : 1, 'UYU' : 38, 'UZS' : 12662, 'VEB' : 3651907631, 'VEF' : 3651908, 'VND' : 25451, 'VUV' : 112, 'WST' : 2.67, 'XAF' : 604, 'XAG' : 0.031347411860134, 'XAU' : 0.00041128929241299, 'XCD' : 2.7, 'XEU' : 0.92005843390143, 'XOF' : 604, 'XPD' : 0.00098009826645798, 'XPF' : 110, 'XPT' : 0.00093444018680404, 'YER' : 249, 'YUN' : 108, 'ZAR' : 18, 'ZMK' : 5176, 'ZWD' : 373 }; /* Amount and currency formatting */ let formatters = { // Amounts without currency symbol amountFraction: new Intl.NumberFormat( donationForm.locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 } ), amountWhole: new Intl.NumberFormat( donationForm.locale, {} ) }; // currencyDisplay: 'narrowSymbol' fixes some issues like en-CO showing the ISO code // but browser support is lacking, so wrap in a try/catch try { formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol' } ); formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol', minimumFractionDigits: 0 } ); } catch(e) { formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency } ); formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, minimumFractionDigits: 0 } ); } donationForm.formatCurrency = function( amount ) { if ( amount % 1 !== 0 ) { // Not a whole number return formatters.currencyFraction.format( amount ); } else { return formatters.currencyWhole.format( amount ); } }; donationForm.formatAmount = function( amount ) { var formatterOptions, output; if ( amount % 1 !== 0 ) { // Not a whole number return formatters.amountFraction.format( amount ); } else { return formatters.amountWhole.format( amount ); } }; /* Localize the amount errors. Call when initialising form. */ donationForm.localizeErrors = function() { var currency = donationForm.currency; $('.lp-error-smallamount').text( function( index, oldText ) { return oldText.replace( '$1', donationForm.formatAmount( donationForm.minLocal ) + '\xa0' + currency ); }); if ( currency === 'USD' ) { // we don't need to include the conversion $('.lp-error-bigamount').text( function( index, oldText ) { return oldText.replace( '($1 $2) ', '' ) .replace( '($1&nbsp;$2) ', '' ); }); } $('.lp-error-bigamount').text( function( index, oldText ) { return oldText.replace( '$1', donationForm.formatAmount( donationForm.maxLocal ) ) .replace( '$2', currency ) .replace( '$3', 'benefactors@wikimedia.org' ) .replace( '$4', donationForm.formatAmount( donationForm.maxUSD ) ); }); }; function adjustHPC() { /* Adjust amounts based on highest previous contribution (hpc) or most recent contribution (mrc) parameter. Used for emails. TODO: split data out? */ var hpcSet = mw.util.getParamValue('hpcSet'); // Look for 'hpc' parameter, then 'mrc' var hpc = parseFloat( mw.util.getParamValue('hpc') ); if( isNaN(hpc) ) { hpc = parseFloat( mw.util.getParamValue('mrc') ); if( isNaN(hpc) ) { if ( hpcSet ) { // Allow using hpcSet even without hpc, for MG appeals hpc = 0; } else { return; } } } var currency = donationForm.currency; // If changing, please update https://docs.google.com/spreadsheets/d/1e02TsZ_bKDAS1BMVBCdyo9D7RGln_wCGnkg7IF5kU5s/edit var radioAmountsData = { "USD" : { // also used for CAD, AUD, NZD "default" : [ [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_USD" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_USD" : [ // Upgrade recurring amount dynamically [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2.75, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 3.50, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3.75, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4.50, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6.75, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15.75, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 24.75, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 44.75, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_USD" : [ // Give less reactivation amount [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ], // Direct Mail - fixed amounts "directmail" : [ [ 0, [ 25, 35, 50, 100, 150, 250, 300 ] ] ], "directmail250" : [ [ 0, [ 250, 300, 500, 750, 1000, 2500, 5000 ] ] ] }, "EUR" : { "default" : [ [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_EUR" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_EUR" : [ // Upgrade recurring amount dynamically [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2.50, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 2.50, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3.50, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4.25, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6.25, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 25, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 45, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_EUR" : [ // Give less reactivation amount [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ] }, "GBP" : { "default" : [ [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_GBP" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_GBP" : [ // Upgrade recurring amount dynamically [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 2, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 20, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 40, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 45, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 125, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 200, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 400, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_GBP" : [ // Give less reactivation amount [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ] }, "JPY" : [ [ 0, [ 500, 1000, 2000, 2500, 4000, 5000, 10000 ] ], [ 1000, [ 1000, 1500, 2500, 4000, 5000, 10000, 15000 ] ], [ 1500, [ 1500, 2000, 3000, 4000, 5000, 10000, 15000 ] ], [ 2000, [ 2000, 2500, 3500, 5000, 7500, 10000, 25000 ] ], [ 2500, [ 2500, 3500, 5000, 7500, 10000, 15000, 25000 ] ], [ 3000, [ 3000, 4000, 5000, 7500, 10000, 15000, 25000 ] ], [ 2500, [ 2500, 5000, 7500, 10000, 20000, 30000, 50000 ] ], [ 2500, [ 2500, 5000, 7500, 10000, 20000, 50000, 100000 ] ], [ 5000, [ 5000, 10000, 15000, 20000, 35000, 50000, 100000 ] ], [ 10000, [ 10000, 25000, 50000, 75000, 100000, 150000, 200000 ] ] ], "SEK" : [ [ 0, [ 30, 100, 150, 200, 500, 750, 1000 ] ], [ 50, [ 50, 100, 150, 200, 300, 750, 1000 ] ], [ 200, [ 50, 100, 200, 300, 500, 750, 1000 ] ] ] }; radioAmountsData.AUD = radioAmountsData.USD; radioAmountsData.CAD = radioAmountsData.USD; radioAmountsData.NZD = radioAmountsData.USD; // Major gifts appeals, hacky but this is easier than adding a load of new forms to maintain var currencyList = [ 'USD', 'CAD', 'AUD', 'NZD', 'GBP', 'EUR' ]; // close enough for ( let i = 0; i < currencyList.length; i++ ) { radioAmountsData[ currencyList[i] ].MG_2024_500 = [ [ 0, [ 500, 750, 1000, 1250, 1500, 1750, 2000 ] ] ]; radioAmountsData[ currencyList[i] ].MG_2024_650 = [ [ 0, [ 650, 750, 1000, 1250, 1500, 1750, 2000 ] ] ]; } var appealAmountsData = { "USD" : [ // also used for CAD, AUD, NZD, GBP, EUR [ 0, [ 5, 10, 20 ] ], [ 10, [ 10, 20, 50 ] ], [ 20, [ 20, 30, 50 ] ], [ 35, [ 20, 30, 50 ] ], [ 50, [ 20, 50, 100 ] ], [ 75, [ 50, 75, 100 ] ], [ 100, [ 75, 100, 150 ] ], [ 150, [ 75, 100, 200 ] ], [ 200, [ 100, 200, 300 ] ] ], "JPY" : [ [ 0, [ 300, 500, 1000 ] ], [ 3, [ 500, 1000, 1500 ] ], [ 5, [ 1000, 1500, 2000 ] ], [ 10, [ 1500, 2000, 5000 ] ], [ 20, [ 2000, 3000, 5000 ] ], [ 50, [ 2000, 5000, 10000 ] ], [ 100, [ 5000, 10000, 15000 ] ] ], "SEK" : [ [ 0, [ 20, 50, 100 ] ], [ 3, [ 30, 50, 100 ] ], [ 5, [ 50, 100, 150 ] ], [ 15, [ 100, 150, 200 ] ], [ 23, [ 100, 200, 300 ] ], [ 38, [ 100, 200, 500 ] ], [ 75, [ 100, 500, 750 ] ], [ 112, [ 100, 500, 1000 ] ] ] }; appealAmountsData.AUD = appealAmountsData.USD; appealAmountsData.CAD = appealAmountsData.USD; appealAmountsData.GBP = appealAmountsData.USD; appealAmountsData.NZD = appealAmountsData.USD; appealAmountsData.EUR = appealAmountsData.USD; // Radio button amounts var radioAmounts = pickAmountArray( radioAmountsData, currency, hpc, hpcSet ); if ( radioAmounts.length ) { // Change buttons for (var j = 0; j < radioAmounts.length; j++) { var $radio = $("#input_amount_" + j); var $label = $("label[for='input_amount_" + j + "']"); $radio.val( radioAmounts[j] ); $label.text( donationForm.formatCurrency( radioAmounts[j] ) ); } } // Appeal amounts var appealAmounts = pickAmountArray( appealAmountsData, currency, hpc, hpcSet ); if ( appealAmounts.length ) { var appealAmountString = appealAmounts.map( donationForm.formatCurrency ).join( ', '); $('.consider-amounts').html(appealAmountString); } } function pickAmountArray( data, currency, hpc, hpcSet ) { /** * Choose the amounts for radio buttons / appeal based on hpc * @param {Object} data * @param {String} currency * @param {Number} hpc * @param {String} hpcSet * @return {Array} Array of amounts (as numbers) */ var set, amounts; if ( !(currency in data) ) { return []; } if ( $.isArray(data[currency]) ) { // No variant sets set = data[currency]; } else { // We need to go deeper. Check the variants. if ( hpcSet in data[currency] ) { set = data[currency][hpcSet]; } else { set = data[currency]['default']; } } // Find correct amount array for this hpc for (var i = 0; i < set.length; i++) { if ( set[i][0] > hpc ) { break; } amounts = set[i][1]; } return amounts; } function preSelect() { /* Check for a 'preSelect' url parameter, and select that option. If there isn't an option, add it to the "Other" box and select that */ var preSelectAmount = parseFloat( mw.util.getParamValue('preSelect') ); if ( preSelectAmount > 0 ) { var $preSelectOption = $('input[name="amount"][value="' + preSelectAmount + '"]'); if ( $preSelectOption.length ) { // Select existing input $preSelectOption.prop('checked', true); } else { $('#input_amount_other_box').val( preSelectAmount ); $('#input_amount_other').prop('checked', true); } donationForm.updateFeeDisplay(); } } function addCardTypesClass(country) { /** * Add card types class to credit card button, so we can show correct logos * Banner equivalent: https://meta.wikimedia.org/wiki/MediaWiki:FundraisingBanners/LocalizeJS-2017.js * @param {String} country ISO code */ var cardTypes = { // Big 6 'US' : 'vmad', 'CA' : 'vma', 'GB' : 'vmaj', 'IE' : 'vmaj', 'AU' : 'vmaj', 'NZ' : 'vma', // Euro countries 'AT' : 'vmaj', 'BE' : 'vmaj', 'ES' : 'vmaj', 'FR' : 'vma', // Adyen - Carte Bancaire was removed 'IT' : 'vmaj', 'LU' : 'vmaj', 'LV' : 'vma', 'NL' : 'vmaj', 'PT' : 'vmaj', 'SK' : 'vmaj', 'GR' : 'vma', // Others 'CZ' : 'vmad', 'DK' : 'vma', 'HU' : 'vma', 'IL' : 'vmad', // Adyen 'JP' : 'vmaj', 'MY' : 'vmaj', 'NO' : 'vma', 'PL' : 'vma', 'RO' : 'vma', 'SE' : 'vma', 'UA' : 'vma', // Adyen 'ZA' : 'vm', 'ZZ' : 'vmad' // For testing }; if ( cardTypes[country] ) { $('.paymentmethod-cc').addClass('cctypes-' + cardTypes[country] ); $('.cc-text-label').addClass('sr-only'); } } /* Form functions */ function clearOther(box) { document.getElementById('input_amount_other').checked = true; box.value = ""; } function selectOther() { document.getElementById('input_amount_other').checked = true; } function selectAmount() { $('#input_amount_other_box').val(''); } /* -- Moved from Template:2012FR/Form-section/Processing/Default -- */ /** * Validate form, and prep most of the parameters * * @param {string} paymentMethod - method e.g. 'cc', 'paypal' * @param {string} paymentSubMethod - submethod e.g. 'rtbt_ideal' (a submethod of 'rtbt') * @param {string} skipAmountValidation - skip validating amount for PayPal forced to USD */ donationForm.redirectPayment = function( paymentMethod, paymentSubMethod, skipAmountValidation ) { if ( donationForm.validate( skipAmountValidation ) ) { var params = {}; params.currency = donationForm.currency; params.country = donationForm.country; // Overrides for specific cc gateways if ( paymentMethod === 'cc-adyen' ) { params.payment_method = 'cc'; params.gateway = 'adyen'; } else if ( paymentMethod === 'cc-dlocal' ) { params.payment_method = 'cc'; params.gateway = 'astropay'; } else { params.payment_method = paymentMethod; } if ( params.payment_method === 'cc' && params.country === 'ZA' ) { params.gateway = 'astropay'; } if ( paymentSubMethod ) { params.payment_submethod = paymentSubMethod; } let frequency = donationForm.getFrequency(); if ( frequency === 'monthly' ) { params.recurring = '1'; params.frequency_unit = 'month'; } else if ( frequency === 'annual' ) { params.recurring = '1'; params.frequency_unit = 'year'; } params.uselang = mw.config.get('wgPageContentLanguage'); // see T281285 for why not wgUserLanguage if ( params.uselang === 'pt' && params.country === 'BR' ) { params.uselang = 'pt-br'; } if ( params.uselang === 'es' && ( params.country === 'AR' || params.country === 'CL' || params.country === 'CO' || params.country === 'MX' || params.country === 'PE' || params.country === 'UY' || params.country === 'US' ) ) { params.uselang = 'es-419'; } var amount = donationForm.getAmount(); if ( $('#ptf-checkbox').prop('checked') ) { amount = amount + donationForm.calculateFee( amount ); donationForm.extraData.ptf = 1; } params.amount = amount; // Email optin if ( $('input[name="opt_in"]').length > 0 ) { var opt_inValue = $('input[name="opt_in"]:checked').val(); params.opt_in = opt_inValue; // donationForm.validate() already checked it's 1 or 0 } if ( mw.util.getParamValue( 'pym_variant' ) ) { params.variant = mw.util.getParamValue( 'pym_variant' ); } if ( params.recurring && params.variant && params.variant.match( /monthlyConvert/ ) ) { // Post-payments monthly convert makes no sense if it's already recurring // Avoid things like T312905 delete params.variant; } // TODO: refactor this to a list of parameters to pass unchanged // or just pass everything by default? if ( mw.util.getParamValue( 'pym_appeal' ) ) { params.appeal = mw.util.getParamValue( 'pym_appeal' ); } // https://phabricator.wikimedia.org/T381405 if ( mw.util.getParamValue( 'contact_id' ) ) { params.contact_id = mw.util.getParamValue( 'contact_id' ); } if ( mw.util.getParamValue( 'contact_hash' ) ) { params.contact_hash = mw.util.getParamValue( 'contact_hash' ); } // SMS if ( mw.util.getParamValue( 'recipient_id' ) ) { params.recipient_id = mw.util.getParamValue( 'recipient_id' ); } // Monthly convert if ( mc ) { // check just in-case this wasn't loaded for some reason mc.main( params, donationForm.finalStep ); } else { donationForm.finalStep( params ); } } else { donationForm.extraData.validateError = 1; // Flag they had an error, even if fixed later } return false; // don't submit if called by a button }; /** * Build final tracking parameters, and submit to payments * @param {Object} params */ donationForm.finalStep = function( params ) { var url = new URL('https://payments.wikimedia.org/index.php/Special:GatewayChooser'); // Skip form chooser for Apple Pay / Google Pay if ( params.payment_method === 'apple' || params.payment_method === 'google' ) { url = new URL('https://payments.wikimedia.org/index.php/Special:AdyenCheckoutGateway'); } // Skip form chooser for Venmo if ( params.payment_method === 'venmo' ) { url = new URL('https://payments.wikimedia.org/index.php/Special:BraintreeGateway'); } donationForm.extraData.time = Math.round( (Date.now() - donationForm.loadedTime)/1000 ); // Tracking data params.wmf_medium = mw.util.getParamValue( 'wmf_medium' ) || mw.util.getParamValue( 'utm_medium' ); params.wmf_campaign = mw.util.getParamValue( 'wmf_campaign' ) || mw.util.getParamValue( 'utm_campaign' ); params.wmf_source = donationForm.buildTrackingSource( params ); params.wmf_key = donationForm.buildTrackingKey( donationForm.extraData ); if ( document.referrer ) { // TODO: do we need this? // Strip protocol to stop firewall complaining params.referrer = document.referrer.replace(/https?:\/\//i, ''); } for ( var key of Object.keys( params ) ) { url.searchParams.set( key, params[key] ); } if ( window.top !== window.self ) { // In a frame, open payments in a new tab window.open( url.toString() ); } else { window.location.href = url.toString(); } }; /** * Build a wmf_source value, including the landing page info. * * Own function so it can be overriden for weird tests * * @param {Object} params * @return {string} wmf_source */ donationForm.buildTrackingSource = function( params ) { var wmf_source = mw.util.getParamValue( 'wmf_source' ) || mw.util.getParamValue( 'utm_source' ); wmf_source += '.'; var fullDottedPaymentMethod = params.payment_method; if ( params.recurring ) { fullDottedPaymentMethod = 'r' + fullDottedPaymentMethod; } if ( params.payment_submethod ) { fullDottedPaymentMethod = fullDottedPaymentMethod + '.' + params.payment_submethod; } /* Get URL parameter, but remove parts using old format. Allow fallback to a default value */ var getParam = function( param, removeText, dflt ) { if ( mw.util.getParamValue( param ) ) { return mw.util.getParamValue( param ).replace( removeText, '' ); } else { return dflt; } }; /* The landing page info, separated by ~. This mostly exists for legacy reasons */ wmf_source += getParam( 'template' , 'Lp-layout' , 'default' ) + '~'; wmf_source += getParam( 'appeal-template' , 'Appeal-template-' , 'default' ) + '~'; wmf_source += getParam( 'appeal' , 'Appeal-' , 'default' ) + '~'; wmf_source += getParam( 'form-template' , 'Form-template-' , 'default' ) + '~'; wmf_source += getParam( 'form-countryspecific', 'Form-countryspecific-', 'control' ); wmf_source += '.' + fullDottedPaymentMethod; return wmf_source; }; /** * Build a string for wmf_key from extra tracking data * * @param {Object} data * @return {string} wmf_key */ donationForm.buildTrackingKey = function(data) { var existingKey = mw.util.getParamValue( 'wmf_key' ) || mw.util.getParamValue( 'utm_key' ), dataArray = []; if ( existingKey ) { dataArray.push( existingKey ); } for (var key in data) { if (data.hasOwnProperty(key)) { dataArray.push( key + '_' + data[key] ); } } return dataArray.join('~'); }; /* Return amount selected or input */ donationForm.getAmount = function() { var form = document.forms.donateForm, amount = null; donationForm.extraData.otherAmt = 0; // If there are some amount radio buttons, then look for the checked one if ( form.amount ) { for ( var i = 0; i < form.amount.length; i++ ) { if ( form.amount[i].checked ) { amount = parseFloat( form.amount[i].value ); } } } // Check the "other" amount box if ( document.getElementById('input_amount_other').checked ) { amount = donationForm.parseOtherAmount( form.input_amount_other_box.value ); donationForm.extraData.otherAmt = 1; } return amount; }; /** * Parse Other field value into amount * * Does some awful regex stuff to rm symbols and turn the string into a number * Remember some locales flip . & , for decimal point/thousands separator * * @param {string} value Value of "Other" field * @return {float} Float with amount, or 0 if NaN */ donationForm.parseOtherAmount = function( value ) { var amount; value = value.replace(/[,.](\d)$/, '\:$10'); value = value.replace(/[,.](\d)(\d)$/, '\:$1$2'); value = value.replace(/[\$£€¥,.]/g, ''); value = value.replace(/:/, '.'); amount = parseFloat( value ); if ( isNaN( amount ) ) { return 0; } else { return amount; } }; /** * Validate the form. */ donationForm.validate = function( skipAmountValidation ) { var error = false; var form = document.forms.donateForm; // Reset all errors $('.lp-haserror').removeClass('lp-haserror'); $('.lp-error').hide(); if ( !skipAmountValidation && !donationForm.validateAmount() ) { error = true; } if ( form.opt_in ) { if ( $('input[name="opt_in"]:checked').val() === undefined ) { $('#error-optin').show().focus(); error = true; } else { $('#error-optin').hide(); } } return !error; }; /** * Check if selected amount is valid i.e. a positive number, between minimum and maximum. * If not, show an error and return false. */ donationForm.validateAmount = function() { var amount = donationForm.getAmount(); if ( amount === null || isNaN(amount) || amount <= 0 || amount < donationForm.minLocal ) { $('.amount-options').addClass('lp-haserror'); $('.lp-error-bigamount').hide(); $('.lp-error-smallamount').show().focus(); return false; } else if ( amount > donationForm.maxLocal ) { $('.amount-options').addClass('lp-haserror'); $('.lp-error-bigamount').show().focus(); return false; } else { $('.amount-options').removeClass('lp-haserror'); $('.lp-error-smallamount, .lp-error-bigamount').hide(); return true; } }; donationForm.getFrequency = function() { return document.forms.donateForm.dataset.frequency || 'onetime'; }; donationForm.setFrequency = function( frequency ) { // TODO: add some validation to reject invalid frequency values let form = document.forms.donateForm; form.frequency.value = frequency; // change input form.dataset.frequency = frequency; }; /* Wrapper for compatibility with old forms */ donationForm.toggleMonthly = function( monthly ) { if ( monthly ) { donationForm.setFrequency( 'monthly' ); } else { donationForm.setFrequency( 'onetime' ); } }; donationForm.updateFeeDisplay = function() { var selectedAmount = donationForm.getAmount(), feeAmount = donationForm.calculateFee( selectedAmount ), feeText; feeText = donationForm.formatCurrency( feeAmount ); $('.ptf label span').text( feeText ); if ( selectedAmount + feeAmount <= donationForm.maxLocal ) { $('.ptf').slideDown(); } }; /** * Calculate approximate transaction fee on given amount * @param {number} amount * @return {number} Rounded to 2 decimal places */ donationForm.calculateFee = function( amount ) { // Minimum fee/PTF amounts. Default is 0.35. // Updated 2019-05-21 to approx 0.35 USD equivalent var feeMinimums = { 'DKK' : 2, 'HUF' : 100, 'ILS' : 1.2, 'INR' : 4, 'JPY' : 35, 'MYR' : 1, 'NOK' : 3, 'PLN' : 1.35, 'CZK' : 7.5, 'RON' : 1.5, 'SEK' : 3, 'UAH' : 10, 'ZAR' : 5, // Latin America // Updated 2024-08-22 to approx 0.35 USD equivalent 'BRL' : 1.75, 'ARS' : 300, 'CLP' : 300, 'COP' : 1400, 'MXN' : 6, 'PEN' : 1.2, 'UYU' : 14 }; var feeMultiplier = 0.04, feeMinimum = feeMinimums[ donationForm.currency ] || 0.35, feeAmount = amount * feeMultiplier; if ( feeAmount < feeMinimum ) { feeAmount = feeMinimum; } return parseFloat( feeAmount.toFixed(2) ); }; donationForm.initOptin = function() { $('.optin-options').on('change', function(e) { $('#error-optin').hide(); // Only do all this if we have translated prompts if ( $('.optin-no-prompt').data('is-translated') === 'yes' ) { if ( e.target.id === 'optin-no' ) { $('.optin-no-prompt').removeClass('is-positive'); if ( !$('.optin-no-prompt').is(':visible') ) { $('.optin-no-prompt').slideDown(); } } else { $('.optin-no-prompt').addClass('is-positive'); } } }); }; /** * Block typing letters and symbols in given input. Used for Other amount inputs * * If we don't do this, Safari allows typing them and then chokes on submit * https://phabricator.wikimedia.org/T118741, https://phabricator.wikimedia.org/T173431 * * @param {Element} inputElement The element to block typing on */ donationForm.otherInputControl = function( inputElement ) { if ( inputElement ) { inputElement.onkeypress = function(e) { // Allow special keys in Firefox if ((e.code == 'ArrowLeft') || (e.code == 'ArrowRight') || (e.code == 'ArrowUp') || (e.code == 'ArrowDown') || (e.code == 'Delete') || (e.code == 'Backspace')) { return; } var chr = String.fromCharCode(e.which); if ('0123456789., '.indexOf(chr) === -1) { return false; } }; } }; /** * Should we show Apple Pay? * * Note there is a ~500ms delay in Safari when checking, so only call this if needed * * @param {string} country * @return {boolean} */ donationForm.shouldShowApplePay = function ( country ) { if ( location.search.match('forceApplePay') ) { return true; } if ( window.ApplePaySession ) { if ( ApplePaySession.canMakePayments() ) { return true; } } return false; }; /* Based on github:braintree/braintree-web/src/venmo/shared/supports-venmo.js See also on meta: MediaWiki:FundraisingBanners/VenmoBrowserCheck.js */ donationForm.isVenmoSupported = function(options) { var options = options || { allowNewBrowserTab: false, allowWebviews: true, allowDesktop: true, allowDesktopWebLogin: true }; var ua = window.navigator.userAgent; var merchantAllowsReturningToNewBrowserTab, merchantAllowsWebviews, merchantAllowsDesktopBrowsers; var isMobileDevice = isAndroid() || isIos(); var isAndroidChrome = isAndroid() && isChrome(); var isMobileDeviceThatSupportsReturnToSameTab = isIosSafari() || isAndroidChrome; var isKnownUnsupportedMobileBrowser = isIosChrome() || isFacebookOwnedBrowserOnAndroid() || isSamsung(); options = options || {}; // NEXT_MAJOR_VERSION allowDesktop will default to true, but can be opted out merchantAllowsDesktopBrowsers = (options.allowDesktopWebLogin || options.allowDesktop) === true; merchantAllowsReturningToNewBrowserTab = options.hasOwnProperty( "allowNewBrowserTab" ) ? options.allowNewBrowserTab : true; // NEXT_MAJOR_VERSION webviews are not supported, except for the case where // the merchant themselves is presenting venmo in a webview using the deep // link url to get back to their app. For the next major version, we should // just not have this option and instead require the merchant to determine // if the venmo button should be displayed when presenting it in the // merchant's app via a webview. merchantAllowsWebviews = options.hasOwnProperty("allowWebviews") ? options.allowWebviews : true; if (isKnownUnsupportedMobileBrowser) { return false; } if ( !merchantAllowsWebviews && (isAndroidWebview() || isIosWebview()) ) { return false; } if (!isMobileDevice) { return merchantAllowsDesktopBrowsers; } if (!merchantAllowsReturningToNewBrowserTab) { return isMobileDeviceThatSupportsReturnToSameTab; } return isMobileDevice; /* -- functions mostly from github:braintree/browser-detection library -- */ function isAndroid() { return /Android/i.test(ua); } function isIos(checkIpadOS = true) { const iOsTest = /iPhone|iPod|iPad/i.test(ua); return checkIpadOS ? iOsTest || isIpadOS() : iOsTest; } function isIpadOS() { // "ontouchend" is used to determine if a browser is on an iPad, otherwise // user-agents for iPadOS behave/identify as a desktop browser return /Mac|iPad/i.test(ua) && "ontouchend" in window.document; } function isEdge() { return ua.indexOf("Edge/") !== -1 || ua.indexOf("Edg/") !== -1; } function isSamsung() { return /SamsungBrowser/i.test(ua); } function isDuckDuckGo() { return ua.indexOf("DuckDuckGo/") !== -1; } function isOpera() { return ( ua.indexOf("OPR/") !== -1 || ua.indexOf("Opera/") !== -1 || ua.indexOf("OPT/") !== -1 ); } function isSilk() { return ua.indexOf("Silk/") !== -1; } function isChrome() { return ( (ua.indexOf("Chrome") !== -1 || ua.indexOf("CriOS") !== -1) && !isEdge() && !isSamsung() && !isDuckDuckGo() && !isOpera() && !isSilk() ); } function isIosFirefox() { return /FxiOS/i.test(ua); } function isWebkit() { const webkitRegexp = /webkit/i; return webkitRegexp.test(ua); } function isIosChrome() { return ua.indexOf("CriOS") > -1; } function isFacebook() { return ua.indexOf("FBAN") > -1; } function isIosSafari() { return ( isIos() && isWebkit() && !isIosChrome() && !isIosFirefox() && !isFacebook() ); } function isFacebookOwnedBrowserOnAndroid() { var e = ua.toLowerCase(); return -1 < e.indexOf("huawei") && -1 < e.indexOf("fban") || isAndroid() && (-1 < e.indexOf("fb_iab") || -1 < e.indexOf("instagram")); } function isSamsungBrowser() { return /SamsungBrowser/i.test(ua); } function isAndroidWebview() { return isAndroid() && -1 < ua.toLowerCase().indexOf("wv"); } function isGoogleSearchApp() { return /\bGSA\b/.test(ua); } function isIosGoogleSearchApp() { return isIos() && isGoogleSearchApp(); } function isIosWebview() { if (isIos()) { // The Google Search iOS app is technically a webview and doesn't support popups. if (isIosGoogleSearchApp()) { return true; } // Historically, a webview could be identified by the presence of AppleWebKit and _no_ presence of Safari after. return /.+AppleWebKit(?!.*Safari)/i.test(ua); } return false; } }; /* End form functions */ $(document).ready(function() { mw.loader.using( ['mediawiki.util'] ).done( function() { var form = document.forms.donateForm; // Minimum amount is usually about 1 USD donationForm.minLocal = donationForm.currencyRates[ donationForm.currency ]; donationForm.minLocal = Math.ceil( donationForm.minLocal * 100 ) / 100; // Round it up donationForm.maxUSD = 25000; donationForm.maxLocal = Math.floor( donationForm.currencyRates[ donationForm.currency ] * donationForm.maxUSD ); // Overrides for India if ( donationForm.currency === 'INR' ) { donationForm.minLocal = 10; // Until https://phabricator.wikimedia.org/T370583 fixed? donationForm.maxUSD = 3000; donationForm.maxLocal = 250000; } // Block typing symbols in Other field donationForm.otherInputControl( document.getElementById('input_amount_other_box') ); // Clear errors and update fee when selected/entered $('.amount-options').on( 'input change', function() { // Ideally we would validate the amount, but this causes issues with focus $('.amount-options .lp-error').hide(); donationForm.updateFeeDisplay(); }); // Disable submitting form with Enter key $('form[name="donateForm"]').on('keypress', function(e) { var code = ( e.keyCode ? e.keyCode : e.which ); if ( code == 13 ) { e.preventDefault(); } }); // But allow Enter on buttons $('.payment-method-button').keyup(function(e) { if (event.keyCode === 13) { e.target.click(); } }); if ( form ) { // hide frequency options for some countries if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) !== -1 ) { $('#frequency_onetime').prop('checked', true); $('.frequency-options, #cancel-monthly, #donate-recurring-smallprint').hide(); } if ( donationForm.noRecurringPaypalCountries.indexOf( donationForm.country ) !== -1 ) { $( '.paymentmethod-pp, .paymentmethod-pp-usd' ).addClass( 'not-monthly-capable' ); } // Format amounts on buttons $( '.amount-options li' ).each( function( index ) { let amount = this.querySelector( 'input' ).value; if ( amount !== 'Other' ) { this.querySelector( 'label' ).innerText = donationForm.formatCurrency( amount ); } }); addCardTypesClass( donationForm.country ); // Only show Amazon for links from Ways to give if ( mw.util.getParamValue( 'wmf_source' ) === 'Waystogive' || mw.util.getParamValue( 'wmf_source' ) === 'Ways_to_Give' ) { $('.paymentmethod-amazon').show(); } // Apple Pay if ( $('.paymentmethod-applepay').length > 0 ) { if ( !donationForm.shouldShowApplePay( donationForm.country ) ) { $('.paymentmethod-applepay').remove(); } } // Venmo browser check if ( $('.paymentmethod-venmo').length > 0 ) { if ( !donationForm.isVenmoSupported() || donationForm.country !== 'US' ) { $('.paymentmethod-venmo').remove(); } } // Dumb hack to remove ACH for Portal test against Fundraise Up if ( mw.util.getParamValue( 'wmf_source' ) === 'portalBanner_en6C_2024_overlayBanner4WikiForm' ) { $('.paymentmethod-ach').remove(); } } // Links open in new tab $('.links-in-new-tab a').attr('target', '_blank'); // Disable logo link $('#p-logo a').attr( { href: '#', title: '' } ); // These don't need to be tabbable on the landing page $('#searchInput, .mw-jump-link').attr('tabindex', '-1'); $('.input_amount_other').click(function() { $('#input_amount_other_box').focus(); }); // Allow preselecting frequency if possible if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) === -1 && mw.util.getParamValue( 'utm_medium' ) !== 'endowment' && mw.util.getParamValue( 'wmf_medium' ) !== 'endowment' ) { if ( mw.util.getParamValue( 'frequency' ) ) { donationForm.setFrequency( mw.util.getParamValue( 'frequency' ) ); } else if ( mw.util.getParamValue('monthly') && mw.util.getParamValue('monthly') !== '0' ) { // old method with "monthly=" parameter donationForm.setFrequency( 'monthly' ); } else { donationForm.setFrequency( 'onetime' ); } } donationForm.initOptin(); try { adjustHPC(); preSelect(); // Make sure to do this *after* other fiddling with values donationForm.localizeErrors(); } finally { $('.frb-monthly-pitch, .frb-monthly-pitch-thanks').appendTo('.frequency-options'); $('.ptf').appendTo('.amount-options'); $('.optin-options').insertAfter('.amount-options'); $('.consider-amounts').show(); $('#actual-form').show(); $('#actual-form-loading').hide(); } }); }); s3ya8vmvty1cy5v6vb0r3cw9ekkei5d 40756 40752 2024-12-11T11:51:48Z Pcoombe 5 decode base64 recipient_id if needed 40756 javascript text/javascript /* jshint strict:false */ /** MediaWiki:DonationForm.js - loaded on all donation forms * TODO: lots of cleanup */ var donationForm = {}; donationForm.loadedTime = Date.now(); donationForm.extraData = {}; donationForm.country = mw.util.getParamValue('country').toUpperCase(); try { donationForm.currency = document.forms.donateForm.currency_code.value; } catch (error) { donationForm.currency = 'USD'; } /** * Make language and country into a standard javascript Intl locale identifier * * @param {string} language * @param {string} country * @return {string} locale identifier e.g. en-GB */ donationForm.getLocale = function( language, country ) { // Sometimes in email testing links the uselang is a variable contiaining % // In that case fall back to English so locale code doesn't break form if ( language.match('%') ) { language = 'en'; } // MediaWiki allows some language codes like en-gb, en-ca, pt-br // We don't want these for a javascript locale, so drop anything after '-' language = language.split('-')[0]; return language + '-' + country; }; donationForm.locale = donationForm.getLocale( mw.config.get('wgPageContentLanguage'), donationForm.country ); // Don't offer recurring at all in these countries donationForm.noRecurringCountries = [ 'AR', 'IN' ]; donationForm.noRecurringPaypalCountries = [ 'CL', 'CO', 'PE', 'UY', 'BR' ]; donationForm.currencyRates = { // From https://github.com/wikimedia/wikimedia-fundraising-SmashPig/blob/master/PaymentData/ReferenceData/CurrencyRates.php // Updated 2024-07-31 'ADF' : 6.04, 'ADP' : 153, 'AED' : 3.67, 'AFA' : 70, 'AFN' : 70, 'ALL' : 90, 'AMD' : 368, 'ANG' : 1.79, 'AOA' : 844, 'AON' : 844, 'ARS' : 887, 'ATS' : 13, 'AUD' : 1.5, 'AWG' : 1.79, 'AZM' : 8500, 'AZN' : 1.7, 'BAM' : 1.8, 'BBD' : 2, 'BDT' : 116, 'BEF' : 37, 'BGL' : 1.8, 'BGN' : 1.8, 'BHD' : 0.37355757356689, 'BIF' : 2842, 'BMD' : 1, 'BND' : 1.35, 'BOB' : 6.71, 'BRL' : 5.1, 'BSD' : 1, 'BTN' : 83, 'BWP' : 13, 'BYR' : 32642, 'BZD' : 1.98, 'CAD' : 1.36, 'CDF' : 2786, 'CHF' : 0.9094629289448, 'CLP' : 890, 'CNY' : 7.23, 'COP' : 3803, 'CRC' : 498, 'CUC' : 1, 'CUP' : 25, 'CVE' : 101, 'CYP' : 0.53848627984321, 'CZK' : 23, 'DEM' : 1.8, 'DJF' : 178, 'DKK' : 6.86, 'DOP' : 58, 'DZD' : 133, 'ECS' : 24094, 'EEK' : 14, 'EGP' : 47, 'ESP' : 153, 'ETB' : 57, 'EUR' : 0.92005843390143, 'FIM' : 5.47, 'FJD' : 2.23, 'FKP' : 0.78703952551207, 'FRF' : 6.04, 'GBP' : 0.78703952551207, 'GEL' : 2.71, 'GHC' : 143125, 'GHS' : 14, 'GIP' : 0.78703952551207, 'GMD' : 68, 'GNF' : 8493, 'GRD' : 314, 'GTQ' : 7.57, 'GYD' : 200, 'HKD' : 7.8, 'HNL' : 24, 'HRK' : 6.93, 'HTG' : 132, 'HUF' : 355, 'IDR' : 15986, 'IEP' : 0.72460490043714, 'ILS' : 3.69, 'INR' : 83, 'IQD' : 1290, 'IRR' : 42009, 'ISK' : 138, 'ITL' : 1781, 'JMD' : 154, 'JOD' : 0.70900000000001, 'JPY' : 156, 'KES' : 130, 'KGS' : 88, 'KHR' : 3993, 'KMF' : 453, 'KPW' : 135, 'KRW' : 1358, 'KWD' : 0.30629670764681, 'KYD' : 0.83333299999999, 'KZT' : 442, 'LAK' : 21103, 'LBP' : 89393, 'LKR' : 298, 'LRD' : 193, 'LSL' : 18, 'LTL' : 3.18, 'LUF' : 37, 'LVL' : 0.64662074757963, 'LYD' : 4.8, 'MAD' : 9.79, 'MDL' : 17, 'MGA' : 4379, 'MGF' : 9150, 'MKD' : 56, 'MMK' : 2075, 'MNT' : 2620, 'MOP' : 8.03, 'MRO' : 391, 'MTL' : 0.39498108567387, 'MUR' : 45, 'MVR' : 15, 'MWK' : 1720, 'MXN' : 17, 'MYR' : 4.68, 'MZM' : 63200, 'MZN' : 63, 'NAD' : 18, 'NGN' : 1505, 'NIO' : 36, 'NLG' : 2.03, 'NOK' : 11, 'NPR' : 131, 'NZD' : 1.63, 'OMR' : 0.38377594841305, 'PAB' : 1, 'PEN' : 3.67, 'PGK' : 3.76, 'PHP' : 58, 'PKR' : 277, 'PLN' : 3.91, 'PTE' : 184, 'PYG' : 7355, 'QAR' : 3.56, 'ROL' : 45713, 'RON' : 4.57, 'RSD' : 108, 'RUB' : 91, 'RWF' : 1277, 'SAR' : 3.75, 'SBD' : 8.37, 'SCR' : 13, 'SDD' : 59800, 'SDG' : 598, 'SDP' : 2261, 'SEK' : 11, 'SGD' : 1.35, 'SHP' : 0.78703952551207, 'SIT' : 220, 'SKK' : 28, 'SLL' : 19750, 'SOS' : 549, 'SRD' : 33, 'SRG' : 33320, 'STD' : 22477, 'SVC' : 8.75, 'SYP' : 513, 'SZL' : 18, 'THB' : 36, 'TJS' : 11, 'TMM' : 16750, 'TMT' : 3.35, 'TND' : 3.11, 'TOP' : 2.32, 'TRL' : 32168418, 'TRY' : 32, 'TTD' : 6.64, 'TWD' : 32, 'TZS' : 2587, 'UAH' : 39, 'UGX' : 3760, 'USD' : 1, 'UYU' : 38, 'UZS' : 12662, 'VEB' : 3651907631, 'VEF' : 3651908, 'VND' : 25451, 'VUV' : 112, 'WST' : 2.67, 'XAF' : 604, 'XAG' : 0.031347411860134, 'XAU' : 0.00041128929241299, 'XCD' : 2.7, 'XEU' : 0.92005843390143, 'XOF' : 604, 'XPD' : 0.00098009826645798, 'XPF' : 110, 'XPT' : 0.00093444018680404, 'YER' : 249, 'YUN' : 108, 'ZAR' : 18, 'ZMK' : 5176, 'ZWD' : 373 }; /* Amount and currency formatting */ let formatters = { // Amounts without currency symbol amountFraction: new Intl.NumberFormat( donationForm.locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 } ), amountWhole: new Intl.NumberFormat( donationForm.locale, {} ) }; // currencyDisplay: 'narrowSymbol' fixes some issues like en-CO showing the ISO code // but browser support is lacking, so wrap in a try/catch try { formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol' } ); formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol', minimumFractionDigits: 0 } ); } catch(e) { formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency } ); formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, minimumFractionDigits: 0 } ); } donationForm.formatCurrency = function( amount ) { if ( amount % 1 !== 0 ) { // Not a whole number return formatters.currencyFraction.format( amount ); } else { return formatters.currencyWhole.format( amount ); } }; donationForm.formatAmount = function( amount ) { var formatterOptions, output; if ( amount % 1 !== 0 ) { // Not a whole number return formatters.amountFraction.format( amount ); } else { return formatters.amountWhole.format( amount ); } }; /* Localize the amount errors. Call when initialising form. */ donationForm.localizeErrors = function() { var currency = donationForm.currency; $('.lp-error-smallamount').text( function( index, oldText ) { return oldText.replace( '$1', donationForm.formatAmount( donationForm.minLocal ) + '\xa0' + currency ); }); if ( currency === 'USD' ) { // we don't need to include the conversion $('.lp-error-bigamount').text( function( index, oldText ) { return oldText.replace( '($1 $2) ', '' ) .replace( '($1&nbsp;$2) ', '' ); }); } $('.lp-error-bigamount').text( function( index, oldText ) { return oldText.replace( '$1', donationForm.formatAmount( donationForm.maxLocal ) ) .replace( '$2', currency ) .replace( '$3', 'benefactors@wikimedia.org' ) .replace( '$4', donationForm.formatAmount( donationForm.maxUSD ) ); }); }; function adjustHPC() { /* Adjust amounts based on highest previous contribution (hpc) or most recent contribution (mrc) parameter. Used for emails. TODO: split data out? */ var hpcSet = mw.util.getParamValue('hpcSet'); // Look for 'hpc' parameter, then 'mrc' var hpc = parseFloat( mw.util.getParamValue('hpc') ); if( isNaN(hpc) ) { hpc = parseFloat( mw.util.getParamValue('mrc') ); if( isNaN(hpc) ) { if ( hpcSet ) { // Allow using hpcSet even without hpc, for MG appeals hpc = 0; } else { return; } } } var currency = donationForm.currency; // If changing, please update https://docs.google.com/spreadsheets/d/1e02TsZ_bKDAS1BMVBCdyo9D7RGln_wCGnkg7IF5kU5s/edit var radioAmountsData = { "USD" : { // also used for CAD, AUD, NZD "default" : [ [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_USD" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_USD" : [ // Upgrade recurring amount dynamically [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2.75, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 3.50, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3.75, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4.50, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6.75, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15.75, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 24.75, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 44.75, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_USD" : [ // Give less reactivation amount [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ], // Direct Mail - fixed amounts "directmail" : [ [ 0, [ 25, 35, 50, 100, 150, 250, 300 ] ] ], "directmail250" : [ [ 0, [ 250, 300, 500, 750, 1000, 2500, 5000 ] ] ] }, "EUR" : { "default" : [ [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_EUR" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_EUR" : [ // Upgrade recurring amount dynamically [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2.50, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 2.50, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3.50, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4.25, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6.25, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 25, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 45, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_EUR" : [ // Give less reactivation amount [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ] }, "GBP" : { "default" : [ [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_GBP" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_GBP" : [ // Upgrade recurring amount dynamically [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 2, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 20, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 40, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 45, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 125, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 200, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 400, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_GBP" : [ // Give less reactivation amount [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ] }, "JPY" : [ [ 0, [ 500, 1000, 2000, 2500, 4000, 5000, 10000 ] ], [ 1000, [ 1000, 1500, 2500, 4000, 5000, 10000, 15000 ] ], [ 1500, [ 1500, 2000, 3000, 4000, 5000, 10000, 15000 ] ], [ 2000, [ 2000, 2500, 3500, 5000, 7500, 10000, 25000 ] ], [ 2500, [ 2500, 3500, 5000, 7500, 10000, 15000, 25000 ] ], [ 3000, [ 3000, 4000, 5000, 7500, 10000, 15000, 25000 ] ], [ 2500, [ 2500, 5000, 7500, 10000, 20000, 30000, 50000 ] ], [ 2500, [ 2500, 5000, 7500, 10000, 20000, 50000, 100000 ] ], [ 5000, [ 5000, 10000, 15000, 20000, 35000, 50000, 100000 ] ], [ 10000, [ 10000, 25000, 50000, 75000, 100000, 150000, 200000 ] ] ], "SEK" : [ [ 0, [ 30, 100, 150, 200, 500, 750, 1000 ] ], [ 50, [ 50, 100, 150, 200, 300, 750, 1000 ] ], [ 200, [ 50, 100, 200, 300, 500, 750, 1000 ] ] ] }; radioAmountsData.AUD = radioAmountsData.USD; radioAmountsData.CAD = radioAmountsData.USD; radioAmountsData.NZD = radioAmountsData.USD; // Major gifts appeals, hacky but this is easier than adding a load of new forms to maintain var currencyList = [ 'USD', 'CAD', 'AUD', 'NZD', 'GBP', 'EUR' ]; // close enough for ( let i = 0; i < currencyList.length; i++ ) { radioAmountsData[ currencyList[i] ].MG_2024_500 = [ [ 0, [ 500, 750, 1000, 1250, 1500, 1750, 2000 ] ] ]; radioAmountsData[ currencyList[i] ].MG_2024_650 = [ [ 0, [ 650, 750, 1000, 1250, 1500, 1750, 2000 ] ] ]; } var appealAmountsData = { "USD" : [ // also used for CAD, AUD, NZD, GBP, EUR [ 0, [ 5, 10, 20 ] ], [ 10, [ 10, 20, 50 ] ], [ 20, [ 20, 30, 50 ] ], [ 35, [ 20, 30, 50 ] ], [ 50, [ 20, 50, 100 ] ], [ 75, [ 50, 75, 100 ] ], [ 100, [ 75, 100, 150 ] ], [ 150, [ 75, 100, 200 ] ], [ 200, [ 100, 200, 300 ] ] ], "JPY" : [ [ 0, [ 300, 500, 1000 ] ], [ 3, [ 500, 1000, 1500 ] ], [ 5, [ 1000, 1500, 2000 ] ], [ 10, [ 1500, 2000, 5000 ] ], [ 20, [ 2000, 3000, 5000 ] ], [ 50, [ 2000, 5000, 10000 ] ], [ 100, [ 5000, 10000, 15000 ] ] ], "SEK" : [ [ 0, [ 20, 50, 100 ] ], [ 3, [ 30, 50, 100 ] ], [ 5, [ 50, 100, 150 ] ], [ 15, [ 100, 150, 200 ] ], [ 23, [ 100, 200, 300 ] ], [ 38, [ 100, 200, 500 ] ], [ 75, [ 100, 500, 750 ] ], [ 112, [ 100, 500, 1000 ] ] ] }; appealAmountsData.AUD = appealAmountsData.USD; appealAmountsData.CAD = appealAmountsData.USD; appealAmountsData.GBP = appealAmountsData.USD; appealAmountsData.NZD = appealAmountsData.USD; appealAmountsData.EUR = appealAmountsData.USD; // Radio button amounts var radioAmounts = pickAmountArray( radioAmountsData, currency, hpc, hpcSet ); if ( radioAmounts.length ) { // Change buttons for (var j = 0; j < radioAmounts.length; j++) { var $radio = $("#input_amount_" + j); var $label = $("label[for='input_amount_" + j + "']"); $radio.val( radioAmounts[j] ); $label.text( donationForm.formatCurrency( radioAmounts[j] ) ); } } // Appeal amounts var appealAmounts = pickAmountArray( appealAmountsData, currency, hpc, hpcSet ); if ( appealAmounts.length ) { var appealAmountString = appealAmounts.map( donationForm.formatCurrency ).join( ', '); $('.consider-amounts').html(appealAmountString); } } function pickAmountArray( data, currency, hpc, hpcSet ) { /** * Choose the amounts for radio buttons / appeal based on hpc * @param {Object} data * @param {String} currency * @param {Number} hpc * @param {String} hpcSet * @return {Array} Array of amounts (as numbers) */ var set, amounts; if ( !(currency in data) ) { return []; } if ( $.isArray(data[currency]) ) { // No variant sets set = data[currency]; } else { // We need to go deeper. Check the variants. if ( hpcSet in data[currency] ) { set = data[currency][hpcSet]; } else { set = data[currency]['default']; } } // Find correct amount array for this hpc for (var i = 0; i < set.length; i++) { if ( set[i][0] > hpc ) { break; } amounts = set[i][1]; } return amounts; } function preSelect() { /* Check for a 'preSelect' url parameter, and select that option. If there isn't an option, add it to the "Other" box and select that */ var preSelectAmount = parseFloat( mw.util.getParamValue('preSelect') ); if ( preSelectAmount > 0 ) { var $preSelectOption = $('input[name="amount"][value="' + preSelectAmount + '"]'); if ( $preSelectOption.length ) { // Select existing input $preSelectOption.prop('checked', true); } else { $('#input_amount_other_box').val( preSelectAmount ); $('#input_amount_other').prop('checked', true); } donationForm.updateFeeDisplay(); } } function addCardTypesClass(country) { /** * Add card types class to credit card button, so we can show correct logos * Banner equivalent: https://meta.wikimedia.org/wiki/MediaWiki:FundraisingBanners/LocalizeJS-2017.js * @param {String} country ISO code */ var cardTypes = { // Big 6 'US' : 'vmad', 'CA' : 'vma', 'GB' : 'vmaj', 'IE' : 'vmaj', 'AU' : 'vmaj', 'NZ' : 'vma', // Euro countries 'AT' : 'vmaj', 'BE' : 'vmaj', 'ES' : 'vmaj', 'FR' : 'vma', // Adyen - Carte Bancaire was removed 'IT' : 'vmaj', 'LU' : 'vmaj', 'LV' : 'vma', 'NL' : 'vmaj', 'PT' : 'vmaj', 'SK' : 'vmaj', 'GR' : 'vma', // Others 'CZ' : 'vmad', 'DK' : 'vma', 'HU' : 'vma', 'IL' : 'vmad', // Adyen 'JP' : 'vmaj', 'MY' : 'vmaj', 'NO' : 'vma', 'PL' : 'vma', 'RO' : 'vma', 'SE' : 'vma', 'UA' : 'vma', // Adyen 'ZA' : 'vm', 'ZZ' : 'vmad' // For testing }; if ( cardTypes[country] ) { $('.paymentmethod-cc').addClass('cctypes-' + cardTypes[country] ); $('.cc-text-label').addClass('sr-only'); } } /* Form functions */ function clearOther(box) { document.getElementById('input_amount_other').checked = true; box.value = ""; } function selectOther() { document.getElementById('input_amount_other').checked = true; } function selectAmount() { $('#input_amount_other_box').val(''); } /* -- Moved from Template:2012FR/Form-section/Processing/Default -- */ /** * Validate form, and prep most of the parameters * * @param {string} paymentMethod - method e.g. 'cc', 'paypal' * @param {string} paymentSubMethod - submethod e.g. 'rtbt_ideal' (a submethod of 'rtbt') * @param {string} skipAmountValidation - skip validating amount for PayPal forced to USD */ donationForm.redirectPayment = function( paymentMethod, paymentSubMethod, skipAmountValidation ) { if ( donationForm.validate( skipAmountValidation ) ) { var params = {}; params.currency = donationForm.currency; params.country = donationForm.country; // Overrides for specific cc gateways if ( paymentMethod === 'cc-adyen' ) { params.payment_method = 'cc'; params.gateway = 'adyen'; } else if ( paymentMethod === 'cc-dlocal' ) { params.payment_method = 'cc'; params.gateway = 'astropay'; } else { params.payment_method = paymentMethod; } if ( params.payment_method === 'cc' && params.country === 'ZA' ) { params.gateway = 'astropay'; } if ( paymentSubMethod ) { params.payment_submethod = paymentSubMethod; } let frequency = donationForm.getFrequency(); if ( frequency === 'monthly' ) { params.recurring = '1'; params.frequency_unit = 'month'; } else if ( frequency === 'annual' ) { params.recurring = '1'; params.frequency_unit = 'year'; } params.uselang = mw.config.get('wgPageContentLanguage'); // see T281285 for why not wgUserLanguage if ( params.uselang === 'pt' && params.country === 'BR' ) { params.uselang = 'pt-br'; } if ( params.uselang === 'es' && ( params.country === 'AR' || params.country === 'CL' || params.country === 'CO' || params.country === 'MX' || params.country === 'PE' || params.country === 'UY' || params.country === 'US' ) ) { params.uselang = 'es-419'; } var amount = donationForm.getAmount(); if ( $('#ptf-checkbox').prop('checked') ) { amount = amount + donationForm.calculateFee( amount ); donationForm.extraData.ptf = 1; } params.amount = amount; // Email optin if ( $('input[name="opt_in"]').length > 0 ) { var opt_inValue = $('input[name="opt_in"]:checked').val(); params.opt_in = opt_inValue; // donationForm.validate() already checked it's 1 or 0 } if ( mw.util.getParamValue( 'pym_variant' ) ) { params.variant = mw.util.getParamValue( 'pym_variant' ); } if ( params.recurring && params.variant && params.variant.match( /monthlyConvert/ ) ) { // Post-payments monthly convert makes no sense if it's already recurring // Avoid things like T312905 delete params.variant; } // TODO: refactor this to a list of parameters to pass unchanged // or just pass everything by default? if ( mw.util.getParamValue( 'pym_appeal' ) ) { params.appeal = mw.util.getParamValue( 'pym_appeal' ); } // https://phabricator.wikimedia.org/T381405 if ( mw.util.getParamValue( 'contact_id' ) ) { params.contact_id = mw.util.getParamValue( 'contact_id' ); } if ( mw.util.getParamValue( 'contact_hash' ) ) { params.contact_hash = mw.util.getParamValue( 'contact_hash' ); } // SMS var recipient_id = mw.util.getParamValue( 'recipient_id' ); if ( recipient_id ) { if ( isNaN( parseFloat( recipient_id ) ) ) { // Lop off last 2 characters and decode base64 params.recipient_id = atob( recipient_id.slice(0, -2) ); } else { params.recipient_id = recipient_id; } } // Monthly convert if ( mc ) { // check just in-case this wasn't loaded for some reason mc.main( params, donationForm.finalStep ); } else { donationForm.finalStep( params ); } } else { donationForm.extraData.validateError = 1; // Flag they had an error, even if fixed later } return false; // don't submit if called by a button }; /** * Build final tracking parameters, and submit to payments * @param {Object} params */ donationForm.finalStep = function( params ) { var url = new URL('https://payments.wikimedia.org/index.php/Special:GatewayChooser'); // Skip form chooser for Apple Pay / Google Pay if ( params.payment_method === 'apple' || params.payment_method === 'google' ) { url = new URL('https://payments.wikimedia.org/index.php/Special:AdyenCheckoutGateway'); } // Skip form chooser for Venmo if ( params.payment_method === 'venmo' ) { url = new URL('https://payments.wikimedia.org/index.php/Special:BraintreeGateway'); } donationForm.extraData.time = Math.round( (Date.now() - donationForm.loadedTime)/1000 ); // Tracking data params.wmf_medium = mw.util.getParamValue( 'wmf_medium' ) || mw.util.getParamValue( 'utm_medium' ); params.wmf_campaign = mw.util.getParamValue( 'wmf_campaign' ) || mw.util.getParamValue( 'utm_campaign' ); params.wmf_source = donationForm.buildTrackingSource( params ); params.wmf_key = donationForm.buildTrackingKey( donationForm.extraData ); if ( document.referrer ) { // TODO: do we need this? // Strip protocol to stop firewall complaining params.referrer = document.referrer.replace(/https?:\/\//i, ''); } for ( var key of Object.keys( params ) ) { url.searchParams.set( key, params[key] ); } if ( window.top !== window.self ) { // In a frame, open payments in a new tab window.open( url.toString() ); } else { window.location.href = url.toString(); } }; /** * Build a wmf_source value, including the landing page info. * * Own function so it can be overriden for weird tests * * @param {Object} params * @return {string} wmf_source */ donationForm.buildTrackingSource = function( params ) { var wmf_source = mw.util.getParamValue( 'wmf_source' ) || mw.util.getParamValue( 'utm_source' ); wmf_source += '.'; var fullDottedPaymentMethod = params.payment_method; if ( params.recurring ) { fullDottedPaymentMethod = 'r' + fullDottedPaymentMethod; } if ( params.payment_submethod ) { fullDottedPaymentMethod = fullDottedPaymentMethod + '.' + params.payment_submethod; } /* Get URL parameter, but remove parts using old format. Allow fallback to a default value */ var getParam = function( param, removeText, dflt ) { if ( mw.util.getParamValue( param ) ) { return mw.util.getParamValue( param ).replace( removeText, '' ); } else { return dflt; } }; /* The landing page info, separated by ~. This mostly exists for legacy reasons */ wmf_source += getParam( 'template' , 'Lp-layout' , 'default' ) + '~'; wmf_source += getParam( 'appeal-template' , 'Appeal-template-' , 'default' ) + '~'; wmf_source += getParam( 'appeal' , 'Appeal-' , 'default' ) + '~'; wmf_source += getParam( 'form-template' , 'Form-template-' , 'default' ) + '~'; wmf_source += getParam( 'form-countryspecific', 'Form-countryspecific-', 'control' ); wmf_source += '.' + fullDottedPaymentMethod; return wmf_source; }; /** * Build a string for wmf_key from extra tracking data * * @param {Object} data * @return {string} wmf_key */ donationForm.buildTrackingKey = function(data) { var existingKey = mw.util.getParamValue( 'wmf_key' ) || mw.util.getParamValue( 'utm_key' ), dataArray = []; if ( existingKey ) { dataArray.push( existingKey ); } for (var key in data) { if (data.hasOwnProperty(key)) { dataArray.push( key + '_' + data[key] ); } } return dataArray.join('~'); }; /* Return amount selected or input */ donationForm.getAmount = function() { var form = document.forms.donateForm, amount = null; donationForm.extraData.otherAmt = 0; // If there are some amount radio buttons, then look for the checked one if ( form.amount ) { for ( var i = 0; i < form.amount.length; i++ ) { if ( form.amount[i].checked ) { amount = parseFloat( form.amount[i].value ); } } } // Check the "other" amount box if ( document.getElementById('input_amount_other').checked ) { amount = donationForm.parseOtherAmount( form.input_amount_other_box.value ); donationForm.extraData.otherAmt = 1; } return amount; }; /** * Parse Other field value into amount * * Does some awful regex stuff to rm symbols and turn the string into a number * Remember some locales flip . & , for decimal point/thousands separator * * @param {string} value Value of "Other" field * @return {float} Float with amount, or 0 if NaN */ donationForm.parseOtherAmount = function( value ) { var amount; value = value.replace(/[,.](\d)$/, '\:$10'); value = value.replace(/[,.](\d)(\d)$/, '\:$1$2'); value = value.replace(/[\$£€¥,.]/g, ''); value = value.replace(/:/, '.'); amount = parseFloat( value ); if ( isNaN( amount ) ) { return 0; } else { return amount; } }; /** * Validate the form. */ donationForm.validate = function( skipAmountValidation ) { var error = false; var form = document.forms.donateForm; // Reset all errors $('.lp-haserror').removeClass('lp-haserror'); $('.lp-error').hide(); if ( !skipAmountValidation && !donationForm.validateAmount() ) { error = true; } if ( form.opt_in ) { if ( $('input[name="opt_in"]:checked').val() === undefined ) { $('#error-optin').show().focus(); error = true; } else { $('#error-optin').hide(); } } return !error; }; /** * Check if selected amount is valid i.e. a positive number, between minimum and maximum. * If not, show an error and return false. */ donationForm.validateAmount = function() { var amount = donationForm.getAmount(); if ( amount === null || isNaN(amount) || amount <= 0 || amount < donationForm.minLocal ) { $('.amount-options').addClass('lp-haserror'); $('.lp-error-bigamount').hide(); $('.lp-error-smallamount').show().focus(); return false; } else if ( amount > donationForm.maxLocal ) { $('.amount-options').addClass('lp-haserror'); $('.lp-error-bigamount').show().focus(); return false; } else { $('.amount-options').removeClass('lp-haserror'); $('.lp-error-smallamount, .lp-error-bigamount').hide(); return true; } }; donationForm.getFrequency = function() { return document.forms.donateForm.dataset.frequency || 'onetime'; }; donationForm.setFrequency = function( frequency ) { // TODO: add some validation to reject invalid frequency values let form = document.forms.donateForm; form.frequency.value = frequency; // change input form.dataset.frequency = frequency; }; /* Wrapper for compatibility with old forms */ donationForm.toggleMonthly = function( monthly ) { if ( monthly ) { donationForm.setFrequency( 'monthly' ); } else { donationForm.setFrequency( 'onetime' ); } }; donationForm.updateFeeDisplay = function() { var selectedAmount = donationForm.getAmount(), feeAmount = donationForm.calculateFee( selectedAmount ), feeText; feeText = donationForm.formatCurrency( feeAmount ); $('.ptf label span').text( feeText ); if ( selectedAmount + feeAmount <= donationForm.maxLocal ) { $('.ptf').slideDown(); } }; /** * Calculate approximate transaction fee on given amount * @param {number} amount * @return {number} Rounded to 2 decimal places */ donationForm.calculateFee = function( amount ) { // Minimum fee/PTF amounts. Default is 0.35. // Updated 2019-05-21 to approx 0.35 USD equivalent var feeMinimums = { 'DKK' : 2, 'HUF' : 100, 'ILS' : 1.2, 'INR' : 4, 'JPY' : 35, 'MYR' : 1, 'NOK' : 3, 'PLN' : 1.35, 'CZK' : 7.5, 'RON' : 1.5, 'SEK' : 3, 'UAH' : 10, 'ZAR' : 5, // Latin America // Updated 2024-08-22 to approx 0.35 USD equivalent 'BRL' : 1.75, 'ARS' : 300, 'CLP' : 300, 'COP' : 1400, 'MXN' : 6, 'PEN' : 1.2, 'UYU' : 14 }; var feeMultiplier = 0.04, feeMinimum = feeMinimums[ donationForm.currency ] || 0.35, feeAmount = amount * feeMultiplier; if ( feeAmount < feeMinimum ) { feeAmount = feeMinimum; } return parseFloat( feeAmount.toFixed(2) ); }; donationForm.initOptin = function() { $('.optin-options').on('change', function(e) { $('#error-optin').hide(); // Only do all this if we have translated prompts if ( $('.optin-no-prompt').data('is-translated') === 'yes' ) { if ( e.target.id === 'optin-no' ) { $('.optin-no-prompt').removeClass('is-positive'); if ( !$('.optin-no-prompt').is(':visible') ) { $('.optin-no-prompt').slideDown(); } } else { $('.optin-no-prompt').addClass('is-positive'); } } }); }; /** * Block typing letters and symbols in given input. Used for Other amount inputs * * If we don't do this, Safari allows typing them and then chokes on submit * https://phabricator.wikimedia.org/T118741, https://phabricator.wikimedia.org/T173431 * * @param {Element} inputElement The element to block typing on */ donationForm.otherInputControl = function( inputElement ) { if ( inputElement ) { inputElement.onkeypress = function(e) { // Allow special keys in Firefox if ((e.code == 'ArrowLeft') || (e.code == 'ArrowRight') || (e.code == 'ArrowUp') || (e.code == 'ArrowDown') || (e.code == 'Delete') || (e.code == 'Backspace')) { return; } var chr = String.fromCharCode(e.which); if ('0123456789., '.indexOf(chr) === -1) { return false; } }; } }; /** * Should we show Apple Pay? * * Note there is a ~500ms delay in Safari when checking, so only call this if needed * * @param {string} country * @return {boolean} */ donationForm.shouldShowApplePay = function ( country ) { if ( location.search.match('forceApplePay') ) { return true; } if ( window.ApplePaySession ) { if ( ApplePaySession.canMakePayments() ) { return true; } } return false; }; /* Based on github:braintree/braintree-web/src/venmo/shared/supports-venmo.js See also on meta: MediaWiki:FundraisingBanners/VenmoBrowserCheck.js */ donationForm.isVenmoSupported = function(options) { var options = options || { allowNewBrowserTab: false, allowWebviews: true, allowDesktop: true, allowDesktopWebLogin: true }; var ua = window.navigator.userAgent; var merchantAllowsReturningToNewBrowserTab, merchantAllowsWebviews, merchantAllowsDesktopBrowsers; var isMobileDevice = isAndroid() || isIos(); var isAndroidChrome = isAndroid() && isChrome(); var isMobileDeviceThatSupportsReturnToSameTab = isIosSafari() || isAndroidChrome; var isKnownUnsupportedMobileBrowser = isIosChrome() || isFacebookOwnedBrowserOnAndroid() || isSamsung(); options = options || {}; // NEXT_MAJOR_VERSION allowDesktop will default to true, but can be opted out merchantAllowsDesktopBrowsers = (options.allowDesktopWebLogin || options.allowDesktop) === true; merchantAllowsReturningToNewBrowserTab = options.hasOwnProperty( "allowNewBrowserTab" ) ? options.allowNewBrowserTab : true; // NEXT_MAJOR_VERSION webviews are not supported, except for the case where // the merchant themselves is presenting venmo in a webview using the deep // link url to get back to their app. For the next major version, we should // just not have this option and instead require the merchant to determine // if the venmo button should be displayed when presenting it in the // merchant's app via a webview. merchantAllowsWebviews = options.hasOwnProperty("allowWebviews") ? options.allowWebviews : true; if (isKnownUnsupportedMobileBrowser) { return false; } if ( !merchantAllowsWebviews && (isAndroidWebview() || isIosWebview()) ) { return false; } if (!isMobileDevice) { return merchantAllowsDesktopBrowsers; } if (!merchantAllowsReturningToNewBrowserTab) { return isMobileDeviceThatSupportsReturnToSameTab; } return isMobileDevice; /* -- functions mostly from github:braintree/browser-detection library -- */ function isAndroid() { return /Android/i.test(ua); } function isIos(checkIpadOS = true) { const iOsTest = /iPhone|iPod|iPad/i.test(ua); return checkIpadOS ? iOsTest || isIpadOS() : iOsTest; } function isIpadOS() { // "ontouchend" is used to determine if a browser is on an iPad, otherwise // user-agents for iPadOS behave/identify as a desktop browser return /Mac|iPad/i.test(ua) && "ontouchend" in window.document; } function isEdge() { return ua.indexOf("Edge/") !== -1 || ua.indexOf("Edg/") !== -1; } function isSamsung() { return /SamsungBrowser/i.test(ua); } function isDuckDuckGo() { return ua.indexOf("DuckDuckGo/") !== -1; } function isOpera() { return ( ua.indexOf("OPR/") !== -1 || ua.indexOf("Opera/") !== -1 || ua.indexOf("OPT/") !== -1 ); } function isSilk() { return ua.indexOf("Silk/") !== -1; } function isChrome() { return ( (ua.indexOf("Chrome") !== -1 || ua.indexOf("CriOS") !== -1) && !isEdge() && !isSamsung() && !isDuckDuckGo() && !isOpera() && !isSilk() ); } function isIosFirefox() { return /FxiOS/i.test(ua); } function isWebkit() { const webkitRegexp = /webkit/i; return webkitRegexp.test(ua); } function isIosChrome() { return ua.indexOf("CriOS") > -1; } function isFacebook() { return ua.indexOf("FBAN") > -1; } function isIosSafari() { return ( isIos() && isWebkit() && !isIosChrome() && !isIosFirefox() && !isFacebook() ); } function isFacebookOwnedBrowserOnAndroid() { var e = ua.toLowerCase(); return -1 < e.indexOf("huawei") && -1 < e.indexOf("fban") || isAndroid() && (-1 < e.indexOf("fb_iab") || -1 < e.indexOf("instagram")); } function isSamsungBrowser() { return /SamsungBrowser/i.test(ua); } function isAndroidWebview() { return isAndroid() && -1 < ua.toLowerCase().indexOf("wv"); } function isGoogleSearchApp() { return /\bGSA\b/.test(ua); } function isIosGoogleSearchApp() { return isIos() && isGoogleSearchApp(); } function isIosWebview() { if (isIos()) { // The Google Search iOS app is technically a webview and doesn't support popups. if (isIosGoogleSearchApp()) { return true; } // Historically, a webview could be identified by the presence of AppleWebKit and _no_ presence of Safari after. return /.+AppleWebKit(?!.*Safari)/i.test(ua); } return false; } }; /* End form functions */ $(document).ready(function() { mw.loader.using( ['mediawiki.util'] ).done( function() { var form = document.forms.donateForm; // Minimum amount is usually about 1 USD donationForm.minLocal = donationForm.currencyRates[ donationForm.currency ]; donationForm.minLocal = Math.ceil( donationForm.minLocal * 100 ) / 100; // Round it up donationForm.maxUSD = 25000; donationForm.maxLocal = Math.floor( donationForm.currencyRates[ donationForm.currency ] * donationForm.maxUSD ); // Overrides for India if ( donationForm.currency === 'INR' ) { donationForm.minLocal = 10; // Until https://phabricator.wikimedia.org/T370583 fixed? donationForm.maxUSD = 3000; donationForm.maxLocal = 250000; } // Block typing symbols in Other field donationForm.otherInputControl( document.getElementById('input_amount_other_box') ); // Clear errors and update fee when selected/entered $('.amount-options').on( 'input change', function() { // Ideally we would validate the amount, but this causes issues with focus $('.amount-options .lp-error').hide(); donationForm.updateFeeDisplay(); }); // Disable submitting form with Enter key $('form[name="donateForm"]').on('keypress', function(e) { var code = ( e.keyCode ? e.keyCode : e.which ); if ( code == 13 ) { e.preventDefault(); } }); // But allow Enter on buttons $('.payment-method-button').keyup(function(e) { if (event.keyCode === 13) { e.target.click(); } }); if ( form ) { // hide frequency options for some countries if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) !== -1 ) { $('#frequency_onetime').prop('checked', true); $('.frequency-options, #cancel-monthly, #donate-recurring-smallprint').hide(); } if ( donationForm.noRecurringPaypalCountries.indexOf( donationForm.country ) !== -1 ) { $( '.paymentmethod-pp, .paymentmethod-pp-usd' ).addClass( 'not-monthly-capable' ); } // Format amounts on buttons $( '.amount-options li' ).each( function( index ) { let amount = this.querySelector( 'input' ).value; if ( amount !== 'Other' ) { this.querySelector( 'label' ).innerText = donationForm.formatCurrency( amount ); } }); addCardTypesClass( donationForm.country ); // Only show Amazon for links from Ways to give if ( mw.util.getParamValue( 'wmf_source' ) === 'Waystogive' || mw.util.getParamValue( 'wmf_source' ) === 'Ways_to_Give' ) { $('.paymentmethod-amazon').show(); } // Apple Pay if ( $('.paymentmethod-applepay').length > 0 ) { if ( !donationForm.shouldShowApplePay( donationForm.country ) ) { $('.paymentmethod-applepay').remove(); } } // Venmo browser check if ( $('.paymentmethod-venmo').length > 0 ) { if ( !donationForm.isVenmoSupported() || donationForm.country !== 'US' ) { $('.paymentmethod-venmo').remove(); } } // Dumb hack to remove ACH for Portal test against Fundraise Up if ( mw.util.getParamValue( 'wmf_source' ) === 'portalBanner_en6C_2024_overlayBanner4WikiForm' ) { $('.paymentmethod-ach').remove(); } } // Links open in new tab $('.links-in-new-tab a').attr('target', '_blank'); // Disable logo link $('#p-logo a').attr( { href: '#', title: '' } ); // These don't need to be tabbable on the landing page $('#searchInput, .mw-jump-link').attr('tabindex', '-1'); $('.input_amount_other').click(function() { $('#input_amount_other_box').focus(); }); // Allow preselecting frequency if possible if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) === -1 && mw.util.getParamValue( 'utm_medium' ) !== 'endowment' && mw.util.getParamValue( 'wmf_medium' ) !== 'endowment' ) { if ( mw.util.getParamValue( 'frequency' ) ) { donationForm.setFrequency( mw.util.getParamValue( 'frequency' ) ); } else if ( mw.util.getParamValue('monthly') && mw.util.getParamValue('monthly') !== '0' ) { // old method with "monthly=" parameter donationForm.setFrequency( 'monthly' ); } else { donationForm.setFrequency( 'onetime' ); } } donationForm.initOptin(); try { adjustHPC(); preSelect(); // Make sure to do this *after* other fiddling with values donationForm.localizeErrors(); } finally { $('.frb-monthly-pitch, .frb-monthly-pitch-thanks').appendTo('.frequency-options'); $('.ptf').appendTo('.amount-options'); $('.optin-options').insertAfter('.amount-options'); $('.consider-amounts').show(); $('#actual-form').show(); $('#actual-form-loading').hide(); } }); }); pid4abnbnyh3egsghatgahi6plnd0wz MediaWiki:DonationFormSandbox.js 8 8629 40754 40749 2024-12-11T10:43:32Z Pcoombe 5 40754 javascript text/javascript /* jshint strict:false */ /** MediaWiki:DonationForm.js - loaded on all donation forms * TODO: lots of cleanup */ var donationForm = {}; donationForm.loadedTime = Date.now(); donationForm.extraData = {}; donationForm.country = mw.util.getParamValue('country').toUpperCase(); try { donationForm.currency = document.forms.donateForm.currency_code.value; } catch (error) { donationForm.currency = 'USD'; } /** * Make language and country into a standard javascript Intl locale identifier * * @param {string} language * @param {string} country * @return {string} locale identifier e.g. en-GB */ donationForm.getLocale = function( language, country ) { // Sometimes in email testing links the uselang is a variable contiaining % // In that case fall back to English so locale code doesn't break form if ( language.match('%') ) { language = 'en'; } // MediaWiki allows some language codes like en-gb, en-ca, pt-br // We don't want these for a javascript locale, so drop anything after '-' language = language.split('-')[0]; return language + '-' + country; }; donationForm.locale = donationForm.getLocale( mw.config.get('wgPageContentLanguage'), donationForm.country ); // Don't offer recurring at all in these countries donationForm.noRecurringCountries = [ 'AR', 'IN' ]; donationForm.noRecurringPaypalCountries = [ 'CL', 'CO', 'PE', 'UY', 'BR' ]; donationForm.currencyRates = { // From https://github.com/wikimedia/wikimedia-fundraising-SmashPig/blob/master/PaymentData/ReferenceData/CurrencyRates.php // Updated 2024-07-31 'ADF' : 6.04, 'ADP' : 153, 'AED' : 3.67, 'AFA' : 70, 'AFN' : 70, 'ALL' : 90, 'AMD' : 368, 'ANG' : 1.79, 'AOA' : 844, 'AON' : 844, 'ARS' : 887, 'ATS' : 13, 'AUD' : 1.5, 'AWG' : 1.79, 'AZM' : 8500, 'AZN' : 1.7, 'BAM' : 1.8, 'BBD' : 2, 'BDT' : 116, 'BEF' : 37, 'BGL' : 1.8, 'BGN' : 1.8, 'BHD' : 0.37355757356689, 'BIF' : 2842, 'BMD' : 1, 'BND' : 1.35, 'BOB' : 6.71, 'BRL' : 5.1, 'BSD' : 1, 'BTN' : 83, 'BWP' : 13, 'BYR' : 32642, 'BZD' : 1.98, 'CAD' : 1.36, 'CDF' : 2786, 'CHF' : 0.9094629289448, 'CLP' : 890, 'CNY' : 7.23, 'COP' : 3803, 'CRC' : 498, 'CUC' : 1, 'CUP' : 25, 'CVE' : 101, 'CYP' : 0.53848627984321, 'CZK' : 23, 'DEM' : 1.8, 'DJF' : 178, 'DKK' : 6.86, 'DOP' : 58, 'DZD' : 133, 'ECS' : 24094, 'EEK' : 14, 'EGP' : 47, 'ESP' : 153, 'ETB' : 57, 'EUR' : 0.92005843390143, 'FIM' : 5.47, 'FJD' : 2.23, 'FKP' : 0.78703952551207, 'FRF' : 6.04, 'GBP' : 0.78703952551207, 'GEL' : 2.71, 'GHC' : 143125, 'GHS' : 14, 'GIP' : 0.78703952551207, 'GMD' : 68, 'GNF' : 8493, 'GRD' : 314, 'GTQ' : 7.57, 'GYD' : 200, 'HKD' : 7.8, 'HNL' : 24, 'HRK' : 6.93, 'HTG' : 132, 'HUF' : 355, 'IDR' : 15986, 'IEP' : 0.72460490043714, 'ILS' : 3.69, 'INR' : 83, 'IQD' : 1290, 'IRR' : 42009, 'ISK' : 138, 'ITL' : 1781, 'JMD' : 154, 'JOD' : 0.70900000000001, 'JPY' : 156, 'KES' : 130, 'KGS' : 88, 'KHR' : 3993, 'KMF' : 453, 'KPW' : 135, 'KRW' : 1358, 'KWD' : 0.30629670764681, 'KYD' : 0.83333299999999, 'KZT' : 442, 'LAK' : 21103, 'LBP' : 89393, 'LKR' : 298, 'LRD' : 193, 'LSL' : 18, 'LTL' : 3.18, 'LUF' : 37, 'LVL' : 0.64662074757963, 'LYD' : 4.8, 'MAD' : 9.79, 'MDL' : 17, 'MGA' : 4379, 'MGF' : 9150, 'MKD' : 56, 'MMK' : 2075, 'MNT' : 2620, 'MOP' : 8.03, 'MRO' : 391, 'MTL' : 0.39498108567387, 'MUR' : 45, 'MVR' : 15, 'MWK' : 1720, 'MXN' : 17, 'MYR' : 4.68, 'MZM' : 63200, 'MZN' : 63, 'NAD' : 18, 'NGN' : 1505, 'NIO' : 36, 'NLG' : 2.03, 'NOK' : 11, 'NPR' : 131, 'NZD' : 1.63, 'OMR' : 0.38377594841305, 'PAB' : 1, 'PEN' : 3.67, 'PGK' : 3.76, 'PHP' : 58, 'PKR' : 277, 'PLN' : 3.91, 'PTE' : 184, 'PYG' : 7355, 'QAR' : 3.56, 'ROL' : 45713, 'RON' : 4.57, 'RSD' : 108, 'RUB' : 91, 'RWF' : 1277, 'SAR' : 3.75, 'SBD' : 8.37, 'SCR' : 13, 'SDD' : 59800, 'SDG' : 598, 'SDP' : 2261, 'SEK' : 11, 'SGD' : 1.35, 'SHP' : 0.78703952551207, 'SIT' : 220, 'SKK' : 28, 'SLL' : 19750, 'SOS' : 549, 'SRD' : 33, 'SRG' : 33320, 'STD' : 22477, 'SVC' : 8.75, 'SYP' : 513, 'SZL' : 18, 'THB' : 36, 'TJS' : 11, 'TMM' : 16750, 'TMT' : 3.35, 'TND' : 3.11, 'TOP' : 2.32, 'TRL' : 32168418, 'TRY' : 32, 'TTD' : 6.64, 'TWD' : 32, 'TZS' : 2587, 'UAH' : 39, 'UGX' : 3760, 'USD' : 1, 'UYU' : 38, 'UZS' : 12662, 'VEB' : 3651907631, 'VEF' : 3651908, 'VND' : 25451, 'VUV' : 112, 'WST' : 2.67, 'XAF' : 604, 'XAG' : 0.031347411860134, 'XAU' : 0.00041128929241299, 'XCD' : 2.7, 'XEU' : 0.92005843390143, 'XOF' : 604, 'XPD' : 0.00098009826645798, 'XPF' : 110, 'XPT' : 0.00093444018680404, 'YER' : 249, 'YUN' : 108, 'ZAR' : 18, 'ZMK' : 5176, 'ZWD' : 373 }; /* Amount and currency formatting */ let formatters = { // Amounts without currency symbol amountFraction: new Intl.NumberFormat( donationForm.locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 } ), amountWhole: new Intl.NumberFormat( donationForm.locale, {} ) }; // currencyDisplay: 'narrowSymbol' fixes some issues like en-CO showing the ISO code // but browser support is lacking, so wrap in a try/catch try { formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol' } ); formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol', minimumFractionDigits: 0 } ); } catch(e) { formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency } ); formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, minimumFractionDigits: 0 } ); } donationForm.formatCurrency = function( amount ) { if ( amount % 1 !== 0 ) { // Not a whole number return formatters.currencyFraction.format( amount ); } else { return formatters.currencyWhole.format( amount ); } }; donationForm.formatAmount = function( amount ) { var formatterOptions, output; if ( amount % 1 !== 0 ) { // Not a whole number return formatters.amountFraction.format( amount ); } else { return formatters.amountWhole.format( amount ); } }; /* Localize the amount errors. Call when initialising form. */ donationForm.localizeErrors = function() { var currency = donationForm.currency; $('.lp-error-smallamount').text( function( index, oldText ) { return oldText.replace( '$1', donationForm.formatAmount( donationForm.minLocal ) + '\xa0' + currency ); }); if ( currency === 'USD' ) { // we don't need to include the conversion $('.lp-error-bigamount').text( function( index, oldText ) { return oldText.replace( '($1 $2) ', '' ) .replace( '($1&nbsp;$2) ', '' ); }); } $('.lp-error-bigamount').text( function( index, oldText ) { return oldText.replace( '$1', donationForm.formatAmount( donationForm.maxLocal ) ) .replace( '$2', currency ) .replace( '$3', 'benefactors@wikimedia.org' ) .replace( '$4', donationForm.formatAmount( donationForm.maxUSD ) ); }); }; function adjustHPC() { /* Adjust amounts based on highest previous contribution (hpc) or most recent contribution (mrc) parameter. Used for emails. TODO: split data out? */ var hpcSet = mw.util.getParamValue('hpcSet'); // Look for 'hpc' parameter, then 'mrc' var hpc = parseFloat( mw.util.getParamValue('hpc') ); if( isNaN(hpc) ) { hpc = parseFloat( mw.util.getParamValue('mrc') ); if( isNaN(hpc) ) { if ( hpcSet ) { // Allow using hpcSet even without hpc, for MG appeals hpc = 0; } else { return; } } } var currency = donationForm.currency; // If changing, please update https://docs.google.com/spreadsheets/d/1e02TsZ_bKDAS1BMVBCdyo9D7RGln_wCGnkg7IF5kU5s/edit var radioAmountsData = { "USD" : { // also used for CAD, AUD, NZD "default" : [ [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_USD" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_USD" : [ // Upgrade recurring amount dynamically [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2.75, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 3.50, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3.75, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4.50, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6.75, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15.75, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 24.75, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 44.75, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_USD" : [ // Give less reactivation amount [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ], // Direct Mail - fixed amounts "directmail" : [ [ 0, [ 25, 35, 50, 100, 150, 250, 300 ] ] ], "directmail250" : [ [ 0, [ 250, 300, 500, 750, 1000, 2500, 5000 ] ] ] }, "EUR" : { "default" : [ [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_EUR" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_EUR" : [ // Upgrade recurring amount dynamically [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2.50, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 2.50, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3.50, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4.25, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6.25, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 25, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 45, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_EUR" : [ // Give less reactivation amount [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ] }, "GBP" : { "default" : [ [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_GBP" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_GBP" : [ // Upgrade recurring amount dynamically [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 2, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 20, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 40, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 45, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 125, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 200, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 400, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_GBP" : [ // Give less reactivation amount [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ] }, "JPY" : [ [ 0, [ 500, 1000, 2000, 2500, 4000, 5000, 10000 ] ], [ 1000, [ 1000, 1500, 2500, 4000, 5000, 10000, 15000 ] ], [ 1500, [ 1500, 2000, 3000, 4000, 5000, 10000, 15000 ] ], [ 2000, [ 2000, 2500, 3500, 5000, 7500, 10000, 25000 ] ], [ 2500, [ 2500, 3500, 5000, 7500, 10000, 15000, 25000 ] ], [ 3000, [ 3000, 4000, 5000, 7500, 10000, 15000, 25000 ] ], [ 2500, [ 2500, 5000, 7500, 10000, 20000, 30000, 50000 ] ], [ 2500, [ 2500, 5000, 7500, 10000, 20000, 50000, 100000 ] ], [ 5000, [ 5000, 10000, 15000, 20000, 35000, 50000, 100000 ] ], [ 10000, [ 10000, 25000, 50000, 75000, 100000, 150000, 200000 ] ] ], "SEK" : [ [ 0, [ 30, 100, 150, 200, 500, 750, 1000 ] ], [ 50, [ 50, 100, 150, 200, 300, 750, 1000 ] ], [ 200, [ 50, 100, 200, 300, 500, 750, 1000 ] ] ] }; radioAmountsData.AUD = radioAmountsData.USD; radioAmountsData.CAD = radioAmountsData.USD; radioAmountsData.NZD = radioAmountsData.USD; // Major gifts appeals, hacky but this is easier than adding a load of new forms to maintain var currencyList = [ 'USD', 'CAD', 'AUD', 'NZD', 'GBP', 'EUR' ]; // close enough for ( let i = 0; i < currencyList.length; i++ ) { radioAmountsData[ currencyList[i] ].MG_2024_500 = [ [ 0, [ 500, 750, 1000, 1250, 1500, 1750, 2000 ] ] ]; radioAmountsData[ currencyList[i] ].MG_2024_650 = [ [ 0, [ 650, 750, 1000, 1250, 1500, 1750, 2000 ] ] ]; } var appealAmountsData = { "USD" : [ // also used for CAD, AUD, NZD, GBP, EUR [ 0, [ 5, 10, 20 ] ], [ 10, [ 10, 20, 50 ] ], [ 20, [ 20, 30, 50 ] ], [ 35, [ 20, 30, 50 ] ], [ 50, [ 20, 50, 100 ] ], [ 75, [ 50, 75, 100 ] ], [ 100, [ 75, 100, 150 ] ], [ 150, [ 75, 100, 200 ] ], [ 200, [ 100, 200, 300 ] ] ], "JPY" : [ [ 0, [ 300, 500, 1000 ] ], [ 3, [ 500, 1000, 1500 ] ], [ 5, [ 1000, 1500, 2000 ] ], [ 10, [ 1500, 2000, 5000 ] ], [ 20, [ 2000, 3000, 5000 ] ], [ 50, [ 2000, 5000, 10000 ] ], [ 100, [ 5000, 10000, 15000 ] ] ], "SEK" : [ [ 0, [ 20, 50, 100 ] ], [ 3, [ 30, 50, 100 ] ], [ 5, [ 50, 100, 150 ] ], [ 15, [ 100, 150, 200 ] ], [ 23, [ 100, 200, 300 ] ], [ 38, [ 100, 200, 500 ] ], [ 75, [ 100, 500, 750 ] ], [ 112, [ 100, 500, 1000 ] ] ] }; appealAmountsData.AUD = appealAmountsData.USD; appealAmountsData.CAD = appealAmountsData.USD; appealAmountsData.GBP = appealAmountsData.USD; appealAmountsData.NZD = appealAmountsData.USD; appealAmountsData.EUR = appealAmountsData.USD; // Radio button amounts var radioAmounts = pickAmountArray( radioAmountsData, currency, hpc, hpcSet ); if ( radioAmounts.length ) { // Change buttons for (var j = 0; j < radioAmounts.length; j++) { var $radio = $("#input_amount_" + j); var $label = $("label[for='input_amount_" + j + "']"); $radio.val( radioAmounts[j] ); $label.text( donationForm.formatCurrency( radioAmounts[j] ) ); } } // Appeal amounts var appealAmounts = pickAmountArray( appealAmountsData, currency, hpc, hpcSet ); if ( appealAmounts.length ) { var appealAmountString = appealAmounts.map( donationForm.formatCurrency ).join( ', '); $('.consider-amounts').html(appealAmountString); } } function pickAmountArray( data, currency, hpc, hpcSet ) { /** * Choose the amounts for radio buttons / appeal based on hpc * @param {Object} data * @param {String} currency * @param {Number} hpc * @param {String} hpcSet * @return {Array} Array of amounts (as numbers) */ var set, amounts; if ( !(currency in data) ) { return []; } if ( $.isArray(data[currency]) ) { // No variant sets set = data[currency]; } else { // We need to go deeper. Check the variants. if ( hpcSet in data[currency] ) { set = data[currency][hpcSet]; } else { set = data[currency]['default']; } } // Find correct amount array for this hpc for (var i = 0; i < set.length; i++) { if ( set[i][0] > hpc ) { break; } amounts = set[i][1]; } return amounts; } function preSelect() { /* Check for a 'preSelect' url parameter, and select that option. If there isn't an option, add it to the "Other" box and select that */ var preSelectAmount = parseFloat( mw.util.getParamValue('preSelect') ); if ( preSelectAmount > 0 ) { var $preSelectOption = $('input[name="amount"][value="' + preSelectAmount + '"]'); if ( $preSelectOption.length ) { // Select existing input $preSelectOption.prop('checked', true); } else { $('#input_amount_other_box').val( preSelectAmount ); $('#input_amount_other').prop('checked', true); } donationForm.updateFeeDisplay(); } } function addCardTypesClass(country) { /** * Add card types class to credit card button, so we can show correct logos * Banner equivalent: https://meta.wikimedia.org/wiki/MediaWiki:FundraisingBanners/LocalizeJS-2017.js * @param {String} country ISO code */ var cardTypes = { // Big 6 'US' : 'vmad', 'CA' : 'vma', 'GB' : 'vmaj', 'IE' : 'vmaj', 'AU' : 'vmaj', 'NZ' : 'vma', // Euro countries 'AT' : 'vmaj', 'BE' : 'vmaj', 'ES' : 'vmaj', 'FR' : 'vma', // Adyen - Carte Bancaire was removed 'IT' : 'vmaj', 'LU' : 'vmaj', 'LV' : 'vma', 'NL' : 'vmaj', 'PT' : 'vmaj', 'SK' : 'vmaj', 'GR' : 'vma', // Others 'CZ' : 'vmad', 'DK' : 'vma', 'HU' : 'vma', 'IL' : 'vmad', // Adyen 'JP' : 'vmaj', 'MY' : 'vmaj', 'NO' : 'vma', 'PL' : 'vma', 'RO' : 'vma', 'SE' : 'vma', 'UA' : 'vma', // Adyen 'ZA' : 'vm', 'ZZ' : 'vmad' // For testing }; if ( cardTypes[country] ) { $('.paymentmethod-cc').addClass('cctypes-' + cardTypes[country] ); $('.cc-text-label').addClass('sr-only'); } } /* Form functions */ function clearOther(box) { document.getElementById('input_amount_other').checked = true; box.value = ""; } function selectOther() { document.getElementById('input_amount_other').checked = true; } function selectAmount() { $('#input_amount_other_box').val(''); } /* -- Moved from Template:2012FR/Form-section/Processing/Default -- */ /** * Validate form, and prep most of the parameters * * @param {string} paymentMethod - method e.g. 'cc', 'paypal' * @param {string} paymentSubMethod - submethod e.g. 'rtbt_ideal' (a submethod of 'rtbt') * @param {string} skipAmountValidation - skip validating amount for PayPal forced to USD */ donationForm.redirectPayment = function( paymentMethod, paymentSubMethod, skipAmountValidation ) { if ( donationForm.validate( skipAmountValidation ) ) { var params = {}; params.currency = donationForm.currency; params.country = donationForm.country; // Overrides for specific cc gateways if ( paymentMethod === 'cc-adyen' ) { params.payment_method = 'cc'; params.gateway = 'adyen'; } else if ( paymentMethod === 'cc-dlocal' ) { params.payment_method = 'cc'; params.gateway = 'astropay'; } else { params.payment_method = paymentMethod; } if ( params.payment_method === 'cc' && params.country === 'ZA' ) { params.gateway = 'astropay'; } if ( paymentSubMethod ) { params.payment_submethod = paymentSubMethod; } let frequency = donationForm.getFrequency(); if ( frequency === 'monthly' ) { params.recurring = '1'; params.frequency_unit = 'month'; } else if ( frequency === 'annual' ) { params.recurring = '1'; params.frequency_unit = 'year'; } params.uselang = mw.config.get('wgPageContentLanguage'); // see T281285 for why not wgUserLanguage if ( params.uselang === 'pt' && params.country === 'BR' ) { params.uselang = 'pt-br'; } if ( params.uselang === 'es' && ( params.country === 'AR' || params.country === 'CL' || params.country === 'CO' || params.country === 'MX' || params.country === 'PE' || params.country === 'UY' || params.country === 'US' ) ) { params.uselang = 'es-419'; } var amount = donationForm.getAmount(); if ( $('#ptf-checkbox').prop('checked') ) { amount = amount + donationForm.calculateFee( amount ); donationForm.extraData.ptf = 1; } params.amount = amount; // Email optin if ( $('input[name="opt_in"]').length > 0 ) { var opt_inValue = $('input[name="opt_in"]:checked').val(); params.opt_in = opt_inValue; // donationForm.validate() already checked it's 1 or 0 } if ( mw.util.getParamValue( 'pym_variant' ) ) { params.variant = mw.util.getParamValue( 'pym_variant' ); } if ( params.recurring && params.variant && params.variant.match( /monthlyConvert/ ) ) { // Post-payments monthly convert makes no sense if it's already recurring // Avoid things like T312905 delete params.variant; } // TODO: refactor this to a list of parameters to pass unchanged // or just pass everything by default? if ( mw.util.getParamValue( 'pym_appeal' ) ) { params.appeal = mw.util.getParamValue( 'pym_appeal' ); } // https://phabricator.wikimedia.org/T381405 if ( mw.util.getParamValue( 'contact_id' ) ) { params.contact_id = mw.util.getParamValue( 'contact_id' ); } if ( mw.util.getParamValue( 'contact_hash' ) ) { params.contact_hash = mw.util.getParamValue( 'contact_hash' ); } // SMS if ( mw.util.getParamValue( 'recipient_id' ) ) { params.recipient_id = mw.util.getParamValue( 'recipient_id' ); } // Monthly convert if ( mc ) { // check just in-case this wasn't loaded for some reason mc.main( params, donationForm.finalStep ); } else { donationForm.finalStep( params ); } } else { donationForm.extraData.validateError = 1; // Flag they had an error, even if fixed later } return false; // don't submit if called by a button }; /** * Build final tracking parameters, and submit to payments * @param {Object} params */ donationForm.finalStep = function( params ) { var url = new URL('https://payments.wikimedia.org/index.php/Special:GatewayChooser'); // Skip form chooser for Apple Pay / Google Pay if ( params.payment_method === 'apple' || params.payment_method === 'google' ) { url = new URL('https://payments.wikimedia.org/index.php/Special:AdyenCheckoutGateway'); } // Skip form chooser for Venmo if ( params.payment_method === 'venmo' ) { url = new URL('https://payments.wikimedia.org/index.php/Special:BraintreeGateway'); } donationForm.extraData.time = Math.round( (Date.now() - donationForm.loadedTime)/1000 ); // Tracking data params.wmf_medium = mw.util.getParamValue( 'wmf_medium' ) || mw.util.getParamValue( 'utm_medium' ); params.wmf_campaign = mw.util.getParamValue( 'wmf_campaign' ) || mw.util.getParamValue( 'utm_campaign' ); params.wmf_source = donationForm.buildTrackingSource( params ); params.wmf_key = donationForm.buildTrackingKey( donationForm.extraData ); if ( document.referrer ) { // TODO: do we need this? // Strip protocol to stop firewall complaining params.referrer = document.referrer.replace(/https?:\/\//i, ''); } for ( var key of Object.keys( params ) ) { url.searchParams.set( key, params[key] ); } if ( window.top !== window.self ) { // In a frame, open payments in a new tab window.open( url.toString() ); } else { window.location.href = url.toString(); } }; /** * Build a wmf_source value, including the landing page info. * * Own function so it can be overriden for weird tests * * @param {Object} params * @return {string} wmf_source */ donationForm.buildTrackingSource = function( params ) { var wmf_source = mw.util.getParamValue( 'wmf_source' ) || mw.util.getParamValue( 'utm_source' ); wmf_source += '.'; var fullDottedPaymentMethod = params.payment_method; if ( params.recurring ) { fullDottedPaymentMethod = 'r' + fullDottedPaymentMethod; } if ( params.payment_submethod ) { fullDottedPaymentMethod = fullDottedPaymentMethod + '.' + params.payment_submethod; } /* Get URL parameter, but remove parts using old format. Allow fallback to a default value */ var getParam = function( param, removeText, dflt ) { if ( mw.util.getParamValue( param ) ) { return mw.util.getParamValue( param ).replace( removeText, '' ); } else { return dflt; } }; /* The landing page info, separated by ~. This mostly exists for legacy reasons */ wmf_source += getParam( 'template' , 'Lp-layout' , 'default' ) + '~'; wmf_source += getParam( 'appeal-template' , 'Appeal-template-' , 'default' ) + '~'; wmf_source += getParam( 'appeal' , 'Appeal-' , 'default' ) + '~'; wmf_source += getParam( 'form-template' , 'Form-template-' , 'default' ) + '~'; wmf_source += getParam( 'form-countryspecific', 'Form-countryspecific-', 'control' ); wmf_source += '.' + fullDottedPaymentMethod; return wmf_source; }; /** * Build a string for wmf_key from extra tracking data * * @param {Object} data * @return {string} wmf_key */ donationForm.buildTrackingKey = function(data) { var existingKey = mw.util.getParamValue( 'wmf_key' ) || mw.util.getParamValue( 'utm_key' ), dataArray = []; if ( existingKey ) { dataArray.push( existingKey ); } for (var key in data) { if (data.hasOwnProperty(key)) { dataArray.push( key + '_' + data[key] ); } } return dataArray.join('~'); }; /* Return amount selected or input */ donationForm.getAmount = function() { var form = document.forms.donateForm, amount = null; donationForm.extraData.otherAmt = 0; // If there are some amount radio buttons, then look for the checked one if ( form.amount ) { for ( var i = 0; i < form.amount.length; i++ ) { if ( form.amount[i].checked ) { amount = parseFloat( form.amount[i].value ); } } } // Check the "other" amount box if ( document.getElementById('input_amount_other').checked ) { amount = donationForm.parseOtherAmount( form.input_amount_other_box.value ); donationForm.extraData.otherAmt = 1; } return amount; }; /** * Parse Other field value into amount * * Does some awful regex stuff to rm symbols and turn the string into a number * Remember some locales flip . & , for decimal point/thousands separator * * @param {string} value Value of "Other" field * @return {float} Float with amount, or 0 if NaN */ donationForm.parseOtherAmount = function( value ) { var amount; value = value.replace(/[,.](\d)$/, '\:$10'); value = value.replace(/[,.](\d)(\d)$/, '\:$1$2'); value = value.replace(/[\$£€¥,.]/g, ''); value = value.replace(/:/, '.'); amount = parseFloat( value ); if ( isNaN( amount ) ) { return 0; } else { return amount; } }; /** * Validate the form. */ donationForm.validate = function( skipAmountValidation ) { var error = false; var form = document.forms.donateForm; // Reset all errors $('.lp-haserror').removeClass('lp-haserror'); $('.lp-error').hide(); if ( !skipAmountValidation && !donationForm.validateAmount() ) { error = true; } if ( form.opt_in ) { if ( $('input[name="opt_in"]:checked').val() === undefined ) { $('#error-optin').show().focus(); error = true; } else { $('#error-optin').hide(); } } return !error; }; /** * Check if selected amount is valid i.e. a positive number, between minimum and maximum. * If not, show an error and return false. */ donationForm.validateAmount = function() { var amount = donationForm.getAmount(); if ( amount === null || isNaN(amount) || amount <= 0 || amount < donationForm.minLocal ) { $('.amount-options').addClass('lp-haserror'); $('.lp-error-bigamount').hide(); $('.lp-error-smallamount').show().focus(); return false; } else if ( amount > donationForm.maxLocal ) { $('.amount-options').addClass('lp-haserror'); $('.lp-error-bigamount').show().focus(); return false; } else { $('.amount-options').removeClass('lp-haserror'); $('.lp-error-smallamount, .lp-error-bigamount').hide(); return true; } }; donationForm.getFrequency = function() { return document.forms.donateForm.dataset.frequency || 'onetime'; }; donationForm.setFrequency = function( frequency ) { // TODO: add some validation to reject invalid frequency values let form = document.forms.donateForm; form.frequency.value = frequency; // change input form.dataset.frequency = frequency; }; /* Wrapper for compatibility with old forms */ donationForm.toggleMonthly = function( monthly ) { if ( monthly ) { donationForm.setFrequency( 'monthly' ); } else { donationForm.setFrequency( 'onetime' ); } }; donationForm.updateFeeDisplay = function() { var selectedAmount = donationForm.getAmount(), feeAmount = donationForm.calculateFee( selectedAmount ), feeText; feeText = donationForm.formatCurrency( feeAmount ); $('.ptf label span').text( feeText ); if ( selectedAmount + feeAmount <= donationForm.maxLocal ) { $('.ptf').slideDown(); } }; /** * Calculate approximate transaction fee on given amount * @param {number} amount * @return {number} Rounded to 2 decimal places */ donationForm.calculateFee = function( amount ) { // Minimum fee/PTF amounts. Default is 0.35. // Updated 2019-05-21 to approx 0.35 USD equivalent var feeMinimums = { 'DKK' : 2, 'HUF' : 100, 'ILS' : 1.2, 'INR' : 4, 'JPY' : 35, 'MYR' : 1, 'NOK' : 3, 'PLN' : 1.35, 'CZK' : 7.5, 'RON' : 1.5, 'SEK' : 3, 'UAH' : 10, 'ZAR' : 5, // Latin America // Updated 2024-08-22 to approx 0.35 USD equivalent 'BRL' : 1.75, 'ARS' : 300, 'CLP' : 300, 'COP' : 1400, 'MXN' : 6, 'PEN' : 1.2, 'UYU' : 14 }; var feeMultiplier = 0.04, feeMinimum = feeMinimums[ donationForm.currency ] || 0.35, feeAmount = amount * feeMultiplier; if ( feeAmount < feeMinimum ) { feeAmount = feeMinimum; } return parseFloat( feeAmount.toFixed(2) ); }; donationForm.initOptin = function() { $('.optin-options').on('change', function(e) { $('#error-optin').hide(); // Only do all this if we have translated prompts if ( $('.optin-no-prompt').data('is-translated') === 'yes' ) { if ( e.target.id === 'optin-no' ) { $('.optin-no-prompt').removeClass('is-positive'); if ( !$('.optin-no-prompt').is(':visible') ) { $('.optin-no-prompt').slideDown(); } } else { $('.optin-no-prompt').addClass('is-positive'); } } }); }; /** * Block typing letters and symbols in given input. Used for Other amount inputs * * If we don't do this, Safari allows typing them and then chokes on submit * https://phabricator.wikimedia.org/T118741, https://phabricator.wikimedia.org/T173431 * * @param {Element} inputElement The element to block typing on */ donationForm.otherInputControl = function( inputElement ) { if ( inputElement ) { inputElement.onkeypress = function(e) { // Allow special keys in Firefox if ((e.code == 'ArrowLeft') || (e.code == 'ArrowRight') || (e.code == 'ArrowUp') || (e.code == 'ArrowDown') || (e.code == 'Delete') || (e.code == 'Backspace')) { return; } var chr = String.fromCharCode(e.which); if ('0123456789., '.indexOf(chr) === -1) { return false; } }; } }; /** * Should we show Apple Pay? * * Note there is a ~500ms delay in Safari when checking, so only call this if needed * * @param {string} country * @return {boolean} */ donationForm.shouldShowApplePay = function ( country ) { if ( location.search.match('forceApplePay') ) { return true; } if ( window.ApplePaySession ) { if ( ApplePaySession.canMakePayments() ) { return true; } } return false; }; /* Based on github:braintree/braintree-web/src/venmo/shared/supports-venmo.js See also on meta: MediaWiki:FundraisingBanners/VenmoBrowserCheck.js */ donationForm.isVenmoSupported = function(options) { var options = options || { allowNewBrowserTab: false, allowWebviews: true, allowDesktop: true, allowDesktopWebLogin: true }; var ua = window.navigator.userAgent; var merchantAllowsReturningToNewBrowserTab, merchantAllowsWebviews, merchantAllowsDesktopBrowsers; var isMobileDevice = isAndroid() || isIos(); var isAndroidChrome = isAndroid() && isChrome(); var isMobileDeviceThatSupportsReturnToSameTab = isIosSafari() || isAndroidChrome; var isKnownUnsupportedMobileBrowser = isIosChrome() || isFacebookOwnedBrowserOnAndroid() || isSamsung(); options = options || {}; // NEXT_MAJOR_VERSION allowDesktop will default to true, but can be opted out merchantAllowsDesktopBrowsers = (options.allowDesktopWebLogin || options.allowDesktop) === true; merchantAllowsReturningToNewBrowserTab = options.hasOwnProperty( "allowNewBrowserTab" ) ? options.allowNewBrowserTab : true; // NEXT_MAJOR_VERSION webviews are not supported, except for the case where // the merchant themselves is presenting venmo in a webview using the deep // link url to get back to their app. For the next major version, we should // just not have this option and instead require the merchant to determine // if the venmo button should be displayed when presenting it in the // merchant's app via a webview. merchantAllowsWebviews = options.hasOwnProperty("allowWebviews") ? options.allowWebviews : true; if (isKnownUnsupportedMobileBrowser) { return false; } if ( !merchantAllowsWebviews && (isAndroidWebview() || isIosWebview()) ) { return false; } if (!isMobileDevice) { return merchantAllowsDesktopBrowsers; } if (!merchantAllowsReturningToNewBrowserTab) { return isMobileDeviceThatSupportsReturnToSameTab; } return isMobileDevice; /* -- functions mostly from github:braintree/browser-detection library -- */ function isAndroid() { return /Android/i.test(ua); } function isIos(checkIpadOS = true) { const iOsTest = /iPhone|iPod|iPad/i.test(ua); return checkIpadOS ? iOsTest || isIpadOS() : iOsTest; } function isIpadOS() { // "ontouchend" is used to determine if a browser is on an iPad, otherwise // user-agents for iPadOS behave/identify as a desktop browser return /Mac|iPad/i.test(ua) && "ontouchend" in window.document; } function isEdge() { return ua.indexOf("Edge/") !== -1 || ua.indexOf("Edg/") !== -1; } function isSamsung() { return /SamsungBrowser/i.test(ua); } function isDuckDuckGo() { return ua.indexOf("DuckDuckGo/") !== -1; } function isOpera() { return ( ua.indexOf("OPR/") !== -1 || ua.indexOf("Opera/") !== -1 || ua.indexOf("OPT/") !== -1 ); } function isSilk() { return ua.indexOf("Silk/") !== -1; } function isChrome() { return ( (ua.indexOf("Chrome") !== -1 || ua.indexOf("CriOS") !== -1) && !isEdge() && !isSamsung() && !isDuckDuckGo() && !isOpera() && !isSilk() ); } function isIosFirefox() { return /FxiOS/i.test(ua); } function isWebkit() { const webkitRegexp = /webkit/i; return webkitRegexp.test(ua); } function isIosChrome() { return ua.indexOf("CriOS") > -1; } function isFacebook() { return ua.indexOf("FBAN") > -1; } function isIosSafari() { return ( isIos() && isWebkit() && !isIosChrome() && !isIosFirefox() && !isFacebook() ); } function isFacebookOwnedBrowserOnAndroid() { var e = ua.toLowerCase(); return -1 < e.indexOf("huawei") && -1 < e.indexOf("fban") || isAndroid() && (-1 < e.indexOf("fb_iab") || -1 < e.indexOf("instagram")); } function isSamsungBrowser() { return /SamsungBrowser/i.test(ua); } function isAndroidWebview() { return isAndroid() && -1 < ua.toLowerCase().indexOf("wv"); } function isGoogleSearchApp() { return /\bGSA\b/.test(ua); } function isIosGoogleSearchApp() { return isIos() && isGoogleSearchApp(); } function isIosWebview() { if (isIos()) { // The Google Search iOS app is technically a webview and doesn't support popups. if (isIosGoogleSearchApp()) { return true; } // Historically, a webview could be identified by the presence of AppleWebKit and _no_ presence of Safari after. return /.+AppleWebKit(?!.*Safari)/i.test(ua); } return false; } }; /* End form functions */ $(document).ready(function() { mw.loader.using( ['mediawiki.util'] ).done( function() { var form = document.forms.donateForm; // Minimum amount is usually about 1 USD donationForm.minLocal = donationForm.currencyRates[ donationForm.currency ]; donationForm.minLocal = Math.ceil( donationForm.minLocal * 100 ) / 100; // Round it up donationForm.maxUSD = 25000; donationForm.maxLocal = Math.floor( donationForm.currencyRates[ donationForm.currency ] * donationForm.maxUSD ); // Overrides for India if ( donationForm.currency === 'INR' ) { donationForm.minLocal = 10; // Until https://phabricator.wikimedia.org/T370583 fixed? donationForm.maxUSD = 3000; donationForm.maxLocal = 250000; } // Block typing symbols in Other field donationForm.otherInputControl( document.getElementById('input_amount_other_box') ); // Clear errors and update fee when selected/entered $('.amount-options').on( 'input change', function() { // Ideally we would validate the amount, but this causes issues with focus $('.amount-options .lp-error').hide(); donationForm.updateFeeDisplay(); }); // Disable submitting form with Enter key $('form[name="donateForm"]').on('keypress', function(e) { var code = ( e.keyCode ? e.keyCode : e.which ); if ( code == 13 ) { e.preventDefault(); } }); // But allow Enter on buttons $('.payment-method-button').keyup(function(e) { if (event.keyCode === 13) { e.target.click(); } }); if ( form ) { // hide frequency options for some countries if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) !== -1 ) { $('#frequency_onetime').prop('checked', true); $('.frequency-options, #cancel-monthly, #donate-recurring-smallprint').hide(); } if ( donationForm.noRecurringPaypalCountries.indexOf( donationForm.country ) !== -1 ) { $( '.paymentmethod-pp, .paymentmethod-pp-usd' ).addClass( 'not-monthly-capable' ); } // Format amounts on buttons $( '.amount-options li' ).each( function( index ) { let amount = this.querySelector( 'input' ).value; if ( amount !== 'Other' ) { this.querySelector( 'label' ).innerText = donationForm.formatCurrency( amount ); } }); addCardTypesClass( donationForm.country ); // Only show Amazon for links from Ways to give if ( mw.util.getParamValue( 'wmf_source' ) === 'Waystogive' || mw.util.getParamValue( 'wmf_source' ) === 'Ways_to_Give' ) { $('.paymentmethod-amazon').show(); } // Apple Pay if ( $('.paymentmethod-applepay').length > 0 ) { if ( !donationForm.shouldShowApplePay( donationForm.country ) ) { $('.paymentmethod-applepay').remove(); } } // Venmo browser check if ( $('.paymentmethod-venmo').length > 0 ) { if ( !donationForm.isVenmoSupported() || donationForm.country !== 'US' ) { $('.paymentmethod-venmo').remove(); } } // Dumb hack to remove ACH for Portal test against Fundraise Up if ( mw.util.getParamValue( 'wmf_source' ) === 'portalBanner_en6C_2024_overlayBanner4WikiForm' ) { $('.paymentmethod-ach').remove(); } } // Links open in new tab $('.links-in-new-tab a').attr('target', '_blank'); // Disable logo link $('#p-logo a').attr( { href: '#', title: '' } ); // These don't need to be tabbable on the landing page $('#searchInput, .mw-jump-link').attr('tabindex', '-1'); $('.input_amount_other').click(function() { $('#input_amount_other_box').focus(); }); // Allow preselecting frequency if possible if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) === -1 && mw.util.getParamValue( 'utm_medium' ) !== 'endowment' && mw.util.getParamValue( 'wmf_medium' ) !== 'endowment' ) { if ( mw.util.getParamValue( 'frequency' ) ) { donationForm.setFrequency( mw.util.getParamValue( 'frequency' ) ); } else if ( mw.util.getParamValue('monthly') && mw.util.getParamValue('monthly') !== '0' ) { // old method with "monthly=" parameter donationForm.setFrequency( 'monthly' ); } else { donationForm.setFrequency( 'onetime' ); } } donationForm.initOptin(); try { adjustHPC(); preSelect(); // Make sure to do this *after* other fiddling with values donationForm.localizeErrors(); } finally { $('.frb-monthly-pitch, .frb-monthly-pitch-thanks').appendTo('.frequency-options'); $('.ptf').appendTo('.amount-options'); $('.optin-options').insertAfter('.amount-options'); $('.consider-amounts').show(); $('#actual-form').show(); $('#actual-form-loading').hide(); } }); }); s3ya8vmvty1cy5v6vb0r3cw9ekkei5d 40755 40754 2024-12-11T11:47:30Z Pcoombe 5 base64 decode recipient_id if needed 40755 javascript text/javascript /* jshint strict:false */ /** MediaWiki:DonationForm.js - loaded on all donation forms * TODO: lots of cleanup */ var donationForm = {}; donationForm.loadedTime = Date.now(); donationForm.extraData = {}; donationForm.country = mw.util.getParamValue('country').toUpperCase(); try { donationForm.currency = document.forms.donateForm.currency_code.value; } catch (error) { donationForm.currency = 'USD'; } /** * Make language and country into a standard javascript Intl locale identifier * * @param {string} language * @param {string} country * @return {string} locale identifier e.g. en-GB */ donationForm.getLocale = function( language, country ) { // Sometimes in email testing links the uselang is a variable contiaining % // In that case fall back to English so locale code doesn't break form if ( language.match('%') ) { language = 'en'; } // MediaWiki allows some language codes like en-gb, en-ca, pt-br // We don't want these for a javascript locale, so drop anything after '-' language = language.split('-')[0]; return language + '-' + country; }; donationForm.locale = donationForm.getLocale( mw.config.get('wgPageContentLanguage'), donationForm.country ); // Don't offer recurring at all in these countries donationForm.noRecurringCountries = [ 'AR', 'IN' ]; donationForm.noRecurringPaypalCountries = [ 'CL', 'CO', 'PE', 'UY', 'BR' ]; donationForm.currencyRates = { // From https://github.com/wikimedia/wikimedia-fundraising-SmashPig/blob/master/PaymentData/ReferenceData/CurrencyRates.php // Updated 2024-07-31 'ADF' : 6.04, 'ADP' : 153, 'AED' : 3.67, 'AFA' : 70, 'AFN' : 70, 'ALL' : 90, 'AMD' : 368, 'ANG' : 1.79, 'AOA' : 844, 'AON' : 844, 'ARS' : 887, 'ATS' : 13, 'AUD' : 1.5, 'AWG' : 1.79, 'AZM' : 8500, 'AZN' : 1.7, 'BAM' : 1.8, 'BBD' : 2, 'BDT' : 116, 'BEF' : 37, 'BGL' : 1.8, 'BGN' : 1.8, 'BHD' : 0.37355757356689, 'BIF' : 2842, 'BMD' : 1, 'BND' : 1.35, 'BOB' : 6.71, 'BRL' : 5.1, 'BSD' : 1, 'BTN' : 83, 'BWP' : 13, 'BYR' : 32642, 'BZD' : 1.98, 'CAD' : 1.36, 'CDF' : 2786, 'CHF' : 0.9094629289448, 'CLP' : 890, 'CNY' : 7.23, 'COP' : 3803, 'CRC' : 498, 'CUC' : 1, 'CUP' : 25, 'CVE' : 101, 'CYP' : 0.53848627984321, 'CZK' : 23, 'DEM' : 1.8, 'DJF' : 178, 'DKK' : 6.86, 'DOP' : 58, 'DZD' : 133, 'ECS' : 24094, 'EEK' : 14, 'EGP' : 47, 'ESP' : 153, 'ETB' : 57, 'EUR' : 0.92005843390143, 'FIM' : 5.47, 'FJD' : 2.23, 'FKP' : 0.78703952551207, 'FRF' : 6.04, 'GBP' : 0.78703952551207, 'GEL' : 2.71, 'GHC' : 143125, 'GHS' : 14, 'GIP' : 0.78703952551207, 'GMD' : 68, 'GNF' : 8493, 'GRD' : 314, 'GTQ' : 7.57, 'GYD' : 200, 'HKD' : 7.8, 'HNL' : 24, 'HRK' : 6.93, 'HTG' : 132, 'HUF' : 355, 'IDR' : 15986, 'IEP' : 0.72460490043714, 'ILS' : 3.69, 'INR' : 83, 'IQD' : 1290, 'IRR' : 42009, 'ISK' : 138, 'ITL' : 1781, 'JMD' : 154, 'JOD' : 0.70900000000001, 'JPY' : 156, 'KES' : 130, 'KGS' : 88, 'KHR' : 3993, 'KMF' : 453, 'KPW' : 135, 'KRW' : 1358, 'KWD' : 0.30629670764681, 'KYD' : 0.83333299999999, 'KZT' : 442, 'LAK' : 21103, 'LBP' : 89393, 'LKR' : 298, 'LRD' : 193, 'LSL' : 18, 'LTL' : 3.18, 'LUF' : 37, 'LVL' : 0.64662074757963, 'LYD' : 4.8, 'MAD' : 9.79, 'MDL' : 17, 'MGA' : 4379, 'MGF' : 9150, 'MKD' : 56, 'MMK' : 2075, 'MNT' : 2620, 'MOP' : 8.03, 'MRO' : 391, 'MTL' : 0.39498108567387, 'MUR' : 45, 'MVR' : 15, 'MWK' : 1720, 'MXN' : 17, 'MYR' : 4.68, 'MZM' : 63200, 'MZN' : 63, 'NAD' : 18, 'NGN' : 1505, 'NIO' : 36, 'NLG' : 2.03, 'NOK' : 11, 'NPR' : 131, 'NZD' : 1.63, 'OMR' : 0.38377594841305, 'PAB' : 1, 'PEN' : 3.67, 'PGK' : 3.76, 'PHP' : 58, 'PKR' : 277, 'PLN' : 3.91, 'PTE' : 184, 'PYG' : 7355, 'QAR' : 3.56, 'ROL' : 45713, 'RON' : 4.57, 'RSD' : 108, 'RUB' : 91, 'RWF' : 1277, 'SAR' : 3.75, 'SBD' : 8.37, 'SCR' : 13, 'SDD' : 59800, 'SDG' : 598, 'SDP' : 2261, 'SEK' : 11, 'SGD' : 1.35, 'SHP' : 0.78703952551207, 'SIT' : 220, 'SKK' : 28, 'SLL' : 19750, 'SOS' : 549, 'SRD' : 33, 'SRG' : 33320, 'STD' : 22477, 'SVC' : 8.75, 'SYP' : 513, 'SZL' : 18, 'THB' : 36, 'TJS' : 11, 'TMM' : 16750, 'TMT' : 3.35, 'TND' : 3.11, 'TOP' : 2.32, 'TRL' : 32168418, 'TRY' : 32, 'TTD' : 6.64, 'TWD' : 32, 'TZS' : 2587, 'UAH' : 39, 'UGX' : 3760, 'USD' : 1, 'UYU' : 38, 'UZS' : 12662, 'VEB' : 3651907631, 'VEF' : 3651908, 'VND' : 25451, 'VUV' : 112, 'WST' : 2.67, 'XAF' : 604, 'XAG' : 0.031347411860134, 'XAU' : 0.00041128929241299, 'XCD' : 2.7, 'XEU' : 0.92005843390143, 'XOF' : 604, 'XPD' : 0.00098009826645798, 'XPF' : 110, 'XPT' : 0.00093444018680404, 'YER' : 249, 'YUN' : 108, 'ZAR' : 18, 'ZMK' : 5176, 'ZWD' : 373 }; /* Amount and currency formatting */ let formatters = { // Amounts without currency symbol amountFraction: new Intl.NumberFormat( donationForm.locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 } ), amountWhole: new Intl.NumberFormat( donationForm.locale, {} ) }; // currencyDisplay: 'narrowSymbol' fixes some issues like en-CO showing the ISO code // but browser support is lacking, so wrap in a try/catch try { formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol' } ); formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, currencyDisplay: 'narrowSymbol', minimumFractionDigits: 0 } ); } catch(e) { formatters.currencyFraction = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency } ); formatters.currencyWhole = new Intl.NumberFormat( donationForm.locale, { style: 'currency', currency: donationForm.currency, minimumFractionDigits: 0 } ); } donationForm.formatCurrency = function( amount ) { if ( amount % 1 !== 0 ) { // Not a whole number return formatters.currencyFraction.format( amount ); } else { return formatters.currencyWhole.format( amount ); } }; donationForm.formatAmount = function( amount ) { var formatterOptions, output; if ( amount % 1 !== 0 ) { // Not a whole number return formatters.amountFraction.format( amount ); } else { return formatters.amountWhole.format( amount ); } }; /* Localize the amount errors. Call when initialising form. */ donationForm.localizeErrors = function() { var currency = donationForm.currency; $('.lp-error-smallamount').text( function( index, oldText ) { return oldText.replace( '$1', donationForm.formatAmount( donationForm.minLocal ) + '\xa0' + currency ); }); if ( currency === 'USD' ) { // we don't need to include the conversion $('.lp-error-bigamount').text( function( index, oldText ) { return oldText.replace( '($1 $2) ', '' ) .replace( '($1&nbsp;$2) ', '' ); }); } $('.lp-error-bigamount').text( function( index, oldText ) { return oldText.replace( '$1', donationForm.formatAmount( donationForm.maxLocal ) ) .replace( '$2', currency ) .replace( '$3', 'benefactors@wikimedia.org' ) .replace( '$4', donationForm.formatAmount( donationForm.maxUSD ) ); }); }; function adjustHPC() { /* Adjust amounts based on highest previous contribution (hpc) or most recent contribution (mrc) parameter. Used for emails. TODO: split data out? */ var hpcSet = mw.util.getParamValue('hpcSet'); // Look for 'hpc' parameter, then 'mrc' var hpc = parseFloat( mw.util.getParamValue('hpc') ); if( isNaN(hpc) ) { hpc = parseFloat( mw.util.getParamValue('mrc') ); if( isNaN(hpc) ) { if ( hpcSet ) { // Allow using hpcSet even without hpc, for MG appeals hpc = 0; } else { return; } } } var currency = donationForm.currency; // If changing, please update https://docs.google.com/spreadsheets/d/1e02TsZ_bKDAS1BMVBCdyo9D7RGln_wCGnkg7IF5kU5s/edit var radioAmountsData = { "USD" : { // also used for CAD, AUD, NZD "default" : [ [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_USD" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_USD" : [ // Upgrade recurring amount dynamically [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2.75, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 3.50, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3.75, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4.50, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6.75, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15.75, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 24.75, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 44.75, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_USD" : [ // Give less reactivation amount [ 0, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.75, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ], // Direct Mail - fixed amounts "directmail" : [ [ 0, [ 25, 35, 50, 100, 150, 250, 300 ] ] ], "directmail250" : [ [ 0, [ 250, 300, 500, 750, 1000, 2500, 5000 ] ] ] }, "EUR" : { "default" : [ [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_EUR" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_EUR" : [ // Upgrade recurring amount dynamically [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2.50, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 2.50, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3.50, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4.25, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6.25, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 25, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 45, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 50, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 150, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 250, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 500, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_EUR" : [ // Give less reactivation amount [ 0, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2.50, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ] }, "GBP" : { "default" : [ [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T11_GBP" : [ // Upgrade recurring +1 for lowest ask [ 0, [ 3, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 10, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 15, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 20, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 25, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 35, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 50, [ 50, 75, 100, 200, 300, 500, 750 ] ], [ 75, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 100, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 150, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 200, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 500, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 1000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ], [ 3000, [ 3000, 4000, 5000, 6000, 7500, 10000, 12000 ] ] ], "FY2425_E1_T14_GBP" : [ // Upgrade recurring amount dynamically [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 2, 10, 15, 20, 25, 35, 50 ] ], [ 15, [ 2, 10, 20, 30, 50, 75, 100 ] ], [ 20, [ 3, 10, 25, 35, 50, 75, 100 ] ], [ 25, [ 4, 10, 25, 35, 50, 75, 100 ] ], [ 35, [ 6, 15, 30, 50, 75, 100, 150 ] ], [ 75, [ 15, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 20, 50, 75, 100, 200, 300, 500 ] ], [ 150, [ 40, 100, 150, 250, 500, 750, 1000 ] ], [ 200, [ 45, 100, 150, 250, 500, 750, 1000 ] ], [ 500, [ 125, 250, 300, 500, 750, 1000, 2000 ] ], [ 1000, [ 200, 500, 750, 1000, 2500, 5000, 10000 ] ], [ 3000, [ 400, 1000, 2000, 3500, 5000, 7500, 10000 ] ] ], "FY2425_E1_T21_GBP" : [ // Give less reactivation amount [ 0, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 5, [ 2, 5, 10, 20, 25, 35, 50 ] ], [ 10, [ 5, 10, 15, 20, 35, 50, 100 ] ], [ 15, [ 10, 15, 20, 25, 35, 50, 100 ] ], [ 20, [ 15, 20, 25, 35, 50, 75, 100 ] ], [ 25, [ 20, 25, 35, 50, 75, 100, 150 ] ], [ 35, [ 25, 30, 40, 50, 75, 100, 150 ] ], [ 75, [ 35, 50, 75, 100, 200, 300, 500 ] ], [ 100, [ 75, 100, 150, 250, 500, 750, 1000 ] ], [ 150, [ 100, 150, 250, 500, 750, 1000, 2500 ] ], [ 200, [ 150, 200, 300, 500, 750, 1000, 2000 ] ], [ 500, [ 200, 300, 500, 750, 1000, 2500, 5000 ] ], [ 1000, [ 500, 750, 1000, 2500, 5000, 7500, 10000 ] ], [ 3000, [ 1000, 2000, 3000, 4000, 5000, 7500, 10000 ] ] ] }, "JPY" : [ [ 0, [ 500, 1000, 2000, 2500, 4000, 5000, 10000 ] ], [ 1000, [ 1000, 1500, 2500, 4000, 5000, 10000, 15000 ] ], [ 1500, [ 1500, 2000, 3000, 4000, 5000, 10000, 15000 ] ], [ 2000, [ 2000, 2500, 3500, 5000, 7500, 10000, 25000 ] ], [ 2500, [ 2500, 3500, 5000, 7500, 10000, 15000, 25000 ] ], [ 3000, [ 3000, 4000, 5000, 7500, 10000, 15000, 25000 ] ], [ 2500, [ 2500, 5000, 7500, 10000, 20000, 30000, 50000 ] ], [ 2500, [ 2500, 5000, 7500, 10000, 20000, 50000, 100000 ] ], [ 5000, [ 5000, 10000, 15000, 20000, 35000, 50000, 100000 ] ], [ 10000, [ 10000, 25000, 50000, 75000, 100000, 150000, 200000 ] ] ], "SEK" : [ [ 0, [ 30, 100, 150, 200, 500, 750, 1000 ] ], [ 50, [ 50, 100, 150, 200, 300, 750, 1000 ] ], [ 200, [ 50, 100, 200, 300, 500, 750, 1000 ] ] ] }; radioAmountsData.AUD = radioAmountsData.USD; radioAmountsData.CAD = radioAmountsData.USD; radioAmountsData.NZD = radioAmountsData.USD; // Major gifts appeals, hacky but this is easier than adding a load of new forms to maintain var currencyList = [ 'USD', 'CAD', 'AUD', 'NZD', 'GBP', 'EUR' ]; // close enough for ( let i = 0; i < currencyList.length; i++ ) { radioAmountsData[ currencyList[i] ].MG_2024_500 = [ [ 0, [ 500, 750, 1000, 1250, 1500, 1750, 2000 ] ] ]; radioAmountsData[ currencyList[i] ].MG_2024_650 = [ [ 0, [ 650, 750, 1000, 1250, 1500, 1750, 2000 ] ] ]; } var appealAmountsData = { "USD" : [ // also used for CAD, AUD, NZD, GBP, EUR [ 0, [ 5, 10, 20 ] ], [ 10, [ 10, 20, 50 ] ], [ 20, [ 20, 30, 50 ] ], [ 35, [ 20, 30, 50 ] ], [ 50, [ 20, 50, 100 ] ], [ 75, [ 50, 75, 100 ] ], [ 100, [ 75, 100, 150 ] ], [ 150, [ 75, 100, 200 ] ], [ 200, [ 100, 200, 300 ] ] ], "JPY" : [ [ 0, [ 300, 500, 1000 ] ], [ 3, [ 500, 1000, 1500 ] ], [ 5, [ 1000, 1500, 2000 ] ], [ 10, [ 1500, 2000, 5000 ] ], [ 20, [ 2000, 3000, 5000 ] ], [ 50, [ 2000, 5000, 10000 ] ], [ 100, [ 5000, 10000, 15000 ] ] ], "SEK" : [ [ 0, [ 20, 50, 100 ] ], [ 3, [ 30, 50, 100 ] ], [ 5, [ 50, 100, 150 ] ], [ 15, [ 100, 150, 200 ] ], [ 23, [ 100, 200, 300 ] ], [ 38, [ 100, 200, 500 ] ], [ 75, [ 100, 500, 750 ] ], [ 112, [ 100, 500, 1000 ] ] ] }; appealAmountsData.AUD = appealAmountsData.USD; appealAmountsData.CAD = appealAmountsData.USD; appealAmountsData.GBP = appealAmountsData.USD; appealAmountsData.NZD = appealAmountsData.USD; appealAmountsData.EUR = appealAmountsData.USD; // Radio button amounts var radioAmounts = pickAmountArray( radioAmountsData, currency, hpc, hpcSet ); if ( radioAmounts.length ) { // Change buttons for (var j = 0; j < radioAmounts.length; j++) { var $radio = $("#input_amount_" + j); var $label = $("label[for='input_amount_" + j + "']"); $radio.val( radioAmounts[j] ); $label.text( donationForm.formatCurrency( radioAmounts[j] ) ); } } // Appeal amounts var appealAmounts = pickAmountArray( appealAmountsData, currency, hpc, hpcSet ); if ( appealAmounts.length ) { var appealAmountString = appealAmounts.map( donationForm.formatCurrency ).join( ', '); $('.consider-amounts').html(appealAmountString); } } function pickAmountArray( data, currency, hpc, hpcSet ) { /** * Choose the amounts for radio buttons / appeal based on hpc * @param {Object} data * @param {String} currency * @param {Number} hpc * @param {String} hpcSet * @return {Array} Array of amounts (as numbers) */ var set, amounts; if ( !(currency in data) ) { return []; } if ( $.isArray(data[currency]) ) { // No variant sets set = data[currency]; } else { // We need to go deeper. Check the variants. if ( hpcSet in data[currency] ) { set = data[currency][hpcSet]; } else { set = data[currency]['default']; } } // Find correct amount array for this hpc for (var i = 0; i < set.length; i++) { if ( set[i][0] > hpc ) { break; } amounts = set[i][1]; } return amounts; } function preSelect() { /* Check for a 'preSelect' url parameter, and select that option. If there isn't an option, add it to the "Other" box and select that */ var preSelectAmount = parseFloat( mw.util.getParamValue('preSelect') ); if ( preSelectAmount > 0 ) { var $preSelectOption = $('input[name="amount"][value="' + preSelectAmount + '"]'); if ( $preSelectOption.length ) { // Select existing input $preSelectOption.prop('checked', true); } else { $('#input_amount_other_box').val( preSelectAmount ); $('#input_amount_other').prop('checked', true); } donationForm.updateFeeDisplay(); } } function addCardTypesClass(country) { /** * Add card types class to credit card button, so we can show correct logos * Banner equivalent: https://meta.wikimedia.org/wiki/MediaWiki:FundraisingBanners/LocalizeJS-2017.js * @param {String} country ISO code */ var cardTypes = { // Big 6 'US' : 'vmad', 'CA' : 'vma', 'GB' : 'vmaj', 'IE' : 'vmaj', 'AU' : 'vmaj', 'NZ' : 'vma', // Euro countries 'AT' : 'vmaj', 'BE' : 'vmaj', 'ES' : 'vmaj', 'FR' : 'vma', // Adyen - Carte Bancaire was removed 'IT' : 'vmaj', 'LU' : 'vmaj', 'LV' : 'vma', 'NL' : 'vmaj', 'PT' : 'vmaj', 'SK' : 'vmaj', 'GR' : 'vma', // Others 'CZ' : 'vmad', 'DK' : 'vma', 'HU' : 'vma', 'IL' : 'vmad', // Adyen 'JP' : 'vmaj', 'MY' : 'vmaj', 'NO' : 'vma', 'PL' : 'vma', 'RO' : 'vma', 'SE' : 'vma', 'UA' : 'vma', // Adyen 'ZA' : 'vm', 'ZZ' : 'vmad' // For testing }; if ( cardTypes[country] ) { $('.paymentmethod-cc').addClass('cctypes-' + cardTypes[country] ); $('.cc-text-label').addClass('sr-only'); } } /* Form functions */ function clearOther(box) { document.getElementById('input_amount_other').checked = true; box.value = ""; } function selectOther() { document.getElementById('input_amount_other').checked = true; } function selectAmount() { $('#input_amount_other_box').val(''); } /* -- Moved from Template:2012FR/Form-section/Processing/Default -- */ /** * Validate form, and prep most of the parameters * * @param {string} paymentMethod - method e.g. 'cc', 'paypal' * @param {string} paymentSubMethod - submethod e.g. 'rtbt_ideal' (a submethod of 'rtbt') * @param {string} skipAmountValidation - skip validating amount for PayPal forced to USD */ donationForm.redirectPayment = function( paymentMethod, paymentSubMethod, skipAmountValidation ) { if ( donationForm.validate( skipAmountValidation ) ) { var params = {}; params.currency = donationForm.currency; params.country = donationForm.country; // Overrides for specific cc gateways if ( paymentMethod === 'cc-adyen' ) { params.payment_method = 'cc'; params.gateway = 'adyen'; } else if ( paymentMethod === 'cc-dlocal' ) { params.payment_method = 'cc'; params.gateway = 'astropay'; } else { params.payment_method = paymentMethod; } if ( params.payment_method === 'cc' && params.country === 'ZA' ) { params.gateway = 'astropay'; } if ( paymentSubMethod ) { params.payment_submethod = paymentSubMethod; } let frequency = donationForm.getFrequency(); if ( frequency === 'monthly' ) { params.recurring = '1'; params.frequency_unit = 'month'; } else if ( frequency === 'annual' ) { params.recurring = '1'; params.frequency_unit = 'year'; } params.uselang = mw.config.get('wgPageContentLanguage'); // see T281285 for why not wgUserLanguage if ( params.uselang === 'pt' && params.country === 'BR' ) { params.uselang = 'pt-br'; } if ( params.uselang === 'es' && ( params.country === 'AR' || params.country === 'CL' || params.country === 'CO' || params.country === 'MX' || params.country === 'PE' || params.country === 'UY' || params.country === 'US' ) ) { params.uselang = 'es-419'; } var amount = donationForm.getAmount(); if ( $('#ptf-checkbox').prop('checked') ) { amount = amount + donationForm.calculateFee( amount ); donationForm.extraData.ptf = 1; } params.amount = amount; // Email optin if ( $('input[name="opt_in"]').length > 0 ) { var opt_inValue = $('input[name="opt_in"]:checked').val(); params.opt_in = opt_inValue; // donationForm.validate() already checked it's 1 or 0 } if ( mw.util.getParamValue( 'pym_variant' ) ) { params.variant = mw.util.getParamValue( 'pym_variant' ); } if ( params.recurring && params.variant && params.variant.match( /monthlyConvert/ ) ) { // Post-payments monthly convert makes no sense if it's already recurring // Avoid things like T312905 delete params.variant; } // TODO: refactor this to a list of parameters to pass unchanged // or just pass everything by default? if ( mw.util.getParamValue( 'pym_appeal' ) ) { params.appeal = mw.util.getParamValue( 'pym_appeal' ); } // https://phabricator.wikimedia.org/T381405 if ( mw.util.getParamValue( 'contact_id' ) ) { params.contact_id = mw.util.getParamValue( 'contact_id' ); } if ( mw.util.getParamValue( 'contact_hash' ) ) { params.contact_hash = mw.util.getParamValue( 'contact_hash' ); } // SMS var recipient_id = mw.util.getParamValue( 'recipient_id' ); if ( recipient_id ) { if ( isNaN( parseFloat( recipient_id ) ) ) { // Lop off last 2 characters and decode base64 params.recipient_id = atob( recipient_id.slice(0, -2) ); } else { params.recipient_id = recipient_id; } } // Monthly convert if ( mc ) { // check just in-case this wasn't loaded for some reason mc.main( params, donationForm.finalStep ); } else { donationForm.finalStep( params ); } } else { donationForm.extraData.validateError = 1; // Flag they had an error, even if fixed later } return false; // don't submit if called by a button }; /** * Build final tracking parameters, and submit to payments * @param {Object} params */ donationForm.finalStep = function( params ) { var url = new URL('https://payments.wikimedia.org/index.php/Special:GatewayChooser'); // Skip form chooser for Apple Pay / Google Pay if ( params.payment_method === 'apple' || params.payment_method === 'google' ) { url = new URL('https://payments.wikimedia.org/index.php/Special:AdyenCheckoutGateway'); } // Skip form chooser for Venmo if ( params.payment_method === 'venmo' ) { url = new URL('https://payments.wikimedia.org/index.php/Special:BraintreeGateway'); } donationForm.extraData.time = Math.round( (Date.now() - donationForm.loadedTime)/1000 ); // Tracking data params.wmf_medium = mw.util.getParamValue( 'wmf_medium' ) || mw.util.getParamValue( 'utm_medium' ); params.wmf_campaign = mw.util.getParamValue( 'wmf_campaign' ) || mw.util.getParamValue( 'utm_campaign' ); params.wmf_source = donationForm.buildTrackingSource( params ); params.wmf_key = donationForm.buildTrackingKey( donationForm.extraData ); if ( document.referrer ) { // TODO: do we need this? // Strip protocol to stop firewall complaining params.referrer = document.referrer.replace(/https?:\/\//i, ''); } for ( var key of Object.keys( params ) ) { url.searchParams.set( key, params[key] ); } if ( window.top !== window.self ) { // In a frame, open payments in a new tab window.open( url.toString() ); } else { window.location.href = url.toString(); } }; /** * Build a wmf_source value, including the landing page info. * * Own function so it can be overriden for weird tests * * @param {Object} params * @return {string} wmf_source */ donationForm.buildTrackingSource = function( params ) { var wmf_source = mw.util.getParamValue( 'wmf_source' ) || mw.util.getParamValue( 'utm_source' ); wmf_source += '.'; var fullDottedPaymentMethod = params.payment_method; if ( params.recurring ) { fullDottedPaymentMethod = 'r' + fullDottedPaymentMethod; } if ( params.payment_submethod ) { fullDottedPaymentMethod = fullDottedPaymentMethod + '.' + params.payment_submethod; } /* Get URL parameter, but remove parts using old format. Allow fallback to a default value */ var getParam = function( param, removeText, dflt ) { if ( mw.util.getParamValue( param ) ) { return mw.util.getParamValue( param ).replace( removeText, '' ); } else { return dflt; } }; /* The landing page info, separated by ~. This mostly exists for legacy reasons */ wmf_source += getParam( 'template' , 'Lp-layout' , 'default' ) + '~'; wmf_source += getParam( 'appeal-template' , 'Appeal-template-' , 'default' ) + '~'; wmf_source += getParam( 'appeal' , 'Appeal-' , 'default' ) + '~'; wmf_source += getParam( 'form-template' , 'Form-template-' , 'default' ) + '~'; wmf_source += getParam( 'form-countryspecific', 'Form-countryspecific-', 'control' ); wmf_source += '.' + fullDottedPaymentMethod; return wmf_source; }; /** * Build a string for wmf_key from extra tracking data * * @param {Object} data * @return {string} wmf_key */ donationForm.buildTrackingKey = function(data) { var existingKey = mw.util.getParamValue( 'wmf_key' ) || mw.util.getParamValue( 'utm_key' ), dataArray = []; if ( existingKey ) { dataArray.push( existingKey ); } for (var key in data) { if (data.hasOwnProperty(key)) { dataArray.push( key + '_' + data[key] ); } } return dataArray.join('~'); }; /* Return amount selected or input */ donationForm.getAmount = function() { var form = document.forms.donateForm, amount = null; donationForm.extraData.otherAmt = 0; // If there are some amount radio buttons, then look for the checked one if ( form.amount ) { for ( var i = 0; i < form.amount.length; i++ ) { if ( form.amount[i].checked ) { amount = parseFloat( form.amount[i].value ); } } } // Check the "other" amount box if ( document.getElementById('input_amount_other').checked ) { amount = donationForm.parseOtherAmount( form.input_amount_other_box.value ); donationForm.extraData.otherAmt = 1; } return amount; }; /** * Parse Other field value into amount * * Does some awful regex stuff to rm symbols and turn the string into a number * Remember some locales flip . & , for decimal point/thousands separator * * @param {string} value Value of "Other" field * @return {float} Float with amount, or 0 if NaN */ donationForm.parseOtherAmount = function( value ) { var amount; value = value.replace(/[,.](\d)$/, '\:$10'); value = value.replace(/[,.](\d)(\d)$/, '\:$1$2'); value = value.replace(/[\$£€¥,.]/g, ''); value = value.replace(/:/, '.'); amount = parseFloat( value ); if ( isNaN( amount ) ) { return 0; } else { return amount; } }; /** * Validate the form. */ donationForm.validate = function( skipAmountValidation ) { var error = false; var form = document.forms.donateForm; // Reset all errors $('.lp-haserror').removeClass('lp-haserror'); $('.lp-error').hide(); if ( !skipAmountValidation && !donationForm.validateAmount() ) { error = true; } if ( form.opt_in ) { if ( $('input[name="opt_in"]:checked').val() === undefined ) { $('#error-optin').show().focus(); error = true; } else { $('#error-optin').hide(); } } return !error; }; /** * Check if selected amount is valid i.e. a positive number, between minimum and maximum. * If not, show an error and return false. */ donationForm.validateAmount = function() { var amount = donationForm.getAmount(); if ( amount === null || isNaN(amount) || amount <= 0 || amount < donationForm.minLocal ) { $('.amount-options').addClass('lp-haserror'); $('.lp-error-bigamount').hide(); $('.lp-error-smallamount').show().focus(); return false; } else if ( amount > donationForm.maxLocal ) { $('.amount-options').addClass('lp-haserror'); $('.lp-error-bigamount').show().focus(); return false; } else { $('.amount-options').removeClass('lp-haserror'); $('.lp-error-smallamount, .lp-error-bigamount').hide(); return true; } }; donationForm.getFrequency = function() { return document.forms.donateForm.dataset.frequency || 'onetime'; }; donationForm.setFrequency = function( frequency ) { // TODO: add some validation to reject invalid frequency values let form = document.forms.donateForm; form.frequency.value = frequency; // change input form.dataset.frequency = frequency; }; /* Wrapper for compatibility with old forms */ donationForm.toggleMonthly = function( monthly ) { if ( monthly ) { donationForm.setFrequency( 'monthly' ); } else { donationForm.setFrequency( 'onetime' ); } }; donationForm.updateFeeDisplay = function() { var selectedAmount = donationForm.getAmount(), feeAmount = donationForm.calculateFee( selectedAmount ), feeText; feeText = donationForm.formatCurrency( feeAmount ); $('.ptf label span').text( feeText ); if ( selectedAmount + feeAmount <= donationForm.maxLocal ) { $('.ptf').slideDown(); } }; /** * Calculate approximate transaction fee on given amount * @param {number} amount * @return {number} Rounded to 2 decimal places */ donationForm.calculateFee = function( amount ) { // Minimum fee/PTF amounts. Default is 0.35. // Updated 2019-05-21 to approx 0.35 USD equivalent var feeMinimums = { 'DKK' : 2, 'HUF' : 100, 'ILS' : 1.2, 'INR' : 4, 'JPY' : 35, 'MYR' : 1, 'NOK' : 3, 'PLN' : 1.35, 'CZK' : 7.5, 'RON' : 1.5, 'SEK' : 3, 'UAH' : 10, 'ZAR' : 5, // Latin America // Updated 2024-08-22 to approx 0.35 USD equivalent 'BRL' : 1.75, 'ARS' : 300, 'CLP' : 300, 'COP' : 1400, 'MXN' : 6, 'PEN' : 1.2, 'UYU' : 14 }; var feeMultiplier = 0.04, feeMinimum = feeMinimums[ donationForm.currency ] || 0.35, feeAmount = amount * feeMultiplier; if ( feeAmount < feeMinimum ) { feeAmount = feeMinimum; } return parseFloat( feeAmount.toFixed(2) ); }; donationForm.initOptin = function() { $('.optin-options').on('change', function(e) { $('#error-optin').hide(); // Only do all this if we have translated prompts if ( $('.optin-no-prompt').data('is-translated') === 'yes' ) { if ( e.target.id === 'optin-no' ) { $('.optin-no-prompt').removeClass('is-positive'); if ( !$('.optin-no-prompt').is(':visible') ) { $('.optin-no-prompt').slideDown(); } } else { $('.optin-no-prompt').addClass('is-positive'); } } }); }; /** * Block typing letters and symbols in given input. Used for Other amount inputs * * If we don't do this, Safari allows typing them and then chokes on submit * https://phabricator.wikimedia.org/T118741, https://phabricator.wikimedia.org/T173431 * * @param {Element} inputElement The element to block typing on */ donationForm.otherInputControl = function( inputElement ) { if ( inputElement ) { inputElement.onkeypress = function(e) { // Allow special keys in Firefox if ((e.code == 'ArrowLeft') || (e.code == 'ArrowRight') || (e.code == 'ArrowUp') || (e.code == 'ArrowDown') || (e.code == 'Delete') || (e.code == 'Backspace')) { return; } var chr = String.fromCharCode(e.which); if ('0123456789., '.indexOf(chr) === -1) { return false; } }; } }; /** * Should we show Apple Pay? * * Note there is a ~500ms delay in Safari when checking, so only call this if needed * * @param {string} country * @return {boolean} */ donationForm.shouldShowApplePay = function ( country ) { if ( location.search.match('forceApplePay') ) { return true; } if ( window.ApplePaySession ) { if ( ApplePaySession.canMakePayments() ) { return true; } } return false; }; /* Based on github:braintree/braintree-web/src/venmo/shared/supports-venmo.js See also on meta: MediaWiki:FundraisingBanners/VenmoBrowserCheck.js */ donationForm.isVenmoSupported = function(options) { var options = options || { allowNewBrowserTab: false, allowWebviews: true, allowDesktop: true, allowDesktopWebLogin: true }; var ua = window.navigator.userAgent; var merchantAllowsReturningToNewBrowserTab, merchantAllowsWebviews, merchantAllowsDesktopBrowsers; var isMobileDevice = isAndroid() || isIos(); var isAndroidChrome = isAndroid() && isChrome(); var isMobileDeviceThatSupportsReturnToSameTab = isIosSafari() || isAndroidChrome; var isKnownUnsupportedMobileBrowser = isIosChrome() || isFacebookOwnedBrowserOnAndroid() || isSamsung(); options = options || {}; // NEXT_MAJOR_VERSION allowDesktop will default to true, but can be opted out merchantAllowsDesktopBrowsers = (options.allowDesktopWebLogin || options.allowDesktop) === true; merchantAllowsReturningToNewBrowserTab = options.hasOwnProperty( "allowNewBrowserTab" ) ? options.allowNewBrowserTab : true; // NEXT_MAJOR_VERSION webviews are not supported, except for the case where // the merchant themselves is presenting venmo in a webview using the deep // link url to get back to their app. For the next major version, we should // just not have this option and instead require the merchant to determine // if the venmo button should be displayed when presenting it in the // merchant's app via a webview. merchantAllowsWebviews = options.hasOwnProperty("allowWebviews") ? options.allowWebviews : true; if (isKnownUnsupportedMobileBrowser) { return false; } if ( !merchantAllowsWebviews && (isAndroidWebview() || isIosWebview()) ) { return false; } if (!isMobileDevice) { return merchantAllowsDesktopBrowsers; } if (!merchantAllowsReturningToNewBrowserTab) { return isMobileDeviceThatSupportsReturnToSameTab; } return isMobileDevice; /* -- functions mostly from github:braintree/browser-detection library -- */ function isAndroid() { return /Android/i.test(ua); } function isIos(checkIpadOS = true) { const iOsTest = /iPhone|iPod|iPad/i.test(ua); return checkIpadOS ? iOsTest || isIpadOS() : iOsTest; } function isIpadOS() { // "ontouchend" is used to determine if a browser is on an iPad, otherwise // user-agents for iPadOS behave/identify as a desktop browser return /Mac|iPad/i.test(ua) && "ontouchend" in window.document; } function isEdge() { return ua.indexOf("Edge/") !== -1 || ua.indexOf("Edg/") !== -1; } function isSamsung() { return /SamsungBrowser/i.test(ua); } function isDuckDuckGo() { return ua.indexOf("DuckDuckGo/") !== -1; } function isOpera() { return ( ua.indexOf("OPR/") !== -1 || ua.indexOf("Opera/") !== -1 || ua.indexOf("OPT/") !== -1 ); } function isSilk() { return ua.indexOf("Silk/") !== -1; } function isChrome() { return ( (ua.indexOf("Chrome") !== -1 || ua.indexOf("CriOS") !== -1) && !isEdge() && !isSamsung() && !isDuckDuckGo() && !isOpera() && !isSilk() ); } function isIosFirefox() { return /FxiOS/i.test(ua); } function isWebkit() { const webkitRegexp = /webkit/i; return webkitRegexp.test(ua); } function isIosChrome() { return ua.indexOf("CriOS") > -1; } function isFacebook() { return ua.indexOf("FBAN") > -1; } function isIosSafari() { return ( isIos() && isWebkit() && !isIosChrome() && !isIosFirefox() && !isFacebook() ); } function isFacebookOwnedBrowserOnAndroid() { var e = ua.toLowerCase(); return -1 < e.indexOf("huawei") && -1 < e.indexOf("fban") || isAndroid() && (-1 < e.indexOf("fb_iab") || -1 < e.indexOf("instagram")); } function isSamsungBrowser() { return /SamsungBrowser/i.test(ua); } function isAndroidWebview() { return isAndroid() && -1 < ua.toLowerCase().indexOf("wv"); } function isGoogleSearchApp() { return /\bGSA\b/.test(ua); } function isIosGoogleSearchApp() { return isIos() && isGoogleSearchApp(); } function isIosWebview() { if (isIos()) { // The Google Search iOS app is technically a webview and doesn't support popups. if (isIosGoogleSearchApp()) { return true; } // Historically, a webview could be identified by the presence of AppleWebKit and _no_ presence of Safari after. return /.+AppleWebKit(?!.*Safari)/i.test(ua); } return false; } }; /* End form functions */ $(document).ready(function() { mw.loader.using( ['mediawiki.util'] ).done( function() { var form = document.forms.donateForm; // Minimum amount is usually about 1 USD donationForm.minLocal = donationForm.currencyRates[ donationForm.currency ]; donationForm.minLocal = Math.ceil( donationForm.minLocal * 100 ) / 100; // Round it up donationForm.maxUSD = 25000; donationForm.maxLocal = Math.floor( donationForm.currencyRates[ donationForm.currency ] * donationForm.maxUSD ); // Overrides for India if ( donationForm.currency === 'INR' ) { donationForm.minLocal = 10; // Until https://phabricator.wikimedia.org/T370583 fixed? donationForm.maxUSD = 3000; donationForm.maxLocal = 250000; } // Block typing symbols in Other field donationForm.otherInputControl( document.getElementById('input_amount_other_box') ); // Clear errors and update fee when selected/entered $('.amount-options').on( 'input change', function() { // Ideally we would validate the amount, but this causes issues with focus $('.amount-options .lp-error').hide(); donationForm.updateFeeDisplay(); }); // Disable submitting form with Enter key $('form[name="donateForm"]').on('keypress', function(e) { var code = ( e.keyCode ? e.keyCode : e.which ); if ( code == 13 ) { e.preventDefault(); } }); // But allow Enter on buttons $('.payment-method-button').keyup(function(e) { if (event.keyCode === 13) { e.target.click(); } }); if ( form ) { // hide frequency options for some countries if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) !== -1 ) { $('#frequency_onetime').prop('checked', true); $('.frequency-options, #cancel-monthly, #donate-recurring-smallprint').hide(); } if ( donationForm.noRecurringPaypalCountries.indexOf( donationForm.country ) !== -1 ) { $( '.paymentmethod-pp, .paymentmethod-pp-usd' ).addClass( 'not-monthly-capable' ); } // Format amounts on buttons $( '.amount-options li' ).each( function( index ) { let amount = this.querySelector( 'input' ).value; if ( amount !== 'Other' ) { this.querySelector( 'label' ).innerText = donationForm.formatCurrency( amount ); } }); addCardTypesClass( donationForm.country ); // Only show Amazon for links from Ways to give if ( mw.util.getParamValue( 'wmf_source' ) === 'Waystogive' || mw.util.getParamValue( 'wmf_source' ) === 'Ways_to_Give' ) { $('.paymentmethod-amazon').show(); } // Apple Pay if ( $('.paymentmethod-applepay').length > 0 ) { if ( !donationForm.shouldShowApplePay( donationForm.country ) ) { $('.paymentmethod-applepay').remove(); } } // Venmo browser check if ( $('.paymentmethod-venmo').length > 0 ) { if ( !donationForm.isVenmoSupported() || donationForm.country !== 'US' ) { $('.paymentmethod-venmo').remove(); } } // Dumb hack to remove ACH for Portal test against Fundraise Up if ( mw.util.getParamValue( 'wmf_source' ) === 'portalBanner_en6C_2024_overlayBanner4WikiForm' ) { $('.paymentmethod-ach').remove(); } } // Links open in new tab $('.links-in-new-tab a').attr('target', '_blank'); // Disable logo link $('#p-logo a').attr( { href: '#', title: '' } ); // These don't need to be tabbable on the landing page $('#searchInput, .mw-jump-link').attr('tabindex', '-1'); $('.input_amount_other').click(function() { $('#input_amount_other_box').focus(); }); // Allow preselecting frequency if possible if ( donationForm.noRecurringCountries.indexOf( donationForm.country ) === -1 && mw.util.getParamValue( 'utm_medium' ) !== 'endowment' && mw.util.getParamValue( 'wmf_medium' ) !== 'endowment' ) { if ( mw.util.getParamValue( 'frequency' ) ) { donationForm.setFrequency( mw.util.getParamValue( 'frequency' ) ); } else if ( mw.util.getParamValue('monthly') && mw.util.getParamValue('monthly') !== '0' ) { // old method with "monthly=" parameter donationForm.setFrequency( 'monthly' ); } else { donationForm.setFrequency( 'onetime' ); } } donationForm.initOptin(); try { adjustHPC(); preSelect(); // Make sure to do this *after* other fiddling with values donationForm.localizeErrors(); } finally { $('.frb-monthly-pitch, .frb-monthly-pitch-thanks').appendTo('.frequency-options'); $('.ptf').appendTo('.amount-options'); $('.optin-options').insertAfter('.amount-options'); $('.consider-amounts').show(); $('#actual-form').show(); $('#actual-form-loading').hide(); } }); }); pid4abnbnyh3egsghatgahi6plnd0wz File:WMF Donation Card.pdf 6 9794 40753 40582 2024-12-10T15:30:49Z RLopez-WMF 53 RLopez-WMF uploaded a new version of [[File:WMF Donation Card.pdf]] 40582 wikitext text/x-wiki phoiac9h4m842xq45sp7s6u21eteeq1