MediaWiki:Gadget-CacheCheck.js

From NPOWiki
Revision as of 11:24, 26 July 2021 by Bobogoobo (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/* CacheCheck.js
 * Crosses out resolved entries on the cached special pages to save time checking them.
 * Note: these pages have a much shorter cache here, but the script also helps at-a-glance on SpecialPages.
 *   Therefore, the script will only run on a report page if ten or fewer items are listed.
 *   Use window.cacheCheckAlways = true; to disable this.
 * Originally by Bobogoobo, edited by KockaAdmiralac and others, then ported off Wikia by Bobogoobo.
 * For full documentation and contribution history (other than changes before publishing), please see:
 *   https://dev.fandom.com/wiki/CacheCheck
 */
window.topLevelCat = 'Category:Contents';

mw.loader.using('mediawiki.util').done(function() {
	if (window.cacheCheckLoaded || mw.config.get('wgCanonicalNamespace') !== 'Special') {
		return;
	}
	window.cacheCheckLoaded = true;

	var removeIfFalse = false,
		skips = window.cacheSkip || [],
		skipLimit = Number(window.cacheSkipLimit) || 1000,
		throttle = !window.cacheCheckAlways;
		$list = $('ol.special').length ? $('ol.special > li') : $('ul.gallery > li'),
		isgallery = $('ol.special').length ? false : true,
		pending = $list.length,
		qstr = mw.util.wikiScript('api') + '?action=query&format=json&',
		structure = ['query'],
		page = mw.config.get('wgCanonicalSpecialPageName'),
		pages = [
			'Specialpages',
			'Deadendpages',
			'Lonelypages', 
			'Uncategorizedcategories',
			'Uncategorizedpages',
			'Uncategorizedimages',
			'Uncategorizedtemplates',
			'Unusedcategories',
			'Unusedimages',
			'Unusedtemplates',
			'Wantedcategories',
			'Wantedpages',
			'Wantedfiles',
			'Wantedtemplates'
		];

	// Only on "Wanted" reports, entries are resolved if the query result is empty.
	if (page.substring(0, 6) === 'Wanted') {
		removeIfFalse = true;
	}

	// Skip execution if not on a relevant page, page is skipped by user, 
	// or list on page is empty. Else, check for empty listings on SpecialPages.
	if (
		pages.indexOf(page) === -1 ||
		skips.indexOf(page) !== -1 ||
		($list.length === 0 && page !== 'Specialpages') ||
		(throttle && $list.length > 10 && page !== 'Specialpages') ||
		skipLimit < (Number(mw.util.getParamValue('limit')) || 0)
	) {
		return;
	} else if (page === 'Specialpages') {
		pages.push('BrokenRedirects', 'DoubleRedirects');
		$('#mw-specialpagesgroup-maintenance + .mw-specialpages-list li').each(function() {
			var $this = $(this),
				exceptions = {
					'Uncategorizedfiles': 'Uncategorizedimages', 
					'Unusedfiles': 'Unusedimages',
					'Brokenredirects': 'BrokenRedirects',
					'Doubleredirects': 'DoubleRedirects'
				},
				link = $this.children('a').attr('title').substring(8);
			link = link.charAt(0) + link.slice(1).toLowerCase();

			if (link in exceptions) {
				link = exceptions[link];
			}
			if (pages.indexOf(link) === -1) {
				return;
			}

			$.getJSON(qstr + 'list=querypage&qppage=' + link, function(data) {
				var results = data.query.querypage.results;
				if (results.length === 0) {
					takeAction($this);
				}
				if (
					link === 'Uncategorizedcategories' &&
					results.length === 1 &&
					results[0].title === window.topLevelCat
				) {
					takeAction($this);
				}
			});
		});
		return;
	}

	// Handles marking the given element as resolved.
	function takeAction($el) {
		if (window.cacheCheckRemove) {
			$el.remove();
		} else {
			var $gallery = $el.find('.gallerytext a:first');
			if ($gallery.length) {
				if ($gallery.find('img')) {
					// The link is actually on the image
					$el.remove();
				} else {
					$gallery.wrap('<s></s>');
				}
			} else {
				$el.wrapInner('<s></s>');
			}
		}
	}

	// Takes list element, returns generated API query string.
	// Foo is 0 or 1 for lonelypages section.
	function getQS($this, foo) {
		var qs = qstr,
			select = isgallery ? '.gallerytext a:first' : 'a:first',
			url = $this.find(select).attr('href');

		if (page === 'Lonelypages') {
			qs += foo ? 'list=embeddedin&eititle=' : 'list=backlinks&bltitle=';
		}
		qs += encodeURIComponent(mw.util.getParamValue('title', url));

		return qs;
	}

	// Takes a JSON request result, returns array relevant to current page.
	function getData(data) {
		for (var i = 0; i < structure.length; i++) {
			if (structure[i] === 'placeholder') {
				//shortcut/hack thanks to StackOverflow
				for (var first in data) break;
				data = data[first];
			} else {
				data = data[structure[i]];
			}
			if (data === undefined) {
				return [];
			}
		}
		return data;
	}

	// Takes element in list, marks script as complete if it is the last list element.
	function checkComplete() {
		pending -= 1;
		if (pending <= 0) {
			$('#CacheCheck').text('CacheCheck completed!');
		} else {
			$('#CacheCheck').text('CacheCheck is running... (' + pending + ' remaining)');
		}
	}

	// Note: all desired data is in the format of an array,
	// which in the case of "prop=" queries is missing when there is no data,
	// and otherwise is empty.
	switch (page) {
		case 'Unusedtemplates':
		case 'Wantedtemplates':
			qstr += 'list=embeddedin&eititle=';
			structure.push('embeddedin');
			break;
		case 'Uncategorizedcategories':
		case 'Uncategorizedpages':
		case 'Uncategorizedtemplates':
		case 'Uncategorizedimages':
			qstr += 'prop=categories&titles=';
			structure.push('pages', 'placeholder', 'categories');
			break;
		case 'Unusedimages':
		case 'Wantedfiles':
			qstr += 'list=imageusage&iutitle=';
			structure.push('imageusage');
			break;
		case 'Unusedcategories':
		case 'Wantedcategories':
			qstr += 'list=categorymembers&cmtitle=';
			structure.push('categorymembers');
			break;
		case 'Wantedpages':
			qstr += 'list=backlinks&bltitle=';
			structure.push('backlinks');
			break;
		case 'Deadendpages':
			qstr += 'prop=links&titles=';
			structure.push('pages', 'placeholder', 'links');
			break;
		default:
			break;
	}

	function init() {
		$('.mw-spcontent').append(
			$('<p>', {
				id: 'CacheCheck',
				text: 'CacheCheck is running... (' + pending + ' remaining)'
			})
		);
		$list.each(function() {
			var $this = $(this);
			if (isgallery) {
				// Uncategorizedimages, Unusedimages
				if ($this.find('img').length) {
					$.getJSON(getQS($this), function(data) {
						data = getData(data);
						if (data.length !== 0) {
							takeAction($this);
						}
						checkComplete();
					});
				} else {
					takeAction($this);
					checkComplete();
				}
			} else if (page === 'Lonelypages') {
				// The only one that needs two queries
				$.getJSON(getQS($this, 0), function(data) {
					data = data.query.backlinks;
					if (data.length && !($this.children('s').length)) {
						takeAction($this);
					}
					checkComplete();
				});
				$.getJSON(getQS($this, 1), function(data) {
					data = data.query.embeddedin;
					if (data.length && !($this.children('s').length)) {
						takeAction($this);
					}
					checkComplete();
				});
			} else {
				$.getJSON(getQS($this), function(data) {
					data = getData(data);
					if (removeIfFalse === (data.length === 0)) {
						takeAction($this);
					}
					checkComplete();
				});
			}
		});
	}

	init();
});