MediaWiki:Gadget-transclusion-check.js

// ================================================================== // Scan an Index page's childen for transclusion status // // Add a tool to the sidebar on Index pages. When activated, each page in the // page list is checked for transclusion. // // Pages that are transcluded have a CSS class added. // Pages that are manually tagged as not transcluded ditto. // // The accompanying CSS then contains simple logic styling pages based on these // classes and whether or not they are expected to be transcluded or not. // ==================================================================

/* eslint-disable one-var, vars-on-top */ // Wait for the page to be parsed (new-style $(document).ready) $(function {	console.log("[transclusion-check]: loading with revision 12.");

// Add portlet to let the user invoke the check. var checkPortlet = mw.util.addPortletLink(		'p-tb', '#', 'Check transclusion', 'ca-checktransclude',		'Check the transclusion status of each page in this index (shift-click to clear).'	); $(checkPortlet).on('click', handleClick);

// Also add a check link to the transclusion status $(' check ') .on('click', handleClick) .appendTo("#ws-index-transclusion-value");

// Then bootstrap by fetching info about page status, but only if logged in. if (mw.config.get('wgUserName') !== null) { var query = makeQuery({}, true); var api = new mw.Api; api.get(query) .done(updateStatusOrFetchMore); } }); // END: $(document).ready

// Common handling of a user click on any one of the several points of // invocation, toggle styling, and run the check if relevant. function handleClick (e) { e.preventDefault; $('.transcluded').removeClass('transcluded'); $('.exempt').removeClass('exempt'); if (e.shiftKey) { // Remove transclusion indicator styling $('.prp-index-pagelist').removeClass('transclusion-check'); } else { $('.prp-index-pagelist').addClass('transclusion-check'); var api = new mw.Api; var query = makeQuery({}, false); api.get(query) .done(updateStatusOrFetchMore); } }

// // Callback called from mw.api's .done. // // If there's more data, call the API again requesting the next batch, giving // ourselves as the callback when .done. // // In either case, add classes to the pagelist entries reflecting their // transclusion status and category menbership. // function updateStatusOrFetchMore(data) { if (typeof data === 'undefined') { // Garbage from the API? console.log("[transclusion-check]: data passed from mw.api was undefined."); return; }

// If the API returns an error or warning, dump it to the console. if (data.hasOwnProperty('errors')) { console.log(data.warnings); }	if (data.hasOwnProperty('warnings')) { console.log(data.warnings); }

// If the response has a .continue node then there is more data to be // fetched, so fire off a request for the next batch immediately. if (data.hasOwnProperty('continue')) { var query; if (data.continue.hasOwnProperty('rvcontinue')) { // We're in the init phase, only getting revisions. query = makeQuery(data, true); } else { query = makeQuery(data, false); }		var api = new mw.Api; api.get(query).done(updateStatusOrFetchMore); }

// Loop over the returned list of pages and update classes in the pagelist // accordingly. Missing data should not be a problem as it'll turn up in // subsequent (.continue) API calls and be updated then. for (var p in data.query.pages) { // ES6 for…of would be nice… var page = data.query.pages[p]; var title = $.escapeSelector(page.title);

// If the page has a transclusion add a class indicating that. //		// If there's no transclusion add a class for that, which will be // removed if we later get data that it is transcluded. //		// We filter the namespaces in the API query so only transclusions to // mainspace (ns:0) and Translation: (ns:114) are included. if (page.hasOwnProperty('transcludedin')) { $('[title="' + title + '"]') .addClass('transcluded') .removeClass('untranscluded'); $('[title="' + title + ' (page does not exist)' + '"]') .addClass('transcluded') .removeClass('untranscluded'); } else { // Not transcluded anywhere, or we haven't gotten info about the // transclusion from the API yet. Add a class to indicate this, // but never add .untranscluded to a page that already has the // .transcluded class because we could be processing the requests // out of order. $('[title="' + title + '"]') .not('.transcluded') .addClass('untranscluded'); $('[title="' + title + ' (page does not exist)' + '"]') .not('.transcluded') .addClass('untranscluded'); }

// If the page has a .category node it means the page us a member of // the "Not transcluded" category we requested data from the API about. if (page.hasOwnProperty('categories')) { $('[title="' + title + '"]').addClass('exempt'); }

// If there is a .revisions node present then this is the bootstrap run // so check it against the current user and tag the page accordingly. if (page.hasOwnProperty('revisions')) { var content = page.revisions[0].slots.main.content; var revision = JSON.parse(content);

// Add class for pages the current user can progress. var user = revision.level.user; var progress = revision.level.level; if (progress === 1 || progress === 2) { // "Problematic" and "Not Proofread" can always be progressed. $('[title="' + title + '"]') .addClass('wsg-user-can-progress'); } else if (progress === 3) { // "Proofread" can be progressed by a different user. if (user !== mw.config.get('wgUserName')) { $('[title="' + title + '"]') .addClass('wsg-user-can-progress'); }			}		}	} }

// // Construct a parameter object (associative array) for mw.api. // function makeQuery (data, init) { // Basic query options for every API call. var query = { "action": "query", "format": "json", "formatversion": "2", "generator": "proofreadpagesinindex", "gprppiiprop": "title", "gprppiititle": mw.config.get("wgPageName"), "prop": [] };

// On the first query we init by requesting revisions too. if (init) { query['prop'].push('revisions'); query['rvprop'] = 'content'; query['rvslots'] = 'main'; query['rvcontentformat-main'] = 'application/json'; } else { query['prop'].push('transcludedin'); query['tiprop'] = 'pageid'; query['tinamespace'] = [0, 114];

query['prop'].push('categories'); query['clcategories'] = 'Category:Not transcluded'; query['clshow'] = 'hidden'; }

// If there's a .continue node present in the response then amend the query // to include it. if (data.hasOwnProperty('continue')) { $.extend(query, data.continue); }

return query; }