User:DR/test.js: Difference between revisions
< User:DR
Content deleted Content added
No edit summary |
No edit summary |
||
Line 4: | Line 4: | ||
$('#mw-content-text > p').remove(); |
$('#mw-content-text > p').remove(); |
||
$('#firstHeading').text('MassDelete'); |
$('#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({ |
var pagesTextarea = new OO.ui.MultilineTextInputWidget({ |
||
Line 10: | Line 19: | ||
rows: 10 |
rows: 10 |
||
}), |
}), |
||
reasonInputField = new OO.ui.TextInputWidget({ |
reasonInputField = new OO.ui.TextInputWidget({ placeholder: 'Reason for deletion' }), |
||
deleteTalkCheckbox = new OO.ui.CheckboxInputWidget({ selected: true }), |
|||
placeholder: 'Reason for deletion' |
|||
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 }), |
|||
deleteTalkCheckbox = new OO.ui.CheckboxInputWidget({ |
|||
cancelButton = new OO.ui.ButtonWidget({ label: 'Cancel', flags: ['primary', 'destructive'], href: 'https:' + mw.config.get('wgServer') }), |
|||
selected: true |
|||
logContainer = $('<div>').hide(); |
|||
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 = { |
var labels = { |
||
deletionModeLabel: deletionModeLabel, |
|||
pagesLabel: $('<p>').text('Pages to Delete:').css('font-weight', 'bold'), |
|||
pagesLabel: $('<p>').text('Pages / Categories:').css('font-weight', 'bold'), |
|||
reasonLabel: $('<p>').text('Reason:').css('font-weight', 'bold'), |
reasonLabel: $('<p>').text('Reason:').css('font-weight', 'bold'), |
||
deleteTalkLabel: $('<label>') |
deleteTalkLabel: $('<label>') |
||
.append(deleteTalkCheckbox.$element, $('<span>').text(' Also delete talk pages').css('padding-left', '5px')) |
|||
.append( |
|||
.css({ 'margin-top': '5px', 'margin-bottom': '5px' }) |
|||
$('<span>').text(' Also delete talk pages').css('padding-left', '5px') |
|||
) |
|||
.css({ |
|||
'margin-top': '5px', |
|||
'margin-bottom': '5px' |
|||
}) |
|||
}; |
}; |
||
Line 50: | Line 38: | ||
$('#mw-content-text').append( |
$('#mw-content-text').append( |
||
labels.deletionModeLabel, |
|||
deletionModeSelect.$element, |
|||
labels.pagesLabel, pagesTextarea.$element, |
labels.pagesLabel, pagesTextarea.$element, |
||
labels.reasonLabel, reasonInputField.$element, |
labels.reasonLabel, reasonInputField.$element, |
||
Line 61: | Line 51: | ||
); |
); |
||
deletionModeSelect.on('choose', function(item) { |
|||
function deletePage(page, reason, deleteTalk, callback) { |
|||
if (item.getData() === 'category') { |
|||
pagesTextarea.setPlaceholder('Enter category names (one per line)'); |
|||
} else { |
|||
pagesTextarea.setPlaceholder('Enter list of pages (one per line)'); |
|||
}; |
|||
if (deleteTalk) { |
|||
params.deletetalk = true; |
|||
} |
} |
||
( |
logContainer.empty().hide(); |
||
startButton.setDisabled(true); |
|||
}); |
|||
'Api-User-Agent': 'en:User:DreamRimmer/MassDelete.js' |
|||
function getPagesFromCategory(category) { |
|||
} |
|||
return $.ajax({ |
|||
url: mw.util.wikiScript('api'), |
|||
data: { action: 'query', list: 'categorymembers', cmtitle: 'Category:' + category, cmlimit: 'max', format: 'json' }, |
|||
async: false |
|||
dataType: 'json' |
|||
}).then(function(data) { |
|||
return data.query?.categorymembers?.map(item => item.title) || []; |
|||
}).fail(function(code, data) { |
|||
callback(code, data, page); |
|||
}); |
}); |
||
} |
} |
||
function |
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) { |
function handleDeleteResponse(err, data, page) { |
||
var logList = $( |
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>`); |
|||
if (err) { |
|||
logList.append("<li>Failed to delete page <b>" + page + "</b>: " + err + "</li>"); |
|||
} else { |
|||
logList.append("<li><b>" + page + "</b> deleted successfully.</li>"); |
|||
} |
|||
} |
} |
||
function previewDeleting() { |
function previewDeleting() { |
||
var |
var mode = deletionModeSelect.findSelectedItem().getData(), |
||
rawInput = pagesTextarea.getValue().trim(), |
|||
reason = reasonInputField.getValue().trim(), |
reason = reasonInputField.getValue().trim(), |
||
deleteTalk = deleteTalkCheckbox.isSelected(); |
deleteTalk = deleteTalkCheckbox.isSelected(); |
||
if (pages[0].trim() === "" || reason === "") { |
|||
if (!rawInput || !reason) { |
|||
showAlert("Please fill in all fields."); |
showAlert("Please fill in all fields."); |
||
return; |
return; |
||
} |
} |
||
logContainer.empty(); |
logContainer.empty().append("<h1><span class='mw-headline'>Deletion preview</span></h1>").show(); |
||
$( |
var logList = $('<ul>').appendTo(logContainer); |
||
logContainer.show(); |
|||
if (mode === 'list') { |
|||
rawInput.split("\n").map(p => p.trim()).filter(Boolean).forEach(page => { |
|||
pages.forEach(function(page) { |
|||
logList.append(`<li><b>${page}</b> will be deleted for reason: <b>${reason}</b></li>`); |
|||
page = page.trim(); |
|||
}); |
|||
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 { |
|||
logList.append("<li>Talk pages will also be deleted if they exist.</li>"); |
|||
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.")); |
|||
} |
} |
||
startButton.setDisabled(false); |
|||
} |
} |
||
function startDeleting() { |
function startDeleting() { |
||
if (!confirm("Are you sure you want to delete the listed pages? This action cannot be undone.")) |
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(); |
|||
return; |
|||
var reason = reasonInputField.getValue().trim(); |
|||
} |
|||
var |
var deleteTalk = deleteTalkCheckbox.isSelected(); |
||
reason = reasonInputField.getValue().trim(), |
|||
function processNextPage(index = 0) { |
|||
if (index >= pages.length) return; |
|||
deletePage(pages[index], reason, deleteTalk, function(err, data) { |
|||
if (mw.config.get("wgUserGroups").indexOf("sysop") >= 0) { |
|||
handleDeleteResponse(err, data, pages[index]); |
|||
setTimeout(() => processNextPage(index + 1), 2000); |
|||
} else if (mw.config.get("wgGlobalGroups").indexOf("steward") >= 0) { |
|||
suffix = " ([[m:stewards|steward]] action)"; |
|||
} else if (mw.config.get("wgGlobalGroups").indexOf("global-sysop") >= 0) { |
|||
suffix = " ([[m:GS|global sysop]] action)"; |
|||
} |
|||
reason += suffix + " (using [[:meta:User:DreamRimmer/MassDelete|MassDelete.js]])"; |
|||
if (pages[0].trim() === "" || reason === "") { |
|||
showAlert("Please fill in all fields."); |
|||
return; |
|||
} |
|||
logContainer.empty(); |
|||
$("<h1>").wrapInner("<span class='mw-headline'>Deletion log</span>").appendTo(logContainer); |
|||
logContainer.show(); |
|||
var currentIndex = 0; |
|||
function processNextPage() { |
|||
if (currentIndex >= pages.length) { |
|||
return; |
|||
} |
|||
var page = pages[currentIndex].trim(); |
|||
deletePage(page, reason, deleteTalk, function(err, data) { |
|||
handleDeleteResponse(err, data, page); |
|||
currentIndex++; |
|||
setTimeout(processNextPage, 2000); |
|||
}); |
}); |
||
} |
} |
||
processNextPage(); |
processNextPage(); |
||
} |
} |
||
pagesTextarea.on('change', function() { |
|||
previewButton.setDisabled(pagesTextarea.getValue().trim() === '' || reasonInputField.getValue().trim() === ''); |
|||
startButton.setDisabled(true); |
|||
}); |
|||
reasonInputField.on('change', function() { |
|||
previewButton.setDisabled(pagesTextarea.getValue().trim() === '' || reasonInputField.getValue().trim() === ''); |
|||
startButton.setDisabled(true); |
|||
}); |
|||
previewButton.on('click', previewDeleting); |
previewButton.on('click', previewDeleting); |
||
Line 172: | Line 141: | ||
} |
} |
||
$.when(mw.loader.using('mediawiki.util'), $.ready).then( |
$.when(mw.loader.using('mediawiki.util'), $.ready).then(() => { |
||
mw.util.addPortletLink( |
mw.util.addPortletLink('p-tb', mw.util.getUrl('Special:BlankPage/MassDelete'), 'MassDelete'); |
||
'p-tb', |
|||
mw.util.getUrl('Special:BlankPage/MassDelete'), |
|||
'MassDelete' |
|||
); |
|||
}); |
}); |
||
if (mw.config.get('wgCanonicalSpecialPageName') === 'Blankpage' && mw.config.get('wgTitle').split('/', 2)[1] === 'MassDelete') { |
if (mw.config.get('wgCanonicalSpecialPageName') === 'Blankpage' && mw.config.get('wgTitle').split('/', 2)[1] === 'MassDelete') { |
||
$.when(mw.loader.using('oojs-ui-core'), $.ready).then( |
$.when(mw.loader.using('oojs-ui-core'), $.ready).then(initializeMassDelete); |
||
initializeMassDelete(); |
|||
}); |
|||
} |
} |
||
}); |
}); |
||
//</nowiki> |
//</nowiki> |
Latest revision as of 15:13, 3 April 2025
//<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>