MediaWiki:VanguardTools.js

/** *  * @module                  VanguardTools * @description            Accelerates Vanguard migration workflow. * @author                 Speedit * @version                0.9.0 * @license                CC-BY-SA 3.0 * @notes                  May be used by non-Vanguard users. * */ require(['wikia.window', 'mw', 'wikia.nirvana'], function (script, mw, nirvana) {    'use strict';

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

// MediaWiki variables VAN.mw = mw.config.get([       'wgCanonicalNamespace',        'wgCanonicalSpecialPageName',        'wgServer',        'wgTitle',        'wgPageName',        'wgArticleId',        'wgUserGroups',        'skin'    ]); // User parrot status VAN.parrot = VAN.mw.wgUserGroups.some(function(ug) {       return ['vanguard', 'staff'].indexOf(ug) > -1;    });

// Script configuration VAN.config = window.vanguardToolsConfig || { state: true, modules: [] };   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(VAN.wds); },       // 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(VAN.i18n); },       // I18n event $loaded: $.Deferred };

// Main script VAN.init = function { if (!VAN.config.state || VAN.mw.skin !== 'oasis') { 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 { // Fire hook mw.hook('van.init').fire(VAN); });       });        // Import dependencies importArticle({ type: 'script', article: 'u:dev:I18n-js/code.js' }); importArticle({ type: 'script', article: 'u:dev:WDSIcons/code.js' }); };

// Redirect module for the lazy VAN.redirect = { init: function { var uri; if (VAN.mw.wgCanonicalSpecialPageName === 'InfoboxBuilder') { uri = new mw.Uri('Template:' + VAN.mw.wgTitle.split('/')[1]); uri.extend({                   action: 'edit',                    useeditor: 'source'                }); window.location.replace(uri.toString); }           if (['sinpi', 's:i/npi'].indexOf(VAN.mw.wgPageName.toLowerCase) > -1) { window.location.replace(uri.toString); }           VAN.redirect.$executed.resolve(true); }   };

// Basic JIRA integration VAN.jira = { // Launch JIRA modal launch: function(e) { e.preventDefault; if (VAN.parrot) { window.open(event.currentTarget.href, 'vanguardJiraWindow', VAN.jira.popup); } else { window.location.href = event.currentTarget.href; }       },        // Popup parameter generator popup: function { var pw = window.innerWidth, pw_mw = 768, pw_h = 670, pw_w = pw < pw_mw ? pw : pw_mw, pw_l = window.screenX + (pw / 2) - (pw_w / 2), pw_t = window.screenY + (window.innerHeight / 2) - (pw_h / 2); return [ 'width=' + pw_w, 'height=' + pw_h, 'top=' + pw_t, 'left=' + pw_l, 'menubar=no', 'status=no', 'location=no', 'toolbar=no', 'scrollbars=no', 'resizable=yes', ].join(','); }   }

// Global navigation links module VAN.nav = { init: function { var $l = $('').addClass('wds-list wds-is-linked'); $.each(VAN.nav.uri, function(link) {               $l.append( $('').append(                       $('', { 'href': '/wiki/' + VAN.nav.uri[link], text: VAN.i18n.msg(link).plain })                   )                );            });            // Icon and dropdown generation var icon = VAN.wds.icon('menu-control-tiny'); icon.classList.add('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('a[data-tracking-label="account.profile"]') .parent.after($c); VAN.nav.$executed.resolve(true); },       // Create dropdown dropdown: function($l, icon) { return $('', {               'id': 'van-tools-list',                'class': 'wds-dropdown-level-2'            }).append(                $('', { 'href': (function {                       if (VAN.parrot) {                            return 'https://wikia-inc.atlassian.net/projects/VAN/issues?filter=myopenissues';                        } else {                            return 'https://dev.wikia.com/wiki/Special:Insights/nonportableinfoboxes';                        }                    }), 'target': '_blank', 'rel': 'noopener noreferrer', 'class': 'wds-dropdown-level-2__toggle van-tools-container', click: VAN.jira.launch }).append( $(' ', {                       text: VAN.i18n.msg('tools').plain                    }), icon ),               $(' ', {                    'class': 'wds-dropdown-level-2__content wds-is-not-scrollable' }).append($l)           ); },       // Global navigation links uri: { insights: 'Special:Insights/nonportableinfoboxes', infoboxes: 'Special:Templates?type=infobox', templates: 'Special:Templates', sitecss: 'Special:CSS', personalcss: 'Special:MyPage/common.css', themescss: 'MediaWiki:Themes.css?action=edit', admins: 'Special:ListUsers/sysop', wikifeatures: 'Special:WikiFeatures' },       $executed: $.Deffered };

// Template reclassification hotkey module VAN.template = { init: function { if (VAN.mw.wgCanonicalNamespace !== 'Template') { return; }           var $popout = $(' ', {                'class': 'van-popout'            }).append(                $('').append( $('', {                       text: VAN.i18n.msg('templatetypeguide')                    }) )           );            $popout.appendTo(document.body); // Delegate keyboard handler $(document).keyup(VAN.template.shortcut); VAN.template.$executed.resolve(true); },       // 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.sendRequest({               controller: 'TemplateClassificationApi',                method: 'classifyTemplate',                data: {                    pageId: mw.config.get('wgArticleId'),                    type: VAN.template.type,                    editToken: mw.user.tokens.values.editToken                },                callback: 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' } },       // Template labels for template types labels: { 'infobox': 'Infobox', 'quote': 'Quote', 'navbox': 'Navbox', 'notice': 'Notice', 'context-link': 'Context-link', 'infoicon': 'Infoicon', 'scrollbox': 'Scrollbox', 'references': 'References', 'media': 'Media', 'data': 'Data', 'design': 'Design', 'navigation': 'Navigation', 'nonarticle': 'Non-article' },       $executed: $.Deffered };

VAN.insights = { // Module initialiser init: function { if (               VAN.mw.wgPageName !== 'Special:Insights/nonportableinfoboxes' ||                !$('.insights-icon-nonportableinfoboxes').has('.insights-red-dot')            ) { return; }           VAN.insights.list = {}; [].slice.call($('.insights-list-item-title')).map(function(e) {               var t = e.innerText;                $(e).closest('.insights-list-item')                    .attr('data-template', t);                VAN.insights.list[t] = {};            }); VAN.insights.api.get({               'action': 'query',                'prop': 'info',                'inprop': 'protection',                'titles': Object.keys(VAN.insights.list).join('|')            }).done(VAN.insights.handler); },       // Template list list: {}, api: new mw.Api, // 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;           }); VAN.insights.ui; },       // Interface configuration map for actions map: { 'viewdraft': { icon: 'eye-small' },           'conversion': { icon: 'gear-small' },           'rawcode': { icon: 'article-small', query: { action: 'raw' }           },            'protected': { icon: 'lock-small', query: { action: 'history' }           },            'unprotected': { icon: 'unlock-small', query: { action: 'history' }              }        },        // UI modification ui: function { // 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-tools-button-group' ].join(' ') }).insertBefore($b).append($b);               // Class addition                $b.attr('class', function { if ($b.attr('href').indexOf('action=edit' > -1)) { return [ 'van-tools-button', 'van-is-conversion' ].join(' '); } else { return [ 'van-tools-button', 'van-is-viewdraft' ].join(' '); }               }).addClass([ 'wds-button', 'wds-is-squished', 'wds-is-secondary' ].join(' ')).html(function(i, html) { return ' ' + 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.wikiGetlink(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                if (c.icon) {                    $t.children('.van-is-' + l)                        .prepend(VAN.wds.icon(c.icon));                }            }); VAN.insights.$executed.resolve(true); },       $executed: $.Deffered };

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

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

});