User:Evad37/TimestampDiffs.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:Evad37/TimestampDiffs.
/*************************************************************************************************** TimestampDiffs --- by Evad37 > Links timestamps to diffs on discussion pages ***************************************************************************************************/ /* jshint esnext:false, laxbreak: true, undef: true, maxerr: 999*/ /* globals console, document, ,ドル mw */ // <nowiki> $.when( mw.loader.using(["mediawiki.api"]), $.ready ).then(function(){ // Pollyfill NodeList.prototype.forEach() per https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach if(window.NodeList&&!NodeList.prototype.forEach){ NodeList.prototype.forEach=Array.prototype.forEach; } varconfig={ version:"1.1.3", mw:mw.config.get([ "wgNamespaceNumber", "wgPageName", "wgRevisionId", "wgArticleId" ]), months:["January","February","March","April","May","June","July","August","September","October","November","December"] }; // Only activate on existing talk pages and project pages varisExistingPage=config.mw.wgArticleId>0; if(!isExistingPage){ return; } varisTalkPage=config.mw.wgNamespaceNumber>0&&config.mw.wgNamespaceNumber%2===1; varisProjectPage=config.mw.wgNamespaceNumber===4; if(!isTalkPage&&!isProjectPage){ return; } mw.util.addCSS(".tsdiffs-timestamp a { color:inherit; text-decoration: underline dotted #6495ED; }"); /** * Wraps timestamps within text nodes inside spans (with classes "tsdiffs-timestamp" and "tsdiffs-unlinked"). * Based on "replaceText" method in https://en.wikipedia.org/wiki/User:Gary/comments_in_local_time.js * * @param {Node} node Node in which to look for timestamps */ varwrapTimestamps=function(node){ vartimestampPatten=/(\d{2}:\d{2}, \d{1,2} \w+ \d{4} \(UTC\))/g; if(!node){ return; } varisTextNode=node.nodeType===3; if(isTextNode){ varparent=node.parentNode; varparentNodeName=parent.nodeName; if(['CODE','PRE'].includes(parentNodeName)){ return; } varvalue=node.nodeValue; varmatches=value.match(timestampPatten); // Manipulating the DOM directly is much faster than using jQuery. if(matches){ // Only act on the first timestamp we found in this node. If // there are two or more timestamps in the same node, they // will be dealt with through recursion below varmatch=matches[0]; varposition=value.search(timestampPatten); varstringLength=match.toString().length; varbeforeMatch=value.substring(0,position); varafterMatch=value.substring(position+stringLength); varspan=document.createElement('span'); span.className='tsdiffs-timestamp tsdiffs-unlinked'; span.append(document.createTextNode(match.toString())); parent=node.parentNode; parent.replaceChild(span,node); varbefore=document.createElement('span'); before.className='before-tsdiffs'; before.append(document.createTextNode(beforeMatch)); varafter=document.createElement('span'); after.className='after-tsdiffs'; after.append(document.createTextNode(afterMatch)); parent.insertBefore(before,span); parent.insertBefore(after,span.nextSibling); // Look for timestamps to wrap in all subsequent sibling nodes varnext=after; varnextNodes=[]; while(next){ nextNodes.push(next); next=next.nextSibling; } nextNodes.forEach(wrapTimestamps); } }else{ node.childNodes.forEach(wrapTimestamps); } }; wrapTimestamps(document.querySelector(".mw-parser-output")); // Account for [[Wikipedia:Comments in local time]] gadget document.querySelectorAll(".localcomments").forEach(function(node){ node.classList.add("tsdiffs-timestamp","tsdiffs-unlinked"); }); /** * Wraps the child nodes of an element within an <a> tag, * with given href and title attributes, and removes the * `tsdiffs-unlinked` class from the element. * * @param {Element} element * @param {string} href * @param {string} title */ varlinkTimestamp=function(element,href,title){ vara=document.createElement("a"); a.setAttribute("href",href); a.setAttribute("title",title); element.childNodes.forEach(function(child){ a.appendChild(child); }); element.appendChild(a); element.classList.remove("tsdiffs-unlinked"); }; /** * Formats a JavaScript Date object as a string in the MediaWiki timestamp format: * hh:mm, dd Mmmm YYYY (UTC) * * @param {Date} date * @returns {string} */ vardateToTimestamp=function(date){ varhours=("0"+date.getUTCHours()).slice(-2); varminutes=("0"+date.getUTCMinutes()).slice(-2); varday=date.getUTCDate(); varmonth=config.months[date.getUTCMonth()]; varyear=date.getUTCFullYear(); returnhours+":"+minutes+", "+day+" "+month+" "+year+" (UTC)"; }; varapi=newmw.Api({ ajax:{ headers:{ "Api-User-Agent":"TimestampDiffs/"+config.version+ " ( https://en.wikipedia.org/wiki/User:Evad37/TimestampDiffs.js )" } } }); // For discussion archives, comments come from the base page varbasePageName=config.mw.wgPageName.replace(/\/Archive..*?$/,""); varapiQueryCount=0; varprocessTimestamps=function(rvStartId){ apiQueryCount++; returnapi.get({ "action":"query", "format":"json", "prop":"revisions", "titles":basePageName, "formatversion":"2", "rvprop":"timestamp|user|comment|ids", "rvslots":"", "rvlimit":"5000", "rvStartId":rvStartId||config.mw.wgRevisionId }).then(function(response){ if(!response||!response.query||!response.query.pages||!response.query.pages[0]||!response.query.pages[0].revisions){ return$.Deferred().reject("API response did not contain any revisions"); } varpageRevisions=response.query.pages[0].revisions.map(function(revision){ varrevisionDate=newDate(revision.timestamp); varoneMinutePriorDate=newDate(revisionDate-1000*60); revision.timestampText=dateToTimestamp(revisionDate); revision.oneMinutePriorTimestampText=dateToTimestamp(oneMinutePriorDate); returnrevision; }); document.querySelectorAll(".tsdiffs-unlinked").forEach(function(timestampNode){ vartimestamp; vartimestampTitle; if(timestampNode.tagName==="TIME"){ timestamp=dateToTimestamp(newDate(timestampNode.dateTime)); timestampTitle=timestampNode.title; }elseif(timestampNode.classList.contains("localcomments")){ timestamp=timestampNode.getAttribute("title"); }else{ timestamp=timestampNode.textContent; } // Try finding revisions with an exact timestamp match varrevisions=pageRevisions.filter(function(revision){ returnrevision.timestampText===timestamp; }); if(!revisions.length){ // Try finding revisions which are off by one miniute revisions=pageRevisions.filter(function(revision){ returnrevision.oneMinutePriorTimestampText===timestamp; }); } if(revisions.length){// One or more revisions had a matching timestamp // Generate a link of the diff the between newest revision in the array, // and the parent (previous) of the oldest revision in the array. varnewerRevId=revisions[0].revid; varolderRevId=revisions[revisions.length-1].parentid||"prev"; varhref="/wiki/Special:Diff/"+olderRevId+"/"+newerRevId; // Title attribute for the link can be the revision comment if there was // only one revision, otherwise use the number of revisions found varcomment=revisions.length===1?revisions[0].comment:revisions.length+" edits"; vartitle="Diff ("+comment+")"; if(timestampTitle){ title+="\n"+timestampTitle; } linkTimestamp(timestampNode,href,title); } }); if(apiQueryCount<5&&document.getElementsByClassName("tsdiffs-unlinked").length){ returnprocessTimestamps(pageRevisions[pageRevisions.length-1].revid); } }); }; returnprocessTimestamps() .catch(function(code,error){ mw.notify("Error: "+(code||"unknown"),{title:"TimestampDiffs failed to load"}); console.warn("[TimestampDiffs] Error: "+(code||"unknown"),error); }); }); // </nowiki>