User:Js/watchlist.js - Wikipedia


Article Images

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.

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.

function WLScript(){

var whenPageLoaded = +(new Date()) - 20000 //add 20 sec just in case

var mainTab, hideInterfaceCSS
var alreadySorted, alreadyAddedUnwatch

mw.util.addCSS('\
a.failure {color:red}\
a.unwatched {text-decoration: line-through}\
')

//enwiki
var mm = 
{sortTip:'Sort rows by even namespace number, then by page title'
,sortDone:'Watchlist changes already sorted'
,unwatchTip:'Add (x) quick unwatch links'
,unwatchDone:'Use (x) links to quickly unwatch pages'
,onlynew:'Only new'
,onlynewTip:'Show changes since this page was last loaded'
,expandAll:'Expand multiple edits'
,fullPage:'Hide/Show interface'
}
PngFixDisabled = true


//enhanced RC: make (x) appear by clicking on timestamp
var isEnhanced = $( '#mw-content-text ul.special').length === 0;
if( isEnhanced ) $( '#mw-content-text' ).click(toggleXLink)

//find insertion points for links:  after "days all"
var linksAt = $('#mw-watchlist-options').find('#days').eq(0);
if( !linksAt.length ) linksAt = $('#mw-watchlist-options').find('hr:last')
//find "Special" tab
mainTab = $('#ca-special, #ca-nstab-special').eq(0);

//"only new" link and tab
addLnk(mm.onlynew, mm.onlynewTip).click(onlyNewEntries).attr('id', 'listSince');
addTab(mm.onlynew, mm.onlynewTip).click(onlyNewEntries);

//"unwatch" link(s)
if( window.unwatchLinksOnLoad ) addXLinks()
else addLnk('x' , mm.unwatchTip).click(addXLinks)

//"sort" link
addLnk('↑↓', mm.sortTip).click(sortWatchlist)

//"expand all" link
if( $('#mw-rc-openarrow-0').length )
  addLnk('±', mm.expandAll).click(expandMultipleEdits)

//"hideInterface" tab
addTab('↸',mm.fullPage).click(hideInterface).attr('href','#')
if( document.cookie.indexOf('wlmax=1') != -1 )
  hideInterface()


function addLnk(txt, tip){
  var link = $('<a href="#" title="'+tip+'" style="font-style:italic">'+txt+'</a>').insertAfter(linksAt);
  linksAt.after(' | ');
  return link;
}
function addTab(txt, tip){
  if( window.wlNoTabs ) return
  var tab = mainTab.clone(true).removeClass('selected').attr('id','')
  tab.find('a').text(txt).attr('title', tip).attr('accesskey','')
  return tab.appendTo(mainTab.parent())
}

return



function onlyNewEntries(e) {
 var url = window.location.href.split('#')[0]
 var days = ( +(new Date()) - whenPageLoaded)/(1000 * 3600 * 24)
 e.target.href = /[?&]days=/.test(url)
  ? url.replace(/([?&]days=)[^&]*/, '$1'+days)
  : url + (url.indexOf('?') < 0 ? '?':'&') + 'days=' + days
 return true
}



function sortWatchlist(e){
 e.preventDefault()
 if( alreadySorted ) return alert(mm.sortDone)
 $( '#mw-content-text' ).find('h4').each(function(i, H4){ //sort all days separately
   sortDay($(H4).next('div, ul'))
 })
 alreadySorted = true
}

function sortDay(dayDiv){
 var i, ns, pgname, rowElem, hiddenDiv, rows = dayDiv.find('a[href*="&action=history"]')
 for (i = 0; i < rows.length; i++){
   pgname = getLinkTitle(rows[i])
   ns = getTitleNamespace(pgname)
   if( ns>0 ) pgname = pgname.replace(/^.+?:/,'') //remove prefix
   if( ns%2 ) ns-- //sort talk page as if it was a base page
   rows[i].sortkey = zzz(ns) + ':' + pgname //assign custom tag attribute: namespace+title
 }
 //sort rows array
 rows.sort(function(a,b){
   if( a.sortkey > b.sortkey ) return 1
   else if( a.sortkey < b.sortkey ) return -1
   else return 0
 })
 //sort rows in HTML, by moving all to the bottom
 if( isEnhanced )
   for (i=0; i<rows.length; i++){
     rowElem = rows.eq(i).closest('table')
     hiddenDiv = rowElem.next('div')
     dayDiv.append(rowElem, hiddenDiv)
   }
 else
   for (i=0; i<rows.length; i++){
     rowElem = rows.eq(i).closest('li')
     dayDiv.append(rowElem)
   }
}



function expandMultipleEdits(e){
 e.preventDefault()
 var i = 0, sp, state = $('#mw-rc-openarrow-0')[0].style.display
 while( sp=document.getElementById('mw-rc-openarrow-'+(i++).toString()) )
   if( sp.style.display == state ) $(sp.firstChild).click()
}




function addXLinks(e){
 if( e ) e.preventDefault()
 if( alreadyAddedUnwatch ) return alert(mm.unwatchDone)
 $( '#mw-content-text' ).find('a[href*="&action=history"]')
 .each( function(i, lnk){ addXLink( $(lnk) ) } )
 alreadyAddedUnwatch = true
}

function addXLink(histLink){ //create and append (x) link to the row with histLink
  var xLnk = $('<a class="aj-unwatch" style="font-size:smaller" href="'
            + histLink.attr('href').replace(/&curid=\d+/,'') + '" />')
          .click(ajaxUnwatch)
  if( isEnhanced ) histLink.parent().prepend( xLnk.text('(x)'), ' ' )
  else histLink.after( ' | ', xLnk.text('x') )
  updateXLink(xLnk)
}

function updateXLink(xLnk, state){ //change title and url of (x) link
  if( !xLnk.length ) return
  state = state ? 'watch' : 'unwatch'
  xLnk.attr( 'title', mw.msg(state) )
      .attr( 'href', xLnk.attr('href').replace(/&action=\w+/, '&action='+ state) )
}





function toggleXLink(e){ //add (x) when clicking on timestamp
   if( ! $(e.target).filter('td.mw-enhanced-rc').length ) return
   var tbl = $(e.target).parents('table.mw-enhanced-rc')
   var x = tbl.find('a.aj-unwatch')
   if( x.length ) x.remove()
   else addXLink(tbl.find('a[href*="&action=history"]'))
}


function ajaxUnwatch(e) {
 var xLnk = $(this), errMsg = ''
 var req = { action: 'watch', format: 'json', title: getLinkTitle(xLnk),
             token: mw.user.tokens.get('watchToken') }
 if( /&action=unwatch/.test(xLnk.attr('href')) ) req.unwatch = ''
 $.ajax({ 
   type:'POST', dataType: 'json', 
   url: mw.util.wikiScript( 'api' ),
   data: req,
   timeout: 5000,
   success: function(resp){
     if( resp.error ) errMsg = resp.error.info
     else if( !resp.watch ) errMsg = 'empty response'
     else if( typeof resp.watch.unwatched == 'string') unwatchSuccess( req.title, true )
     else if( typeof resp.watch.watched   == 'string') unwatchSuccess( req.title, false )
     else errMsg = 'unrecognized response'
   },
   error: function(xhr, status, err) {
     errMsg = status + ':' + err
   },
   complete: function(){ //update X link
     if( errMsg ) xLnk.attr( 'title', 'API error: ' + errMsg ).addClass('failure')
     else xLnk.removeClass('failure')
   }
 })
 return false
}



function unwatchSuccess(name, isUnwatched) {
  //find full name of associated talk page (or vice versa)
  var ns = getTitleNamespace(name)
  var name2 = name
  if( ns > 0 ) name2 = name2.replace(/^.+?:/,'') //remove old prefix
  if( ns % 2 )  ns--; else ns++ //switch to  "other" namespace
  if( ns > 0 ) name2 = mw.config.get('wgFormattedNamespaces')[ns] + ':' +  name2 //add new prefix
  //mark all rows that are either name or name2
  $( '#mw-content-text' ).find('a[href*="&action=history"]').each(function(){
    var ttl = getLinkTitle(this)
    if( ttl != name && ttl != name2 ) return
    var row = $(this).parent()
    zthis = this
    row.children('a[href^="/wiki"]:first').toggleClass('unwatched', isUnwatched)
    updateXLink( row.children('a.aj-unwatch'), isUnwatched )
       
  })
}



function hideInterface(e){

 if( e ) e.preventDefault()

 if (!hideInterfaceCSS)  hideInterfaceCSS = mw.util.addCSS('\
 div#siteNotice, h1#firstHeading, #siteSub, #contentSub, fieldset#mw-watchlist-options,\
 div.mw-rc-label-legend, #mw-fr-watchlist-pending-notice {display:none}')
 else hideInterfaceCSS.disabled = !hideInterfaceCSS.disabled

 document.cookie = 'wlmax=' + (!hideInterfaceCSS.disabled ? '1' : '0;expires=' + (new Date()).toGMTString() + ';;')

 var a = mainTab.find('a') //replace "Special" tab text with "Watchlist"
 if( hideInterfaceCSS.disabled ){ //restore
     a.text( a.attr('oldtext') )
 }else{//set to "watchlist"
   a.attr('oldtext', a.text())
   a.text($('h1#firstHeading').text())
 }

}



function getTitleNamespace(title){ //returns namespace number
 var prefix = /^(.+?):/.exec(title)
 if( !prefix ) return 0 //no prefix means article
 return mw.config.get('wgNamespaceIds')[ prefix[1].toLowerCase().replace(/ /g,'_') ] || 0
} 

function getLinkTitle (lnk){ //gets 'title=' part from a link
  var ma = /(&|\?)title=([^&]+)/.exec( $(lnk).attr('href') )
  if( ma ) return decodeURIComponent(ma[2]).replace(/_/g,' ')
  else return ''
}

function zzz(s){ // 5 -> 005
 s = s.toString()
 if( s.length==1 ) return '00'+s
 else if( s.length==2 ) return '0'+s
 else return s
}


}


if( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Watchlist' && mw.config.get( 'wgAction' ) === 'view' ) {
	$.when( mw.loader.using( [ 'mediawiki.util', 'mediawiki.page.ready'] ), $.ready ).done( WLScript );
}