User:IAmaPersonthatExists/global.js

importArticles({   type: 'script',    articles: [        'u:cjrichards-and-applemasterexpert:MediaWiki:MessageWallBlock/code.js',        'u:dev:MediaWiki:GlobalEditcount/code.js',        'u:dev:MediaWiki:SeeMoreActivityButton/code.js',         'u:dev:MediaWiki:QuickLogs/code.js',         'u:dev:MediaWiki:FastCreate.js',         'u:dev:MediaWiki:MassProtect/code.js',          'u:dev:MediaWiki:AjaxEdit.js',           'u:dev:MediaWiki:UserInfo.js',             'u:dev:MediaWiki:Message/code.js',             'u:dev:MediaWiki:MessageWallImprovements.js',             'u:dev:MediaWiki:RevealAnonIP/usercode.js',            'u:dev:MediaWiki:AutoPurge/code.js',            'u:dev:MediaWiki:View Source/code.js',            'u:dev:MediaWiki:DiscussionsFeed.js',            'u:dev:MediaWiki:DeepLTranslate/code.js',            'u:dev:MediaWiki:AvatarLink.js',             'u:dev:MediaWiki:QuickDelete/code.js', 'u:dev:MediaWiki:Rollback/code.js', 'u:dev:MediaWiki:AjaxTemplate/code.js', 'u:dev:MediaWiki:ChainQuotes.js', 'u:dev:MediaWiki:AnchoredRollback/code.js', 'u:dev:MediaWiki:RollbackSpamUserContribs/code.js', 'u:dev:MediaWiki:PiniginsUserInfo/code.js', 'u:dev:MediaWiki:ClearSandbox/code.js', 'u:dev:MediaWiki:AddBlockUserTag/code.js', 'u:dev:MediaWiki:DiscussionsActivity.js', ] });

/*--Other--*/ require(['wikia.window', 'jquery', 'mw', 'wikia.nirvana', 'ext.wikia.design-system.loading-spinner'], function (window, $, mw, nirvana, Spinner) {   'use strict';

// Script variables and double run protection. if (window.vanguardToolsLoaded) { return; }   window.vanguardToolsLoaded = true; var VAN = {};

// MediaWiki variables. VAN.mw = mw.config.get([       'wgMessages',        'wgCityId',        'wgDBname',        'wgServer',        'wgCanonicalNamespace',        'wgCanonicalSpecialPageName',        'wgTitle',        'wgAction',        'wgArticleId',        'wgArticlePath',        'wgLoadScript',        'wgUserGroups'    ]);

// User parrot status. VAN.parrot = VAN.mw.wgUserGroups.some(function(ug) {       return ['sysop', 'content-moderator', 'threadmoderator', 'chatmoderator', 'rollback', 'users', '*'].indexOf(ug) > -1;    });

// Script configuration. VAN.config = window.vanguardToolsConfig || { state: true, modules: [], redirect: true, nav: true, template: true, insights: true, pdash: true, adminalert: true };   if (VAN.config.modules && !$.isArray(VAN.config.modules)) { delete VAN.config.modules; }

// Design system integration. VAN.wds = { // Library handler. handler: function(wds) { // Cache our design system utils. $.extend(VAN.wds, wds); // Asset loading done. VAN.wds.$loaded.resolve; },       // Asset loading event. $loaded: $.Deferred };

// I18n implementation. VAN.i18n = { // Message & utility loader. handler: function(i18no) { i18no.loadMessages('VanguardTools').done(VAN.i18n.store); },       // Message data handler. store: function(i18n) { // Cache our msg data, utils $.extend(VAN.i18n, i18n); // Message loading done. VAN.i18n.$loaded.resolve; },       // I18n event. $loaded: $.Deferred };

// Main script VAN.init = function { if (!VAN.parrot || !VAN.config.state) { return; } // Dispatch dependency handlers. mw.hook('dev.i18n').add(VAN.i18n.handler); mw.hook('dev.wds').add(VAN.wds.handler); // Module activator. $.when(VAN.i18n.$loaded, VAN.wds.$loaded).then(function {           // Run all modules by default.            VAN.config.modules = VAN.config.modules.length > 0 ?                VAN.config.modules :                VAN.modules;            // Validation for modules.            $.each(VAN.config.modules, function(i, m) { if (VAN.modules.indexOf(m) === -1) { VAN.modules.splice(i, 1); }           });            // Initialise all configured modules.            $.each(VAN.config.modules, function(i, m) { VAN[m].init; });           // Post-execution event            $.when.apply(null, VAN.config.modules.map(function(m) {                return VAN[m].$executed;            })).then(function { // Loaded class. $(document.body).addClass('van-is-loaded'); // Fire hook. mw.hook('dev.van').fire(VAN); });       });        // Import dependencies. importArticle({ type: 'script', article: 'u:dev:I18n-js/code.js' }); importArticle({ type: 'script', article: 'u:dev:WDSIcons/code.js' }); importArticle({ type: 'script', article: 'u:dev:ProtectionIcons.js' }); };

// Redirect module for S:IB. VAN.redirect = { init: function { if (               VAN.config.redirect !== true ||                VAN.mw.wgCanonicalSpecialPageName !== 'InfoboxBuilder' ||                VAN.mw.wgTitle.indexOf('/') === -1            ) { VAN.redirect.$executed.resolve; return; }           // Template existence check. VAN.redirect.template = mw.util.wikiUrlencode(VAN.mw.wgTitle.match(/\/([\s\S]+)$/)[1]); nirvana.getJson('PortableInfoboxBuilderController', 'getTemplateExists', {               title: VAN.redirect.template            }, VAN.redirect.builder); },       // Redirect notification. builder: function(t) { if (t.exists) { VAN.redirect.execute; return; }           if (navigator.serviceWorker) { // Create notification service worker. VAN.redirect.worker = navigator.serviceWorker.register(new mw.Uri(VAN.mw.wgLoadScript).extend({ 'debug': mw.config.get('debug'), 'lang': mw.config.get('wgUserLanguage'), 'mode': 'articles', 'skin': mw.config.get('skin'), 'missingCallback': 'importNotifications.importArticleMissing', 'articles': mw.util.wikiUrlencode('u:dev:VanguardTools/service-worker.js'), 'reviewed': mw.config.get('wgReviewedScriptsTimestamp'), 'only': 'scripts' }).getRelativePath); // Create two-way message channel. VAN.redirect.mch = new MessageChannel; VAN.redirect.mch.port1.onmessage = VAN.redirect.handler; // Post notification data to worker. Notification.requestPermission.then(VAN.redirect.post); }       },        post: function(r) { if (r !== 'granted') { return; }           navigator.serviceWorker.controller.postMessage({                command: 'van_send_notif',                i18n: {                    cancel: VAN.mw.wgMessages['cancel'],                    ok: VAN.mw.wgMessages['ok'],                    source: VAN.i18n.msg('sourceredirect').plain                }            }, [VAN.redirect.mch.port2]); },       // Infobox builder template creation. handler: function(e) { if (e.data.command !== 'van_create_infobox') { return; } // Spinner code. VAN.redirect.spinner = $(' ').css({                   background:                        $(document.body).css('background-color')                            .replace('rgb','rgba').replace(')', ', 0.5)'),                    position: 'fixed',                    height: '100%',                    width: '100%',                    left: '0',                    top: '0',                    'z-index': '1000000000'                }).html(function {                    return new Spinner(38, 2).html                        .replace('wds-block', 'wds-spinner__block')                        .replace('wds-path', 'wds-spinner__stroke');                }).appendTo(document.body); // Create infobox. nirvana.sendRequest({               controller: 'PortableInfoboxBuilderController',                method: 'publish',                data: {                    data: VAN.redirect.infobox,                    title: VAN.redirect.template,                    oldTitle: VAN.redirect.template,                    token: mw.user.tokens.get('editToken')                },                callback: VAN.redirect.callback            }); },       // Infobox data object. infobox: function { return JSON.stringify({               "data": [                    {                        "data": { "defaultValue": "" },                        "source": "name",                        "type": "title"                    },                    {                        "data": { "caption": { "source": "caption" }},                        "source": "image",                        "type": "image"                    },                    {                        "data": VAN.i18n.msg('piheader').plain,                        "collapsible": false,                        "type": "section-header"                    },                    {                        "data": {"label": VAN.i18n.msg('pitype').plain },                        "source": "type",                        "type": "row",                        "sourceFrozen": false                    }                ]            }); },       // Infobox builder redirection. callback: function(d) { VAN.redirect.spinner.remove; if (d.success) { VAN.redirect.execute; } else { VAN.redirect.handler; }       },        execute: function { var uri = new mw.Uri(               mw.util.getUrl('Template:' + VAN.redirect.template)            ); uri.extend({               action: 'edit',                useeditor: 'source'            }); window.location.href = uri.toString; VAN.redirect.$executed.resolve; },       $executed: $.Deferred };

// Global navigation links module. VAN.nav = { init: function { if (VAN.config.nav !== true) { VAN.nav.$executed.resolve; return; }           var $l = $('').addClass('wds-list wds-is-linked'); $.each(VAN.nav.uri, function(l, t) {               $l.append( $('').append(                       $('', { 'href': (function(t) {                               var p = VAN.mw.wgArticlePath.replace('$1', t);                                return (l === 'portabilitydash') ?                                    'https://portability.wikia.com' + p:                                    p;                            }(t)), text: VAN.i18n.msg(l).plain })                   )                );            });            // Icon and dropdown generation. var icon = VAN.wds.icon('menu-control-tiny', {               'class': 'wds-dropdown-chevron'            }); var $c = VAN.nav.dropdown($l, icon); // Append to menu $('.wds-global-navigation__user-menu') // Prevent scrollable dropdown. .children('.wds-dropdown__content') .addClass('wds-is-not-scrollable') // Insert dropdown. .find('.wds-list > li > a[data-tracking-label="account.profile"]').parent.after($c); VAN.nav.$executed.resolve; },       // Create dropdown. dropdown: function($l, icon) { return $('', {               'id': 'van-tools-dropdown',                'class': 'wds-dropdown-level-2'            }).append(                $('', { 'href': mw.util.getUrl(VAN.nav.uri.insights), 'target': '_blank', 'rel': 'noopener noreferrer', 'class': [ 'wds-dropdown-level-2__toggle', 'van-tools-link' ].join(' ') }).append( $(' ', {                       text: VAN.i18n.msg('tools').plain                    }), icon ),               $(' ', {                    'class': [ 'wds-dropdown-level-2__content', 'wds-is-not-scrollable', 'van-tools-menu' ].join(' ') }).append($l)           ); },       // Global navigation links. uri: { insights:       'Special:Insights/nonportableinfoboxes', infoboxes:      'Special:Templates?type=infobox', templates:      'Special:Templates', sitecss:        'Special:CSS', ImportJS:       'MediaWiki:ImportJS', CommonCSS:     'MediaWiki:Common.css', CommonJS:     'MediaWiki:Common.js', personalcss:    'Special:MyPage/common.css', themescss:      'MediaWiki:Themes.css?action=edit', admins:         'Special:ListUsers/sysop', wikifeatures:   'Special:WikiFeatures', portabilitydash: 'Special:PortabilityDashboard?url=' + VAN.mw.wgServer.match(/\/\/([^.]+)/)[1] },       $executed: $.Deferred };

// Template reclassification hotkey module. VAN.template = { init: function { if (               VAN.config.template !== true ||                VAN.mw.wgCanonicalNamespace !== 'Template' ||                VAN.mw.wgAction !== 'view'            ) { VAN.template.$executed.resolve; return; }           var $popout = $(' ', {                'class': 'van-popout color1'            }).hide.append(                $('', { text: VAN.i18n.msg('templatetypeguide').plain }),               $('')            ); $popout.appendTo(document.body); nirvana.getJson(               'TemplateClassification',                'getTemplateClassificationEditForm',                function(d) {                    // Extract labels.                    d.templateTypes.forEach(function(dt) { VAN.template.labels[dt.type] = dt.name; });                   // Ready the popout.                    $popout.children('ul').append( $.map(VAN.template.types, function(o, k) {                           return $('').append( $(' ', {                                   text: o.key                                }), $(' ', {                                   text: VAN.template.labels[o.type]                                }) );                       })                    );                    $popout.show;                    // Delegate keyboard handler.                    $(document).keyup(VAN.template.shortcut);                    VAN.template.$executed.resolve;                }            ); },       // Shortcut keys. shortcut: function(e) { if (               !VAN.template.types.hasOwnProperty(e.which) ||                !e.altKey            ) { return; }           VAN.template.type = VAN.template.types[e.which].type, VAN.template.label = VAN.template.labels[VAN.template.type]; nirvana.postJson(               'TemplateClassificationApi',                'classifyTemplate',                {                    pageId: mw.config.get('wgArticleId'),                    type: VAN.template.type,                    editToken: mw.user.tokens.values.editToken                },                VAN.template.success            ); },       // Callback for TemplateClassification controller. success: function { $('.template-classification-type-label').text(VAN.template.label); var message = VAN.i18n.msg('templatetypechange', VAN.template.label).plain; notification = new BannerNotification(message, 'confirm'); notification.show; },       // Template type map for keyboard shortkeys. types: { 223: { key: '`', type: 'infobox' }, 49: { key: '1', type: 'quote' }, 50: { key: '2', type: 'navbox'}, 51: { key: '3', type: 'notice' }, 52: { key: '4', type: 'context-link' }, 53: { key: '5', type: 'infoicon' }, 54: { key: '6', type: 'scrollbox' }, 55: { key: '7', type: 'references' }, 56: { key: '8', type: 'media' }, 57: { key: '9', type: 'data' }, 48: { key: '0', type: 'design' }, 189: { key: '-', type: 'navigation' }, 187: { key: '=', type: 'nonarticle' } },       labels: {}, $executed: $.Deferred };

// S:I/NPI utility extension. VAN.insights = { // Module initialiser. init: function { if (               VAN.config.insights !== true ||                !$('.insights-nav-item.insights-icon-nonportableinfoboxes.active')                    .find('.insights-red-dot').exists            ) { VAN.insights.$executed.resolve; return; }           // Data lists. VAN.insights.list = {}; var chunks = []; [].slice.call($('.insights-list-item-title')).map(function(e, i) {               // Template name.                var t = e.innerText;                $(e).closest('.insights-list-item')                    .attr('data-template', t);                // API data.                VAN.insights.list[t] = {};                ( chunks[Math.floor(i / 50)] = chunks[Math.floor(i / 50)] || []               )[i % 50] = t;            }); VAN.insights.api = new mw.Api; chunks.forEach(function(c) {               VAN.insights.api.get({ 'action': 'query', 'prop': 'info', 'inprop': 'protection', 'titles': c.join('|') }).done(VAN.insights.handler);           }); },       // Template list list: {}, // API handler. handler: function(d) { $.each(d.query.pages, function(id, data) {               VAN.insights.list[data.title].protection =                    data.protection.filter(function(obj) { return (obj.type === 'edit'); }).length > 0;           }); if (Object.keys(VAN.insights.list).every(function(t) { return VAN.insights.list[t].hasOwnProperty('protection'); })) {               VAN.insights.ui; }       },        // Interface configuration map for actions. map: { 'viewdraft': { icon: 'eye-small' },           'conversion': { icon: 'gear-small' },           'rawcode': { icon: 'article-small', query: { action: 'raw', ctype: 'text/css' // Firefox fix. }           },            'protected': { icon: 'lock-small', query: { action: 'history' }           },            'unprotected': { icon: 'unlock-small', query: { action: 'history' }              }        },        // UI modification. ui: function { // Add page header class (hack for button colors). $('.insights-content').addClass('page-header'); // Button map for WDS icon addition. $('.insights-list-cell-altaction .wikia-button').each(function {               var $b = $(this),                    t = $(this).closest('.insights-list-item')                        .attr('data-template');                VAN.insights.list[t].$toolbar =                    $(' ', { 'class': [ 'wds-button-group', 'van-action-button-group' ].join(' ') }).insertBefore($b).append($b);               // Class addition.                $b                    .removeAttr('class')                    .addClass([ 'wds-button', 'wds-is-squished' ].join(' '))                   .addClass(function(i, c) { if ($b.attr('href').indexOf('action=edit') > -1) { return [ 'van-action-button', 'van-is-conversion' ].join(' '); } else { return [ 'wds-is-secondary', 'van-action-button', 'van-is-viewdraft' ].join(' '); }                   }).html(function(i, html) { return ' ' + mw.html.escape(html) + ' '; });               // List buttons.                VAN.insights.list[t].$buttons = [$b];                // Generate toolbar.                VAN.insights.tbr(t);            }); },       // Template toolbar generator. tbr: function(t) { var b = { 'unprotected': false, 'protected': true },               $t = VAN.insights.list[t].$toolbar; // Button creation. $.each(VAN.insights.map, function(l, c) {               // Prevent duplication.                if ( !['conversion', 'viewdraft'].some(function(s) {                       return l === s;                    }) && (                       Object.keys(b).indexOf(l) === -1 ||                        VAN.insights.list[t].protection === b[l]                    ) ) {                   // Button element.                    var $b = $('', { 'href': (function {                               var uri = new mw.Uri(mw.util.getUrl(t));                                // Add query                                if (c.query) {                                    uri.extend(c.query);                                }                                return uri.toString;                            }), html: $(' ', {                               text: VAN.i18n.msg(l).plain                            }) })                       .addClass([ 'wds-button', 'wds-is-squished', 'wds-is-secondary', 'van-tools-button', 'van-is-' + l                       ].join(' '))                        .appendTo(VAN.insights.list[t].$toolbar);                    // Cache button.                    VAN.insights.list[t].$buttons.push($b);                }                // Icon addition.                $t.children('.van-is-' + l)                    .prepend(VAN.wds.icon(c.icon));            }); VAN.insights.$executed.resolve; },       $executed: $.Deferred };

// S:PortabilityDashboard utility extension. VAN.pdash = { init: function { if (               VAN.config.pdash !== true ||                VAN.mw.wgCityId !== '1230494' ||                VAN.mw.wgCanonicalSpecialPageName !== 'PortabilityDashboard'            ) { VAN.pdash.$executed.resolve; return; }           // Table elements. var $p = mw.util.$content.children('.portability-dashboard-table'), $h = $p.find('.headerSort'); // Table sorting deactivation. $h .removeAttr('title').removeAttr('class') .off('click') .children('div').remove; // Add index. $(' ', {               append: $(' ', { 'class': 'tooltip-icon-wrapper', text:   'Rank' }),           }).prependTo('.portability-dashboard-table thead tr'); $p.find('tbody tr').each(function(i) {               $(' ', { text: (i + 1) }).prependTo(this);           }); // Re-sort table. $p.removeClass('jquery-tablesorter').tablesorter; VAN.pdash.$executed.resolve; },       $executed: $.Deferred };

// "You are editing this page without admin" alert. VAN.adminalert = { init: function { if (VAN.config.adminalert !== true) { VAN.adminalert.$executed.resolve; return; }           if (                !['dev', 'communitytest'].includes(VAN.mw.wgDBname) &&                VAN.mw.wgCanonicalNamespace === 'MediaWiki' &&                !/sysop/.test(VAN.mw.wgUserGroups)            ) { $('#ca-edit') .addClass('van-admin-alert') .attr('title', VAN.i18n.msg('adminalert').plain) .find('svg').before(VAN.wds.icon('alert-small').outerHTML); }           VAN.adminalert.$executed.resolve; },       $executed: $.Deferred };

// Module registry. VAN.modules = Object.keys(VAN).filter(function(m) {       return ( typeof VAN[m] === 'object' && // class check VAN[m].init                  // initializer check );   });

// Import styling. importArticle({       type: 'style',        article: 'u:dev:MediaWiki:VanguardTools.css'    });

// Script initializer. mw.loader.using([       'mediawiki.util',        'mediawiki.api',        'jquery.tablesorter',        'ext.bannerNotifications'    ]).then(VAN.init);

}); //TEST /*global mediaWiki */

(function ($, mw) {   'use strict';    var conf = mw.config.get([ 'debug', 'wgAction', 'wgCanonicalSpecialPageName', 'wgNamespaceNumber', 'wgTitle', 'wgUserName' ]),

// variable to not hide existing tags noHideTags = !!((window.dev || {}).profileTags || {}).noHideTags; /**    * Hide tags from the user profile masthead. *     * @todo enable ability conditionally remove tags *     * @param $masthead {jquery.object} A reference to the user profile masthead. */   function hideTags($masthead) { var $tags = $masthead.find('.tag'); // whitelist of which tags not to remove // noRemove = ['staff', 'vstf', 'council', 'authenticated', 'helper']; /*       // this tests if the tag is one of the tags not to remove // however, there's nothing reliable to hook off at the moment // so this is commented out until that's done $tags.each(function {            var $this = $(this),            noRemove.forEach(function (tag) { if (!$this.hasClass(tag)) { $this.remove; }           });        });        */        // @todo remove when above code goes live $tags.hide; }   /**     * Get a class to add to the user tag. *     * @param tag {string} The text of the user tag. * @return {string} A string representing the tag's class. */   function getTagClass(tag) { var tagClass = 'tag-' + tag.toLowerCase.replace(/\s/g, '_'); return tagClass; }   /**     * Get a user tag with a link within. *     * @param $span {jquery.object} A reference to the user tag. * @param tag {string} The user tag to turn into a link. * @return {jquery.object} The linked user tag. */   function getLinkTag($span, tag) { var re = /\[\[(.+?)\|(.+?)\]\]/, match = re.exec(tag), href = mw.util.wikiGetlink(match[1]), text = match[2], $a = $('') .attr('href', href) .css('color', 'inherit') .text(text); $span.addClass(getTagClass(tag)).append($a); return $span; }   /**     * Add a user's tags to their profile masthead. *     * @param tags {array} The tags to add to the user masthead. */   function addProfileTags(tags) { var $masthead = $('.UserProfileMasthead hgroup'), linkTestRe = /\[\[.+?\|.+?\]\]/;

if (!noHideTags) { hideTags($masthead); }       tags.forEach(function (tag) {            var $span = $(' ').addClass('tag');

if (linkTestRe.test(tag)) { $span = getLinkTag($span, tag); } else { $span.addClass(getTagClass(tag)).text(tag); }

// add a space because otherwise the padding isn't right // when existing tags aren't hidden $masthead.append($span, ' '); });       mw.hook('dev.profile-tags').fire;    }    /**     * Get the target user's name from the page title.     *      * @return {string} The user's name.     */    function getUserName {        var user = conf.wgTitle,            target = $.getUrlVar('target'),            parts;        if (conf.wgCanonicalSpecialPageName === 'Contributions') {            parts = user.split('/');            // the username can be specified as Special:Contrbutions/USERNAME            if (parts.length === 2) {                user = parts[1];            // or Special:Contributions?target=USERNAME            } else if (target) {                user = decodeURIComponent(target).replace(/_/g, ' ');            // otherwise default to plain Special:Contributions            } else {                // if no user is specified it defaults to the currently logged in user                // and to your IP if you're logged out user = conf.wgUserName; // wgUserName is null when the user is logged out // default to empty string which won't match anything when we look for a tag if (user === null) { user = ''; }           }        }

return user; }   /**     * Get the user tag configuration for a user. */   function getUserTags { var params = { action: 'raw', title: 'User:IAmaPersonthatExists/ProfileTags' };

// get uncached page in debug mode if (conf.debug) { params.maxage = 0; params.smaxage = 0; }

$.get(mw.util.wikiScript, params, function(data) {

if (!data.length) { return; }           // syntax: // $username | $tag1, $tag2, $tag3 var user = $.escapeRE(getUserName), re = new RegExp('(?:^|\\n)\\s*' + user + '\\s*\\|\\s*(.*?)\\s*(?:\\n|$)'), match = re.exec(data), tags; if (match === null) { return; }           tags = match[1].split(/\s*,\s*/); if (tags.length) { addProfileTags(tags); }       });    }    /**     * Check for the correct environment and load the required dependencies.     */    function init {        // rather than checking the namespace/special page name        // just look for the masthead        // which prevents loading on user subpages and monobook        if ($('.UserProfileMasthead').length) {            // wait for site RL module to load to ensure config is picked up correctly            mw.loader.using(['mediawiki.util', 'site'], getUserTags);        }    }    $(init); }(jQuery, mediaWiki));

//---ChatThing

require(['wikia.window', 'jquery', 'mw'], function(window, $, mw) {   if (mw.config.get('wgCanonicalSpecialPageName') !== 'Chat') {        return;    }    window.ChatToolbox = $.extend({ init: function { this.$menu = $('', {               'class': 'dropdown'            }).insertAfter('#ChatHeader'); new mw.Api.get({               action: 'query',                prop: 'revisions',                titles: [                    'User:IAmaPersonthatExists/Chat-toolbox',                    'User:IAmaPersonthatExists/Custom-Chat-toolbox'                ].join('|'),                rvprop: 'content',                indexpageids: true            }).done($.proxy(this.callback, this)); },       callback: function(data) { if (data.error) { console.error('API error:', data.error); return; }           var q = data.query, pageids = q.pageids, id = pageids[0]; if (id === '-1') { id = pageids[1]; if (id === '-1') { return; }           }            var content = q.pages[id].revisions[0]['*']; this.render(this.parse(content.split(/\r\n|\n|\r/))); importArticle({               type: 'script',                article: 'MediaWiki:Chat-toolbox.js'            }); },       trimPart: function(part) { return part.trim; },       parse: function(lines) { var options = []; for (var i = 0; i < lines.length; i++) { var line = lines[i].trim; if (line.length === 0 || line.charAt(0) !== '*') { continue; }               var parts = line .substring(1) .split('|') .map(this.trimPart), item = { 'class': parts[0] .replace(/[^a-z0-9\s]/gi, '') .replace(/[_\s]/g, '') .toLowerCase, contents: parts[0], url: mw.util.getUrl(parts[0]) };               if (parts.length === 2) { item.url = mw.util.getUrl(parts[0]); item.contents = parts[1]; } else if (parts.length === 3) { item.url = '#' + mw.util.wikiUrlencode(parts[1]); item.contents = parts[2]; }               options.push(item); }           return options; },       renderItem: function(item) { var opts = { href: item.url, text: item.contents };           if (item.url.charAt(0) !== '#') { opts.target = '_blank'; }           return $('', {                'class': item['class']            }).append($('', opts)); },       render: function(parsed) { this.$menu.append(parsed.map(this.renderItem, this)) .find('> li:first-child') .addClass('active') .find('> a') .contents .unwrap; }   }, window.ChatToolbox);    importArticles({ type: 'style', articles: [ 'u:dev:MediaWiki:ChatToolbox.css', 'MediaWiki:Chat-toolbox.css' ]   });    mw.loader.using('mediawiki.api')        .then($.proxy(window.ChatToolbox.init, window.ChatToolbox)); });

require(['wikia.window', 'jquery', 'mw'], function(window, $, mw) {   if (mw.config.get('wgCanonicalSpecialPageName') !== 'Chat') {        return;    }    window.ChatToolbox = $.extend({ init: function { this.$menu = $('', {               'class': 'dropdown'            }).insertAfter('#ChatHeader'); new mw.Api.get({               action: 'query',                prop: 'revisions',                titles: [                    'MediaWiki:Chat-toolbox',                    'MediaWiki:Custom-Chat-toolbox'                ].join('|'),                rvprop: 'content',                indexpageids: true            }).done($.proxy(this.callback, this)); },       callback: function(data) { if (data.error) { console.error('API error:', data.error); return; }           var q = data.query, pageids = q.pageids, id = pageids[0]; if (id === '-1') { id = pageids[1]; if (id === '-1') { return; }           }            var content = q.pages[id].revisions[0]['*']; this.render(this.parse(content.split(/\r\n|\n|\r/))); importArticle({               type: 'script',                article: 'MediaWiki:Chat-toolbox.js'            }); },       trimPart: function(part) { return part.trim; },       parse: function(lines) { var options = []; for (var i = 0; i < lines.length; i++) { var line = lines[i].trim; if (line.length === 0 || line.charAt(0) !== '*') { continue; }               var parts = line .substring(1) .split('|') .map(this.trimPart), item = { 'class': parts[0] .replace(/[^a-z0-9\s]/gi, '') .replace(/[_\s]/g, '') .toLowerCase, contents: parts[0], url: mw.util.getUrl(parts[0]) };               if (parts.length === 2) { item.url = mw.util.getUrl(parts[0]); item.contents = parts[1]; } else if (parts.length === 3) { item.url = '#' + mw.util.wikiUrlencode(parts[1]); item.contents = parts[2]; }               options.push(item); }           return options; },       renderItem: function(item) { var opts = { href: item.url, text: item.contents };           if (item.url.charAt(0) !== '#') { opts.target = '_blank'; }           return $('', {                'class': item['class']            }).append($('', opts)); },       render: function(parsed) { this.$menu.append(parsed.map(this.renderItem, this)) .find('> li:first-child') .addClass('active') .find('> a') .contents .unwrap; }   }, window.ChatToolbox);    importArticles({ type: 'style', articles: [ 'u:dev:MediaWiki:ChatToolbox.css', 'MediaWiki:Chat-toolbox.css' ]   });    mw.loader.using('mediawiki.api')        .then($.proxy(window.ChatToolbox.init, window.ChatToolbox)); });

window.massEditConfig = { editInterval: 1500 }; // Edit Bar if (mwCustomEditButtons.length) { mwCustomEditButtons[mwCustomEditButtons.length] = { "imageFile": "//images.wikia.com/central/images/c/c8/Button_redirect.png", "speedTip": "Redirect", "tagOpen": "#REDIRECT [" + "[", "tagClose": "]]", "sampleText": "Insert text" };	mwCustomEditButtons[mwCustomEditButtons.length] = { "imageFile": "//images.wikia.com/central/images/c/c9/Button_strike.png", "speedTip": "Strike", "tagOpen": " ", "tagClose": " ", "sampleText": "Strike-through text" };	mwCustomEditButtons[mwCustomEditButtons.length] = { "imageFile": "//images.wikia.com/central/images/1/13/Button_enter.png", "speedTip": "Line break", "tagOpen": " ", "tagClose": "", "sampleText": "" };	mwCustomEditButtons[mwCustomEditButtons.length] = { "imageFile": "//images.wikia.com/central/images/7/74/Button_comment.png", "speedTip": "Comment visible only for editors", "tagOpen": "", "sampleText": "Insert comment here" }; } // Special Page test if(wgNamespaceNumber == -1 && wgTitle == "Test") { document.title = 'TEST - ' + wgSiteName; if (window.skin == "oasis") { document.getElementById("PageHeader").getElementsByTagName("h1")[0].textContent = "Test"; //Oasis skin title } else if (window.skin == "monobook") { document.getElementById("firstHeading").textContent = "Test"; //Monobook skin title }       var content = document.getElementById("mw-content-text"); content.innerHTML = 'Hey!'; }

//-UserPage AutoCreate window.FCButtons = [ {       label: 'Create userpage', target: 'User:IAmaPersonthatExists', summary: 'Creating Userpage', content: '', alwaysDisplay: true, }, ];

//MassEdit

require(["jquery", "mw", "wikia.window", "wikia.ui.factory"],       function (jQuery, mw, wk, ui) {    "use strict";

if (jQuery("#massEdit-li").exists || window.isMassEditLoaded) { return; }   window.isMassEditLoaded = true;

if (!window.dev || !window.dev.i18n) { wk.importArticle({           type: "script",            article: "u:dev:MediaWiki:I18n-js/code.js"        }); }

// Constant for future testing const DEBUG = false;

//I18n-js var $i18n;

/**    * @class MassEdit * @classdesc The central MassEdit class */   var MassEdit = { meta: { author: "User:Eizen", created: "05/02/17", lastEdit: "03/09/18", version: "2.4.4" },       hasRights: new RegExp(["(users|*|sysop|content-moderator|bot|bot-global" + "|staff|vstf|helper|global-discussions-moderator" + "|content-volunteer|wiki-manager)"].join("")).test(wk.wgUserGroups.join(" ")), legalChars: new RegExp("^[" + wk.wgLegalTitleChars + "]*$"),

/**        * @method addLogEntry * @description Method allows for quick adding of a MassEdit log entry *             to the appropriate text field. * @param {String} $key - The name of the JSON field * @returns {void} */       addLogEntry: function ($key) { jQuery("#massEdit-log").prepend($i18n.msg($key).escape + " "); },

/**        * @method addLogEntry * @description "Overloaded" two-parameter variation of the method above *             that accepts a JSON key and an entry substitute for $1 *             or $2. * @param {String} $key - The name of the JSON field * @param {String} $entry - Name of the page to substitute * @returns {void} */       addLogEntry: function ($key, $entry) { jQuery("#massEdit-log").prepend(               $i18n.msg($key, $entry).escape + " "); },

/**        * @method constructItem * @description Method returns a completed *             representing the menu link item. Is comprised of a        *              link inside a list item. * @param {String} $text - Text to be displayed in the item and title * @returns {String} */       constructItem: function ($text) { return mw.html.element("li", {               "class": "overflow",                "id": "massEdit-li"            }, new mw.html.Raw( mw.html.element("a", {                   "id": "massEdit-a",                    "href": "#",                    "title": $text                }, $text) ));       },

/**        * @method isLegalPage * @description Utility function used to test if inputted page name *             matches the legal characters regex. Returns a boolean *             flag depending on result. * @param {String} $page - Inputted page name * @returns {boolean} */       isLegalPage: function ($page) { if (!this.legalChars.test($page)) { jQuery("#massEdit-modal-form")[0].reset; this.addLogEntry("modalSecurity"); return false; } else { return true; }       },

/**        * @method displayModal * @description Method constructs and displays the main user interface. *             Injects custom CSS prior to construction and handles all *             button click events. * @param {String} $modalHTML - The modal HTML layout * @returns {void} */       displayModal: function ($modalHTML) { var that = this;

mw.util.addCSS(               ".massEdit-menu," +                ".massEdit-textbox {" +                    "width: 100%;" +                    "padding: 0;" +                "}" +                ".massEdit-textarea {" +                    "height: 50px;" +                    "width: 100%;" +                    "padding: 0;" +                    "overflow: auto;" +                "}" +                "#massEdit-log {" +                    "height: 55px;" +                    "width: 100%;" +                    "border: 1px solid;" +                    "font-family: monospace;" +                    "background: #fff;" +                    "color: #aeaeae;" +                    "overflow: auto;" +                    "padding:0;" +                "}"            );

ui.init(["modal"]).then(function (modal) {               var config = {                    vars: {                        id: "massEdit-modal",                        size: "medium",                        title: $i18n.msg("itemTitle").escape,                        content: $modalHTML,                        buttons: [{                            vars: {                                value: $i18n.msg("buttonCancel").escape,                                classes: ["normal", "primary"],                                data: [{                                    key: "event",                                    value: "cancel"                                }]                            }                        }, {                            vars: {                                value: $i18n.msg("buttonClear").escape,                                classes: ["normal", "primary"], data: [{ key: "event", value: "clear" }]                           }                        }, {                            vars: { value: $i18n.msg("buttonSubmit").escape, classes: ["normal", "primary"], data: [{ key: "event", value: "submit" }]                           }                        }]                    }                };

modal.createComponent(config, function (massEditModal) {                   massEditModal.bind("cancel", function  { massEditModal.trigger("close"); });

massEditModal.bind("clear", function {                        jQuery("#massEdit-modal-form")[0].reset;                    });

massEditModal.bind("submit", function {                        that.main;                    });

massEditModal.show; });           });

// Disable replacements menu depending on current selected option jQuery(document).on("change", "#massEdit-actionType", function {                if (jQuery("#massEdit-actionType").val === "replace") {                    jQuery("#massEdit-replaceThis-value")                        .prop("disabled", false);                } else {                    jQuery("#massEdit-replaceThis-value")                        .prop("disabled", true);                }            }); },

/**        * @method getContent * @description This method retrieves the content of the inputted page, *             including information about its time of creation and *             relevant timestamp info. Used exclusively by the find *             and dropdown option. * @param {String} $action - Editing action (prepend, append, replace) * @param {String} $editSummary - Edit summary * @param {String} $page - The page in question * @param {String} $newContent - New text to replace the target * @param {String} $replace - The target to be replaced in the callback * @param {function} callback - The callback handler */       getContent: function ($action, $editSummary, $page, $newContent,                $replace, callback) {

var that = this; this.api.get({               action: "query",                prop: "info|revisions",                intoken: "edit",                titles: $page,                rvprop: "content|timestamp",                rvlimit: "1",                indexpageids: "true",                format : "json"            }).done(function ($data) {                if (!$data.error) {                    callback(           // handleContent that,          // this $action,       // "replace" $editSummary,  // "#massEdit-summary-value" $data,         // $data $page,         // $pagesArray[$counter] $newContent,   // "#massEdit-content-value" $replace       // "#massEdit-replaceThis-value" );               }            });        },

/**        * @method handleContent * @description Callback function for. Sifts *             through included data and passes relevant bits to the *               method. Used exclusively by the *             find and replace dropdown option. * @param {this} that - Scope variable * @param {String} $action - Editing action (prepend, append, replace) * @param {String} $editSummary - Edit summary * @param {JSON} $data - Passed data from * @param {String} $page - Specific page in question * @param {String} $newContent - New text to replace the target * @param {String} $replaceThis - Text to be replaced by $newContent * @returns {void} */       handleContent: function (that, $action, $editSummary, $data, $page,                $newContent, $replaceThis) {

// Check if page actually exists if (Object.keys($data.query.pages)[0] === "-1") { jQuery("#massEdit-modal-form")[0].reset; that.addLogEntry("noSuchPage", $page); return; }

var $newText; var $result = $data.query.pages[Object.keys($data.query.pages)[0]]; var $text = $result.revisions[0]["*"]; var $timestamp = $result.revisions[0].timestamp; var $starttimestamp = $result.starttimestamp; var $token = $result.edittoken;

// Replace all instances of chosen text with inputted new text $newText = $text.split($replaceThis).join($newContent);

// Check if old & new revisions are identical in content if ($newText === $text) { jQuery("#massEdit-log").prepend(                   $i18n.msg("noMatch", $replaceThis, $page).escape +                    " "                ); } else { that.editPage(that, $page, $newText, $action, $editSummary,                   $timestamp, $starttimestamp, $token); }       },

/**        * @method editPage * @description The one-size-fits-all editing handler for use by all *             three main MassEdit functions. Takes several different *             numbers of input parameters depending on the action to         *              be taken by the handler. * @param {this} that - Scope variable * @param {String} $page - The page to be edited * @param {String} $content - The content to be added to the page * @param {String} $action - Editing action (prepend, append, replace) * @param {String} $editSummary - Edit summary * @param {String} $timestamp - Optional, for replace option only * @param {String} $starttimestamp - Optional, for replace option only * @param {String} $token - Optional, for replace option only * @returns {void} */       editPage: function (that, $page, $content, $action, $editSummary,                $timestamp, $starttimestamp, $token) {

// Edit without editing; for testing purposes if (DEBUG) { that.addLogEntry("editSuccess", $page); return; }

// Default base properties var $params = { action: "edit", minor: true, bot: true, title: $page, summary: $editSummary };

// Set additional Object properties depending on action to be taken switch ($action) { case "prepend": $params.prependtext = $content; $params.token = mw.user.tokens.get("editToken"); break; case "append": $params.appendtext = $content; $params.token = mw.user.tokens.get("editToken"); break; case "replace": $params.text = $content; $params.basetimestamp = $timestamp; $params.startimestamp = $starttimestamp; $params.token = $token; break; }

that.api.post($params).done(function ($data) {               jQuery("#massEdit-modal-form")[0].reset;                if (!$data.error) {                    that.addLogEntry("editSuccess", $page);                } else {                    that.addLogEntry("editFailure", $page);                }            }); },

/**        * @method getNamespaceMembers * @description As the name implies, this method returns the results of        *              a request for an inputted namespace's associated page *             contents. * @param {String} $namespace - Number of the namespace in question * @return {JSON} */       getNamespaceMembers: function ($namespace) { return jQuery.ajax({               type: "GET",                url: mw.util.wikiScript("api"),                data: {                    action: "query",                    list: "allpages",                    aplimit: "max",                    apnamespace: $namespace,                    format: "json"                }            }); },

/**        * @method getCategoryMembers * @description As the name implies, this method returns the results of        *              a request for an inputted category's associated page *             contents. * @param {String} $category - Name of the category in question * @return {JSON} */       getCategoryMembers: function ($category) { return jQuery.ajax({               type: "GET",                url: mw.util.wikiScript("api"),                data: {                    action: "query",                    list: "categorymembers",                    cmtitle: $category,                    cmprop: "title",                    cmdir: "desc",                    cmlimit: "max",                    format: "json"                }            }); },

/**        * @method membersHandler * @description This method, inspired by Java-style reflection, is a        *              general purpose handler for use by both namespace and *             category bulk editing. The method accepts either the *             <tt>getCategoryMembers</tt> or         *              <tt>getNamespaceMembers<tt> methods as the requests of         *              choice, running basically the same process with the *             results of each once all calls have been completed. *

*

*             Basically, once the calls have been made, the method *             assembles all the pages from the request results and *             pushes them into an array for processing by the *             <tt>actionHandler</tt> method. * @param {String[]} $inputArray * @param {String} $newContent * @param {String} $toReplace * @param {int} $actionIndex * @param {String} $action * @param {String} $editSummary * @param {function} getMembers * @param {String} $queryProperty * @returns {void} */       membersHandler: function ($inputArray, $newContent, $toReplace,                $actionIndex, $action, $editSummary, getMembers,                $queryProperty) {

var that = this; var $members; var $requests; var $arguments; var $defer; var $data;

$members = []; $requests = []; $arguments = [];

$inputArray.forEach(function ($member) {               if ( $queryProperty === "categorymembers" && !$member.startsWith("Category:") ) {                   $member = "Category:" + $member;                }

if (                   ( // If is category-based and member is legal $queryProperty === "categorymembers" && that.isLegalPage($member) ) ||                   ( // If is namespace-based and member is integer $queryProperty === "allpages" && $member.match(/^[0-9]+$/) !== null )               ) {                    $members.push($member); $requests.push(getMembers($member)); }           });

if (               !$members.length ||                !$requests.length ||                $members.length !== $requests.length            ) { return; }

$inputArray = []; $defer = jQuery.when.apply(jQuery, $requests);

$defer.done(function {                if ($requests.length === 1) {                    $arguments.push(arguments);                } else {                    $arguments = Array.prototype.slice.call(arguments);                }

jQuery.each($arguments, function ($index, $results) {                   if ($results[1] === "success") {                        $data = $results[0].query[$queryProperty];

if ($data === undefined || $data.length === 0) { that.addLogEntry("noSuchPage", $members[$index]); return; }

$data.forEach(function ($page) {                           $inputArray.push($page.title);                        }); }               });

if ($inputArray.length) { that.actionHandler($inputArray, $newContent, $toReplace,                       $actionIndex, $action, $editSummary); }           });        },

/**        * @method actionHandler * @description This function invokes methods based on user's desired *             action. If the user is not in the proper user rights *             group, access is denied. If no action is selected, the *             user is prompted to select an action. *             <tt>setInterval</tt> is employed to ensure that the *             script does not make too many consecutive content GETs *             or edit POSTs; replaces <tt>forEach</tt> *             implementation. *

*

*             Addition of global pages-based find-and-replace option *             replaces old find-and-delete option, and now checks for *             cases of empty pages or empty target text. * @param {String[]} $inputArray * @param {String} $newContent * @param {String} $toReplace * @param {int} $actionIndex * @param {String} $action * @param {String} $editSummary * @returns {void} */       actionHandler: function ($inputArray, $newContent, $toReplace,                $actionIndex, $action, $editSummary) {

var that = this; var $counter = 0; var $editInterval;

switch ($actionIndex) { case 0: // No action selected this.addLogEntry("noOptionSelected"); break; case 1: case 2: // Edit methods (prepend and append) this.addLogEntry("loading");

$editInterval = setInterval(function {                    if (that.isLegalPage($inputArray[$counter])) {                        that.editPage(that, $inputArray[$counter], $newContent, $action, $editSummary);                   }                    $counter++;                    if ($counter === $inputArray.length) {                        clearInterval($editInterval);                    }                }, that.config.editInterval); break; case 3: // Find and replace this.addLogEntry("loading");

$editInterval = setInterval(function {                    if (that.isLegalPage($inputArray[$counter])) {                        that.getContent($action, $editSummary, $inputArray[$counter], $newContent, $toReplace, that.handleContent);                   }

$counter++; if ($counter === $inputArray.length) { clearInterval($editInterval); }               }, that.config.editInterval);                break;            }        },

/**        * @method main * @description The main method handles the collection of user input *             from the GUI modal and tests against a series of base *             cases to ensure ill-formed or illegitimate input is not *             included in the program's operations. Furthermore, the *             new category-based function necessitated the removal of         *              some old code used to execute different actions (i.e.         *              prepend, append, etc.) to a different method, namely *             <tt>actionHandler</tt>. The main method now handles the *             acquisition of category members from user input cats, *             passing the array of pages to the handler above. *

*

*             Addition of global pages-based find-and-replace option *             replaces old find-and-delete option, and now checks for *             cases of empty pages or empty target text. * @returns {void} */       main: function  { var that = this;

// Values of textareas var $newContent = jQuery("#massEdit-content-value")[0].value; var $toReplace = jQuery("#massEdit-replaceThis-value")[0].value; var $pagesInput = jQuery("#massEdit-pages-value")[0].value; var $editSummary = jQuery("#massEdit-summary-value")[0].value; var $pagesArray = $pagesInput.split(/[\n]+/);

// Dropdown menu var $actionIndex = jQuery("#massEdit-actionType")[0].selectedIndex; var $action = jQuery("#massEdit-actionType").val; var $typeIndex = jQuery("#massEdit-contentType")[0].selectedIndex;

// Is not in the proper rights group if (!this.hasRights) { jQuery("#massEdit-modal-form")[0].reset; this.addLogEntry("modalUserRights"); return;

// No pages included } else if (!$pagesInput) { this.addLogEntry("noPages"); return;

// Is either append/prepend with no content input included } else if ($action !== "replace" && !$newContent) { this.addLogEntry("noContent"); return;

// Is find-and-replace with no target content included } else if ($action === "replace" && !$toReplace) { this.addLogEntry("noTarget"); return;

// If user forgot to select dropdown options (no reset b/c annoying) } else if ($actionIndex === 0 || $typeIndex === 0) { this.addLogEntry("noOptionSelected"); return;

// If edit summary is greater than permitted max of 800 characters } else if ($editSummary.length > 800) { this.addLogEntry("overlongSummary"); return; }

switch ($typeIndex) { case 1: // Loose pages that.actionHandler($pagesArray, $newContent, $toReplace,                   $actionIndex, $action, $editSummary); break; case 2: // Categories that.membersHandler($pagesArray, $newContent, $toReplace,                   $actionIndex, $action, $editSummary,                    that.getCategoryMembers, "categorymembers"); break; case 3: // Namespaces that.membersHandler($pagesArray, $newContent, $toReplace,                   $actionIndex, $action, $editSummary,                    that.getNamespaceMembers, "allpages"); break; }       },

/**        * @method init * @description Method initializes the program, assembling the toolbar *             link and handling click events. Config options are set *             per user input or the defaults. * @param {JSON} $lang - I18n-js content * @returns {void} */       init: function ($lang) { var that = this;

$i18n = $lang; $i18n.useContentLang;

this.api = new mw.Api; this.config = jQuery.extend({               editInterval: 1500            }, window.massEditConfig);

$i18n.useUserLang;

/**            * Handle removal of   right for bots/users * Current rate limit for default user/sysop/etc. is 40 edits/minute * Current rate limit for bot (not bot-global) is 80 edits/minute * @see <a href="https://git.io/fA4Jk">SUS-4775</a> * @see <a href="https://git.io/fA4eQ">VariablesBase.php</a> */           if (                jQuery.inArray("bot", wk.wgUserGroups) !== -1 &&                this.config.editInterval < 750            ) { this.config.editInterval = 750; // Reset to max 80 edits/minute } else if (               jQuery.inArray("user", wk.wgUserGroups) !== -1 &&                this.config.editInterval < 1500            ) { this.config.editInterval = 1500; // Reset to max 40 edits/minute }

var $modalHTML = "<form id='massEdit-modal-form' class='WikiaForm '>" + " " +                   " " + $i18n.msg("modalSelect").escape + " " +                       "<select size='1' id='massEdit-actionType'" + "class='massEdit-menu' name='action'>" + "<option selected=''>" + $i18n.msg("modalSelect").escape + " " +                           "<option value='prepend'>" + $i18n.msg("dropdownPrepend").escape + " " +                           "<option value='append'>" + $i18n.msg("dropdownAppend").escape + " " +                           "<option value='replace'>" + $i18n.msg("dropdownReplace").escape + " " +                       " " +                        " " +                    " " +                    " " +                    " " + $i18n.msg("modalContentType").escape + " " +                       "<select size='1' id='massEdit-contentType'" + "class='massEdit-menu' name='action'>" + "<option selected=''>" + $i18n.msg("modalContentType").escape + " " +                           "<option value='pages'>" + $i18n.msg("dropdownPages").escape + " " +                           "<option value='categories'>" + $i18n.msg("dropdownCategories").escape + " " +                           "<option value='namespaces'>" + $i18n.msg("dropdownNamespaces").escape + " " +                       " " +                        " " +                    " " +                    " " +                    " " + $i18n.msg("modalContentTitle").escape + " " +                       "<textarea id='massEdit-content-value' " + "class='massEdit-textarea' placeholder='" + $i18n.msg("modalContentPlaceholder").escape + "'/>" +                       " " +                    " " +                    " " +                    " " + $i18n.msg("modalReplaceTitle").escape + " " +                       "<textarea id='massEdit-replaceThis-value' " + "class='massEdit-textarea' placeholder='" + $i18n.msg("modalReplacePlaceholder").escape + "' disabled/>" + " " +                   " " +                    " " +                    " " + $i18n.msg("modalPagesTitle").escape + " " +                       "<textarea id='massEdit-pages-value' " + "class='massEdit-textarea' placeholder='" + $i18n.msg("modalPagesPlaceholder").escape + "'/>" +                       " " +                    " " +                    " " +                    " " + $i18n.msg("modalSummaryTitle").escape + " " +                       "<input type='textbox' id='massEdit-summary-value'" + "class='massEdit-textbox' />" + " " +                   " " +                " " +                " " +                " " +            " " +            " " + $i18n.msg("modalLog").escape + " " + " " +           " ";

var $tbElement = this.constructItem($i18n.msg("itemTitle").plain); jQuery($tbElement).prependTo("#my-tools-menu").click(function {                that.displayModal($modalHTML);            }); }   };

mw.hook("dev.i18n").add(function ($i18n) {       jQuery.when( $i18n.loadMessages("MassEdit"), mw.loader.using(["mediawiki.util", "mediawiki.api"]) ).done(jQuery.proxy(MassEdit.init, MassEdit));   }); });