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.
* By Bobogoobo
*/
//TODO: potential additions:
// *Maybe update the number of links on "Wanted" reports
// *Maybe make a progress meter of some sort
// *Should probably use .fail to make sure everything gets wrapped up
// *Internationalization (as noted in code)
// *Combine some requests so it doesn't take as long and make as many (maybe use POST and do them all at once)
// *Add a button to run the script if execution is skipped due to user specification;
// not sure how drastic a restructure this would require
//Note: imageusage, embeddedin, and backlinks can take &xxcount=true to return only the number of them.
mw.loader.using('mediawiki.util').done(function() {
'use strict';
if (window.CacheCheckLoaded) {
return;
}
window.CacheCheckLoaded = true;
var removeIfFalse = false,
aliase = [],
skips = window.cacheSkip || [],
skipLimit = Number(window.cacheSkipLimit) || 1000,
list = $('ol.special').length ? $('ol.special > li') : $('ul.gallery > li, div.wikia-gallery-item'),
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',
'UnusedVideos',
'Wantedcategories',
'Wantedpages',
'Wantedfiles',
'Wantedtemplates'
],
pathRegex,
i18n;
function takeAction($el) {
if (window.CacheCheckRemove) {
$el.remove();
} else {
var $gallery = $el.find('.gallerytext a:first, .gallery-image-wrapper 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>');
}
}
}
// 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') ||
skipLimit < (Number(mw.util.getParamValue('limit')) || 0)
) {
return;
} else if (page === 'Specialpages') {
$.getJSON(qstr + 'meta=siteinfo&formatversion=2&siprop=specialpagealiases').then(function(data) {
var spa = data.query.specialpagealiases;
for (var i = 0; i < spa.length; i++) {
var aliasList = spa[i].aliases;
for (var j = 0; j < aliasList.length; j++) {
aliase[aliasList[j].replace(/_/g, ' ')] = spa[i].realname;
}
}
}).then(function() {
pages.push('BrokenRedirects', 'DoubleRedirects');
$('#mw-specialpagesgroup-maintenance + .mw-specialpages-list li.mw-specialpagecached').each(function() {
var $this = $(this),
link = $this.children('a').attr('title').substring(8);
var tmp = aliase[link] || link;
if (pages.indexOf(tmp) === -1) {
console.log('[CacheCheck]', 'Missing page: ' + tmp + ' (' + link + ')');
return;
}
$.getJSON(qstr + 'list=querypage&qppage=' + tmp, function(data) {
var results = data.query.querypage.results;
if (results.length === 0) {
takeAction($this);
}
if (
tmp === 'Uncategorizedcategories' &&
results.length === 1 &&
results[0].title === window.topLevelCat
) {
takeAction($this);
}
});
});
});
return;
}
// Only on "Wanted" reports, entries are resolved if the query result is empty.
if (page.substring(0, 6) === 'Wanted') {
removeIfFalse = true;
}
// 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, .gallery-image-wrapper a:first' : 'a:first',
url = $this.find(select).attr('href'),
redlinkUrl = $this.find(select).data('uncrawlableUrl');
if (redlinkUrl) {
url = atob(redlinkUrl);
}
url = new mw.Uri(url);
if (page === 'Lonelypages') {
qs += foo ? 'list=embeddedin&eititle=' : 'list=backlinks&bltitle=';
}
qs += encodeURIComponent(decodeURIComponent(url.path).replace(pathRegex, ''));
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 https://archive.is/RwvEn
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(i18n('checkdone').plain());
} else {
$('#CacheCheck').text(i18n('checking', pending).plain());
}
}
// 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 'UnusedVideos':
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(i18nData) {
var regexEscape = $.escapeRE ?
// Legacy Fandom
$.escapeRE :
mw.RegExp ?
// MediaWiki 1.26+
mw.RegExp.escape :
// MediaWiki 1.34+
mw.util.escapeRegExp;
pathRegex = new RegExp('^' + regexEscape(mw.config.get('wgArticlePath').replace('$1', '')));
i18n = i18nData.msg;
$('.mw-spcontent').append(
$('<p>', {
id: 'CacheCheck',
text: i18n('checking', pending).plain()
})
);
list.each(function() {
var $this = $(this);
if (isgallery) {
// Uncategorizedimages, Unusedimages, UnusedVideos
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 (Boolean(removeIfFalse) === (data.length === 0)) {
takeAction($this);
}
checkComplete();
});
}
});
}
mw.hook('dev.i18n').add(function (i18njs) {
i18njs.loadMessages('CacheCheck').done(init);
});
if (!window.dev || !window.dev.i18n) {
importArticle({
type: 'script',
article: 'u:dev:MediaWiki:I18n-js/code.js'
});
}
});