User:Fred Gandt/watchUserContribs.js

if ( ( /^Special:Contributions/ ).test( mw.config.get( "wgPageName" ) ) ) { "use strict";

let wtchlst = sessionStorage[ "fg-watchlist" ] || {};

const STYL = document.createElement( "style" ),

quotes2Hashes = s => s.replace( /\"/g, "#" ),

firstInputIn = e => e.querySelector( "input" ),

sessionStore = => sessionStorage[ "fg-watchlist" ] = JSON.stringify( wtchlst ),

sessionClear = => { if ( confirm( "The cache will be recompiled the next time you load a user contribs page." ) ) {				delete sessionStorage[ "fg-watchlist" ]; }		},

apiQuery = ( dt, fnc ) => { dt.format = "json"; $.ajax( {				type: "POST",				url: "/w/api.php",				dataType: dt.format,				data: dt,				success: function( data ) { fnc( data ) },				error: function( data) { console.error( data ) }			} ); },

doTheDo = => { $( document ).ready( => {				const SCTN = document.querySelector( "section.mw-pager-body" ),					LIS = SCTN.querySelectorAll( "li[data-mw-revid]" ),

boSelector = evt => { let trg = evt.target, chckd = trg.checked; LIS.forEach( li => firstInputIn( li ).checked = chckd ); firstInputIn( trg.parentElement === TOPOPT ? BTMOPT : TOPOPT ).checked = chckd; },

captainKoons = evt => { let wtchn = evt.target.value === "Watch", slctd = Array.from( LIS ) .map( li => firstInputIn( li ) ) .filter( npt => npt.checked && !( wtchn && npt.parentElement.classList.contains( "fg-watched" ) ) ) .map( npt => npt.value.replace( /( talk(?=:)|Talk:)/, "" ) ); slctd = [ ...new Set( slctd ) ]; let ttls = slctd.splice( 0, 50 ); while ( ttls.length ) { let qs = { action: "watch", titles: ttls.join( "|" ), token: mw.user.tokens.values.watchToken };							if ( !wtchn ) { qs.unwatch = true; }							apiQuery( qs, function( data ) {								data.watch.map( r => r.title ).forEach( ttl => { if ( wtchn ) { wtchlst[ ttl ] = 1; } else { delete wtchlst[ ttl ]; }									SCTN.querySelectorAll( `input[data-title$="${quotes2Hashes( ttl )}"]` ).forEach( npt => npt.parentElement.classList.toggle( "fg-watched", wtchn ) ); } );								sessionStore;							} ); ttls = slctd.splice( 0, 50 ); }					},

makeInput = ( t, v ) => { let npt = document.createElement( "input" ); npt.type = t;						npt.title = npt.value = v;						npt.dataset.title = quotes2Hashes( v ); npt.classList.toggle( "fg-checkbox", t === "checkbox" ); return npt; },

makeOptions = => { let p = document.createElement( "p" ); npt = makeInput( "checkbox", "(De)select all" ); npt.addEventListener( "change", boSelector, { passive: true } ); p.append( npt ); npt = makeInput( "button", "Watch" ); npt.addEventListener( "click", captainKoons, { passive: true } ); p.append( npt ); p.append( document.createTextNode( " or " ) ); npt = makeInput( "button", "Unwatch" ); npt.addEventListener( "click", captainKoons, { passive: true } ); p.append( npt ); p.append( document.createTextNode( " the selected pages. " ) ); npt = makeInput( "button", "Clear watchlist cache" ); npt.addEventListener( "click", sessionClear, { once: true, passive: true } ); p.append( npt ); return p;					},

TOPOPT = makeOptions, BTMOPT = makeOptions;

STYL.textContent = "li.fg-watched{border:0 solid #90d4e9;border-width:1px .5em}input.fg-checkbox{margin:0 1em 0 .5em;vertical-align:-10%}"; document.querySelector( "head" ).append( STYL );

LIS.forEach( li => {					let ttl = li.querySelector( "a.mw-contributions-title" ).title;					li.classList.toggle( "fg-watched", !!wtchlst[ ttl ] );					li.prepend( makeInput( "checkbox", ttl ) );				} ); SCTN.prepend( TOPOPT ); SCTN.append( BTMOPT ); } );		},

compileWatchlist = wlr => { apiQuery( wlr, function( data ) {				data.watchlistraw.forEach( ttl => wtchlst[ ttl.title ] = 1 );				if ( data.continue ) {					wlr.wrcontinue = data.continue.wrcontinue;					compileWatchlist( wlr );				} else if ( data.hasOwnProperty( "batchcomplete" ) ) {					sessionStore;					doTheDo;				}			} ); };

if ( $.isEmptyObject( wtchlst ) ) { compileWatchlist( { action: "query", list: "watchlistraw", wrlimit: 500 } ); } else { wtchlst = JSON.parse( wtchlst ); doTheDo; } }