User:Yair rand/interwikiwatchlist2.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.
// newNode from [[wikt:Mediawiki:Common.js]], JsMwApi from [[wikt:WT:EDIT]].
// Previous version (works without enhanced RC) at [[User:Yair rand/interwikiwatchlist.js]].
// To enable, turn on "Enhanced recent changes (requires JavaScript)" 
// in [[Special:Preferences#mw-prefsection-rc]], and add 
// importScript ("User:Yair rand/interwikiwatchlist2.js"); 
// to [[Special:MyPage/common.js]].

// NOTE: this script is buggy and does not work on certain browsers.
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)
			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('wgPageName') == "Special:Watchlist" && 'localStorage' in window && jQuery(document).ready(function(){
  function doubledigits(n){return (+n)<10?'0'+n:''+n}
  var v = document.getElementById("mw-watchlist-options") || $(".mw-specialpage-summary")[ 0 ];
  var qw, er=['Wikipedia','Wiktionary','Wikibooks','Wikisource','Wikiquote','Wikiversity','Wikinews','Meta-Wiki','Commons','Wikispecies','Mediawiki'], cv, bn, sd;
  var wspan;
  v.appendChild(newNode('hr'));
  v.appendChild(newNode('span', 'Interwiki watchlists: ', wspan = newNode('span'), newNode('a','(+new watchlist)',{href:"#",click:function(){
    v.lastChild.lastChild.style.display='none';
    v.appendChild(newNode('form',
      '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':'/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 <=6 || !bn.value){
          bn.parentNode.lastChild.innerHTML = bn.value?"Choose a valid language code.":"Enter watchlist token.";
          return false;
          }
        var importedurl=(qw.value > 6?(qw.value==7?"meta.wikimedia":qw.value==8?'commons.wikimedia':qw.value==9?'species.wikimedia':'mediawiki'):cv.value+'.'+er[qw.value].toLowerCase());
        localStorage['importedwatchlists'+mw.config.get('wgUserName')] = (localStorage['importedwatchlists'+mw.config.get('wgUserName')]?localStorage['importedwatchlists'+mw.config.get('wgUserName')]+"|":"")+importedurl;
        localStorage['importedwatchlist'+mw.config.get('wgUserName')+importedurl+'token']=bn.value;
        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 >6){
        sd.href = "//"+(qw.value > 6?(qw.value==7?"meta.wikimedia":qw.value==8?'commons.wikimedia':qw.value==9?'species.wikimedia':'mediawiki'):cv.value+'.'+er[qw.value].toLowerCase())+".org/wiki/Special:Preferences#mw-prefsection-watchlist";
        }
      }
    cv.onchange=qw.onchange=df;
    }})));
  for(var k = localStorage['importedwatchlists'+mw.config.get('wgUserName')]?localStorage['importedwatchlists'+mw.config.get('wgUserName')].split("|"):[], ii=0; ii < k.length; ii++){
    function st(rt){
      var tkn = localStorage['importedwatchlist'+mw.config.get('wgUserName')+rt+'token'], project = location.protocol+"//"+rt+".org/";
      wspan.appendChild(newNode('span',project, ' ', newNode('a','(remove)',{click:function(){
        localStorage.removeItem('importedwatchlist'+mw.config.get('wgUserName')+rt+'token');
        localStorage.removeItem('importedwatchlist'+mw.config.get('wgUserName')+rt+'hidden');
        localStorage['importedwatchlists'+mw.config.get('wgUserName')] = localStorage['importedwatchlists'+mw.config.get('wgUserName')].replace(rt,'').replace(/(^\||\|\||\|$)/,'');
        location.reload()
        }}),', '))
      var d = new Date(+new Date()+new Date().getTimezoneOffset()*60000-mw.user.options.get('watchlistdays')*24*60*60*1000); d = d.getFullYear()+'-'+doubledigits(d.getMonth()+1)+'-'+doubledigits(d.getDate())+"T"+doubledigits(d.getHours())+":"+doubledigits(d.getMinutes())+":"+doubledigits(d.getSeconds())+"Z";
      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|sizes',wllimit:500,wlend:d},function(r){
/*
        var b=newNode('div',{'style':'display:'+
          (localStorage['importedwatchlist'+mw.config.get('wgUserName')+rt+'hidden']?'none;':'block;')
          });
*/
        var g = r && r.query && r.query.watchlist;
        if(!g) g = [];
        for(var i = 0; i < g.length; i++){try{
          var zx = newNode('span',{class:'comment'}); zx.innerHTML = g[i].parsedcomment && ' ('+g[i].parsedcomment.replace(/\ href\=\"\//g,' href="'+project)+')';
          var date = (new Date(+new Date(g[i].timestamp)+new Date().getTimezoneOffset()*60000)), day = date.getDate(), month = date.getMonth(), time = g[i].timestamp.match(/\d\d\:\d\d/);time=time&&time[0];
          var sizediff = g[i].newlen-g[i].oldlen;
          var table = newNode('table',{'class':'mw-enhanced-rc'},newNode('tbody',newNode('tr',newNode('td',{'class':"mw-enhanced-rc"},newNode('span',{"class":"mw-enhancedchanges-arrow-space"}),
            ("new" in g[i]?newNode("abbr",{class:"newpage"},"N"):" "),
            ("bot" in g[i]?newNode("abbr",{class:"botedit"},"b"):"minor" in g[i]?newNode("abbr",{class:"minoredit"},"m"):" "),
            "       "+time+" "),newNode('td',
            newNode('a',g[i].title,{class:'extiw',href:project+"wiki/"+g[i].title}),
            ' (',
            newNode('a','diff',{href:project+"w/index.php?title="+g[i].title+"&curid="+g[i].pageid+"&diff="+g[i].revid}),
            ' | ',
            newNode('a','hist',{href:project+"w/index.php?title="+g[i].title+"&curid="+g[i].pageid+"&action=history"}),
            ') . . ',
            newNode(Math.abs(sizediff)>500?'strong':'span',{class:'mw-plusminus-'+(sizediff>0?'pos':'neg')},'('+(sizediff>0?"+":"")+sizediff+")"),
            ' . . ',
            newNode('a',{class:'extiw',href:project+"wiki/User:"+g[i].user},g[i].user),
            ' (',
            newNode('a',{class:'extiw',href:project+"wiki/User talk:"+g[i].user},'Talk'),
            ' | ',
            newNode('a',{class:'extiw',href:project+"wiki/Special:Contributions/"+g[i].user},'contribs'),
            ') ',
            zx
            ))));
          for(var ii = $(".mw-changeslist")[ 0 ].firstChild; ii; ii = ii.nextSibling){
            if(ii.nodeName == "H4"){
              var hdate = new Date(ii.innerText || ii.textContent);
              if(hdate.getMonth() == month && hdate.getDate() == day){
                for(;ii && ii.nodeName != "DIV"; ii = ii.nextSibling);
                for(var trs = $(ii).find('tr:first-child'), iii = 0; true; iii++){
                  if(iii >= trs.length){
                    trs[iii-1].parentNode.parentNode.parentNode.appendChild(table);
                    break;
                    }
                  var tds = trs[iii].getElementsByTagName('td'),
                	td = tds[2]&&tds[2].className=='mw-enhanced-rc'?tds[2]:tds[1];
                  //if( +(((td.innerText || td.textContent).match(/\d/g)||[]).join("")) < time){
                  try{
                  	var match = (td.innerText || td.textContent).match(/\d\d\:\d\d/g);
                  	if( match && match[0] < time){
	                    trs[iii].parentNode.parentNode.parentNode.insertBefore(table, trs[iii].parentNode.parentNode);
	                    break;
                    }}catch(a){
                    	throw new Error( 22, a, trs[iii].parentNode.parentNode );
                	}
                  }
                break;
                }
              }
            if(ii.className == 'printfooter'){
              ii.parentNode.insertBefore(newNode("h4", date.getDate()+' '+['January','February','March','April','May','June','July','August','September','October','November','December'][date.getMonth()]+' '+date.getFullYear()), ii);
              ii.parentNode.insertBefore(newNode('div', table), ii);
              }
            }
          }catch(err){window.console&&console.log(err.stack)}}
        });
      }
    st(k[ii]);
    }
  })