Jump to content

User:Evad37/TimestampDiffs.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Evad37 (talk | contribs) at 12:27, 27 November 2019 (remove portlet link; just do it). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/***************************************************************************************************
 TimestampDiffs --- by Evad37
 > Links timestamp to diffs on discussion pages
----------------------------------------------------------------------------------------------------
***************************************************************************************************/
/* jshint esversion: 5, laxbreak: true, undef: true, maxerr: 999*/
/* globals console, window, $, mw, OO, extraJs */
// <nowiki>

$.when(
	// Resource loader modules
	mw.loader.using([
		'mediawiki.util', 'mediawiki.api', 'mediawiki.Uri',
		'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows'
	]),
	// Page ready
	$.ready
).then(function() {
	var config = {
		scriptVersion: "1.0.0",
		mw: mw.config.get(['wgNamespaceNumber', 'wgPageName']),
		wgMonthNames: ["", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
	};
	var isTalkPage = config.mw.wgNamespaceNumber %2 === 1;
	var isProjectPage = config.mw.wgNamespaceNumber === 4;
	if( !isTalkPage && !isProjectPage ) {
		// only operate in Special: namespace
		return;
	}

	var API = new mw.Api( {
		ajax: {
			headers: { 
				'Api-User-Agent': 'TimestampDiffs/' + config.scriptVersion + 
					' ( https://en.wikipedia.org/wiki/User:Evad37/TimestampDiffs )'
			}
		}
	} );

	var messagesPromise = API.get( {
		action: 'query',
		meta: 'allmessages',
		ammessages: [ "Diff" ],
		amenableparser: 1,
		amargs: mw.config.get('wgUserName')
	} ).then(function(response) {
		var messages = {};
		response.query.allmessages.forEach(function(message) {
			messages[message.normalizedname] = message['*'];
		});
		return messages;
	});

	var revisionsPromise = API.get({
		action: "query",
		format: "json",
		prop: "revisions",
		titles: config.mw.wgPageName,
		indexpageids: 1,
		rvprop: "timestamp|ids",
		rvlimit: "500"
	}).then(function(response) {
		var id = response.query.pageids[0];
		return response.query.pages[id].revisions;
	});

	var dateFromSigTimestamp = function(sigTimestamp) {
		var pattern = /(\d\d\:\d\d), (\d{1,2}) (\w+) (\d\d\d\d) \(UTC\)/;
		var parts = pattern.exec(sigTimestamp);
		if ( parts === null ) {
			return NaN;
		}
		var year = parts[4];
		var monthIndex = config.wgMonthNames.indexOf(parts[3]);
		if ( monthIndex === -1 ) {
			return NaN;
		}
		var month = ( monthIndex < 10 )
			? '0' +  monthIndex
			: monthIndex;
		var day = ( parts[2].length === 1 )
			? '0' + parts[2]
			: parts[2];
		var time = 'T' + parts[1] + 'Z';
		var iso8601DateString = year + '-' + month + '-' + day + time;
		return Date.parse(iso8601DateString) && new Date(iso8601DateString);
	};
	/**
	 * 
	 * @param {string[]|number[]} array 
	 * @returns {string[]|number[]} array with only unique values
	 * e.g. `uniqueArray(["apple", "apple", "orange"])` returns `["apple", "orange"]`
	 */
	function uniqueArray(array) {
		if (!array || !Array.isArray(array) || array.length === 0)
			return [];
		var seen = {};
		var unique = [];
		array.forEach(function(item) {
			if (!seen[item]) {
				unique.push(item);
				seen[item] = true;
			}
		});
		return unique;
	}

	$.when(messagesPromise, revisionsPromise).then(function(messages, revisions) {
		mw.util.$content.find(':contains(" (UTC)")').not(':has(:contains(" (UTC)"))').each(function() {
			var $el = $(this);
			var htmlString = $el.html();
			var timestamps = htmlString.match(/\d\d\:\d\d, \d{1,2} \w+ \d\d\d\d \(UTC\)/);
			if (timestamps.length === 0) {
				return;
			}
			uniqueArray(timestamps).forEach(function(timestamp) {
				var rev = revisions.find(function(revision) { // Try for exact match
					return dateFromSigTimestamp(timestamp).getTime() === new Date(revision.timestamp.replace(/\:\d\dZ/,":00Z")).getTime();
				}) || revisions.find(function(revision) { // Try for an "off by 1 second" match
					return new Date(revision.timestamp.replace(/\:\d\dZ/,":00Z")).getTime() - dateFromSigTimestamp(timestamp).getTime() <= 1010;
				});
				if (!rev) {
					return;
				}
				var linkedTimestamp = $('<a>')
					.text(timestamp)
					.attr({
						"href": mw.util.getUrl("Special:Diff/"+rev.revid),
						"title": messages.diff
					})
					.get(0).outerHTML;

				htmlString = htmlString.replace(
					new RegExp(mw.util.escapeRegExp(timestamp),'g'),
					linkedTimestamp
				);
			});
			$el.html(htmlString);
		});
	}).catch(function(code, err) {
		console.error("TimestampDiffs", {"code": code, "error": err});
	});
});
// </nowiki>