ميدياويكي:Gadget-transclusion-check.js
ملاحظة: بعد النشر، أنت قد تحتاج إلى إفراغ الكاش الخاص بمتصفحك لرؤية التغييرات.
- فايرفوكس / سافاري: أمسك Shift أثناء ضغط Reload، أو اضغط على إما Ctrl-F5 أو Ctrl-R (⌘-R على ماك)
- جوجل كروم: اضغط Ctrl-Shift-R (⌘-Shift-R على ماك)
- إنترنت إكسبلورر/إيدج: أمسك Ctrl أثناء ضغط Refresh، أو اضغط Ctrl-F5
- أوبرا: اضغط Ctrl-F5.
// ==================================================================
// 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 */
// Make sure the necessary modules are loaded
mw.loader.using(['mediawiki.util', 'mediawiki.api'], function () {
// Only active on Index:-namespace pages.
if (mw.config.get('wgCanonicalNamespace' ) !== 'Index') {
return;
}
// Only active when in view mode.
if (mw.config.get('wgAction') !== 'view') {
return;
}
// Wait for the page to be parsed (new-style $(document).ready())
$(function () {
// 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">فحص</span>')
.on('click', handleClick)
.appendTo("#ws-index-transclusion-value");
// And hijack the old link while we migrate to the new tool
$("#mw-indicator-transclusion_checker, #mw-indicator-transclusion_checker a").on('click', handleClick);
}); // END: $(document).ready()
}); // END: mw.loader.using()
// 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');
$('.prp-index-pagelist').removeClass(['transcluded', 'exempt']);
} else {
$('.prp-index-pagelist').addClass('transclusion-check');
checkTransclusion();
}
}
// Grab all pages listed in the pagelist, divide them into batches matching the
// API limit, and request transclusion status and applied categories from the
// API. Uses a factory function for the API query because the API can return
// partial results that require a nested continue request.
//
// TODO: The API limit may change so we really should have some way to determine
// it dynamically. Or, I suppose, set it as a global(ish) constant up top some
// suitable place if it can't be made dynamic.
function checkTransclusion() {
var batchSize = 50; // API action=query limit.
var allPages = $('.prp-index-pagelist-page').map(function() {
return $(this).attr('title')
.replace(/ \(page does not exist\)$/, '');
}).toArray();
for (var i = 0; i < allPages.length; i += batchSize) {
var batch = allPages.slice(i, i + batchSize).join('|');
var query = makeQuery(batch);
var api = new mw.Api();
api.get(query).done(createCallback(batch));
}
}
//
// Create a callback to handle API responses.
//
// The use of a factory function is because API requests that need to be
// continued will have to trigger a new request from the callback; in other
// words we have multiple call sites where this function is needed.
//
// The .bind() is because mw.Api() tramples all over the argument list when it
// calls the callback. To get the necessary parameter to the call site inside
// the callback we have to .bind() a dummy "this" and the "batch" parameter.
function createCallback(batch) {
return function(batch, data) {
if (data.hasOwnProperty('continue')) {
var query = makeQuery(batch, data);
var api = new mw.Api();
api.get(query).done(createCallback(batch));
}
for (var k in data.query.pages) { // ES6 for…of would be nice…
var page = data.query.pages[k];
if (page.hasOwnProperty('transcludedin')) {
$('[title="' + page.title + '"]').addClass('transcluded');
$('[title="' + page.title + " (page does not exist)" + '"]')
.addClass('transcluded');
}
if (page.hasOwnProperty('categories')) {
$('[title="' + page.title + '"]').addClass('exempt');
}
}
}.bind(this, batch);
}
//
// Construct a parameter object (associative array) for mw.api().
//
function makeQuery (batch, data) {
var query = {
action: 'query',
titles: batch,
prop: 'categories|transcludedin',
tiprop: 'title',
tinamespace: "0",
clcategories: "Category:Not transcluded",
format: 'json',
formatversion: 2
};
if (typeof data !== 'undefined' && data.hasOwnProperty('continue')) {
$.extend(query, data.continue);
}
return query;
}