Jump to content

User:MolecularPilot/massRollback.js

From Wikipedia, the free encyclopedia
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/// 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 + "'>&nbsp;");
                            $(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'>&nbsp;");
                    });
                }
                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);
            });

        });
    }
});