MediaWiki:Gadget-BatchPurge.js
Note : après avoir publié vos modifications, il se peut que vous deviez forcer le rechargement complet du cache de votre navigateur pour voir les changements.
- Firefox / Safari : maintenez la touche Maj (Shift) en cliquant sur le bouton Actualiser ou appuyez sur Ctrl + F5 ou Ctrl + R (⌘ + R sur un Mac).
- Google Chrome : appuyez sur Ctrl + Maj + R (⌘ + Shift + R sur un Mac).
- Edge : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl + F5.
/* Copied from https://dev.fandom.com/wiki/MediaWiki:MassNullEdit/code.js */
/* MassNullEdit originally by OneTwoThreeFall and Ozuzanna */
const apiModeData = {
backlinks: {
name: 'backlinks',
limit: 'bllimit',
value: 'bltitle'
},
transclusions: {
name: 'embeddedin',
limit: 'eilimit',
value: 'eititle'
},
fileusage: {
name: 'imageusage',
limit: 'iulimit',
value: 'iutitle'
},
prefix: {
name: 'prefixsearch',
limit: 'pslimit',
value: 'pssearch'
},
category: {
name: 'categorymembers',
limit: 'cmlimit',
value: 'cmtitle'
},
namespace: {
name: 'allpages',
limit: 'aplimit',
value: 'apnamespace'
}
};
const namespaces = mw.config.get('wgFormattedNamespaces');
let i18n;
const editApi = new mw.Api();
let failedPages = [];
let input;
const modalMain = new mw.libs.QDmodal('mne-main');
const modalAddPages = new mw.libs.QDmodal('mne-addpages');
let paused = true;
let rateLimited = false;
let rateLimitTimeoutId;
let stopAddPages = null;
modalMain.$element.addClass("mne-modal");
modalAddPages.$element.addClass("mne-modal");
function log(i18nMsg) {
$('#mne-output').prepend(i18nMsg.parse(), '<br>');
}
function addToInput(pages) {
var currentPages = input.value.split('\n');
pages = pages.filter(function (page) {
return currentPages.indexOf(page) === -1;
});
if (pages.length) {
input.value += pages.join('\n') + '\n';
}
return pages.length;
}
function nullEdit(titles) {
var editReq = editApi.post({
action: 'purge',
titles,
forcerecursivelinkupdate: true
});
editReq.always(function (result, resultIfRejected) {
if (editReq.state() === 'rejected') {
result = resultIfRejected;
}
var error = result.error && result.error.code;
if (error === 'ratelimited') {
rateLimited = true;
input.value = `${titles.join('\n')}\n${input.value}`;
} else if (error) {
failedPages.push(...titles);
log(i18n('fail', titles, error));
}
process();
});
}
function pause() {
paused = true;
rateLimited = false;
modalMain.$element.removeClass("processing");
}
function start() {
paused = false;
modalMain.$element.addClass("processing");
process();
}
function process() {
if (rateLimited) {
log(i18n('notice-ratelimit'));
pause();
rateLimitTimeoutId = setTimeout(start, 30000);
}
if (paused || input === null) {
return;
}
const pages = input.value
.trim()
.split('\n')
.map(p => p.trim())
.filter(Boolean);
const batch = pages.splice(0, 50);
input.value = pages.join('\n');
if (batch.length) {
nullEdit(batch);
} else {
log(i18n('notice-finished'));
addToInput(failedPages);
failedPages = [];
pause();
}
}
function addPages(query, mode, displayValue) {
var pages = [];
var queryApi = new mw.Api({parameters: query});
function complete(error) {
if (error) {
log(i18n('notice-error-' + mode, displayValue, error));
}
// show success message if either no error (a successful result may be 0 pages)
// or error (in which case a multi-request query might still have some results)
if (!error || pages.length) {
var addedCount = addToInput(pages);
log(i18n('notice-success-' + mode, displayValue, addedCount));
}
// reset "add pages" modal if it was used
modalAddPages.$element.removeClass("processing");
modalAddPages.hide();
}
function collect(more) {
var queryReq = queryApi.get(more);
queryReq.always(function (result, resultIfRejected) {
if (queryReq.state() === 'rejected') {
result = resultIfRejected;
}
var error = (result.error && result.error.code) || 'unknown';
var data = result.query && result.query[query.list];
var continueData = result['query-continue'];
if (data) {
data.forEach(function (entry) {
pages.push(entry.title);
});
} else {
complete(error);
return;
}
if (continueData && stopAddPages === null) {
stopAddPages = !confirm(i18n('confirm-big-request', result.limits[query.list]).parse());
}
if (continueData && !stopAddPages) {
collect(continueData[query.list]);
} else {
complete();
}
});
}
modalAddPages.$element.addClass("processing");
collect();
}
function addPagesProcess(mode, value) {
var modeData = apiModeData[mode];
var query = {rawcontinue: ''};
const nsCategory = `${namespaces[14]}:`;
const nsFile = namespaces[6] + ':';
// cancel if unknown mode or empty/undefined value
if (!modeData || !value) {
return;
}
let displayValue = value;
// mode-specific adjustments
switch (mode) {
case 'namespace':
// use namespace name for displaying namespace requests
displayValue = value === '0'
? i18n('namespace-main').escape()
: namespaces[value];
break;
case 'category':
// add namespace to category value if not included,
// else remove it from display for brevity
if (value.indexOf(nsCategory) !== 0) {
value = nsCategory + value;
} else {
displayValue = displayValue.slice(nsCategory.length);
}
break;
case 'fileusage':
// add namespace to file value if not included,
// else remove it from display for brevity
if (value.indexOf(nsFile) !== 0) {
value = nsFile + value;
} else {
displayValue = displayValue.slice(nsFile.length);
}
break;
case 'prefix':
// separate namespace id
var nsAndTitle = new mw.Title(value);
query.apnamespace = nsAndTitle.namespace;
value = nsAndTitle.title;
break;
}
query.list = modeData.name;
query[modeData.value] = value;
query[modeData.limit] = 'max';
addPages(query, mode, displayValue);
}
function addPagesCreateModalRow(mode) {
var $row = $('<p>').attr('class', 'mne-addpages-row');
var $radio = $('<input>').attr({
type: 'radio',
name: 'mode',
value: mode
});
var $input = $('<input>').attr({
type: 'text',
name: mode
});
if (mode === 'namespace') {
$input = $('<select>').attr('name', mode);
Object.keys(namespaces).forEach(function (ns) {
if (Number(ns) < 0) {
return;
}
var opt = document.createElement('option');
opt.value = ns;
opt.textContent = ns === '0'
? i18n('namespace-main').plain()
: namespaces[ns];
$input.append(opt);
});
}
// select a mode if its value is changed
$input.on('change', function () {
$radio.prop('checked', true);
});
$row.append(
$('<label>').append(
$radio,
document.createTextNode(i18n('addpages-' + mode).plain())
),
$input
);
return $row;
}
function addPagesOpenModal() {
var formData;
var $modalContent = $('<form>').attr('id', 'mne-mode');
Object.keys(apiModeData).forEach(function (mode) {
$modalContent.append(addPagesCreateModalRow(mode));
});
modalAddPages.show({
title: i18n('addpages').plain(),
content: $modalContent,
onShow: function () {
stopAddPages = null;
formData = document.forms['mne-mode'].elements;
modalAddPages.$footer.append(
$('<span>').attr('id', 'mne-processing-msg').text(i18n('processing').plain()),
mw.libs.QDmodal.getSpinner()
);
},
onHide: function () {
stopAddPages = true;
},
buttons: [{
text: i18n('addpages').plain(),
attr: {id: 'mne-addpages-start'},
handler: function () {
// formData.mode.value would be better, but not available in IE 11
var mode = modalAddPages.$content.find('[name=mode]:checked').val();
var value = formData[mode] && formData[mode].value;
addPagesProcess(mode, value);
}
}, {
text: i18n('cancel').plain(),
handler: modalAddPages.hide.bind(modalAddPages)
}]
});
}
function autoFillPages() {
const relevantPage = new mw.Title(mw.config.get('wgRelevantPageName'));
if (mw.config.get('wgCanonicalNamespace') === 'Category') {
addPagesProcess('category', relevantPage.getPrefixedText());
}
switch (mw.config.get('wgCanonicalSpecialPageName')) {
case 'Whatlinkshere':
addPagesProcess('backlinks', relevantPage.getPrefixedText());
addPagesProcess('transclusions', relevantPage.getPrefixedText());
if (relevantPage.namespace === 6) {
addPagesProcess('fileusage', relevantPage.getPrefixedText());
}
break;
case 'Allpages':
addPagesProcess(
'namespace',
$('form [name="namespace"]').val()
);
break;
case 'Prefixindex':
var prefix = $('form [name="prefix"]').val();
var prefixNs = $('form [name="namespace"]').val();
var page = '';
if (prefixNs !== '0') {
page += namespaces[prefixNs] + ':';
}
page += prefix;
addPagesProcess('prefix', page);
break;
}
}
function openModal(ev) {
ev.preventDefault();
var modalContents = (
'<p>' + i18n('instructions').escape() + '</p>' +
'<textarea id="mne-input"></textarea>' +
'<div id="mne-output">' +
'<i>' + i18n('notice-output').escape() + '</i>' +
'</div>'
);
modalMain.show({
title: i18n('title').plain(),
content: modalContents,
onShow: function () {
input = document.getElementById('mne-input');
pause();
modalMain.$footer.append(
$('<span>').attr('id', 'mne-processing-msg').text(i18n('processing').plain()),
mw.libs.QDmodal.getSpinner()
);
},
onHide: function () {
pause();
input = null;
clearTimeout(rateLimitTimeoutId);
},
buttons: [{
text: i18n('initiate').plain(),
attr: {id: 'mne-main-start'},
handler: start
}, {
text: i18n('pause').plain(),
attr: {id: 'mne-main-pause'},
handler: pause
}, {
text: i18n('addpages').plain(),
handler: addPagesOpenModal
}, {
text: i18n('cancel').plain(),
handler: modalMain.hide.bind(modalMain)
}]
});
autoFillPages();
}
window.dev.i18n.loadMessages('MassNullEdit').done(function (i18nData) {
i18n = i18nData.msg;
const link = mw.util.addPortletLink('p-tb', '#', i18n('title').plain(), 't-mne');
if (link) {
link.addEventListener('click', openModal);
}
});