User:Sven Manguard/linkclassifier.js

/* If you want to use this script, simply add the following line to your Special:Mypage/monobook.js:

importScript('User:Sven Manguard/linkclassifier.js'); // Linkback: User:Sven Manguard/linkclassifier.js


 * (Please keep the comment so I can see how many people use this). You will also want to
 * add some CSS classes, such as those at User:Sven Manguard/linkclassifier.css.

/* If you want this to run "on demand" instead of on every page, set "LinkClassifierOnDemand=true" and * use mw.util.addPortletLink or the like to add a button calling LinkClassifier.onDemand. */

var LinkClassifier={ /* This object maps classes to the categories for which to apply them. Values may be an array of strings or a regex. */   cats:{ deletion:[ 'Category:All articles proposed for deletion', 'Category:All books proposed for deletion', 'Category:All disputed non-free Wikipedia files', 'Category:All orphaned non-free use Wikipedia files', 'Category:All possibly unfree Wikipedia files', 'Category:All replaceable non-free use Wikipedia files', 'Category:All Wikipedia files with no copyright tag', 'Category:All Wikipedia files with no non-free use rationale', 'Category:All Wikipedia files with unknown copyright status', 'Category:All Wikipedia files with unknown source', 'Category:Articles for deletion', 'Category:Articles on deletion review', 'Category:Candidates for speedy deletion', 'Category:Candidates for undeletion', 'Category:Categories for conversion', 'Category:Categories for deletion', 'Category:Categories for listifying', 'Category:Categories for merging', 'Category:Categories for renaming', 'Category:Categories for speedy renaming', 'Category:Categories to be listified then deleted', 'Category:Duplicate or hardcoded templates awaiting deletion', 'Category:Items pending OTRS confirmation of permission for over 30 days', 'Category:Miscellaneous pages for deletion', 'Category:Redirects for discussion', 'Category:Stub categories for deletion', 'Category:Stub template deletion candidates', 'Category:Templates for deletion', 'Category:Wikipedia deprecated and orphaned templates', 'Category:Wikipedia files for deletion', 'Category:Wikipedia files with unknown source for deletion in dispute', 'Category:Wikipedia templates for deletion' ].sort, disambiguation:[ 'Category:All disambiguation pages' ].sort, 'set-index':[ 'Category:All set index articles' ].sort, 'featured-content':[ 'Category:Featured articles', 'Category:Featured lists', 'Category:Featured pictures', 'Category:Featured sounds', 'Category:Featured videos', 'Category:Featured portals' ].sort, 'good-content':[ 'Category:Good articles' ].sort, 'soft-redirect-cats':[ 'Category:Wikipedia soft redirected categories', ].sort, 'spoken-articles':[ 'Category:Spoken articles' ].sort, stubcls:/^Category:.* stubs$/, 'nonfree-media':[ 'Category:Photos of copyrighted works' ].sort, unprintworthy:[ 'Category:Unprintworthy redirects', 'Category:Middle-earth redirects from redundant titles' ].sort, 'unprintworthy-shortcut':[ 'Category:Redirects from shortcuts', ].sort },   callback:function(r, sts, xhr){ if(!r.query) { if(typeof(window.console)=='undefined' || typeof(window.console.error)!='function') throw new Error('Bad response'); window.console.error("Bad response", r); return; }       if(r['query-continue']){ var cc=this.rawdata; for(var k in r['query-continue']){ for(var k2 in r['query-continue'][k]){ cc[k2]=r['query-continue'][k][k2]; }           }            $.ajax({                url:mw.util.wikiScript('api'),                dataType:'json',                type:'POST',                data:cc,                rawdata:cc,                success:arguments.callee,                error:function(xhr,textStatus,errorThrown){                    throw new Error('AJAX error: '+textStatus+' '+errorThrown);                }            }); }       r=r.query;

var a=document.getElementById('wikiPreview'); if(!a) a=document.getElementById('bodyContent'); if(!a) throw new Error('Huh? No body content?'); a=a.getElementsByTagName('A'); if(a.length==0) return;

var redir={}; var redirlist=[]; if(r.redirects) for(var i=r.redirects.length-1; i>=0; i--){ redir[r.redirects[i].from]=r.redirects[i].to; redirlist.push(r.redirects[i].from); }       if(redirlist.length>0) { var q = { format:'json', action:'query', titles:redirlist.join('|'), prop:'categories|info', inprop:'protection', cllimit:'max' };           $.ajax({                url:mw.util.wikiScript('api'),                dataType:'json',                type:'POST',                data:q,                rawdata:q,                success:arguments.callee,                error:function(xhr,textStatus,errorThrown){                    throw new Error('AJAX error: '+textStatus+' '+errorThrown);                }            }); }

var prefix=(this.rawdata.redirects?'':'redir-'); var cats={}; var missing={}; var classes={}; if(r.pages) for(var i in r.pages){ missing[r.pages[i].title]=(typeof(r.pages[i].missing)!='undefined'); if(typeof(r.pages[i].categories)!='undefined'){ cats[r.pages[i].title]=r.pages[i].categories.map(function(a){ return a.title; }).sort; }           if(typeof(r.pages[i].protection)!='undefined'){ classes[r.pages[i].title]=[]; var x={}; for(var j=r.pages[i].protection.length-1; j>=0; j--){ var p=prefix+'protection-'+r.pages[i].protection[j].type+'-'+r.pages[i].protection[j].level; if(typeof(x[p])=='undefined'){ x[p]=1; classes[r.pages[i].title].push(p); }                   if(r.pages[i].protection[j].expiry=='infinity'){ p+='-indef'; if(typeof(x[p])=='undefined'){ x[p]=1; classes[r.pages[i].title].push(p); }                   }                }            }            if(typeof(r.pages[i].flagged)!='undefined'){ if(r.pages[i].lastrevid!=r.pages[i].flagged.stable_revid){ classes[r.pages[i].title].push('needs-review'); }           }        }        Array.prototype.forEach.call(a, function(a){            if(typeof(a.wikipage)=='undefined') return;            if(typeof(redir[a.wikipage])!='undefined'){                $(a).addClass('redirect');                a.wikipage=redir[a.wikipage];                a.title=a.wikipage;                var cns=mw.config.get('wgCanonicalNamespace');                if(a.wikipage==(cns?cns+':':)+mw.config.get('wgTitle'))                    $(a).addClass('self-redirect');                if(missing[a.wikipage])                    $(a).addClass('broken-redirect');            }            var m=a.href.match(/#.*/);            if(m && m[0].substr(0,10)!=="#cite_note"){                a.title=a.title.replace(/#.*/,)+m[0].replace(/_/g,' ').replace(/\.([0-9A-F][0-9A-F])/gi, function(x,n){ return String.fromCharCode(parseInt(n,16)); });            }            if(/ \(disambiguation\)$/.test(a.origwikipage)){ $(a).addClass('intentional-disambiguation'); }           if(typeof(classes[a.wikipage])!='undefined'){ for(var j=classes[a.wikipage].length-1; j>=0; j--) $(a).addClass(classes[a.wikipage][j]); }           if(a.wikipage!=a.origwikipage && typeof(classes[a.origwikipage])!='undefined'){ for(var j=classes[a.origwikipage].length-1; j>=0; j--) $(a).addClass(classes[a.origwikipage][j]); }           var c1=[]; if(typeof(cats[a.wikipage])!='undefined'){ c1=c1.concat(cats[a.wikipage]); }           if(a.wikipage!=a.origwikipage && typeof(cats[a.origwikipage])!='undefined'){ c1=c1.concat(cats[a.origwikipage]); }           if(c1.length>0){ c1=c1.sort; for(var cls in LinkClassifier.cats){ var i1=c1.length-1; var c2=LinkClassifier.cats[cls]; if(c2 instanceof RegExp){ while(i1>=0){ if(c2.test(c1[i1])){ $(a).addClass(cls); break; }                           i1--; }                   } else { var i2=c2.length-1; while(i1>=0 && i2>=0){ if(c1[i1]==c2[i2]){ $(a).addClass(cls); break; }                           (c1[i1]>c2[i2])?--i1:--i2; }                   }                }            }        });    },

getPageName:function(url){ var m=url.match(/\/wiki\/([^?#]+)/); if(!m) m=url.match(/\/w\/index.php\?(?:.*&)?title=([^&#]+)/); if(!m) return ''; var t=decodeURIComponent(m[1]).replace(/_/g,' '); if(t.substr(0,6)=='Image:') t='File:'+t.substr(6); if(t.substr(0,11)=='Image talk:') t='File talk:'+t.substr(6); if(t.substr(0,8)=='Special:') t=''; return t;   },

classifyChildren:function(node){ mw.loader.using(['mediawiki.util','mediawiki.user'], function{           var a=node.getElementsByTagName('A');            if(a.length==0) return;            var self=LinkClassifier.getPageName(location.href);            a=Array.prototype.map.call(a, function(a){ a.wikipage=''; if(/(^|\s)(external|extiw)(\s|$)/.test(a.className)) return ''; if(!/(^|\s)(image)(\s|$)/.test(a.className)) a.className+=" nonimage"; a.wikipage=LinkClassifier.getPageName(a.href); if(a.wikipage==self) a.wikipage=''; a.origwikipage=a.wikipage; return a.wikipage; }).sort.filter(function(e,i,a){ return e!=='' && (i==0 || a[i-1]!==e); });

function processLinks(limit){ while(a.length>0){ var q={ format:'json', action:'query', rawcontinue: '', titles:a.splice(0,limit).join('|'), prop:'categories|info|flagged', redirects:1, cllimit:'max', inprop:'protection' };                   $.ajax({                        url:mw.util.wikiScript('api'),                        dataType:'json',                        type:'POST',                        data:q,                        rawdata:q,                        success:LinkClassifier.callback,                        error:function(xhr,textStatus,errorThrown){                            throw new Error('AJAX error: '+textStatus+' '+errorThrown);                        }                    }); }           }

if(a.length<=100){ // Not worth querying the API to see if the user has apihighlimits processLinks(50); } else { // Note mw.user.getRights queries the API mw.user.getRights(function(rights){                   processLinks( (rights.indexOf('apihighlimits')>=0) ? 500 : 50 );               });            }        });    },    onLoad:function{        if(window.LinkClassifierOnDemand) return;        if(window.AJAXPreview) window.AJAXPreview.AddOnLoadHook(LinkClassifier.classifyChildren);        LinkClassifier.onDemand;    },    onDemand:function{        var node=document.getElementById('wikiPreview');        if(!node) node=document.getElementById('bodyContent');        if(node) LinkClassifier.classifyChildren(node);    } };

if(!window.LinkClassifierOnDemand) $(document).ready(LinkClassifier.onLoad);