MediaWiki:PortableListUsers.js

/** * @name           PortableListUsers * @version        v1.0 * @author         TheGoldenPatrik1 * @author         Ursuul * @description    Alternative to Special:ListUsers. * @protect */ require([   'wikia.window',    'jquery',    'mw',    'wikia.browserDetect',    'ext.wikia.design-system.loading-spinner' ], function (window, $, mw, browserDetect, Spinner) {    'use strict';    if (window.PortableListUsersLoaded) {        return;    }    window.PortableListUsersLoaded = true;    /**     * @class LU     * @classdesc Central PortableListUsers class     */    var LU = {};    /**     * @type {Number}     * @description Number of script preloads     */    LU.preloads = 4;    /**     * @type {Object}.{Object}     * @description User groups     */    LU.users = {        'authenticated': {},        'bot': {},        'bot-global': {},        'bureaucrat': {},        'chatmoderator': {},        'content-moderator': {},        'content-reviewer': {},        'content-volunteer': {},        'council': {},        'fandom-editor': {},        'global-discussions-moderator': {},        'helper': {}, 'request-to-be-forgotten-admin': {}, 'restricted-login': {}, 'restricted-long-exempt': {}, 'reviewer': {}, 'staff': {}, 'sysop': {}, 'threadmoderator': {}, 'util': {}, 'vanguard': {}, 'voldev': {}, 'vstf': {} };   /**     * @type {Object}.{Object} * @description Object for storing user data */   LU.data = {}; /**    * @type {Object} * @description Object for storing cached jQuery values */   LU.$ = {}; /**    * @type {Object} * @description Script configuration options */   LU.options = $.extend(        {            editcount: '0',            landing: 'sysop',            storage: false,            time: 'timeago'        },        window.PortableListUsers    ); /**    * @type {Boolean} * @description Shortcut for mobile or not */   LU.mobile = browserDetect.isMobile; /**    * @method preload * @description Preloads the script * @returns {void} */   LU.preload = function  { if (--this.preloads === 0) { this.api = new mw.Api; window.dev.i18n.loadMessages('PortableListUsers').then(               $.proxy(this.init, this)            ); }   };    /**     * @method init * @description Adds the link * @param {Object} i18n - Data from I18n-js * @returns {void} */   LU.init = function (i18n) { this.i18n = i18n.msg; window.dev.placement.loader.util({           script: 'PortableListUsers',            element: 'tools',            type: 'prepend',            content: $('', { 'id': 'lu-link' }).append( $('', {                   'text': this.i18n('title').plain,                    'click': $.proxy(this.click, this)                }) )       });    };    /**     * @method click * @description Displays the modal/spinner * @returns {void} */   LU.click = function  { if (this.modal) { this.modal.show; this.createContent; } else { $(' ', {               'id': 'lu-throbber',                'html':                    new Spinner(38, 2).html                    .replace('wds-block', 'wds-spinner__block')                    .replace('wds-path', 'wds-spinner__stroke')                    .replace('stroke-width=""', 'stroke-width="3"')            }).appendTo(document.body); this.$.spinner = $('#lu-throbber'); this.getUsers; }   };    /**     * @method getUsers * @description Gets all members of a usergroup * @returns {Function|void} */   LU.getUsers = function  { this.$.spinner.show; var val1 = $('#lu-group-select').val; var sto = localStorage.getItem('PortableListUsers'); if (val1) { this.currentGroup = val1; } else { if (this.options.storage && sto) { this.currentGroup = sto.split('|')[0]; } else { this.currentGroup = this.options.landing; }       }        var val2 = $('#lu-edits-select').val; if (val2) { this.currentNumber = val2; } else { if (this.options.storage && sto) { this.currentNumber = sto.split('|')[1]; } else { this.currentNumber = this.options.editcount; }       }        this.setStorage; var obj = this.currentGroup; if (this.isObject(this.users[obj])) { return this.getData; }       this.api.get({            action: 'query',            list: 'groupmembers',            gmgroups: obj,            gmlimit: 'max'        }).done(            $.proxy(this.getData, this)        ); };   /**     * @method setStorage * @description Resets the localStorage * @returns {void} */   LU.setStorage = function  { if (this.options.storage) { localStorage.setItem(               'PortableListUsers',                this.currentGroup + '|' + this.currentNumber            ); }   };    /**     * @method isObject * @description Tests to see if the object is empty * @param {Object} obj - The object to test * @returns {Boolean} */   LU.isObject = function (obj) { for (var key in obj) { if (obj.hasOwnProperty(key)) { return true; }       }        return false; };   /**     * @method getData * @description Processes usergroup data and gets more data * @param {JSON} d - Data from getUsers * @returns {Function|void} */   LU.getData = function (d) { var obj = this.users[this.currentGroup]; if (d) { if (d.error) { return; }           $.each(d.users, $.proxy(function (k, v) { obj[v.name] = v.name; }, this)); }       if (!this.isObject(obj)) { return this.loadModal; }       var users = Object.keys(obj).join('|'); this.api.get({           action: 'query',            list: 'users|usercontribs',            ususers: users,            usprop: 'groups|editcount|gender|registration',            ucuser: users,            uclimit: 'max',            ucprop: 'timestamp|title'        }).done(            $.proxy(this.loadData, this)        ); };   /**     * @method loadData * @description Loads the data from getData * @param {JSON} d - The data from getData * @returns {void} */   LU.loadData = function (d) { if (d.error) { return; }       $.each(d.query.users, $.proxy(function (k, v) { if (!this.data[v.name]) { this.data[v.name] = v;           } }, this)); $.each(d.query.usercontribs, $.proxy(function (k, v) { if (!this.data[v.user]) { return; }           if (!this.data[v.user].timestamp) { this.data[v.user].timestamp = v.timestamp; }           if (!this.data[v.user].title) { this.data[v.user].title = v.title; }       }, this)); this.loadModal; };   /**     * @method loadModal * @description Updates/creates the modal * @returns {void} */   LU.loadModal = function  { if (this.modal) { this.currentNumber = this.$.edits.val || this.options.editcount; this.setStorage; this.$.list.html(''); this.createRow; this.addContent; } else { this.createModal; }   };    /**     * @method createModal * @description Creates the script modal * @returns {void} */   LU.createModal = function  { this.modal = new window.dev.modal.Modal({           content: $(' ', { 'class': 'list-users list-users-' + (this.mobile ? 'mobile' : 'desktop') }).append( this.createSelect('group'), this.createSelect('edits'), $(' ', {                   'id': 'lu-tally'                }), $(this.mobile ? '' : ' ', {                   'class': this.mobile ? '' : 'article-table',                    'id': this.mobile ? 'lu-list' : 'lu-table'                }) ).prop('outerHTML'),           id: 'list-users',            size: 'large',            title: this.i18n('title').plain,            buttons: [                {                    text: this.i18n('close').plain,                    event: 'close'                }            ]        }); this.modal.create.then(           $.proxy(this.createContent, this)        ); this.modal.show; };   /**     * @method createContent * @description Creates the modal's main content * @returns {void} */   LU.createContent = function  { this.$.list = $(this.mobile ? '#lu-list' : '#lu-table'); this.$.group = $('#lu-group-select'); this.$.group.change(           $.proxy(this.getUsers, this)        ); $.each(this.users, $.proxy(function (k, v) { this.$.group.append(               $(' ', { 'text': k,                   'value': k,                    'selected': this.currentGroup === k ? true : false })           );        }, this)); this.$.edits = $('#lu-edits-select'); this.$.edits.change(           $.proxy(this.loadModal, this)        ); $.each([           '0',            '1',            '5',            '10',            '20',            '50',            '100'        ], $.proxy(function (k, v) { this.$.edits.append(               $(' ', { 'text': this.i18n('number', v).plain, 'value': v,                   'selected': this.currentNumber === v ? true : false })           );        }, this)); this.createRow; this.addContent; };   /**     * @method addContent * @description Adds the user data * @returns {void} */   LU.addContent = function  { $.each(this.data, $.proxy(function (k, v) { if (this.users[this.currentGroup][v.name || k]) { var count = v.editcount || '0'; if (Number(count) < Number(this.currentNumber)) { return; }               this.createRow(                    v.name || k,                    v.timestamp,                    v.title,                    v.userid,                    count,                    v.gender,                    v.registration,                    v.groups                ); }       }, this)); $('#lu-tally').html(           this.i18n( 'tally', this.mobile ? this.$.list.find('li').length : (this.$.list.find('tr').length -1) ).plain       ); $('img#lu-avatar').each(function {            $(this).error(function  { $(this).attr(                   'src',                    'https://images.wikia.nocookie.net/messaging/images/1/19/Avatar.jpg'                ); });       });        this.$.spinner.hide; };   /**     * @method createRow * @description Creates a table row or list item * @param {String} user * @param {String} timestamp * @param {String} title * @param {String} id    * @param {Number|String} editcount * @param {String} gender * @param {String} registration * @param {Array} groups * @returns {void} */   LU.createRow = function (user, timestamp, title, id, editcount, gender, registration, groups) { var item = this.mobile ? '' : ' '; if (user) { this.$.list.append(               $(item).append( this.createItem(                       $(' ').append( this.createLink(user, 'User:' + user), ' (',                           this.createLink( this.i18n('talk').plain, 'User talk:' + user ),                           ' | ',                            this.createLink( this.i18n('contribs').plain, 'Special:Contributions/' + user ),                           ')'                        ),                        'user'                    ), this.createItem(                       timestamp ?                        this.createLink(this.timestamp(timestamp), title)  :                        (editcount === '0' ? 'N/A' : timestamp),                       'last-edited'                    ), this.createItem(                       editcount ?                        this.createLink( editcount, 'Special:EditCount/' + user ) :                        editcount,                        'editcount'                    ), this.createItem(gender, 'gender'), this.createItem(                       registration ?                        this.timestamp(registration) :                        registration,                        'registration'                    ), this.createItem(                       groups.join(', ')                        .replace(', *', ).replace(', user', ),                        'groups'                    ), this.createItem(                       id ? $(' ', { 'src': 'https://services.wikia.com/user-avatar/user/' + id + '/avatar', 'id': 'lu-avatar' }) : id,                       'avatar'                    ) )           );        } else if (!this.mobile) { this.$.list.append(               $(item, { 'id': 'lu-table-first' }).append( this.createSpecialItem('user'), this.createSpecialItem('last-edited'), this.createSpecialItem('editcount'), this.createSpecialItem('gender'), this.createSpecialItem('registration'), this.createSpecialItem('groups'), this.createSpecialItem('avatar') )           );        }    };    /**     * @method createItem * @description Creates a div or td item * @param {String} html - The item's HTML * @param {String} id - The item's id    * @returns {String} */   LU.createItem = function (html, id) { if (this.mobile) { return $(' ', {               'id': 'lu-list-' + id,                'html': html || this.i18n('unknown').plain            }).prepend(                /user|groups|avatar/.test(id) ?                '' :                (' ' + this.i18n(id).escape + ' ')            ); } else { return $(' ', {               'html': html || this.i18n('unknown').plain            }); }   };    /**     * @method createSpecialItem * @description Creates a different td item * @param {String} msg - The text * @returns {String} */   LU.createSpecialItem = function (msg) { return $(' ', {           'html': this.i18n(msg).plain        }); };   /**     * @method createSelect * @description Creates a select item * @param {String} id - The select's id    * @returns {String} */   LU.createSelect = function (id) { return $(' ', {           'id': 'lu-' + id + '-select'        }); };   /**     * @method createLink * @description Creates an a item * @param {String} text - The link text * @param {String} href - The link href * @returns {String} */   LU.createLink = function (text, href) { return $('', {           'text': text,            'href': mw.util.getUrl(href)        }); };   /**     * @method timestamp * @description Processes timestamps * @param {String} time - The timestamp to process * @returns {String} */   LU.timestamp = function (time) { var $time = new Date(time).toString; var formattedTime; if (this.options.time === 'timeago') { formattedTime = $.timeago(               $time.slice(0, 3) + ', ' +                $time.slice(4, 15) + ', ' +                $time.slice(16, 24)            ); } else if (this.options.time === 'utc') { $time = new Date(time).toUTCString; formattedTime = $time.slice(0, 3) + ', ' + $time.slice(4, 16) + ', ' + $time.slice(17, 25) + ' (' +               $time.slice(26) + ')'; } else { formattedTime = $time.slice(0, 3) + ', ' + $time.slice(4, 15) + ', ' + $time.slice(16, 24) + ' ' + $time.slice(34); }       return formattedTime; };   mw.loader.using([        'mediawiki.api',        'mediawiki.util'    ]).then(        $.proxy(LU.preload, LU)    ); mw.hook('dev.i18n').add(       $.proxy(LU.preload, LU)    ); mw.hook('dev.modal').add(       $.proxy(LU.preload, LU)    ); mw.hook('dev.placement').add(       $.proxy(LU.preload, LU)    ); importArticles(       {            type: 'script',            articles: [                'u:dev:MediaWiki:I18n-js/code.js',                'u:dev:MediaWiki:Modal.js',                'u:dev:MediaWiki:Placement.js'            ]        },        {            type: 'style',            articles: ['u:dev:MediaWiki:ListUsers.css']        }    ); });