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: ' + result.error.code + ']');

alert('API error: ' + result.error.info + ' [code: ' + result.error.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: ' + result.error.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';

}

}

}), ']'

]));

});

})();