User:Ed6767/sandbox.js

// #REDIRECT User:Ed6767 // // THE MAIN PAGE DOES NOT INCLUDE MATERIAL DESIGN LITE CSS. Include all the things here if needed. var wikiEditorStyle = ` .mdl-tooltip { -webkit-transform: scale(0); transform: scale(0); -webkit-transform-origin: top center; transform-origin: top center; z-index: 999; background: rgba(97, 97, 97, .9); border-radius: 2px; color: #fff; display: inline-block; font-size: 10px; font-weight: 500; line-height: 14px; max-width: 170px; position: fixed; top: -500px; left: -500px; padding: 8px; text-align: center }

.mdl-tooltip.is-active { -webkit-animation: pulse 200ms cubic-bezier(0, 0, .2, 1)forwards; animation: pulse 200ms cubic-bezier(0, 0, .2, 1)forwards }

.mdl-tooltip--large { line-height: 14px; font-size: 14px; padding: 16px }

@-webkit-keyframes pulse { 0% {       -webkit-transform: scale(0); transform: scale(0); opacity: 0 }

50% {       -webkit-transform: scale(.99); transform: scale(.99) }

100% {       -webkit-transform: scale(1); transform: scale(1); opacity: 1; visibility: visible } }

@keyframes pulse { 0% {       -webkit-transform: scale(0); transform: scale(0); opacity: 0 }

50% {       -webkit-transform: scale(.99); transform: scale(.99) }

100% {       -webkit-transform: scale(1); transform: scale(1); opacity: 1; visibility: visible } } .mdl-snackbar { position: fixed; bottom: 0; left: 50%; cursor: default; background-color: #323232; z-index: 3; display: block; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-justify-content: space-between; -ms-flex-pack: justify; justify-content: space-between; font-family: "Roboto", "Helvetica", "Arial", sans-serif; will-change: transform; -webkit-transform: translate(0, 80px); transform: translate(0, 80px); transition: transform .25s cubic-bezier(.4, 0, 1, 1); transition: transform .25s cubic-bezier(.4, 0, 1, 1), -webkit-transform .25s cubic-bezier(.4, 0, 1, 1); pointer-events: none }

@media (max-width:479px) { .mdl-snackbar { width: 100%; left: 0; min-height: 48px; max-height: 80px } }

@media (min-width:480px) { .mdl-snackbar { min-width: 288px; max-width: 568px; border-radius: 2px; -webkit-transform: translate(-50%, 80px); transform: translate(-50%, 80px) } }

.mdl-snackbar--active { -webkit-transform: translate(0, 0); transform: translate(0, 0); pointer-events: auto; transition: transform .25s cubic-bezier(0, 0, .2, 1); transition: transform .25s cubic-bezier(0, 0, .2, 1), -webkit-transform .25s cubic-bezier(0, 0, .2, 1) }

@media (min-width:480px) { .mdl-snackbar--active { -webkit-transform: translate(-50%, 0); transform: translate(-50%, 0) } }

.mdl-snackbar__text { padding: 14px 12px 14px 24px; vertical-align: middle; color: #fff; float: left }

.mdl-snackbar__action { background: 0 0; border: none; color: rgb(83, 109, 254); float: right; padding: 14px 24px 14px 12px; font-family: "Roboto", "Helvetica", "Arial", sans-serif; font-size: 14px; font-weight: 500; text-transform: uppercase; line-height: 1; letter-spacing: 0; overflow: hidden; outline: none; opacity: 0; pointer-events: none; cursor: pointer; text-decoration: none; text-align: center; -webkit-align-self: center; -ms-flex-item-align: center; -ms-grid-row-align: center; align-self: center }

.mdl-snackbar__action::-moz-focus-inner { border: 0 }

.mdl-snackbar__action:not([aria-hidden]) { opacity: 1; pointer-events: auto }

.mdl-dialog { border: none; box-shadow: 0 9px 46px 8px rgba(0, 0, 0, .14), 0 11px 15px -7px rgba(0, 0, 0, .12), 0 24px 38px 3px rgba(0, 0, 0, .2); }

.mdl-dialog__title { padding: 24px 24px 0; margin: 0; font-size: 2.5rem }

.mdl-dialog__actions { padding: 8px 8px 8px 24px; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-flex-direction: row-reverse; -ms-flex-direction: row-reverse; flex-direction: row-reverse; -webkit-flex-wrap: wrap; -ms-flex-wrap: wrap; flex-wrap: wrap }

.mdl-dialog__actions>* { margin-right: 8px; height: 36px }

.mdl-dialog__actions>*:first-child { margin-right: 0 }

.mdl-dialog__actions--full-width { padding: 0 0 8px }

.mdl-dialog__actions--full-width>* { height: 48px; -webkit-flex: 0 0 100%; -ms-flex: 0 0 100%; flex: 0 0 100%; padding-right: 16px; margin-right: 0; text-align: right }

.mdl-dialog__content { padding: 20px 24px 24px; color: rgba(0, 0, 0, .54) }

.mdl-button { background: 0 0; border: none; border-radius: 2px; color: #000; position: relative; height: 36px; margin: 0; min-width: 64px; padding: 0 16px; display: inline-block; font-family: "Roboto", "Helvetica", "Arial", sans-serif; font-size: 14px; font-weight: 500; text-transform: uppercase; letter-spacing: 0; overflow: hidden; will-change: box-shadow; transition: box-shadow .2s cubic-bezier(.4, 0, 1, 1), background-color .2s cubic-bezier(.4, 0, .2, 1), color .2s cubic-bezier(.4, 0, .2, 1); outline: none; cursor: pointer; text-decoration: none; text-align: center; line-height: 36px; vertical-align: middle }

.mdl-button::-moz-focus-inner { border: 0 }

.mdl-button:hover { background-color: rgba(158, 158, 158, .2) }

.mdl-button:focus:not(:active) { background-color: rgba(0, 0, 0, .12) }

.mdl-button:active { background-color: rgba(158, 158, 158, .4) }

.mdl-button.mdl-button--colored { color: rgb(33, 150, 243) }

.mdl-button.mdl-button--colored:focus:not(:active) { background-color: rgba(0, 0, 0, .12) }

input.mdl-button[type="submit"] { -webkit-appearance: none }

.mdl-button--raised { background: rgba(158, 158, 158, .2); box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12) }

.mdl-button--raised:active { box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2); background-color: rgba(158, 158, 158, .4) }

.mdl-button--raised:focus:not(:active) { box-shadow: 0 0 8px rgba(0, 0, 0, .18), 0 8px 16px rgba(0, 0, 0, .36); background-color: rgba(158, 158, 158, .4) }

.mdl-button--raised.mdl-button--colored { background: rgb(33, 150, 243); color: rgb(255, 255, 255) }

.mdl-button--raised.mdl-button--colored:hover { background-color: rgb(33, 150, 243) }

.mdl-button--raised.mdl-button--colored:active { background-color: rgb(33, 150, 243) }

.mdl-button--raised.mdl-button--colored:focus:not(:active) { background-color: rgb(33, 150, 243) }

.mdl-button--raised.mdl-button--colored .mdl-ripple { background: rgb(255, 255, 255) }

.mdl-button--fab { border-radius: 50%; font-size: 24px; height: 56px; margin: auto; min-width: 56px; width: 56px; padding: 0; overflow: hidden; background: rgba(158, 158, 158, .2); box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, .12), 0 1px 1px 0 rgba(0, 0, 0, .24); position: relative; line-height: normal }

.mdl-button--fab .material-icons { position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-12px, -12px); transform: translate(-12px, -12px); line-height: 24px; width: 24px }

.mdl-button--fab.mdl-button--mini-fab { height: 40px; min-width: 40px; width: 40px }

.mdl-button--fab .mdl-button__ripple-container { border-radius: 50%; -webkit-mask-image: -webkit-radial-gradient(circle, #fff, #000) }

.mdl-button--fab:active { box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2); background-color: rgba(158, 158, 158, .4) }

.mdl-button--fab:focus:not(:active) { box-shadow: 0 0 8px rgba(0, 0, 0, .18), 0 8px 16px rgba(0, 0, 0, .36); background-color: rgba(158, 158, 158, .4) }

.mdl-button--fab.mdl-button--colored { background: rgb(83, 109, 254); color: rgb(255, 255, 255) }

.mdl-button--fab.mdl-button--colored:hover { background-color: rgb(83, 109, 254) }

.mdl-button--fab.mdl-button--colored:focus:not(:active) { background-color: rgb(83, 109, 254) }

.mdl-button--fab.mdl-button--colored:active { background-color: rgb(83, 109, 254) }

.mdl-button--fab.mdl-button--colored .mdl-ripple { background: rgb(255, 255, 255) }

.mdl-button--icon { border-radius: 50%; font-size: 24px; height: 32px; margin-left: 0; margin-right: 0; min-width: 32px; width: 32px; padding: 0; overflow: hidden; color: inherit; line-height: normal }

.mdl-button--icon .material-icons { position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-12px, -12px); transform: translate(-12px, -12px); line-height: 24px; width: 24px }

.mdl-button--icon.mdl-button--mini-icon { height: 24px; min-width: 24px; width: 24px }

.mdl-button--icon.mdl-button--mini-icon .material-icons { top: 0; left: 0 }

.mdl-button--icon .mdl-button__ripple-container { border-radius: 50%; -webkit-mask-image: -webkit-radial-gradient(circle, #fff, #000) }

.mdl-button__ripple-container { display: block; height: 100%; left: 0; position: absolute; top: 0; width: 100%; z-index: 0; overflow: hidden }

.mdl-button[disabled] .mdl-button__ripple-container .mdl-ripple, .mdl-button.mdl-button--disabled .mdl-button__ripple-container .mdl-ripple { background-color: transparent }

.mdl-button--primary.mdl-button--primary { color: rgb(33, 150, 243) }

.mdl-button--primary.mdl-button--primary .mdl-ripple { background: rgb(255, 255, 255) }

.mdl-button--primary.mdl-button--primary.mdl-button--raised, .mdl-button--primary.mdl-button--primary.mdl-button--fab { color: rgb(255, 255, 255); background-color: rgb(33, 150, 243) }

.mdl-button--accent.mdl-button--accent { color: rgb(83, 109, 254) }

.mdl-button--accent.mdl-button--accent .mdl-ripple { background: rgb(255, 255, 255) }

.mdl-button--accent.mdl-button--accent.mdl-button--raised, .mdl-button--accent.mdl-button--accent.mdl-button--fab { color: rgb(255, 255, 255); background-color: rgb(83, 109, 254) }

.mdl-button[disabled][disabled], .mdl-button.mdl-button--disabled.mdl-button--disabled { color: rgba(0, 0, 0, .26); cursor: default; background-color: transparent }

.mdl-button--fab[disabled][disabled], .mdl-button--fab.mdl-button--disabled.mdl-button--disabled { background-color: rgba(0, 0, 0, .12); color: rgba(0, 0, 0, .26) }

.mdl-button--raised[disabled][disabled], .mdl-button--raised.mdl-button--disabled.mdl-button--disabled { background-color: rgba(0, 0, 0, .12); color: rgba(0, 0, 0, .26); box-shadow: none }

.mdl-button--colored[disabled][disabled], .mdl-button--colored.mdl-button--disabled.mdl-button--disabled { color: rgba(0, 0, 0, .26) }

.mdl-button .material-icons { vertical-align: middle }

`; // (c) Ed.E 2020

function waitForMDLLoad(cb) { // Used to wait for MDL load if(typeof componentHandler !== "undefined"){ cb; // callback } else { setTimeout(=>waitForMDLLoad(cb), 250); } }

function redirect(url, inNewTab) { if (inNewTab) { Object.assign(document.createElement('a'), { target: '_blank', href: url}).click; // Open in new tab } else { window.location.href = url; // open here } }

var wikiEditor = { "version" : "rev6final", // don't forget to change each version! "sign": =>{return atob("fn5+fg==")}, // we have to do this because mediawiki will swap this out with devs sig. "welcome": => {return atob("e3tzdWJzdDpXZWxjb21lfX0=");}, "visuals" : { "init" : (callback) => { // Welcome message console.log(` +--+ +--+           `); // Load MDL and everything needed, then callback when all loaded $('head').append(`                                                                                                                   /* Context menus */                .context-menu-list {                    list-style-type: none;                    list-style-image: none;                }
 * RedWarn (c) 2020 Ed E       |
 * and contributors            |
 * and contributors            |

/* MDL */ `+ wikiEditorStyle +` `); // Append required libaries to page           // wait for load            waitForMDLLoad(callback);        },

"register" : function(c) { // Register a componant with MDL componentHandler.upgradeElement(c); },

"pageIcons" : => { try { /* DO NOT REMOVE THIS LINE */

if (mw.config.get("wgRelevantPageName").includes("User:") || mw.config.get("wgRelevantPageName").includes("User_talk:")) { document.getElementsByClassName("mw-indicators mw-body-content")[0].innerHTML += ` send New Message

sentiment_satisfied_alt Quick Welcome

report Send Notice

gavel Report to Admin `; } // end this section document.getElementsByClassName("mw-indicators mw-body-content")[0].innerHTML += `

{});">watch_later Latest revision settings RedWarn Preferences `;

/* DO NOT REMOVE THIS LINE */ } catch (error) { // Likely invalid theme dialogEngine.create(`               Sorry                 RedWarn isn't compatible with this theme. Please revert to a compatible theme to continue using RedWarn.                 Go to Theme Preferences                 Close`).showModal; return; // Exit }

// Now register all icons for (let item of document.getElementsByClassName("mdl-tooltip")) { wikiEditor.visuals.register(item); }           // That's done :)        }    },    "alerts" : {        "accountNotPermitted" :  => {            // BEHAVIOR            // Shows toast for 15 seconds, shows dialog on click            wikiEditor.visuals.toast.show(` To prevent vandalism, you cannot use this tool until you are a confirmed user. Come back later. `, false, false, 15000);       }    },

"recentChanges" : { "openPage" : (filters)=> { // Open recent changes url let sidebarSize = 500; let addCol = "0,255,0"; // rbg let rmCol = "255,0,0"; // rgb if (wikiEditor.config.ptrSidebar) sidebarSize = wikiEditor.config.ptrSidebar; // If preferences set, apply them if (wikiEditor.config.ptrAddCol) addCol = wikiEditor.config.ptrAddCol; if (wikiEditor.config.ptrRmCol) rmCol = wikiEditor.config.ptrRmCol; let url = URL.createObjectURL(new Blob([mdlContainers.generateHtml(`           <!DOCTYPE HTML>        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js">         <link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">        <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">        <script defer src="https://code.getmdl.io/1.3.0/material.min.js">         <link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.blue-indigo.min.css" />    <body onload="refreshLive;">             <div class="mdl-layout__drawer" style="width:`+ sidebarSize +`px">            RedWarn Recent Changes Patrol             <nav class="mdl-navigation">                <a class="mdl-navigation__link" href="https://en.wikipedia.org/wiki/Special:RecentChanges">Return to Wikipedia / Change filter options</a> <a class="mdl-navigation__link" href="#" style="background-color: teal;color:white;" onmouseover="tI = setInterval(refreshLive, 750);" onmouseout="clearTimeout(tI);">Hover your cursor here for live updates</a> <main class="mdl-layout__content">

<div id="welcomeContainer" style="padding-left: `+ (sidebarSize - 220) +`;padding-top: calc(5% - 60px);padding-right:5%;"> Welcome to RedWarn Patrol! To the left, you can see a list of recent changes. To view the latest revision of the article that was changed, simply click it on the left. The stronger the colour, the more the amount of content that has been changed. By default, red means a change that made the page smaller, and green as an edit that made the page bigger. You can change these colours in your preferences. For full instructions, refer to the user guide.

<div id="loadingContainer" style="display: none;padding-left: `+ (sidebarSize - 240) +`;text-align: center;padding-top: calc(10% - 60px);">

<iframe src="about:blank" style="display: none; height:100%; width: calc(100% - `+ (sidebarSize - 250) +`px);padding-left: `+ (sidebarSize - 250) +`;">

var tI; function convertRange( value, r1, r2 ) { return ( value - r1[ 0 ] ) * ( r2[ 1 ] - r2[ 0 ] ) / ( r1[ 1 ] - r1[ 0 ] ) + r2[ 0 ]; } // Check for new updates every 750ms function refreshLive { // Don't use JSON API so that the vars are interchangable from Special:RecentChanges parseRecentChanges(arr=>{       arr.forEach(edit => { console.log(edit); // Clear excess if ($('a[id^="recentChange"]').length > 50) { // Max 50, delete bottom $('a[id^="recentChange"]').last.remove; // remove the last one }           // Add new if ($("#recentChange-"+ edit.revID).length < 1) { // Only continue if edit not already in page let sizeDiff = edit.changeSize; let opacityLevel = 0; if ((sizeDiff > 1000) || (sizeDiff < -1000)) { // Max opacity opacityLevel = 1; } else { // We can map if (sizeDiff < 0) { // Red map opacityLevel = convertRange(sizeDiff, [0, -1000], [0.1, 0.75]); } else { // Green map opacityLevel = convertRange(sizeDiff, [0, 1000], [0.1, 0.75]); }               }                let style = (sizeDiff < 0) ? "background-color: rgba(`+ rmCol +`,"+ opacityLevel +"); color:black;" : "background-color: rgba(`+ addCol +`,"+ opacityLevel +"); color:black;" // First neg style, next add style $("#recentChangesContainer").prepend('<a class="mdl-navigation__link notif" href="#" onclick="goToLatestDiffPage(\\\''+ edit.title +'\\\')" style="display:none;'+ style +'" id="recentChange-'+ edit.revID +'"><i id="title-'+ edit.revID +'"></i> '+ edit.user +' ('+ sizeDiff +') <span id="comment-'+ edit.revID +'"> '+ edit.tags +'</a>'); $('#title-'+ edit.revID).text(edit.title); // XSS security $('#comment-'+ edit.revID).text(edit.comment); $("#recentChange-"+ edit.revID).fadeIn; // fancy }       });    }); }

function goToLatestDiffPage(article) { $("#welcomeContainer").hide; $("iframe").hide; $("#loadingContainer").show;

$("iframe").on("load", =>{       // Page loaded handke        $("#welcomeContainer").hide;        $("iframe").show;        $("#loadingContainer").hide;    }); // Nav to latest diff page $.getJSON("https://en.wikipedia.org/w/api.php?action=query&prop=revisions&titles="+ encodeURIComponent(article) +"&rvslots=*&rvprop=ids%7Cuser&formatversion=2&format=json", r=>{           // We got the response            let latestRId = r.query.pages[0].revisions[0].revid;            let parentRId = r.query.pages[0].revisions[0].parentid;            // Load the preview page of the latest one            $("iframe").attr("src", "https://en.wikipedia.org/w/index.php?title="+ encodeURIComponent(name) +"&diff="+ latestRId +"&oldid="+ parentRId +"&diffmode=source");    }); }

function parseRecentChanges(callback) { // USING HTML API for one reason // 1. works easily with Special:RecentChanges filters $.get("https://en.wikipedia.org/wiki/Special:RecentChanges?`+ filters +`&action=render&enhanced=0", r=>{       $("body").append(" "); // create temp div        $("#toDelete").html(r);        let _ = $("#toDelete").find("ul").find("li");        let arr = [];        let recentChanges = _.each(i=> { let el = _[i]; let revId = $(el).attr("data-mw-revid"); // get revision ID           let changeSize = $(el).find(".mw-diff-bytes").text; // get size (+123) let changeTitle = $(el).find(".mw-changeslist-title").text; // get title of page let changeUsername = $(el).find(".mw-userlink").text; // get username of changer let tags = $(el).find(".mw-tag-markers").text; // get tags (mobile edit ext) let comment = $(el).find(".comment").text; // get comment if (!isNaN(parseInt(changeSize))) { // Valid arr[i] = { "revID": revId, "changeSize": parseInt(changeSize), "tags": tags, "user": changeUsername, "title": changeTitle, "comment": comment }; // append data to the array }       });

$("toDelete").remove; // dispose unneeded callback(arr); // we done }); }

`)], { type: 'text/html' })); // blob url           redirect(url, false);        },        "diffLinkAddRedWarn" :  => { // add redwarn to recent changes page            $('body').unbind('DOMSubtreeModified'); // Prevent infinite loop            $.each($(".mw-changeslist-diff"), (i,el)=>{ if ($(el).parent.html.includes("#redwarn")) { // Link already there. } else { $(el).parent.prepend(`<a href='#redwarn' onclick='wikiEditor.ui.revisionBrowser("`+ el.href +`");'>Redwarn</a> | `); }           });            window.addEventListener("focus", e=>{ wikiEditor.recentChanges.bindRecentChanges; // fix chrome unfocus bug }, false);           wikiEditor.recentChanges.bindRecentChanges;        },

"bindRecentChanges" : => { // on list change add redwarn $('body').on('DOMSubtreeModified', 'ul.special', =>wikiEditor.recentChanges.diffLinkAddRedWarn); }   } };

var messageHandlers = {"testHandler": => {alert("Working!");}};

function addMessageHandler(msg, callback) { // calling more than once will just overwrite Object.assign(messageHandlers, ((a,b)=>{let _ = {}; _[a]=b; return _;})(msg, callback)); // function ab returns a good formatted obj }

window.onmessage = function(e){ if (messageHandlers[e.data]){messageHandlers[e.data];} // Excecute handler if exact else { // We find ones that contain for (const evnt in messageHandlers) { if ((evnt.substr(evnt.length - 1) == "*") && e.data.includes(evnt.substr(0, evnt.length - 2))) { // and includes w * chopped off messageHandlers[evnt](e.data); return; } // if contains and ends with wildcard then we do it       } } };

// init everthing function initwikiEdit { wikiEditor.visuals.init(=>{       wikiEditor.visuals.toast.init;        dialogEngine.init;        wikiEditor.visuals.pageIcons;        wikiEditor.ui.registerContextMenu; // register context menus

// Quick check we have perms to use (in confirmed/autoconfirmed group) wikiEditor.info.featureRestrictPermissionLevel("confirmed", false, =>{           // We don't have permission            // Add red lock to the top right to show that RedWarn cannot be used            document.getElementsByClassName("mw-indicators mw-body-content")[0].innerHTML = `             lock                  You don't have permission to use RedWarn yet. Please refer to the user guide for more information.            `;            // Now register that            for (let item of document.getElementsByClassName("mdl-tooltip")) {                wikiEditor.visuals.register(item);             }            wikiEditor = {}; // WIPE OUT ENTIRE CLASS. We're not doing anything here.            // Notification            mw.notify("Thank you for you interest in moderating Wikipedia. However, you do not have permission to use RedWarn. Please refer to the user guide for more information."); // That's it       });

// We have perms, let's continue.

// Load config and check if updated wikiEditor.info.getConfig(=> {           if (wikiEditor.config.lastVersion != wikiEditor.version) {                // We've had an update                wikiEditor.config.lastVersion = wikiEditor.version; // update entry                 wikiEditor.info.writeConfig(true, => { // update the config file // Push an update toast wikiEditor.visuals.toast.show("RedWiki has been updated!", "MORE",                   =>redirect("https://en.wikipedia.org/wiki/User:Ed6767/redwarn/bugsquasher", true), 7500); });           }        });

// Check if a message is in URL (i.e edit complete ext) if(window.location.hash.includes("#noticeApplied-")) { // Show toast w undo edit capabilities // #noticeApplied-currentEdit-pastEdit wikiEditor.visuals.toast.show("Message saved", "UNDO", =>{               // Redirect to undo page mw.config.get("wgRelevantPageName");                // TODO: maybe replace with custom page in future?                 window.location.href = "/w/index.php?title="+ mw.config.get("wgRelevantPageName") +"&action=edit&undoafter="+ window.location.hash.split("-")[2] +"&undo="+ window.location.hash.split("-")[1];            }, 7500); } else if (window.location.hash.includes("#redirectLatestRevision")) { wikiEditor.visuals.toast.show("Redirected to the lastest revision."); } else if (window.location.hash.includes("#configChange")) { wikiEditor.visuals.toast.show("Preferences saved."); } else if (window.location.hash.includes("#compLatest")) { // Go to the latest revison wikiEditor.info.isLatestRevision(mw.config.get("wgRelevantPageName"), 0, =>{}); // auto filters and redirects for us - 0 is an ID that will never be       } else if (window.location.hash.includes("#rollbackPreview")) { // Rollback preview iframe. NEEDS WORK. DON'T FORGET TO SET common.js back!!! $('.mw-revslider-container').html(`           #mw-navigation {                display: none;            }

.mw-indicators { display:none; }

.mw-body {margin-left:0;}

.noprint { display: none; } .diff-ntitle {display: none; } .diff-otitle {display: none; } This is a rollback preview <a href="#" onclick="window.parent.parent.postMessage('closeDialog');">Click here</a> or the cross in the top-right corner to close this preview

// We're ready window.parent.parent.postMessage('showBrwsrDialog');

`);

$('.mw-revslider-container').attr("style", "border: 3px solid red;");

} else if (window.location.hash.includes("#rollbackFailNoRev")) { wikiEditor.visuals.toast.show("Could not rollback as there were no recent revisions by other users. Use the history page to try and manually revert.", false, false, 15000); }       if (window.location.href.includes("&diff=") && window.location.href.includes("&oldid=")) { // Diff page wikiEditor.rollback.loadIcons; // load rollback icons } else if (window.location.href.includes("/wiki/Special:RecentChanges")) { // Recent changes page // Add redwarn btn $(".mw-rcfilters-ui-filterWrapperWidget-bottom").prepend(`           <span style="cursor: pointer;" onclick="wikiEditor.recentChanges.openPage(window.location.search.substr(1));">how_to_reg                  Launch RedWarn Patrol with these filters            `); // Register tooltip for (let item of document.getElementsByClassName("mdl-tooltip")) { wikiEditor.visuals.register(item); }

wikiEditor.recentChanges.diffLinkAddRedWarn; // Add redwarn to all links }   }); } var dialogEngine = {    "init" : function{        $("body").append(` `);       // Add events        addMessageHandler("closeDialog", =>{dialogEngine.dialog.close;}); // closing    },    "create" : (content, noPad)=>{         $("#dialogEngineContainer").html(` <dialog class="mdl-dialog"> `+ content +` `);

dialogEngine.dialog = document.querySelector('dialog');

if (noPad) $("dialog").attr("style", "padding:inherit;"); // if no padding requested

// Firefox issue fix if (! dialogEngine.dialog.showModal) { dialogPolyfill.registerDialog(dialogEngine.dialog); }       return dialogEngine.dialog; } } /* (c) Ed E 2020

NOTICE: All cross-domain addresses in containers MUST BE ABSOLUTE (i.e https:// rather than //) var mdlContainers = { "generateHtml" : innerContent => { let content = ` <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"> <link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet"> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"> <script defer src="https://code.getmdl.io/1.3.0/material.min.js"> `;

// Themes let theme = ""; if (wikiEditor.config.colTheme){ theme = wikiEditor.config.colTheme; } else { theme = "blue-indigo"; // default theme }       content += ` <link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.`+ theme +`.min.css" /> .getmdl-select{outline:none}.getmdl-select .mdl-textfield__input{cursor:pointer}.getmdl-select .selected{background-color:#ddd}.getmdl-select .mdl-icon-toggle__label{float:right;margin-top:-30px;color:rgba(0,0,0,0.4);transform:rotate(0);transition:transform 0.3s}.getmdl-select.is-focused .mdl-icon-toggle__label{color:#3f51b5;transform:rotate(180deg)}.getmdl-select .mdl-menu__container{width:100% !important;margin-top:2px}.getmdl-select .mdl-menu__container .mdl-menu{width:100%}.getmdl-select .mdl-menu__container .mdl-menu .mdl-menu__item{font-size:16px}.getmdl-select__fix-height .mdl-menu__container .mdl-menu{overflow-y:auto;max-height:288px !important}.getmdl-select__fix-height .mdl-menu.mdl-menu--top-left{bottom:auto;top:0} "use strict";!function{function e{getmdlSelect.init(".getmdl-select")}window.addEventListener?window.addEventListener("load",e,!1):window.attachEvent&&window.attachEvent("onload",e)};var getmdlSelect={_defaultValue:{width:300},_addEventListeners:function(e){var t=e.querySelector("input"),n=e.querySelector('input[type="hidden"]'),l=e.querySelectorAll("li"),a=e.querySelector(".mdl-js-menu"),o=e.querySelector(".mdl-icon-toggle__label"),i="",c="",s="",u=!1,d=function(o){var i=o.textContent.trim;if(t.value=i,l.forEach(function(e){e.classList.remove("selected")}),o.classList.add("selected"),e.MaterialTextfield.change(i),setTimeout(function{e.MaterialTextfield.updateClasses_},250),n.value=o.dataset.val||"",c=t.value,s=n.value,"createEvent"in document){var u=document.createEvent("HTMLEvents");u.initEvent("change",!1,!0),a.MaterialMenu.hide,t.dispatchEvent(u)}else t.fireEvent("onchange")},r=function{u=!1,t.value=c,n.value=s,e.querySelector(".mdl-menu__container").classList.contains("is-visible")||e.classList.remove("is-focused");var l=document.querySelectorAll(".getmdl-select .mdl-js-menu");[].forEach.call(l,function(e){e.MaterialMenu.hide});var o=new Event("closeSelect");a.dispatchEvent(o)};document.body.addEventListener("click",r,!1),e.onkeydown=function(l){9==l.keyCode&&(t.value=c,n.value=s,a.MaterialMenu.hide,e.classList.remove("is-focused"))},t.onfocus=function(e){a.MaterialMenu.show,a.focus,u=!0},t.onblur=function(e){e.stopPropagation},t.onclick=function(t){t.stopPropagation,a.classList.contains("is-visible")?(a.MaterialMenu.hide,u=!1):(a.MaterialMenu.show,r,e.classList.add("is-focused"),u=!0)},t.onkeydown=function(l){27==l.keyCode&&(t.value=c,n.value=s,a.MaterialMenu.hide,e.MaterialTextfield.onBlur_,""!==i&&(e.querySelector(".mdl-textfield__label").textContent=i,i=""))},a.addEventListener("closeSelect",function(l){t.value=c,n.value=s,e.classList.remove("is-focused"),""!==i&&(e.querySelector(".mdl-textfield__label").textContent=i,i="")}),a.onkeydown=function(l){27==l.keyCode&&(t.value=c,n.value=s,e.classList.remove("is-focused"),""!==i&&(e.querySelector(".mdl-textfield__label").textContent=i,i=""))},o&&(o.onclick=function(l){l.stopPropagation,u?(a.MaterialMenu.hide,u=!1,e.classList.remove("is-focused"),e.MaterialTextfield.onBlur_,t.value=c,n.value=s):(r,e.MaterialTextfield.onFocus_,t.focus,a.MaterialMenu.show,u=!0)}),[].forEach.call(l,function(n){n.onfocus=function{e.classList.add("is-focused");var l=n.textContent.trim;t.value=l,e.classList.contains("mdl-textfield--floating-label")||""!=i||(i=e.querySelector(".mdl-textfield__label").textContent.trim,e.querySelector(".mdl-textfield__label").textContent="")},n.onclick=function{d(n)},n.dataset.selected&&d(n)})},init:function(e){var t=document.querySelectorAll(e);[].forEach.call(t,function(e){getmdlSelect._addEventListeners(e),componentHandler.upgradeElement(e),componentHandler.upgradeElement(e.querySelector("ul"))})}}; `+innerContent+` `;       return content; // return },

"generateContainer" : function(innerContent, width, height) { let url = URL.createObjectURL(new Blob([mdlContainers.generateHtml(innerContent)], { type: 'text/html' })); // blob url return `<iframe width="`+width+`" height="`+height+`" src="`+ url + `" frameborder="0" scrolling="no"> `; } } // Data processed from Twinkle Source at https://github.com/azatoth/twinkle var rules = [ {       "name": "Vandalism", "catagory": "Common warnings", "template": "uw-vandalism", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Disruptive editing", "catagory": "Common warnings", "template": "uw-disruptive", "warningLevels": [ 1,           2,            3        ]    },    {        "name": "Editing tests", "catagory": "Common warnings", "template": "uw-test", "warningLevels": [ 1,           2,            3        ]    },    {        "name": "Removal of content, blanking", "catagory": "Common warnings", "template": "uw-delete", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Generic warning (for template series missing level 4)", "catagory": "Common warnings", "template": "uw-generic", "warningLevels": [ 4       ]    },    {        "name": "Adding unreferenced defamatory information about living persons", "catagory": "Behavior in articles", "template": "uw-biog", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Addition of defamatory content", "catagory": "Behavior in articles", "template": "uw-defamatory", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Introducing deliberate factual errors", "catagory": "Behavior in articles", "template": "uw-error", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Frequent or mass changes to genres without consensus or reference", "catagory": "Behavior in articles", "template": "uw-genre", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Image-related vandalism", "catagory": "Behavior in articles", "template": "uw-image", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Using improper humor", "catagory": "Behavior in articles", "template": "uw-joke", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Adding original research, including unpublished syntheses of sources", "catagory": "Behavior in articles", "template": "uw-nor", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Censorship of material", "catagory": "Behavior in articles", "template": "uw-notcensored", "warningLevels": [ 1,           2,            3        ]    },    {        "name": "Ownership of articles", "catagory": "Behavior in articles", "template": "uw-own", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Removal of maintenance templates", "catagory": "Behavior in articles", "template": "uw-tdel", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Addition of unsourced or improperly cited material", "catagory": "Behavior in articles", "template": "uw-unsourced", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Using Wikipedia for advertising or promotion", "catagory": "Promotions and spam", "template": "uw-advert", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Not adhering to neutral point of view", "catagory": "Promotions and spam", "template": "uw-npov", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Paid editing without disclosure under the Wikimedia Terms of Use", "catagory": "Promotions and spam", "template": "uw-paid", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Adding spam links", "catagory": "Promotions and spam", "template": "uw-spam", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Not assuming good faith", "catagory": "Behavior towards other editors", "template": "uw-agf", "warningLevels": [ 1,           2,            3        ]    },    {        "name": "Harassment of other users", "catagory": "Behavior towards other editors", "template": "uw-harass", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Personal attack directed at a specific editor", "catagory": "Behavior towards other editors", "template": "uw-npa", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Improper use of warning or blocking template", "catagory": "Behavior towards other editors", "template": "uw-tempabuse", "warningLevels": [ 1,           2        ]    },    {        "name": "Removing  templates", "catagory": "Removal of deletion tags", "template": "uw-afd", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Removing  templates", "catagory": "Removal of deletion tags", "template": "uw-blpprod", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Removing file deletion tags", "catagory": "Removal of deletion tags", "template": "uw-idt", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Removing speedy deletion tags", "catagory": "Removal of deletion tags", "template": "uw-speedy", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Triggering the edit filter", "catagory": "Other", "template": "uw-attempt", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Using talk page as forum", "catagory": "Other", "template": "uw-chat", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Creating inappropriate pages", "catagory": "Other", "template": "uw-create", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Manual of style", "catagory": "Other", "template": "uw-mos", "warningLevels": [ 1,           2,            3,            4        ]    },    {        "name": "Page moves against naming conventions or consensus", "catagory": "Other", "template": "uw-move", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Refactoring others' talk page comments", "catagory": "Other", "template": "uw-tpv", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Uploading unencyclopedic images", "catagory": "Other", "template": "uw-upload", "warningLevels": [ 1,           2,            3,            4,            5        ]    },    {        "name": "Bad AIV report", "catagory": "Single Notice", "template": "uw-aiv", "warningLevels": [ 0       ]    },    {        "name": "Creating autobiographies", "catagory": "Single Notice", "template": "uw-autobiography", "warningLevels": [ 0       ]    },    {        "name": "Adding incorrect categories", "catagory": "Single Notice", "template": "uw-badcat", "warningLevels": [ 0       ]    },    {        "name": "Adding inappropriate entries to lists", "catagory": "Single Notice", "template": "uw-badlistentry", "warningLevels": [ 0       ]    },    {        "name": "Being harsh to newcomers", "catagory": "Single Notice", "template": "uw-bite", "warningLevels": [ 0       ]    },    {        "name": "Conflict of interest", "catagory": "Single Notice", "template": "uw-coi", "warningLevels": [ 0       ]    },    {        "name": "Introducing controversial material", "catagory": "Single Notice", "template": "uw-controversial", "warningLevels": [ 0       ]    },    {        "name": "Copying text to another page", "catagory": "Single Notice", "template": "uw-copying", "warningLevels": [ 0       ]    },    {        "name": "Adding speculative or unconfirmed information", "catagory": "Single Notice", "template": "uw-crystal", "warningLevels": [ 0       ]    },    {        "name": "Cut and paste moves", "catagory": "Single Notice", "template": "uw-c&pmove", "warningLevels": [ 0       ]    },    {        "name": "Incorrect edit to a disambiguation page", "catagory": "Single Notice", "template": "uw-dab", "warningLevels": [ 0       ]    },    {        "name": "Unnecessarily changing date formats", "catagory": "Single Notice", "template": "uw-date", "warningLevels": [ 0       ]    },    {        "name": "Removing proper sources containing dead links", "catagory": "Single Notice", "template": "uw-deadlink", "warningLevels": [ 0       ]    },    {        "name": "User should draft in userspace without the risk of speedy deletion", "catagory": "Single Notice", "template": "uw-draftfirst", "warningLevels": [ 0       ]    },    {        "name": "Not using edit summary", "catagory": "Single Notice", "template": "uw-editsummary", "warningLevels": [ 0       ]    },    {        "name": "Adding external links to the body of an article", "catagory": "Single Notice", "template": "uw-elinbody", "warningLevels": [ 0       ]    },    {        "name": "Not communicating in English", "catagory": "Single Notice", "template": "uw-english", "warningLevels": [ 0       ]    },    {        "name": "Hasty addition of speedy deletion tags", "catagory": "Single Notice", "template": "uw-hasty", "warningLevels": [ 0       ]    },    {        "name": "Italicize books, films, albums, magazines, TV series, etc within articles", "catagory": "Single Notice", "template": "uw-italicize", "warningLevels": [ 0       ]    },    {        "name": "Unnecessarily changing between British and American English", "catagory": "Single Notice", "template": "uw-lang", "warningLevels": [ 0       ]    },    {        "name": "Excessive addition of redlinks or repeated blue links", "catagory": "Single Notice", "template": "uw-linking", "warningLevels": [ 0       ]    },    {        "name": "Incorrect use of minor edits check box", "catagory": "Single Notice", "template": "uw-minor", "warningLevels": [ 0       ]    },    {        "name": "Creating non-English articles", "catagory": "Single Notice", "template": "uw-notenglish", "warningLevels": [ 0       ]    },    {        "name": "We use consensus, not voting", "catagory": "Single Notice", "template": "uw-notvote", "warningLevels": [ 0       ]    },    {        "name": "Copying from public domain sources without attribution", "catagory": "Single Notice", "template": "uw-plagiarism", "warningLevels": [ 0       ]    },    {        "name": "Use preview button to avoid mistakes", "catagory": "Single Notice", "template": "uw-preview", "warningLevels": [ 0       ]    },    {        "name": "Indiscriminate removal of redlinks", "catagory": "Single Notice", "template": "uw-redlink", "warningLevels": [ 0       ]    },    {        "name": "Reverting self tests", "catagory": "Single Notice", "template": "uw-selfrevert", "warningLevels": [ 0       ]    },    {        "name": "Wikipedia is not a social network", "catagory": "Single Notice", "template": "uw-socialnetwork", "warningLevels": [ 0       ]    },    {        "name": "Be bold and fix things yourself", "catagory": "Single Notice", "template": "uw-sofixit", "warningLevels": [ 0       ]    },    {        "name": "Adding spoiler alerts or removing spoilers from appropriate sections", "catagory": "Single Notice", "template": "uw-spoiler", "warningLevels": [ 0       ]    },    {        "name": "Talk in article", "catagory": "Single Notice", "template": "uw-talkinarticle", "warningLevels": [ 0       ]    },    {        "name": "Not signing posts", "catagory": "Single Notice", "template": "uw-tilde", "warningLevels": [ 0       ]    },    {        "name": "Posting at the top of talk pages", "catagory": "Single Notice", "template": "uw-toppost", "warningLevels": [ 0       ]    },    {        "name": "Stale userspace draft", "catagory": "Single Notice", "template": "uw-userspace draft finish", "warningLevels": [ 0       ]    },    {        "name": "Adding video game walkthroughs, cheats or instructions", "catagory": "Single Notice", "template": "uw-vgscope", "warningLevels": [ 0       ]    },    {        "name": "Place user warning templates when reverting vandalism", "catagory": "Single Notice", "template": "uw-warn", "warningLevels": [ 0       ]    },    {        "name": "Using inaccurate or inappropriate edit summaries", "catagory": "Single Notice", "template": "uw-wrongsummary", "warningLevels": [ 0       ]    },    {        "name": "Potential three-revert rule violation; see also uw-ew", "catagory": "Single Warning", "template": "uw-3rr", "warningLevels": [ 6       ]    },    {        "name": "Affiliate marketing", "catagory": "Single Warning", "template": "uw-affiliate", "warningLevels": [ 6       ]    },    {        "name": "Use of multiple accounts (assuming good faith)", "catagory": "Single Warning", "template": "uw-agf-sock", "warningLevels": [ 6       ]    },    {        "name": "Creating attack pages", "catagory": "Single Warning", "template": "uw-attack", "warningLevels": [ 6       ]    },    {        "name": "Business promotion", "catagory": "Single Warning", "template": "uw-bizlist", "warningLevels": [ 6       ]    },    {        "name": "Bot username", "catagory": "Single Warning", "template": "uw-botun", "warningLevels": [ 6       ],        "note" : "Username notices should not be added for blatent violations. In these cases, click the gavel to report the username to the admins." },   {        "name": "Canvassing", "catagory": "Single Warning", "template": "uw-canvass", "warningLevels": [ 6       ]    },    {        "name": "Copyright violation", "catagory": "Single Warning", "template": "uw-copyright", "warningLevels": [ 6       ]    },    {        "name": "Linking to copyrighted works violation", "catagory": "Single Warning", "template": "uw-copyright-link", "warningLevels": [ 6       ]    },    {        "name": "Copyright violation (with explanation for new users)", "catagory": "Single Warning", "template": "uw-copyright-new", "warningLevels": [ 6       ]    },    {        "name": "Removing  template from articles", "catagory": "Single Warning", "template": "uw-copyright-remove", "warningLevels": [ 6       ]    },    {        "name": "Edit summary triggering the edit filter", "catagory": "Single Warning", "template": "uw-efsummary", "warningLevels": [ 6       ]    },    {        "name": "Edit warring (stronger wording)", "catagory": "Single Warning", "template": "uw-ew", "warningLevels": [ 6       ]    },    {        "name": "Edit warring (softer wording for newcomers)", "catagory": "Single Warning", "template": "uw-ewsoft", "warningLevels": [ 6       ]    },    {        "name": "Hijacking articles", "catagory": "Single Warning", "template": "uw-hijacking", "warningLevels": [ 6       ]    },    {        "name": "Creating hoaxes", "catagory": "Single Warning", "template": "uw-hoax", "warningLevels": [ 6       ]    },    {        "name": "Making legal threats", "catagory": "Single Warning", "template": "uw-legal", "warningLevels": [ 6       ]    },    {        "name": "Editing while logged out", "catagory": "Single Warning", "template": "uw-login", "warningLevels": [ 6       ]    },    {        "name": "Usage of multiple IPs", "catagory": "Single Warning", "template": "uw-multipleIPs", "warningLevels": [ 6       ]    },    {        "name": "Personal info", "catagory": "Single Warning", "template": "uw-pinfo", "warningLevels": [ 6       ]    },    {        "name": "Recreating salted articles under a different title", "catagory": "Single Warning", "template": "uw-salt", "warningLevels": [ 6       ]    },    {        "name": "Sockpuppetry", "catagory": "Single Warning", "template": "uw-socksuspect", "warningLevels": [ 6       ]    },    {        "name": "Userpage vandalism", "catagory": "Single Warning", "template": "uw-upv", "warningLevels": [ 6       ]    },    {        "name": "Username is against policy", "catagory": "Single Warning", "template": "uw-username", "warningLevels": [ 6       ],        "note" : "Username notices should not be added for blatent violations. In these cases, click the gavel to report the username to the admins." },   {        "name": "Username is against policy, and conflict of interest", "catagory": "Single Warning", "template": "uw-coi-username", "warningLevels": [ 6       ],        "note" : "Username notices should not be added for blatent violations. In these cases, click the gavel to report the username to the admins." },   {        "name": "Userpage or subpage is against policy", "catagory": "Single Warning", "template": "uw-userpage", "warningLevels": [ 6       ],        "note" : "Username notices should not be added for blatent violations. In these cases, click the gavel to report the username to the admins." } ]; // Used to manage the toast notifications // init is seperate here as it isn't always needed or used

/*   EXAMPLE SYNTAX: Required somewhere: wikiEditor.visuals.toast.init; Then: (for no button) wikiEditor.visuals.toast.show("Text", false, false, 2000); (for button) wikiEditor.visuals.toast.show("Text", "BtnTxt", function {       // your code here    }, 5000);

wikiEditor.visuals.toast = { "active" : false,

"init" : function{ if (!wikiEditor.visuals.toast.active) { // If init already done, no need $('body').append(`               <div class="mdl-snackbar__text">                 <button class="mdl-snackbar__action" type="button">             `); // init (function {               'use strict';                window['counter'] = 0;                var toast = document.querySelector('#wikiEditor-toast');                wikiEditor.visuals.register(toast); // register comp

// create function wikiEditor.visuals.toast.show = (text, buttonTxt, btnClick, tOut) => { 'use strict'; if (buttonTxt) { // Show with action and button toast.MaterialSnackbar.showSnackbar({message: text, actionHandler: btnClick, actionText: buttonTxt, timeout: tOut}); } else { // Show just message toast.MaterialSnackbar.showSnackbar({message: text, timeout: tOut}); }               };                });

// Init done. Register. wikiEditor.visuals.toast.active = true; }   },

"show" : function(text, buttonTxt, btnClick) {} // made in init

} // API calls ext. wikiEditor.info = { // API "targetUsername": un=>{ if (un) {return un;} // return username if defined return mw.config.values.wgRelevantUserName}, "getUsername": =>{return mw.config.values.wgUserName},

"getConfig": (callback) => { if (wikiEditor.config) {callback;} // if config loaded, no need to reload

let defaultConfig = { // Default config on reset or anything like that "lastVersion" : wikiEditor.version };

// gets user config from their page. let user = wikiEditor.info.getUsername; $.getJSON("https://en.wikipedia.org/w/api.php?action=query&prop=revisions&titles=User:"+user+"/redwarnConfig.js&rvslots=*&rvprop=content&formatversion=2&format=json", latestR=>{           // Grab text from latest revision of talk page            // Check if exists            let revisionWikitext = "";            if (!latestR.query.pages[0].missing) { // If page isn't missing, i.e exists                revisionWikitext = latestR.query.pages[0].revisions[0].slots.main.content;            } else {                // Config doesn't exist  we need to make it                console.log("creating config file");                wikiEditor.config = defaultConfig;                wikiEditor.info.writeConfig(callback); // write new config file                return;            }

// Now that's done, verify config file / load it           try { eval(revisionWikitext); if (!wikiEditor.config) {throw "no config";} } catch (err) { // Corrupt config file wikiEditor.config = defaultConfig; wikiEditor.visuals.toast.show("Your config file is corrupt."); }           callback; // we done });   },

"writeConfig": (noRedirect, callback)=> { // CALLBACK ONLY IF NOREDIRECT IS TRUE. // Write config to the users page and refresh let finalTxt = ` /* +-+ +-+
 * !!!! DO NOT ADD THIS FILE TO YOUR !!!! |
 * common.js FILE. RedWarn loads     |
 * this script automatically.        |
 * this script automatically.        |

+-+ +-+
 * Generated by RedWarn          |

wikiEditor.config = `+ JSON.stringify(wikiEditor.config) +"; // "; // generate config text $.post("https://en.wikipedia.org/w/api.php", {               "action": "edit",                "format": "json",                "token" : mw.user.tokens.get("csrfToken"),                "title" : "User:"+ wikiEditor.info.getUsername + "/redwarnConfig.js",                "summary" : "Apply changes to config (RedWarn)", // summary sign here                "text": finalTxt            }).done(dt => {                // We done. Check for errors, then callback appropriately                if (!dt.edit) {                    // Error occured or other issue                    console.error(dt);                    wikiEditor.visuals.toast.show("Sorry, there was an error. See the console for more info. Your changes have not been saved.");                } else {                    // Success!                    if (noRedirect) {callback; return;}; // DO NOT continue if no redirect is requested window.location.hash = "#configChange"; window.location.reload; // we done }           });    },

"featureRestrictPermissionLevel": (l, callback, callbackIfNot)=> { // Restrict feature to users in this group mw.user.getGroups(g=>{           let hasPerm = g.includes(l);            if ((l == "confirmed") && !hasPerm) {hasPerm = g.includes("autoconfirmed");} // Due to 2 types of confirmed user, confirmed and autoconfirmed, we have to check both            if (hasPerm) {                // Has the permission needed                if (callback) {                    callback;                }            } else {                if (callbackIfNot) {                    // Make no perm callback                    callbackIfNot;                } else {                    // Show no perm toast                    wikiEditor.visuals.toast.show("Your account doesn't have permission to do that yet.", false, false, 5000);                }            }        }); },

"getRelatedPage" : (pg)=> { if (pg) {return pg;} // return page if defined try { let x = mw.util.getParamValue('vanarticle'); if (x != null) {return x;} else {return "";} } catch (er) { // If none return "error"; }     },

"parseWikitext" : (wikiTxt, callback) => { // Uses Wikipedia's API to turn Wikitext to string. NEED TO USE POST IF USERPAGE IS LARGE EXT.. $.post("https://en.wikipedia.org/w/api.php", {               "action": "parse",                "format": "json",                "contentmodel" : "wikitext",                "prop": "text",                "pst": true,                "assert": "user",                "text": wikiTxt            }).done(r => {                let processedResult = r.parse.text['*'].replace(/\/\//g, "https://").replace(/href=\"\/wiki/g, `href="https://en.wikipedia.org/wiki`); // regex replace w direct urls                callback(processedResult); // make callback w HTML            }); },

"lastWarningLevel" : (user, callback)=> { // callback(wLevel. thisMonthsNotices, userPg) 0 none 1 notice 2 caution 3 warning 4 final warning // Get the last warning level of a user this month $.getJSON("https://en.wikipedia.org/w/api.php?action=query&prop=revisions&titles=User_talk:"+user+"&rvslots=*&rvprop=content&formatversion=2&format=json", latestR=>{           // Grab text from latest revision of talk page            // Check if exists            let revisionWikitext = "";            if (!latestR.query.pages[0].missing) { // If page isn't missing, i.e exists                revisionWikitext = latestR.query.pages[0].revisions[0].slots.main.content;            } else {                // Return that record is clean as no past warnings due to page not existing                callback(0, "Talk page doesn't exist.", "Talk page doesn't exist."); // exit                return;            }            let wikiTxtLines = revisionWikitext.split("\n");            // let's continue            // Returns date in == Month Year == format and matches            let currentDateHeading = ((d)=>{return "== " + ['January','February','March','April','May','June','July','August','September','October','November','December'][d.getMonth] + " " + (1900 + d.getYear) + " =="})(new Date); let pageIncludesCurrentDate = wikiTxtLines.includes(currentDateHeading); if (!pageIncludesCurrentDate) { // No warnings this month callback(0, "No notices for this month.", revisionWikitext); return; }

let highestWarningLevel = 0; // Set highest to nothing so if there is a date title w nothing in then that will be reported let thisMonthsNotices = ""; // for dialog // For each line for (let i = wikiTxtLines.indexOf(currentDateHeading) + 1; i < wikiTxtLines.length; i++) { if (wikiTxtLines[i].startsWith("==")) { // New section break; // exit the loop }

// Check if it contains logo for each level thisMonthsNotices += wikiTxtLines[i]; // Add to this months if (wikiTxtLines[i].includes("File:Stop hand nuvola.svg")) { // Level 4 warning // This is the highest warning level. We can leave now highestWarningLevel = 4; break; // exit the loop }

// Not using elseif in case of formatting ext..

if (wikiTxtLines[i].includes("File:Nuvola apps important.svg")) { // Level 3 warning highestWarningLevel = 3; // No need for if check as highest level exits }

if (wikiTxtLines[i].includes("File:Information orange.svg")) { // Level 2 warning if (highestWarningLevel < 3) { // We can set highestWarningLevel = 2; }               }

if (wikiTxtLines[i].includes("File:Information.svg")) { // Level 1 notice if (highestWarningLevel < 2) { // We can set highestWarningLevel = 1; }               }            } // End for loop

callback(highestWarningLevel, thisMonthsNotices, revisionWikitext); // We done

});   },// End lastWarningLevel

"addWikiTextToUserPage" : (user, text, underDate, summary, blacklist, blacklistToast) => { // Add text to a page. If underdate true, add it under a date marker wikiEditor.visuals.toast.show("Please wait...", false, false, 2500); $.getJSON("https://en.wikipedia.org/w/api.php?action=query&prop=revisions&titles=User_talk:"+user+"&rvslots=*&rvprop=content&formatversion=2&format=json", latestR=>{           // Grab text from latest revision of talk page            // Check if exists            let revisionWikitext = "";            if (!latestR.query.pages[0].missing) { // If page isn't missing, i.e exists                revisionWikitext = latestR.query.pages[0].revisions[0].slots.main.content;            } // else we keep to ""            let wikiTxtLines = revisionWikitext.split("\n");            let finalTxt = "";

// Check blacklist (if defined) if (blacklist) { if (revisionWikitext.includes(blacklist)) { // Don't continue and show toast wikiEditor.visuals.toast.show(blacklistToast, false, false, 5000); return; }           }

// let's continue // Returns date in == Month Year == format and matches let currentDateHeading = ((d)=>{return "== " + ['January','February','March','April','May','June','July','August','September','October','November','December'][d.getMonth] + " " + (1900 + d.getYear) + " =="})(new Date); let pageIncludesCurrentDate = wikiTxtLines.includes(currentDateHeading); if (underDate) { if (pageIncludesCurrentDate) { // Locate and add text in section

// Locate where the current date section ends so we can append ours to the bottom let locationOfLastLine = wikiTxtLines.indexOf(currentDateHeading) + 1; // in case of date heading w nothing under it                   for (let i = wikiTxtLines.indexOf(currentDateHeading) + 1; i < wikiTxtLines.length; i++) { if (wikiTxtLines[i].startsWith("==")) { // New section locationOfLastLine = i - 1; // the line above is therefore the last console.log("exiting loop: " +wikiTxtLines[locationOfLastLine]); break; // exit the loop } else if (i == wikiTxtLines.length - 1) { // End of page, let's break and set location of last line. locationOfLastLine = i;                           break; // exit loop }                   }                    console.log(locationOfLastLine); if (locationOfLastLine == wikiTxtLines.length - 1) { // To prevent to end notices squishing against eachother // Same as without, but we just include the date string at bottom of page wikiTxtLines.push(["\n\n" + text]); } else { wikiTxtLines.splice(locationOfLastLine, 0, ["\n\n" + text]); // Add notice to array at correct position. Note the "" at the start is for a newline to seperate from prev content }               } else { // Page doesn't have current date // Same as without, but we just include the date string at bottom of page wikiTxtLines.push(["\n" + currentDateHeading + "\n\n" + text]); }           } else { // No need to add to date. Just shove at the bottom of the page wikiTxtLines.push([text]); }

// Process final string wikiTxtLines.forEach(ln => finalTxt = finalTxt + ln + "\n"); // Remap to lines console.log(finalTxt);

// Push edit using CSRF token $.post("https://en.wikipedia.org/w/api.php", {               "action": "edit",                "format": "json",                "token" : mw.user.tokens.get("csrfToken"),                "title" : "User_talk:"+ user,                "summary" : summary + " (RedWarn)", // summary sign here                "text": finalTxt            }).done(dt => {                // We done. Check for errors, then callback appropriately                if (!dt.edit) {                    // Error occured or other issue                    console.error(dt);                    wikiEditor.visuals.toast.show("Sorry, there was an error. See the console for more info. Your message has not been sent.");                    // Reshow dialog                    dialogEngine.dialog.showModal;                } else {                    // Success! Redirect to complete page                    let reloadNeeded = window.location.href.includes("https://en.wikipedia.org/wiki/User_talk:"+ user); // if we are already on the talk page we need to refresh as this would just change the hash redirect("https://en.wikipedia.org/wiki/User_talk:"+ user + "#noticeApplied-" + dt.edit.newrevid + "-" + dt.edit.oldrevid); // go to talk page if (reloadNeeded) {location.reload;} // We done }           });        });     }, // end addTextToUserPage

"quickWelcome" : un=>{ // Quickly welcome the current user wikiEditor.info.addWikiTextToUserPage(wikiEditor.info.targetUsername(un), "\n"+ wikiEditor.welcome +" " + wikiEditor.sign +"\n", false, "Welcome!"); },

// Used for rollback "isLatestRevision" : (name, revID, callback) => { // callback(username) only if successful!! in other cases, will REDIRECT to latest revison compare page // Check if revsion is the latest revision $.getJSON("https://en.wikipedia.org/w/api.php?action=query&prop=revisions&titles="+ encodeURIComponent(name) +"&rvslots=*&rvprop=ids%7Cuser&formatversion=2&format=json", r=>{           // We got the response            let latestRId = r.query.pages[0].revisions[0].revid;            let parentRId = r.query.pages[0].revisions[0].parentid;            let latestUsername = r.query.pages[0].revisions[0].user;            if (latestRId == revID) {                // Yup! Send the callback                callback(latestUsername);            } else {                // Nope :( // Load the preview page of the latest one try {if (dialogEngine.dialog.open) {return;}} catch (error) {} // DO NOT REDIRECT IF DIALOG IS OPEN. redirect("https://en.wikipedia.org/w/index.php?title="+ encodeURIComponent(name) +"&diff="+ latestRId +"&oldid="+ parentRId +"&diffmode=source#redirectLatestRevision"); }       });    },

"latestRevisionNotByUser" : (name, username, callback) => { // CALLBACK revision, summaryText, rId // Name is page name, username is bad username $.getJSON("https://en.wikipedia.org/w/api.php?action=query&prop=revisions&titles="+ encodeURIComponent(name) +"&rvslots=*&rvprop=ids%7Cuser%7Ccontent&rvexcludeuser="+ username +"&formatversion=2&format=json", r=>{           // We got the response            let _r;            try {                _r = r.query.pages[0].revisions[0]; // get latest revision                if (_r == null) { throw "can't be null"; } // if empty error            } catch (error) {                // Probably no other edits. Redirect to history page and show the notice                redirect("https://en.wikipedia.org/w/index.php?title="+ encodeURIComponent(name) +"&action=history#rollbackFailNoRev");                return; // exit            }

console.log("_r"); let latestContent = _r.slots.main.content; let summary = "Rollback recent rev. by "+ username +" (talk) to rev. "+ _r.revid +" by " +_r.user; callback(latestContent, summary, _r.revid); });   },

"stripWikiTxt" : wikiTxt=> { // VERY BASIC Convert WikiText to string try { wikiTxt = wikiTxt.replace(//g, ""); // Strip html comments wikiTxt.match(/\[\[(?:[^\]\]]*)\]\]/g).forEach(t=>{ // match *               txtToKeep = (a=>{return a[a.length - 1];})(t.split("|")).replace("]]", ""); // Last | iin the string then rm the end                wikiTxt = wikiTxt.replace(t, txtToKeep); // now replace            }); wikiTxt = wikiTxt.replace(/'''/g, ""); // rm bold wikiTxt = wikiTxt.replace(/''/g, ""); // rm italic } catch (err) {} // Probably no wikitxt there return wikiTxt; } }; wikiEditor.rollback = { // Rollback features "preview" : => { // Redirect to the preview of the rollback (compare page) // Check if latest, else redirect wikiEditor.visuals.toast.show("Please wait..."); wikiEditor.info.isLatestRevision(mw.config.get("wgRelevantPageName"), mw.util.getParamValue("diff"), un=>{           // Fetch latest revision not by user            wikiEditor.info.latestRevisionNotByUser(mw.config.get("wgRelevantPageName"), un, (content, summary, rID) => { // Got it! Now open preview dialog

// Add handler for when page loaded

addMessageHandler("showBrwsrDialog", c=> {                   // We ready to show                    dialogEngine.dialog.showModal;                });

let url = "https://en.wikipedia.org/w/index.php?title="+ mw.config.get("wgRelevantPageName") +"&diff="+ rID +"&oldid="+ mw.util.getParamValue("diff") +"&diffmode=source#rollbackPreview";

dialogEngine.create(mdlContainers.generateContainer(` <span style="cursor: pointer; padding-right:15px;" onclick="window.parent.postMessage('closeDialog');"> clear Close <iframe src="`+ url +`" frameborder="0" style="height:95%;"> `, document.body.offsetWidth-70, document.body.offsetHeight-50)); // DON'T SHOW until we get the loaded message (see above) });       });    },

"apply" : (reason) => { // Apply rollback wikiEditor.visuals.toast.show("Please wait...", false, false, 1000); wikiEditor.info.isLatestRevision(mw.config.get("wgRelevantPageName"), mw.util.getParamValue("diff"), un=>{           // Fetch latest revision not by user            wikiEditor.info.latestRevisionNotByUser(mw.config.get("wgRelevantPageName"), un, (content, summary, rID) => { // Got it! Now set page content to summary // Push edit using CSRF token $.post("https://en.wikipedia.org/w/api.php", {                   "action": "edit",                    "format": "json",                    "token" : mw.user.tokens.get("csrfToken"),                    "title" : mw.config.get("wgRelevantPageName"),                    "summary" : summary + ": " + reason + " (RedWarn)", // summary sign here                    "text": content,                    "tags": "undo" // Tag with undo flag                }).done(dt => {                    // We done. Check for errors, then callback appropriately                    if (!dt.edit) {                        // Error occured or other issue                        console.error(dt);                        wikiEditor.visuals.toast.show("Sorry, there was an error, likely an edit conflict. Your rollback has not been applied.");

} else { // Success! Now show warning dialog but w correct info wikiEditor.ui.beginWarn(false, un, mw.config.get("wgRelevantPageName"));

wikiEditor.visuals.toast.show("Rollback complete.", "DON'T WARN AND VIEW", =>{                           wikiEditor.info.isLatestRevision(mw.config.get('wgRelevantPageName'), 0, =>{});                        }, 5000); // clicking undo takes to the closest revision, has to be here to overlay the dialog }               });            });        });    },

"restore" : (revID, reason) => { // Restore revision by ID       wikiEditor.visuals.toast.show("Restoring...", false, false, 4000); // Ask API for this revision $.getJSON("https://en.wikipedia.org/w/api.php?action=query&prop=revisions&rvprop=user|content&rvstartid="+ revID +"&rvendid="+ revID +"&titles="+ encodeURI(mw.config.get("wgRelevantPageName")) +"&formatversion=2&rvslots=*&format=json", r=>{           let revUsr = r.query.pages[0].revisions[0].user; // get user            let content = r.query.pages[0].revisions[0].slots.main.content; // get content            let summary = "Restoring revision "+ revID + " by " + revUsr; // gen our summary            // Now we've got that, we just need to submit.            $.post("https://en.wikipedia.org/w/api.php", { "action": "edit", "format": "json", "token" : mw.user.tokens.get("csrfToken"), "title" : mw.config.get("wgRelevantPageName"), "summary" : summary + ": " + reason + " (RedWarn)", // summary sign here "text": content, "tags": "undo" // Tag with undo flag }).done(dt => { // Request done. Check for errors, then go to the latest revision if (!dt.edit) { // Error occured or other issue console.error(dt); wikiEditor.visuals.toast.show("Sorry, there was an error, likely an edit conflict. This edit has not been restored."); } else { wikiEditor.info.isLatestRevision(mw.config.get('wgRelevantPageName'), 0, =>{}); // we done, go to the latest revision }               });        });    },

"promptRollbackReason" : reason=> { wikiEditor.info.isLatestRevision(mw.config.get("wgRelevantPageName"), mw.util.getParamValue("diff"),un=>{ // validate is latest           // Show dialog then rollback            // Add submit handler

addMessageHandler("reason`*", rs=>wikiEditor.rollback.apply(rs.split("`")[1])); // When reason recieved, submit rollback

// CREATE DIALOG // MDL FULLY SUPPORTED HERE (container). dialogEngine.create(mdlContainers.generateContainer(` <form id="newMsgForm" onsubmit="pushRollback;" action="#"> <input class="mdl-textfield__input" type="text" name="rollbackReason" id="rollbackReason" value="`+ reason +`" minlength="5"> <label class="mdl-textfield__label" for="rollbackReason">Rollback Reason <span class="mdl-textfield__error">You must enter a longer rollback reason. Enter a reason for this rollback <button class="mdl-button mdl-js-button mdl-js-ripple-effect" onclick="window.parent.postMessage('closeDialog', '*');"> CANCEL <button id="submitBtn" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent" onclick="pushRollback;"> Rollback

function pushRollback { var data = $('#newMsgForm').serializeArray.reduce(function(obj, item) {               obj[item.name] = item.value;                return obj;                }, {}); // form data let reason = data.rollbackReason; if (reason.length < 5) { return false; // Too short } else { // Submit it           window.parent.postMessage('reason\\\`' + reason); // Push upstairs window.parent.postMessage("closeDialog"); // We done here. return false; // prevent redirect }   }

document.getElementById("rollbackReason").focus; // focus on text box for quick rollback `, 500, 120)).showModal; // 500x120 dialog, see rollbackReason.html for code });   },

"promptRestoreReason" : revID=> { // Prompt for reason to restore. very sim to rollback reason let reason = ""; // Needed for rollback reason page

// Add submit handler addMessageHandler("reason`*", rs=>wikiEditor.rollback.restore(revID, rs.split("`")[1])); // When reason recieved, submit rollback

// CREATE DIALOG // MDL FULLY SUPPORTED HERE (container). dialogEngine.create(mdlContainers.generateContainer(` <form id="newMsgForm" onsubmit="pushRollback;" action="#"> <input class="mdl-textfield__input" type="text" name="rollbackReason" id="rollbackReason" value="`+ reason +`" minlength="5"> <label class="mdl-textfield__label" for="rollbackReason">Rollback Reason <span class="mdl-textfield__error">You must enter a longer rollback reason. Enter a reason for this rollback <button class="mdl-button mdl-js-button mdl-js-ripple-effect" onclick="window.parent.postMessage('closeDialog', '*');"> CANCEL <button id="submitBtn" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent" onclick="pushRollback;"> Rollback

function pushRollback { var data = $('#newMsgForm').serializeArray.reduce(function(obj, item) {               obj[item.name] = item.value;                return obj;                }, {}); // form data let reason = data.rollbackReason; if (reason.length < 5) { return false; // Too short } else { // Submit it           window.parent.postMessage('reason\\\`' + reason); // Push upstairs window.parent.postMessage("closeDialog"); // We done here. return false; // prevent redirect }   }

document.getElementById("rollbackReason").focus; // focus on text box for quick rollback `, 500, 120)).showModal; // 500x120 dialog, see rollbackReason.html for code },

"welcomeRevUsr" : => { // Send welcome to user who made most recent revision wikiEditor.visuals.toast.show("Please wait...", false, false, 1000); wikiEditor.info.isLatestRevision(mw.config.get("wgRelevantPageName"), mw.util.getParamValue("diff"), un=>{           // We got the username, send the welcome            wikiEditor.info.quickWelcome(un);        }); },

"loadIcons" : => { // Add icons to page // Icons for current revision let currentRevIcons = ` <span style="cursor: pointer; font-size:28px; padding-right:5px; color:red;" onclick="wikiEditor.rollback.apply('vandalism');">delete_forever Quick rollback vandalism

<span style="cursor: pointer; font-size:28px; padding-right:5px; color:orange;" onclick="wikiEditor.rollback.apply('rm content w no good reason or consensus');">format_indent_increase Quick rollback removal of content with no good reason or consensus

<span style="cursor: pointer; font-size:28px; padding-right:5px; color:gold;" onclick="wikiEditor.rollback.apply('non-constructive edit');">work_outline Quick rollback non-constructive edit <span style="cursor: pointer; font-size:28px; padding-right:5px; color:blue;" onclick="wikiEditor.rollback.promptRollbackReason('');">replay Rollback <span style="cursor: pointer; font-size:28px; padding-right:5px; color:green;" onclick="wikiEditor.rollback.promptRollbackReason('revert good faith edits ');">thumb_up Assume Good Faith and Rollback <span style="cursor: pointer; font-size:28px; padding-right:5px;" onclick="wikiEditor.rollback.preview;">compare_arrows Preview Rollback

<span style="cursor: pointer; font-size:28px; padding-right:5px;" onclick="wikiEditor.rollback.welcomeRevUsr;">sentiment_satisfied_alt Quick Welcome User `;

// RESTORE THIS VERSION ICONS. DO NOT FORGET TO CHANGE BOTH FOR LEFT AND RIGHT

let isLatest = $("#mw-diff-ntitle1").text.includes("Latest revision"); // is this the latest revision diff page? // On left side (always restore) // DO NOT FORGET TO CHANGE BOTH!! $('.diff-otitle').prepend(`       <span style="cursor: pointer; font-size:28px; padding-right:5px; color:purple;"            onclick="wikiEditor.rollback.promptRestoreReason($('#mw-diff-otitle1 > strong > a').attr('href').split('&')[1].split('=')[1]);">                 history            Restore this version        `        );

// On the right side $('.diff-ntitle').prepend(isLatest ? currentRevIcons : `       <span style="cursor: pointer; font-size:28px; padding-right:5px; color:purple;"            onclick="wikiEditor.rollback.promptRestoreReason($('#mw-diff-ntitle1 > strong > a').attr('href').split('&')[1].split('=')[1]);">                 history            Restore this version        `); // if the latest rev, show the accurate revs, else, don't

// Now register all tooltips for (let item of document.getElementsByClassName("mdl-tooltip")) { wikiEditor.visuals.register(item); }        // That's done :)    } };

// Most UI elements // See also dialog.js (dialogEngine) and mdlContainer.js (mdlContainer) wikiEditor.ui = {

"revisionBrowser" : url=> { // Show new container for revision reviewing dialogEngine.create(mdlContainers.generateContainer(` <span style="cursor: pointer; padding-right:15px;" onclick="window.parent.postMessage('closeDialog');"> clear Close <iframe src="`+ url +`" frameborder="0" style="height:95%;"> `, document.body.offsetWidth-70, document.body.offsetHeight-50)).showModal; },

"beginWarn" : (ignoreWarnings, un, pg)=> { // Give user a warning (show dialog) if ((wikiEditor.info.targetUsername(un) == wikiEditor.info.getUsername) && !ignoreWarnings) { // Usernames are the same, give toast. wikiEditor.visuals.toast.show("You can not warn yourself. To test this tool, use a sandbox.", false, false, 7500); return; // DO NOT continue. }

// Let's continue let finalListBox = ""; rules.forEach((rule, i) => {           let style = "";            if (rule.name.length > 62) {                // Too long to fit                style="font-size:14px"            }            finalListBox += `<li class="mdl-menu__item" data-val="`+ i +`" onmousedown="refreshLevels(`+i+`);"style="`+style +`">`+ rule.name +`</li>`;        });

// Setup preview handling addMessageHandler("generatePreview`*", m=>{           wikiEditor.info.parseWikitext(m.split("`")[1], parsed=>{ // Split to Wikitext and send over to the API to be handled dialogEngine.dialog.getElementsByTagName("iframe")[0].contentWindow.postMessage({                   "action": "parseWikiTxt",                    "result": parsed}, '*'); // push to container for handling in dialog and add https:// to stop image breaking });       });

// Add toast handler addMessageHandler("pushToast`*", m=>wikiEditor.visuals.toast.show(m.split('`')[1],false,false, 5000));

// Add submit handler

addMessageHandler("applyNotice`*", eD=> {           // i.e applyNotice`user`wikitext`summary            // TODO: maybe b64 encode?            let _eD = eD.split("`"); // params            let user = _eD[1];            let wikiTxt = _eD[2];            let summary = _eD[3];

// MAKE EDIT wikiEditor.info.addWikiTextToUserPage(user, wikiTxt, true, summary); });

// Check most recent warning level

wikiEditor.info.lastWarningLevel(wikiEditor.info.targetUsername(un), (w, usrPgMonth, userPg)=>{           let lastWarning = [ // Return HTML for last warning level. TODO: add preview section on click                // NO PAST WARNING                `                <span class="material-icons" id="PastWarning" style="cursor:help;position: relative;top: 5px;padding-left: 10px;color:green;">thumb_up                     No notices this month.                `,

// NOTICE `               <span class="material-icons" id="PastWarning" style="cursor:help;position: relative;top: 5px;padding-left: 10px;color:blue;">info Has been given a Level 1 notice this month. `,               // CAUTION `               <span class="material-icons" id="PastWarning" style="cursor:help;position: relative;top: 5px;padding-left: 10px;color:orange;">announcement Has been given a Level 2 caution this month. `,               // Warning- in red. RedWarn, get it? This is the peak of programming humour. `               <span class="material-icons" id="PastWarning" style="cursor:help;position: relative;top: 5px;padding-left: 10px; color:red;">report_problem Has been given a Level 3 warning this month. `,

// Final/Only Warning (dark red) TODO: Click opens admin report pannel. `               <span class="material-icons" id="PastWarning" style="cursor:help;position: relative;top: 5px;padding-left: 10px;color:#a20000;">report Has been given a Level 4 Final or ONLY warning. Click here to report to admins. `           ][w];

// CREATE DIALOG // MDL FULLY SUPPORTED HERE (container). dialogEngine.create(mdlContainers.generateContainer(`

#previewUsrPg h2{ font-size:25px }

#previewUsrPg .mw-editsection { display: none; /* Hide edit links */ }

#previewUsrPg .toc { /* Hide table of contents */ display: none; }   <h2 style="font-weight: 200;">New Notice

<form id="newNoticeForm"> <input class="mdl-textfield__input" type="text" id="trgtUsrVisualBox" value="`+ wikiEditor.info.targetUsername(un) +`" readonly> <label class="mdl-textfield__label" for="trgtUsrVisualBox">Target To target a different user, please visit their userpage.

`+ lastWarning +`

<span class="material-icons" id="prevUsrPgMonth" style="cursor:pointer;position: relative;top: 5px;padding-left: 10px;" onclick="showThisMonthsUsrMsgs;">assignment_late See notices for this month

<span class="material-icons" id="prevUsrPg" style="cursor:pointer;position: relative;top: 5px;padding-left: 10px;" onclick="showUsrPg;">assignment_ind Preview Userpage

<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label getmdl-select" style="width:100%"> <input type="text" value="" class="mdl-textfield__input" id="template" style="font-size:14px;" onkeypress="searchReasons;" autocomplete="off"> <input type="hidden" value="" name="template"> <i class="mdl-icon-toggle__label material-icons">keyboard_arrow_down</i> <label for="template" class="mdl-textfield__label">Reason <ul for="template" class="mdl-menu mdl-menu--bottom-left mdl-js-menu" style="overflow-y: scroll;height: 300px"> `+ finalListBox +` </ul>

Notice Level:

<label id="l1Lbl" class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="level1" style="padding-right: 10;"> <input type="radio" id="level1" class="mdl-radio__button" name="warnLevel" value="1" checked> <span class="mdl-radio__label"> info Notice

Level 1

Assumes Good Faith

<label id="l2Lbl" class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="level2" style="padding-right: 10;"> <input type="radio" id="level2" class="mdl-radio__button" name="warnLevel" value="2"> <span class="mdl-radio__label"> announcement Caution

Level 2

No Faith Assumption.

<label id="l3Lbl" class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="level3" style="padding-right: 10;"> <input type="radio" id="level3" class="mdl-radio__button" name="warnLevel" value="3"> <span class="mdl-radio__label"> report_problem Warning

Level 3

Assumes bad faith, cease and desist.

<label id="l4Lbl" class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="level4" style="padding-right: 10;"> <input type="radio" id="level4" class="mdl-radio__button" name="warnLevel" value="4"> <span class="mdl-radio__label"> report Final Warning

Level 4

Bad faith, last warning.

<label id="l4imLbl" class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="level4im" style="padding-right: 10;"> <input type="radio" id="level4im" class="mdl-radio__button" name="warnLevel" value="4im"> <span class="mdl-radio__label"> new_releases ONLY Warning

Level 4im

Excessive and continuous disruption.

<label id="l4noLbl" class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="level4no" style="padding-right: 10; display:none;"> <input type="radio" id="level4no" class="mdl-radio__button" name="warnLevel" value="" disabled> <span class="mdl-radio__label"> report_off No final warning.

A final warning cannot be issued under this reason. To issue a level 4 warning, choose the "Generic Warning" option.

Reminder Reminder

Single Notice

Serves to remind other editors about minor mistakes

Policy Violation Warning Policy Violation Warning

Single Warning

Serves to advise editors of policy breaches that, if repeated, are likely to result in a block.

<input class="mdl-textfield__input" name="relatedPage" type="text" id="relatedPage" value="`+ wikiEditor.info.getRelatedPage(pg).replace(/_/g, ' ') +`"> <label class="mdl-textfield__label" for="relatedPage">Related Page Optionally, enter the page that this notice relates to.

<input class="mdl-textfield__input" name="extraInfo" type="text" id="extraInfo" value=""> <label class="mdl-textfield__label" for="extraInfo">Additional info Optionally, add additional info that will be appended to the end of the notice.

<input class="mdl-textfield__input" name="specialInfo" type="text" id="specialInfo" value=""> <label class="mdl-textfield__label" for="specialInfo">Special Information Placeholder :)

<span id="editBtn" class="material-icons" style="font-size: 16px;padding-bottom: 3px;float: right;padding-right: 5px;cursor: pointer;" onclick="$('#previewContainer').hide;$('#editorContainer').show;"> create

<span id="previewBtn" class="material-icons" style="font-size: 16px;padding-bottom: 3px;float: right;padding-right: 5px;cursor: pointer;" onclick="$('#previewContainer').show;$('#editorContainer').hide;grabPreview(true);"> visibility <textarea id="wikiTxt" style="height: 150px; max-height: 150px; overflow-y: auto; width:100%;">

<button class="mdl-button mdl-js-button mdl-js-ripple-effect" onclick="window.parent.postMessage('closeDialog', '*');"> CANCEL <button id="submitBtn" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent" onclick="submitEdit;"> SEND NOTICE

<span class="material-icons" id="prevUsrPg" style="cursor:pointer;position: relative;top: 5px;padding-bottom: 10px;" onclick="returnTonoticeForm;">arrow_back Back to Notice Editor

Generating preview... <div class="mdl-progress mdl-js-progress mdl-progress__indeterminate"> <pre id="uMloadingPre" style="white-space: pre-wrap;">`+ usrPgMonth +`

<span class="material-icons" id="prevUsrPg" style="cursor:pointer;position: relative;top: 5px;padding-bottom: 10px;" onclick="returnTonoticeForm;">arrow_back Back to Notice Editor Generating preview... <div class="mdl-progress mdl-js-progress mdl-progress__indeterminate"> <pre id="uloadingPre" style="white-space: pre-wrap;">`+ userPg +`

function showThisMonthsUsrMsgs { $("#noticeFmContainer").hide; $("#usrPgPrev").hide; $("#usrPgPrevMth").show; // Generate preview if needed (i.e. loading pre still there) if ($("#uMloadingPre").length > 0) { let wikiTxt = $("#uMloadingPre").text; window.parent.postMessage('generatePreview\\\`'+ wikiTxt, '*'); }   }

function showUsrPg { $("#noticeFmContainer").hide; $("#usrPgPrev").show; $("#usrPgPrevMth").hide; // Generate preview if needed (i.e. loading pre still there) if ($("#uloadingPre").length > 0) { let wikiTxt = $("#uloadingPre").text; window.parent.postMessage('generatePreview\\\`'+ wikiTxt, '*'); }   }

function returnTonoticeForm { $("#noticeFmContainer").show; $("#usrPgPrevMth").hide; $("#usrPgPrev").hide; }

// Handle incoming data window.onmessage = function(e){ if (e.data.action == 'parseWikiTxt') { if ($("#usrPgPrevMth:visible").length > 0) { // user page month preview $("#previewUsrPgMth").html(e.data.result); // set content return; // exit } else if ($("#usrPgPrev:visible").length > 0) { // User page preview $("#previewUsrPg").html(e.data.result); // set content return; // exit }

// Normal preview $("#preview").html(e.data.result); // Set preview to content }   };

// Search reasons // Very basic but it works TODO: work on, including selecting best match on ENTER function searchReasons { let toSearch = document.getElementById("template").value.toLowerCase; $(".mdl-menu__item").each((x,y)=>{           if (y.innerText.toLowerCase.includes(toSearch)) {                $(y).show;            } else {                $(y).hide;            }        }); }

var grabPreview = (fromCustomTxt)=> { // Generate preview // Wikitext grab if (fromCustomTxt) { // Edited using Wikitext editor var wikiTxt = document.getElementById("wikiTxt").value; if (!wikiTxt.includes("`+ wikiEditor.sign +`")) { // Not signed, warn pushToast("Don't forget to sign your notice!"); }           window.parent.postMessage('generatePreview\\\`'+ wikiTxt, '*'); } else { if ($('#editorContainer:visible').length > 0) { // Editor is open, we don't want to overwrite by accident. pushToast("Warning: This will overwrite your changes. Switch back to preview to confirm."); return; }           // Get preview as usual getTemplateName(name=>{           var wikiTxt = " " + "`+ wikiEditor.sign +`";            document.getElementById("wikiTxt").value = wikiTxt; // set edit box            window.parent.postMessage('generatePreview\\\`'+ wikiTxt, '*');            }); }    }

var rules = `+ JSON.stringify(rules) +`; // get rules from host var refreshLevels = i=> { if (rules[i].warningLevels.includes(0)) { // Single notice $("#warningRadioButtons").hide; $("#singleNoticeOnly").show; $("#singleWarnOnly").hide; } else if (rules[i].warningLevels.includes(6)) { // Single warning $("#warningRadioButtons").hide; $("#singleNoticeOnly").hide; $("#singleWarnOnly").show; } else { // Normal warning $("#warningRadioButtons").show; $("#singleNoticeOnly").hide; $("#singleWarnOnly").hide;

if (!rules[i].warningLevels.includes(1)) { // No l1 warning $("#l1Lbl").hide; } else { $("#l1Lbl").show; }

if (!rules[i].warningLevels.includes(2)) { // No l2 warning $("#l2Lbl").hide; } else { $("#l2Lbl").show; }          if (!rules[i].warningLevels.includes(3)) { // No l3 warning $("#l3Lbl").hide; } else { $("#l3Lbl").show; }

// LEVEL 4 if (!rules[i].warningLevels.includes(4)) { // No final warning $("#l4Lbl").hide; $("#l4noLbl").show; } else { $("#l4Lbl").show; $("#l4noLbl").hide; }          if (!rules[i].warningLevels.includes(5)) { // No ONLY warning $("#l4imLbl").hide; } else { $("#l4imLbl").show; }      }

if (rules[i].note != null) { // A disclaimer toast needs to be shown pushToast(rules[i].note); }      // TODO!! let noneStandard = { 'uw-agf-sock': 'Optional username of other account (without User:) ', 'uw-bite': "Username of 'bitten' user (without User:) ", 'uw-socksuspect': 'Username of sock master, if known (without User:) ', 'uw-username': 'Username violates policy because... ',               'uw-aiv': 'Optional username that was reported (without User:) ' }; // These all take a different thing and only have 1 input

if (noneStandard[rules[i].template] != null) { // Requires special input $("#specialInfo").show; $("#ordInfo").hide; $("#specialInfoTt").html(noneStandard[rules[i].template]); // Set tool tip text } else { // Doesn't require $("#specialInfo").hide; $("#ordInfo").show; }   }

function pushToast(text) {window.parent.postMessage('pushToast\\\`' + text);} // Push toast to host

var getTemplateName = (callback)=> { // CALLBACK IS ONLY CALLED IF SUCCESSFUL let currentTemplate = ""; let currentLevel = ""; var data = $('#newNoticeForm').serializeArray.reduce(function(obj, item) {           obj[item.name] = item.value;            return obj;            }, {}); // form data

// LEVEL if ($("input:radio:visible:checked").length == 0) { // If no visble radio buttons checked if ($("#singleNoticeOnly:visible").length > 0 || $("#singleWarnOnly:visible").length > 0) { // No warning level needed, leaving for readability } else { // No radio button pressed, not a single warning/notice pushToast("Please select a notice level"); return; }       } else { // Radio button currentLevel = data.warnLevel; // Set to selected radiobutton value }

// TEMPLATE if (data.template == "") { // No reason selected pushToast("Please select a reason"); return; }

currentTemplate = rules[data.template].template; // assemble if ($("#specialInfo:visible").length > 0) { callback(currentTemplate + currentLevel + "|" + data.specialInfo); // callback w data for special } else { callback(currentTemplate + currentLevel + "|" + data.relatedPage + "|" + " "+ data.extraInfo +""); // callback, extra info italics }   };

function submitEdit { // Add notice to page getTemplateName(r=>{ // acts as validation           // SEND IT            var data = $('#newNoticeForm').serializeArray.reduce(function(obj, item) { obj[item.name] = item.value; return obj; }, {}); // form data

var wikiTxt = document.getElementById("wikiTxt").value; if (!wikiTxt.includes("`+ wikiEditor.sign +`")) { // Not signed, warn pushToast("Sign your notice!"); return; // Do not continue }           window.parent.postMessage('applyNotice\\\`' + document.getElementById("trgtUsrVisualBox").value + '\\\`' + wikiTxt + '\\\`' + "New Notice RE: "+ rules[data.template].name); // Push upstairs and commit window.parent.postMessage("closeDialog"); // We done here. Top will refresh or reshow if error occurs. });   }

// Check for change in form data // then 500ms since last change, update preview var oldData = ""; var updatePreviewTOut; setInterval(=>{       var data = $('#newNoticeForm').serializeArray.reduce(function(obj, item) { obj[item.name] = item.value; return obj; }, {}); // form data       if (JSON.stringify(data) === oldData) {            // No change        } else {            oldData = JSON.stringify(data); // set            $("#submitBtn").hide; // hide until template refresh            // Change. Set timeout for 500ms            try {                clearTimeout(updatePreviewTOut); // clear timeout so it resets after last change            } catch (e) {}            updatePreviewTOut = setTimeout(=>{ grabPreview; $("#submitBtn").show; }, 500); // show previews after 500ms since last change       }    }, 100); `, 500, 630)).showModal; // 500x630 dialog, see warnUserDialog.html for code });   }, // end beginWarn

"newMsg" : un=>{ // New message dialog // Setup preview handling addMessageHandler("generatePreview`*", m=>{           wikiEditor.info.parseWikitext(m.split("`")[1], parsed=>{ // Split to Wikitext and send over to the API to be handled dialogEngine.dialog.getElementsByTagName("iframe")[0].contentWindow.postMessage({                   "action": "parseWikiTxt",                    "result": parsed}, '*'); // push to container for handling in dialog and add https:// to stop image breaking });       });

// Add toast handler addMessageHandler("pushToast`*", m=>wikiEditor.visuals.toast.show(m.split('`')[1],false,false,15000));

// Add submit handler

addMessageHandler("applyNotice`*", eD=> {           // i.e applyNotice`user`wikitext`summary            // TODO: maybe b64 encode?            let _eD = eD.split("`"); // params            let user = _eD[1];            let wikiTxt = _eD[2];            let summary = _eD[3];

// MAKE EDIT wikiEditor.info.addWikiTextToUserPage(user, wikiTxt, false, summary); // This requires title. });

// CREATE DIALOG // MDL FULLY SUPPORTED HERE (container). dialogEngine.create(mdlContainers.generateContainer(` h2 { font-size: 20px; line-height: 0px; }   .mw-editsection { display: none; } <h2 style="font-weight: 200;font-size:45px;line-height: 48px;">Compose New Message <form id="newMsgForm"> <input class="mdl-textfield__input" type="text" id="trgtUsrVisualBox" value="`+ wikiEditor.info.targetUsername(un) +`" readonly> <label class="mdl-textfield__label" for="trgtUsrVisualBox">Target To target a different user, please visit their userpage.

<span id="editBtn" class="material-icons" style="font-size: 16px;padding-bottom: 3px;float: right;padding-right: 5px;cursor: pointer;" onclick="$('#previewContainer').hide;$('#editorContainer').show;"> create

<span id="previewBtn" class="material-icons" style="font-size: 16px;padding-bottom: 3px;float: right;padding-right: 5px;cursor: pointer;" onclick="$('#previewContainer').show;$('#editorContainer').hide;grabPreview;"> visibility <textarea id="wikiTxt" name="wikiTxt" style="height: 150px; max-height: 150px; overflow-y: auto; width:100%;">

Your Message Title
Your message here. `+ wikiEditor.sign +`

<button class="mdl-button mdl-js-button mdl-js-ripple-effect" onclick="window.parent.postMessage('closeDialog', '*');"> CANCEL <button id="submitBtn" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent" onclick="sendMessage;"> SEND MESSAGE

// Handle incoming data window.onmessage = function(e){ if (e.data.action == 'parseWikiTxt') { $("#preview").html(e.data.result); // Set preview to content }   };

function pushToast(text) {window.parent.postMessage('pushToast\\\`' + text);} // Push toast to host

function grabPreview { var wikiTxt = document.getElementById("wikiTxt").value; if (!wikiTxt.includes("`+ wikiEditor.sign +`")) { // Not signed, warn pushToast("Don't forget to sign your message!"); }       window.parent.postMessage('generatePreview\\\`'+ wikiTxt, '*'); }

function sendMessage { // Send it! var data = $('#newMsgForm').serializeArray.reduce(function(obj, item) {               obj[item.name] = item.value;                return obj;                }, {}); // form data

var wikiTxt = data.wikiTxt; if (!wikiTxt.includes("`+ wikiEditor.sign +`")) { // Not signed, warn pushToast("Sign your message with '`+ wikiEditor.sign +`'"); return; // Do not continue }       window.parent.postMessage('applyNotice\\\`' + document.getElementById("trgtUsrVisualBox").value + '\\\`' + wikiTxt + '\\\`' + "New message"); // Push upstairs and commit window.parent.postMessage("closeDialog"); // We done here. Top will refresh or reshow if error occurs. }       `, 500, 390)).showModal; // 500x390 dialog, see newMsg.html for code },

"registerContextMenu" : => { // Register context menus for right-click actions // More docs at https://swisnl.github.io/jQuery-contextMenu/demo/trigger-custom.html

// USER TALK ACTIONS $(=>{           $.contextMenu({ selector: 'a[href*="/wiki/User_talk:"], a[href*="/wiki/User:"], a[href*="/wiki/Special:Contributions/"]', // Select all appropriate user links callback: (act, info)=>{ // CALLBACK let hrefOfSelection = $(info.$trigger[0]).attr("href"); // href of userpage or contribs let targetUsername = ""; if (hrefOfSelection.includes("/wiki/User_talk:") || hrefOfSelection.includes("/wiki/User:")) { // This is easy because w should just be ablt to spit at last : targetUsername = (a=>{return a[a.length - 1]})(hrefOfSelection.split(":")).split("/")[0]; // wacky function returns last. Split at slash [0] in case it is a link to a user subpage. } else { // Contribs link, go split at last slash targetUsername = (a=>{return a[a.length - 1]})(hrefOfSelection.split("/")); }                   // Do the action for each action now. ({                       "usrPg" : un=>redirect("https://en.wikipedia.org/wiki/User:"+ un, true),  // Open user page in new tab

"tlkPg" : un=>redirect("https://en.wikipedia.org/wiki/User_talk:"+ un, true), // Open talk page in new tab

"contribs" : un=>redirect("https://en.wikipedia.org/wiki/Special:Contributions/"+ un, true), // Redirect to contribs page in new tab

"accInfo" : un=>redirect("https://en.wikipedia.org/wiki/Special:CentralAuth?target="+ un, true), // Redirect to Special:CentralAuth page in new tab

"sendMsg" : un=>wikiEditor.ui.newMsg(un), // show new msg dialog

"quickWel" : un=>wikiEditor.info.quickWelcome(un), // Submit quick welcome

"newNotice" : un=>wikiEditor.ui.beginWarn(false, un) // show new warning dialog })[act](targetUsername);               },                items: {                    "usrPg": {name: "User Page"},                    "tlkPg": {name: "Talk Page"},                    "sendMsg": {name: "Send message"},                    "newNotice": {name: "New Notice"},                    "quickWel": {name: "Quick Welcome"},                    "contribs": {name: "Contributions"},                    "accInfo": {name: "Account Info"},                    "adminReport": {name: "Report to Admin"}                }            }); }); // END USER ACTIONS CONTEXT MENU

// VOID NOTICE CONTEXT MENU (extendedconfirmed ONLY) wikiEditor.info.featureRestrictPermissionLevel("extendedconfirmed", =>$(=>{ $.contextMenu({               selector: 'p:has(a), p:has(a), p:has(a), p:has(a)', // Select all appropriate paragraphs containing a notice                callback: (act, info)=>{                    // CALLBACK                    let textToMatch = $(info.$trigger[0]).text; // Text to match w api                    if (!$(info.$trigger[0]).html.includes("/wiki/User_talk:")) { // No sig. Likely multi-line                        // We can't void this as it is multi-line. Maybe something to add in future?                        wikiEditor.visuals.toast.show("This type of notice can't be automatically voided. You will need to remove this notice manually.", false, false, 7500);                        return; //exit                    }                    console.log(textToMatch);                    // Now we make the request and read line by line                    $.getJSON("https://en.wikipedia.org/w/api.php?action=query&prop=revisions&titles="+mw.config.get("wgRelevantPageName")+"&rvslots=*&rvprop=content&formatversion=2&format=json", latestR=>{ // Grab text from latest revision of talk page // Check if exists if (latestR.query.pages[0].missing) { // If page doesn't exist, error because something defo went wrong wikiEditor.visuals.toast.show("The notice could not be automatically removed due to an error.", false, false, 5000); return; // exit }

wikiEditor.visuals.toast.show("Please wait...", false, false, 2000); let revisionWikitext = latestR.query.pages[0].revisions[0].slots.main.content; let wikiTxtLines = revisionWikitext.split("\n"); // let's continue let hasBeenMatched = false; let finalStr = ""; wikiTxtLines.forEach((element, i) => {                           let compStr = wikiEditor.info.stripWikiTxt(element);                            if (compStr.toLowerCase.includes(textToMatch.toLowerCase.trim)) {                                // Match! Don't add this one normally. Add our sig and that it is now void. MUST REMOVE PIC (as the textTomatch did) in order to stop Redwarn showing as warning still                                hasBeenMatched = true;                                finalStr += "" + textToMatch + " The above notice was placed in error and is now void. " + wikiEditor.sign + " \n";                            } else {                                finalStr += element + "\n";                            }                        }); if (!hasBeenMatched) { // For whatever reason, we cannot remove this, no match. wikiEditor.visuals.toast.show("This type of notice can't be automatically voided. You will need to remove this notice manually.", false, false, 7500); return; //exit }

// Let's continue and apply edit $.post("https://en.wikipedia.org/w/api.php", {                           "action": "edit",                            "format": "json",                            "token" : mw.user.tokens.get("csrfToken"),                            "title" : mw.config.get("wgRelevantPageName"),                            "summary" : "Void notice made in error (RedWarn)", // summary sign here                            "text": finalStr                        }).done(dt => {                            // We done. Check for errors, then callback appropriately                            if (!dt.edit) {                                // Error occured or other issue                                console.error(dt);                                wikiEditor.visuals.toast.show("Sorry, there was an error. This notice has not been voided.");                            } else { // Success! Redirect to complete page window.location.hash = "#noticeApplied-" + dt.edit.newrevid + "-" + dt.edit.oldrevid; location.reload; // We done }                       });                        // END CALLBACK                    }); },               items: { "rm": {name: "Void this notice"} }           });        }), =>{}); // END REMOVE NOTICE CONTEXT MENU

// NON-CONTRUCTIVE QUICKROLLBACK BUTTON CONTEXT MENU $(=>{           $.contextMenu({ selector: '#rollBackNC', // Select non-constructive edit button callback: (act, info)=>{ // CALLBACK // Do the action for each action now.

({                       "rbTestEdits" : =>wikiEditor.rollback.apply('test edit.')  // Submit quick rollback                    })[act]; },               items: { "rbTestEdits": {name: "Quick Rollback Test Edit"} }           });        }); // NON-CONTRUCTIVE QUICKROLLBACK BUTTON CONTEXT MENU

// TODO: add more, like quick welcome options ext.. and right-click on article link to begin rollback ext.

}, // end context menus

"requestSpeedyDelete" : (pg)=>{ // Open Speedy Deletion dialog for first selection, i.e I'm requesting the speedy deletion of.. // Programming this is proving to be very boring. addMessageHandler("csdR`*", rs=>{           // Reason recieved.            let reason = eval(rs.split("`")[1]);            let reasonTitle = reason.title;            let additionalInfoReq = reason.input != ""; // if special info needed            let additionalInfo = "";            if (additionalInfoReq) {                if (rs.split("`")[2] == "undefined") {                    // No reason specified                    additionalInfo = "Not specified.";                } else {                    additionalInfo = rs.split("`")[2]; // set to the additional info                }            }            console.log(`Deleting under: `+ reasonTitle +` `+ reason.input + additionalInfo + ` (redwarn) `);       });

let finalStr = ``; for (const key in speedyDeleteReasons) { speedyDeleteReasons[key].forEach((e,i)=>{               let style = "";                if ((key + e.title).length > 62) {                    // Too long to fit                    style="font-size:10px;";                }                finalStr += `<li class="mdl-menu__item" data-val='speedyDeleteReasons["`+ key + `"][`+ i +`]' onmousedown="refreshLevels('speedyDeleteReasons[\\\'`+ key + `\\\'][`+ i +`]');" style="`+ style +`">`+ key + e.title +`</li>`;;            }); }       // CREATE DIALOG // MDL FULLY SUPPORTED HERE (container). dialogEngine.create(mdlContainers.generateContainer(`

<h2 style="font-weight: 200;font-size:45px;line-height: 48px;">Request Speedy Deletion <form id="newMsgForm" onsubmit="pushRollback;" action="#"> <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label getmdl-select" style="width:100%"> <input type="text" value="" class="mdl-textfield__input" id="reason" style="font-size:14px;" onkeypress="searchReasons;" autocomplete="off"> <input type="hidden" value="" name="reason"> <i class="mdl-icon-toggle__label material-icons">keyboard_arrow_down</i> <label for="template" class="mdl-textfield__label">I'm requesting the speedy deletion of...            <ul for="template" class="mdl-menu mdl-menu--bottom-left mdl-js-menu" style="overflow-y: scroll;height: 250px"> `+ finalStr +` </ul> <p id="desP">Please select a valid reason. <input class="mdl-textfield__input" type="text" id="customInput" name="customInput"> <label class="mdl-textfield__label" for="customInput" id="customInputLabel">Custom Reason Enter this info correctly <span style="       color: red;        font-size: small;    "> Before nominating a page for speedy deletion, consider whether it could be improved, reduced to a stub, merged or redirected elsewhere, reverted to a better previous revision, or handled in <a href="https://en.wikipedia.org/wiki/Wikipedia:Deletion_policy#Alternatives_to_deletion" target="_blank">some other way</a>. A page is eligible for speedy deletion only if all of its revisions are also eligible.

Are you sure a speedy deletion request is the best option and the data you have entered is correct?

<button class="mdl-button mdl-js-button mdl-js-ripple-effect" onclick="window.parent.postMessage('closeDialog', '*');"> CANCEL <button id="submitBtn" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent" onclick="pushRollback;"> YES, PROPOSE SPEEDY DELETION

function pushRollback { var data = $('#newMsgForm').serializeArray.reduce(function(obj, item) {               obj[item.name] = item.value;                return obj;                }, {}); // form data // Submit it       console.log(data); window.parent.postMessage("csdR\\\`"+data.reason + '\\\`' + data.customInput); // Push upstairs window.parent.postMessage("closeDialog"); // We done here. }   // Search reasons // Very basic but it works TODO: work on, including selecting best match on ENTER function searchReasons { let toSearch = document.getElementById("reason").value.toLowerCase; $(".mdl-menu__item").each((x,y)=>{           if (y.innerText.toLowerCase.includes(toSearch)) {                $(y).show;            } else {                $(y).hide;            }        }); }

var refreshLevels = i=>{ // Show the correct description and textbox let speedyDeleteReasons = `+ JSON.stringify(speedyDeleteReasons) +`; let reason = eval(i); console.log(reason); // Info box $("#desP").html(' info ' + reason.helpText);

if (reason.input != "") { // Requires a custom input, show $("#customInputLabel").text(reason.input); $("#textBcontainer").show; // Make the textbox visible try { if (reason.inputTooltip.length > 0) { // Tool tip too $("#customInputTt").show; $("#customInputTt").text(reason.inputTooltip); } else { // No tooltip $("#customInputTt").hide; }           } catch (error) { // No tooltip $("#customInputTt").hide; }       } else { $("#textBcontainer").hide; }   }        `, 500, 450)).showModal; // 500x300 dialog, see speedyDeletionp1.html for code },

"openPreferences" : => { // Open Preferences page addMessageHandler("config`*", rs=>{           // New config recieved            let config = JSON.parse(atob(rs.split("`")[1])); // b64 encoded json string            //Write to our config            for (const key in config) {                if (config.hasOwnProperty(key)) {                    const element = config[key];                    wikiEditor.config[key] = element; // add or change value                }            }

// Push change wikiEditor.info.writeConfig; });        // Open preferences page with no padding, full screen        dialogEngine.create(mdlContainers.generateContainer(`  <header class="mdl-layout__header">    <div class="mdl-layout__header-row">      <span class="mdl-layout-title" style="width: calc(100% - 60px);">RedWarn Preferences         <span style="cursor: pointer; padding-right:15px;" onclick="saveConfig;">            save            Apply Changes

<span style="cursor: pointer; padding-right:15px;" onclick="window.parent.postMessage('closeDialog');"> clear Don't apply changes and Close <div class="mdl-layout__tab-bar mdl-js-ripple-effect"> <a href="#scroll-tab-1" class="mdl-layout__tab is-active">Appearance</a> <a href="#scroll-tab-2" class="mdl-layout__tab">Behavior</a> <main class="mdl-layout__content" style="padding-left: 5%;"> <section class="mdl-layout__tab-panel is-active" id="scroll-tab-1"> Appearance UI Colour Scheme: <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="option-1"> <input type="radio" id="option-1" class="mdl-radio__button" name="colTheme" value="blue-indigo" checked> <span class="mdl-radio__label">WikiBlue (default) <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="option-2"> <input type="radio" id="option-2" class="mdl-radio__button" name="colTheme" value="amber-yellow"> <span class="mdl-radio__label">Sunshine <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="option-3"> <input type="radio" id="option-3" class="mdl-radio__button" name="colTheme" value="purple-deep_purple"> <span class="mdl-radio__label">Purple Power <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="option-4"> <input type="radio" id="option-4" class="mdl-radio__button" name="colTheme" value="blue_grey-red"> <span class="mdl-radio__label">Red and Dull Previews coming soon.

Patrol Appearance

Sidebar size: The size of the sidebar where recent changes are shown. Use Small is your screen is low resolution, otherwise, changing this option is not recommended. <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="ptrSidebarSmall"> <input type="radio" id="ptrSidebarSmall" class="mdl-radio__button" name="ptrSidebar" value="250"> <span class="mdl-radio__label">Small <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="ptrSidebarMed"> <input type="radio" id="ptrSidebarMed" class="mdl-radio__button" name="ptrSidebar" value="500" checked> <span class="mdl-radio__label">Medium (default) <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="ptrSidebarLg"> <input type="radio" id="ptrSidebarLg" class="mdl-radio__button" name="ptrSidebar" value="750"> <span class="mdl-radio__label">Large

Colour of additions: The background colour for changes that increase the size of a page. <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="ptraddcolGreen"> <input type="radio" id="ptraddcolGreen" class="mdl-radio__button" name="ptrAddCol" value="0,255,0" checked> <span class="mdl-radio__label">Green (default) <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="ptraddcolRed"> <input type="radio" id="ptraddcolRed" class="mdl-radio__button" name="ptrAddCol" value="255,0,0"> <span class="mdl-radio__label">Red <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="ptraddcolBlue"> <input type="radio" id="ptraddcolBlue" class="mdl-radio__button" name="ptrAddCol" value="0,195,255"> <span class="mdl-radio__label">Blue <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="ptraddcolYellow"> <input type="radio" id="ptraddcolYellow" class="mdl-radio__button" name="ptrAddCol" value="255,255,0"> <span class="mdl-radio__label">Yellow

Colour of removals: The background colour for changes that decrease the size of a page. <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="ptrrmcolGreen"> <input type="radio" id="ptrrmcolGreen" class="mdl-radio__button" name="ptrRmCol" value="0,255,0"> <span class="mdl-radio__label">Green <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="ptrrmcolRed"> <input type="radio" id="ptrrmcolRed" class="mdl-radio__button" name="ptrRmCol" value="255,0,0" checked> <span class="mdl-radio__label">Red (default) <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="ptrrmcolBlue"> <input type="radio" id="ptrrmcolBlue" class="mdl-radio__button" name="ptrRmCol" value="0,195,255"> <span class="mdl-radio__label">Blue <label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="ptrrmcolYellow"> <input type="radio" id="ptrrmcolYellow" class="mdl-radio__button" name="ptrRmCol" value="255,255,0"> <span class="mdl-radio__label">Yellow <section class="mdl-layout__tab-panel" id="scroll-tab-2"> Behavior settings coming soon! Please leave suggestions for options you'd like to see in RedWarn's talk page. <section class="mdl-layout__tab-panel" id="scroll-tab-3"> <section class="mdl-layout__tab-panel" id="scroll-tab-4"> <section class="mdl-layout__tab-panel" id="scroll-tab-5"> <section class="mdl-layout__tab-panel" id="scroll-tab-6"> To apply your changes, click the save icon in the top right corner.

var config = `+ JSON.stringify(wikiEditor.config) +`; function saveConfig { var data = $('form').serializeArray.reduce(function(obj, item) {               obj[item.name] = item.value;                return obj;                }, {}); // form data window.parent.postMessage("config\\\`"+ btoa(JSON.stringify(data))); // send to the big boss }

function loadFromConfig { $.each(config, function(key, value) {             var ctrl = $('[name='+key+']');                  switch(ctrl.prop("type")) {                     case "radio": case "checkbox":                           ctrl.each(function { if($(this).attr('value') == value) $(this).attr("checked",value); });                          break;                      default:                        ctrl.val(value);                 }          }); }

loadFromConfig; `, document.body.offsetWidth, document.body.offsetHeight), true).showModal; } } // Processed from Twinkle source. See User Guide for more info. var speedyDeleteReasons = { "anything, under ": [ {           "title": "G1: Nonsense.", "helpText": "Pages consisting purely of incoherent text or gibberish with no meaningful content or history. This does not include poor writing, partisan screeds, obscene remarks, vandalism, fictional material, material not in English, poorly translated material, implausible theories, or hoaxes. In short, if you can understand it, G1 does not apply.", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G2: Test page", "helpText": "A page created to test editing or other Wikipedia functions. Pages in the User namespace are not included, nor are valid but unused or duplicate templates (although criterion T3 may apply).", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G3: Pure vandalism", "helpText": "Plain pure vandalism (including redirects left behind from pagemove vandalism)", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G3: Blatant hoax", "helpText": "Blatant and obvious hoax, to the point of vandalism", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G4: Recreation of material deleted via a deletion discussion", "helpText": "A copy, by any title, of a page that was deleted via an XfD process or Deletion review, provided that the copy is substantially identical to the deleted version. This clause does not apply to content that has been \"userfied\", to content undeleted as a result of Deletion review, or if the prior deletions were proposed or speedy deletions, although in this last case, other speedy deletion criteria may still apply", "input": "Page where the deletion discussion took place: ", "inputMaxLength": 60, "inputTooltip": "Must start with \"Wikipedia:\"" },       {            "title": "G5: Created by a banned or blocked user", "helpText": "Pages created by banned or blocked users in violation of their ban or block, and which have no substantial edits by others", "input": "Username of banned user (if available): ", "inputTooltip": "Should not start with \"User:\"" },       {            "title": "G6: Move", "helpText": "Making way for an uncontroversial move like reversing a redirect" },       {            "title": "G6: Deletion discussion was closed as \"delete\"", "helpText": "A deletion discussion (at AfD, FfD, RfD, TfD, CfD, or MfD) was closed as \"delete\", but the page wasn't actually deleted.", "input": "Page where the deletion discussion was held: ", "inputMaxLength": 40, "inputTooltip": "Must start with \"Wikipedia:\"" },       {            "title": "G6: Copy-and-paste page move", "helpText": "This only applies for a copy-and-paste page move of another page that needs to be temporarily deleted to make room for a clean page move.", "input": "Original page that was copy-pasted here: " },       {            "title": "G6: Housekeeping and non-controversial cleanup", "helpText": "Other routine maintenance tasks", "input": "Rationale: ", "inputMaxLength": 60 },       {            "title": "G7: Author requests deletion, or author blanked", "helpText": "Any page for which deletion is requested by the original author in good faith, provided the page's only substantial content was added by its author. If the author blanks the page, this can also be taken as a deletion request.", "input": "Optional explanation: ", "inputMaxLength": 60, "inputTooltip": "Perhaps linking to where the author requested this deletion." },       {            "title": "G8: Pages dependent on a non-existent or deleted page", "helpText": "such as talk pages with no corresponding subject page; subpages with no parent page; file pages without a corresponding file; redirects to non-existent targets; or categories populated by deleted or retargeted templates. This excludes any page that is useful to the project, and in particular: deletion discussions that are not logged elsewhere, user and user talk pages, talk page archives, plausible redirects that can be changed to valid targets, and file pages or talk pages for files that exist on Wikimedia Commons.", "input": "Optional explanation: ", "inputMaxLength": 60 },       {            "title": "G8: Subpages with no parent page", "helpText": "This excludes any page that is useful to the project, and in particular: deletion discussions that are not logged elsewhere, user and user talk pages, talk page archives, plausible redirects that can be changed to valid targets, and file pages or talk pages for files that exist on Wikimedia Commons.", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G10: Attack page", "helpText": "Pages that serve no purpose but to disparage or threaten their subject or some other entity (e.g., \"John Q. Doe is an imbecile\"). This includes a biography of a living person that is negative in tone and unsourced, where there is no NPOV version in the history to revert to. Administrators deleting such pages should not quote the content of the page in the deletion summary!", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G10: Wholly negative, unsourced BLP", "helpText": "A biography of a living person that is entirely negative in tone and unsourced, where there is no neutral version in the history to revert to.", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G11: Unambiguous advertising or promotion", "helpText": "Pages which exclusively promote a company, product, group, service, or person and which would need to be fundamentally rewritten in order to become encyclopedic. Note that an article about a company or a product which describes its subject from a neutral point of view does not qualify for this criterion; an article that is blatant advertising should have inappropriate content as well", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G12: Unambiguous copyright infringement", "helpText": "Either: (1) Material was copied from another website that does not have a license compatible with Wikipedia, or is photography from a stock photo seller (such as Getty Images or Corbis) or other commercial content provider; (2) There is no non-infringing content in the page history worth saving; or (3) The infringement was introduced at once by a single person rather than created organically on wiki and then copied by another website such as one of the many Wikipedia mirrors" },       {            "title": "G13: Page in draft namespace or userspace AfC submission, stale by over 6 months", "helpText": "Any rejected or unsubmitted AfC submission in userspace or any non-redirect page in draft namespace, that has not been edited for more than 6 months. Blank drafts in either namespace are also included.", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G14: Unnecessary disambiguation page", "helpText": "This only applies for orphaned disambiguation pages which either: (1) disambiguate only one existing Wikipedia page and whose title ends in \"(disambiguation)\" (i.e., there is a primary topic); or (2) disambiguate no (zero) existing Wikipedia pages, regardless of its title. It also applies to orphan \"Foo (disambiguation)\" redirects that target pages that are not disambiguation or similar disambiguation-like pages (such as set index articles or lists)", "input": "", "inputMaxLength": 0, "inputTooltip": "" }   ],

"a user page, under ": [ {           "title": "U1: User request", "helpText": "Personal subpages, upon request by their user. In some rare cases there may be administrative need to retain the page. Also, sometimes, main user pages may be deleted as well. See Wikipedia:User page for full instructions and guidelines", "input": "Explain why this user talk page should be deleted (required): ", "inputMaxLength": 60, "inputTooltip": "User talk pages are deleted only in highly exceptional circumstances. See WP:DELTALK." },       {            "title": "U2: Nonexistent user", "helpText": "User pages of users that do not exist (Check Special:Listusers)", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "U3: Non-free galleries", "helpText": "Galleries in the userspace which consist mostly of \"fair use\" or non-free files. Wikipedia's non-free content policy forbids users from displaying non-free files, even ones they have uploaded themselves, in userspace. It is acceptable to have free files, GFDL-files, Creative Commons and similar licenses along with public domain material, but not \"fair use\" files", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "U5: Blatant WP:NOTWEBHOST violations", "helpText": "Pages in userspace consisting of writings, information, discussions, and/or activities not closely related to Wikipedia's goals, where the owner has made few or no edits outside of userspace, with the exception of plausible drafts and pages adhering to WP:UPYES.", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G11: Promotional user page under a promotional user name", "helpText": "A promotional user page, with a username that promotes or implies affiliation with the thing being promoted. Note that simply having a page on a company or product in one's userspace does not qualify it for deletion. If a user page is spammy but the username is not, then consider tagging with regular G11 instead.", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G13: AfC draft submission or a blank draft, stale by over 6 months", "helpText": "Any rejected or unsubmitted AfC draft submission or a blank draft, that has not been edited in over 6 months (excluding bot edits).", "input": "", "inputMaxLength": 0, "inputTooltip": "" }   ],

"an article, under ": [ {           "title": "A1: No context. Articles lacking sufficient context to identify the subject of the article.", "helpText": "Example: \"He is a funny man with a red car. He makes people laugh.\" This applies only to very short articles. Context is different from content, treated in A3, below.", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "A2: Foreign language articles that exist on another Wikimedia project", "helpText": "If the article in question does not exist on another project, the template should be used instead. All articles in a non-English language that do not meet this criteria (and do not meet any other criteria for speedy deletion) should be listed at Pages Needing Translation (PNT) for review and possible translation", "input": "Interwiki link to the article on the foreign-language wiki: ", "inputTooltip": "For example, fr:Bonjour" },       {            "title": "A3: No content whatsoever", "helpText": "Any article consisting only of links elsewhere (including hyperlinks, category tags and \"see also\" sections), a rephrasing of the title, and/or attempts to correspond with the person or group named by its title. This does not include disambiguation pages", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "A5: Transwikied articles", "helpText": "Any article that has been discussed at Articles for Deletion (et al), where the outcome was to transwiki, and where the transwikification has been properly performed and the author information recorded. Alternately, any article that consists of only a dictionary definition, where the transwikification has been properly performed and the author information recorded", "input": "Link to where the page has been transwikied: ", "inputTooltip": "For example, https://en.wiktionary.org/wiki/hello or hello" },       {            "title": "A7: Unremarkable", "helpText": "An article about a real person, group of people, band, club, company, web content, individual animal, tour, or party that does not assert the importance or significance of its subject. If controversial, or if a previous AfD has resulted in the article being kept, the article should be nominated for AfD instead", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "A7: Unremarkable person", "helpText": "An article about a real person that does not assert the importance or significance of its subject. If controversial, or if there has been a previous AfD that resulted in the article being kept, the article should be nominated for AfD instead", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "A7: Unremarkable musician(s) or band", "helpText": "Article about a band, singer, musician, or musical ensemble that does not assert the importance or significance of the subject", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "A7: Unremarkable club", "helpText": "Article about a club that does not assert the importance or significance of the subject", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "A7: Unremarkable company or organization", "helpText": "Article about a company or organization that does not assert the importance or significance of the subject", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "A7: Unremarkable website or web content", "helpText": "Article about a web site, blog, online forum, webcomic, podcast, or similar web content that does not assert the importance or significance of its subject", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "A7: Unremarkable individual animal", "helpText": "Article about an individual animal (e.g. pet) that does not assert the importance or significance of its subject", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "A7: Unremarkable organized event", "helpText": "Article about an organized event (tour, function, meeting, party, etc.) that does not assert the importance or significance of its subject", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "A9: Unremarkable musical recording where artist's article doesn't exist", "helpText": "An article about a musical recording which does not indicate why its subject is important or significant, and where the artist's article has never existed or has been deleted", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "A10: Recently created article that duplicates an existing topic", "helpText": "A recently created article with no relevant page history that does not aim to expand upon, detail or improve information within any existing article(s) on the subject, and where the title is not a plausible redirect. This does not include content forks, split pages or any article that aims at expanding or detailing an existing one.", "input": "Article that is duplicated: " },       {            "title": "A11: Obviously made up by creator, and no claim of significance", "helpText": "An article which plainly indicates that the subject was invented/coined/discovered by the article's creator or someone they know personally, and does not credibly indicate why its subject is important or significant", "input": "", "inputMaxLength": 0, "inputTooltip": "" }   ],    "a talk page, under ": [ {           "title": "G8: Talk pages with no corresponding subject page", "helpText": "This excludes any page that is useful to the project - in particular, user talk pages, talk page archives, and talk pages for files that exist on Wikimedia Commons.", "input": "", "inputMaxLength": 0, "inputTooltip": "" }   ],    "a file, under ": [ {           "title": "F1: Redundant file", "helpText": "Any file that is a redundant copy, in the same file format and same or lower resolution, of something else on Wikipedia. Likewise, other media that is a redundant copy, in the same format and of the same or lower quality. This does not apply to files duplicated on Wikimedia Commons, because of licence issues; these should be tagged with or  instead", "input": "File this is redundant to: ", "inputTooltip": "The \"File:\" prefix can be left off." },       {            "title": "F2: Corrupt, mising, or empty file", "helpText": "Before deleting this type of file, verify that the MediaWiki engine cannot read it by previewing a resized thumbnail of it. This also includes empty (i.e., no content) file description pages for Commons files", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "F2: Unneeded file description page for a file on Commons", "helpText": "An image, hosted on Commons, but with tags or information on its English Wikipedia description page that are no longer needed. (For example, a failed featured picture candidate.)", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "F3: Improper license", "helpText": "Files licensed as \"for non-commercial use only\", \"non-derivative use\" or \"used with permission\" that were uploaded on or after 2005-05-19, except where they have been shown to comply with the limited standards for the use of non-free content. This includes files licensed under a \"Non-commercial Creative Commons License\". Such files uploaded before 2005-05-19 may also be speedily deleted if they are not used in any articles", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "F4: Lack of licensing information", "helpText": "Files in category \"Files with unknown source\", \"Files with unknown copyright status\", or \"Files with no copyright tag\" that have been tagged with a template that places them in the category for more than seven days, regardless of when uploaded. Note, users sometimes specify their source in the upload summary, so be sure to check the circumstances of the file.", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "F5: Unused non-free copyrighted file", "helpText": "Files that are not under a free license or in the public domain that are not used in any article, whose only use is in a deleted article, and that are very unlikely to be used on any other article. Reasonable exceptions may be made for files uploaded for an upcoming article.", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "F6: Missing fair-use rationale", "helpText": "Any file without a fair use rationale may be deleted seven days after it is uploaded. Boilerplate fair use templates do not constitute a fair use rationale.", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "F7: Clearly invalid fair-use tag", "helpText": "This is only for files with a clearly invalid fair-use tag, such as a tag on a photograph of a mascot.", "input": "Optional explanation: ", "inputMaxLength": 60 },       {            "title": "F7: Fair-use media from a commercial image agency which is not the subject of sourced commentary", "helpText": "Non-free images or media from a commercial source (e.g., Associated Press, Getty), where the file itself is not the subject of sourced commentary, are considered an invalid claim of fair use and fail the strict requirements of WP:NFCC.", "input": "Optional explanation: ", "inputMaxLength": 60 },       {            "title": "F8: File available as an identical or higher-resolution copy on Wikimedia Commons", "helpText": "Provided the following conditions are met: 1: The file format of both images is the same. 2: The file's license and source status is beyond reasonable doubt, and the license is undoubtedly accepted at Commons. 3: All information on the file description page is present on the Commons file description page. That includes the complete upload history with links to the uploader's local user pages. 4: The file is not protected, and the file description page does not contain a request not to move it to Commons. 5: If the file is available on Commons under a different name than locally, all local references to the file must be updated to point to the title used at Commons. 6: For files: They may be speedily deleted as soon as they are off the Main Page", "input": "Filename on Commons: ", "inputTooltip": "This can be left blank if the file has the same name on Commons as here. The \"File:\" prefix is optional." },       {            "title": "F9: Unambiguous copyright infringement", "helpText": "The file was copied from a website or other source that does not have a license compatible with Wikipedia, and the uploader neither claims fair use nor makes a credible assertion of permission of free use. Sources that do not have a license compatible with Wikipedia include stock photo libraries such as Getty Images or Corbis. Non-blatant copyright infringements should be discussed at Wikipedia:Files for deletion" },       {            "title": "F10: Useless non-media file", "helpText": "Files uploaded that are neither image, sound, nor video files (e.g. .doc, .pdf, or .xls files) which are not used in any article and have no foreseeable encyclopedic use", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "F11: No evidence of permission", "helpText": "If an uploader has specified a license and has named a third party as the source/copyright holder without providing evidence that this third party has in fact agreed, the item may be deleted seven days after notification of the uploader", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G8: File description page with no corresponding file", "helpText": "This is only for use when the file doesn't exist at all. Corrupt files, and local description pages for files on Commons, should use F2; implausible redirects should use R3; and broken Commons redirects should use R4.", "input": "", "inputMaxLength": 0, "inputTooltip": "" }   ],    "a category, under ": [ {           "title": "C1: Empty categories", "helpText": "Categories that have been unpopulated for at least seven days. This does not apply to categories being discussed at WP:CFD, disambiguation categories, and certain other exceptions. If the category isn't relatively new, it possibly contained articles earlier, and deeper investigation is needed", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G8: Categories populated by a deleted or retargeted template", "helpText": "This is for situations where a category is effectively empty, because the template(s) that formerly placed pages in that category are now deleted. This excludes categories that are still in use.", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G8: Redirects to non-existent targets", "helpText": "This excludes any page that is useful to the project, and in particular: deletion discussions that are not logged elsewhere, user and user talk pages, talk page archives, plausible redirects that can be changed to valid targets, and file pages or talk pages for files that exist on Wikimedia Commons.", "input": "", "inputMaxLength": 0, "inputTooltip": "" }   ],    "a template, under ": [ {           "title": "T2: Templates that are blatant misrepresentations of established policy", "helpText": "This includes \"speedy deletion\" templates for issues that are not speedy deletion criteria and disclaimer templates intended to be used in articles", "input": "Optional explanation: ", "inputMaxLength": 60 },       {            "title": "T3: Duplicate templates or hardcoded instances", "helpText": "Templates that are either substantial duplications of another template or hardcoded instances of another template where the same functionality could be provided by that other template", "input": "Template this is redundant to: ", "inputTooltip": "The \"Template:\" prefix is not needed." }   ],    "a portal, under ": [ {           "title": "P1: Portal that would be subject to speedy deletion if it were an article", "helpText": "You must specify a single article criterion that applies in this case (A1, A3, A7, or A10).", "input": "Article criterion that would apply: " },       {            "title": "P2: Underpopulated portal (fewer than three non-stub articles)", "helpText": "Any Portal based on a topic for which there is not a non-stub header article, and at least three non-stub articles detailing subject matter that would be appropriate to discuss under the title of that Portal", "input": "", "inputMaxLength": 0, "inputTooltip": "" }   ],

"a redirect, under ": [ {           "title": "R2: Redirect from mainspace to any other namespace.", "helpText": "Excluding the Category:, Template:, Wikipedia:, Help: and Portal: namespaces. This does not include the pseudo-namespace shortcuts. If this was the result of a page move, consider waiting a day or two before deleting the redirect", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "R3: Recently created redirect from an implausible typo or misnomer", "helpText": "However, redirects from common misspellings or misnomers are generally useful, as are redirects in other languages", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "R4: File namespace redirect with a name that matches a Commons page", "helpText": "The redirect should have no incoming links (unless the links are cleary intended for the file or redirect at Commons).", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G6: Redirect to malplaced disambiguation page", "helpText": "This only applies for redirects to disambiguation pages ending in (disambiguation) where a primary topic does not exist.", "input": "", "inputMaxLength": 0, "inputTooltip": "" },       {            "title": "G8: Redirects to non-existent targets", "helpText": "This excludes any page that is useful to the project, and in particular: deletion discussions that are not logged elsewhere, user and user talk pages, talk page archives, plausible redirects that can be changed to valid targets, and file pages or talk pages for files that exist on Wikimedia Commons.", "input": "", "inputMaxLength": 0, "inputTooltip": "" }   ],    "write a ": [ {           "title": "custom reason", "helpText": "At least one of the other deletion criteria must still apply to the page, and you must make mention of this in your rationale. This is not a \"catch-all\" for when you can't find any criteria that fit.", "input": "Rationale: ", "inputMaxLength": 60 }   ] };

$( document ).ready( function {        // Init when page loaded      try {        initwikiEdit;      } catch (err) {        mw.notify("Sorry, an error occured while loading RedWarn.");        console.error(err);      }    } ); //