MediaWiki:Common.js/User:Fumple/PatrolTool.js

From Inkipedia, the Splatoon wiki
Revision as of 14:41, 11 June 2020 by Fumple (talk | contribs) (Fix for fix)

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
function patroltool_error(data) {
    $("#funpl-patroltool").css("display", "none");
    $("#funpl-patroltool-error").css("display", "");
    $("#funpl-patroltool-error-text").text(data);
    console.error(data);
    throw new Error(data);
}

$(function () {
    try { //try catch all the lines!
        var namespaceselect = null,
            continuebutton = null,
            patrolbutton = null,
            cignorebutton = null,
            cblayout = null,
            cilayout = null,
            finalchanges = [],
            currentchange = -1,
            mwApi = new mw.Api();

        mwApi.get({
            "action": "query",
            "format": "json",
            "meta": "userinfo",
            "uiprop": "rights"
        }).done((data) => {
            console.log("[PatrolTool] Rights", data);
            if (data.query.userinfo.rights.includes("patrol")) {
                loadFilters();
            }
            else if (data.query.userinfo.id != 0) {
                $("#funpl-patroltool").css("display", "none");
                $("#funpl-patroltool-error").css("display", "");
                $("#funpl-patroltool-error-text").html("You can't use this tool as you don't have the correct rights");
            }
            else {
                $("#funpl-patroltool").css("display", "none");
                $("#funpl-patroltool-error").css("display", "");
                $("#funpl-patroltool-error-text").html("You can't use this tool as you don't have the correct rights<br>You're also logged out, maybe you want to <a href='/w/index.php?title=Special:UserLogin&amp;returnto=User%3AFunPL%2FPatrolTool'>log in</a>");
            }
        }).catch(patroltool_error);

        async function loadFilters() {
            try {
                await mw.loader.load("oojs-ui");
                await mw.loader.load("oojs-ui-widgets");
                $("#funpl-patroltool-header").text("Loading namespaces...");
                mwApi.get({
                    "action": "query",
                    "format": "json",
                    "meta": "siteinfo",
                    "siprop": "namespaces"
                }).done((data) => {
                    console.log("namespaces", data);
                    namespaceselect = new OO.ui.MenuTagMultiselectWidget({
                        "options": [{
                            "data": "*",
                            "label": "All namespaces"
                        }]
                    });
                    var layout = new OO.ui.FieldLayout(namespaceselect, {
                        "align": 'top',
                        "label": 'Namespaces',
                        "id": "funpl-patroltool-nss"
                    });
                    continuebutton = new OO.ui.ButtonWidget({
                        label: 'Continue',
                        icon: 'arrowNext'
                    });
                    cblayout = new OO.ui.FieldLayout(continuebutton, {
                        "align": 'top',
                        "label": '',
                        "id": "funpl-patroltool-cb",
                        "notices": ["Pro tip: Want to save your filters? Bookmark this page after you click continue"]
                    });
                    var url = new URL(window.location);
                    if (url.searchParams.has("namespaces"))
                        var urlns = url.searchParams.get("namespaces").split('|');
                    else
                        var urlns = [];

                    var selected = [];
                    if (urlns.includes("*"))
                        selected = selected.concat({
                            "data": "*",
                            "label": "All namespaces"
                        });
                    for (var nsid in data.query.namespaces) {
                        namespaceselect.addOptions([{
                            "data": nsid,
                            "label": data.query.namespaces[nsid]["*"] != "" ? data.query.namespaces[nsid]["*"] : "(Main)"
                        }])
                        if (urlns.includes(nsid))
                            selected = selected.concat({
                                "data": nsid,
                                "label": data.query.namespaces[nsid]["*"] != "" ? data.query.namespaces[nsid]["*"] : "(Main)"
                            });
                    }
                    namespaceselect.setValue(selected);
                    $("#funpl-patroltool-header").text("Select filters");
                    $("#funpl-patroltool-loading").css("display", "none");
                    $("#funpl-patroltool").append(layout.$element);
                    $("#funpl-patroltool").append(cblayout.$element);
                    continuebutton.on("click", function () {
                        continuebutton.disabled = true;
                        continuebutton.updateDisabled();
                        namespaceselect.disabled = true;
                        namespaceselect.updateDisabled();
                        $("#funpl-patroltool-header").text("Loading changes...");
                        cblayout.setNotices(["Loading... This might take a second"]);
                        $("#funpl-patroltool-loading").css("display", "");
                        loadChanges();
                    })
                }).catch(patroltool_error);
            }
            catch (ex) {
                patroltool_error(ex);
            }
        }

        async function loadChanges(rccontinue) {
            return new Promise(function (k, no) {
                try {
                    var namespace = namespaceselect.getValue().includes("*") ? "*" : namespaceselect.getValue().join('|');
                    if (namespace == "") namespace = "*"
                    var url = new URL(window.location);
                    url.searchParams.set("namespaces", namespace);
                    window.history.pushState("", "", url.toString());

                    var options = {
                        "action": "query",
                        "format": "json",
                        "list": "recentchanges",
                        "rcnamespace": namespace,
                        "rcprop": "title|timestamp|ids|user|parsedcomment",
                        "rcshow": "unpatrolled",
                        "rcdir": "newer",
                        "rclimit": "max"
                    };
                    if (rccontinue != null)
                        options.rccontinue = rccontinue;
                    mwApi.get(options).done(async function (data) {
                        console.log("rcdata", data);
                        var changes = data.query.recentchanges;
                        if (data.continue != null) {
                            var cchanges = await loadChanges(data.continue.rccontinue);
                            changes = changes.concat(cchanges);
                        }
                        if (rccontinue != null) {
                            k(changes);
                            return;
                        }
                        console.log(changes.length, changes);
                        finalchanges = changes;
                        window.patroltoolchanges = finalchanges;
                        $("#funpl-patroltool-header").text("Ready!");
                        cblayout.setNotices(["Found " + changes.length + " changes", "Press continue to load the first edit"]);
                        $("#funpl-patroltool-loading").css("display", "none");
                        continuebutton.disabled = false;
                        continuebutton.updateDisabled();
                        continuebutton.off("click");
                        continuebutton.on("click", function () {
                            continuebutton.off("click");
                            continuebutton.disabled = true;
                            continuebutton.updateDisabled();
                            $("#funpl-patroltool-header").text("Preparing...");
                            cblayout.setNotices([]);
                            $("#funpl-patroltool-loading").css("display", "");
                            $("#funpl-patroltool-nss").remove();
                            $("#funpl-patroltool-cb").remove();
                            $("#funpl-patroltool").append('<div id="funpl-patroltool-desc"></div>');
                            $("#funpl-patroltool").append('<h2 id="funpl-patroltool-diff-header">Diff</h2>');
                            $("#funpl-patroltool").append('<div id="funpl-patroltool-diff" class="diff"></div>');
                            patrolbutton = new OO.ui.ButtonWidget({
                                "label": "Mark as patrolled and continue",
                                "icon": 'arrowNext',
                                "disabled": true,
                                "flags": ["primary", "progressive"]
                            });
                            cignorebutton = new OO.ui.ButtonWidget({
                                "label": 'Ignore and continue',
                                "icon": 'arrowNext',
                                "disabled": true,
                                "flags": ["progressive"]
                            });
                            var toplayout = new OO.ui.HorizontalLayout({
                                items: [
                                    patrolbutton, cignorebutton
                                ]
                            });
                            $("#funpl-patroltool").append(toplayout.$element);
                            $("#funpl-patroltool").append('<h2 id="funpl-patroltool-preview-header">Page preview</h2>');
                            $("#funpl-patroltool").append('<div id="funpl-patroltool-preview"></div>');
                            loadNextChange();
                        })
                    }).catch(patroltool_error).catch(no);
                }
                catch (ex) {
                    patroltool_error(ex);
                }
            });
        }
        function loadNextChange() {
            loadChange(currentchange + 1);
        }
        function loadChange(i) {
            try {
                $("#funpl-patroltool-header").text("Loading...");
                $("#funpl-patroltool-loading").css("display", "");
                $("#funpl-patroltool-desc").html('');
                $("#funpl-patroltool-diff").html('');
                $("#funpl-patroltool-preview").html('');
                currentchange = i; //and this is the place where we load the changes. how exciting
                var change = finalchanges[currentchange];
                console.log("[PatrolTool] Loading change ", change);
                console.log("[PatrolTool] " + (i + 1) + "/" + finalchanges.length);
                console.log("[PatrolTool] Checking whether change " + i + " is patrolled");

                mwApi.get({ //Try to find the edit in the unpatrolled section, if it isn't found, skip this edit as someone patrolled it
                    "action": "query",
                    "format": "json",
                    "list": "recentchanges",
                    "rcstart": finalchanges[currentchange].timestamp,
                    "rcend": finalchanges[currentchange].timestamp,
                    "rcshow": "unpatrolled"
                }).done((data) => {
                    console.log("rccheck", data);
                    if (data.query.recentchanges.length > 0) {
                        console.log("[PatrolTool] Change " + i + " is not patrolled, loading it");
                        $("#funpl-patroltool-header").text('[' + change.type + '] ' + change.title);
                        if (change.type == "edit") {
                            mwApi.get({ //Get the diff
                                "action": "compare",
                                "format": "json",
                                "fromrev": change.old_revid,
                                "torev": change.revid,
                                "prop": "diff|ids|title|user|parsedcomment"
                            }).done((data) => {
                                console.log("compare", data);
                                let compare = data.compare;
                                console.log("[PatrolTool] Loaded compare for change " + i);
                                $("#funpl-patroltool-desc").html(`<table class="wikitable">
                            <tr><th></th><th>Previous change</th><th>This change</th></tr>
                            <tr>
                            <th>Page title</th>
                            <td><a target="_blank" href="/wiki/${encode(compare.fromtitle)}">${compare.fromtitle.encodeHTML()}</a></td>
                            <td><a target="_blank" href="/wiki/${encode(compare.totitle)}">${compare.totitle.encodeHTML()}</a></td>
                            </tr>
                            <tr>
                            <th>Editor</th>
                            <td><a target="_blank" href="/wiki/User:${encode(compare.fromuser)}">${compare.fromuser.encodeHTML()}</a> <a target="_blank" href="/wiki/User%20talk:${encode(compare.fromuser)}">(talk)</a></td>
                            <td><a target="_blank" href="/wiki/User:${encode(compare.touser)}">${compare.touser.encodeHTML()}</a> <a target="_blank" href="/wiki/User%20talk:${encode(compare.touser)}">(talk)</a></td>
                            </tr>
                            <tr>
                            <th>Edit summary</th>
                            <td>${compare.fromparsedcomment}</td>
                            <td>${compare.toparsedcomment}</td>
                            </tr>
                            <tr>
                            <th>Date</th>
                            <td>-</td>
                            <td>${new Date(change.timestamp).toUTCString()}</td>
                            </tr>
                            <tr>
                            <th></th>
                            <td><a target="_blank" href="/wiki/${encode(compare.fromtitle)}?oldid=${urlSafe(compare.fromrevid)}">View</a></td>
                            <td><a target="_blank" href="/wiki/${encode(compare.totitle)}?oldid=${urlSafe(compare.torevid)}">View</a></td>
                            </tr>
                            <tr>
                            <th></th>
                            <td><a target="_blank" href="/wiki/${encode(compare.fromtitle)}?action=edit&oldid=${urlSafe(compare.fromrevid)}">Edit</a></td>
                            <td><a target="_blank" href="/wiki/${encode(compare.totitle)}?action=edit&oldid=${urlSafe(compare.torevid)}">Edit</a></td>
                            </tr>
                            <tr>
                            <th></th>
                            <td></td>
                            <td><a target="_blank" href="/wiki/${encode(compare.totitle)}?action=edit&undoafter=${urlSafe(compare.fromrevid)}&undo=${urlSafe(compare.torevid)}">Undo</a></td>
                            </tr>
                            </table>`)
                                $("#funpl-patroltool-diff").html(compare["*"]);
                                mwApi.get({
                                    "action": "parse",
                                    "format": "json",
                                    "oldid": compare.torevid
                                }).done((parse) => {
                                    console.log("[PatrolTool] parse", parse);
                                    $("#funpl-patroltool-preview").html(parse.parse.text["*"]);
                                    $("#funpl-patroltool-preview").append('<div id="#funpl-patroltool-categories" class="catlinks"></div>');
                                    let cattext = "";
                                    for (var cat of parse.parse.categories) {
                                        cattext += '<li><a href="/wiki/Category:' + encode(cat["*"]) + '">' + cat["*"].encodeHTML() + '</a></li>';
                                    }
                                    if (cattext != "") {
                                        $("#funpl-patroltool-categories").html("<b>Categories:</b> <ul>" + cattext + "</ul>");
                                    }
                                    patrolbutton.disabled = false;
                                    patrolbutton.updateDisabled();
                                    patrolbutton.off("click");
                                    patrolbutton.on("click", function () {
                                        patrolbutton.off("click");
                                        patrolbutton.disabled = true;
                                        patrolbutton.updateDisabled();
                                        cignorebutton.off("click");
                                        cignorebutton.disabled = true;
                                        cignorebutton.updateDisabled();
                                        $("#funpl-patroltool-header").text("Loading...");
                                        $("#funpl-patroltool-loading").css("display", "");
                                        $("#funpl-patroltool-desc").html('');
                                        $("#funpl-patroltool-diff").html('');
                                        $("#funpl-patroltool-preview").html('');
                                        mwApi.postWithToken("patrol", {
                                            "action": "patrol",
                                            "format": "json",
                                            "revid": compare.torevid
                                        }).done(function () {
                                            loadNextChange();
                                        }).catch(function (err) {
                                            if (err == notpatrollable) {
                                                alert("Failed to patrol edit due to it being not patrolable");
                                                loadNextChange();
                                            }
                                            else {
                                                patroltool_error(err);
                                            }
                                        });
                                    });
                                    cignorebutton.disabled = false;
                                    cignorebutton.updateDisabled();
                                    cignorebutton.off("click");
                                    cignorebutton.on("click", function () {
                                        patrolbutton.off("click");
                                        patrolbutton.disabled = true;
                                        patrolbutton.updateDisabled();
                                        cignorebutton.off("click");
                                        cignorebutton.disabled = true;
                                        cignorebutton.updateDisabled();
                                        loadNextChange();
                                    });
                                    $("#funpl-patroltool-loading").css("display", "none");
                                }).catch(patroltool_error);
                            }).catch(patroltool_error);
                        }
                        else {
                            console.log("[PatrolTool] Ignored compare for change " + i);
                            $("#funpl-patroltool-desc").html(`<table class="wikitable">
                            <tr><th></th><th>Previous change</th><th>This change</th></tr>
                            <tr>
                            <th>Page title</th>
                            <td>-</td>
                            <td><a target="_blank" href="/wiki/${encode(change.title)}">${change.title.encodeHTML()}</a></td>
                            </tr>
                            <tr>
                            <th>Editor</th>
                            <td>-</td>
                            <td><a target="_blank" href="/wiki/User:${encode(change.user)}">${change.user.encodeHTML()}</a> <a target="_blank" href="/wiki/User%20talk:${encode(change.user)}">(talk)</a></td>
                            </tr>
                            <tr>
                            <th>Edit summary</th>
                            <td>-</td>
                            <td>${change.parsedcomment}</td>
                            </tr>
                            <tr>
                            <th></th>
                            <td>-</td>
                            <td><a target="_blank" href="/wiki/${encode(change.title)}?oldid=${urlSafe(change.revid)}">View</a></td>
                            </tr>
                            <tr>
                            <th>Date</th>
                            <td>-</td>
                            <td>${new Date(change.timestamp).toLocaleString()}</td>
                            </tr>
                            <tr>
                            <th></th>
                            <td>-</td>
                            <td><a target="_blank" href="/wiki/${encode(change.title)}?action=edit&oldid=${urlSafe(change.revid)}">Edit</a></td>
                            </tr>
                            </table>`)
                            $("#funpl-patroltool-diff").html("No diff data available");
                            mwApi.get({
                                "action": "parse",
                                "format": "json",
                                "oldid": change.revid
                            }).done((parse) => {
                                console.log("[PatrolTool] parse", parse);
                                $("#funpl-patroltool-preview").html(parse.parse.text["*"]);
                                $("#funpl-patroltool-preview").append('<div id="#funpl-patroltool-categories" class="catlinks"></div>');
                                let cattext = "";
                                for (var cat of parse.parse.categories) {
                                    cattext += '<li><a href="/wiki/Category:' + encode(cat["*"]) + '">' + cat["*"].encodeHTML() + '</a></li>';
                                }
                                if (cattext != "") {
                                    $("#funpl-patroltool-categories").html("<b>Categories:</b> <ul>" + cattext + "</ul>");
                                }
                                patrolbutton.disabled = false;
                                patrolbutton.updateDisabled();
                                patrolbutton.off("click");
                                patrolbutton.on("click", function () {
                                    patrolbutton.off("click");
                                    patrolbutton.disabled = true;
                                    patrolbutton.updateDisabled();
                                    cignorebutton.off("click");
                                    cignorebutton.disabled = true;
                                    cignorebutton.updateDisabled();
                                    $("#funpl-patroltool-header").text("Loading...");
                                    $("#funpl-patroltool-loading").css("display", "");
                                    $("#funpl-patroltool-desc").html('');
                                    $("#funpl-patroltool-diff").html('');
                                    $("#funpl-patroltool-preview").html('');
                                    mwApi.postWithToken("patrol", {
                                        "action": "patrol",
                                        "format": "json",
                                        "revid": change.revid
                                    }).done(function () {
                                        loadNextChange();
                                    }).catch(function (err) {
                                        if (err == notpatrollable) {
                                            alert("Failed to patrol edit due to it being not patrolable");
                                            loadNextChange();
                                        }
                                        else {
                                            patroltool_error(err);
                                        }
                                    });
                                });
                                cignorebutton.disabled = false;
                                cignorebutton.updateDisabled();
                                cignorebutton.off("click");
                                cignorebutton.on("click", function () {
                                    patrolbutton.off("click");
                                    patrolbutton.disabled = true;
                                    patrolbutton.updateDisabled();
                                    cignorebutton.off("click");
                                    cignorebutton.disabled = true;
                                    cignorebutton.updateDisabled();
                                    loadNextChange();
                                });
                                $("#funpl-patroltool-loading").css("display", "none");
                            }).catch(patroltool_error);
                        }
                    }
                    else {
                        console.log("[PatrolTool] Change " + i + " is patrolled, skipping");
                        loadNextChange();
                    }
                }).catch(patroltool_error);
            }
            catch (ex) {
                patroltool_error(ex);
            }
        }
        window.loadChange = loadChange;
        if (!String.prototype.encodeHTML) { //https://stackoverflow.com/a/7918944
            String.prototype.encodeHTML = function () {
                return this.replace(/&/g, '&amp;')
                    .replace(/</g, '&lt;')
                    .replace(/>/g, '&gt;')
                    .replace(/"/g, '&quot;')
                    .replace(/'/g, '&apos;');
            };
        }

        if (!String.prototype.decodeHTML) { //https://stackoverflow.com/a/7918944
            String.prototype.decodeHTML = function () {
                return this.replace(/&apos;/g, "'")
                    .replace(/&quot;/g, '"')
                    .replace(/&gt;/g, '>')
                    .replace(/&lt;/g, '<')
                    .replace(/&amp;/g, '&');
            };
        }

        function encode(str) {
            return str.replace(/"/g, "\"")
            .replace(/\\/g, "\\\\");
        }

        function urlSafe(str) {
            return encode(encodeURIComponent(str));
        }
    }
    catch (err) {
        patroltool_error(err)
    }
})