Community Central
Community Central

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

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
//__NOWYSIWYG__ <source lang="javascript">
 
/* Imports */
importArticles({
    type: 'script',
    articles: [
        'u:dev:AjaxBatchDelete.js',
        'u:dev:AjaxDelete/code.js',
        'u:dev:AjaxEdit/code.js',
        'u:dev:AjaxUndo/code.js',
        'u:dev:AnalyticsShortcut.js',
        'u:dev:BlogLink/code.js',
        'u:dev:CategoryQuickRemove.js',
        'u:dev:CommentPreview/code.js',
        'u:dev:EditConflictAlert/code.js',
        'u:dev:FindAndReplace/code.js',
        'u:dev:GalleryCaptions/code.js',
        'u:dev:ManageReferences/code.js',
        'u:dev:MassBlock/code.js',
        'u:dev:MassEdit/code.js',
        'u:dev:MobileEditor.js',
        'u:dev:ModernLightbox.js',
        'u:dev:ModernProfile/EditButton.js',
        'u:dev:Nuke/code.js',
        'u:dev:NullEditButton/code.js',
        'u:dev:PurgeButton/code.js',
        'u:dev:QQX/code.js',
        'u:dev:RandomPageShortcut/code.js',
        'u:dev:RedirectManagement/code.js',
        'u:dev:RefreshThreads/code.js',
        'u:dev:RevealAnonIP/code.js',
        'u:dev:Rollback/code.js',
        'u:dev:SandboxLink/code.js',
        'u:dev:SandboxTab/code.js',
        'u:dev:SeeMoreActivityButton/code.js',
        'u:dev:UserActivityTab/code.js',
        'u:dev:View Raw/code.js',
        'u:dev:VSTFReport.js',
        'u:dev:WallGreetingButton/code.js',
        'u:dev:WHAM/code.2.js',
        'u:dev:WLHEditLinks/code.js',
    ]
});
 
//Change text direction in arabic wikis
if ( mw.config.get('wgContentLanguage') === 'ar' ) mw.util.addCSS( 'body { direction: rtl } ' );
 
//RemoveBlueOutline
/* It basically removes unnecessary blue outlines except when tabbing */
 
importArticles({
    type: 'style',
    articles: [
        'u:dev:RemoveBlueOutline.css'
    ]
});
function handleFirstTab(e) {
    if (e.keyCode === 9) { // the "I am a keyboard user" key
        document.body.classList.add('user-is-tabbing');
        window.removeEventListener('keydown', handleFirstTab);
    }
}
 
window.addEventListener('keydown', handleFirstTab);
 
var didScroll;
var lastScrollTop = 0;
var delta = 5;
var navbarHeight = $('div#globalNavigation').outerHeight();
 
$(window).scroll(function(event){
    didScroll = true;
});
 
setInterval(function() {
    if (didScroll) {
        hasScrolled();
        didScroll = false;
    }
}, 250);
 
function hasScrolled() {
    var st = $(this).scrollTop();
 
    if(Math.abs(lastScrollTop - st) <= delta)
        return;
 
    if (st > lastScrollTop && st > navbarHeight){
        $('div#globalNavigation').removeClass('wds-global-navigation').addClass('wds-global-navigation-up');
    } else {
        if(st + $(window).height() < $(document).height()) {
            $('div#globalNavigation').removeClass('wds-global-navigation-up').addClass('wds-global-navigation');
        }
    }
 
    lastScrollTop = st;
}
 
if (mw.config.get("wgUserGroups").indexOf('sysop') > -1) {
    window.massCategorizationDelay = 1000;
    importArticle({
        type: 'script',
        article: 'u:dev:MediaWiki:MassCategorization/code.js'
    });
}
 
if (typeof(namespaceNotifyWiki) == "undefined") {     var namespaceNotifyWiki = 'vstf'; } if (typeof(namespaceNotifyNamespace) == "undefined") {     var namespaceNotifyNamespace = 114; } if (typeof(namespaceNotifyScriptLocation) == "undefined") {     var namespaceNotifyScriptLocation = "ul.tools"; }   function pagesUpdate() {       $('head').append('<script src="//' + namespaceNotifyWiki + '.wikia.com/api.php?action=query&list=recentchanges&rclimit=1&rcprop=title|comment|ids|user&rctype=edit&rcnamespace=' + namespaceNotifyNamespace + '&format=json&callback=getData" onload="this.parentNode.removeChild(this);">'); }   function getData(dis){     $('#NamespaceNotify').html('<a id="NSNotifyLink" href="//' + namespaceNotifyWiki + '.wikia.com/wiki/?diff=' + dis.query.recentchanges[0].revid + '" title="“' + dis.query.recentchanges[0].comment + '”">' + dis.query.recentchanges[0].user + ' changed ' + dis.query.recentchanges[0].title + '</a>')   };   $(document).ready(function(){     if (mw.config.get('skin') == "oasis") {         $(namespaceNotifyScriptLocation).append('<li id="NamespaceNotify"></li>');         $('head').append('<style type="text/css">a#NSNotifyLink:visited {color:#77F !important;}</style>');     } else if (mw.config.get('skin') == "monobook") {         $('#p-personal .pBody ul:first-child').prepend('<li id="NamespaceNotify" style="text-transform:none;color:#FF8C00"></li>');         $('head').append('<style type="text/css">#p-personal li a#NSNotifyLink {color:#F00 !important;} #p-personal li a#NSNotifyLink:visited {color:#77F !important;}</style>');     }           pagesUpdate(); })
 
/* <nowiki>
 * 
 * @module                  FANSUN.js
 * @description             Script for official wiki dark theming.
 * @author                  Speedit
 * @version                 1.2.10
 * @license                 CC-BY-SA 3.0
 * @notes                   Install FANSUN.css stylesheet(s) on the official
                            wiki(s) to use this script.
 * 
 */
;(function (window, mw, $) {
 
    // Double-run protection
    window.dev = window.dev || {};
    if (window.dev.dark) {
        return;
    }
    window.dev.dark = { cache: [] };
 
    /**
     * @class               FANSUN
     * @classdesc           The main FANSUN class. Contains script logic
     *                      for post-render dark theming.
     */
    function FANSUN () {
        // Scoping to official wikis + FANSUN CSS import
        this.active =
            this.wikis.indexOf(mw.config.get('wgDBname')) > -1 &&
            $(document.body).css('color').match(/\d+/g).slice(0, 3)
                .map(Number).reduce(this.add) > 459;
        if (!this.active) {
            return;
        }
        // Override sassParams
        mw.config.set('wgSassParams', this.sassParams);
        $.extend(window.sassParams, this.sassParams);
        // Dark theme class
        $(document.body).addClass(window.dev.colors
            ? 'oasis-dark-theme ' +
              'menu-dark ' +
              'page-dark'
            : 'oasis-dark-theme'
        ).removeClass('menu-bright page-bright');
        // Editor dark theme
        if (this.darkHighlight.bool) {
            $(document.body).on('animationstart.fansun', $.proxy(this.darkHighlight, this));
        }
        // Override post-render MediaWiki imports
        $([document.head, document.body]).each($.proxy(this.postRender, this));
    }
 
    /**
     * Helper method for numeric addition.
     * @method          add
     */
    FANSUN.prototype.add = function(a, c) {
        return +a+c;
    };
 
    /**
     * SASS parameters for use in JavaScript.
     * @type            {Object.<String>}
     */
    FANSUN.prototype.sassParams = {
        'background-dynamic': 'false',
        'background-image': '',
        'background-image-height': '801',
        'background-image-width': '1700',
        'color-body': '#2c343d',
        'color-body-middle': '#2c343d',
        'color-buttons': '#00b7e0',
        'color-community-header': '#404a57',
        'color-header': '#404a57',
        'color-links': '#00c8e0',
        'color-page': '#39424d',
        'oasisTypography': 1,
        'page-opacity': '100',
        'widthType': 0,
        'wordmark-font': 'cpmono'
    };
 
    /**
     * Database names for official wikis.
     * @type            {Array.<String>}
     */
    FANSUN.prototype.wikis = [
        'wikia',
        'ca',
        'de',
        'es',
        'fiwikia',
        'frfr',
        'it',
        'ja',
        'kowikia',
        'nlwikia',
        'plwikia',
        'ptcommunity',
        'ruwikia',
        'vicommunity',
        'zh',
        'dev',
        'infobox',
        'vstf',
        'communitycouncil'
    ];
 
    /**
     * Dark highlighting in Source mode.
     * @method          darkHighlight
     * @see             https://kocka.wikia.com/index.php?title=MediaWiki:Minimalism/VSTF.js&action=raw
     * @see             https://github.com/Wikia/app/blob/dev/extensions/wikia/EditPageLayout/js/plugins/WikitextSyntaxHighlighterQueueInit.js
     */
    FANSUN.prototype.darkHighlight = function(e) {
        if (e.originalEvent.animationName !== this.darkHighlight.animation) {
            return;
        }
        $(document.body).off('animationstart.fansun');
        setTimeout($.proxy(require, null, ['WikiTextSyntaxHighlighter'], this.darkHighlight.syntax, 0));
    };
    FANSUN.prototype.darkHighlight.bool = (
        mw.config.get('wgIsEditPage') &&
        typeof window.ace !== 'object' &&
        typeof window.RTE !== 'object'
    );
    FANSUN.prototype.darkHighlight.syntax = function(sh) {
        sh.reset();
        var $t = $('#wpTextbox1'),
            $p = $t.parent();
        $p.parent().children('#toolbar').after($t);
        $p.remove();
        sh.init($t.get(0), WikiaEditor.plugins.syntaxhighlighterqueueinit.prototype.initDarkThemeColors());
    };
    FANSUN.prototype.darkHighlight.animation = 'fansun__textbox';
 
    /**
     * Post render MediaWiki import replacement.
     * @method          postRender
     */
    FANSUN.prototype.postRender = function(i, docNode) {
        var o = new MutationObserver($.proxy(function(M) {
            M.forEach($.proxy(function(R) {
                [].slice.call(R.addedNodes).filter(this.isSASS).forEach($.proxy(function(s) {
                    var url = s.getAttribute('href');
 
                    if (!window.dev.dark.cache.includes(url)) {
                        Object.keys(this.sassUtil).forEach($.proxy(function(mode) {
                            $.proxy(this.sassUtil[mode], this)(mode, url, s);
                        }, this));
                    }
                }, this));
            }, this));
        }, this));
        o.observe(docNode, { childList: true });
    };
 
    /**
     * String caching for SASS.
     * @type            {Object.<String>}
     */
    FANSUN.prototype.cache = {
        '__am': '',
        '__load': ''
    };
 
    /**
     * SASS filter for CSS imports.
     * @method          isSass
     */
    FANSUN.prototype.isSASS = function(n) {
        return (
            n.nodeName.toLowerCase() === 'link' &&
            n.getAttribute('rel') === 'stylesheet' &&
            n.getAttribute('href').indexOf('sass') > -1 &&
            n.getAttribute('href').indexOf('background-dynamic') > -1
        );
    };
 
    /**
     * SASS filter for CSS imports.
     * @member          sassUtil
     */
    FANSUN.prototype.sassUtil = {};
 
    /**
     * AssetManager imports.
     * @method      __am
     */
    FANSUN.prototype.sassUtil.__am = function(mode, url, s) {
        if (url.indexOf(mode) === -1) {
            return;
        }
 
        // Array processing for AssetManager link
        // https://slot1-images.wikia.nocookie.net/__am/<StyleVersion>/sasses/<mwSassParams>/<scss>
        var url_a = url.split('/'),
            sass_i = +url_a.indexOf(mode)+3,
            sass_s_new;
        // SASS parameter-string conversion
        if (this.cache[mode].length > 0) {
            sass_s_new = this.cache[mode];
        } else {
            sass_s_new = encodeURIComponent($.param(this.sassParams));
            // Caching for our new SASS string
            this.cache[mode] = this.cache.length > 0 ?
                this.cache[mode] :
                sass_s_new;
        }
        // URL insertion for new SASS parameters
        url_a.splice(sass_i, 1, sass_s_new);
        var url_new = url_a.join('/');
        // URL setter
        window.dev.dark.cache.push(url_new);
 
        var newStyle = document.createElement('link');
            newStyle.setAttribute('href', url_new);
            newStyle.setAttribute('rel', 'stylesheet');
 
        document.head.appendChild(newStyle);
    };
 
    /**
     * ResourceLoader imports.
     * @method      __load
     */
    FANSUN.prototype.sassUtil.__load = function(mode, url, s) {
        if (url.indexOf(mode) === -1) {
            return;
        }
 
        // Array processing for ResourceLoader asset
        // https://slot1-images.wikia.nocookie.net/__load/-/cb%3D1518765819%26debug%3Dfalse%26lang%3Den%26only%3Dstyles%26<sassParams>%26sass_wordmark-font%3D<font>%26skin%3D<skin>
        var url_a = url.split('/'),
            sass_bounds = [
                'only%3Dstyles%26',
                '%26sass_wordmark-font'
            ],
            sass_p_mw,
            sass_i = +url_a.indexOf(mode)+2,
            sass_s_mw;
        // SASS parameter-string conversion
        if (this.cache[mode].length > 0) {
            sass_s_mw = this.cache[mode];
        } else {
            // Convert MediaWiki 'mwSassParams' into 'sassParams' format
            sass_p_mw = {};
            for (var k in this.sassParams) {
                sass_p_mw['sass_' + k] = this.sassParams[k];
            }
            sass_s_mw = $.param(sass_p_mw);
            // Caching for our new SASS string
            this.cache[mode] = this.cache.length > 0 ?
                this.cache[mode] :
                sass_s_mw;
        }
        // URL parsing logic to replace SASS parameters
        var sass_rgx = new RegExp(sass_bounds.join('|'));
        var sass_a_url = sass_s_url.split(sass_rgx);
        sass_a_url.splice(1, 1, sass_bounds[0], sass_s_mw, sass_bounds[1]);
        // Creating new URL
        var sass_s_new = sass_a_url.join('');
        url_a.splice(sass_i, 1, sass_s_new);
        var url_new = url_a.join('/');
        // URL setter
        window.dev.dark.cache.push(url_new);
 
        var newStyle = document.createElement('link');
            newStyle.setAttribute('href', url_new);
            newStyle.setAttribute('rel', 'stylesheet');
 
        document.head.appendChild(newStyle);
    };
 
    // Script bootloader
    $(window).on('load', function () {
        window.dev.dark = new FANSUN();
    });
 
}(window, mediaWiki, jQuery));
 
importArticles({
    type: 'script',
    articles: [
        'u:dev:MediaWiki:FANSUN.js',
    ]
});
 
importArticles({
    type: 'style',
    articles: [
        'u:community:User:JustLeafy/DarkMeta/community.css',
        'u:community:User:JustLeafy/DarkMeta/dev.css',
    ]
});
 
window.WHAMBotMe = true;
window.WHAMBotReason = "Cleanup";
window.WHAMDelay = 100;
window.WHAMDeleteReason = "Housekeeping.";
window.WHAMBlockReason = "Vandalism";
 
/**
 * @name        MultiUpload
 * @author      Gguigui1, KhangND
 * @desc        Allows selecting multiple files directly from the dialog box and upload them
 * <nowiki>
 */
mw.loader.using([
    'mediawiki',
    'mediawiki.user',
    'jquery.client',
    'ext.wikia.LinkSuggest'
], function() {
    var groups  = mw.config.get('wgUserGroups').join(),
        config = mw.config.get([
            'wgCanonicalSpecialPageName',
            'wgNamespaceNumber',
            'wgTitle',
            'wgUserLanguage',
            'wgUserName'
        ]);
 
    // load protections
    if(window.MultiUploadLoaded
    || config.wgUserName === null
    || !/autoconfirmed/.test(groups)) {
        return;
    } window.MultiUploadLoaded = true;
 
    var storage = 'MultiUploadLicenses';
    var content = $('#mw-content-text');
    var allowTypes = [
        '.png', '.gif', '.jpg', '.jpeg', '.ico', '.pdf',
        '.svg', '.odt', '.ods', '.odp', '.odg', '.odc',
        '.odf', '.odi', '.odm', '.ogg', '.ogv', '.oga'
    ];
    var style = {
        block: {
            display: 'inline-block',
            margin: '0 8px'
        },
        textarea: {
            width: '100%',
            height: 150,
            boxSizing: 'border-box',
            resize: 'none'
        }
    };
 
    function loadMWMessagesIfMissing(messages) {
        var deferred = $.Deferred(),
            missingMessages = messages.filter(function (message) { return !mw.messages.exists(message); });
        if (!missingMessages.length) {
            deferred.resolve();
        } else {
            $.get(mw.util.wikiScript('api'), {
                format: 'json',
                action: 'query',
                meta: 'allmessages',
                ammessages: missingMessages.join('|'),
                amlang: config.wgUserLanguage
            }).then(function (data) {
                if ($.isArray(data.query.allmessages)) {
                    $.each(data.query.allmessages, function (_, message) {
                        if (message.missing !== '') {
                            mw.messages.set(message.name, message['*']);
                        }
                    });
                }
                deferred.resolve();
            }, function () {
                // Silently swallow failures; we don't want error reporting to stall just because we failed to fetch some messages.
                deferred.resolve();
            });
        }
        return deferred;
    }
 
    var MultiUpload = {
        input: $(),  // available on init
        editor: $(), // available on init
        button: $(), // available on init
        fileCount: 0,// available on create
        preload: function(i18n) {
            $.extend(this, window.MultiUploadoption || {});
            this.i18n = i18n;
 
            // prepends a link in My Tools menu
            $('<li>', {
                'class': 'custom',
                prependTo: '#my-tools-menu',
                append: $('<a>', {
                    href: mw.util.getUrl('Special:MultiUpload'),
                    text: this.i18n.msg('title').plain()
                })
            });
 
            // creates Special page
            if(
                (config.wgNamespaceNumber === -1 && config.wgTitle === 'MultiUpload') ||
                (config.wgCanonicalSpecialPageName === 'Blankpage' && /MultiUpload/.test($.getUrlVar('blankspecial')))
            ) {
                $('.page-header__title').text(this.i18n.msg('title').plain());
                $('title').text(this.i18n.msg('title').plain());
                this.init();
                content.after(
                    $('<div>', {
                        id: 'mu-footer',
                        css: {
                            textAlign: 'center',
                            fontSize: 10,
                            borderTop: '1px solid',
                            marginTop: 10
                        },
                        text: this.i18n.msg('poweredby').plain() + ' ',
                        append: $('<a>', {
                            href: '//dev.fandom.com/wiki/MultiUpload',
                            text: 'MultiUpload'
                        })
                    })
                );
            }
        },
        init: function() {
            content.empty().append([
                $('<input>', {
                    id: 'fileinput',
                    type: 'file',
                    multiple: true,
                    accept: allowTypes.join(),
                }),
                $('<div>', {
                    id: 'editor',
                    css: { display: 'none' },
                }),
                $('<button>', {
                    id: 'go',
                    text: this.i18n.msg('update').plain(),
                    click: $.proxy(this.getLicenses, this)
                })
            ]);
            this.input = $('#fileinput');
            this.editor = $('#editor');
            this.button = $('#go');
        },
        notify: function(message, type) {
            new BannerNotification(message, type, null).show();
        },
        getLicenses: function() {
            var data = localStorage.getItem(storage);
            if(data !== null) {
                this.create(data);
                return;
            }
 
            $.get(mw.util.wikiScript('api'), {
                action: 'query',
                meta: 'allmessages',
                ammessages: 'Licenses',
                format: 'json'
            }).success(
                $.proxy(this.create, this)
            ).error($.proxy(function(data) {
                this.notify(this.i18n.msg('errorapi').plain() + ' : ' + data.error.info, 'error');
            }), this);
        },
        create: function(data) {
            // conditions
            var formatError = false;
            this.fileCount = this.input[0].files.length;
 
            $(this.input[0].files).each(function(i, file) {
                if(!new RegExp(allowTypes.join('|\\'), 'i').test(file.name)) {
                    formatError = true;
                    return;
                }
            });
            if (formatError) {
                this.notify(this.i18n.msg('fileformat').plain(), 'warn');
                return;
            }
            if (!this.input[0].files) {
                this.notify(this.i18n.msg('browsersupport').plain(), 'notify');
                return;
            }
            if (this.fileCount === 0) {
                this.notify(this.i18n.msg('nofile').plain(), 'warn');
                return;
            }
            if(!this.max
            ||  this.max < 0
            ||  this.max > 101
            || typeof this.max !== 'number') {
                if (/staff|helper|util|bot-global/.test(groups)) {
                    this.max = 200;
                } else if (/bureaucrat|bot/.test(groups)) {
                    this.max = 100;
                } else if (/sysop/.test(groups)) {
                    this.max = 100;
                } else if (/rollback/.test(groups)) {
                    this.max = 30;
                } else {
                    this.max = 20;
                }
            }
            if (!this.max) {
                this.notify(this.i18n.msg('problem').plain(), 'error');
                return;
            }
 
            // creates form
            data = typeof data === 'object'
                ? data.query.allmessages[0]['*'].trim()
                : data;
            localStorage.setItem(storage, data); // retrieves licenses 1 time only
            var licenses = data.split('\n');
            var limit = this.max < this.fileCount ? this.max : this.fileCount;
            for (i = 1; i <= limit; i++) {
                $('<fieldset>', {
                    id: 'field' + i,
                    appendTo: this.editor,
                    append: [
                        $('<legend>', {
                            text: this.i18n.msg('imagename').plain() + ' ' + i
                        }),
                        $('<div>', {
                            css: style.block,
                            text: this.i18n.msg('filename').plain(),
                            append: $('<input>', {
                                type: 'text',
                                id: 'imagename' + i,
                                'class': 'imagename',
                                val: this.input[0].files[i - 1].name
                            })
                        }),
                        $('<div>', {
                            css: style.block,
                            text: this.i18n.msg('licensetext').plain(),
                            append: $('<select>', {
                                id: 'licence' + i,
                                'class': 'licence',
                                append: $('<option>', {
                                    val: 'none',
                                    text: this.i18n.msg('nolicence').plain()
                                })
                            })
                        }),
                        $('<div>', {
                            id: 'progress' + i,
                            css: style.block
                        })
                    ]
                });
            }
            for (i = 0; i < licenses.length; i++) {
                if (licenses[i].indexOf('**') === 0) {
                    var name = licenses[i].split('|')[0].replace('**', '').trim(),
                        text = licenses[i].split('|')[1];
                    $('<option>', {
                        val: name,
                        text: text,
                        selected: name == this.defaultlicence,
                        appendTo: $('.licence').find('optgroup:last-child')
                    });
                } else {
                    $('<optgroup>', {
                        label: licenses[i].replace('*', '').trim(),
                        appendTo: $('.licence')
                    });
                }
            }
            $('<div>', {
                appendTo: this.editor,
                text: this.i18n.msg('filedescription').plain()
            }),
            $('<textarea>', {
                appendTo: this.editor,
                id: 'UploadDescription',
                css: style.textarea,
            }).linksuggest();
            $('<button>', {
                'class': 'secondary',
                id: 'reset',
                css: style.block,
                text: this.i18n.msg('reset').plain(),
                click: $.proxy(this.init, this),
                appendTo: content
            }),
            $('<input>', {
                type: 'checkbox',
                id: 'ignorewarnings',
                name: 'ignorewarnings',
                appendTo: content
            }),
            $('<label>', {
                'for': 'ignorewarnings',
                text: this.i18n.msg('ignorewarnings').plain(),
                appendTo: content
            });
 
            this.input.attr('disabled', true);
            this.editor.show();
            this.button
                .unbind('click')
                .click($.proxy(this.upload, this))
                .text(this.i18n.msg('uploadfiles').plain());
        },
        upload: function() {
            content.find('*').attr('disabled', true);
            $('#reset').removeAttr('disabled');
 
            for (i = 1; i <= this.fileCount; i++) {
                var file = this.input[0].files[i - 1],
                    filename = $('#imagename' + i).val() || file.name,
                    licence = $('#licence' + i).find('option:selected').val(),
                    text = $('#UploadDescription').val();
                if(licence !== "none") text = '{{' + licence + '}}\n' + text;
                this.uploadFile(file, filename, text, i);
            }
        },
        uploadFile: function(fileToUpload, fileName, text, index) {
            // https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects
            formdata = new FormData(); 
            formdata.append('action', 'upload');
            formdata.append('format', 'json');
            formdata.append('filename', fileName);
            formdata.append('token', mw.user.tokens.get('editToken'));
            formdata.append('file', fileToUpload);
            formdata.append('text', text);
            formdata.append(
                $('#ignorewarnings').prop('checked') ? 'ignorewarnings' : '', ''
            );
 
            // https://stackoverflow.com/a/8244082
            $.ajax({
                url: mw.util.wikiScript('api'),
                contentType: false,
                processData: false,
                type: 'POST',
                data: formdata,
                dataType: 'json',
                xhr: function() { // https://stackoverflow.com/a/27030092
                    myXhr = $.ajaxSettings.xhr();
                    myXhr.upload.addEventListener('progress', function(e) {
                        MultiUpload.progress(index, e);
                    });
                    return myXhr;
                },
                success: $.proxy(function(data) {
                    this.success(index, data);
                }, this),
                error: $.proxy(function(_, __, error) {
                    this.notify(error, 'error');
                }, this)
            });
        },
        progress: function(index, e) {
            var progress = e.loaded / e.total * 100;
            $('#progress' + index).text(progress.toFixed(0) + '%');
        },
        success: function(index, data) {
            // Error
            if (data.error) {
                var errorInfo, errorDetails;
 
                function displayError() {                
                    $('#progress' + index).html([
                        $('<strong/>').text(errorInfo),
                        (errorDetails === undefined) ? null : $('<br/>'),
                        (errorDetails === undefined) ? null : $('<div/>').text(errorDetails)
                    ]);
                }
 
                // Excluding variants of `unknownerror`, we're going to ignore `error.info` since it mightn't be localized.
                // See <https://github.com/Wikia/app/blob/release-886.001/includes/upload/UploadBase.php> for special cases.
                if (data.error.code.startsWith('unknownerror')) {
                    errorInfo = data.error.info;
                    displayError();
                } else {
                    var messages = [data.error.code];
                    if (data.error.code === 'verification-error') {
                        messages.push(data.error.details[0]);
                    }
                    loadMWMessagesIfMissing(messages).then(function () {
                        errorInfo = mw.msg(data.error.code);
                        if (data.error.code === 'verification-error') {
                            errorDetails = mw.msg.apply(null, data.error.details);
                        } else if (data.error.code === 'hookaborted') {
                            errorDetails = data.error.error;  // TODO: Determine whether it's safe to assume this'll always be properly escaped HTML.
                        }
                        displayError();
                    });
                }
                return;
            }
 
            // Success
            if(data.upload.result === 'Success') {
                $('#progress' + index).text(this.i18n.msg('success').plain());
                return;
            }
 
            // Warnings
            var msg;
            if(data.upload.warnings.hasOwnProperty('was-deleted')) {
                msg = this.i18n.msg('deleted').plain();
            } else if(data.upload.warnings.hasOwnProperty('duplicate')) {
                msg = this.i18n.msg('duplicate').plain();
            } else if(data.upload.warnings.hasOwnProperty('exists')) {
                msg = this.i18n.msg('exist').plain();
            } else {
                msg = this.i18n.msg('success').plain();
            }
 
            $('#progress' + index).text(msg);
        }
    };
 
    mw.hook('dev.i18n').add(function(i18n) {
        i18n.loadMessages('MultiUpload').then(
            $.proxy(MultiUpload.preload, MultiUpload)
        );
    });
    importArticle({
        type: 'script',
        article: 'u:dev:MediaWiki:I18n-js/code.js'
    });
});