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

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,            loadPreviewbutton = 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 You're also logged out, maybe you want to log in"); }       }).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', accessKey: 'd'                   });                    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(' ');                            $("#funpl-patroltool").append('Diff ');                            $("#funpl-patroltool").append(' ');                            patrolbutton = new OO.ui.ButtonWidget({ "label": "Mark as patrolled and continue", "icon": 'arrowNext', "disabled": true, "flags": ["primary", "progressive"], "accessKey":"d" });                           cignorebutton = new OO.ui.ButtonWidget({ "label": 'Ignore and continue', "icon": 'arrowNext', "disabled": true, "flags": ["progressive"], "accessKey":"s" });                           loadPreviewbutton = new OO.ui.ButtonWidget({ "label": 'Load preview', "icon": 'article', "disabled": true, "accessKey":"a" });                           var toplayout = new OO.ui.HorizontalLayout({ items: [ patrolbutton, cignorebutton, loadPreviewbutton ]                           });                            $("#funpl-patroltool").append(toplayout.$element);                            $("#funpl-patroltool").append('Page preview ');                            $("#funpl-patroltool").append(' ');                            loadNextChange;                        }) }).catch(patroltool_error).catch(no);               }                catch (ex) {                    patroltool_error(ex);                }            }); }       function loadNextChange { if (finalchanges[currentchange + 1] == null) { $("#funpl-patroltool-header").text("All done!"); $("#funpl-patroltool-loading").css("display", "none"); $("#funpl-patroltool-desc").html('You reached the end of the queue!\nIf you want to load new changes in, refresh this page'); $("#funpl-patroltool-diff-header").remove; $("#funpl-patroltool-diff").remove; $("#funpl-patroltool-preview-header").remove; $("#funpl-patroltool-preview").remove; }           else loadChange(currentchange + 1); }       function loadChange(i) { try { if (finalchanges[i] == null) { return patroltool_error("Change not found") }               $("#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(` `) $("#funpl-patroltool-diff").html(compare["*"]); }).catch(patroltool_error);                       }                        else {                            console.log("[PatrolTool] Ignored compare for change " + i);                            $("#funpl-patroltool-desc").html(` `)                            $("#funpl-patroltool-diff").html("No diff data available");                        }

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;                            loadPreviewbutton.disabled = true;                            loadPreviewbutton.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", "rcid": change.rcid }).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;                            loadPreviewbutton.disabled = true;                            loadPreviewbutton.updateDisabled;                            loadNextChange;                        }); loadPreviewbutton.disabled = false; loadPreviewbutton.updateDisabled; loadPreviewbutton.on("click", function {                            patrolbutton.disabled = true;                            patrolbutton.updateDisabled;                            cignorebutton.disabled = true;                            cignorebutton.updateDisabled;                            loadPreviewbutton.disabled = true;                            loadPreviewbutton.updateDisabled;                            loadPreview(currentchange);                            patrolbutton.disabled = false;                            patrolbutton.updateDisabled;                            cignorebutton.disabled = false;                            cignorebutton.updateDisabled;                        }); $("#funpl-patroltool-loading").css("display", "none"); }                   else { console.log("[PatrolTool] Change " + i + " is patrolled, skipping"); loadNextChange; }               }).catch(patroltool_error);            }            catch (ex) {                patroltool_error(ex);            }        }

function loadPreview(i) { $("#funpl-patroltool-loading").css("display", ""); var pchange = finalchanges[i]; mwApi.get({               "action": "parse",                "format": "json",                "oldid": pchange.revid            }).done((parse) => {                console.log("[PatrolTool] parse", parse);                $("#funpl-patroltool-preview").html(parse.parse.text["*"]);                $("#funpl-patroltool-preview").append(' ');                let cattext = "";                for (var cat of parse.parse.categories) {                    cattext += '' + cat["*"].replace(/_/g, " ").encodeHTML + '';                }                if (cattext != "") {                    $("#funpl-patroltool-categories").html("Categories:" + cattext + "");                }                $("#funpl-patroltool-loading").css("display", "none");            }).catch(function (err) {                if (err == "nosuchrevid") { $("#funpl-patroltool-preview").html("You can't preview this edit"); $("#funpl-patroltool-loading").css("display", "none"); }               else { patroltool_error(err); }           });        }

window.loadChange = loadChange; if (!String.prototype.encodeHTML) { //https://stackoverflow.com/a/7918944 String.prototype.encodeHTML = function { return this.replace(/&/g, '&amp;') .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) } })