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();
}
}