No edit summary Tag: Reverted |
No edit summary |
||
(72 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
/ | // ==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', 'jquery'], function () { | |||
if ( | 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 = {}; | |||
showModal('Handle Links and Redirects', '<div class="form-group">' + | |||
'<label>Specify how you would like to handle all incoming links and redirects:</label>' + | |||
'<select id="link-handling-select" class="form-control">' + | |||
'<option value="delete">Delete Links and Redirects</option>' + | |||
'<option value="change">Change Target of Links and Redirects</option>' + | |||
'</select>' + | |||
'</div>', function () { | |||
var choice = $('#link-handling-select').val(); | |||
if (choice === 'change') { | |||
showModal('Specify New Target', '<div class="form-group">' + | |||
'<label>Enter the new target page name to update all links and redirects:</label>' + | |||
'<input type="text" id="new-target-input" class="form-control" placeholder="Enter new target">' + | |||
'</div>', function () { | |||
decisions.links = $('#new-target-input').val(); | |||
confirmDeletion(pageTitle, decisions); | |||
}); | |||
} else { | |||
decisions.links = ''; | |||
confirmDeletion(pageTitle, decisions); | |||
} | |||
}); | |||
} | |||
function confirmDeletion(pageTitle, decisions) { | |||
showModal('Confirm Page Deletion', '<p>Are you sure you want to delete "' + pageTitle + '" after handling all links and redirects?</p>', function () { | |||
decisions.deletion = true; | |||
showLoadingDialog('Performing Cleanup', function (loadingDialog, updateLoadingText, logDetail) { | |||
executeAllActions(pageTitle, decisions, function () { | |||
loadingDialog.close().closed.then(function() { | |||
location.reload(); | |||
}); | |||
}, updateLoadingText, logDetail); | |||
}); | |||
}); | |||
} | } | ||
function showModal(title, body, onConfirm) { | |||
var modal = $( | |||
'<div class="modal fade" tabindex="-1" role="dialog">' + | |||
'<div class="modal-dialog" role="document">' + | |||
'<div class="modal-content">' + | |||
'<div class="modal-header">' + | |||
'<h5 class="modal-title">' + title + '</h5>' + | |||
'<button type="button" class="close" data-dismiss="modal" aria-label="Close">' + | |||
'<span aria-hidden="true">×</span>' + | |||
'</button>' + | |||
'</div>' + | |||
'<div class="modal-body">' + body + '</div>' + | |||
'<div class="modal-footer">' + | |||
'<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>' + | |||
'<button type="button" class="btn btn-primary">Confirm</button>' + | |||
'</div>' + | |||
'</div>' + | |||
'</div>' + | |||
'</div>' | |||
); | |||
modal.find('.btn-primary').click(function () { | |||
onConfirm(); | |||
modal.modal('hide'); | |||
}); | |||
modal.on('hidden.bs.modal', function () { | |||
modal.remove(); | |||
}); | |||
$('body').append(modal); | |||
modal.modal('show'); | |||
} | |||
function showLoadingDialog(message, callback) { | |||
var modal = $( | |||
'<div class="modal fade" tabindex="-1" role="dialog">' + | |||
'<div class="modal-dialog" role="document">' + | |||
'<div class="modal-content">' + | |||
'<div class="modal-header">' + | |||
'<h5 class="modal-title">Performing Cleanup</h5>' + | |||
'</div>' + | |||
'<div class="modal-body">' + | |||
'<p id="loading-text">' + message + '</p>' + | |||
'<ul id="loading-log"></ul>' + | |||
'</div>' + | |||
'</div>' + | |||
'</div>' + | |||
'</div>' | |||
); | |||
$('body').append(modal); | |||
modal.modal('show'); | |||
callback(modal, function (text) { | |||
$('#loading-text').text(text); | |||
$('#loading-log').append('<li>' + text + '</li>'); | |||
}, function (detail) { | |||
$('#loading-log').append('<li>' + detail + '</li>'); | |||
}); | }); | ||
} | } | ||
function executeAllActions(pageTitle, decisions, callback, updateLoadingText, logDetail) { | |||
var api = new mw.Api(); | |||
function handleLinksAndRedirects(action, newTarget, next) { | |||
updateLoadingText('Fetching backlinks...'); | |||
api.get({ | |||
action: 'query', | |||
list: 'backlinks', | |||
bltitle: pageTitle, | |||
bllimit: 'max', | |||
blfilterredir: 'all' // Include both redirects and non-redirects | |||
}).done(function (data) { | |||
logDetail('Backlinks fetched.'); | |||
if (data.query.backlinks) { | |||
var promises = $.map(data.query.backlinks, function (link) { | |||
return new $.Deferred(function (defer) { | |||
api.get({ | |||
action: 'parse', | |||
page: link.title, | |||
prop: 'wikitext' | |||
}).done(function (linkData) { | |||
var isRedirect = linkData.parse.wikitext['*'].trim().startsWith('#REDIRECT'); | |||
if (isRedirect) { | |||
if (action === 'update') { | |||
updateRedirectTarget(link.title, newTarget, api, defer.resolve, logDetail); | |||
} else { | |||
logDetail('Backlink ' + link.title + ' is a redirect. Deleting...'); | |||
performDeletion(link.title, defer.resolve, logDetail); | |||
} | |||
} else { | |||
if (action === 'update') { | |||
updateLinkInPage(link.title, pageTitle, newTarget, api, defer.resolve, logDetail); | |||
} else { | |||
removeLinkFromPage(link.title, pageTitle, api, defer.resolve, logDetail); | |||
} | } | ||
} | } | ||
}).fail(function (error) { | |||
logDetail('Error checking if backlink ' + link.title + ' is a redirect: ' + error); | |||
defer.resolve(); | |||
}); | |||
}).promise(); | |||
}); | |||
$.when.apply($, promises).then(function () { | |||
updateLoadingText(action === 'update' ? 'All links updated.' : 'All links removed.'); | |||
next(); | |||
$ | |||
}); | }); | ||
} | } else { | ||
next(); | |||
} | } | ||
}).fail(function (error) { | |||
updateLoadingText('Error fetching backlinks: ' + error); | |||
next(); | |||
}); | }); | ||
} | } | ||
function updateLinkInPage(linkedPageTitle, originalPageTitle, newTarget, api, resolve, logDetail) { | |||
api.get({ | |||
action: 'parse', | |||
page: linkedPageTitle, | |||
} | prop: 'wikitext' | ||
}).then(function (data) { | |||
var wikitext = data.parse.wikitext['*']; | |||
var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g'); | |||
var newWikitext = wikitext.replace(regex, '[[' + newTarget + '$1]]'); | |||
if (wikitext !== newWikitext) { | |||
logDetail('Updating link in ' + linkedPageTitle); | |||
} else { | |||
logDetail('No link found in ' + linkedPageTitle); | |||
} | |||
return api.postWithToken('csrf', { | |||
action: 'edit', | |||
title: linkedPageTitle, | |||
text: newWikitext, | |||
summary: 'Updated link to [[' + newTarget + ']]' | |||
}).then(function (response) { | |||
console.log('API response from updating link: ', response); | |||
if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) { | |||
logDetail('Successfully updated link in ' + linkedPageTitle); | |||
} else { | |||
logDetail('No changes made to link in ' + linkedPageTitle); | |||
} | |||
resolve(); | |||
}).fail(function (error) { | |||
logDetail('Error updating link in ' + linkedPageTitle + ': ' + error); | |||
resolve(); | |||
}); | |||
}).fail(function (error) { | |||
logDetail('Error fetching page content for ' + linkedPageTitle + ': ' + error); | |||
resolve(); | |||
}); | |||
} | |||
function | function updateRedirectTarget(redirectPageTitle, newTarget, api, resolve, logDetail) { | ||
logDetail('Updating redirect target in ' + redirectPageTitle); | |||
return api.postWithToken('csrf', { | |||
action: 'edit', | |||
} | title: redirectPageTitle, | ||
text: '#REDIRECT [[' + newTarget + ']]', | |||
summary: 'Updated redirect to [[' + newTarget + ']]' | |||
}).then(function (response) { | |||
console.log('API response from updating redirect: ', response); | |||
if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) { | |||
logDetail('Successfully updated redirect in ' + redirectPageTitle); | |||
} else { | |||
logDetail('No changes made to redirect in ' + redirectPageTitle); | |||
} | |||
resolve(); | |||
}).fail(function (error) { | |||
logDetail('Error updating redirect in ' + redirectPageTitle + ': ' + error); | |||
resolve(); | |||
}); | |||
} | |||
function removeLinkFromPage(linkedPageTitle, originalPageTitle, api, resolve, logDetail) { | |||
api.get({ | |||
action: 'parse', | |||
page: linkedPageTitle, | |||
prop: 'wikitext' | |||
}).then(function (data) { | |||
var wikitext = data.parse.wikitext['*']; | |||
var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g'); | |||
var newWikitext = wikitext.replace(regex, function(match, p1) { | |||
return p1 ? p1.substring(1) : originalPageTitle; | |||
}); | |||
if (wikitext !== newWikitext) { | |||
logDetail('Removing link from ' + linkedPageTitle); | |||
} else { | |||
logDetail('No link found in ' + linkedPageTitle); | |||
} | |||
return api.postWithToken('csrf', { | |||
action: 'edit', | |||
title: linkedPageTitle, | |||
text: newWikitext, | |||
summary: 'Removed link to [[' + originalPageTitle + ']]' | |||
}).then(function (response) { | |||
console.log('API response from removing link: ', response); | |||
if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) { | |||
logDetail('Successfully removed link from ' + linkedPageTitle); | |||
} else { | |||
logDetail('No changes made to link in ' + linkedPageTitle); | |||
} | |||
resolve(); | |||
}).fail(function (error) { | |||
logDetail('Error removing link from ' + linkedPageTitle + ': ' + error); | |||
resolve(); | |||
}); | |||
}).fail(function (error) { | |||
logDetail('Error fetching page content for ' + linkedPageTitle + ': ' + error); | |||
resolve(); | |||
}); | |||
} | |||
function handleRedirects(next) { | |||
$( | updateLoadingText('Fetching redirects...'); | ||
$( | api.get({ | ||
action: 'query', | |||
titles: pageTitle, | |||
redirects: true | |||
}).done(function (data) { | |||
logDetail('Redirects fetched.'); | |||
var redirects = data.query.pages[Object.keys(data.query.pages)[0]].redirects; | |||
if (redirects) { | |||
var promises = $.map(redirects, function (redirect) { | |||
return new $.Deferred(function (defer) { | |||
logDetail('Found redirect: ' + redirect.title); | |||
performDeletion(redirect.title, defer.resolve, logDetail); | |||
}).promise(); | |||
}); | |||
$.when.apply($, promises).then(function () { | |||
next(); | |||
}); | |||
} else { | |||
next(); | |||
} | |||
}).fail(function (error) { | |||
updateLoadingText('Error fetching redirects: ' + error); | |||
next(); | |||
}); | |||
} | |||
function performDeletion(pageTitle, resolve, logDetail) { | |||
updateLoadingText('Deleting the page: ' + pageTitle); | |||
api.postWithToken('csrf', { | |||
action: 'delete', | |||
title: pageTitle, | |||
reason: 'Automated clean delete by admin' | |||
}).done(function (response) { | |||
console.log('API response from deleting page: ', response); | |||
if (response.delete && response.delete.title) { | |||
logDetail('Successfully deleted page: ' + response.delete.title); | |||
} else { | |||
logDetail('No deletion performed for ' + pageTitle); | |||
} | |||
resolve(); | |||
}).fail(function (error) { | |||
logDetail('Error during clean deletion of ' + pageTitle + ': ' + error); | |||
resolve(); | |||
}); | |||
} | |||
})( | var tasks = [ | ||
function (resolve) { | |||
if (decisions.links === '') { | |||
handleLinksAndRedirects('remove', '', resolve); | |||
} else { | |||
handleLinksAndRedirects('update', decisions.links, resolve); | |||
} | |||
}, | |||
function (resolve) { | |||
if (decisions.deletion) { | |||
handleRedirects(resolve); | |||
} else { | |||
resolve(); | |||
} | |||
}, | |||
function (resolve) { | |||
if (decisions.deletion) { | |||
performDeletion(pageTitle, resolve, logDetail); | |||
} else { | |||
resolve(); | |||
} | |||
} | |||
]; | |||
(function executeTasks(i) { | |||
if (i < tasks.length) { | |||
tasks[i](function () { | |||
executeTasks(i + 1); | |||
}); | |||
} else { | |||
callback(); | |||
} | |||
})(0); | |||
} | |||
} | |||
} | } | ||
mw.hook('wikipage.content').add(addCleanDeleteLink); | |||
}); | }); | ||
(function() { | |||
// Function to remove special characters from the search term | |||
function sanitizeSearchTerm(term) { | |||
return term.replace(/[^a-zA-Z0-9\s]/g, ''); // Keep only alphanumeric characters and spaces | |||
} | } | ||
// Save the original fetch function | |||
var originalFetch = window.fetch; | |||
var | |||
var | // Override the fetch function | ||
window.fetch = function() { | |||
var url = arguments[0]; | |||
var options = arguments[1] || {}; | |||
// Check if the URL is the target API endpoint | |||
if (typeof url === 'string' && url.indexOf('action=bs-extendedsearch-query') !== -1) { | |||
// Decode the URL to manipulate it | |||
var decodedUrl = decodeURIComponent(url); | |||
// Find the search term in the URL | |||
var searchTermMatch = decodedUrl.match(/searchTerm=([^&]*)/); | |||
if (searchTermMatch && searchTermMatch[1]) { | |||
var originalSearchTerm = searchTermMatch[1]; | |||
// Sanitize the search term | |||
var sanitizedSearchTerm = sanitizeSearchTerm(originalSearchTerm); | |||
// Replace the original search term with the sanitized one | |||
decodedUrl = decodedUrl.replace(originalSearchTerm, sanitizedSearchTerm); | |||
// Re-encode the URL | |||
url = encodeURI(decodedUrl); | |||
} | |||
} | } | ||
}); | |||
// Call the original fetch function with the modified URL | |||
return originalFetch.apply(this, [url, options]); | |||
}; | |||
})(); |
Latest revision as of 23:50, 25 August 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', 'jquery'], 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 = {};
showModal('Handle Links and Redirects', '<div class="form-group">' +
'<label>Specify how you would like to handle all incoming links and redirects:</label>' +
'<select id="link-handling-select" class="form-control">' +
'<option value="delete">Delete Links and Redirects</option>' +
'<option value="change">Change Target of Links and Redirects</option>' +
'</select>' +
'</div>', function () {
var choice = $('#link-handling-select').val();
if (choice === 'change') {
showModal('Specify New Target', '<div class="form-group">' +
'<label>Enter the new target page name to update all links and redirects:</label>' +
'<input type="text" id="new-target-input" class="form-control" placeholder="Enter new target">' +
'</div>', function () {
decisions.links = $('#new-target-input').val();
confirmDeletion(pageTitle, decisions);
});
} else {
decisions.links = '';
confirmDeletion(pageTitle, decisions);
}
});
}
function confirmDeletion(pageTitle, decisions) {
showModal('Confirm Page Deletion', '<p>Are you sure you want to delete "' + pageTitle + '" after handling all links and redirects?</p>', function () {
decisions.deletion = true;
showLoadingDialog('Performing Cleanup', function (loadingDialog, updateLoadingText, logDetail) {
executeAllActions(pageTitle, decisions, function () {
loadingDialog.close().closed.then(function() {
location.reload();
});
}, updateLoadingText, logDetail);
});
});
}
function showModal(title, body, onConfirm) {
var modal = $(
'<div class="modal fade" tabindex="-1" role="dialog">' +
'<div class="modal-dialog" role="document">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<h5 class="modal-title">' + title + '</h5>' +
'<button type="button" class="close" data-dismiss="modal" aria-label="Close">' +
'<span aria-hidden="true">×</span>' +
'</button>' +
'</div>' +
'<div class="modal-body">' + body + '</div>' +
'<div class="modal-footer">' +
'<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>' +
'<button type="button" class="btn btn-primary">Confirm</button>' +
'</div>' +
'</div>' +
'</div>' +
'</div>'
);
modal.find('.btn-primary').click(function () {
onConfirm();
modal.modal('hide');
});
modal.on('hidden.bs.modal', function () {
modal.remove();
});
$('body').append(modal);
modal.modal('show');
}
function showLoadingDialog(message, callback) {
var modal = $(
'<div class="modal fade" tabindex="-1" role="dialog">' +
'<div class="modal-dialog" role="document">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<h5 class="modal-title">Performing Cleanup</h5>' +
'</div>' +
'<div class="modal-body">' +
'<p id="loading-text">' + message + '</p>' +
'<ul id="loading-log"></ul>' +
'</div>' +
'</div>' +
'</div>' +
'</div>'
);
$('body').append(modal);
modal.modal('show');
callback(modal, function (text) {
$('#loading-text').text(text);
$('#loading-log').append('<li>' + text + '</li>');
}, function (detail) {
$('#loading-log').append('<li>' + detail + '</li>');
});
}
function executeAllActions(pageTitle, decisions, callback, updateLoadingText, logDetail) {
var api = new mw.Api();
function handleLinksAndRedirects(action, newTarget, next) {
updateLoadingText('Fetching backlinks...');
api.get({
action: 'query',
list: 'backlinks',
bltitle: pageTitle,
bllimit: 'max',
blfilterredir: 'all' // Include both redirects and non-redirects
}).done(function (data) {
logDetail('Backlinks fetched.');
if (data.query.backlinks) {
var promises = $.map(data.query.backlinks, function (link) {
return new $.Deferred(function (defer) {
api.get({
action: 'parse',
page: link.title,
prop: 'wikitext'
}).done(function (linkData) {
var isRedirect = linkData.parse.wikitext['*'].trim().startsWith('#REDIRECT');
if (isRedirect) {
if (action === 'update') {
updateRedirectTarget(link.title, newTarget, api, defer.resolve, logDetail);
} else {
logDetail('Backlink ' + link.title + ' is a redirect. Deleting...');
performDeletion(link.title, defer.resolve, logDetail);
}
} else {
if (action === 'update') {
updateLinkInPage(link.title, pageTitle, newTarget, api, defer.resolve, logDetail);
} else {
removeLinkFromPage(link.title, pageTitle, api, defer.resolve, logDetail);
}
}
}).fail(function (error) {
logDetail('Error checking if backlink ' + link.title + ' is a redirect: ' + error);
defer.resolve();
});
}).promise();
});
$.when.apply($, promises).then(function () {
updateLoadingText(action === 'update' ? 'All links updated.' : 'All links removed.');
next();
});
} else {
next();
}
}).fail(function (error) {
updateLoadingText('Error fetching backlinks: ' + error);
next();
});
}
function updateLinkInPage(linkedPageTitle, originalPageTitle, newTarget, api, resolve, logDetail) {
api.get({
action: 'parse',
page: linkedPageTitle,
prop: 'wikitext'
}).then(function (data) {
var wikitext = data.parse.wikitext['*'];
var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g');
var newWikitext = wikitext.replace(regex, '[[' + newTarget + '$1]]');
if (wikitext !== newWikitext) {
logDetail('Updating link in ' + linkedPageTitle);
} else {
logDetail('No link found in ' + linkedPageTitle);
}
return api.postWithToken('csrf', {
action: 'edit',
title: linkedPageTitle,
text: newWikitext,
summary: 'Updated link to [[' + newTarget + ']]'
}).then(function (response) {
console.log('API response from updating link: ', response);
if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) {
logDetail('Successfully updated link in ' + linkedPageTitle);
} else {
logDetail('No changes made to link in ' + linkedPageTitle);
}
resolve();
}).fail(function (error) {
logDetail('Error updating link in ' + linkedPageTitle + ': ' + error);
resolve();
});
}).fail(function (error) {
logDetail('Error fetching page content for ' + linkedPageTitle + ': ' + error);
resolve();
});
}
function updateRedirectTarget(redirectPageTitle, newTarget, api, resolve, logDetail) {
logDetail('Updating redirect target in ' + redirectPageTitle);
return api.postWithToken('csrf', {
action: 'edit',
title: redirectPageTitle,
text: '#REDIRECT [[' + newTarget + ']]',
summary: 'Updated redirect to [[' + newTarget + ']]'
}).then(function (response) {
console.log('API response from updating redirect: ', response);
if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) {
logDetail('Successfully updated redirect in ' + redirectPageTitle);
} else {
logDetail('No changes made to redirect in ' + redirectPageTitle);
}
resolve();
}).fail(function (error) {
logDetail('Error updating redirect in ' + redirectPageTitle + ': ' + error);
resolve();
});
}
function removeLinkFromPage(linkedPageTitle, originalPageTitle, api, resolve, logDetail) {
api.get({
action: 'parse',
page: linkedPageTitle,
prop: 'wikitext'
}).then(function (data) {
var wikitext = data.parse.wikitext['*'];
var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g');
var newWikitext = wikitext.replace(regex, function(match, p1) {
return p1 ? p1.substring(1) : originalPageTitle;
});
if (wikitext !== newWikitext) {
logDetail('Removing link from ' + linkedPageTitle);
} else {
logDetail('No link found in ' + linkedPageTitle);
}
return api.postWithToken('csrf', {
action: 'edit',
title: linkedPageTitle,
text: newWikitext,
summary: 'Removed link to [[' + originalPageTitle + ']]'
}).then(function (response) {
console.log('API response from removing link: ', response);
if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) {
logDetail('Successfully removed link from ' + linkedPageTitle);
} else {
logDetail('No changes made to link in ' + linkedPageTitle);
}
resolve();
}).fail(function (error) {
logDetail('Error removing link from ' + linkedPageTitle + ': ' + error);
resolve();
});
}).fail(function (error) {
logDetail('Error fetching page content for ' + linkedPageTitle + ': ' + error);
resolve();
});
}
function handleRedirects(next) {
updateLoadingText('Fetching redirects...');
api.get({
action: 'query',
titles: pageTitle,
redirects: true
}).done(function (data) {
logDetail('Redirects fetched.');
var redirects = data.query.pages[Object.keys(data.query.pages)[0]].redirects;
if (redirects) {
var promises = $.map(redirects, function (redirect) {
return new $.Deferred(function (defer) {
logDetail('Found redirect: ' + redirect.title);
performDeletion(redirect.title, defer.resolve, logDetail);
}).promise();
});
$.when.apply($, promises).then(function () {
next();
});
} else {
next();
}
}).fail(function (error) {
updateLoadingText('Error fetching redirects: ' + error);
next();
});
}
function performDeletion(pageTitle, resolve, logDetail) {
updateLoadingText('Deleting the page: ' + pageTitle);
api.postWithToken('csrf', {
action: 'delete',
title: pageTitle,
reason: 'Automated clean delete by admin'
}).done(function (response) {
console.log('API response from deleting page: ', response);
if (response.delete && response.delete.title) {
logDetail('Successfully deleted page: ' + response.delete.title);
} else {
logDetail('No deletion performed for ' + pageTitle);
}
resolve();
}).fail(function (error) {
logDetail('Error during clean deletion of ' + pageTitle + ': ' + error);
resolve();
});
}
var tasks = [
function (resolve) {
if (decisions.links === '') {
handleLinksAndRedirects('remove', '', resolve);
} else {
handleLinksAndRedirects('update', decisions.links, resolve);
}
},
function (resolve) {
if (decisions.deletion) {
handleRedirects(resolve);
} else {
resolve();
}
},
function (resolve) {
if (decisions.deletion) {
performDeletion(pageTitle, resolve, logDetail);
} else {
resolve();
}
}
];
(function executeTasks(i) {
if (i < tasks.length) {
tasks[i](function () {
executeTasks(i + 1);
});
} else {
callback();
}
})(0);
}
mw.hook('wikipage.content').add(addCleanDeleteLink);
});
(function() {
// Function to remove special characters from the search term
function sanitizeSearchTerm(term) {
return term.replace(/[^a-zA-Z0-9\s]/g, ''); // Keep only alphanumeric characters and spaces
}
// Save the original fetch function
var originalFetch = window.fetch;
// Override the fetch function
window.fetch = function() {
var url = arguments[0];
var options = arguments[1] || {};
// Check if the URL is the target API endpoint
if (typeof url === 'string' && url.indexOf('action=bs-extendedsearch-query') !== -1) {
// Decode the URL to manipulate it
var decodedUrl = decodeURIComponent(url);
// Find the search term in the URL
var searchTermMatch = decodedUrl.match(/searchTerm=([^&]*)/);
if (searchTermMatch && searchTermMatch[1]) {
var originalSearchTerm = searchTermMatch[1];
// Sanitize the search term
var sanitizedSearchTerm = sanitizeSearchTerm(originalSearchTerm);
// Replace the original search term with the sanitized one
decodedUrl = decodedUrl.replace(originalSearchTerm, sanitizedSearchTerm);
// Re-encode the URL
url = encodeURI(decodedUrl);
}
}
// Call the original fetch function with the modified URL
return originalFetch.apply(this, [url, options]);
};
})();
This page was edited 146 days ago on 08/26/2024. What links here