Jump to content

User:Beetstra/Gadget-Spam-whitelist-Handler.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/**
 * Support for quick handling of the [[MediaWiki:Spam-whitelist]] at en.wikipedia.
 * See [[:m:User:Erwin/SWHandler]] for more information.
 * Tested only in Firefox.
 *
 * Author: [[:m:User:Erwin]], October 2008 - February 2009
 * License: Quadruple licensed GFDL, GPL, LGPL and Creative Commons Attribution 3.0 (CC-BY-3.0)
 *
 * Version history:
 *
 * - This tool uses code from DelReqHandler at Commons.
 *   [[:Commons:MediaWiki:Gadget-DelReqHandler.js]] (oldid=15093612)
 *   Author: [[:Commons:User:Lupo]], October 2007 - January 2008
 *   License: Quadruple licensed GFDL, GPL, LGPL and Creative Commons Attribution 3.0 (CC-BY-3.0)
 *
 * - Script adapted to account for change in section edit links -- [[m:user:billinghurst]] 2013-05
 *
 * - User sDrewth reported the script is broken. -- 2013-11-27
 *
 * - Cleaned up to pass JSHint, and migrated use of (now deprecated) legacy wikibits to
 *   jQuery and newer MediaWiki core built-in javascript libraries. --Krinkle 2013-11-28
 * 
 * - ported to en.wikipedia, adapted which pages to handle  --Beetstra 2015-04-25
 * - ported to spam-whitelist -- Beetstra 2016-06-05
 */
/*jshint unused:true, eqnull:true, browser:true, white:true, indent:4 */
/*global mw, $ */
/*global SWHandlerAddComment, SWHandlerRemComment, SWHandlerCloseComment, SWHandlerRevComment, SWHandlerDecComment */
// <nowiki>
(function () {
    // Guard against double inclusions
    if (typeof window.SWHandler !== 'undefined') {
        return;
    }
	
    var conf = mw.config.get([
        'wgUserGroups',
        'wgPageName',
        'wgServer',
        'wgScriptPath',
        'wgUserName'
    ]);

    if ((conf.wgPageName !== 'MediaWiki_talk:Spam-whitelist') && (conf.wgPageName !== 'Special:SpamWhiteList')) {
        return;
   }

    var action, urls, params, logtitle, tprevid, log_text, summary;

    var SWrequest;
    var SWdebug;

    var SWlist;
    var SWlog;

    var SWUtils = {
        // userIsInGroup (from Commons:MediaWiki:Utilities.js)
        userIsInGroup: function (group) {
            if (conf.wgUserGroups) {
                if (!group || group.length === 0) {
                    group = '*';
                }
                for (var i = 0; i < conf.wgUserGroups.length; i++) {
                    if (conf.wgUserGroups[i] === group) {
                        return true;
                    }
                }
            }
            return false;
        },

        // setEditSummary (from Commons:MediaWiki:Utilities.js)
        setEditSummary: function (text) {
            if (document.editform == null || document.editform.wpSummary == null) {
                return;
            }
            var summary = document.editform.wpSummary.value;
            if (summary == null || summary.length === 0) {
                document.editform.wpSummary.value = text;
            } else if (summary.substr(-3) === '*/ ' || summary.substr(-2) === '*/') {
                document.editform.wpSummary.value += text;
            } else {
                document.editform.wpSummary.value += '; ' + text;
            }
        },

        // makeRawLink (from Commons:MediaWiki:Utilities.js)
        makeRawLink: function (name, url, target) {
            var link = document.createElement('a');
            link.setAttribute('href', url);
            if (target) {
                link.setAttribute('target', target);
            }
            link.appendChild(document.createTextNode(name));
            return link;
        },

        // The following function is defined in several places, and unfortunately, it is defined
        // wrongly in some places. (For instance, in [[:en:User:Lupin/popups.js]]: it should use
        // decodeURIComponent, not decodeURI!!!) Make sure we've got the right version here:
        getParamValue: function (paramName) {
            var cmdRe = new RegExp('[&?]' + paramName + '=([^&]*)');
            var m = cmdRe.exec(document.location.href);
            if (m) {
                try {
                    return decodeURIComponent(m[1]);
                } catch (someError) {}
            }
            return null;
        }
    };

    /**** Enable the whole shebang only for sysops and stewards. */
    var SWHandler;
    if (SWUtils.userIsInGroup('sysop') || SWUtils.userIsInGroup('steward')) {

        SWHandler = {

            /*------------------------------------------------------------------------------------------
            MediaWiki:Spam-whitelist requests closing: add "[add]", "[remove]", "[reverted]" and "[decline]" links to
            the left of the section edit links of a request.
            ------------------------------------------------------------------------------------------*/

            sw_close_add: 'close_add',
            sw_close_rem: 'close_rem',
            sw_close_na: 'close_na',
            sw_close_rev: 'close_rev',
            sw_close_dec: 'close_dec',
            sw_close_NB: 'close_NB',
            sw_close_CR: 'close_CR',
            sw_close_NR: 'close_NR',
            sw_close_about: 'close_about',
            close_add_summary: 'Added.',
            close_rem_summary: 'Removed.',
            close_na_summary: 'Closed.',
            close_rev_summary: 'Reverted.',
            close_dec_summary: 'Declined.',
            close_NB_summary: 'Not blacklisted.',
            close_CR_summary: 'Did you read [[/Common requests]]?',
            close_about_summary: 'per [[/Common requests]]: we need an about page.',
            close_NR_summary: 'Not done due to lack of reply.',
            sw_add: 'add',
            sw_rem: 'rem',

            closeRequestLinks: function () {
                function addRequestLinks(name, href, before, parent) {
                    parent.insertBefore(document.createTextNode('['), before);
                    parent.insertBefore(SWUtils.makeRawLink(name, href), before);
                    parent.insertBefore(document.createTextNode(']'), before);
                }

                var param = SWUtils.getParamValue('fakeaction');
                var wpAction = SWUtils.getParamValue('action');
                var edit_lks, anchors, ignore;
                var anchor, href, orig_bracket, title, lk_name, lk_action;
                if (param == null) {
                    if (conf.wgPageName === 'MediaWiki_talk:Spam-whitelist') {
                        // We're on [[MediaWiki talk:Spam-whitelist]]
                        edit_lks = $('span.mw-editsection').toArray();
                        if (edit_lks.length === 0) {
                            return;
                        }
                        for (i = 0; i < edit_lks.length; i++) {
                            // Set to true if the addition or removal section is found
                            ignore = false;
                            // Find the A within:
                            anchors = edit_lks[i].getElementsByTagName('a');
                            if (anchors != null && anchors.length > 0) {
                                anchor = anchors[0];
                                href = anchor.getAttribute('href');
                                title = anchor.getAttribute('title');
                                if (title.indexOf('Proposed additions') > 0 ) {
                                    ignore = true;
                                    lk_name = 'add WL';
                                } else if (title.indexOf('Proposed removals') > 0) {
                                    ignore = true;
                                    lk_name = 'rem WL';
                                }
                                if (href.indexOf('MediaWiki_talk:Spam-whitelist') > 0 && href.indexOf('&section=') > 0 && lk_name != null && !ignore) {
                                    orig_bracket = edit_lks[i].firstChild;
                                    if (lk_name == 'add WL') {
	                                    addRequestLinks('add WL', href + '&fakeaction=' + SWHandler.sw_close_add, orig_bracket, edit_lks[i]);
    	                                addRequestLinks('decline', href + '&fakeaction=' + SWHandler.sw_close_dec, orig_bracket, edit_lks[i]);
        	                            addRequestLinks('Not blacklisted',href+'&fakeaction=' + SWHandler.sw_close_NB, orig_bracket, edit_lks[i]);
            	                        addRequestLinks('CR?',href+'&fakeaction=' + SWHandler.sw_close_CR, orig_bracket, edit_lks[i]);
                	                    addRequestLinks('about?',href+'&fakeaction=' + SWHandler.sw_close_about, orig_bracket, edit_lks[i]);
                    	                addRequestLinks('NR',href+'&fakeaction=' + SWHandler.sw_close_NR, orig_bracket, edit_lks[i]);
                                    }
                                    if (lk_name == 'rem WL') {
	                                    addRequestLinks('rem WL', href + '&fakeaction=' + SWHandler.sw_close_rem, orig_bracket, edit_lks[i]);
    	                                addRequestLinks('decline', href + '&fakeaction=' + SWHandler.sw_close_dec, orig_bracket, edit_lks[i]);
                    	                addRequestLinks('NR',href+'&fakeaction=' + SWHandler.sw_close_NR, orig_bracket, edit_lks[i]);
                                    }
                                }
                            }
                        }
                    } 

                } else if (param != null) {
                    // We're on a request page
                    var summary = null;
                    action = null;
                    var text = document.editform.wpTextbox1;
                    urls = [];
                    var i, m, url;
                    var append;

                    //Only do anything if we're editing a section.
                    if (document.getElementsByName('wpSection') == null) {
                        return;
                    }

                    // Get URLs
                    if (conf.wgPageName == 'MediaWiki_talk:Spam-whitelist') {
                        var reurl = /\{\{([Ww][Ll][Rr]equest[Rr]egex)\|(.*?)\}\}/g;	
                        m = text.value.match(reurl);
                        if (m != null) {	
                            for (i = 0; i < m.length; i++) {
                                url = m[i].substr(m[i].indexOf('|') + 1, m[i].length - m[i].indexOf('|') - 3); // Can't simply refer to the group
                                url = url.replace(/^regex\=/,'');
                                urls.push(url);
                            }
                        } else {
	                        reurl = /\{\{([Ww][Ll][Rr]equest[Ll]ink)\|(.*?)\}\}/g;	
    	                    m = text.value.match(reurl);
        	                if (m != null) {	
            	                for (i = 0; i < m.length; i++) {
            		                url = m[i].substr(m[i].indexOf('|') + 1, m[i].length - m[i].indexOf('|') - 3); // Can't simply refer to the group
                    	            url = url.replace(/^link\=/,'');
                            	    url = url.replace(/^http:\/\//,'');
                            	    url = url.replace(/^https:\/\//,'');
                            	    url = url.replace(/\=/g,'\\=');
                        	        url = url.replace(/\s/g, '');
                        	        url = url.replace(/\&/g, '\\&');
                    	            url = url.replace(/\//g,'\\/');
                	                url = url.replace(/\?/g,'\\?');	
            	                    url = '\\b' + url.replace(/\./g, '\\.') + '\\b'
        	                        url = url.replace(/\\\/\\b/g,'\\/');
    	                            url = url.replace(/\$\\b/,'$');                        	        
	                                urls.push(url);
                            	}
                        	} else {
		                        reurl = /\{\{([Ll]ink[Ss]ummary|[Ll]ink[Tt]rack|[Ll]ink\s[Tt]rack|[Ll]ink\s[Ss]ummary|[Ss]pam[Ll]ink)\|(.*?)\}\}/g;
    		                    m = text.value.match(reurl);
        		                if (m != null) {	
            		                for (i = 0; i < m.length; i++) {
                		                url = m[i].substr(m[i].indexOf('|') + 1, m[i].length - m[i].indexOf('|') - 3); // Can't simply refer to the group
                    		            urls.push('\\b' + url.replace(/\./g, '\\.') + '\\b');
                        		    }
        	                	}
                        	}
                        }        	                

                        SWrequest = text.value.match(/^\=.*?\=$/m);
                        if (SWrequest && SWrequest.length > 0) {
                            SWrequest = SWrequest[0].substr(3, SWrequest[0].length - 6);
                        } else {
                            SWrequest = '';
                        }

                        if (urls === '' && SWrequest !== '') {
                            m = SWrequest.match(/(?:www\.|)[^\s]*?\.[a-zA-Z]{2,3}/g);
                            for (i = 0; i < m.length; i++) {
                                if (m[i].substr(0, 4) === 'www.') {
                                    urls.push('\\b' + m[i].substr(4).replace(/\./g, '\\.') + '\\b');
                                } else {
                                    urls.push('\\b' + m[i].replace(/\./g, '\\.') + '\\b');
                                }
                            }
                        }
                    }

                    var copyWarn = document.getElementById('editpage-copywarn');
                    copyWarn.innerHTML = copyWarn.innerHTML + '<div style=\"border: 1px solid; margin: 5px; padding: 5px;\"><h3>SWHandler</h3>\n<div id=\"SWdebug\"></div>';
                    SWdebug = document.getElementById('SWdebug');
                    if (param == SWHandler.sw_close_add) {
                        summary = "Added using [[User:Beetstra/SWH|SWHandler]]";
                    	var matchregex = /\[\[[Uu]ser\:(.*?)[\|\]]/;
                    	var signeduser = text.value.match(matchregex); 
                    	if (signeduser != null) {
	                        append = (typeof SWHandlerAddComment !== 'undefined' ? SWHandlerAddComment : ':{{rto|'+signeduser[1]+'}} {{Added}} to [[MediaWiki:Spam-whitelist]]. --~~~~');
                    	} else {
	                        append = (typeof SWHandlerAddComment !== 'undefined' ? SWHandlerAddComment : ':{{Added}} to [[MediaWiki:Spam-whitelist]]. --~~~~');
                    	}
                        action = SWHandler.sw_add;
                    } else if (param == SWHandler.sw_close_rem) {
                        summary = "Removed using [[User:Beetstra/SWH|SWHandler]]";
                    	var matchregex = /\[\[[Uu]ser\:(.*?)[\|\]]/;
                    	var signeduser = text.value.match(matchregex); 
                    	if (signeduser != null) {
	                        append = (typeof SWHandlerAddComment !== 'undefined' ? SWHandlerAddComment : ':{{rto|'+signeduser[1]+'}} {{Removed}} from [[MediaWiki:Spam-whitelist]]. --~~~~');
                    	} else {
	                        append = (typeof SWHandlerAddComment !== 'undefined' ? SWHandlerAddComment : ':{{Removed}} from [[MediaWiki:Spam-whitelist]]. --~~~~');
                    	}
                        action = SWHandler.sw_rem;
                    } else if (param == SWHandler.sw_close_na) {
                        summary = "Closed using [[User:Beetstra/SWH|SWHandler]].";
                    	var matchregex = /\[\[[Uu]ser\:(.*?)[\|\]]/;
                    	var signeduser = text.value.match(matchregex); 
                    	if (signeduser != null) {
    	                    append = (typeof SWHandlerCloseComment !== 'undefined' ? SWHandlerCloseComment : ':{{rto|'+signeduser[1]+'}} {{Close}}. --~~~~');
                    	} else {
	                        append = (typeof SWHandlerCloseComment !== 'undefined' ? SWHandlerCloseComment : ':{{Close}}. --~~~~');
                    	}
                    } else if (param == SWHandler.sw_close_dec) {
                        summary = "Declined using [[User:Beetstra/SWH|SWHandler]].";
                    	var matchregex = /\[\[[Uu]ser\:(.*?)[\|\]]/;
                    	var signeduser = text.value.match(matchregex); 
                    	if (signeduser != null) {
	                        append = (typeof SWHandlerDecComment !== 'undefined' ? SWHandlerDecComment : ':{{rto|'+signeduser[1]+'}} {{Declined}}. --~~~~');
                    	} else {
	                        append = (typeof SWHandlerDecComment !== 'undefined' ? SWHandlerDecComment : ':{{Declined}}. --~~~~');
                    	}
                    } else if (param == SWHandler.sw_close_NB) {
                        summary = "Declined using [[User:Beetstra/SWH|SWHandler]].";
                    	var matchregex = /\[\[[Uu]ser\:(.*?)[\|\]]/;
                    	var signeduser = text.value.match(matchregex); 
                    	var url;
	                    reurl = /\{\{([Ww][Ll][Rr]equest[Ll]ink)\|(.*?)\}\}/g;	
                        m = text.value.match(reurl);
                    	if (signeduser != null) {
	                        append = ':{{rto|'+signeduser[1]+'}} This is not blacklisted (anymore)';
	    	                if (m != null) {	
	        	                for (i = 0; i < m.length; i++) {
	        	                	url = m[i].substr(m[i].indexOf('|') + 1, m[i].length - m[i].indexOf('|') - 3); // Can't simply refer to the group
    	            	            url = url.replace(/^link\=/,'');
        	                	    url = url.replace(/^http:\/\//,'');
            	            	    url = url.replace(/^https:\/\//,'');
	        	                	append += '\n:* https://'+url;
	        	                }
	        	                append += '\n';
	        	            }	                        
	                        append += ': {{not done}}.  --~~~~';
                    	} else {
	                        append = ':This is not blacklisted (anymore)';
	    	                if (m != null) {	
	        	                for (i = 0; i < m.length; i++) {
	        	                	url = m[i].substr(m[i].indexOf('|') + 1, m[i].length - m[i].indexOf('|') - 3); // Can't simply refer to the group
    	            	            url = url.replace(/^link\=/,'');
        	                	    url = url.replace(/^http:\/\//,'');
            	            	    url = url.replace(/^https:\/\//,'');
	        	                	append += '\n:* https://'+url;
	        	                }
	        	                append += '\n';
	        	            }	                        
	                        append += ': {{not done}}.  --~~~~';
                    	}
                    } else if (param == SWHandler.sw_close_CR) {
                    	summary = "Did you read [[/Common requests]]? (using [[User:Beetstra/SWH|SWHandler]])";
                    	var matchregex = /\[\[[Uu]ser\:(.*?)[\|\]]/;
                    	var signeduser = text.value.match(matchregex); 
                    	if (signeduser != null) {
                        	append = (typeof SWHandlerDecComment !== 'undefined' ? SWHandlerDecComment : ':{{rto|'+signeduser[1]+'}} did you read [[/Common requests]]? --~~~~');
                    	} else {
                        	append = (typeof SWHandlerDecComment !== 'undefined' ? SWHandlerDecComment : ':Did you read [[/Common requests]]? --~~~~');
                    	}
                    } else if (param == SWHandler.sw_close_about) {
                    	summary = "per [[MediaWiki talk:Spam-whitelist/Common_requests#The_official_homepage_of_the_subject_of_a_page]], we need an about page (using [[User:Beetstra/SWH|SWHandler]])";
                    	var matchregex = /\[\[[Uu]ser\:(.*?)[\|\]]/;
                    	var signeduser = text.value.match(matchregex); 
                    	if (signeduser != null) {
                        	append = (typeof SWHandlerDecComment !== 'undefined' ? SWHandlerDecComment : ':{{rto|'+signeduser[1]+'}} per [[MediaWiki talk:Spam-whitelist/Common_requests#The_official_homepage_of_the_subject_of_a_page]], we would need an about-page or a full url (including an index.htm) of the index page.  Can you please provide a suitable link?  --~~~~');
                    	} else {
                        	append = (typeof SWHandlerDecComment !== 'undefined' ? SWHandlerDecComment : ':Per [[MediaWiki talk:Spam-whitelist/Common_requests#The_official_homepage_of_the_subject_of_a_page]], we would need an about-page or a full url of the index page.  Can you please provide a suitable link? --~~~~');
                    	}
                    } else if (param == SWHandler.sw_close_NR) {
                    	summary = "Not done due to lack of reply. (using [[User:Beetstra/SWH|SWHandler]])";
                    	var matchregex = /\[\[user\:(.*?)[\|\]]/;
                    	var signeduser = text.value.match(matchregex); 
                    	if (signeduser != null) {
                        	append = (typeof SWHandlerDecComment !== 'undefined' ? SWHandlerDecComment : ':{{rto|'+signeduser[1]+'}} {{not done}} due to lack of reply.  --~~~~');
                    	} else {
                        	append = (typeof SWHandlerDecComment !== 'undefined' ? SWHandlerDecComment : ': {{not done}} due to lack of reply.  --~~~~');
                    	}
                    }
                    if (summary != null) {
                        if (wpAction == 'edit') {
                            SWUtils.setEditSummary(summary);
							var $textbox = $( '#wpTextbox1' );
							mytext = $textbox.textSelection( 'getContents');
							$textbox.textSelection( 'setContents', mytext+'\n'+append);                        }
                        if (action != null && urls !== '') {
                            SWdebug.innerHTML += '<span style=\"font-weight:bold;\">Action: </span>' + action + ';<br />';
                            SWdebug.innerHTML += '<span style=\"font-weight:bold;\">Links: </span>' + urls.join(', ') + ';<br />';
                            var editform = document.getElementById('editform');
                            editform.action += '&fakeaction=' + param;

                            // Remove save button
                            var wpSave = document.getElementById('wpSave');
                            wpSave.parentNode.removeChild(wpSave);

                            //Add save link:
                            wpSave = document.createElement('span');
                            wpSave.setAttribute('id', 'wpSave');
                            wpSave.innerHTML = '<a href=\"javascript:SWHandler.saveRequest()\">Save and edit whitelist</a> ';

                            var wpPreview = document.getElementById('wpPreview');
                            wpPreview.parentNode.insertBefore(wpSave, wpPreview);
                        }
                        // Don't close the window to allow adding a comment.
                        if (text.scrollHeight > text.clientHeight) {
                            text.scrollTop = text.scrollHeight - text.clientHeight;
                        }
                        text.focus();
                    }
                }
            },

            saveRequest: function () {
                SWdebug.innerHTML += '<span style=\"font-weight:bold;\">Saving request…</span><br />';
                var summary = document.getElementById('wpSummary').value;
				var $textbox = $( '#wpTextbox1' );
				var text = $textbox.textSelection( 'getContents');
                var section = document.getElementsByName('wpSection')[0].value;
                var minor = document.getElementById('wpMinoredit');
                if (minor.checked) {
                    minor = '&minor=1';
                } else {
                    minor = '&notminor=1';
                }
                var watch = document.getElementById('wpWatchthis');
                if (watch.checked) {
                    watch = '&watchlist=watch';
                } else {
                    watch = '&watchlist=unwatch';
                }
                if (section !== '') {
                    section = '&section=' + encodeURIComponent(section);
                }
                var edittoken = mw.user.tokens.get('csrfToken');
                var query = 'format=xml';
                var params = 'action=edit&title=' + encodeURIComponent(conf.wgPageName) + '&summary=' + encodeURIComponent(summary) + '&text=' + encodeURIComponent(text) + section + minor + watch + '&token=' + encodeURIComponent(edittoken);
                SWHandler.postRequest(query, SWHandler.setLocation, params, true);
            },

            setLocation: function (request) {
                var xml = request.responseXML;
                var location = conf.wgServer + conf.wgScriptPath + '/index.php' +
                    '?title=Special:SpamWhiteList' +
                    '&action=' + action +
                    '&urls=' + urls.join('|') +
                    '&request=' + SWrequest;
                if (xml != null) {
                    var edits = xml.getElementsByTagName('edit');
                    if (edits.length === 0) {
                        SWdebug.innerHTML = '<div style=\"font-weight:bold;\">Saving might have failed. Please close the request yourself. ' +
                            'Use <a href="' + location +
                            '" title="Special:SpamWhiteList">Special:SpamWhiteList</a>' +
                            ' to add/remove the links to/from the whitelist.<br />Params:<br /><pre>' + params + '</pre><br />Response:<pre>' + request.responseText + '</pre></div>';
                        return;
                    }
                    var result = edits[0].getAttribute('result');
                    SWHandler.oldid = edits[0].getAttribute('newrevid');
                    if (result != 'Success') {
                        SWdebug.innerHTML = '<div style=\"font-weight:bold;\">Saving failed. Please close the request yourself. ' +
                            'Use <a href="' + location +
                            '" title="Special:SpamWhiteList">Special:SpamWhiteList</a>' +
                            ' to add/remove the links to/from the whitelist.<br />Params:<br /><pre>' + params + '</pre><br />Response:<pre>' + request.responseText + '</pre></div>';
                        return;
                    } else {
                        window.location = location;
                    }
                } else {
                    SWdebug.innerHTML += '<div style=\"font-weight:bold;\">ERROR: ' + request.status + '<br /> Please close the request yourself. ' +
                        'Use <a href="' + location +
                        '" title="Special:SpamWhiteList">Special:SpamWhiteList</a>' +
                        ' to add/remove the links to/from the whitelist.<br />Params:<br /><pre>' + params + '</pre><br />Response:<pre>' + request.responseText + '</pre></div>';
                    return;
                }
            },

            /*------------------------------------------------------------------------------------------
            Add to whitelist.
            ------------------------------------------------------------------------------------------*/
            edittoken: '',
            text: '',
            request: '',
            urls: '',
            action: '',
            timestamp: '',
            oldid: '',
            custom: false,

            SBWrapper: function () {
                document.title = 'MediaWiki:Spam-whitelist';

                // Set header
                var header = document.getElementsByTagName('h1')[0];
                header.innerHTML = 'MediaWiki:Spam-whitelist';

                // Set content
                var content = document.getElementById('bodyContent');
                content.innerHTML = '<h3 id=\"siteSub\">From Meta, a Wikimedia project coordination wiki</h3>' +
                  '<p>Use this tool to add links to the <a href=\"//en.wikipedia.org/wiki/MediaWiki:Spam-whitelist\" title=\"MediaWiki:Spam-whitelist\">MediaWiki:Spam-whitelist</a>, or remove them, and log the change. Note that it does not escape paths. <span style=\"font-weight:bold;\">Do not use this tool unless you have a basic understanding of regex.</span> You still need to confirm the changes. Do not assume that the proposed edit is correct.</p>';

                SWHandler.action = SWUtils.getParamValue('action');
                SWHandler.urls = SWUtils.getParamValue('urls');
                SWHandler.request = SWUtils.getParamValue('request');
				if (SWHandler.request.substr(0,1) == ' ') {
					SWHandler.request = SWHandler.request.substr(1, 256); // try to strip initial space
				}
				if (SWHandler.request.substr(0,1) == ' ') {
					SWHandler.request = SWHandler.request.substr(1, 256); // try to strip initial space
				}
				if (SWHandler.request.substr(0,1) == ' ') {
					SWHandler.request = SWHandler.request.substr(1, 256); // try to strip initial space
				}
                if ((SWHandler.action === 'add' || SWHandler.action === 'rem') && SWHandler.urls != null && SWHandler.urls !== '' && SWHandler.request != null) {
                    content.innerHTML += '<div id=\"SBstatus\" style=\"font-style: italic; border: 1px solid; padding: 5px; float:right;\">' +
                                        '<span id=\"Sthrobber\" style=\"text-align:center; font-weight:bold; float:right;\">' +
                                        '<img src=\"//upload.wikimedia.org/wikipedia/commons/d/d2/Spinning_wheel_throbber.gif\" alt=\"Loading\">' +
                                        'Loading…</span>' +
                                        '<br clear=\"all\" />' +
                                        '<table><tr style=\"vertical-align:top;\"><td>' +
                                        '<h5>whitelist</h5>' +
                                        '<ul><li id=\"SgetBL\" style=\"color:grey;\">Get whitelist text</li>' +
                                        '<li id=\"SaddBL\" style=\"color:grey;\">Add/remove links</li>' +
                                        '<li id=\"SgetC\" style=\"color:grey;\">Get changes from server</li>' +
                                        '<li id=\"SparseBL\" style=\"color:grey;\">Parse and show changes</li>' +
                                        '<li id=\"SconfirmBL\" style=\"color:grey;\">Confirm changes</li>' +
                                        '<li id=\"SsaveBL\" style=\"color:grey;\">Save changes</li></ul></td><td>' +
                                        '<h5>Log</h5>' +
                                        '<ul><li id=\"SgetL\" style=\"color:grey;\">Get log text</li>' +
                                        '<li id=\"SaddL\" style=\"color:grey;\">Add/remove links</li>' +
                                        '<li id=\"SsaveL\" style=\"color:grey;\">Save changes</li>' +
                                        '</ul></tr></table></div><br clear=\"all\" />' +
                                        '<h3>whitelist</h3><div id=\"SWlist\"></div>' +
                                        '<h3>Log</h3><div id=\"SWlog\"></div>';
                    SWlist = document.getElementById("SWlist");
                    SWlog = document.getElementById("SWlog");
                    var edittoken = mw.user.tokens.get('csrfToken');
                    SWHandler.getRequest('action=query&prop=info&titles=MediaWiki:Spam-whitelist&token=' + encodeURIComponent(edittoken), SWHandler.getBL, true);
                } else {
                    content.innerHTML += '<p style=\"font-style:italic\">This tool can only be used in conjunction with <a href=\"//en.wikipedia.org/wiki/MediaWiki_talk:Spam-whitelist\" title=\"MediaWiki talk:Spam-whitelist\">MediaWiki talk:Spam-whitelist</a> to add or remove links.</p>';
                }
            },

            // Get the current text and oldid of [[MediaWiki:Spam-whitelist]]
            getBL: function (request) {
                var xml = request.responseXML;
                if (xml != null) {
                    var pages = xml.getElementsByTagName('page');
                    SWHandler.edittoken = mw.user.tokens.get('csrfToken');
                    SWHandler.getRequest('action=query&prop=revisions&titles=MediaWiki:Spam-whitelist&rvprop=ids|timestamp|user|comment|content', SWHandler.parseBL, true);
                }
            },

            // Add/remove links from the text
            parseBL: function (request) {
                var xml = request.responseXML;
                if (xml == null) {
                    SWlist.innerHTML += '<div style=\"font-weight:bold;\">ERROR: ' + request.status + '<br />Aborting.</div>';
                    return;
                }
                var revs = xml.getElementsByTagName('rev');
                SWHandler.timestamp = revs[0].getAttribute('timestamp');
                SWHandler.text = revs[0].textContent;
                var oldlength = SWHandler.text.length;
                document.getElementById('SgetBL').style.color = 'black';

                if (SWHandler.action == SWHandler.sw_add) {
                    urls = SWHandler.urls.replace(/\|/g, '\n');
                    if (SWHandler.text.length > 1000) {
                        var lastchars = SWHandler.text.substr(-1000);
                        SWHandler.text = SWHandler.text.substr(0, SWHandler.text.length - 1000);
                        if (lastchars.indexOf('## SWHandler_end') > 0) {
                            lastchars = lastchars.replace('## SWHandler_end', urls + '\n## SWHandler_end');
                        } else {
                            SWlist.innerHTML += '<div style=\"font-weight:bold;\">ERROR: Could not find marker. Aborting.</div>';
                            return;
                        }
                        SWHandler.text += lastchars;
                    } else {
                        if (SWHandler.text.indexOf('## SWHandler_end') > 0) {
                            SWHandler.text = SWHandler.text.replace('## SWHandler_end', urls + '\n## SWHandler_end');
                        } else {
                            SWlist.innerHTML += '<div style=\"font-weight:bold;\">ERROR: Could not find marker. Please add \"## SWHandler_end\" on a single line below the whitelist\'s entry\'s and try again.</div>';
                            return;
                        }
                    }
                } else if (SWHandler.action == SWHandler.sw_rem) {
                    urls = SWHandler.urls.split('|');
                    for (var i = 0; i < urls.length; i++) {
                        SWHandler.text = SWHandler.text.replace(urls[i] + '\n', '');
                    }
                }
                //Check if the length changed, if not assume nothing changed.
                if (oldlength == SWHandler.text.length) {
                    SWlist.innerHTML += '<div style=\"font-weight:bold;\">ERROR: The length of the old and new text are the same. This shouldn\'t happen. Aborting.</div>';
                    return;
                }
                document.getElementById('SaddBL').style.color = 'black';
                params = 'action=query&prop=revisions&titles=MediaWiki:Spam-whitelist&rvdifftotext=' + encodeURIComponent(SWHandler.text);
                SWHandler.postRequest('format=xml', SWHandler.parseDiff, params, true);
            },

            // Parse and show the proposed edit
            parseDiff: function (request) {
                var xml = request.responseXML;
                if (xml != null) {
                    document.getElementById('SgetC').style.color = 'black';
                    var diffSource = xml.getElementsByTagName('diff');
                    var summary;
                    if (diffSource[0].childNodes[0].nodeValue) {
                        urls = SWHandler.urls.split('|');

                        if (SWHandler.action == 'add') {
                            summary = 'Adding ';
                        } else {
                            summary = 'Removing ';
                        }

                        if (urls.length > 1) {
                            summary += urls.length + ' links ';
                        } else {
                            summary += urls[0] + ' ';
                        }

                        summary += 'per [[MediaWiki talk:Spam-whitelist]].';

                        SWlist.innerHTML += '<div id="wikiDiff"><table class="diff"><col class="diff-marker" /><col class="diff-content" /><col class="diff-marker" /><col class="diff-content" /><tr valign="top"><td colspan="2" class="diff-otitle">Current revision</td><td colspan="2" class="diff-ntitle">Your text</td></tr>' +
                          diffSource[0].childNodes[0].nodeValue + '</table></div>' +
                          '<br /><div id=\"BLform\">' +
                          '<input type=\"text\" value=\"' + summary + '\" id=\"summary\" maxlength=\"200\" size=\"60\" >&nbsp;&nbsp;&nbsp;<button onclick=\"SWHandler.submitBL()\">Confirm changes</button><button onclick=\"SWHandler.editBL()\">Edit changes</button></div>';

                        document.getElementById('SparseBL').style.color = 'black';
                    } else {
                        SWlist.innerHTML += '<div style=\"font-weight:bold;\">ERROR: Could not show diff.<br />Aborting.</div>';
                        return;
                    }
                } else {
                    SWlist.innerHTML += '<div style=\"font-weight:bold;\">ERROR: ' + request.status + '<br />Aborting.</div>';
                    return;
                }
            },

            // Add a text area to change the whitelist yourself

            editBL: function () {
                var BLform = document.getElementById('BLform');
                BLform.innerHTML = '<textarea name=\"wpTextbox1\" id=\"wpTextbox1\" cols=\"80\" rows=\"25\" accesskey=\",\">' +
                  SWHandler.text +
                  '</textarea>' +
                  BLform.innerHTML;
            },

            // Submit the edit to [[MediaWiki:Spam-whitelist]]
            submitBL: function () {
                var wpTextbox = document.getElementById('wpTextbox1');
                if (wpTextbox != null) {
                    SWHandler.text = wpTextbox.value;
                    SWHandler.custom = true; //We can't simply log the change. User needs to do that.
                }
                document.getElementById('SconfirmBL').style.color = 'black';
                summary = document.getElementById('summary').value;
                summary += ' Using [[User:Beetstra/SWH|SWHandler]].';
                var query = 'format=xml';
                params = 'action=edit&title=MediaWiki:Spam-whitelist&summary=' + encodeURIComponent(summary) + '&text=' + encodeURIComponent(SWHandler.text) + '&basetimestamp=' + SWHandler.timestamp  +  '&token=' + encodeURIComponent(SWHandler.edittoken);
                SWHandler.postRequest(query, SWHandler.LWrapper, params, true);
            },

            // Start logging procedure
            LWrapper: function (request) {
                var xml = request.responseXML;
                if (xml != null) {
                    var edits = xml.getElementsByTagName('edit');
                    if (edits.length === 0) {
                        SWlist.innerHTML = '<div style=\"font-weight:bold;\">Saving might have failed. Please check if it succeeded and log the edit yourself if necessary.</div>';
                        return;
                    }
                    var result = edits[0].getAttribute('result');
                    SWHandler.oldid = edits[0].getAttribute('newrevid');
                    if (result !== 'Success') {
                        SWlist.innerHTML = '<div style=\"font-weight:bold;\">Saving failed. Please whitelist the links yourself.</div>';
                        return;
                    } else {
                        document.getElementById('SsaveBL').style.color = 'black';
                        SWlist.innerHTML = '<div>whitelist has been updated, <a href=\"' + conf.wgServer + conf.wgScriptPath + '/index.php?oldid=' + SWHandler.oldid + '&diff=prev\" title=\"diff\">diff</a>.</div>';
                    }

                } else {
                    SWlist.innerHTML += '<div style=\"font-weight:bold;\">ERROR: ' + request.status + '<br />Aborting.</div>';
                    return;
                }

                var d = new Date();
                var m = d.getMonth() + 1;
                if (m < 10) {
                    m = '0' + m;
                }
                var y = d.getFullYear();		
                logtitle = 'MediaWiki_talk:Spam-whitelist/Log';

                SWHandler.getRequest('action=query&prop=revisions&titles=MediaWiki_talk:Spam-whitelist&rvprop=ids|timestamp|user|comment|content', SWHandler.parseTBL, true);
            },

            // Get current oldid of [[MediaWiki talk:Spam-whitelist]], because that's the location of the request.
            parseTBL: function (request) {
                var xml = request.responseXML;
                if (xml != null) {
                    var revs = xml.getElementsByTagName('rev');
                    tprevid = revs[0].getAttribute('revid');
                } else {
                    SWlog.innerHTML += '<div style=\"font-weight:bold;\">ERROR: ' + request.status + '<br />. Please log the edit yourself.</div>';
                    return;
                }

                SWHandler.getRequest('action=query&prop=revisions&titles=' + logtitle + '&rvprop=ids|timestamp|user|comment|content', SWHandler.parseL, true);
            },

            // Add/remove links to/from log
            parseL: function (request) {
                var xml = request.responseXML;
                if (xml != null) {
                    document.getElementById('SgetL').style.color = 'black';
                    var revs = xml.getElementsByTagName('rev');
                    if (revs.length === 0) {
                        SWlog.innerHTML += '<div style=\"font-weight:bold;\">ERROR: Could not get log.<br /> It probably does not exist yet. Please create <a href="//en.wikipedia.org/wiki/' + logtitle + '" title="' + logtitle + '">' + logtitle + '</a> and log the edit yourself.</div>';
                        return;
                    }
                    SWHandler.timestamp = revs[0].getAttribute('timestamp');
                    SWHandler.text = revs[0].textContent;
                } else {
                    SWlog.innerHTML += '<div style=\"font-weight:bold;\">ERROR: ' + request.status + '<br /> Please log the edit yourself.</div>';
                    return;
                }

                var sbldiff;
                if (SWHandler.action == SWHandler.sw_add) {
                    sbldiff = '{{swl-diff|' + SWHandler.oldid + '}}';
                } else {
                    sbldiff = '{{swl-diff|' + SWHandler.oldid + '|removal}}';
                }

                urls = SWHandler.urls.split('|');
                var r = SWHandler.request;
                r = '{{swl-log|' + tprevid + '#{{subst:anchorencode:' + r + '}}}}';

                var spaces = '                                        ';

                if (urls.length == 1) {
                    log_text = ' ' + urls[0] + spaces.substr(0, 39 - urls[0].length) + '# ' +
                      conf.wgUserName + ' # ' + sbldiff + '; see ' + r;
                } else {
                    log_text = ' #:                                     ' +
                      conf.wgUserName + ' # ' + sbldiff + '; see ' + r;
                    for (var i = 0; i < urls.length; i++) {
                        log_text += '\n   ' + urls[i];
                    }
                }

                // User needs to confirm log edit
                if (SWHandler.custom) {
                    SWlog.innerHTML += '<p>The following text will be added to the log. You need to update this to reflect the changes you made to the proposed edit.</p>' +
                      '<textarea name=\"wpTextbox1\" id=\"wpTextbox1\" cols=\"80\" rows=\"10\" accesskey=\",\">' +
                      log_text +
                      '</textarea>' +
                      '<button onclick=\"SWHandler.submitL()\">Confirm changes</button>';
                } else {
                    SWHandler.submitL();
                }
            },

            submitL: function () {
                var wpTextbox = document.getElementById('wpTextbox1');
                if (wpTextbox != null) {
                    SWHandler.text += '\n' + wpTextbox.value;
                } else {
                    SWHandler.text += '\n' + log_text;
                }
                document.getElementById('SaddL').style.color = 'black';
                var query = 'format=xml';
                var params = 'action=edit&title=' + encodeURIComponent(logtitle) + '&summary=' + encodeURIComponent(summary) + '&text=' + encodeURIComponent(SWHandler.text) + '&token=' + encodeURIComponent(SWHandler.edittoken);
                SWHandler.postRequest(query, SWHandler.LEnd, params, true);
            },

            // Confirm results
            LEnd: function (request) {
                var xml = request.responseXML;

                if (xml != null) {
                    var edits = xml.getElementsByTagName('edit');
                    if (edits.length === 0) {
                        SWlist.innerHTML = '<div style=\"font-weight:bold;\">Saving might have failed. Please check if it succeeded and log the edit yourself if necessary.</div>';
                        return;
                    }
                    var result = edits[0].getAttribute('result');
                    var oldid = edits[0].getAttribute('newrevid');
                    if (result !== 'Success') {
                        SWlog.innerHTML = '<div>Saving failed. Please log the edit yourself.</div>';
                        return;
                    } else {
                        document.getElementById('SsaveL').style.color = 'black';
                        document.getElementById('Sthrobber').innerHTML = '';
                        SWlog.innerHTML = '<div>Log has been updated, <a href=\"' + conf.wgServer + conf.wgScriptPath + '/index.php?oldid=' + oldid + '&diff=prev\" title=\"diff\">diff</a>.<p style=\"font-style:italic\">Thanks for helping with the Spam whitelist! Return to <a href=\"//en.wikipedia.org/wiki/MediaWiki_talk:Spam-whitelist\" title=\"MediaWiki talk:Spam-whitelist\">MediaWiki talk:Spam-whitelist</a>.</p></div>';
                    }
                }
            },

            getRequest: function (query, callback, api) {
                var url;
                if (api) {
                    url = conf.wgServer + conf.wgScriptPath + '/api.php?format=xml&' + query;
                } else {
                    url = conf.wgServer + conf.wgScriptPath + '/index.php?' + query;
                }

                $.ajax({
                    url: url,
                    type: 'GET',
                    headers: {
                        'Pragma': 'cache=yes',
                        'Cache-Control': 'no-transform'
                    }
                }).done(function (data, textStatus, jqXHR) {
                    callback(jqXHR);
                });
            },

            postRequest: function (query, callback, params, api) {
                var url;
                if (api) {
                    url = conf.wgServer + conf.wgScriptPath + '/api.php?' + query;
                } else {
                    url = conf.wgServer + conf.wgScriptPath + '/index.php?' + query;
                }

                $.ajax({
                    url: url,
                    type: 'POST',
                    headers: {
                        'Content-type': 'application/x-www-form-urlencoded',
                        'Content-length': params.length,
                        'Pragma': 'cache=yes',
                        'Cache-Control': 'no-transform'
                    },
                    data: params
                }).done(function (data, textStatus, jqXHR) {
                    callback(jqXHR);
                });
            },

            setupHandler: function () {
                if (conf.wgPageName == 'Special:SpamWhiteList') {
                    SWHandler.SBWrapper();
                } else {
                    SWHandler.closeRequestLinks();
                }
            }

        };
        // End of SWHandler object

        $(SWHandler.setupHandler);

    }
    // End of if-sysop check

    // Export global variables
    window.SWHandler = SWHandler;
    window.SWrequest = SWrequest;

}());
// </nowiki>
// [[Category:Wikipedia scripts|SWHandler.js]]