No edit summary |
No edit summary |
||
Line 194: | Line 194: | ||
LoadingDialog.static.name = 'loadingDialog'; | LoadingDialog.static.name = 'loadingDialog'; | ||
LoadingDialog.static.title = ' | LoadingDialog.static.title = 'Performing Cleanup'; | ||
LoadingDialog.prototype.initialize = function () { | LoadingDialog.prototype.initialize = function () { |
Revision as of 22:44, 7 July 2024
// ==UserScript==
// @name MediaWiki Clean Delete
// @namespace MediaWikiScripts
// @description Adds a 'Clean Delete' action link to pages for admins to delete pages and clean up incoming links and redirects.
// ==/UserScript==
mw.loader.using(['mediawiki.api', 'mediawiki.util', 'oojs-ui'], function () {
function addCleanDeleteLink() {
if (mw.config.get('wgUserGroups').indexOf('sysop') !== -1) {
if ($('#ca-cleandelete').length === 0) {
var $link = $('<div>').attr('id', 'ca-cleandelete').attr('class', 'mw-list-item').append(
$('<a>').attr('href', '#').attr('class', 'ca-cleandelete').text('Clean Delete').click(function (e) {
e.preventDefault();
gatherAllDecisions(mw.config.get('wgPageName'));
})
);
$('#p-actions .tab-group').append($link);
}
}
}
function gatherAllDecisions(pageTitle) {
var decisions = {};
var windowManager = new OO.ui.WindowManager();
$('body').append(windowManager.$element);
askForLinkHandling(pageTitle, decisions, windowManager, function () {
confirmDeletion(pageTitle, decisions, windowManager, function () {
showLoadingDialog(windowManager, function (loadingDialog, updateLoadingText) {
executeAllActions(pageTitle, decisions, function () {
loadingDialog.close();
location.reload();
}, updateLoadingText);
});
});
});
}
function askForLinkHandling(pageTitle, decisions, windowManager, callback) {
function LinkHandlingDialog(config) {
LinkHandlingDialog.super.call(this, config);
}
OO.inheritClass(LinkHandlingDialog, OO.ui.ProcessDialog);
LinkHandlingDialog.static.name = 'linkHandlingDialog';
LinkHandlingDialog.static.title = 'Handle Links and Redirects';
LinkHandlingDialog.static.actions = [
{ action: 'continue', label: 'Continue', flags: ['primary', 'progressive'] },
{ action: 'cancel', label: 'Cancel', flags: ['safe', 'close'] }
];
LinkHandlingDialog.prototype.initialize = function () {
LinkHandlingDialog.super.prototype.initialize.apply(this, arguments);
this.radioSelect = new OO.ui.RadioSelectWidget({
items: [
new OO.ui.RadioOptionWidget({ data: 'delete', label: 'Delete Links and Redirects' }),
new OO.ui.RadioOptionWidget({ data: 'change', label: 'Change Target of Links and Redirects' })
]
});
var fieldset = new OO.ui.FieldsetLayout({
items: [
new OO.ui.FieldLayout(this.radioSelect, {
label: 'Specify how you would like to handle all incoming links and redirects:',
align: 'top'
})
]
});
this.content = new OO.ui.PanelLayout({
padded: true,
expanded: false
});
this.content.$element.append(fieldset.$element);
this.$body.append(this.content.$element);
};
LinkHandlingDialog.prototype.getActionProcess = function (action) {
var dialog = this;
var process = new OO.ui.Process(function () {
if (action === 'continue') {
var choice = dialog.radioSelect.findSelectedItem();
if (choice && choice.data === 'change') {
dialog.close().then(function () {
askForNewTarget(pageTitle, decisions, windowManager, callback);
});
} else {
decisions.links = '';
dialog.close().then(function () {
callback();
});
}
} else if (action === 'cancel') {
dialog.close().then(function () {
windowManager.destroy();
});
}
});
return process;
};
windowManager.addWindows([new LinkHandlingDialog()]);
windowManager.openWindow('linkHandlingDialog');
}
function askForNewTarget(pageTitle, decisions, windowManager, callback) {
function NewTargetDialog(config) {
NewTargetDialog.super.call(this, config);
}
OO.inheritClass(NewTargetDialog, OO.ui.ProcessDialog);
NewTargetDialog.static.name = 'newTargetDialog';
NewTargetDialog.static.title = 'Specify New Target';
NewTargetDialog.static.actions = [
{ action: 'continue', label: 'Continue', flags: ['primary', 'progressive'] },
{ action: 'cancel', label: 'Cancel', flags: ['safe', 'close'] }
];
NewTargetDialog.prototype.initialize = function () {
NewTargetDialog.super.prototype.initialize.apply(this, arguments);
this.input = new OO.ui.TextInputWidget({
value: '',
placeholder: 'Enter new target'
});
var fieldset = new OO.ui.FieldsetLayout({
items: [
new OO.ui.FieldLayout(this.input, {
label: 'Enter the new target page name to update all links and redirects:',
align: 'top'
})
]
});
this.content = new OO.ui.PanelLayout({
padded: true,
expanded: false
});
this.content.$element.append(fieldset.$element);
this.$body.append(this.content.$element);
};
NewTargetDialog.prototype.getActionProcess = function (action) {
var dialog = this;
var process = new OO.ui.Process(function () {
if (action === 'continue') {
decisions.links = dialog.input.getValue();
dialog.close().then(function () {
callback();
});
} else if (action === 'cancel') {
dialog.close().then(function () {
windowManager.destroy();
});
}
});
return process;
};
windowManager.addWindows([new NewTargetDialog()]);
windowManager.openWindow('newTargetDialog');
}
function confirmDeletion(pageTitle, decisions, windowManager, callback) {
var dialog = new OO.ui.MessageDialog();
windowManager.addWindows([dialog]);
windowManager.openWindow(dialog, {
title: 'Confirm Page Deletion',
message: 'Are you sure you want to delete "' + pageTitle + '" after handling all links and redirects?',
actions: [
{ label: 'Confirm Deletion', action: 'confirm', flags: ['primary', 'destructive'] },
{ label: 'Cancel', action: 'cancel' }
]
}).closed.then(function (data) {
if (data.action === 'confirm') {
decisions.deletion = true;
callback();
} else {
windowManager.destroy();
}
});
}
function showLoadingDialog(windowManager, callback) {
function LoadingDialog(config) {
LoadingDialog.super.call(this, config);
}
OO.inheritClass(LoadingDialog, OO.ui.ProcessDialog);
LoadingDialog.static.name = 'loadingDialog';
LoadingDialog.static.title = 'Performing Cleanup';
LoadingDialog.prototype.initialize = function () {
LoadingDialog.super.prototype.initialize.apply(this, arguments);
this.loadingLabel = new OO.ui.LabelWidget({ label: 'Starting...' });
this.content = new OO.ui.PanelLayout({
padded: true,
expanded: false
});
this.content.$element.append(this.loadingLabel.$element);
this.$body.append(this.content.$element);
};
LoadingDialog.prototype.getActionProcess = function (action) {
return new OO.ui.Process();
};
windowManager.addWindows([new LoadingDialog()]);
windowManager.openWindow('loadingDialog').then(function (opened) {
opened.then(function (dialog) {
callback(dialog, function (text) {
dialog.loadingLabel.setLabel(text);
});
});
});
}
function executeAllActions(pageTitle, decisions, callback, updateLoadingText) {
var api = new mw.Api();
var tasks = [
function (resolve) {
if (decisions.links === '') {
updateLoadingText('Removing all links and redirects...');
removeAllLinksAndRedirects(pageTitle, api, function () {
updateLoadingText('All links and redirects removed.');
resolve();
});
} else {
updateLoadingText('Updating all links and redirects...');
updateAllLinksAndRedirects(pageTitle, decisions.links, api, function () {
updateLoadingText('All links and redirects updated.');
resolve();
});
}
},
function (resolve) {
updateLoadingText('Deleting the page...');
performDeletion(pageTitle, api, function () {
updateLoadingText('Page deleted.');
resolve();
});
}
];
(function executeTasks(i) {
if (i < tasks.length) {
tasks[i](function () {
executeTasks(i + 1);
});
} else {
callback();
}
})(0);
}
function updateAllLinksAndRedirects(pageTitle, newTarget, api, callback) {
handleLinks(pageTitle, newTarget, 'update', api, function () {
handleRedirects(pageTitle, newTarget, 'update', api, callback);
});
}
function removeAllLinksAndRedirects(pageTitle, api, callback) {
handleLinks(pageTitle, '', 'remove', api, function () {
handleRedirects(pageTitle, '', 'remove', api, callback);
});
}
function handleLinks(pageTitle, newTarget, action, api, callback) {
api.get({
action: 'query',
list: 'backlinks',
bltitle: pageTitle,
blfilterredir: 'nonredirects',
bllimit: 'max'
}).done(function (data) {
if (data.query.backlinks) {
var promises = data.query.backlinks.map(function (link) {
return new Promise(function (resolve) {
if (action === 'update') {
updateLink(link.title, newTarget, api).then(resolve);
} else {
removeLink(link.title, api).then(resolve);
}
});
});
Promise.all(promises).then(callback);
} else {
callback();
}
}).fail(function (error) {
console.error('Error fetching backlinks:', error);
updateLoadingText('Error fetching backlinks: ' + error);
callback();
});
}
function handleRedirects(pageTitle, newTarget, action, api, callback) {
api.get({
action: 'query',
list: 'backlinks',
bltitle: pageTitle,
blfilterredir: 'redirects',
bllimit: 'max'
}).done(function (data) {
if (data.query.backlinks) {
var promises = data.query.backlinks.map(function (redirect) {
return new Promise(function (resolve) {
if (action === 'update') {
updateLink(redirect.title, newTarget, api).then(resolve);
} else {
removeLink(redirect.title, api).then(resolve);
}
});
});
Promise.all(promises).then(callback);
} else {
callback();
}
}).fail(function (error) {
console.error('Error fetching redirects:', error);
updateLoadingText('Error fetching redirects: ' + error);
callback();
});
}
function updateLink(pageTitle, newTarget, api) {
return api.postWithToken('csrf', {
action: 'edit',
title: pageTitle,
text: function (text) {
return text.replace(new RegExp('\\[\\[' + mw.util.escapeRegExp(pageTitle) + '(\\|[^\\]]+)?\\]\\]', 'g'), '[[' + newTarget + '$1]]');
},
summary: 'Updated redirect to new target [[' + newTarget + ']]'
}).fail(function (error) {
console.error('Error updating link:', error);
});
}
function removeLink(pageTitle, api) {
return api.postWithToken('csrf', {
action: 'edit',
title: pageTitle,
text: function (text) {
return text.replace(new RegExp('\\[\\[' + mw.util.escapeRegExp(pageTitle) + '(\\|[^\\]]+)?\\]\\]', 'g'), '');
},
summary: 'Removed link to [[' + pageTitle + ']]'
}).fail(function (error) {
console.error('Error removing link:', error);
});
}
function performDeletion(pageTitle, api, callback) {
api.postWithToken('csrf', {
action: 'delete',
title: pageTitle,
reason: 'Automated clean delete by admin'
}).done(function () {
console.log('Page deleted:', pageTitle);
callback();
}).fail(function (error) {
console.error('Error during clean deletion:', error);
callback();
});
}
mw.hook('wikipage.content').add(addCleanDeleteLink);
});
This page was edited 146 days ago on 08/26/2024. What links here