User:DR/test.js
< User:DR
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)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
//<nowiki>
$(document).ready(function() {
function initializeMassDelete() {
$('#mw-content-text > p').remove();
$('#firstHeading').text('MassDelete');
var deletionModeLabel = $('<p>').text('Deletion mode:').css('font-weight', 'bold');
var deletionModeSelect = new OO.ui.RadioSelectWidget({
items: [
new OO.ui.RadioSelectOptionWidget({ data: 'list', label: 'List of pages' }),
new OO.ui.RadioSelectOptionWidget({ data: 'category', label: 'Category' })
]
});
deletionModeSelect.selectItemByData('list');
var pagesTextarea = new OO.ui.MultilineTextInputWidget({
placeholder: 'Enter list of pages (one per line)',
autosize: true,
rows: 10
}),
reasonInputField = new OO.ui.TextInputWidget({ placeholder: 'Reason for deletion' }),
deleteTalkCheckbox = new OO.ui.CheckboxInputWidget({ selected: true }),
previewButton = new OO.ui.ButtonWidget({ label: 'Preview Deletion', flags: ['primary'] }),
startButton = new OO.ui.ButtonWidget({ label: 'Start Deletion', icon: 'alert', flags: ['primary', 'progressive'], disabled: true }),
cancelButton = new OO.ui.ButtonWidget({ label: 'Cancel', flags: ['primary', 'destructive'], href: 'https:' + mw.config.get('wgServer') }),
logContainer = $('<div>').hide();
var labels = {
deletionModeLabel: deletionModeLabel,
pagesLabel: $('<p>').text('Pages / Categories:').css('font-weight', 'bold'),
reasonLabel: $('<p>').text('Reason:').css('font-weight', 'bold'),
deleteTalkLabel: $('<label>')
.append(deleteTalkCheckbox.$element, $('<span>').text(' Also delete talk pages').css('padding-left', '5px'))
.css({ 'margin-top': '5px', 'margin-bottom': '5px' })
};
previewButton.$element.css('margin-top', '10px');
$('#mw-content-text').append(
labels.deletionModeLabel,
deletionModeSelect.$element,
labels.pagesLabel, pagesTextarea.$element,
labels.reasonLabel, reasonInputField.$element,
labels.deleteTalkLabel,
'<br/>',
previewButton.$element,
startButton.$element,
cancelButton.$element,
'<br/>',
logContainer
);
deletionModeSelect.on('choose', function(item) {
if (item.getData() === 'category') {
pagesTextarea.setPlaceholder('Enter category names (one per line)');
} else {
pagesTextarea.setPlaceholder('Enter list of pages (one per line)');
}
logContainer.empty().hide();
startButton.setDisabled(true);
});
function getPagesFromCategory(category) {
return $.ajax({
url: mw.util.wikiScript('api'),
data: { action: 'query', list: 'categorymembers', cmtitle: 'Category:' + category, cmlimit: 'max', format: 'json' },
dataType: 'json'
}).then(function(data) {
return data.query?.categorymembers?.map(item => item.title) || [];
});
}
function deletePage(page, reason, deleteTalk, callback) {
var params = { action: 'delete', title: page, reason: reason };
if (deleteTalk) params.deletetalk = true;
(new mw.Api({ ajax: { headers: { 'Api-User-Agent': 'en:User:DreamRimmer/MassDelete.js' } } }))
.postWithToken('csrf', params, { async: false })
.done(data => callback(null, data, page))
.fail((code, data) => callback(code, data, page));
}
function showAlert(message) { alert("Error: " + message); }
function handleDeleteResponse(err, data, page) {
var logList = $('<ul>').appendTo(logContainer);
logList.append(err ? `<li>Failed to delete page <b>${page}</b>: ${err}</li>` : `<li><b>${page}</b> deleted successfully.</li>`);
}
function previewDeleting() {
var mode = deletionModeSelect.findSelectedItem().getData(),
rawInput = pagesTextarea.getValue().trim(),
reason = reasonInputField.getValue().trim(),
deleteTalk = deleteTalkCheckbox.isSelected();
if (!rawInput || !reason) {
showAlert("Please fill in all fields.");
return;
}
logContainer.empty().append("<h1><span class='mw-headline'>Deletion preview</span></h1>").show();
var logList = $('<ul>').appendTo(logContainer);
if (mode === 'list') {
rawInput.split("\n").map(p => p.trim()).filter(Boolean).forEach(page => {
logList.append(`<li><b>${page}</b> will be deleted for reason: <b>${reason}</b></li>`);
});
if (deleteTalk) logList.append("<li>Talk pages will also be deleted if they exist.</li>");
startButton.setDisabled(false);
} else {
var categories = rawInput.split("\n").map(c => c.trim()).filter(Boolean);
Promise.all(categories.map(getPagesFromCategory)).then(results => {
var pages = [...new Set(results.flat())];
if (!pages.length) {
showAlert("No pages found in the provided category/categories.");
return;
}
pages.forEach(page => logList.append(`<li><b>${page}</b> will be deleted for reason: <b>${reason}</b></li>`));
if (deleteTalk) logList.append("<li>Talk pages will also be deleted if they exist.</li>");
startButton.setDisabled(false);
}).catch(() => showAlert("Failed to retrieve pages from category."));
}
}
function startDeleting() {
if (!confirm("Are you sure you want to delete the listed pages? This action cannot be undone.")) return;
var pages = logContainer.find('li b').map((_, el) => $(el).text()).get();
var reason = reasonInputField.getValue().trim();
var deleteTalk = deleteTalkCheckbox.isSelected();
function processNextPage(index = 0) {
if (index >= pages.length) return;
deletePage(pages[index], reason, deleteTalk, function(err, data) {
handleDeleteResponse(err, data, pages[index]);
setTimeout(() => processNextPage(index + 1), 2000);
});
}
processNextPage();
}
previewButton.on('click', previewDeleting);
startButton.on('click', startDeleting);
}
$.when(mw.loader.using('mediawiki.util'), $.ready).then(() => {
mw.util.addPortletLink('p-tb', mw.util.getUrl('Special:BlankPage/MassDelete'), 'MassDelete');
});
if (mw.config.get('wgCanonicalSpecialPageName') === 'Blankpage' && mw.config.get('wgTitle').split('/', 2)[1] === 'MassDelete') {
$.when(mw.loader.using('oojs-ui-core'), $.ready).then(initializeMassDelete);
}
});
//</nowiki>