MediaWiki:Centralnotice-template-trilogy community 20190207
<style>
- mw-mf-page-center {
background-color: #fff;
}
/* Resets */ .cbnnr * {
margin: 0; padding: 0;
}
/* Box-sizing */ .cbnnr, .cbnnr *, .cbnnr *:before, .cbnnr *:after {
-moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
}
/* Font sizes and line heights */
.cbnnr-message {
font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif; font-weight: medium; font-size: 13px; line-height: 1.4; color: #555A5F !important; text-align: left;
}
.cbnnr-special .cbnnr-message {
color: #d9e0f5 !important;
}
.cbnnr-cta {
font-size: 15px; font-weight: bold; color: #222;
}
.cbnnr-special .cbnnr-cta {
color: white;
}
@media all and (min-width: 720px) {
.cbnnr-message { font-size: 18px; line-height: 1.5; } .cbnnr-cta { font-size: 20px; }
}
/* Styles */
.cbnnr {
background-color: #fff; position: relative; margin-bottom: 12px;
}
/* Hide banner when Wikipedia site search is enabled */ .overlay-enabled .cbnnr {
display: none !important;
}
.cbnnr-main {
position: relative; clear: both; padding: 10px; background-color: white; border-bottom: 1px solid #eee; height: 88px;
}
.cbnnr-special .cbnnr-main {
background-color: #4a67cc; border: none;
}
@media all and (min-width: 720px) {
.cbnnr-main { padding: 15px; height: 98px; }
}
@media all and (min-width: 1025px) {
.cbnnr-main { border: 1px solid #eee; border-top: none; }
}
.cbnnr-message {
display: block;
}
.cbnnr-icon {
width: 68px; height: 68px; border-radius: 2px; overflow: hidden; position: absolute; top: 10px; left: 10px; overflow: hidden; background: #fff;
}
@media all and (min-width: 720px) {
.cbnnr-icon { top: 15px; left: 15px; }
}
.cbnnr-icon-border {
border: 1px solid #eee;
}
.cbnnr-icon img {
max-width: 100%; max-height: 100%; position: absolute; top: 0; left: 0;
}
.cbnnr-icon-border img {
max-width: 80%; max-height: 80%; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%);
}
.cbnnr-message p {
padding-left: 78px; padding-right: 54px; padding-top: 5px; margin: auto;
}
@media all and (min-width: 720px) {
.cbnnr-message p { padding-left: 83px; padding-right: 64px; padding-top: 4px; }
}
.cbnnr-headline, .cbnnr-text {
display: block;
}
@media all and (min-width: 720px) {
.cbnnr-headline, .cbnnr-text { display: inline; } .cbnnr-headline:after { content: ' | '; }
}
.cbnnr-cta {
display: block; margin-top: 4px;
}
@media all and (min-width: 720px) {
.cbnnr-cta { margin-top: 2px; }
}
.cbnnr-cta:hover {
text-decoration: underline;
}
/* --- Close Options --- */
.cbnnr-close {
cursor: pointer; position: absolute; top: 50%; right: 10px; transform: translateY(-50%); z-index: 1; opacity: .8; background: #eaecf0; border-radius: 50%; padding: 12px; width: 44px; height: 44px; transition: all .3s ease-in-out;
}
.cbnnr-special .cbnnr-close {
background: rgba(255,255,255,.5); opacity: 1;
}
body.rtl .cbnnr-close {
left: 10px; right: unset;
}
@media all and (min-width: 720px) {
.cbnnr-close { right: 15px; } body.rtl .cbnnr-close { left: 15px; right: unset; }
}
.cbnnr-close:hover {
opacity: 1;
}
.cbnnr-special .cbnnr-close:hover {
background: rgba(255,255,255,.7);
}
.cbnnr-close-icon{
background: linear-gradient(transparent,transparent), url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2220%22 height=%2220%22 viewBox=%220 0 20 20%22%3E%3Ctitle%3Eclose%3C/title%3E%3Cpath d=%22M4.34 2.93l12.73 12.73-1.41 1.41L2.93 4.35z%22/%3E%3Cpath d=%22M17.07 4.34L4.34 17.07l-1.41-1.41L15.66 2.93z%22/%3E%3C/svg%3E"); height: 100%; width: 20px; min-width: 20px; min-height: 20px; background-size: contain; background-position: center center; background-repeat: no-repeat; opacity: 0.8;
}
.cbnnr-special .cbnnr-close-icon {
background: linear-gradient(transparent,transparent), url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2220%22 height=%2220%22 fill=%22%23ffffff%22 viewBox=%220 0 20 20%22%3E%3Ctitle%3Eclose%3C/title%3E%3Cpath d=%22M4.34 2.93l12.73 12.73-1.41 1.41L2.93 4.35z%22/%3E%3Cpath d=%22M17.07 4.34L4.34 17.07l-1.41-1.41L15.66 2.93z%22/%3E%3C/svg%3E");
}
.cbnnr-close-icon:hover {
opacity: 1;
}
</style>
<a href="https://www.wikilovesmonuments.org/presenting-the-2018-winners-from-the-worlds-largest-photo-contest/" class="cbnnr-message">
<figure class="cbnnr-icon"> <img src="https://upload.wikimedia.org/wikipedia/donate/9/91/Wiki-loves-monuments-winnder-2018-70x70.png" alt="1st prize. Sheikh Lotfollah Mosque, Iran. Photo by Alireza Akhlaghi, CC BY-SA 4.0"/> </figure>
Wiki Loves Monuments World's largest photography contest Participate now
</a>
<script> var cbnnr = cbnnr || {};
cbnnr.show = function() {
$('.banner-container').insertBefore('#content'); $('.cbnnr').css('display', 'block');
};
/* jshint maxerr: 600 */ /* MediaWiki:FundraisingBanners/CoreJS-2018.js
* Core code for banner forms, with new inline error messages */
var frb = frb || {};
/**
* Test for general ES6 and <dialog> support * * Checks for arrow functions, default parameters, NodeList.prototype.forEach(), <dialog> support * Should be roughly Chrome 51+, Firefox 98+, Edge 79+, Safari 15.4+ * Based on https://gist.github.com/bendc/d7f3dbc83d0f65ca0433caf90378cd95 * @return {boolean} */
frb.supportedBrowser = function() {
try { new Function('(a = 0) => a'); document.querySelectorAll('.frb').forEach(a => a); if ( typeof HTMLDialogElement === 'function' ) { return true; } else { return false; } } catch (err) { return false; }
}();
if ( !mw.centralNotice.adminUi ) { // T262693
frb.loadedTime = Date.now(); frb.didSelectAmount = false; frb.optinRequiredCountries = [ 'AR', 'AT', 'BE', 'BR', 'CL', 'CO', 'CZ', 'DK', 'ES', 'FR', 'GB', 'GR', 'HU', 'IE', 'IT', 'IL', 'LU', 'LV', 'MX', 'NL', 'NO', 'PE', 'PL', 'PT', 'RO', 'SE', 'SK', 'UA', 'UY' ]; frb.optinRequired = frb.optinRequiredCountries.indexOf(mw.centralNotice.data.country) !== -1; frb.maxUSD = 25000; frb.reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}
// Keyboard shortcut to go from banner preview to editor - Ctrl+Shift+E if ( mw.config.get('wgUserName') ) {
if ( mw.config.get('wgUserName').match(/\(WMF\)/) ) { window.addEventListener('keydown', function(e) { if ( e.ctrlKey && e.shiftKey && e.keyCode === 69 ) { window.open( 'https://meta.wikimedia.org/wiki/Special:CentralNoticeBanners/Edit/' + mw.centralNotice.data.banner ); } }); }
}
/**
* Main function to submit to paymentswiki * * @param {Object} options * - method (required) * - submethod (optional) * - gateway (optional) * - skipValidation (optional boolean, for pp-usd. Not yet implemented.) * @param {Boolean} isEndowment - deprecated, set frb.isEndowment instead */
frb.submitForm = function( options, isEndowment ) {
var uri = new mw.Uri('https://payments.wikimedia.org/index.php/Special:GatewayChooser'); var params = {};
if ( !frb.validateForm( options ) ) { frb.extraData.validateError = 1; // Flag they had an error, even if fixed later return false; // Error, bail out of submitting }
// Skip form chooser for Apple Pay / Google Pay if ( options.method === 'apple' || options.method === 'google' ) { uri = new mw.Uri('https://payments.wikimedia.org/index.php/Special:AdyenCheckoutGateway'); }
// Skip form chooser for Venmo if ( options.method === 'venmo' ) { uri = new mw.Uri('https://payments.wikimedia.org/index.php/Special:BraintreeGateway'); }
// Form selection data params.payment_method = options.method; if ( options.submethod ) { params.payment_submethod = options.submethod; } if ( options.gateway ) { params.gateway = options.gateway; } if ( options.variant ) { params.variant = options.variant; } params.recurring = frb.getRecurring();
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; }
params.currency = frb.getCurrency(mw.centralNotice.data.country) || 'USD';
params.uselang = mw.centralNotice.data.uselang || 'en'; params.country = mw.centralNotice.data.country || 'XX';
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'; }
// dLocal override for South Africa if ( params.payment_method === 'cc' && params.country === 'ZA' ) { params.gateway = 'astropay'; }
// Amount var amount = frb.getAmount(); if ( $('#frb-ptf-checkbox').prop('checked') ) { amount = amount + frb.calculateFee(amount); frb.extraData.ptf = 1; } params.amount = amount;
// Email optin if ( frb.optinRequired && $('input[name="opt_in"]').length > 0 ) { var opt_inValue = $('input[name="opt_in"]:checked').val(); params.opt_in = opt_inValue; // frb.validateForm() already checked it's 1 or 0 }
// Tracking info if ( isEndowment || frb.isEndowment ) { params.utm_medium = 'endowment'; params.appeal = 'EndowmentQuote'; } else { params.utm_medium = 'sitenotice'; } params.utm_campaign = mw.centralNotice.data.campaign || 'test'; params.utm_source = frb.buildUtmSource(params);
frb.extraData.time = Math.round( (Date.now() - frb.loadedTime)/1000 );
if ( !$.isEmptyObject( frb.extraData ) ) { params.utm_key = frb.buildUtmKey( frb.extraData ); }
// Link to Banner History if enabled var mixins = mw.centralNotice.getDataProperty( 'mixins' ); if ( mixins && mixins.bannerHistoryLogger ) { params.bannerhistlog = mw.centralNotice.bannerHistoryLogger.id; }
uri.extend(params);
// Set a cookie with current location so we can return here from TY page mw.loader.using( [ 'mediawiki.cookie', 'mediawiki.util' ] ).then( function () { // Exclude URL parameters like banner, but cope with paths like /w/index.php?title=Foo var returnToUrl = window.location.origin + mw.util.getUrl(); mw.cookie.set( 'fundraising_returnTo', returnToUrl, { expires: 300, prefix: , domain: '.wikipedia.org', secure: true } ); });
if ( mixins && mixins.bannerHistoryLogger ) { mw.centralNotice.bannerHistoryLogger.ensureLogSent().always(function() { frb.goToPayments( uri ); }); } else { frb.goToPayments( uri ); }
};
frb.goToPayments = function( uri ) {
if ( window.top !== window.self ) { // banner is in a frame, open payments in a new tab window.open( uri.toString() ); } else { window.location.href = uri.toString(); }
};
/**
* Check the form for errors. * * Called on submission, can also be called on input * * @param {object} options * @return {boolean} Whether form is error-free */
frb.validateForm = function( options ) {
var error = false;
/* Reset all errors */ $('.frb-haserror').removeClass('frb-haserror'); $('.frb-error').hide();
if ( !options.method ) { error = true; $('.frb-methods').addClass('frb-haserror'); $('.frb-error-method').show(); }
if ( !frb.validateAmount() ) { error = true; }
/* Email optin */ if ( frb.optinRequired && $('.frb-optin').is(':visible') ) { var opt_inValue = $('input[name="opt_in"]:checked').val(); if ( opt_inValue !== '1' && opt_inValue !== '0' ) { $('.frb-optin').addClass('frb-haserror'); $('.frb-error-optin').show(); error = true; } }
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. */
frb.validateAmount = function() {
var amount = frb.getAmount(), currency = frb.getCurrency( mw.centralNotice.data.country ), minAmount = frb.amounts.minimums[ currency ], maxAmount = Math.round( frb.maxUSD * minAmount ); // Math.round to account for floating point math errors: https://phabricator.wikimedia.org/T246262
if ( amount === null || isNaN(amount) || amount <= 0 || amount < minAmount ) { $('fieldset.frb-amounts').addClass('frb-haserror'); $('.frb-error-bigamount').hide(); $('.frb-error-smallamount').show(); return false; } else if ( amount > Math.round( maxAmount ) ) { $('fieldset.frb-amounts').addClass('frb-haserror'); $('.frb-error-bigamount').show(); return false; } else { $('fieldset.frb-amounts').removeClass('frb-haserror'); $('.frb-error-smallamount, .frb-error-bigamount').hide(); return true; }
};
/**
* Build the utm_source for analytics. * * Own function so it can be overriden for weird tests * * @param {Object} params * @return {string} utm_source */
frb.buildUtmSource = function(params) {
var utm_source; var fullDottedPaymentMethod = params.payment_method; if ( params.recurring ) { fullDottedPaymentMethod = 'r' + fullDottedPaymentMethod; } if ( params.payment_submethod ) { fullDottedPaymentMethod = fullDottedPaymentMethod + '.' + params.payment_submethod; }
utm_source = mw.centralNotice.data.banner;
// Keeping opt-in in utm_source for safety for now // Eventually remove it, or move to utm_key? if ( params.opt_in ) { utm_source += '_optIn' + params.opt_in; }
utm_source += '.no-LP.' + fullDottedPaymentMethod;
return utm_source;
};
/**
* Build a string for utm_key from extra tracking data * * @param {Object} data * @return {string} utm_key */
frb.buildUtmKey = function(data) {
var dataArray = []; for (var key in data) { if (data.hasOwnProperty(key)) { dataArray.push( key + '_' + data[key] ); } } return dataArray.join('~');
};
/**
* Determine if we should show recurring choice on step 2 * * NOTE 2023-12-07: we don't currently use this for step 2, since there are no * banners where users select method before frequency. However it is used by * frb.shouldShowMonthlyConvert() * * @param {Object} options Including method and optional gateway * @param {String} country * @return {boolean} */
frb.shouldShowRecurring = function( options, country ) {
if ( frb.isEndowment ) { return false; } if ( frb.noRecurringCountries.indexOf( country ) !== -1 ) { // Defined in LocalizeJS-2017.js return false; } if ( options.method === undefined ) { return true; // Show if a method hasn't been selected yet } if ( [ 'cc', 'venmo', 'apple', 'google' ].indexOf( options.method ) !== -1 ) { return true; } if ( options.method === 'paypal' ) { if ( [ 'AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY' ].includes( country ) ) { return false; } else { return true; } } // Adyen iDEAL if ( options.submethod === 'rtbt_ideal' ) { return true; } if ( options.submethod === 'upi' || options.submethod === 'paytmwallet' ) { return true; } return false;
};
/* Is recurring method selected? This function can be overriden for different forms */ frb.getRecurring = function() {
// Can't use simple form.frequency.value, doesn't work in IE var selected = $('#frb-form input[name="frequency"]:checked').val(); return selected === 'monthly';
};
/* Return amount selected */ frb.getAmount = function() {
var form = document.getElementById('frb-form'); var amount = null; frb.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 = form.amount[i].value; } } }
// Check the "other" amount box if (form.otherAmount.value !== ) { var otherAmount = form.otherAmount.value; otherAmount = otherAmount.replace(/[,.](\d)$/, ':$10'); otherAmount = otherAmount.replace(/[,.](\d)(\d)$/, ':$1$2'); otherAmount = otherAmount.replace(/[$£€¥,.]/g, ); otherAmount = otherAmount.replace(/:/, '.'); amount = otherAmount; frb.extraData.otherAmt = 1; }
amount = parseFloat(amount);
if ( isNaN(amount) ) { return 0; } else { return amount; }
};
/* Localize the amount errors. Call when initialising banner. */ frb.localizeErrors = function() {
var currency = frb.getCurrency( mw.centralNotice.data.country ), language = mw.centralNotice.data.uselang, minAmount = frb.amounts.minimums[ currency ], maxAmount = Math.round( frb.maxUSD * minAmount ); // Math.round to account for floating point math errors: https://phabricator.wikimedia.org/T246262
$('.frb-error-smallamount').text( function( index, oldText ) { return oldText.replace( '$1', frb.formatCurrency(currency, minAmount, language) ); });
$('.frb-error-bigamount').text( function( index, oldText ) { // We cannot accept donations greater than $1 $2 through our website. Please contact our major gifts staff at $3. return oldText.replace( '$1', maxAmount ) .replace( '$2', currency ) .replace( '$3', 'benefactors@wikimedia.org' ); });
};
/**
* Shared code for amount input handling */
frb.initAmountOptions = function() {
// Reset "Other" input if user clicks a preset amount $('#frb-form [id^=frb-amt-ps]').click(function() { $('#frb-amt-other-input').val(); });
// Track if they selected and then later changed amount var checkAmountChange = function(e) { if ( frb.didSelectAmount ) { frb.extraData.changedAmt = 1; } // check if amount radio button is selected OR there is a value in the other amount if ( $('.frb-amounts input[type="radio"]:checked').val() !== 'Other' || $('#frb-amt-other-input').val().length > 0 ) { frb.didSelectAmount = true; } return; };
$('.frb-amounts input[type="radio"]').on('change', checkAmountChange); $('#frb-amt-other-input').on('focusout', checkAmountChange);
// Block typing non-numerics in input field, otherwise Safari allows them and then chokes // https://phabricator.wikimedia.org/T118741, https://phabricator.wikimedia.org/T173431 var blockNonNumeric = 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; } }; $('#frb-amt-other-input').on('keypress', blockNonNumeric); $('#frb-amt-monthly-other-input').on('keypress', blockNonNumeric);
};
/**
* Calculate approximate transaction fee on given amount * * @param {number} amount * @return {number} Rounded to 2 decimal places */
frb.calculateFee = function(amount) {
var currency = frb.getCurrency(mw.centralNotice.data.country), feeMultiplier = 0.04, feeMinimum = frb.amounts.feeMinimums[currency] || 0.35, feeAmount = amount * feeMultiplier;
if ( feeAmount < feeMinimum ) { feeAmount = feeMinimum; } return parseFloat(feeAmount.toFixed(2));
};
frb.updateFeeDisplay = function() {
var currency = frb.getCurrency(mw.centralNotice.data.country), language = mw.centralNotice.data.uselang, amount, feeAmount, totalAmount;
amount = frb.getAmount(); feeAmount = frb.calculateFee(amount); if ( $('#frb-ptf-checkbox').prop('checked') ) { totalAmount = amount + feeAmount; } else { totalAmount = amount; }
var feeAmountFormatted = frb.formatCurrency(currency, feeAmount, language); $('.frb-ptf-fee').text(feeAmountFormatted);
var totalAmountFormatted = frb.formatCurrency(currency, totalAmount, language); $('.frb-ptf-total').text(totalAmountFormatted);
$('.frb-ptf').slideDown( frb.reduceMotion ? 0 : 400 );
};
/**
* Custom hide cookie function * * Purposely sets only for this domain. * CentralNotice builtin method seems buggy - see T270401 * * @param {string} reason Reason to store in the hide cookie * @param {number} duration Cookie duration, in seconds */
frb.altSetHideCookie = function ( reason, duration ) {
mw.loader.using( 'mediawiki.cookie' ).then( function () {
var cookieName = 'centralnotice_hide_fundraising', date = new Date(), hideData = { v: 1, created: Math.floor( date.getTime() / 1000 ), reason: reason };
// Re-use the same date object to set the cookie's expiry time date.setSeconds( date.getSeconds() + duration );
mw.cookie.set( cookieName, JSON.stringify( hideData ), { expires: date, path: '/', domain: 'wikipedia.org', prefix: } );
});
};
/**
* Determine if banner should be shown, and set correct data for impression logging * * @return {boolean} Show banner? */
frb.shouldShowBanner = function() {
mw.centralNotice.bannerData.hideResult = false;
/* Hide in unsupported browsers */ if ( !frb.supportedBrowser ) { mw.centralNotice.bannerData.hideResult = true; mw.centralNotice.bannerData.hideReason = 'browser'; }
/* Hide outside main namespace (except Main Page, for sites where it isn't in main namespace) */ if ( mw.config.get('wgNamespaceNumber') > 0 && !mw.config.get('wgIsMainPage') ) { mw.centralNotice.bannerData.hideResult = true; mw.centralNotice.bannerData.hideReason = 'namespace'; }
// Hide banner on sensitive articles // TODO - possibly add wgWikibaseItemId for multilingual support and resilience to moves? var hideTitles = [ 'Murder of Don Banfield' ]; if ( hideTitles.indexOf( mw.config.values.wgTitle ) !== -1 ) { mw.centralNotice.bannerData.hideResult = true; mw.centralNotice.bannerData.hideReason = 'article'; }
/* Hide banner if on wrong site (desktop/mobile) in case wrong device settings were chosen */ var bannerName = mw.centralNotice.data.banner, skin = mw.config.get('skin'); if ( ( bannerName.indexOf('_dsk_') !== -1 && skin === 'minerva' ) || ( bannerName.indexOf('_m_') !== -1 && skin !== 'minerva' ) ) { mw.centralNotice.bannerData.hideResult = true; mw.centralNotice.bannerData.hideReason = 'other'; console.warn('Hiding fundraising banner on wrong site (desktop/mobile)'); }
return !mw.centralNotice.bannerData.hideResult;
};
/* Debug function to highlight dynamically replaced elements */ frb.highlightReplacements = function() {
$('.frb [class^="frb-replace"], .frb-ptf-fee, .frb-ptf-total, .frb-upsell-ask, frb-amt').css('background-color', '#fa0');
};
if ( !mw.centralNotice.adminUi ) { // T262693
/** * Provides alterImpressionData hook for CentralNotice * This info will be sent back with Special:RecordImpression * TODO: check if/when we can remove this (and RecordImpression) */ mediaWiki.centralNotice.bannerData.alterImpressionData = function( impressionData ) { // Returning true from this function indicates the banner was shown if (mediaWiki.centralNotice.bannerData.hideReason) { impressionData.reason = mediaWiki.centralNotice.bannerData.hideReason; } if (mediaWiki.centralNotice.bannerData.cookieCount) { impressionData.banner_count = mediaWiki.centralNotice.bannerData.cookieCount; }
return !mediaWiki.centralNotice.bannerData.hideResult; };
}
/* End of MediaWiki:FundraisingBanners/CoreJS-2018.js */
$(function() {
if ( !mw.centralNotice.bannerData.hideResult ) { cbnnr.show(); }
}); </script>