User:Fixuture/gadgets/hollis.js

"use strict"; // 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('API error: ' + result.error.info + ' [code: ]');								alert('API error: ' + result.error.info + ' [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('API error: ' + result.error.info + ' [code:  ]');							mw.util.jsMessage('Request error. 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'; }		}	}), ']' ]));

});

});