User:Lupin/recentdiffs.js
From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Firefox/Mozilla/Safari: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Internet Explorer: press Ctrl-F5, Opera/Konqueror: press F5.
// <pre><nowiki> // ************************************************** // Downloader // ************************************************** window.Downloader=function(url) { // Source: http://jibbering.com/2002/4/httprequest.html this.http = false; /*@cc_on @*/ /*@if (@_jscript_version >= 5) // JScript gives us Conditional compilation, // we can cope with old IE versions. // and security blocked creation of the objects. try { this.http = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { this.http = new ActiveXObject("Microsoft.XMLHTTP"); } catch (E) { // this.http = false; } } @end @*/ if (! this.http && typeof XMLHttpRequest!='undefined') this.http = new XMLHttpRequest(); this.url = url; this.id=null; this.lastModified = null; this.callbackFunction = null; }; Downloader.prototype.send = function (x) {if (!this.http) return null; return this.http.send(x);}; Downloader.prototype.abort = function () {if (!this.http) return null; return this.http.abort();}; Downloader.prototype.runCallback = function () {this.callbackFunction(this);}; Downloader.prototype.getData = function () {if(!this.http) return null; return this.http.responseText;}; Downloader.prototype.setTarget = function () {if(!this.http) return null; this.http.open("GET", this.url, true);}; Downloader.prototype.start=function () {if(!this.http) return null; return this.http.send(null);}; Downloader.prototype.getReadyState=function () {if(!this.http) return null; return this.http.readyState;}; Downloader.prototype.getLastModifiedDate=function () { if(!this.http) return null; var lastmod=null; try { lastmod=this.http.getResponseHeader('Last-Modified'); } catch (err) {} if (lastmod) return new Date(lastmod); return null; } Downloader.prototype.setCallback = function (f) { if(!this.http) return; this.http.onreadystatechange = f; this.callbackFunction = f; }; Downloader.newDownload = function(url, id, callback) { var d=new Downloader(url); if (!d.http) return 'ohdear'; d.id=id; d.setTarget(); var f = function () { if (d.getReadyState() == 4) { d.data=d.getData(); d.lastModified=d.getLastModifiedDate(); callback(d); } }; d.setCallback(f); return d;//d.start(); }; Downloader.startDownload = function (url, id, callback, userData) { var d=Downloader.newDownload(url, id, callback); d.userData=userData; if (typeof d == typeof '' ) return d; return d.start(); }; // ************************************************** // DOM abbreviations // ************************************************** $a = function (obj, parent) { var p=(parent)?parent:document.body; if (typeof obj== 'object' && obj.length != null && obj.length > 0 && typeof obj[0] == 'object' && obj[0].nodeType!=null) { // assume it's a list of nodes for (var i=0; i<obj.length; ++i) { p.appendChild(obj[i]); } } else p.appendChild(obj); } $e=function (id) {return document.getElementById(id);}; $c=function(elt) {return document.createElement(elt);}, $t=function(txt) {return document.createTextNode(txt);}; $ee=function(nm, parent) {var p=(parent)?parent:document; return p.getElementsByTagName(nm);}; // ************************************************** // Downloadqueue // ************************************************** window.Downloadqueue=function(max) { this.max=max || 5; this.queue=[]; this.active={length: 0, highestIndex: 0}; this.timer=null; this.freq=1000; this.runFunction=Downloader.startDownload; this.runQueueHook=function() {}; this.downloadCompleteHook=function() {}; } Downloadqueue.prototype.push=function() { this.queue.push(arguments); } Downloadqueue.prototype.runQueue=function () { // document.title=['active:'+this.active.length, 'max:'+this.max, 'queuelen:'+this.queue.length].join('|'); this.runQueueHook(); if (this.active.length < this.max && this.queue.length > 0) { var newActive=this.queue.shift(); var f=newActive[2]; var savedThis=this; var idString=this.active.highestIndex++; idString=idString.toString(); this.active[idString]=newActive; ++this.active.length; // modify the third argument (the callback) so that it deletes the entry from this.active // NB this is brittle - will break if the signature of this.runFunction changes newActive[2] = function (d) { f(d); savedThis.active[idString]=null; --savedThis.active.length; savedThis.downloadCompleteHook(); }; this.activeId++; this.runFunction.apply(window, newActive); this.runQueue.apply(this, []); // run again to top up if needed } } Downloadqueue.prototype.start=function () { var savedThis=this; this.timer=setInterval(function () { savedThis.runQueue.apply(savedThis) }, this.freq); } // ************************************************** // Recentchecker // ************************************************** window.Recentchecker = function () { this.status=$c('div'); var h1=$ee('h1')[0]; h1.parentNode.insertBefore(this.status, h1.nextSibling); this.queue=new Downloadqueue(10); this.numHits=0; var savedThis=this; this.queue.runQueueHook=function () { var keys=[]; for (var k in savedThis.queue.active) { if (savedThis.queue.active[k] && k != 'length' && k != 'highestIndex') keys.push(k); } var s=[savedThis.numHits, ' diffs shown<br>', savedThis.queue.active.length, ' active downloads, keys=[', keys.join(','), ']<br>', savedThis.queue.queue.length, ' waiting'].join(''); savedThis.status.innerHTML=s; } this.queue.downloadCompleteHook=this.queue.runQueueHook; this.queue.start(); } Recentchecker.prototype.getDiffs=function () { var ret=[]; for (var i=0; i<document.links.length; ++i) { switch (document.links[i].innerHTML) { case 'diff': case '(diff)': case 'last': ret.push(document.links[i]); } } this.diffPages=ret; } Recentchecker.prototype.checkDiffs=function (re) { if (this.diffPages==null) this.getDiffs(); for (var i=0; i<this.diffPages.length; ++i) { var savedThis=this; var f=function(d) { savedThis.diffHandler.apply(savedThis, [d]); }; this.queue.push(this.diffPages[i].href, 0, f, {sourceNode: this.diffPages[i], regex: re}); } } Recentchecker.prototype.diffHandler=function (d) { var data=d.data.replace(RegExp("^<tr>.*class='diff-context'.*$", 'gm'), ''); var diffTableMatch=/<table[^>]*?class='diff'[^>]*?>(.|\n)*?<\/table>/.exec(data); if (!diffTableMatch) return; var diffTable=diffTableMatch[0]; var re=d.userData.regex; var match = ( ! re || re.exec(diffTable)); if (! match) return; this.numHits++; var diffNode=d.userData.sourceNode; var newDiv=$c('div'); newDiv.innerHTML='Match: ' + match[1] + '<br>' + match[0] + '<br>' + diffTable; var nextBrSib=nextSiblingOfType(diffNode, 'br'); if (nextBrSib && nextBrSib.nextSibling) { nextBrSib = nextBrSib.nextSibling; diffNode.parentNode.insertBefore(newDiv, nextBrSib); } else diffNode.parentNode.appendChild(newDiv); } // ************************************************** // Miscellany // ************************************************** function isNodeName(node, str) { return node.nodeName.toUpperCase() == str.toUpperCase(); } function nextSiblingOfType(node, type) { for (var n=node; n; n=n.nextSibling) { if (isNodeName(n, type)) return n; } return null; } window.gettingBadWords=false; window.badWords=null; function getBadWords() { window.gettingBadWords=true; var d= Downloader.startDownload( 'http://en.wikipedia.org/w/index.php?title=User:Lupin/badwords&action=raw&ctype=text/css', 0, processBadWords); } function processBadWords(d) { var data=d.data.split('\n'); var ret=[]; for (var i=0; i<data.length; ++i) { var s=data[i]; if (s.length==0) continue; if (s.charAt(0)=='<') continue; ret.push(s.replace(RegExp('([-|.()\\+:!,?*^${}\\[\\]])', 'g'), '\\$1')); } window.badWords=RegExp("<td class='diff-addedline'>.*(([^.\s])\1\1|\\b(" + ret.join('|') + ")\\b).*</td>", 'im'); } function runOnce(f, time) { var i=runOnce.timers.length; var ff = function () { clearInterval(runOnce.timers[i]); f() }; var timer=setInterval(ff, time); runOnce.timers.push(timer); } runOnce.timers=[]; runOnce.index=0; function filteredRecentDiffs() { if (! window.gettingBadWords) { getBadWords(); } if (! window.badWords) { runOnce(filteredRecentDiffs, 500); return; } new Recentchecker().checkDiffs(badWords); } function checkRecentDiffs() { new Recentchecker().checkDiffs(); } // ************************************************** // Installation // ************************************************** function addlilink(tabs, url, name, id, title, key){ var na = document.createElement('a'); na.href = url; na.appendChild(document.createTextNode(name)); var li = document.createElement('li'); if(id) li.id = id; li.appendChild(na); tabs.appendChild(li); if(id) { if(key && title) { ta[id] = [key, title]; } else if(key) { ta[id] = [key, '']; } else if(title) { ta[id] = ['', title]; } } // re-render the title and accesskeys from existing code in wikibits.js akeytt(); return li; } function addToolboxLink(url, name, id){ var tb = document.getElementById('p-tb').getElementsByTagName('ul')[0]; addlilink(tb, url, name, id); } function addPowerdiffLink() { addToolboxLink('#', 'Show filtered diffs', 'toolbox_filtereddiffs'); $e('toolbox_filtereddiffs').onclick=filteredRecentDiffs; addToolboxLink('#', 'Show all diffs', 'toolbox_alldiffs'); $e('toolbox_alldiffs').onclick=checkRecentDiffs; } if (window.addEventListener) { window.addEventListener("DOMContentLoaded",addPowerdiffLink,false) || window.addEventListener("load", addPowerdiffLink, false); } else if (window.attachEvent) { window.attachEvent("onload",addPowerdiffLink); } else { window._old_recent_onload = window.onload; window.onload = function() { window._old_recent_onload(); addPowerdiffLink(); } } // </nowiki></pre> /// Local Variables: /// /// mode:c /// /// fill-prefix:"// " /// /// End: ///