MediaWiki:FlipCounter.js

Vai alla navigazione Vai alla ricerca

Questa pagina definisce alcuni parametri di aspetto e comportamento generale di tutte le pagine. Per personalizzarli vedi Aiuto:Stile utente.


Nota: dopo aver salvato è necessario pulire la cache del proprio browser per vedere i cambiamenti, e comunque qualche minuto di preghiera non guasta. Per Mozilla / Firefox / Safari: fare clic su Ricarica tenendo premuto il tasto delle maiuscole, oppure premere Ctrl-F5 o Ctrl-R (Command-R su Mac); per Chrome premere Ctrl-Shift-R (Command-Shift-R su un Mac); per Konqueror: premere il pulsante Ricarica o il tasto F5; per Opera può essere necessario svuotare completamente la cache dal menu Strumenti → Preferenze; per Internet Explorer: mantenere premuto il tasto Ctrl mentre si preme il pulsante Aggiorna o premere Ctrl-F5.

var initializedCounter = false;
var myCounter;
var flipCounter = function(divId, options) {
	// Default values
	var defaults = {
		value: 0,
		inc: 1,
		pace: 1000,
		auto: true,
		tFH: 39,
		bFH: 64,
		fW: 53,
		bOffset: 390
	};
	options = options || {};
	divId = typeof divId !== 'undefined' && divId !== '' ? divId : 'flip-counter';
	var div = $('#' + divId);
	for(var opt in defaults) {
		options[opt] = (opt in options) ? options[opt] : defaults[opt];
	}
	var nextCount = null;
	var best = {
		q: null,
		pace: 0,
		inc: 0
	};

	// Imposta il valore del contatore e avvia l'animazione per il nuovo valore
	// Parametri:
	// n: Nuovo valore
	this.setValue = function(n) {
		if(isNumber(n)) {
			var x = options.value;
			var y = n;
			options.value = n;
			digitCheck(x, y);
		}
		return this;
	};

	// Imposta l'incremento per il contatore ma non avvia l'animazione
	// Parametri:
	// n: Incremento
	this.setIncrement = function(n) {
		options.inc = isNumber(n) ? n : defaults.inc;
		return this;
	};

	// Imposta il passo per il contatore, serve solo se auto == true
	// Parametri:
	// n: Nuovo ritmo
	this.setPace = function(n) {
		options.pace = isNumber(n) ? n : defaults.pace;
		return this;
	};

	// Imposta l'autoincremento
	// Parametri:
	// a: Se true l'incremento è automatico, se è false no
	this.setAuto = function(a) {
		if(a && !options.auto) {
			options.auto = true;
			doCount();
		}
		if(!a && options.auto) {
			if(nextCount) {
				clearNext();
			}
			options.auto = false;
		}
		return this;
	};

	// Aumenta il contatore di un'animazione basandosi sul valore di inc
	this.step = function() {
		if(!options.auto) {
			doCount();
		}
		return this;
	};

	// Aggiunge un numero al contatore senza influire su inc o pace
	// Parametri:
	// n: Numero da aggiungere
	this.add = function(n) {
		if(isNumber(n)) {
			var x = options.value;
			options.value += n;
			var y = options.value;
			digitCheck(x, y);
		}
		return this;
	};

	// Sottrae un numero al contatore senza influire su inc o pace
	// Parametri:
	// n: Numero da sottrarre
	this.subtract = function(n) {
		if(isNumber(n)) {
			var x = options.value;
			options.value -= n;
			if (options.value >= 0) {
				var y = options.value;
			}
			else {
				var y = '0';
				options.value = 0;
			}
			digitCheck(x, y);
		}
		return this;
	};

	// Incrementa il contatore animando secondo inc e pace
	// Parametri:
	// n: Incremento
	// t: Durata in millisecondi
	// p: Passo desiderato se è impostata la durata
	this.incrementTo = function(n, t, p) {
		if(nextCount) {
			clearNext();
		}
		// Incremento intelligente
		if(typeof t != 'undefined') {
			var time = isNumber(t) ? t * 1000 : 10000;
			var pace = typeof p != 'undefined' && isNumber(p) ? p : options.pace;
			var diff = typeof n != 'undefined' && isNumber(n) ? n - options.value : 0;
			best.q = null;
			// Migliore stima iniziale
			pace = (time / diff > pace) ? Math.round(time / (diff * 10)) * 10 : pace;
			var cycles = Math.floor(time / pace);
			var inc = Math.floor(diff / cycles);
			var check = checkSmartValues(diff, cycles, inc, pace, time);
			if(diff > 0) {
				var i = 0;
				while(check.result === false && i < 100) {
					pace += 10;
					cycles = Math.floor(time / pace);
					inc = Math.floor(diff / cycles);
					check = checkSmartValues(diff, cycles, inc, pace, time);
					i++;
				}
				if(i == 100) {
					// Non riesce a trovare le impostazioni migliori, usa le migliori trovate finora
					options.inc = best.inc;
					options.pace = best.pace;
				}
				else {
					// Ha trovato le impostazioni migliori
					options.inc = inc;
					options.pace = pace;
				}
				doIncrement(n, true, cycles);
			}
		}
		// Incremento regolare
		else {
			doIncrement(n);
		}
	};

	// Restituisce il valore corrente del contatore
	this.getValue = function() {
		return options.value;
	};

	// Ferma tutti gli incrementi
	this.stop = function() {
		if(nextCount) {
			clearNext();
		}
		return this;
	};

	//---------------------------------------------------------------------------//

	function doCount() {
		var x = options.value;
		options.value += options.inc;
		var y = options.value;
		digitCheck(x, y);
		if(options.auto === true) {
			nextCount = setTimeout(doCount, options.pace);
		}
	}

	function doIncrement(n, s, c) {
		var val = options.value;
		var smart = (typeof s == 'undefined') ? false : s;
		var cycles = (typeof c == 'undefined') ? 1 : c;
		if(smart === true) {
			cycles--;
		}
		if(val != n) {
			var x = options.value;
			options.auto = true;
			if(val + options.inc <= n && cycles != 0) {
				val += options.inc;
			}
			else {
				val = n;
			}
			options.value = val;
			var y = options.value;
			digitCheck(x, y);
			nextCount = setTimeout(function() {doIncrement(n, smart, cycles);}, options.pace);
		}
		else {
			options.auto = false;
		}
	}

	function digitCheck(x, y) {
		var digitsOld = splitToArray(x);
		var digitsNew = splitToArray(y);
		var xlen = digitsOld.length;
		var ylen = digitsNew.length;
		if(ylen > xlen) {
			var diff = ylen - xlen;
			while(diff > 0) {
				addDigit(ylen - diff + 1, digitsNew[ylen - diff]);
				diff--;
			}
		}
		else if(ylen < xlen) {
			var diff = xlen - ylen;
			while(diff > 0) {
				removeDigit(xlen - diff);
				diff--;
			}
		}
		for(var i = 0; i < xlen; i++) {
			if(digitsNew[i] != digitsOld[i]) {
				animateDigit(i, digitsOld[i], digitsNew[i]);
			}
		}
	}

	function animateDigit(n, oldDigit, newDigit) {
		var speed = 80;
		var step = 0;
		var bp = [
			'-' + options.fW + 'px -' + (oldDigit * options.tFH) + 'px',
			(options.fW * -2) + 'px -' + (oldDigit * options.tFH) + 'px',
			'0 -' + (newDigit * options.tFH) + 'px',
			'-' + options.fW + 'px -' + (oldDigit * options.bFH + options.bOffset) + 'px',
			(options.fW * -2) + 'px -' + (newDigit * options.bFH + options.bOffset) + 'px',
			(options.fW * -3) + 'px -' + (newDigit * options.bFH + options.bOffset) + 'px',
			'0 -' + (newDigit * options.bFH + options.bOffset) + 'px'
		];
		if(options.auto === true && options.pace <= 300) {
			switch(n) {
				case 0:
					speed = options.pace/6;
					break;
				case 1:
					speed = options.pace/5;
					break;
				case 2:
					speed = options.pace/4;
					break;
				case 3:
					speed = options.pace/3;
					break;
				default:
					speed = options.pace/1.5;
					break;
			}
		}
		speed = (speed > 80) ? 80 : speed;

		function animate() {
			if(step < 7) {
				var w = step < 3 ? 't' : 'b';
				var a = $('#' + divId + '_' + w + '_d' + n);
				if(a.length) {
					a.css('background-position', bp[step]);
				}
				step++;
				if(step != 3) {
					setTimeout(animate, speed);
				}
				else {
					animate();
				}
			}
		}
		animate();
	}

	// Crea un array di cifre per una manipolazione più facile
	function splitToArray(input) {
		return input.toString().split('').reverse();
	}

	// Aggiunge una nuova cifra
	function addDigit(len, digit) {
		var li = Number(len) - 1;
		var newDigit = $('<ul></ul>').attr({
			'class': 'cd',
			'id': divId + '_d' + li
		}).html('<li class="t" id="' + divId + '_t_d' + li + '"></li><li class="b" id="' + divId + '_b_d' + li + '"></li>');
		if(li % 3 == 0) {
			var newComma = $('<ul></ul>').attr('class', 'cd').html('<li class="s"></li>');
			div.prepend(newComma);
		}
		div.prepend(newDigit);
		$('#' + divId + '_t_d' + li).css('background-position', '0 -' + (digit * options.tFH) + 'px');
		$('#' + divId + '_b_d' + li).css('background-position', '0 -' + (digit * options.bFH + options.bOffset) + 'px');
	}

	// Rimuove una cifra
	function removeDigit(id) {
		$('#' + divId + '_d' + id).remove();
		// Controlla le virgole
		var first = $(':first-child', div);
		if((' ' + $(':first-child', first).attr('class') + ' ').indexOf(' s ') > -1) {
			first.remove();
		}
	}

	// Imposta le cifre corrette al caricamento
	function initialDigitCheck(init) {
		// Crea il numero giusto di cifre
		var initial = init.toString();
		var count = initial.length;
		var bit = 1;
		for(var i = 0; i < count; i++) {
			var newDigit = $('<ul></ul>').attr({
				'class': 'cd',
				'id': divId + '_d' + i
			}).html('<li class="t" id="' + divId + '_t_d' + i + '"></li><li class="b" id="' + divId + '_b_d' + i + '"></li>');
			div.prepend(newDigit);
			if(bit != count && bit % 3 == 0) {
				var newComma = $('<ul></ul>').attr('class', 'cd').html('<li class="s"></li>');
				div.prepend(newComma);
			}
			bit++;
		}
		// Le imposta al numero giusto
		var digits = splitToArray(initial);
		for(var i = 0; i < count; i++) {
			$('#' + divId + '_t_d' + i).css('background-position', '0 -' + (digits[i] * options.tFH) + 'px');
			$('#' + divId + '_b_d' + i).css('background-position', '0 -' + (digits[i] * options.bFH + options.bOffset) + 'px');
		}
		// Esegue la prima animazione
		if(options.auto === true) {
			nextCount = setTimeout(doCount, options.pace);
		}
	}

	// Controlla i valori per l'incremento intelligente e restituisce il testo di debug
	function checkSmartValues(diff, cycles, inc, pace, time) {
		var r = {result: true};
		// Controlla le condizioni, devono passare tutte per continuare:
		// 1: Il valore non arrotondato di inc deve essere almeno 1
		r.cond1 = (diff / cycles >= 1) ? true : false;
		// 2: Non bisogna sorpassare il numero voluto
		r.cond2 = (cycles * inc <= diff) ? true : false;
		// 3: Bisogna essere entro 10 dal numero voluto
		r.cond3 = (Math.abs(cycles * inc - diff) <= 10) ? true : false;
		// 4: Il tempo totale deve essere entro 100ms dal tempo voluto
		r.cond4 = (Math.abs(cycles * pace - time) <= 100) ? true : false;
		// 5: Calculated time should not be over target time
		r.cond5 = (cycles * pace <= time) ? true : false;
		// Tiene traccia dei valori "abbastanza buoni" se non si riesce a trovare i migliori entro 100 cicli
		if(r.cond1 && r.cond2 && r.cond4 && r.cond5) {
			var q = Math.abs(diff - (cycles * inc)) + Math.abs(cycles * pace - time);
			if(best.q === null) {
				best.q = q;
			}
			if(q <= best.q) {
				best.pace = pace;
				best.inc = inc;
			}
		}
		for(var i = 1; i <= 5; i++) {
			if(r['cond' + i] === false) {
				r.result = false;
				break;
			}
		}
		return r;
	}

	// http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric/1830844
	function isNumber(n) {
		return !isNaN(parseFloat(n)) && isFinite(n);
	}

	function clearNext() {
		clearTimeout(nextCount);
		nextCount = null;
	}

	// Avviamento
	initialDigitCheck(options.value);
};

mw.hook('nonciclopedia.ready').fire();