ਮੀਡੀਆਵਿਕੀ:Gadget-transclusion-check.js

Note: After saving, changes may not occur immediately. Click here to learn how to bypass your browser's cache.
  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (Cmd-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (Cmd-Shift-R on a Mac)
  • Internet Explorer: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Clear the cache in Tools → Preferences

For details and instructions about other browsers, see Wikipedia:Bypass your cache.

// ==================================================================
// 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
	$('<span id="ws-transclusion-check-inline">check</span>')
		.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;
}