Jump to content

User:Awesome Aasim/rcpatrol.js

From Wikipedia, the free encyclopedia
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.
/** MIT Licensed - see https://github.com/Awesome-Aasim/WikiRCPatrol/blob/master/LICENSE
* 
* Copyright (c) 2020-23 Awesome Aasim and contributors
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* This script is a work in progress.  Your help in developing this tool is welcomed at https://github.com/Awesome-Aasim/WikiRCPatrol.
* Contributions and changes to this script should be made at the GitHub repository above.
* All other changes will be lost if this file is rebuilt and saved.
* By contributing to this project, you agree to release your work under the MIT license.
*/
mw.loader.using(['oojs-ui-core', 'oojs-ui.styles.icons-editing-core', 'oojs-ui.styles.icons-movement', 'oojs-ui.styles.icons-interactions', 'oojs-ui.styles.icons-layout', 'oojs-ui.styles.icons-alerts'], function () {
    if (!window.rcpatrol) { // stops multiple instances of RC patrol from running
        //necessary resources
        var rcpatrol = {};
        window.rcpatrol = rcpatrol;
        if (mw.config.get("wgPageName").toLowerCase() == "Special:RecentChanges".toLowerCase()) {
            rcpatrol = true;
            $(document).ready(function () {
                var rcpatrollocation = mw.config.get("wgArticlePath").replace("$1", "Special:BlankPage/RCPatrol")
                $("#mw-content-text").prepend('<a href="' + rcpatrollocation + '">RC patrol</a> (<a href="' + rcpatrollocation + '?oresreview=1">ORES</a>)');
            });
        }
        if ((mw.config.get("wgPageName").toLowerCase() == "Special:BlankPage/RCPatrol".toLowerCase())) {
            /**
             * Initialize variables related to RC patrol
             */
            rcpatrol.changes = [];
            rcpatrol.currentChange = 0;
            window.setInterval(() => {
                $("#rcpatroldiff").find("a").attr("target", "_blank");
                $(".mw-rollback-link").hide();
                $(".ve-init-mw-diffPage-diffMode").hide();
                $(".mw-revslider-container").hide();
                if (rcpatrol.currentChange == 0) {
                    rcpatrol.previouseditbutton.setDisabled(true);
                } else if (!rcpatrol.isDisabled) {
                    rcpatrol.previouseditbutton.setDisabled(false);
                }
            }, 100);
            $(document).ready(function () {
                rcpatrol.fetch();
                $("#firstHeading, #section_0").html("Recent Changes Patrol");
                $("title").text("Recent Changes Patrol - " + mw.config.get("wgSiteName"));
                /*
                if (mw.config.get("skin") == "minerva") {
                    $("body").html($("main").html());
                    $("#siteNotice").prepend('<a id="rcpatrolexit" href="/">Exit</a>');
                    $("#rcpatrolexit").click(function () {
                        window.history.back();
                    })
                }
                */
                $("#mw-content-text").html("");
                $("#mw-content-text").append('<div id="rcpatrolbuttons"></div>');
                $("#mw-content-text").append('<div id="rcpatroldiff"></div>');
                $("#rcpatrolbuttons").prepend(rcpatrol.rcpatrolbar.$element);
                $("#rcpatrolbuttons").prepend(rcpatrol.rollbackbar.$element);
                $("#rcpatrolbuttons").prepend(rcpatrol.dropdownmenu.$element);
                $("#rcpatrolbuttons").prepend('<a href="/wiki/Special:BlankPage/RCPatrol?oresreview=1">Only show edits that likely need review</a><br>');
                if (mw.config.get('wgUserGroups').includes('sysop')) {
                    $("#rcpatrolbuttons").append('<div>Admin tools: <span id="rcpatroladmintools"></span></div>');
                }
                $("#rcpatrolbuttons").append('<div>Page tools: <span id="rcpatrolpagetools"></span></div>');
                $("#rcpatroldiff").css({
                    overflow: "auto"
                });
            })
        }
    }/**
 * Internationalization here
 */
    rcpatrol.i18n = {
        reasontorollback: {
            en: 'Reason to rollback (optional)'
        },
        rollback: {
            en: 'Rollback'
        },
        rollingback: {
            en: 'Rolling back...'
        },
        rollbackfailed: {
            en: 'Rollback failed'
        },
        rollbacksuccess: {
            en: 'Rollback complete'
        },
        rollbacksummary: {
            en: '[[w:User:Awesome Aasim/rcpatrol|RCP]] reverted edits by [[Special:Contributions/$2|$2]] ([[User_talk:$2|Talk]]); changed back to last revision by [[Special:Contributions/$1|$1]]'
        },
        warnsummary: {
            en: '[[w:User:Awesome Aasim/rcpatrol|RCP]] send warning to $1 about [[$2]]'
        },
        reportsummary: {
            en: '[[w:User:Awesome Aasim/rcpatrol|RCP]] report $1'
        },
        rollbacktitle: {
            en: "Revert this user's edits",
        },
        previousedit: {
            en: 'Previous edit'
        },
        previousedittitle: {
            en: 'Load the previous edit in the batch'
        },
        nextedit: {
            en: 'Next edit'
        },
        nextedittitle: {
            en: 'Load the next edit in the batch'
        },
        refresh: {
            en: 'Refresh'
        },
        connectionlost: {
            en: 'Lost connection'
        },
        connectionlostdiffmessage: {
            en: "Could not load diff.  Please check your Internet connection.  The diff will automatically reload when the connection is reestablished."
        },
        thank: {
            en: 'Thank'
        },
        thanktitle: {
            en: "Thank this user for their edits"
        },
        rollbackandwarn: {
            en: 'Rollback and warn'
        },
        endoflist: {
            en: 'Reached end of list.  Loading next batch...'
        },
        thankssent: {
            en: 'Thanks sent!'
        },
        rcpatroltitle: {
            en: 'Recent Changes Patrol'
        },
        rcpatroltitlewithdiff: {
            en: 'Recent Changes Patrol "$1"'
        },
        delete: {
            en: 'Delete'
        },
        protect: {
            en: 'Protect'
        },
        block: {
            en: 'Block poster'
        },
        history: {
            en: 'View page history'
        },
        diff: {
            en: 'View diff'
        }
    }
    /**
     * End of internationaliztaion.  DO NOT EDIT BELOW THIS LINE
     */
    rcpatrol.msgs = {};
    for (var i in rcpatrol.i18n) {
        rcpatrol.msgs[i] = rcpatrol.i18n[mw.config.get("wgUserLanguage")] ? rcpatrol.i18n[mw.config.get("wgUserLanguage")] : rcpatrol.i18n["en"]; //always fall back to English if the message translation is incomplete
    }/**
 * Configuration for English Wikipedia
 * Eventually this will be stored elsewhere on a separate page, maybe at [[Project:RC Patrol Script/config.js]]
 * The idea is that any particular modules that need to be disabled or reconfigured can be done so on a wiki by wiki basis by simply "reprogramming" it here.
 * The configuration file should be locked so that only administrators can edit it.
 */
    rcpatrol.reportpage = "Wikipedia:Administrator intervention against vandalism"; //the page that users should be reported on
    rcpatrol.reportstring = "\n\n* {{vandal|1=$1}} - $2"; //the string pattern to use for the report
    rcpatrol.dropdown = [
        {
            keycode: 84, //t
            val: "Test edit",
            summary: "Test edit",
            template: "uw-test"
        },
        {
            keycode: 69, //e
            val: "Disruptive edit",
            summary: "[[WP:DE|Disruptive edit]]",
            template: "uw-disruptive"
        },
        {
            keycode: 77, //m
            val: "Manual of style violation",
            summary: "Violates [[WP:MOS|manual of style]]",
            template: "uw-mos"
        },
        {
            keycode: 65, //a
            val: "Personal attack",
            summary: "[[WP:NPA|Personal attack]]",
            template: "uw-npa"
        },
        {
            keycode: 76, //l
            val: "BLP violation",
            summary: "Violation of the [[WP:BLP|biographies of living people policy]]",
            template: "uw-biog"
        },
        {
            keycode: 78, //n
            val: "Neutral point of view violation",
            summary: "Violates [[WP:NPOV|neutral point of view]]",
            template: "uw-npov"
        },
        {
            keycode: 85, //u
            val: "Unsourced",
            summary: "[[WP:UNSOURCED|Unsourced]]",
            template: "uw-unsourced"
        },
        {
            keycode: 68, //d
            val: "Unexplained content removal",
            summary: "Unexplained removal of content",
            template: "uw-delete"
        },
        {
            keycode: 66, //b
            val: "Page blanking",
            summary: "Blanking the page",
            template: "uw-blank"
        },
        {
            keycode: 86, //v
            val: "Vandalism",
            summary: "Unconstructive edit",
            template: "uw-vandalism"
        },
        {
            keycode: 83, //s
            val: "Link spam",
            summary: "Inappropriate external link",
            template: "uw-spam"
        },
        {
            keycode: 80, //p
            val: "Advertising",
            summary: "Promotional language in article",
            template: "uw-advert"
        }
    ];/**
 * Load all OOUI items, including buttons, etc.
 */

    rcpatrol.rcpatrolbar = new OO.ui.HorizontalLayout({ align: 'inline' });
    rcpatrol.rcpatrolbox = new OO.ui.TextInputWidget({
        autosize: true,
        placeholder: 'Reason to rollback (optional)',
        icon: 'textSummary',
        align: 'inline'
    });
    rcpatrol.rcpatrolbutton = new OO.ui.ButtonWidget({
        autosize: true,
        label: 'Rollback',
        flags: [
            'primary',
            'progressive'
        ],
        icon: "editUndo",
        align: 'inline'
    });
    rcpatrol.rollbackbar = new OO.ui.ActionFieldLayout(rcpatrol.rcpatrolbox, rcpatrol.rcpatrolbutton, { align: "inline" });
    rcpatrol.previouseditbutton = new OO.ui.ButtonWidget({
        autosize: true,
        label: 'Previous edit',
        icon: "previous",
        align: 'inline'
    });
    rcpatrol.nexteditbutton = new OO.ui.ButtonWidget({
        autosize: true,
        label: 'Next edit',
        icon: "next",
        align: 'inline'
    });
    rcpatrol.fetchbutton = new OO.ui.ButtonWidget({
        autosize: true,
        label: 'Refresh',
        icon: "reload",
        align: 'inline'
    });
    rcpatrol.thankbutton = new OO.ui.ButtonWidget({
        autosize: true,
        label: 'Thank',
        icon: "heart",
        align: 'inline'
    });
    rcpatrol.patrolbutton = new OO.ui.ButtonWidget({
        autosize: true,
        label: 'Mark as patrolled',
        icon: 'check',
        align: 'inline'
    });
    rcpatrol.dropdownmenu = new OO.ui.DropdownWidget({
        label: "Rollback and warn...",
        icon: "speechBubbleAdd",
        menu: {
            items: []
        }
    });
    rcpatrol.rcpatrolbar.addItems([
        rcpatrol.previouseditbutton,
        rcpatrol.nexteditbutton,
        rcpatrol.fetchbutton,
        rcpatrol.thankbutton,
        rcpatrol.patrolbutton
    ]);
    rcpatrol.rcpatrolbutton.$element.attr("title", "Revert this user's edits [ctrl-alt R]");
    rcpatrol.thankbutton.$element.attr("title", "Thank this user for their edits [ctrl-alt =]");
    rcpatrol.patrolbutton.$element.attr("title", "Mark this edit as patrolled [ctrl-alt P]");
    rcpatrol.nexteditbutton.$element.attr("title", "Load the next edit in the batch [ctrl-alt space]");
    rcpatrol.previouseditbutton.$element.attr("title", "Load the previous edit in the batch [ctrl-alt ,]");
    for (var i in rcpatrol.dropdown) {
        var temp = new OO.ui.MenuOptionWidget({
            data: rcpatrol.dropdown[i].keycode,
            label: rcpatrol.dropdown[i].val
        });
        temp.$element.attr("title", rcpatrol.dropdown[i].val + (String.fromCharCode(rcpatrol.dropdown[i].keycode) ? " [ctrl-alt-shift " + String.fromCharCode(rcpatrol.dropdown[i].keycode) + "]" : ""));
        rcpatrol.dropdownmenu.getMenu().addItems([temp]);
    }
    /**
     * Disables/enables the RC patrol controls
     * @param {*} bool whether to disable the controls or not
     */
    rcpatrol.setDisabled = function (bool) {
        rcpatrol.isDisabled = bool;
        rcpatrol.dropdownmenu.setDisabled(bool);
        rcpatrol.previouseditbutton.setDisabled(bool);
        rcpatrol.nexteditbutton.setDisabled(bool);
        rcpatrol.rcpatrolbutton.setDisabled(bool);
        rcpatrol.rcpatrolbox.setDisabled(bool);
        rcpatrol.thankbutton.setDisabled(bool);
        rcpatrol.patrolbutton.setDisabled(bool);
        rcpatrol.fetchbutton.setDisabled(bool);
    };
    /**
     * Fetches a list of recent changes and loads it onto RC patrol
     */
    rcpatrol.timeoutDuration = 1000;
    rcpatrol.fetch = function () {
        if (!rcpatrol.fetchbutton.isDisabled()) {
            $("#rcpatroldiff").fadeOut();
            rcpatrol.setDisabled(true);
            $.get(mw.config.get("wgScriptPath") + "/api.php", {
                "action": "query",
                "format": "json",
                "list": "recentchanges",
                "rcprop": "title|timestamp|flags|loginfo|parsedcomment|user|ids|tags",
                "rcshow": "!bot" + ((new URL(window.location.href)).searchParams.get("oresreview") ? "|oresreview" : ""),
                "rctoponly": true,
                "rclimit": "max",
                "rctype": "edit|new",
                "uselang": mw.config.get("wgUserLanguage")
            }).done(function (result) {
                if (result.error) {
                    rcpatrol.timeoutDuration *= 2
                    window.setTimeout(rcpatrol.fetch, rcpatrol.timeoutDuration / 2);
                    console.error(result.error.info);
                } else {
                    rcpatrol.timeoutDuration = 1000
                    rcpatrol.changes = result.query.recentchanges;
                    console.log(result.query.recentchanges);
                    rcpatrol.setDisabled(false);
                    rcpatrol.currentChange = 0;
                    rcpatrol.loadChange(rcpatrol.changes[rcpatrol.currentChange]);
                }
            }).fail(function () {
                rcpatrol.timeoutDuration *= 2
                window.setTimeout(rcpatrol.fetch, 1000);
            });
        }
    };
    /**
     * Loads a change and places it in the RC patrol diff output.
     * @param {*} change the diff of the change to load
     */
    rcpatrol.loadChange = function (change) {
        $("#rcpatroldiff").fadeOut();
        $("#rcpatroladmintools").fadeOut();
        $("#rcpatrolpagetools").fadeOut();
        rcpatrol.setDisabled(true);
        $.get(mw.config.get("wgScriptPath") + "/api.php", {
            "action": "query",
            "format": "json",
            "prop": "revisions",
            "titles": change.title,
            "rvlimit": "1",
            "uselang": mw.config.get("wgUserLanguage")
        }).done(function (result) {
            for (var pageid in result.query.pages) {
                change.revid = result.query.pages[pageid].revisions[0].revid;
                change.user = result.query.pages[pageid].revisions[0].user;
                break;
            }
            $.get(mw.config.get("wgScriptPath") + "/api.php", {
                "action": "query",
                "format": "json",
                "prop": "revisions",
                "titles": change.title,
                "rvexcludeuser": change.user,
                "rvlimit": "1",
                "uselang": mw.config.get("wgUserLanguage")
            }).done(function (result) {
                console.log(result);
                var oldid;
                try {
                    for (var pageid in result.query.pages) {
                        oldid = result.query.pages[pageid].revisions[0].revid;
                        break;
                    }
                } catch (Error) {
                    var temp = oldid;
                    oldid = change.revid;
                    change.revid = "";
                }
                console.log(mw.config.get("wgScriptPath") + "/index.php?oldid=" + oldid + "&diff=" + change.revid);
                var scriptpath = mw.config.get('wgScriptPath');
                var loadurl = mw.config.get("wgScriptPath") + "/index.php?oldid=" + oldid + (change.revid ? "&diff=" + change.revid : "");
                if (mw.config.get("wgMFMode")) {
                    loadurl = mw.config.get("wgArticlePath").replace("$1", "Special:MobileDiff/" + oldid + (change.revid ? "..." + change.revid : ""));
                }
                $.get(loadurl, {
                    safemode: "1",
                    uselang: mw.config.get("wgUserLanguage"),
                    useskin: mw.config.get("skin")
                }).done(function (result) {
                    var $r;
                    $r = $(result);
                    $("#rcpatroldiff").html($r.find("#mw-content-text").html());
                    if (mw.config.get("wgMFMode")) {
                        mw.loader.load("mobile.special.mobilediff.styles");
                    } else {
                        mw.loader.load("mediawiki.diff.styles");
                    }
                    $("#firstHeading, #section_0").html('Recent Changes Patrol \"<a target=\"_blank\" href=\"' + scriptpath + '/index.php?title=' + change.title + '\">' + change.title + "</a>\"");
                    $("title").text("Recent Changes Patrol \"" + change.title + "\" - " + mw.config.get("wgSiteName"));

                    $("#rcpatroldiff").fadeIn();
                    $("#rcpatroladmintools").fadeIn();
                    $("#rcpatrolpagetools").fadeIn();
                    rcpatrol.rcpatrolbox.setValue("");
                    rcpatrol.rcpatrolbutton.setLabel("Rollback");
                    rcpatrol.patrolbutton.setLabel("Mark as patrolled");
                    rcpatrol.setDisabled(false);
                    $("#rcpatroladmintools").html('');
                    $("#rcpatroladmintools").append('<a target="_blank" href="' + scriptpath + '/index.php?title=' + change.title + '&action=delete">Delete</a>');
                    $("#rcpatroladmintools").append(' &bull; ');
                    $("#rcpatroladmintools").append('<a target="_blank" href="' + scriptpath + '/index.php?title=' + change.title + '&action=protect">Protect</a>');
                    $("#rcpatroladmintools").append(' &bull; ');
                    $("#rcpatroladmintools").append('<a target="_blank" href="' + scriptpath + '/index.php?title=Special:Block/' + change.user + '">Block poster</a>');
                    $("#rcpatrolpagetools").html('');
                    $("#rcpatrolpagetools").append('<a target="_blank" href="' + scriptpath + '/index.php?title=' + change.title + '&action=history">View page history</a>');
                    $("#rcpatrolpagetools").append(' &bull; ');
                    $("#rcpatrolpagetools").append('<a target="_blank" href="' + scriptpath + '/index.php?oldid=' + oldid + '&diff=' + change.revid + '">View diff</a>');
                }).fail(function () {
                    $("#rcpatroldiff").fadeIn(1000);
                    $("#rcpatroldiff").text("Could not load diff.  Please check your Internet connection.  The diff will automatically reload when the connection is reestablished.");
                    window.setTimeout(function () {
                        rcpatrol.loadChange(change);
                    }, 1000);
                });
                /*
                $("#rcpatroldiff").load(loadurl, function (response, status, xhr) {
                    if (status == "error") {
                    } else {
                        $("#rcpatroldiff").find("form").hide();
                        $("#rcpatroldiff").find("#firstHeading").hide();
                    }
                });
                */
            }).fail(function (result) {
                $("#rcpatroldiff").fadeIn(1000);
                $("#rcpatroldiff").text("Could not load diff.  Please check your Internet connection.  The diff will automatically reload when the connection is reestablished.");
                window.setTimeout(function () {
                    rcpatrol.loadChange(change)
                }, 1000);
            });
        }).fail(function (result) {
            $("#rcpatroldiff").fadeIn(1000);
            $("#rcpatroldiff").text("Could not load diff.  Please check your Internet connection.  The diff will automatically reload when the connection is reestablished.");
            window.setTimeout(function () {
                rcpatrol.loadChange(change)
            }, 1000);
        });
    };/**
 * Rolls back edits on diffs
 * @param {*} page the page to revert the edits on
 * @param {*} user the user to revert
 * @param {*} afterSuccess what to do after the revert is successful
 * @param {*} afterFail what to do if the revert fails
 */
    rcpatrol.revert = function (page, user, afterSuccess, afterFail) {
        if (!rcpatrol.rcpatrolbutton.isDisabled()) {
            var summary = rcpatrol.rcpatrolbox.getValue();
            rcpatrol.rcpatrolbutton.setLabel("Rolling back...");
            rcpatrol.setDisabled(true);
            $.get(mw.config.get("wgScriptPath") + "/api.php", {
                "action": "query",
                "format": "json",
                "meta": "tokens",
                "type": "rollback"
            }).done(function (result) {
                if (result.error) {
                    rcpatrol.rcpatrolbutton.setLabel("Rollback failed");
                    alert(result.error.info);
                    afterFail();
                } else {
                    $.post(mw.config.get("wgScriptPath") + "/api.php", {
                        "action": "rollback",
                        "format": "json",
                        "title": page,
                        "token": result.query.tokens.rollbacktoken,
                        "user": user,
                        "summary": "[[User:Awesome Aasim/rcpatrol|RCP]] reverted edits by [[Special:Contributions/$2|$2]] ([[User_talk:$2|Talk]]); changed back to last revision by [[Special:Contributions/$1|$1]]" + (summary ? ": " + summary : "")
                    }).done(function (result) {
                        if (result.error) {
                            rcpatrol.rcpatrolbutton.setLabel("Rollback failed");
                            alert(result.error.info);
                            afterFail();
                        } else {
                            rcpatrol.rcpatrolbutton.setLabel("Rollback complete");
                            afterSuccess();
                        }
                    }).fail(function () {
                        console.log(result);
                        alert("Lost connection.");
                        rcpatrol.rcpatrolbutton.setLabel("Rollback failed");
                        afterFail();
                    });
                }
            });
        }
    };/**
 * Warns a user with a specified warning template
 * @param {*} user the user to warn
 * @param {*} template the template prefix to use as a warning
 * @param {*} page the relevant page
 */
    rcpatrol.warn = function (user, template, page, reason) {
        var date = new Date();
        var months = mw.config.get("wgMonthNames");
        var currentMonth = months[date.getUTCMonth() + 1];
        var year = date.getUTCFullYear();
        var header = currentMonth + " " + year;
        $.get(mw.config.get("wgScriptPath") + "/api.php", {
            "action": "query",
            "format": "json",
            "meta": "tokens",
            "type": "csrf",
            "uselang": mw.config.get("wgUserLanguage")
        }).done(function (result) {
            var token = result.query.tokens.csrftoken;
            $.get(mw.config.get("wgScriptPath") + "/api.php", {
                "action": "parse",
                "format": "json",
                "prop": "text",
                "page": "User_talk:" + user,
                "uselang": mw.config.get("wgUserLanguage")
            }).done(function (result) {
                if (result.error) {
                    if (result.error.code == "missingtitle") {
                        $.post(mw.config.get("wgScriptPath") + "/api.php", {
                            "action": "edit",
                            "section": "new",
                            "sectiontitle": header,
                            "format": "json",
                            "title": "User_talk:" + user,
                            "text": "{{subst:" + template + "1|1=" + page + "}} ~~" + "~~",
                            "summary": "[[User:Awesome Aasim/rcpatrol|RCP]] send warning to " + user + " about [[" + page + "]]",
                            "token": token,
                            "uselang": mw.config.get("wgUserLanguage")
                        }).done(function (result) {
                            if (result.error) {
                                mw.notify("We could not send a warning to " + user + ".");
                            } else {
                                mw.notify("A warning was automatically sent to " + user + ".");
                            }
                        });
                    }
                } else {
                    var section = "new";
                    $(result.parse.text["*"]).find(".mw-headline").each(function (i) {
                        if ($(this).text() == header) {
                            section = i + 1;
                        }
                    });
                    if (section == "new") {
                        $.post(mw.config.get("wgScriptPath") + "/api.php", {
                            "action": "edit",
                            "section": "new",
                            "sectiontitle": header,
                            "format": "json",
                            "title": "User_talk:" + user,
                            "text": "{{subst:" + template + "1|1=" + page + "}} ~~" + "~~",
                            "summary": "[[User:Awesome Aasim/rcpatrol|RCP]] send warning to " + user + " about [[" + page + "]]",
                            "token": token,
                            "uselang": mw.config.get("wgUserLanguage")
                        }).done(function (result) {
                            if (result.error) {
                                mw.notify("We could not send a warning to " + user + ".");
                            } else {
                                mw.notify("A warning was automatically sent to " + user + ".");
                            }
                        });
                    } else {
                        $.get(mw.config.get("wgScriptPath") + "/api.php", {
                            "action": "parse",
                            "section": section,
                            "format": "json",
                            "prop": "wikitext",
                            "page": "User_talk:" + user,
                            "uselang": mw.config.get("wgUserLanguage")
                        }).done(function (result) {
                            if (result.error) {
                                console.error(result.error.info);
                            } else {
                                console.log(result.parse.wikitext["*"]);
                                var warninglevelstrings = result.parse.wikitext["*"].match(/<!--( ){0,}Template:.*(1|2|3|4)(im)?( ){0,}-->/g);
                                console.log(warninglevelstrings);
                                var warninglevels = warninglevelstrings[warninglevelstrings.length - 1].match(/[(1|2|3|4)]/);
                                var warninglevel = parseInt(warninglevels[warninglevels.length - 1]) + 1;
                                var oldtimestamp = (new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()) - 86400000)).toISOString();
                                $.get(mw.config.get("wgScriptPath") + "/api.php", {
                                    "action": "query",
                                    "format": "json",
                                    "prop": "revisions",
                                    "titles": "User_talk:" + user,
                                    "rvsection": section,
                                    "rvend": oldtimestamp,
                                    "uselang": mw.config.get("wgUserLanguage")
                                }).done(function (result) {
                                    var revisions = [];
                                    try {
                                        for (var pageid in result.query.pages) {
                                            revisions = result.query.pages[pageid].revisions;
                                        }
                                    } catch (Error) {

                                    }
                                    if (revisions) {
                                        if (warninglevel > 4) {
                                            rcpatrol.report(user, reason);
                                        } else {
                                            $.post(mw.config.get("wgScriptPath") + "/api.php", {
                                                "action": "edit",
                                                "section": section,
                                                "sectiontitle": header,
                                                "format": "json",
                                                "title": "User_talk:" + user,
                                                "appendtext": "\n\n{{subst:" + template + warninglevel + "|1=" + page + "}} ~~" + "~~",
                                                "summary": "[[User:Awesome Aasim/rcpatrol|RCP]] send warning to " + user + " about [[" + page + "]]",
                                                "token": token,
                                                "uselang": mw.config.get("wgUserLanguage")
                                            }).done(function (result) {
                                                if (result.error) {
                                                    mw.notify("We could not send a warning to " + user + ".");
                                                } else {
                                                    mw.notify("A warning was automatically sent to " + user + ".");
                                                }
                                            });
                                        }
                                    } else {
                                        $.post(mw.config.get("wgScriptPath") + "/api.php", {
                                            "action": "edit",
                                            "section": section,
                                            "sectiontitle": header,
                                            "format": "json",
                                            "title": "User_talk:" + user,
                                            "appendtext": "\n\n{{subst:" + template + "1|1=" + page + "}} ~~" + "~~",
                                            "summary": "[[User:Awesome Aasim/rcpatrol|RCP]] send warning to " + user + " about [[" + page + "]]",
                                            "token": token,
                                            "uselang": mw.config.get("wgUserLanguage")
                                        }).done(function (result) {
                                            if (result.error) {
                                                mw.notify("We could not send a warning to " + user + ".");
                                            } else {
                                                mw.notify("A warning was automatically sent to " + user + ".");
                                            }
                                        });
                                    }
                                });
                            }
                        });
                    }
                }
            });
        });
    };/**
 * Reports any user to a preconfigured project page
 * If admin, blocks the user for a preset time
 * @param {*} user user to report
 */
    rcpatrol.report = function (user, reason) {
        if (mw.config.get("wgUserGroups").includes("sysop")) {
            //TODO:  get block suggestion for vandals 1 day initially, then double the block if the user commits another infraction after getting unblocked
            //also:  block API
            var blockwindow = window.open(mw.config.get("wgArticlePath").replace("$1", "Special:Block/" + user) + "?wpReason-other=" + encodeURI(reason));
            blockwindow.onload = function () {
                alert("The user has received a final warning in the last 24 hours, so this window was opened.  When you are done blocking the user, you can close this tab and go back to RC patrol.");
            }
        } else {
            var reportwindow = window.open(mw.config.get("wgArticlePath").replace("$1", rcpatrol.reportpage));
            reportwindow.onload = function () {
                var reportinfo = reportwindow.prompt("This user has received a final warning in the last 24 hours or was recently unblocked, so RC patrol is proceeding to report to AIV. Enter information about the report here, leave blank for \"" + reason + ": after final warning.\". If you think a report is inappropriate, click 'Cancel' and proceed to report on your own accord.");
                if (reportinfo == null || reportinfo == undefined) return;
                reportinfo = reportinfo ? reportinfo : reason + ": after final warning.";
                $.get(mw.config.get("wgScriptPath") + "/api.php", {
                    "action": "query",
                    "format": "json",
                    "meta": "tokens",
                    "type": "csrf",
                    "uselang": mw.config.get("wgUserLanguage")
                }).done(function (result) {
                    $.post(mw.config.get("wgScriptPath") + "/api.php", {
                        "action": "edit",
                        "format": "json",
                        "title": rcpatrol.reportpage,
                        "summary": "[[User:Awesome Aasim/rcpatrol|RCP]] report " + user,
                        "appendtext": rcpatrol.reportstring.replace("$1", user).replace("$2", reportinfo) + " ~~" + "~~",
                        "uselang": mw.config.get("wgUserLanguage"),
                        "token": result.query.tokens.csrftoken
                    }).done(function (result) {
                        if (result.error) {
                            reportwindow.alert(result.error.info);
                        } else {
                            mw.notify("User successfully reported to admins.");
                        }
                        reportwindow.close();
                    });
                });
            }
        }
    }/**
 * Handles global events, including clicks, keypresses, etc.
 */
    rcpatrol.fetchbutton.$element.click(rcpatrol.fetch);
    rcpatrol.rcpatrolbutton.$element.click(function (e) {
        rcpatrol.revert(rcpatrol.changes[rcpatrol.currentChange].title, rcpatrol.changes[rcpatrol.currentChange].user, function () {
            rcpatrol.currentChange++;
            rcpatrol.loadChange(rcpatrol.changes[rcpatrol.currentChange]);
        },
            function () {
                rcpatrol.loadChange(rcpatrol.changes[rcpatrol.currentChange]);
            });
    });
    rcpatrol.nexteditbutton.$element.click(function (e) {
        if (!rcpatrol.nexteditbutton.isDisabled()) {
            e.preventDefault();
            rcpatrol.currentChange++;
            if (rcpatrol.currentChange >= rcpatrol.changes.length) {
                mw.notify("Reached end of list.  Loading next batch...")
                rcpatrol.fetch();
            } else {
                rcpatrol.loadChange(rcpatrol.changes[rcpatrol.currentChange]);
            }
        }
    });
    rcpatrol.previouseditbutton.$element.click(function (e) {
        if (!rcpatrol.previouseditbutton.isDisabled()) {
            e.preventDefault();
            rcpatrol.currentChange--;
            if (rcpatrol.currentChange < 0) {
                rcpatrol.currentChange = 0;
            }
            rcpatrol.loadChange(rcpatrol.changes[rcpatrol.currentChange]);
        }
    });
    rcpatrol.thankbutton.$element.click(function (e) {
        if (!rcpatrol.thankbutton.isDisabled()) {
            e.preventDefault();
            rcpatrol.thankbutton.setDisabled(true);
            $.get(mw.config.get("wgScriptPath") + "/api.php", {
                "action": "query",
                "format": "json",
                "meta": "tokens",
                "type": "csrf"
            }).done(function (result) {
                $.post(mw.config.get("wgScriptPath") + "/api.php", {
                    "action": "thank",
                    "format": "json",
                    "rev": rcpatrol.changes[rcpatrol.currentChange].revid,
                    "token": result.query.tokens.csrftoken
                }).done(function (result) {
                    if (result.error) {
                        alert(result.error.info);
                    } else {
                        mw.notify("Thanks sent!");
                    }
                })
            })
        }
    });
    /**
     * Mark the edit as patrolled
     **/
    rcpatrol.patrolbutton.$element.click(function (e) {
        rcpatrol.patrolbutton.setLabel('Marking as patrolled');
        if (!rcpatrol.patrolbutton.isDisabled()) {
            e.preventDefault();
            rcpatrol.patrolbutton.setDisabled(true);
            $.get(mw.config.get("wgScriptPath") + "/api.php", {
                "action": "query",
                "format": "json",
                "meta": "tokens",
                "type": "patrol"
            }).done(function (result) {
                $.post(mw.config.get("wgScriptPath") + "/api.php", {
                    "action": "patrol",
                    "format": "json",
                    "rcid": rcpatrol.changes[rcpatrol.currentChange].rcid,
                    "token": result.query.tokens.patroltoken,
                    "formatversion": 2
                }).done(function (result) {
                    if (result.error) {
                        mw.notify(result.error.info);
                    } else {
                        mw.notify("The version (rcid " + rcpatrol.changes[rcpatrol.currentChange].rcid + ") has been marked as patrolled!");
                        rcpatrol.patrolbutton.setLabel('Marked as patrolled');
                    }
                })
            })
        }
    })
    rcpatrol.rcpatrolbox.$element.keypress(function (e) {

        if (e.which == 13) {
            rcpatrol.revert(rcpatrol.changes[rcpatrol.currentChange].title, rcpatrol.changes[rcpatrol.currentChange].user, function () {
                rcpatrol.currentChange++;
                rcpatrol.loadChange(rcpatrol.changes[rcpatrol.currentChange]);
            },
                function () {
                    rcpatrol.loadChange(rcpatrol.changes[rcpatrol.currentChange]);
                });
        }
    });

    rcpatrol.dropdownmenu.getMenu().on('select', function () {
        var val = rcpatrol.dropdownmenu.getLabel();
        for (var option of rcpatrol.dropdown) {
            if (option.val == val) {
                rcpatrol.rcpatrolbox.setValue(option.summary);
                rcpatrol.revert(rcpatrol.changes[rcpatrol.currentChange].title, rcpatrol.changes[rcpatrol.currentChange].user, function () {
                    rcpatrol.warn(rcpatrol.changes[rcpatrol.currentChange].user, option.template, rcpatrol.changes[rcpatrol.currentChange].title, option.val);
                    rcpatrol.currentChange++;
                    rcpatrol.loadChange(rcpatrol.changes[rcpatrol.currentChange]);
                    rcpatrol.dropdownmenu.getMenu().unselectItem();
                    rcpatrol.dropdownmenu.setLabel("Rollback and warn...");
                }, function () {
                    rcpatrol.dropdownmenu.getMenu().unselectItem();
                    rcpatrol.dropdownmenu.setLabel("Rollback and warn...");
                    rcpatrol.loadChange(rcpatrol.changes[rcpatrol.currentChange]);
                });
                break;
            } else {
                continue;
            }
        }
    });
    /**
     * Page for processing key combinations
     */

    $(document).keydown(function (e) {
        if (e.ctrlKey && e.altKey && !e.shiftKey) {
            switch (e.which) {
                case 82: e.preventDefault(); //rollback (r)
                    rcpatrol.revert(rcpatrol.changes[rcpatrol.currentChange].title, rcpatrol.changes[rcpatrol.currentChange].user, function () {
                        rcpatrol.currentChange++;
                        rcpatrol.loadChange(rcpatrol.changes[rcpatrol.currentChange]);
                    },
                        function () {
                            rcpatrol.loadChange(rcpatrol.changes[rcpatrol.currentChange]);
                        });
                    break;
                case 80: e.preventDefault(); //patrol (p)
                    rcpatrol.patrolbutton.$element.click();
                    break;
                case 32: e.preventDefault(); //next edit ( )
                    rcpatrol.nexteditbutton.$element.click();
                    break;
                case 188: e.preventDefault(); //previous edit (<)
                    rcpatrol.previouseditbutton.$element.click();
                    break;
                case 187: e.preventDefault(); //thanks (+)
                    rcpatrol.thankbutton.$element.click();
                    break;
            }
        } else if (e.ctrlKey && e.altKey && e.shiftKey) {
            for (var option of rcpatrol.dropdown) {
                if (option.keycode == e.which) {
                    rcpatrol.rcpatrolbox.setValue(option.summary);
                    rcpatrol.revert(rcpatrol.changes[rcpatrol.currentChange].title, rcpatrol.changes[rcpatrol.currentChange].user, function () {
                        rcpatrol.warn(rcpatrol.changes[rcpatrol.currentChange].user, option.template, rcpatrol.changes[rcpatrol.currentChange].title, option.val);
                        rcpatrol.currentChange++;
                        rcpatrol.loadChange(rcpatrol.changes[rcpatrol.currentChange]);
                    }, function () {
                        rcpatrol.loadChange(rcpatrol.changes[rcpatrol.currentChange]);
                    });
                    break;
                } else {
                    continue;
                }
            }
        }
    });
})