Jump to content

User:Fixuture/gadgets/hollis.js

From Wikipedia, the free encyclopedia
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.
"use strict"; // <nowiki> [[User:Kephir/gadgets/hollis.js]]
//Potential cause/fix: min wait time between requests;
//https://www.mediawiki.org/wiki/API:Etiquette#Request_limit (3 sections)
//https://www.mediawiki.org/wiki/API:FAQ#call_the_API.3F
/*jshint shadow:true, scripturl:true, loopfunc:true, latedef:true, undef:true */
/*global mw, jQuery */
(function(){

function el(tag, child, attr, events) {
	var node = document.createElement(tag);

	if (child) {
		if (typeof child !== 'object')
			child = [child];
		for (var i = 0; i < child.length; ++i) {
			var ch = child[i];
			if ((ch === void(null)) || (ch === null) || (ch === false))
				continue;
			else if (typeof ch !== 'object')
				ch = document.createTextNode(String(ch));
			node.appendChild(ch);
		}
	}

	if (attr) for (var key in attr) {
		node.setAttribute(key, String(attr[key]));
	}

	if (events) for (var key in events) {
		node.addEventListener(key, events[key], false);
	}

	return node;
}

if ((window.wgCanonicalSpecialPageName === "Watchlist") && !mw.user.options.get('extendwatchlist') && !window.kephirHollisLeaveWatchlistAlone)
mw.loader.using(['mediawiki.api', 'mediawiki.user', 'mediawiki.Title', 'mediawiki.Uri'], function () {

var api = new mw.Api();
var chlist = document.getElementsByClassName('mw-changeslist')[0];
var titles = chlist.getElementsByClassName('mw-title');
var titlemap = {};
var finishedTitles = [];

var hideopts = {
	bot: Number(mw.util.getParamValue('hideBots')      || mw.user.options.get('watchlisthidebots')),
	ano: Number(mw.util.getParamValue('hideAnons')     || mw.user.options.get('watchlisthideanons')),
	liu: Number(mw.util.getParamValue('hideLiu')       || mw.user.options.get('watchlisthideliu')),
	own: Number(mw.util.getParamValue('hideOwn')       || mw.user.options.get('watchlisthideown')),
	pat: Number(mw.util.getParamValue('hidePatrolled') || mw.user.options.get('watchlisthidepatrolled')),
	min: Number(mw.util.getParamValue('hideMinor')     || mw.user.options.get('watchlisthideminor')),
};

for (var i = 0; i < titles.length; ++i) {
	var links = titles[i].parentNode.getElementsByTagName('a');
	for (var j = 0; j < links.length; ++j) {
		var href = new mw.Uri(links[j].href);
		if (href.query.oldid && href.query.diff) {
			titlemap[String(parseInt(href.query.diff, 10))] = links[j];
			break;
		}
	}
}

function makeLink(title, pageid, revid, oldid) {
	return mw.util.getUrl(title, { "curid": pageid, "diff": revid, "oldid": oldid });
}

function prepareLink(link, ready) {
	if (!/^javascript/.test(link.href))
		return;
	if (link.busy)
		return;
	link.busy = true;

	api.get({
		action: 'query',
		pageids: link.pageinfo.pageid,
		prop: 'revisions',
		rvprop: 'ids',
		rvstart: link.pageinfo.notificationtimestamp,
		// rvstartid: link.pageinfo.old_revid,
		rvdir: 'older',
		rvlimit: 2
	}, {
		success: function (result) {
			if (result.error) {
				alert(result.error);
				link.href = 'javascript:void("API_ERROR_WHILE_ACQUIRING_LINK:CODE=' + result.error.code + '");';
				link.busy = false;
				link.style.color = 'red';
				console.error(result.error);
				return;	
			}
			var revs = result.query.pages[link.pageinfo.pageid].revisions;
			link.href = makeLink(link.pageinfo.title, link.pageinfo.pageid, link.pageinfo.revid, (revs[1] || revs[0]).revid);
		},
		error: function () {
			link.href = 'javascript:void("ERROR_WHILE_ACQUIRING_LINK");';
			link.style.opacity = '0.5';
			link.busy = false;
			link.style.color = 'red';
			console.error(arguments);
		}
	});
}

var havePatrol = false;

function grabWatchlist(cont) {
	var query = {
		action: 'query',
		list: 'watchlist',
		wlprop: 'ids|title|timestamp|notificationtimestamp' + (havePatrol ? '|patrol' : ''), // why does it have to error? could the API not just ignore wlprop=patrol?
		wltype: 'edit',
		wlshow: ''
	};

	if (hideopts.own) query.wlexcludeuser = mw.config.get('wgUserName');
	if (hideopts.bot) query.wlshow += '|!bot';
	if (hideopts.ano) query.wlshow += '|!anon';
	if (hideopts.liu) query.wlshow += '|anon';
	if (hideopts.min) query.wlshow += '|!minor';

	if (cont) {
		for (var key in cont) {
			query[key] = cont[key];
		}
	}

	api.get(query, {
		success: function (result) {
			for (var i = 0; i < result.query.watchlist.length; ++i) {
				var item = result.query.watchlist[i];
				if (!titlemap[String(item.revid)])
					if (hideopts.pat && ('patrolled' in item))
						continue;
					else
						return; // we seem to have reached the end.
				if (!item.notificationtimestamp) // seen it. skip.
					continue;

				var seenlink;
				if (item.notificationtimestamp !== item.timestamp) {
					seenlink = el('a', ['since last seen'], {
						"href": 'javascript:void("PLEASE_WAIT_AND_TRY_AGAIN");'
					}, {
						"mouseover": function () {
							prepareLink(this);
						},
						"mousedown": function () {
							prepareLink(this);
						},
						"click": function () {
							prepareLink(this, function (href) {
								location.href = href;
							});
						}
					});
					seenlink.pageinfo = item;
				} else {
					if (!window.kephirHollisShowRedundant)
						continue;
					seenlink = el('a', ['since last seen'], {
						"href": makeLink(item.title, item.pageid, item.revid, item.oldid)
					});
					finishedTitles.push(item.title);
				}

				var difflink = titlemap[String(item.revid)];
				difflink.parentNode.insertBefore(seenlink, difflink);
				difflink.parentNode.insertBefore(document.createTextNode('\xa0| '), difflink);
			}
			
			if (!('batchcomplete' in result))
				alert(result);
				setTimeout(grabWatchlist(result["continue"]), 5000);
		}
	});
}

if (hideopts.pat)
	mw.user.getRights(function (rights) {
		havePatrol = (rights.indexOf("patrol") !== -1);
		setTimeout(grabWatchlist(), 5000);
		alert(finishedTitles.length() + 'B');
	});
else
	setTimeout(grabWatchlist(), 5000);
	alert(finishedTitles.length() + 'C');

});
else if (mw.util.getParamValue('diff') && mw.util.getParamValue('diff') && document.getElementsByClassName('diff-multi').length && !window.kephirHollisLeaveDiffsAlone)
mw.loader.using(['mediawiki.api', 'mediawiki.user', 'mediawiki.Title', 'mediawiki.Uri', 'mediawiki.language.months'], function () {

var haveRevdel = false;
var haveBlock  = false;

function fmtDate(date) {
	// XXX: uses browser's time zone instead of preferences
	date = new Date(date);
 
	switch (mw.user.options.get('date')) {
	case 'dmy'     : return date.toLocaleTimeString() + ', ' + date.getDate() + ' ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getFullYear();
	case 'mdy'     : return date.toLocaleTimeString() + ', ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getFullYear() + ', ' + date.getDate();
	case 'ymd'     : return date.toLocaleTimeString() + ', ' + date.getFullYear() + ' ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getDate();
	case 'default' : return date.toLocaleFormat();
	case 'ISO 8601': return date.toISOString(); 
	}
}

var api = new mw.Api();

var linkwrap, linklabel, revsform;
var dm = document.getElementsByClassName('diff-multi')[0]; // XXX: better detection
dm.appendChild(linkwrap = el('span', [
	'\xa0[',
	el('a', [linklabel = document.createTextNode('show list')], {
		"href": 'javascript:void(window.warranty);'
	}, {
		"click": function (ev) {
			if (!revsform)
			mw.user.getRights(function (rights) {
				haveRevdel = (rights.indexOf("deleterevision") !== -1);
				haveBlock  = (rights.indexOf("block") !== -1);

				var lower = Number(mw.util.getParamValue('oldid'));
				var hiher = Number(mw.util.getParamValue('diff'));
			
				if (hiher < lower) {
					var t = lower;
					lower = hiher;
					hiher = t;
				}
			
				var revstab;
				revsform = el('form', [
					el('input', null, { type: "submit", value: "View difference" }),
					' ',
					haveRevdel && el('button', ["Change visibility"], { type: "submit", name: "action", value: "revisiondelete" }),
					revstab = el('table', null, {
						"class": "wikitable", // XXX
						"style": "text-align: left; margin: 0.5em auto;"
					}),
					el('input', null, { type: "submit", value: "View difference" }),
					' ',
					haveRevdel && el('button', ["Change visibility"], { type: "submit", name: "action", value: "revisiondelete" }),
				], { action: mw.config.get('wgScript'), style: "display: none; margin: 0.5em auto;" });
	
				revstab.appendChild(el('tr', [
					el('th', ['#']),
					el('th', ['←']),
					el('th', ['→']),
					el('th', ['Timestamp']),
					el('th', ['Author']),
					el('th', ['Summary'])
				]));
				linkwrap.parentNode.appendChild(revsform);

				var k = 0;
				function grabHistory(cont) {
					var query = {
						action: 'query',
						pageids: mw.config.get('wgArticleId'),
						prop: 'revisions',
						rvprop: 'ids|parsedcomment|user|timestamp|tags|size|flags',
						rvstartid: hiher,
						rvendid: lower,
						rvdir: 'older',
						rvlimit: 'max',
						'continue': ""
					};
					if (cont) {
						for (var key in cont) {
							query[key] = cont[key];
						}
					}
					api.get(query, {
						success: function (result) {
							var wgPageName = mw.config.get('wgPageName');
							if (result.error) {
								mw.util.jsMessage('<b>API error</b>: ' + result.error.info + ' [code: <code>' + result.error.code + '</code>]');
								alert('<b>API error</b>: ' + result.error.info + ' [code: <code>' + result.error.code + '</code>]');
								return;
							}
							var revs = result.query.pages[mw.config.get('wgArticleId')].revisions;
							for (var j = 0; j < revs.length; ++j) {
								var rev = revs[j];
								var sumcell;
								var row = el('tr', [
									el('td', [k++]),
									el('td', [el('input', null, { type: "radio", value: rev.revid, name: "oldid" })]),
									el('td', [el('input', null, { type: "radio", value: rev.revid, name: "diff"  })]),
									el('td', [
										haveRevdel && el('input', null, { type: "checkbox", name: "ids[" + rev.revid + "]", value: "1" }), ' ',
										el('a', [fmtDate(rev.timestamp)], {
											href: mw.util.getUrl(wgPageName, { "oldid": rev.revid })
										}), el('br'), el('small', [
											el('a', ['diff to prev'], { href: mw.util.getUrl(wgPageName, { "oldid": rev.revid, "diff": "prev" }) }),
											' \u2022 ',
											el('a', ['next'], { href: mw.util.getUrl(wgPageName, { "oldid": rev.revid, "diff": "next" }) }),
											' \u2022 ',
											el('a', ['edit'], { href: mw.util.getUrl(wgPageName, { "oldid": rev.revid, "action": "edit" }) }),
										])
									]), 
									el('td', [
										el('a', [rev.user], { href: mw.util.getUrl('User:' + rev.user) }), el('br'),
										el('small', [
											el('a', ['talk'], { href: mw.util.getUrl('User talk:' + rev.user) }),
											' \u2022 ',
											el('a', ['contribs'], { href: mw.util.getUrl('Special:Contributions/' + rev.user) }),
											haveBlock && ' \u2022 ',
											haveBlock && el('a', ['block'], { href: mw.util.getUrl('Special:Block/' + rev.user) }),
										])
									]),
									sumcell = el('td')
								]);
								sumcell.innerHTML = rev.parsedcomment;
								revstab.appendChild(row);
							}
							if (result.continue)
								grabHistory(result['continue']);
						},
						error: function () {
							alert('<b>API error</b>: ' + result.error.info + ' [code: <code>' + result.error.code + '</code>]');
							mw.util.jsMessage('<b>Request error</b>. Details sent to console.');
							console.error(arguments);
						}
					});
				}
				
				grabHistory();
			});

			if (revsform.style.display === 'none') {
				linklabel.data = 'hide list';
				revsform.style.display = '';
			} else {
				linklabel.data = 'show list';
				revsform.style.display = 'none';
			}
		}
	}), ']'
]));

});

})();