User:Yair rand/interwikiwatchlist.js

// newNode from wikt:Mediawiki:Common.js, JsMwApi from wikt:WT:EDIT,

// interwiki watchlist from wikt:User:Yair rand/superwatchlist.js. To enable, add

// importScript ("User:Yair rand/interwikiwatchlist.js");

// to Special:MyPage/common.js. You should see an "Import watchlist" button

// in the top-right corner of Special:Watchlist. For more info see the notes at the

// top of http://en.wikipedia.org/wiki/User_talk:Yair_rand/interwikiwatchlist.js

function newNode(tagname){

var node = document.createElement(tagname);

for( var i=1;i

if(typeof arguments[i] == 'string'){ //Text

node.appendChild( document.createTextNode(arguments[i]) );

}else if(typeof arguments[i] == 'object'){

if(arguments[i].nodeName){ //If it is a DOM Node

node.appendChild(arguments[i]);

}else{ //Attributes (hopefully)

for(var j in arguments[i]){

if(j == 'class'){ //Classname different because...

node.className = arguments[i][j];

}else if(j == 'style'){ //Style is special

node.style.cssText = arguments[i][j];

}else if(typeof arguments[i][j] == 'function'){ //Basic event handlers

try{ node.addEventListener(j,arguments[i][j],false); //W3C

}catch(e){try{ node.attachEvent('on'+j,arguments[i][j],"Language"); //MSIE

}catch(e){ node['on'+j]=arguments[i][j]; }}; //Legacy

}else{

node.setAttribute(j,arguments[i][j]); //Normal attributes

}

}

}

}

}

return node;

}

//JsMwApi documentation is at http://en.wiktionary.org/wiki/User_talk:Conrad.Irwin/Api.js

function JsMwApi (api_url, request_type) {

if (!api_url)

{

if (typeof(true) === 'undefined' || true == false)

throw "Local API is not usable.";

api_url = mw.config.get('wgScriptPath') + "/api.php";

}

if (!request_type)

{

if (api_url.indexOf('http://') == 0 || api_url.indexOf('https://') == 0 || api_url.indexOf('//') == 0)

request_type = "remote";

else

request_type = "local";

}

function call_api (query, callback)

{

if(!query || !callback)

throw "Insufficient parameters for API call";

query = serialise_query(query);

if(request_type == "remote")

request_remote(api_url, query, callback, call_api.on_error || default_on_error);

else

request_local(api_url, query, callback, call_api.on_error || default_on_error);

}

var default_on_error = JsMwApi.prototype.on_error || function (xhr, callback, res)

{

if (typeof(console) != 'undefined')

console.log([xhr, res]);

callback(null);

}

function get_xhr ()

{

try{

return new XMLHttpRequest();

}catch(e){ try {

return new ActiveXObject("Msxml2.XMLHTTP");

}catch(e){ try {

return new ActiveXObject("Microsoft.XMLHTTP");

}catch(e){

throw "Could not create an XmlHttpRequest";

}}}

}

function request_local (url, query, callback, on_error)

{

var xhr = get_xhr();

xhr.open('POST', url + '?format=json', true);

xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

xhr.send(query);

xhr.onreadystatechange = function ()

{

if (xhr.readyState == 4)

{

var res;

if (xhr.status != 200)

res = {error: {

code: '_badresponse',

info: xhr.status + " " + xhr.statusText

}};

else

{

try

{

res = JSON.parse("("+xhr.responseText+")");

}

catch(e)

{

res = {error: {

code: '_badresult',

info: "The server returned an incorrectly formatted response"

}};

}

}

if (!res || res.error || res.warnings)

on_error(xhr, callback, res);

else

callback(res);

}

}

}

function request_remote (url, query, callback, on_error)

{

if(! window.__JsMwApi__counter)

window.__JsMwApi__counter = 0;

var cbname = '__JsMwApi__callback' + window.__JsMwApi__counter++;

window[cbname] = function (res)

{

if (res.error || res.warnings)

on_error(null, callback, res);

else

callback(res);

}

var script = document.createElement('script');

script.setAttribute('type', 'text/javascript');

script.setAttribute('src', url + '?format=json&callback=window.' + cbname + '&' + query);

document.getElementsByTagName('head')[0].appendChild(script);

}

function serialise_query (obj)

{

var amp = "";

var out = "";

if (String(obj) === obj)

{

out = obj;

}

else if (obj instanceof Array)

{

for (var i=0; i < obj.length; i++)

{

out += amp + serialise_query(obj[i]);

amp = (out == || out.charAt(out.length-1) == '&') ? : '&';

}

}

else if (obj instanceof Object)

{

for (var k in obj)

{

if (obj[k] === true)

out += amp + encodeURIComponent(k) + '=1';

else if (obj[k] === false)

continue;

else if (obj[k] instanceof Array)

out += amp + encodeURIComponent(k) + '=' + encodeURIComponent(obj[k].join('|'));

else if (obj[k] instanceof Object)

throw "API parameters may not be objects";

else

out += amp + encodeURIComponent(k) + '=' + encodeURIComponent(obj[k]);

amp = '&';

}

}

else if (typeof(obj) !== 'undefined' && obj !== null)

{

throw "An API query can only be a string or an object";

}

return out;

}

// Make JSON.parse work

var JSON = (typeof JSON == 'undefined' ? new Object() : JSON);

if (typeof JSON.parse != 'function')

JSON.parse = function (json) { return eval('(' + json + ')'); };

// Allow .prototype. extensions

if (JsMwApi.prototype)

{

for (var i in JsMwApi.prototype)

{

call_api[i] = JsMwApi.prototype[i];

}

}

return call_api;

}

mw.config.get('wgCanonicalSpecialPageName') == "Watchlist" && $(document).ready(function () {

var v = document.getElementById("mw-watchlist-options");

if(!v) return

v = v.parentNode.insertBefore(newNode('div'), v.nextSibling)

var opt = JSON.parse(mw.user.options.values['userjs-YRIWW'] || "{}");

function updateOpt( cb ) {

$.get( "/w/api.php?format=json&action=query&meta=tokens", function( r ) {

$.post( "/w/api.php?format=json&action=options&change=userjs-YRIWW=" + JSON.stringify( opt ), {token : r.query.tokens.csrftoken }, function() {

cb && cb();

})

})

}

for ( var i in opt ) {

( function( i ) {

var tkn = opt[ i ].token,

project = "//" + i + ".org/";

JsMwApi( project + "w/api.php" )({

action: 'query',

list: 'watchlist',

wlowner: mw.config.get('wgUserName'),

wltoken: tkn,

wlexcludeuser: mw.user.options.get('watchlisthideown') ? mw.config.get('wgUserName') : 'Example',

wlprop: 'title|flags|user|parsedcomment|timestamp|ids',

continue: ''

}, function ( r ) {

t = r

var b = newNode('ul', {

'style': 'display:' +

( opt[ i ].hidden ? 'none;' : 'block;' )

});

v.parentNode.insertBefore(b, v.nextSibling);

v.parentNode.insertBefore(newNode('h3', project + " watchlist", newNode('span', {

'style': 'font-size:12px;'

}, ' [', newNode('a', 'Remove', {

style: 'cursor:pointer;',

click: function () {

delete opt[ i ];

updateOpt( function() { location.reload(); } );

}

}), '] [', newNode('a', opt[ i ].hidden ? 'Expand ▼' : 'Collapse ▲', {

'style': 'cursor:pointer;',

'click': function () {

if ( b.style.display == 'none') {

b.style.display = 'block';

this.innerHTML = "Collapse ▲"; // todo: replace innerHTML with something more sanitary, hm?

opt[ i ].hidden = false;

updateOpt();

} else {

b.style.display = 'none';

this.innerHTML = "Expand ▼";

opt[ i ].hidden = true;

}

updateOpt();

}

}), ']')), v.nextSibling);

var g = r.query.watchlist;

for (var ii = 0; ii < g.length; ii++) {

var zx = newNode('span', {

class: 'comment'

}), item = g[ ii ];

zx.innerHTML = ' (' + item.parsedcomment.replace(/\ href\=\"\//g, ' href="' + project) + ')';

b.appendChild(newNode('li', '(',

newNode('a', 'diff', {

href: project + "w/index.php?title=" + item.title + "&curid=" + item.pageid + "&diff=" + item.revid

}),

' | ',

newNode('a', 'hist', {

href: project + "w/index.php?title=" + item.title + "&curid=" + item.pageid + "&action=history"

}),

') . . ',

newNode('a', item.title, {

href: project + "wiki/" + item.title

}),

'; ' + item.timestamp.match(/\d\d\:\d\d/)[0] + ' . . ',

item.user,

zx))

}

})

})( i );

}

var qw, er = ['Wikipedia', 'Wiktionary', 'Wikibooks', 'Wikisource', 'Wikiquote', 'Wikiversity', 'Wikinews', 'Wikivoyage', 'Meta-Wiki', 'Commons', 'Wikispecies', 'Mediawiki', 'Wikidata'],

domains = ['meta.wikimedia', 'commons.wikimedia', 'species.wikimedia', 'www.mediawiki', 'www.wikidata'],

cv, bn, sd;

document.getElementById('firstHeading').appendChild(newNode('a', "Import watchlist", {

'style': 'padding-left:10px;cursor:pointer; float:right; font-size: 13px;',

click: function () {

v.innerHTML = '';

v.appendChild(newNode('form', {

'style': 'display: inline;'

},

'Language: ', cv = newNode('input', {

size: 3

}),

' Project: ', qw = newNode('select'), newNode('br'),

'Watchlist token ', newNode('small', '(can be found be found at ', sd = newNode('a', 'Special:Preferences', {

'href': '//en.wikipedia.org/wiki/Special:Preferences#mw-prefsection-watchlist'

}), ' in the Watchlist section)'), ': ', bn = newNode('input'),

newNode('input', {

'type': 'submit',

'value': 'Import watchlist'

}), newNode('span', {

style: 'color:red;'

}))).onsubmit = function () {

if (!/^[a-z]{2,3}(-?[a-z]{2,3})?$/.test(cv.value) && qw.value <= 7 || !bn.value) {

bn.parentNode.lastChild.innerHTML = bn.value ? "Choose a valid language code." : "Enter watchlist token."

return false

}

var importedurl = (qw.value > 7 ? domains[ qw.value - 7 ] : cv.value + '.' + er[qw.value].toLowerCase())

opt[ importedurl ] = { 'token' : bn.value };

updateOpt( function(){ location.reload(); })

return false;

}

for (var i = 0; i < er.length; i++) {

qw.appendChild(newNode('option', {

'value': i

}, er[i]))

};

function df() {

if (/^[a-z]{2,3}(-?[a-z]{2,3})?$/.test(cv.value) || qw.value > 7) {

sd.href = "//" + (qw.value > 7 ? domains[ qw.value - 7 ] : cv.value + '.' + er[qw.value].toLowerCase()) + ".org/wiki/Special:Preferences#mw-prefsection-watchlist";

}

}

cv.onchange = qw.onchange = df;

}

}))

})