User:Kephir/gadgets/unclutter.js
Appearance
From Wikipedia, the free encyclopedia
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.
This code will be executed when previewing this page.
This user script seems to have a documentation page at User:Kephir/gadgets/unclutter and an accompanying .css page at User:Kephir/gadgets/unclutter.css.
// more info: [[User:Kephir/gadgets/unclutter]] /*jshint shadow:true, latedef:true, boss:true, scripturl:true, loopfunc:true, undef:true, latedef:true, unused:true */ /*global mw, jQuery, importStylesheet */ mw.loader.using(['mediawiki.user','mediawiki.util','mediawiki.Title','mediawiki.Uri'],function(){ "use strict"; varwgConf=mw.config.get(); varsettings=window.kephirUnclutter||{}; vardefSettings={ enableOnPageLoad:true, wrapDiscussions:true, collapseDiscussionsByDefault:false, signaturesProcess:true, signaturesMinimise:true, signaturesColourise:true, signaturesExceptions:[], liquidThreadsColourPosts:true, userAnnotations:{}, processSig:function(context){return!settings.signaturesMinimise;}, postProcessSig:function(context){returnfalse;}, discussionPagePatterns:[] }; if(wgConf.wgServer==='//en.wikipedia.org'){ // workaround for [[User:Writ Keeper/Scripts/teahouseTalkbackLink.js]] if(window.talkbackSubmit&&window.teahouseTalkbackLink&&(wgConf.wgPageName==='Wikipedia:Teahouse/Questions')){ defSettings.signaturesMinimise=false; // defSettings.postProcessSig } defSettings.userAnnotations={ "קיפודנחש":'kipod', "הסרפד":'Hasirpad', "Eric Corbett":'Malleus Fatuorum', "㓟":'Pi', "とある白い猫":'White Cat', "You Can Act Like A Man":"Basket Feudalist", "Piotrus":"Piotr Konieczny", "Thumperward":"Chris Cunningham", "Pigsonthewing":"Andy Mabbett", "Underlying lk":"eh bien mon prince", "QTxVi4bEMRbrNqOorWBV":"jps", "I9Q79oL78KiL0QTFHgyc":"jps", "1Wiki8Q5G7FviTHBac3dx8HhdNYwDVstR":"Eclipsed", "Hisashiyarouin":"野狼院ひさし", "":"" }; defSettings.discussionPagePatterns=[ /^Wikipedia:Administrators'_noticeboard\//, /^Wikipedia:Articles_for_deletion\//, /^Wikipedia:Templates_for_discussion/, /^Wikipedia:Possibly_unfree_files/, /^Wikipedia:Files_for_deletion/, /^Wikipedia:Redirects_for_discussion/, /^Wikipedia:Categories_for_discussion/, /^Wikipedia:Miscellany_for_deletion/, /^Wikipedia:Sockpuppet_investigations\//, /^Wikipedia:Teahouse\/Questions/, /^Wikipedia:Deletion_review\// ]; } if(wgConf.wgServer==='//en.wiktionary.org'){ defSettings.discussionPagePatterns=[ /^Wiktionary:Votes(\/|$)/, /^Wiktionary:Beer_parlour(\/|$)/, /^Wiktionary:Grease_pit(\/|$)/, /^Wiktionary:Etymology_scriptorium(\/|$)/, /^Wiktionary:Information_desk(\/|$)/, /^Wiktionary:Tea_room(\/|$)/, ]; } for(varkeyindefSettings){ if(!(keyinsettings)) settings[key]=defSettings[key]; } varsheet; functioncheckSheet(sheet){ varret; if(!sheet); returnnull; varuri=newmw.Uri(sheet.href); if((uri.host===location.hostname)&&(uri.path===wgConf.wgScript)){ if((uri.query.action==='raw')&&(uri.query.title==='User:Kephir/gadgets/unclutter.css')) returnsheet; } if(sheet.rules){ for(varj=0;j<sheet.rules.length;++j){ if(ret=checkSheet(sheet.rules[j].styleSheet)) returnret; } } returnnull; } for(vari=0;i<document.styleSheets.length;++i){ if(sheet=checkSheet(document.styleSheets[i])) break; } if(!sheet) sheet=importStylesheet('User:Kephir/gadgets/unclutter.css'); varsheetToggler=mw.util.addPortletLink('p-tb','javascript:void(0);','Toggle Unclutter','p-kephir-unclutter'); sheetToggler.addEventListener('click',function(ev){ ev.preventDefault(); sheet.disabled=!sheet.disabled; },false); sheet.disabled=!settings.enableOnPageLoad; varisDiscussionPage=settings.isDiscussionPage; if(wgConf.wgServer==='//en.wikipedia.org'){ (function(grps){ if(grps.indexOf('autoconfirmed')!==-1) return;// sorry to bother you. if(settings.enableOnPageLoad){ sheet.disabled=true; alert('You have installed Unclutter, but are not autoconfirmed. This means that you are probably an inexperienced editor. Unclutter usage by inexperienced editors is discouraged, as the stylesheet hides advice which new editors might need to be reminded of; therefore the stylesheet has been disabled.\n\nThis message will display on every page load until you configure Unclutter to disable the stylesheet by default. Read [[User:Kephir/gadgets/unclutter#Configuration]] to learn how to do it.'); } })(wgConf.wgUserGroups); } varisLQTPage= mw.loader.getState('ext.liquidThreads')==='ready'|| mw.loader.getState('ext.liquidThreads')==='loaded'; if(isDiscussionPage===void(0)){ isDiscussionPage=(((wgConf.wgNamespaceNumber>=0)&&(wgConf.wgNamespaceNumber%2))||document.getElementById('ca-addsection')); if(!isDiscussionPage)for(vari=0;i<settings.discussionPagePatterns.length;++i){ if(settings.discussionPagePatterns[i].test(wgConf.wgPageName)){ isDiscussionPage=true; break; } } if(wgConf.wgServer==='//en.wikipedia.org'){ if(/^Wikipedia_talk:Articles_for_creation\//i.test(wgConf.wgPageName)) isDiscussionPage=false; } if(isLQTPage) isDiscussionPage=false;// XXX: for the purpose of section collapsing, that is. } functionlink(handler,text){ varspan=document.createElement('span'); vara=document.createElement('a'); vartx=document.createTextNode(text); a.appendChild(tx); a.href='#'; a.addEventListener('click',function(ev){ ev.preventDefault(); ev.stopPropagation(); returnhandler(ev,a,tx,span); },false); varlb=document.createElement('span'); varrb=document.createElement('span'); lb.textContent='[';lb.className='mw-editsection-bracket'; rb.textContent=']';rb.className='mw-editsection-bracket'; span.appendChild(lb); span.appendChild(a); span.appendChild(rb); span.click=function(){ a.click.apply(a,arguments); }; returnspan; } vartogglerStore={}; try{ togglerStore=JSON.parse(window.localStorage.getItem('kephir-unclutter-togglers'))||{}; }catch(e){ /* swallow */ } functiontoggler(element,state,stateKey,showText,hideText){ showText=showText||'show'; hideText=hideText||'hide'; state==stateKeyintogglerStore?togglerStore[stateKey]:state; element.style.display=state?'none':''; returnlink(function(ev,a,tx){ state=!state; element.style.display=state?'none':''; tx.data=state?showText:hideText; if(stateKey){ try{ togglerStore=JSON.parse(window.localStorage.getItem('kephir-unclutter-togglers'))||{}; }catch(e){ /* swallow */ } togglerStore[stateKey]=state; try{ window.localStorage.setItem('kephir-unclutter-togglers',JSON.stringify(togglerStore)); }catch(e){ /* swallow */ } } returnfalse; },state?showText:hideText); } functionancestors(node){ varresult=[]; while(node!==null){ result[result.length]=node; node=node.parentNode; } returnresult; } functionclicker(target){ returnfunction(ev){ if(ancestors(ev.target).filter(function(item){returnitem.tagName==='A';}).length){ return; } target.click(); }; } functionprocessPreview(){ vartu=document.getElementsByClassName('templatesUsed')[0],tup,tuul; varpt; if(tu){ tup=tu.getElementsByTagName('p')[0]; tuul=tu.getElementsByTagName('ul')[0]; } varhc=document.getElementsByClassName('hiddencats')[0],hcp,hcul; if(hc){ hcp=hc.getElementsByTagName('p')[0]; hcul=hc.getElementsByTagName('ul')[0]; } varph=document.getElementById('mw-previewheader'); if(tup&&tuul){ tup.appendChild(document.createTextNode(' ('+tuul.getElementsByTagName('li').length+')')); tup.appendChild(pt=toggler(tuul,true)); pt.className='mw-editsection'; tuul.style.display='none'; } if(hcp&&hcul){ // hcp.appendChild(document.createTextNode(' (' + hcul.getElementsByTagName('li').length + ')')); hcp.appendChild(pt=toggler(hcul,true)); pt.className='mw-editsection'; hcul.style.display='none'; } if(ph){ varpc=document.getElementById('wikiPreview').getElementsByClassName('mw-content-ltr')[0];// XXX ph.appendChild(pt=toggler(pc,false)); pt.className='mw-editsection'; } /* TODO: handle #wikiDiff too */ } if((wgConf.wgAction==='edit')||(wgConf.wgAction==='submit')){ processPreview(); if(mw.user.options.get('uselivepreview')=='1'){ jQuery(mw).bind('LivePreviewDone',processPreview); } } varenarea=document.getElementById('editnotice-area'); if(((wgConf.wgAction==='submit')||(wgConf.wgAction==='edit'))&&enarea){ varenn=enarea.getElementsByClassName('editnotice-namespace')[0]; varnonempty=enn&&enn.textContent.trim(); vareditintro=document.getElementsByClassName('mw-editintro')[0]; if(!nonempty){ varenl=enarea.getElementsByClassName('editnotice-link')[0]; nonempty=enl&&!enl.classList.contains("editnotice-redlink"); } if(editintro){ vareiname=mw.util.getParamValue('editintro'); vareihider=document.createElement('div'); eihider.className='kephir-unclutter-editintro-hide-link'; eihider.style.fontSize='smaller'; eihider.style.textAlign='right'; eihider.appendChild(toggler(editintro,false,einame?('editintro-'+einame):null,'show editintro','hide editintro')); editintro.parentNode.insertBefore(eihider,editintro); } if(nonempty){ varhider=document.createElement('div'); hider.style.fontSize='smaller'; hider.style.textAlign='right'; hider.className='kephir-unclutter-editnotice-hide-link'; hider.appendChild(toggler(enarea,false,'editnotice-'+wgConf.wgPageName,'show editnotices','hide editnotices')); enarea.parentNode.insertBefore(hider,enarea); } } if(wgConf.wgAction==='submit'){ varph=document.getElementById('mw-previewheader'); if(ph){ varcont=document.getElementById('wikiPreview').getElementsByClassName('mw-content-ltr')[0];// XXX ph.insertBefore(toggler(cont,false),ph.firstChild); } } if(wgConf.wgAction==='view'){ varcontent=document.getElementById('mw-content-text'); varallHidden=settings.collapseDiscussionsByDefault; varheadlines=document.getElementsByClassName('mw-headline'); if((headlines.length>1)&&settings.wrapDiscussions&&isDiscussionPage){ varwrappers={}; varsect0wrapper=document.createElement('div'); varl0,l1; content.insertBefore(sect0wrapper,content.firstChild); while(sect0wrapper.nextSibling){ if(sect0wrapper.nextSibling.contains(headlines[0])) break; sect0wrapper.appendChild(sect0wrapper.nextSibling); } sect0wrapper.className='kephir-unclutter-sectionzero-wrapper'; document.getElementById('siteSub').appendChild(l0=toggler(sect0wrapper,false,'sect0-'+wgConf.wgPageName,'show header','hide header')); document.getElementById('siteSub').appendChild(l1=link(function(ev,a,tx){ allHidden=!allHidden; tx.data=allHidden?'show topics':'hide topics'; for(varkeyinwrappers){ if(wrappers[key].wrapper.style.display!==(allHidden?'none':'')) wrappers[key].click(); } },allHidden?'show topics':'hide topics')); l0.className=l1.className='mw-editsection'; for(vari=0;i<headlines.length;++i){ varhdr=headlines[i].parentNode; varnhdr=null; for(varj=i+1;j<headlines.length;++j){ if(headlines[j].parentNode.tagName===hdr.tagName){ nhdr=headlines[j].parentNode; break; } } varwrapper=document.createElement('div'); hdr.parentNode.insertBefore(wrapper,hdr.nextSibling); while(wrapper.nextSibling){ if(wrapper.nextSibling.contains(nhdr)) break; wrapper.appendChild(wrapper.nextSibling); } wrapper.className='kephir-unclutter-'+hdr.tagName+'-contents kephir-unclutter-discussion-contents'; varheaderLink=toggler(wrapper,(hdr.tagName==='H2')&&settings.collapseDiscussionsByDefault,'header-'+wgConf.wgPageName+'#'+headlines[i].id); varsuperwrapper=document.createElement('div'); hdr.parentNode.insertBefore(superwrapper,hdr); superwrapper.appendChild(hdr); superwrapper.appendChild(wrapper); superwrapper.className='kephir-unclutter-'+hdr.tagName+'-wrapper kephir-unclutter-discussion-wrapper'; headerLink.className='mw-editsection'; headerLink.wrapper=wrapper; hdr.appendChild(headerLink); hdr.style.cursor='pointer'; hdr.classList.add('kephir-unclutter-collapsible-section'); hdr.addEventListener('click',clicker(headerLink),false); wrappers[headlines[i].id]=headerLink; } varoldhash=location.hash.substr(1); location.hash=''; window.addEventListener('hashchange',function(ev){ varid=location.hash.substr(1); if(wrappers[id]){ varh=document.getElementById(id); if(wrappers[id].wrapper.style.display==='none'){ wrappers[id].click(); window.setTimeout(function(){ h.scrollIntoView(); },0);// fix scrolling position } } },false); location.hash=oldhash; } } functionescapeClass(clbutt){ returnclbutt.replace(/[^_a-zA-Z0-9-]/g,function(m){ /* TODO: do I care or do I not about non-BMP usernames? */ vart=m.charCodeAt(0).toString(16); while(t.length<6) t='0'+t; return'\\'+t; }); } varredirCache={}; functionsolveRedirect(title){ if(titleinredirCache) returnredirCache[title]; varapi=newmw.Api(); varresult=redirCache[title]=title; api.ajax({ action:'query', titles:title, redirects:'1' },{ async:false, success:function(data){ result=redirCache[title]=data.query.redirects[0].to; }, error:function(){ thrownewError('redirect resolution failed'); } }); returnresult; } functionextractUserName(title){ varm; if((title.getNamespaceId()===wgConf.wgNamespaceIds.user)||(title.getNamespaceId()===wgConf.wgNamespaceIds.user_talk)) returntitle.getMainText().replace(/\/.*$/,''); elseif(title.getNamespaceId()===wgConf.wgNamespaceIds.special) if(m=/^(Contributions|EmailUser|Log(?:\/delete|\/protect|\/block|))\/(?![a-z])([^?&#/]+)$/.exec(title.getMainText())){ if(m[1]==='EmailUser') m[2]=m[2].replace(/^User:/i,''); returnm[2]; }else returnnull; else returnnull; } functionnormaliseUsername(uname){ vartit; try{ tit=newmw.Title('User:'+uname); }catch(e){ returnnull; } varnorm=tit.getMainText(); returnnorm; } functionunameClasses(username){ if(mw.util.isIPv4Address(username)) return'unregistered ipv4'; if(mw.util.isIPv6Address(username)) return'unregistered ipv6'; return''; } varrxPage=newRegExp('^'+wgConf.wgArticlePath.replace('1ドル','(.*)')+'$'); functiontargetPage(href,params){ varuri; try{ uri=newmw.Uri(href); }catch(e){ returnnull; } if((uri.host!==location.hostname)) returnnull; if(params) for(varkinuri.query) params[k]=uri.query[k]; try{ if(m=rxPage.exec(uri.path)) returnnewmw.Title(decodeURIComponent(m[1])+(uri.fragment?'#'+uri.fragment:''));// XXX: why does mw.Title not decodeURIComponent on its own? elseif(uri.path===wgConf.wgScript) returnnewmw.Title(uri.query.title+(uri.fragment?'#'+uri.fragment:'')); }catch(e){/* failed to parse, bail out. */} returnnull; } functionwrapSignature(node,uname){ varbadtags=['DIV','DL','DD','BLOCKQUOTE','UL','OL','LI','P','BR','TD','TH','TR','H1','H2','H3','H4','H5','H6','PRE','DEL','INS']; varwraptags=['FONT','EM','B','I','SMALL']; functionisStylingNode(node,relax){ if(node.tagName==='FONT') returntrue; elseif(badtags.indexOf(node.tagName)!==-1) returnfalse; elseif(['SPAN','SMALL'].indexOf(node.tagName)===-1) if((['B','I','EM','STRONG'].indexOf(node.tagName)!==-1) &&(node.attributes.length===1)&&node.hasAttribute('style')); // do the loop check elseif(!relax||(['B','I','EM','STRONG'].indexOf(node.tagName)===-1) ||!((node.attributes.length<2)&&((node.attributes.length===1)<=node.hasAttribute('style')))){ if(node.childNodes){ varhads=false; for(vari=0;i<node.childNodes.length;++i){ if(node.childNodes[i].nodeType!==document.TEXT_NODE&&!(hads=isStylingNode(node.childNodes[i],true))) returnfalse; } returnhads; } returnfalse; }else; elseif(!((node.attributes.length===1)&&node.hasAttribute('style'))) returnfalse; if(node.childNodes){ for(vari=0;i<node.childNodes.length;++i){ if(node.childNodes[i].nodeType!==document.TEXT_NODE&&!isStylingNode(node.childNodes[i],true)) returnfalse; } } returntrue; } functiongrabProlog(last,wrapper){ varm; while(last.previousSibling){ if(isStylingNode(last.previousSibling)){ wrapper.insertBefore(last.previousSibling,wrapper.firstChild); continue; } if((last.previousSibling.nodeType===document.TEXT_NODE) &&(m=/[\u2000-\u200a\u2011\x20\x09\xa0\x0a\x0d]*([\u2003\x20\x09\xa0\x0a\x0d][([{]|[‐-][‐-]?|\/?[–—~]\/?|·{1,3}|(?:[\x20\xa0]?[᛭•§|\u2190-\u21ff\u2600-\u27bf\u2200-\u22ff])+|[\u2003\x20\x09\xa0\x0a\x0d])[\u2000-\u200a\u2011\x20\x09\xa0\x0a\x0d]*$/.exec(last.previousSibling.data))){ last.previousSibling.data=last.previousSibling.data.substr(0,last.previousSibling.data.length-m[0].length); wrapper.insertBefore(document.createTextNode(m[0]),wrapper.firstChild); if(last.previousSibling.data===''){ last.parentNode.removeChild(last.previousSibling); continue; } } break; } } functioncanBeSigNode(subcheck){ functioncheckTarget(tit){ if(tit.namespace===wgConf.wgNamespaceIds.special){ if(m=/^(Contributions|EmailUser|Log(?:\/delete|\/protect|\/block|))\/(.*)/.exec(tit.getMainText())){ if(m[1]==='EmailUser') m[2]=m[2].replace(/^User:/i,''); if(normaliseUsername(m[2])!==uname) return0; }else return-1; }elseif((tit.namespace===wgConf.wgNamespaceIds.user)||(tit.namespace===wgConf.wgNamespaceIds.user_talk)){ if(tit.namespace===wgConf.wgNamespaceIds.user_talk) if(sigll[href]) return-2;// a signature never links to the same page twice. if((tit.namespace===wgConf.wgNamespaceIds.user)&&(tit.getMainText().substr(0,uname.length+1)===(uname+'/'))) return1; if(tit.getMainText()!==uname) return0; sigll[href]=true; if(!tit.fragment||/^(no ?bold|top)$/i.test(tit.fragment)) return1;// OK else return-3;// invalid! } if(href.fragment)// section links are probably not parts of a signature. return-3; return1; } if(subcheck.nodeType===document.TEXT_NODE) returnsubcheck.data.length<64; if(subcheck.getElementsByTagName('img').length>0) returnnull;// no images are allowed in signatures; reject. if(subcheck.getElementsByTagName('li').length>0) returnnull;// XXX: I need a better way to do this... varsiglinks=Array.prototype.slice.call(subcheck.getElementsByTagName('a')); if(subcheck.tagName==='A') siglinks.push(subcheck); if(wgConf.wgServer==='//en.wikipedia.org'){ // helps with some false positives if(/\b(plainlinks|template-ping)\b/.test(subcheck.className)) returnnull; if(subcheck.querySelector('span.plainlinks')) returnnull; if(subcheck.querySelector('span.template-ping')) returnnull; } for(vari=0;i<siglinks.length;++i){ varhref=newmw.Uri(siglinks[i].href); varpagepat=newRegExp('^'+wgConf.wgArticlePath.replace(/([\\{}()|.?*+\-\^$\[\]])/g,'\\1ドル').replace('\\1ドル','(.+)')+'$');// XXX: awful varm,tit; // workaround for [[User:Writ Keeper/Scripts/teahouseTalkbackLink.js]] if(window.teahouseTalkbackLink&&/^TBsubmit\d+$/.test(siglinks[i].id)) continue; if(href.host!==wgConf.wgServer.replace(/^\/\//,'')) returnnull;// reject, external link. if(m=pagepat.exec(href.path)){ tit=newmw.Title(decodeURIComponent(m[1])); }elseif(href.path===wgConf.wgScript){ if(!href.query.title) returnnull; tit=newmw.Title(href.query.title); if(href.query.action&&(['edit','view'].indexOf(href.query.action)===-1)) returnnull; if(href.query.section&&(href.query.section!=='new')) returnnull; if(Object.keys(href.query).some(function(item){ return['action','section','redlink','preload','title'].indexOf(item)===-1; })) returnnull; }else returnnull;// looks like an external link. there are not allowed, so no signature here. if(!tit) returnnull;// not a good link. if([ wgConf.wgNamespaceIds.draft, wgConf.wgNamespaceIds.draft_talk, wgConf.wgNamespaceIds.help, wgConf.wgNamespaceIds.help_talk, wgConf.wgNamespaceIds.category, wgConf.wgNamespaceIds.category_talk, wgConf.wgNamespaceIds.file, wgConf.wgNamespaceIds.file_talk, wgConf.wgNamespaceIds.mediawiki, wgConf.wgNamespaceIds.mediawiki_talk, wgConf.wgNamespaceIds.template_talk, wgConf.wgNamespaceIds.module, wgConf.wgNamespaceIds.module_talk, ].indexOf(tit.namespace)!==-1) returnnull; varwhy=checkTarget(tit); if(why===0){ if(siglinks[i].classList.contains('mw-redirect')){ try{ tit=newmw.Title(solveRedirect(tit.toString())); }catch(e){ continue;// assume OK } if(checkTarget(tit)>0) continue; } returnnull; }elseif(why<0){ returnnull; } } returntrue; } varm; varlast=node; varwrapper=document.createElement('span'); // lifted from Comments in Local Time, later relaxed to accommodate a few bloody divas vartsregex=/(\s*\d?\d:\d\d(\s+[APap](\. ?)?[Mm](\. ?)?)?,?\s+(\d\d?\s[A-Za-z]+|[A-Za-z]+\s+\d\d?,?)\s+\d\d\d\d|\d\d\d\d-\d\d-\d\d\s+\d\d:\d\d|[A-Za-z]+\s\d\d?,\s\d\d\d\d\s*[;,]\s*\d\d:\d\d)(\s*\(UTC\))?/; wrapper.className='kephir-unclutter-signature-wrapper signature signature-'+uname.replace(/ /g,'_')+' '+unameClasses(uname); while(last=node,node=node.parentNode){ vargot=null; varsigll={}; varscnm; // XXX: handle {{spa}} and such somehow /*if (node.tagName === 'SMALL') return null;*/ if(badtags.indexOf(last.tagName)!==-1) returnnull; varsubcheck=last; do{ if(subcheck.classList&&subcheck.classList.contains('before-localcomments')){ got=subcheck; m=[]; break; }elseif(subcheck.getElementsByClassName&&(scnm=subcheck.getElementsByClassName('before-localcomments')).length){ if(!canBeSigNode(subcheck)) returnnull; scnm=scnm[0]; varsceit=scnm,scenext=scnm,posnode=subcheck.nextSibling; while(sceit!==subcheck.nextSibling){ while(!scenext.nextSibling){ scenext=scenext.parentNode; if(scenext===subcheck) break; } scenext=scenext.nextSibling; subcheck.parentNode.insertBefore(sceit,posnode); posnode=sceit.nextSibling; sceit=scenext; } got=subcheck; break; }elseif((subcheck.nodeType===document.TEXT_NODE)&&(m=tsregex.exec(subcheck.data))){ // split subcheck into two text nodes: before and after start of match. subcheck.parentNode.insertBefore( document.createTextNode(subcheck.data.substr(0,m.index)), subcheck ); subcheck.data=subcheck.data.substr(m.index); if(!canBeSigNode(subcheck.previousSibling)) returnnull; got=subcheck; break; }elseif(m=tsregex.exec(subcheck.textContent)){ if(!canBeSigNode(subcheck)) returnnull; // dig up the node got=subcheck; while(got.nodeType!==document.TEXT_NODE){ got=got.firstChild; while(String(got.textContent).indexOf(m[0])===-1){ got=got.nextSibling; if(!got) returnnull;// whoops... } } // split at match got.parentNode.insertBefore( document.createTextNode(got.data.substr(0,got.data.indexOf(m[0]))), got ); got.data=got.data.substr(got.data.indexOf(m[0])); // carve it out if(got!==subcheck){ varsceit=got,scenext=got,posnode=subcheck.nextSibling; while(sceit){ while(!scenext.nextSibling){ scenext=scenext.parentNode; if(scenext===subcheck){ scenext=null; break; } } scenext=scenext&&scenext.nextSibling; subcheck.parentNode.insertBefore(sceit,posnode); posnode=sceit.nextSibling; sceit=scenext; } } break; }elseif((subcheck.nodeType===document.TEXT_NODE)&&(subcheck.data.length>=64)){ // long passages of text? probably a false positive. returnnull; } if(!subcheck.getElementsByTagName) continue; if(!canBeSigNode(subcheck)) returnnull; }while(subcheck=subcheck.nextSibling); if(got){ grabProlog(last,wrapper); if(last.parentNode.firstChild===last){ if(wraptags.indexOf(last.parentNode.tagName)!==-1){ if(got.nodeType===document.TEXT_NODE){// raw timestamp got.parentNode.parentNode.insertBefore(got,got.parentNode.nextSibling); last=last.parentNode; node=node.parentNode; }else{// LocalComments varggot=got; while(ggot&&!ggot.classList.contains('after-localcomments')){ ggot=ggot.nextSibling; } if(!ggot||(ggot.parentNode.lastChild===ggot)){ varitn=null,lip=got.parentNode.nextSibling; for(varit=got;it&&it!==ggot.nextSibling;it=itn){ itn=it.nextSibling; if(lip) it.parentNode.parentNode.insertBefore(it,lip); else it.parentNode.parentNode.appendChild(it); lip=it.nextSibling; } last=last.parentNode; node=node.parentNode; } } } } grabProlog(last,wrapper); node.insertBefore(wrapper,last); for(varit=last;it&&it!==got;it=wrapper.nextSibling){ wrapper.appendChild(it); } if(got.nodeType!==document.TEXT_NODE){ wrapper.appendChild(got); } returnwrapper; } } returnnull; } // XXX: customising colours? remembering across pages? varuserColours,userLQTColours; varuserColoursQueue={}; varuserColoursSheet; try{ userColours=JSON.parse(window.sessionStorage.getItem('kephir-unclutter-sigcolours-'+wgConf.wgPageName))||{}; userLQTColours=JSON.parse(window.sessionStorage.getItem('kephir-unclutter-lqtcolours-'+wgConf.wgPageName))||{}; }catch(e){ /* ignore */ } if(settings.signaturesColourise){ varstyleElm=document.createElement('style'); styleElm.appendChild(document.createTextNode('')); document.head.appendChild(styleElm); userColoursSheet=styleElm.sheet||styleElm.styleSheet; if(!userColoursSheet){ settings.signaturesColourise=false; } if(!userColoursSheet.addRule){ if(userColoursSheet.insertRule) userColoursSheet.addRule=function(selector,css){ this.insertRule(selector+'{'+css+'}',0); }; else{ settings.signaturesColourise=false; userColoursSheet=null; } } } if(userColoursSheet) for(varunameinuserColours){ varcolour=userColours[uname]; varlqtc=userLQTColours[uname]; userColoursSheet.addRule( '.kephir-unclutter-minisig.signature-'+escapeClass(uname.replace(/ /g,'_')), 'background: '+colour ); if(settings.liquidThreadsColourPosts&&lqtc){ userColoursSheet.addRule( '.lqt-post-wrapper.post-'+escapeClass(uname.replace(/ /g,'_')), 'background: '+lqtc ); } } // this algorithm is described at [[HSL and HSV#Converting to RGB]]. functionhsv2rgb(hue,sat,val1){ varchro=val1*sat; varval2=val1-chro*Math.abs((hue/120-Math.floor(hue/120))*2-1); varval3=val1-chro; switch(Math.floor(hue/60)%6){ case0:return[val1,val2,val3]; case1:return[val2,val1,val3]; case2:return[val3,val1,val2]; case3:return[val3,val2,val1]; case4:return[val2,val3,val1]; case5:return[val1,val3,val2]; } } functionpickSigColour(){ // XXX: minimise collisions varhue=Math.random()*360; varsat=0.9*Math.sqrt(Math.random()); varval=0.5+Math.pow(Math.random(),1/3)*0.3; return{ lqtVariant:{ hue:hue,sat:sat/8,val:0.9, toString:function(){ varrgb=hsv2rgb(this.hue,this.sat,this.val); return'rgb('+Math.floor(rgb[0]*255)+','+Math.floor(rgb[1]*255)+', '+Math.floor(rgb[2]*255)+')'; } }, hue:hue,sat:sat,val:val, toString:function(){ varrgb=hsv2rgb(this.hue,this.sat,this.val); return'rgba('+Math.floor(rgb[0]*255)+','+Math.floor(rgb[1]*255)+', '+Math.floor(rgb[2]*255)+', 0.175)'; } }; } functionminimiseSig(wrapper,username,annotation){ functiondisplacement(node){ varx=0,y=0; while(node.offsetParent){ x+=node.offsetLeft; y+=node.offsetTop; node=node.offsetParent; } return[x,y]; } functionel(tag,child,attr,events){ varnode=document.createElement(tag); if(child){ if(typeofchild!=='object') child=[child]; for(vari=0;i<child.length;++i){ varch=child[i]; if((ch===void(null))||(ch===null)) continue; elseif(typeofch!=='object') ch=document.createTextNode(String(ch)); node.appendChild(ch); } } if(attr)for(varkeyinattr){ node.setAttribute(key,String(attr[key])); } if(events)for(varkeyinevents){ node.addEventListener(key,events[key],false); } returnnode; } functionlink(child,href,attr,ev){ attr=attr||{}; ev=ev||{}; if(typeofattr==='string'){ attr={title:attr}; } if(typeofhref==='string') attr.href=href; else{ attr.href='javascript:void(null);'; ev.click=href; } returnel('a',child,attr,ev); } functioncwrap(clbutt,child){ returnel('span',child,{'class':clbutt}); } if(settings.signaturesExceptions.indexOf(username)!==-1) return; varclbutt='signature-'+username.replace(/ /g,'_'); varminisig=el('span',[ el('span',['—'],{'class':'dash'}), '\xa0', mw.util.isIPv4Address(username)||mw.util.isIPv6Address(username) ?el('span',[username],{'class':'username'}) :link([username],mw.util.getUrl('User:'+username),{'class':'username'}), annotation?el('span',[ ' ('+annotation+')' ],{"class":"annotation"}):void(null), ' ', el('small',[ '(', cwrap('tlk-link',[link(['talk'],mw.util.getUrl('User talk:'+username), 'Discussion page of this user' )]), cwrap('ctb-link',['\xa0•\xa0',link(['contrib'],mw.util.getUrl('Special:Contributions/'+username), 'Contributions of this user' )]), cwrap('act-link',['\xa0•\xa0',link(['actions'],mw.util.getUrl('Special:Log',{user:username}), 'Actions performed by this user' )]), cwrap('log-link',['\xa0•\xa0',link(['log'],mw.util.getUrl('Special:Log',{page:'User:'+username}), 'Actions performed on this user' )]), cwrap('sig-link',['\xa0•\xa0',link(['sig'],function(ev){ wrapper.style.display=wrapper.style.display==='none'?'inline-block':'none'; if(wrapper.style.display!=='none'){ varmsd=displacement(minisig); varwsd=displacement(wrapper.offsetParent); wrapper.style.top=(msd[1]-wsd[1]+minisig.offsetHeight+4)+'px'; wrapper.style.left=(msd[0]-wsd[0])+'px'; wrapper.style.position='absolute !important'; } },'Show original signature')]), ')' ]), ],{'class':'kephir-unclutter-minisig signature '+clbutt+' '+unameClasses(username)}); wrapper.style.cssText+='; position: absolute !important; z-index: 69;'; wrapper.style.display='none'; wrapper.parentNode.insertBefore(document.createTextNode(' '),wrapper); wrapper.parentNode.insertBefore(minisig,wrapper); wrapper.parentNode.insertBefore(document.createTextNode(' '),wrapper); minisig.insertBefore(wrapper,minisig.firstChild); wrapper.style.background='#ffffcc'; wrapper.style.border='1px solid black'; wrapper.style.padding='0.2em'; returnminisig; } functionprocessLiquidSignature(lqtwrapper){ // determine username varsiglinks=lqtwrapper.getElementsByTagName('a'); varusername,oldname,tparams={}; // the checks are much lighter here, since we are much more sure that this is a signature for(vark=0;k<siglinks.length;++k){ vartitle=targetPage(siglinks[k].href,tparams); if(!title) continue; varoldname=(username=extractUserName(title)); if(!oldname) continue;// XXX if(siglinks[k].classList.contains('mw-redirect')){ try{ username=extractUserName(newmw.Title(solveRedirect(title.toString())))||oldname; }catch(e){} } break; } if(!username) return;// skip. what else can we do? varwrapper=document.createElement('span'); lqtwrapper.insertBefore(wrapper,lqtwrapper.firstChild); while(wrapper.nextSibling) wrapper.appendChild(wrapper.nextSibling); varcontext={ sigOriginal:wrapper, oldUsername:oldname, username:username, annotation:settings.userAnnotations[username], colourise:settings.signaturesColourise, colour:userColours[username]||(userColoursQueue[username]?userColoursQueue[username].colour:void(0)), lqtWrapper:lqtwrapper, lqtTimestamp:lqtwrapper.nextSibling, }; while(lqtwrapper=lqtwrapper.parentNode) if(lqtwrapper.classList.contains('lqt-post-wrapper')) break; context.lqtPostWrapper=lqtwrapper; lqtwrapper.classList.add('post-'+username.replace(/ /g,'_')); if(settings.processSig(context)!==true){ if(!context.annotation&&(oldname!==username)) context.annotation=oldname; context.sigMinimised=minimiseSig(wrapper,username,context.annotation); } settings.postProcessSig(context); if(context.colourise&&!userColours[username]){ varuq=userColoursQueue[username]=userColoursQueue[username]||{count:0}; uq.colour=context.colour; uq.count++; } } functionassignColours(){ if(!userColoursSheet) return; varqueue=Object.keys(userColoursQueue).sort(function(apple,orange){ if(userColoursQueue[apple].colour&&!userColoursQueue[orange].count) return-1; elseif(!userColoursQueue[apple].colour&&userColoursQueue[orange].count) return1; returnuserColoursQueue[apple].count-userColoursQueue[orange].count; }); for(varj=0;j<queue.length;++j){ varcolour=(userColoursQueue[queue[j]].colour||pickSigColour()); userColours[queue[j]]=String(colour); userLQTColours[queue[j]]=String(colour.lqtVariant||colour); userColoursSheet.addRule( '.kephir-unclutter-minisig.signature-'+escapeClass(queue[j].replace(/ /g,'_')), 'background: '+colour ); if(settings.liquidThreadsColourPosts){ userColoursSheet.addRule( '.lqt-post-wrapper.post-'+escapeClass(queue[j].replace(/ /g,'_')), 'background: '+colour.lqtVariant||colour ); } } userColoursQueue={}; try{ if(!Object.keys(userColours).length) return; window.sessionStorage.setItem('kephir-unclutter-sigcolours-'+wgConf.wgPageName,JSON.stringify(userColours)); window.sessionStorage.setItem('kephir-unclutter-lqtcolours-'+wgConf.wgPageName,JSON.stringify(userLQTColours)); }catch(e){ /* ignore */ } } if(((wgConf.wgNamespaceNumber>0)||(wgConf.wgCanonicalSpecialPageName==='NewMessages'))&&(wgConf.wgAction==='view')&&settings.signaturesProcess){ if(isLQTPage){/* lovely. */ mw.loader.using(['ext.liquidThreads'],function(){ varsigs=document.getElementsByClassName('lqt-thread-user-signature'); for(varj=0;j<sigs.length;++j){ processLiquidSignature(sigs[j]); } var_setupThread=window.liquidThreads.setupThread; window.liquidThreads.setupThread=function(container){ varresult=_setupThread.apply(this,arguments); varsigs=container[0].getElementsByClassName('lqt-thread-user-signature'); for(varj=0;j<sigs.length;++j){ processLiquidSignature(sigs[j]); } assignColours(); returnresult; }; assignColours(); }); return; } varlinks=(document.getElementById('mw-content-text')||{getElementsByTagName:function(){return[];}}).getElementsByTagName('a'); for(vari=0;i<links.length;++i){ varm; if(links[i].processedSig) continue; vartparams={}; vartitle=targetPage(links[i].href,tparams); if(!title) continue; varoldname; if(tparams.redlink?tparams.action!=='edit':tparams.action) continue; if((title.getNamespaceId()===wgConf.wgNamespaceIds.user)||(title.getNamespaceId()===wgConf.wgNamespaceIds.user_talk)) if(title.fragment&&!/^(top|no ?bold)$/i.test(title.fragment)) continue; elseif(title.getPrefixedDb().indexOf('/')!==-1) continue; if(!(oldname=extractUserName(title))) continue; varusername=oldname; if(links[i].classList.contains('mw-redirect')){ try{ username=extractUserName(newmw.Title(solveRedirect(title.toString())))||oldname; }catch(e){} } varwrapper=wrapSignature(links[i],username); if(wrapper){ varsiglinks=wrapper.getElementsByTagName('a'); varminisig=null; for(varj=0;j<siglinks.length;++j) siglinks[j].processedSig=true; varcontext={ sigOriginal:wrapper, oldUsername:oldname, username:username, annotation:settings.userAnnotations[username], colourise:settings.signaturesColourise, colour:userColours[username]||(userColoursQueue[username]?userColoursQueue[username].colour:void(0)) }; if(settings.processSig(context)!==true){ if(!context.annotation&&(oldname!==username)) context.annotation=oldname; context.sigMinimised=minimiseSig(wrapper,username,context.annotation,context.colourise?context.colour:null); } settings.postProcessSig(context); if(context.colourise&&!userColours[username]){ varuq=userColoursQueue[username]=userColoursQueue[username]||{count:0}; uq.colour=context.colour; uq.count++; } if(minisig){ varsiglinks=minisig.getElementsByTagName('a'); for(varj=0;j<siglinks.length;++j) siglinks[j].processedSig=true; } } } assignColours(); } });