User:Yair rand/interwikiwatchlist.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
Documentation for this user script can be added at User:Yair rand/interwikiwatchlist. |
// 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<arguments.length;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;
}
}))
})