Jump to content
Wikipedia The Free Encyclopedia

User:Evad37/TimestampDiffs.js

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 user script seems to have a documentation page at User:Evad37/TimestampDiffs.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
 /***************************************************************************************************
  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>

AltStyle によって変換されたページ (->オリジナル) /