/*************************************************************************************************** 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/forEachif(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 pagesvarisExistingPage=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 belowvarmatch=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 nodesvarnext=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]] gadgetdocument.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 pagevarbasePageName=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 matchvarrevisions=pageRevisions.filter(function(revision){returnrevision.timestampText===timestamp;});if(!revisions.length){// Try finding revisions which are off by one miniuterevisions=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 foundvarcomment=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>