Usuari:Coet/wikistorm/utils.js

De la Viquipèdia, l'enciclopèdia lliure

Nota: Després de desar, heu de netejar la memòria cau del navegador per veure els canvis. En la majoria de navegadors amb Windows o Linux, premeu Ctrl+F5 o bé premeu Shift i cliqueu el botó "Actualitza" (Ctrl i "Actualitza" amb Internet Explorer). Vegeu més informació i instruccions per a cada navegador a Viquipèdia:Neteja de la memòria cau.

(function(){	
	Wikistorm.utils = {};
	window.Wikistorm.utils = Wikistorm.utils;
	Wikistorm.utils.normalizeTitle = (title) => {
		return title.replace(/ /g, '_');
	};

	Wikistorm.utils.simplifyChars = (str) => {
		str = str.replace('\u00f3', 'o').replace('ó', 'o');
		str = str.toLowerCase();
		return str;
	};

	Wikistorm.utils.monthToIndex = (month) => {
		/*
			L'abreviatura 'ago' és una anomalia viquipèdica i raó per la què 
			utilitze un object. Un simple vector amb les abreviatures i tornar
			un months.indexOf(month) seria suficient.
			return [
				'gen', 'feb', 'març', 
				'abr', 'maig', 'juny', 
				'jul', 'ag', 'set', 
				'oct', 'nov', 'des'
			].indexOf(month).
			A l'espera que desaparega l'ago, seguirem emprant l'obejte.
			
			Queda pendent obtenir les abreviatures en un vector per mitjà
			de  la consulta api:
			"/api.php?action=query&meta=allmessages&amlang=ca
				&ammessages=jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec"
			var query = {
				action: 'query',
				meta: 'allmessages',
				ammessages: 'jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec'
				amlang: 'ca'
			}
			Facilitant que amlang puga bescanviarse per una altra llengua...
		*/
		months = {
			gen: 0, feb: 1, març: 2,
			abr: 3, maig: 4, juny: 5,
			jul: 6, ag: 7, ago: 7, set: 8,
			oct: 9, nov: 10, des: 11
		};
		return months[month];
	};
	
	Date.prototype.format = function (sep='-') {
		let day = `${this.getDate()}`.padStart(2, '0');
		let month = `${this.getMonth()+1}`.padStart(2, '0');
		return `${day}${sep}${month}${sep}${this.getFullYear()}`;
	};

	class DateDiff {
		/*
			Creat amb IA, no és una bona classe però per a l'ús que se'n
			farà sobra, ja que no hem de calcular periodes llargs, i s'havia
			de provar esta nova eina!!! xD
			
			Calculem la diferència entre dos dates o hui i la data proporcionada
			negligint hores, minuts i segons.
			
			Queda pendent afegir mètode si passem cadenes en lloc d'objectes
			del tipus Date.
		*/
		constructor() {
			this.startDate = null;
			this.endDate = null;
			this.years = 0;
			this.months = 0;
			this.days = 0;
		}
		
		checkSecondDate(secondDate) {
			/* 
				Si no s'ha proporcionat una segona data fem que siga hui
				a les 00:00:00.
			*/
			if (secondDate)
				return secondDate;
			var sd = new Date();
			return new Date(sd.getFullYear(), sd.getMonth(), sd.getDate());
		}
		
		setDate(firstDate) {
			var secondDate = this.checkSecondDate(null);
			this.setDates(firstDate, secondDate);
		}
		
		setDates(firstDate, secondDate) {
			if (firstDate > secondDate)
				[firstDate, secondDate] = [secondDate, firstDate];
			this.startDate = firstDate;
			this.endDate = secondDate;
		}
		
		daysInMonth(month, year){
			return new Date(year, month, 0).getDate();
		}
		
		isLeapYear(year){
			return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
		}
		
		calculateDifference() {
		  var tempDate = new Date(this.startDate);
		  var years = 0;
		  var months = 0;
		  var days = 0;
		
		  while (tempDate > this.endDate) {
		    tempDate.setFullYear(tempDate.getFullYear() - 1);
		    years++;
		  }
		
		  while (tempDate > this.endDate) {
		    var month = tempDate.getMonth();
		    var year = tempDate.getFullYear();
		    tempDate.setDate(
		    	tempDate.getDate() - this.daysInMonth(month, year)
		    );
		    months++;
		  }
		  
		  days = Math.floor(
		  	(this.endDate - tempDate) / (1000 * 60 * 60 * 24)
		  );
		  this.years = years;
		  this.months = months;
		  this.days = days;
		}
		
		toObject() {
			return {
				years: this.years,
				months: this.months,
				days: this.days
			};
		}
		
		translate(key, number) {
			return {
				ca: {
					day : {
						s: 'dia', p: 'dies'
					},
					month: {
						s: 'mes', p: 'mesos'
					},
					year: {
						s: 'any', p: 'anys'
					}
				}
			}['ca'][key][number];
		}
		
		format(key, val) {
			let dict = {
				days: val == 1 ? this.translate('day', 's') :
					this.translate('day', 'p'),
				months: val == 1 ? this.translate('month', 's') :
					this.translate('month', 'p'),
				years: val == 1 ? this.translate('year', 's') :
					this.translate('year', 'p')
			};
			return `${val} ${dict[key]}`;
		}
		
		toString() {
			var conj = ' i ';
			var sep = ', ';
			var result = [];
			Object.entries(
				this.toObject()
			).forEach(
				([k, v]) => {
					if (v>0) result.push(this.format(k, v));
				}
			);
			
			return result.slice(0, -1)
				.join(sep)
				.concat(result.length > 1 ? conj : '', result.slice(-1));
		}
	}
	Wikistorm.utils.DateDiff = DateDiff;
	
	class ArticleForDeletion {
		constructor() {
			this.body = '';
			this.title = '';
			this.votes = {};
			this.voteSummary = {
				positive: 0, negative: 0, revoked: 0, abstentions: 0
			};
			this.promotion = {};
			this.posKeys = ['aprovacio', 'a favor', 'suport', 'assumible'];
			this.negKeys = ['objeccio', 'en contra', 'rebuig', 'consentible'];
			this.absKeys = ['indiferent', 'nsnc'];
			this.award = {};
			this.availableResults = {
				cancel: "S'anul·la",
				delete: "S'esborra",
				keep: "Es conserva",
				pending: "Pendent",
				store: "S'arxiva"
			};
		}
		parseVotes() {
			var pattern = /((?<discard_begin><s(?:trike)?>)? *(?: *\*? *)?\{\{ ?(?<vote>aprovaci(?:ó|\\u00f3)|objecci(?:ó|\\u00f3)|suport|assumible|indiferent|consentible|rebuig|nsnc|en contra|a favor) ?\}\} *(?<discard_end><\/s(?:trike)?>)?)/gmi;
			var match, revoked = 0, votes = {};
			// console.log(this.body);
			while ((match = pattern.exec(this.body)) !== null) {
			    if (match.index === pattern.lastIndex)
			        pattern.lastIndex++;
			    if (match.groups)
			    	if(!match.groups.discard_begin && !match.groups.discard_end) {
				    	var vote = Wikistorm.utils.simplifyChars(match.groups.vote);
				    	if (!Object.keys(votes).includes(vote))
				    		votes[vote] = 0;
				    	votes[vote]++;
			    	} else
				    	revoked++;
			}
			this.votes = votes;

			// Resum
			var pos = [], neg = [], abst = [];
			Object.entries(votes).forEach(([key, val]) => {
				if (this.posKeys.includes(key)) {
					pos.push(val);
				} else if (this.negKeys.includes(key)) {
					neg.push(val);
				} else if (this.absKeys.includes(key)) {
					abst.push(val);
				} else {
					console.log('vot desconegut', key, val);
				}				
			});
			
			var p = pos.length > 0 ? 
				pos.reduce((last, curr) => {return last + curr}) : 0;
			var n = neg.length > 0 ?
				neg.reduce((last, curr) => {return last + curr}) : 0;
			var a = abst.length > 0 ?
				abst.reduce((last, curr) => {return last + curr}): 0;

			this.voteSummary = {
				positive: p,
				negative: n,
				abstentions: a,
				revoked: revoked
			};

			// console.log('votes', this.votes);
			// console.log('resum', this.voteSummary);
		}
		parsePromotion() {
			var pattern = /\* *.*?\[\[(?:us(?:uari|er)|\{\{ns:2\}\}):(?<user>[^|]+?)\|(?:[^\]]+?)\]\].*?[\d:]{5}, (?<day>\d\d?) (?<month>[a-zç]{3,4}) (?<year>\d{4}) \(CES?T\)(?: \(proponent\))?/i;
			var match = pattern.exec(this.body);
			if (match){
				var pr = match.groups;
				pr.date = new Date(
					pr.year, Wikistorm.utils.monthToIndex(pr.month), pr.day
				);
				// Esborrem propietats innecessàries.
				['year', 'month', 'day'].forEach((item) => {delete pr[item]});
				
				var delta = new Wikistorm.utils.DateDiff();
				delta.setDate(pr.date);
				delta.calculateDifference();
				pr.datediff = delta.toObject();
				
				this.promotion = pr;
				// console.log('promotion', this.promotion);
			}
		}
		setAward() {
			if( /\{\{anul·lada\}\}\s*(?!<\/s(?:trike)?>)/gi.test(this.body) ) 
				result = this.availableResults.cancel;
	        let date = this.promotion.date;
	        var result = "";
	        let allVotes  = this.voteSummary.positive + this.voteSummary.negative;
	        let ratio = 0.75 * allVotes;
	        let ratio7d = 0.75 * allVotes;
	        let ratio14d = 0.64 * allVotes;
	        let diff = new DateDiff();
	        diff.setDate(date);
	        diff.calculateDifference();
	        let diffToText = diff.toString();
	        let diffToObject = diff.toObject();
	        
	        if (!result) { 
		        if (diffToObject.days >= 4){
	            	if (this.voteSummary.positive >= 5 && this.voteSummary.negative == 0)
	            		result = this.availableResults.delete;
	            	if (this.voteSummary.negative >= 5 && this.voteSummary.positive == 0)
	            		result = this.availableResults.keep;
				}
				if (diffToObject.days != 0 || ratio14d != 0) {
	            	if (diffToObject.days >= 7 && result == "") {
						if (this.voteSummary.positive >= ratio7d)
							result = this.availableResults.delete;
						if (this.voteSummary.negative >= ratio7d)
							result = this.availableResults.keep;
					}
					if (diffToObject.days >= 14 && result == "") {
						if (this.voteSummary.positive >= ratio14d)
							result = this.availableResults.delete;
						if (this.voteSummary.negative >= ratio14d)
							result = this.availableResults.keep;
					}
					if (diffToObject.days >= 14 && result == "") {
						if (
							this.voteSummary.positive < ratio14d &&
		                    this.voteSummary.negative < ratio14d
		                )
		                    result = this.availableResults.store;
					}
	        	}
        	}
			// En qualsevol altre cas:
			if (!result) 
				result = this.availableResults.pending;
			this.award = {
				ratio: ratio,
				ratio7d: ratio7d,
				ratio14d: ratio14d,
				text: diffToText,
				obj: diffToObject,
				result: result 
			};
		}
	}
	Wikistorm.utils.ArticleForDeletion = ArticleForDeletion;
})();