Jump to content

MediaWiki:WMDE FR2015/Resources/DesktopBanner-test.js

From Meta, a Wikimedia project coordination wiki

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/*jshint latedef: nofunc */
/*jshint unused: false */
/* globals mw, alert, GlobalBannerSettings */
var currentDate = new Date(),
	finalDateTime = new Date( 2015, 11, 31, 23, 59, 59 ),
	goalSum = 8600000,
	/* jshint -W079 */
	GlobalBannerSettings = typeof GlobalBannerSettings !== 'undefined' ? GlobalBannerSettings : {},
	/* jshint +W079 */
	baseDate = replaceWikiVars( '{{{donations-date-base}}}' ),
	collectedBase = parseInt( replaceWikiVars( '{{{donations-collected-base}}}' ), 10 ),
	donorsBase = parseInt( replaceWikiVars( '{{{donators-base}}}' ), 10 ),
	donationsPerMinApproximation = parseFloat( replaceWikiVars( '{{{appr-donations-per-minute}}}' ) ),
	donorsPerMinApproximation = parseFloat( replaceWikiVars( '{{{appr-donators-per-minute}}}' ) ),
	noIntervalSelectedMessage = replaceWikiVars( '{{{no-interval-message}}}' ) || 'Bitte wählen Sie ein Zahlungsintervall.',
	amountTooLowMessage = replaceWikiVars( '{{{amount-too-low-message}}}' ) || 'Der Mindestbetrag beträgt 1 Euro.',
	amountTooHighMessage = replaceWikiVars( '{{{amount-too-high-message}}}' ) || 'Der Spendenbetrag ist zu hoch.',
	allBannersImpCookie = 'centralnotice_banner_impression_count',
	singleBannerImpCookie = 'centralnotice_single_banner_impression_count',
	bannerCloseTrackRatio = replaceWikiVars( '{{{banner-close-track-ratio}}}' ) || 0.01,
	bannerClosedCookie = replaceWikiVars( '{{{banner-closed-cookie}}}' ),
	bannerClosedCookieExpiryDate = parseDateString( replaceWikiVars( '{{{banner-closed-cookie-expiry-date}}}' ) ) || new Date( currentDate.getFullYear() + 1, 0, 1 ),
	bannerClosedCookieValue = replaceWikiVars( '{{{banner-closed-cookie-custom-value}}}' ) || '1',
	showBanner = true,
	messages = {
		en: {
			day: 'day',
			days: 'days'
		},
		de: {
			day: 'Tag',
			days: 'Tage'
		}
	};

if ( bannerClosedCookieIsSet() ) {
	showBanner = false;
}

if ( onMediaWiki() ) {
	mw.centralNotice.bannerData.alterImpressionData = function ( impressionData ) {
		if ( showBanner ) {
			return true;
		}

		mw.centralNotice.bannerData.hideResult = true;
		mw.centralNotice.bannerData.hideReason = 'close';
		return false;
	};
}

$( function () {
	$( '#WMDE_Banner-close' ).click( function () {
		if ( Math.random() < bannerCloseTrackRatio ) {
			$( '#WMDE_Banner-close-ct' ).attr( 'src', replaceWikiVars( 'https://tracking.wikimedia.de/piwik/piwik.php?idsite=1&url=https://spenden.wikimedia.de/banner-closed/{{{BannerName}}}&rec=1' ) );
		}
		$( '#WMDE_Banner' ).hide();
		removeBannerSpace();
		setBannerClosedCookie();

		return false;
	} );

	$( '#amount-other-input' ).on( 'click', function () {
		$( 'input:radio[name=betrag_auswahl]' ).prop( 'checked', false );
		$( '#amount_other' ).prop( 'checked', true );
	} );
	$( '#amount_other' ).on( 'click', function () {
		$( '#amount-other-input' ).trigger( 'click' );
	} );
	$( 'input:radio[name=betrag_auswahl]' ).on( 'click', function () {
		$( '#amount_other' ).prop( 'checked', false );
		hideAmountError();
	} );
	$( '#interval_onetime' ).on( 'click', function () {
		removeSpaceForIntervalOptions();
		$( '.interval-options' ).addClass( 'interval-hidden' );
		$( '#interval_multiple' ).prop( 'checked', false );
		hideFrequencyError();
	} );
	$( '#interval_multiple' ).on( 'click', function () {
		addSpaceForIntervalOptions();
		$( '.interval-options' ).removeClass( 'interval-hidden' );
		$( '#interval_onetime' ).prop( 'checked', false );
	} );
	$( 'input:radio[name=interval]' ).on( 'click', function () {
		hideFrequencyError();
	} );
} );

function parseDateString( dateString ) {
	var dateParts = dateString.split( '-' );
	if ( dateParts.length !== 3 ) {
		return false;
	}
	return new Date( dateParts[ 0 ], dateParts[ 1 ] - 1, dateParts[ 2 ] );
}

function setBannerClosedCookie() {
	$.cookie( bannerClosedCookie, bannerClosedCookieValue, { expires: bannerClosedCookieExpiryDate, path: '/' } );
}

function getDaysLeft() {
	var daysLeft = Math.floor( new Date( finalDateTime - new Date() ) / 1000 / 60 / 60 / 24 );
	return ( daysLeft < 0 ) ? 0 : daysLeft;
}

function getDaysRemaining( language ) {
	var daysRemaining = getDaysLeft(),
		lang = language || 'de';
	// TODO manually hack to fix older banners from 2014
	if ( daysRemaining === 0 ) {
		$( '#donationRemaining' ).width( 0 );
		$( '#donationRemaining' ).html( '' );
	}
	return daysRemaining + ' ' + ( daysRemaining > 1 ? messages[ lang ].days : messages[ lang ].day );
}

function getSecsPassed() {
	var startDate = parseDateString( baseDate ),
		maxSecs = Math.floor( new Date( finalDateTime - startDate ) / 1000 ),
		secsPassed = Math.floor( ( new Date() - startDate ) / 1000 );

	if ( secsPassed < 0 ) {
		secsPassed = 0;
	}
	if ( secsPassed > maxSecs ) {
		secsPassed = maxSecs;
	}

	return secsPassed;
}

function getApprDonationsRaw( rand ) {
	var startDonations = collectedBase,
		secsPast = getSecsPassed();

	return startDonations + getApprDonationsFor( secsPast, rand );
}

function getApprDonatorsRaw( rand ) {
	var startDonators = donorsBase,
		secsPast = getSecsPassed();

	return startDonators + getApprDonatorsFor( secsPast, rand );
}

function getApprDonationsFor( secsPast, rand ) {
	var apprDontionsMinute = donationsPerMinApproximation,
		randFactor = 0;

	if ( rand === true ) {
		randFactor = Math.floor( ( Math.random() ) + 0.5 - 0.2 );
	}

	return ( secsPast / 60 * ( apprDontionsMinute * ( 100 + randFactor ) ) / 100 );
}

function getApprDonatorsFor( secsPast, rand ) {
	var apprDonatorsMinute = donorsPerMinApproximation,
		randFactor = 0;

	if ( rand === true ) {
		randFactor = Math.floor( ( Math.random() ) + 0.5 - 0.2 );
	}

	return ( secsPast / 60 * ( apprDonatorsMinute * ( 100 + randFactor ) ) / 100 );
}

function getCurrentGermanDay() {
	switch ( currentDate.getDay() ) {
		case 0:
			return 'Sonntag';
		case 1:
			return 'Montag';
		case 2:
			return 'Dienstag';
		case 3:
			return 'Mittwoch';
		case 4:
			return 'Donnerstag';
		case 5:
			return 'Freitag';
		case 6:
			return 'Samstag';
		default:
			return '';
	}
}

function addPointsToNum( num ) {
	// jscs:disable disallowImplicitTypeConversion
	num = parseInt( num, 10 ) + '';
	// jscs:enable disallowImplicitTypeConversion
	num = num.replace( /\./g, ',' );
	return num.replace( /(\d)(?=(\d\d\d)+(?!\d))/g, '$1.' );
}

function floorF( num ) {
	return Math.floor( num * 100 ) / 100;
}

function getImpCount() {
	return parseInt( $.cookie( allBannersImpCookie ), 10 ) || 0;
}

function getBannerImpCount( bannerId ) {
	var cookieValue, cookieData;

	if ( $.cookie( singleBannerImpCookie ) ) {
		cookieValue = $.cookie( singleBannerImpCookie );
		cookieData = cookieValue.split( '|' );
		if ( cookieData[ 0 ] === bannerId ) {
			return parseInt( cookieData[ 1 ], 10 );
		}
	}
	return 0;
}

function increaseImpCount() {
	var impCount = getImpCount();
	$.cookie( allBannersImpCookie, impCount + 1, { expires: 7, path: '/' } );
	return impCount + 1;
}

function increaseBannerImpCount( bannerId ) {
	var impCount = getBannerImpCount( bannerId );

	$.cookie( singleBannerImpCookie, bannerId + '|' + ( impCount + 1 ), {
		expires: 7,
		path: '/'
	} );
	return ( impCount + 1 );
}

function validateForm() {
	var chkdPayment = $( 'input[name=pay]:checked', '#WMDE_BannerForm' ).val(),
		form = document.donationForm,
		error = false,
		amount;

	switch ( chkdPayment ) {
		case 'BEZ':
			$( '#form-page' ).val( 'Formularseite2-Lastschrift' );
			break;
		case 'UEB':
			$( '#form-page' ).val( 'Formularseite2-Überweisung' );
			break;
		case 'PPL':
			$( '#form-page' ).val( 'Formularseite2-PayPal' );
			break;
		case 'MCP':
			$( '#form-page' ).val( 'Formularseite2-Micropayment' );
			break;
	}

	if ( !validateAndSetPeriod() ) {
		return false;
	}
	amount = getAmount();

	// Check amount is at least the minimum
	if ( amount < 1 || error ) {
		showAmountError( amountTooLowMessage );
		return false;
	} else if ( amount > 99999 ) {
		showAmountError( amountTooHighMessage );
		return false;
	}
	hideAmountError();
	return amount;
}

function showAmountError( text ) {
	if ( $( '#WMDE_Banner-amounts-error-text' ).length < 1 ) {
		alert( text );
		return;
	}
	$( '#WMDE_Banner-amounts-error-text' ).text( text ).show();
	$( '#WMDE_Banner-amounts' ).addClass( 'fieldset-error' );
}

function hideAmountError() {
	$( '#WMDE_Banner-amounts-error-text' ).hide();
	$( '#WMDE_Banner-amounts' ).removeClass( 'fieldset-error' );
}

function showFrequencyError( text ) {
	if ( $( '#WMDE_Banner-frequency-error-text' ).length < 1 ) {
		alert( text );
		return;
	}
	$( '#WMDE_Banner-frequency-error-text' ).text( text ).show();
	$( '#WMDE_Banner-frequency' ).addClass( 'fieldset-error' );
}

function hideFrequencyError() {
	$( '#WMDE_Banner-frequency-error-text' ).hide();
	$( '#WMDE_Banner-frequency' ).removeClass( 'fieldset-error' );
}

/**
 * Check the "interval" radio buttons and change the "period" and "intervalType" fields accordingly.
 * If "periodically" is selected but no interval is selected, this function
 * will display an error message via alert.
 */
function validateAndSetPeriod() {
	var form = document.donationForm;
	if ( $( '#interval_multiple' ).is( ':checked' ) ) {
		if ( $( 'input[name=interval]:checked', form ).length !== 1 ) {
			showFrequencyError( noIntervalSelectedMessage );
			return false;
		} else {
			$( '#intervalType' ).val( '1' );
			$( '#periode' ).val( $( 'input[name=interval]:checked', form ).val() );
		}
	} else if ( $( '#interval_onetime' ).is( ':checked' ) )  {
		$( '#periode' ).val( '0' );
		$( '#intervalType' ).val( '0' );
	} else {
		showFrequencyError( noIntervalSelectedMessage );
		return false;
	}
	hideFrequencyError();
	return true;
}

function getAmount() {
	var amount = null,
		otherAmount = $( '#amount-other-input' ).val(),
		form = document.donationForm;

	amount = $( 'input[name=betrag_auswahl]:checked' ).val();

	if ( otherAmount !== '' ) {
		otherAmount = otherAmount.replace( /[,.](\d)$/, '\:$10' );
		otherAmount = otherAmount.replace( /[,.](\d)(\d)$/, '\:$1$2' );
		otherAmount = otherAmount.replace( /[\$,.]/g, '' );
		otherAmount = otherAmount.replace( /:/, '.' );
		$( '#amount-other-input' ).val( otherAmount );
		amount = otherAmount;
	}

	if ( amount === null || isNaN( amount ) || amount.value <= 0 ) {
		return false;
	}

	return amount;
}

function addBannerSpace() {
	var expandableBannerHeight = $( 'div#WMDE_Banner' ).height() + 44,
		bannerDivElement = $( '#WMDE_Banner' ),
		skin = getSkin();

	if ( !showBanner ) {
		return;
	}
	switch ( skin ) {
		case 'vector':
			bannerDivElement.css( 'top', 0 );
			bannerDivElement.css( 'display', 'block' );
			$( '#mw-panel' ).css( 'top', expandableBannerHeight + 160 );
			$( '#mw-head' ).css( 'top', expandableBannerHeight );
			$( '#mw-page-base' ).css( 'paddingTop', expandableBannerHeight );
			break;
		case 'monobook':
			$( '#globalWrapper' ).css( 'position', 'relative' );
			$( '#globalWrapper' ).css( 'top', expandableBannerHeight );
			bannerDivElement.css( 'top', '-20px' );
			bannerDivElement.css( 'background', 'none' );
			break;
	}
	setTimeout( animateProgressBar, 1000 );
}

function addBannerSpaceWithRollo() {
	var expandableBannerHeight = $( 'div#WMDE_Banner' ).height() + 44,
		bannerDivElement = $( '#WMDE_Banner' ),
		skin = getSkin();

	if ( !showBanner ) {
		return;
	}
	switch ( skin ) {
		case 'vector':
			bannerDivElement.css( 'top', 0 - expandableBannerHeight );
			$( '#mw-panel' ).animate( { top: expandableBannerHeight + 160 }, 1000 );
			$( '#mw-head' ).animate( { top: expandableBannerHeight }, 1000 );
			$( '#mw-page-base' ).animate( { paddingTop: expandableBannerHeight }, 1000 );
			break;
		case 'monobook':
			$( '#globalWrapper' ).css( 'position', 'relative' );
			$( '#globalWrapper' ).css( 'top', expandableBannerHeight );
			bannerDivElement.css( 'top', '-20px' );
			bannerDivElement.css( 'background', 'none' );
			break;
	}
	bannerDivElement.css( 'display', 'block' );
	bannerDivElement.animate( { top: 0 }, 1000 );
	setTimeout( animateProgressBar, 1000 );
}

function removeBannerSpace() {
	var $intervalOptionsContainer = $( 'div.interval-options' ),
		expandableBannerHeight = $intervalOptionsContainer.height();
	switch ( getSkin() ) {
		case 'vector':
			$( '#mw-panel' ).css( 'top', 160 );
			$( '#mw-head' ).css( 'top', 0 );
			$( '#mw-page-base' ).css( 'padding-top', 0 );
			break;
		case 'minerva':
			$( '#mw-mf-viewport' ).css( 'top', expandableBannerHeight );
			break;
		case 'monobook':
			$( '#globalWrapper' ).css( 'position', 'relative' );
			$( '#globalWrapper' ).css( 'top', 0 );
			break;
	}
}

function addSpaceForIntervalOptions() {
	var $intervalOptionsContainer = $( 'div.interval-options' ),
		expandableBannerHeight = $intervalOptionsContainer.height();
	if ( $intervalOptionsContainer && $intervalOptionsContainer.is( ':visible' ) ) {
		return;
	}

	switch ( getSkin() ) {
		case 'vector':
			$( '#mw-panel' ).css( { top: parseInt( $( '#mw-panel' ).css( 'top' ), 10 ) + expandableBannerHeight + 'px' } );
			$( '#mw-head' ).css( { top: parseInt( $( '#mw-head' ).css( 'top' ), 10 ) + expandableBannerHeight + 'px' } );
			$( '#mw-page-base' ).css( { paddingTop: parseInt( $( '#mw-page-base' ).css( 'padding-top' ), 10 ) + expandableBannerHeight + 'px' } );
			break;
		case 'minerva':
			$( '#mw-mf-viewport' ).css( { top: parseInt( $( '#mw-mf-viewport' ).css( 'top' ), 10 ) + expandableBannerHeight + 'px' } );
			break;
		case 'minerva':
			$( '#mw-mf-viewport' ).css( 'top', 0 );
			break;
		case 'monobook':
			$( '#globalWrapper' ).css( { top: parseInt( $( '#globalWrapper' ).css( 'top' ), 10 ) + expandableBannerHeight + 'px' } );
			break;
	}
}

function removeSpaceForIntervalOptions() {
	var $intervalOptionsContainer = $( 'div.interval-options' ),
		expandableBannerHeight = $intervalOptionsContainer.height() + 5;
	if ( $intervalOptionsContainer && !$intervalOptionsContainer.is( ':visible' ) ) {
		return;
	}

	switch ( getSkin() ) {
		case 'vector':
			$( '#mw-panel' ).css( { top: ( parseInt( $( '#mw-panel' ).css( 'top' ), 10 ) - expandableBannerHeight ) + 'px' } );
			$( '#mw-head' ).css( { top: ( parseInt( $( '#mw-head' ).css( 'top' ), 10 ) - expandableBannerHeight ) + 'px' } );
			$( '#mw-page-base' ).css( { paddingTop: ( parseInt( $( '#mw-page-base' ).css( 'padding-top' ), 10 ) - expandableBannerHeight ) + 'px' } );
			break;
		case 'minerva':
			$( '#mw-mf-viewport' ).css( { top: ( parseInt( $( '#mw-mf-viewport' ).css( 'top' ), 10 ) - expandableBannerHeight ) + 'px' } );
			break;
		case 'monobook':
			$( '#globalWrapper' ).css( { top: ( parseInt( $( '#globalWrapper' ).css( 'top' ), 10 ) - expandableBannerHeight ) + 'px' } );
			break;
	}
}

function animateProgressBar() {
	var donationFillElement = $( '#donationFill' ),
		daysLeftElement = $( '#daysLeft' ),
		donationValueElement = $( '#donationValue' ),
		remainingValueElement = $( '#valRem' ),
		preFillValue = 0,
		barWidth, dTarget, dCollected, dRemaining, fWidth, widthToFill;

	donationFillElement.clearQueue();
	donationFillElement.stop();
	donationFillElement.width( preFillValue + 'px' );

	daysLeftElement.hide();

	barWidth = $( '#donationMeter' ).width();
	dTarget = goalSum;
	dCollected = getApprDonationsRaw();
	dRemaining = dTarget - dCollected;
	fWidth = dCollected / dTarget * barWidth;
	widthToFill = getFillWidth( barWidth, dTarget, dCollected );

	donationFillElement.animate( { width: widthToFill + 'px' }, {
		duration: 3000,
		progress: function () {
			var dFill = donationFillElement.width() / widthToFill * fWidth,
				pFill = dFill / barWidth,
				dColl = dTarget * pFill,
				vRem = dTarget - ( dTarget * pFill ) ;
			setCollectedAndRemaining( dColl, vRem );
		},
		complete: function () {
			setCollectedAndRemaining( dCollected, dRemaining );
			$( '#donationText' ).show();
			$( '#donationRemaining' ).show();
			daysLeftElement.show();
		}
	} );

	function setCollectedAndRemaining( donationsCollected, donationsRemaining ) {
		remainingValueElement.html( formatMillion( donationsRemaining ) );
		donationValueElement.html( formatMillion( donationsCollected ) );
	}
}

function formatMillion( value ) {
	value = value / 1000000;
	value = value.toFixed( 1 );
	// TODO Find a way to skip the next step for english locale
	value = value.replace( '.', ',' );
	return value;
}

function setProgressBarSize() {
	var donationFillElement = $( '#donationFill' ),
		barWidth, dCollected;
	barWidth = $( '#donationMeter' ).width();
	dCollected = getApprDonationsRaw();
	donationFillElement.width( getFillWidth( barWidth, goalSum, dCollected ) + 'px' );
}

function getFillWidth( donationBarWidth, donationTarget, donationsCollected ) {
	var widthToFill,
		maxFillWidth = donationBarWidth - $( '#donationRemaining' ).width(),
		fWidth = donationsCollected / donationTarget * donationBarWidth;

	widthToFill = Math.min( maxFillWidth, fWidth );
	// Fill at least 100px or 15% (in case 15% fill is lower than 100px)
	widthToFill = Math.max( 100, 0.15 * donationBarWidth, widthToFill );
	return widthToFill;
}

/**
 * Calculate the number of donors needed, given an average donation amount.
 *
 * This function cannot return less than 0 donors when the target has been reached.
 *
 * @param  {number} averageDonation Average donation amount in EUR
 * @return {number} Number of donors needed (rounded up)
 */
function getRemainingDonorsNeeded( averageDonation ) {
	var dRemaining, dCollected, numDonors;
	dCollected = getApprDonationsRaw();
	dRemaining = goalSum - dCollected;
	numDonors = Math.ceil( dRemaining / averageDonation );
	return Math.max( 0, numDonors );
}

/**
 * For instances where this JS is not generated by a Wiki, try to replace the
 * placeholders with values fram a global object
 */
function replaceWikiVars( text ) {
	var re = /\{\{\{([^\}]+)\}\}\}/g,
		wikiVarMatch;
	while ( ( wikiVarMatch = re.exec( text ) ) !== null ) {
		if ( GlobalBannerSettings[ wikiVarMatch[ 1 ] ] ) {
			text = text.replace( wikiVarMatch[ 0 ], GlobalBannerSettings[ wikiVarMatch[ 1 ] ] );
		} else {
			text = text.replace( wikiVarMatch[ 0 ], '' );
		}
	}
	return text;
}

function getSkin() {
	if ( onMediaWiki() ) {
		return mw.config.get( 'skin' );
	}
	return 'vector';
}

function onMediaWiki() {
	return typeof mw === 'object' && typeof mw.centralNotice !== 'undefined';
}

function bannerClosedCookieIsSet() {
	if ( bannerClosedCookieValue !== '1' ) {
		return $.cookie( bannerClosedCookie ) === bannerClosedCookieValue;
	}
	return $.cookie( bannerClosedCookie ) !== null && typeof $.cookie( bannerClosedCookie ) !== 'undefined';
}