User:MolecularPilot/massRollback.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
![]() | Documentation for this user script can be added at User:MolecularPilot/massRollback. |
/// Mass rollback function with user-specified rate limit and bot tagging (if flagged)
/// Re-written by MolecularPilot, based on original by Mr.Z-man, John254, Writ Keeper and TheDJ
if (typeof wkContribsCheckboxInit === "undefined") {
wkContribsCheckboxInit = false;
}
if (typeof wkRollbackPortlet === "undefined") {
wkRollbackPortlet = "p-cactions";
}
function rollbackEverythingWKMR(editSummary) {
if (editSummary === null) {
return false;
}
if (mw.config.get("wgRelevantUserName") === mw.config.get("wgUserName")) {
if (!(confirm("You are about to roll back *all* of *your own* edits. Please note that this will be very difficult to undo. Are you *ABSOLUTELY SURE* you want to do this?"))) {
return false;
}
}
// Prompt user for the max rollbacks per minute
var maxRollbacksPerMinute = parseInt(prompt("Enter the maximum number of rollbacks you want to perform in one minute:", "10"));
if (isNaN(maxRollbacksPerMinute) || maxRollbacksPerMinute <= 0) {
mw.notify("Invalid input! Please enter a positive integer.");
return false;
}
mw.loader.using('mediawiki.api').done(function () {
var rbMetadata = {};
rbMetadata.api = new mw.Api();
rbMetadata.userName = mw.config.get("wgRelevantUserName");
rbMetadata.ipRange = (rbMetadata.userName === null);
rbMetadata.titleRegex = /title=([^&]+)/;
rbMetadata.editSummary = editSummary;
var rollbackLinks = $("a[href*='action=rollback']");
// Calculate delay per rollback based on user-specified limit
var delayBetweenRollbacks = 60000 / maxRollbacksPerMinute; // Delay in ms for each rollback to stay within the limit (60,000ms = 1 minute)
var rollbacksMade = 0;
var startTime = Date.now(); // Time tracking for 1-minute window
// Start the rollbacks with a delay
rollbackLinks.each(function (ind, el) {
// Ensure we don't exceed the max rollbacks in 1 minute
var timeElapsed = Date.now() - startTime;
var timeLeft = 60000 - timeElapsed; // Time remaining in the current minute
if (rollbacksMade >= maxRollbacksPerMinute) {
// If we've hit the limit, wait until the next minute
var waitForNextMinute = 60000 - timeElapsed;
setTimeout(function () {
startTime = Date.now(); // Reset start time for the new minute
rollbacksMade = 0; // Reset the rollback counter
rollbackOneThingWKMR(el, rbMetadata);
}, waitForNextMinute);
} else {
// If we can proceed with a rollback
setTimeout(function () {
rollbackOneThingWKMR(el, rbMetadata);
rollbacksMade++; // Increment the rollback counter
}, ind * delayBetweenRollbacks); // Apply delay based on user input
}
});
});
return false;
}
function rollbackSomeThingsWKMR(editSummary) {
if (editSummary === null) {
return false;
}
// Prompt user for the max rollbacks per minute
var maxRollbacksPerMinute = parseInt(prompt("Enter the maximum number of rollbacks you want to perform in one minute:", "10"));
if (isNaN(maxRollbacksPerMinute) || maxRollbacksPerMinute <= 0) {
mw.notify("Invalid input! Please enter a positive integer.");
return false;
}
mw.loader.using('mediawiki.api').done(function () {
var rbMetadata = {};
rbMetadata.api = new mw.Api();
rbMetadata.userName = mw.config.get("wgRelevantUserName");
rbMetadata.titleRegex = /title=([^&]+)/;
rbMetadata.editSummary = editSummary;
var rollbackList = $("input.revdelIds:checked").parents("li.mw-contributions-current").find("a[href*='action=rollback']");
if (rollbackList.length <= 0) {
mw.notify("You didn't select any edits that could be rolled back!");
return;
}
// Calculate delay per rollback based on user-specified limit
var delayBetweenRollbacks = 60000 / maxRollbacksPerMinute; // Delay in ms for each rollback to stay within the limit (60,000ms = 1 minute)
var rollbacksMade = 0;
var startTime = Date.now(); // Time tracking for 1-minute window
// Start the rollbacks with a delay
rollbackList.each(function (ind, el) {
// Ensure we don't exceed the max rollbacks in 1 minute
var timeElapsed = Date.now() - startTime;
var timeLeft = 60000 - timeElapsed; // Time remaining in the current minute
if (rollbacksMade >= maxRollbacksPerMinute) {
// If we've hit the limit, wait until the next minute
var waitForNextMinute = 60000 - timeElapsed;
setTimeout(function () {
startTime = Date.now(); // Reset start time for the new minute
rollbacksMade = 0; // Reset the rollback counter
rollbackOneThingWKMR(el, rbMetadata);
}, waitForNextMinute);
} else {
// If we can proceed with a rollback
setTimeout(function () {
rollbackOneThingWKMR(el, rbMetadata);
rollbacksMade++; // Increment the rollback counter
}, ind * delayBetweenRollbacks); // Apply delay based on user input
}
});
});
}
function rollbackOneThingWKMR(edit, rbMetadata) {
var userName;
// If in an anonymous IP range, determine the username for each edit individually.
if (rbMetadata.userName === null) {
userName = $(edit).parents("li:first").children("a.mw-anonuserlink").not(".mw-contributions-title").text();
} else {
userName = rbMetadata.userName;
}
var params = {
bot: true // Mark rollback as a bot edit
};
if (rbMetadata.editSummary !== '') {
params.summary = rbMetadata.editSummary;
}
rbMetadata.api.rollback(decodeURIComponent(rbMetadata.titleRegex.exec(edit.href)[1]), userName, params).done(function () {
$(edit).after("reverted");
$(edit).remove();
});
}
$(document).ready(function () {
if (mw.config.get("wgCanonicalSpecialPageName") == "Contributions" && $("span.mw-rollback-link").length > 0) {
mw.loader.using("mediawiki.util").done(function () {
mw.util.addPortletLink(wkRollbackPortlet, '#', "Rollback all", "ca-rollbackeverything", "rollback all edits displayed here");
if (!wkContribsCheckboxInit) {
if ($("ul.mw-contributions-list .mw-revdelundel-link").length > 0) {
$("ul.mw-contributions-list .mw-revdelundel-link").each(function (ind, el) {
if ($(this).children("a").length > 0) {
var revId = /ids=(\d+)/.exec($(this).children("a").attr("href"))[1];
var pageTitle = /target=([^&]+)/.exec($(this).children("a").attr("href"))[1];
$(el).prepend("<input type='checkbox' name='" + decodeURIComponent(pageTitle) + "' class='revdelIds' value='" + revId + "'> ");
$(el).children(".revdelIds").data("index", ind);
}
});
} else {
$("ul.mw-contributions-list a.mw-changeslist-date").each(function (ind, el) {
$(el).before("<input type='checkbox' class='revdelIds'> ");
});
}
wkContribsCheckboxInit = true;
}
mw.util.addPortletLink(wkRollbackPortlet, '#', "Rollback selected", "ca-rollbacksome", "rollback selected edits");
$("#ca-rollbackeverything").click(function (event) {
event.preventDefault();
mw.loader.load('mediawiki.api'); //start loading, while the user is in the prompt
return rollbackEverythingWKMR(prompt("Rollback all edits: Enter an edit summary, or leave blank to use the default (or hit Cancel to cancel the rollback entirely)"));
});
$("#ca-rollbacksome").click(function (event) {
event.preventDefault();
mw.loader.load('mediawiki.api'); //start loading, while the user is in the prompt
return rollbackSomeThingsWKMR(prompt("Rollback selected edits: Enter an edit summary, or leave blank to use the default (or hit Cancel to cancel the rollback entirely)"));
});
$("#ca-rollbacksome").data("lastSelectedIndex", -1);
$("input.revdelIds").off("click").click(function (ev) {
var lastSelectedRevdel = $("#ca-rollbacksome").data("lastSelectedIndex");
var newIndex = $(this).data("index");
if (ev.shiftKey && lastSelectedRevdel >= 0) {
var checkboxArray = $("input.revdelIds");
var start = lastSelectedRevdel;
var stop = newIndex;
if (start < stop) {
for (var i = start; i < stop; i++) {
if (i != lastSelectedRevdel) {
$(checkboxArray[i]).prop("checked", !($(checkboxArray[i]).prop("checked")));
}
}
} else {
for (var i = start; i > stop; i--) {
if (i != lastSelectedRevdel) {
$(checkboxArray[i]).prop("checked", !($(checkboxArray[i]).prop("checked")));
}
}
}
}
$("#ca-rollbacksome").data("lastSelectedIndex", newIndex);
});
});
}
});