MediaWiki:ChatHacks/beta.js

/* * ChatHacks.js, by Monchoman45 and FANDOM Open Source Library. * Version 8.0 * * Features: *  Ability to clear your chat window *  A host of slash commands *  Ability to create multi user private chats *  Inline alerts every time your away status changes *  Icons next to messages by staff and chat mods in the room *  Pings when someone mentions your name or any other specified phrases */ (function(mw) {   'use strict';    if (window.ChatHacks) {        return;    }    var config = mw.config.get([ 'wgChatMyAvatarUrl', 'wgCanonicalSpecialPageName', 'wgSassParams', 'wgSiteName', 'wgUserName' ]), ChatHacks = {       /* eslint-disable max-len */        staffIcon: window.ChatHacksIconStaff || 'https://images.wikia.nocookie.net/wikiaglobal/images/6/6c/Staff_icon.png',        modIcon: window.ChatHacksIconMod || 'https://images.wikia.nocookie.net/monchbox/images/6/6b/Icon-chatmod.png',        pingSound: window.ChatHacksPingSound || 'https://images.wikia.nocookie.net/monchbox/images/0/01/Beep-sound.ogg',        /* eslint-enable max-len */        _loaded: 0,        handleIcon: function(msg) {            var icon,                vd = window.mainRoom.viewDiscussion,                user = vd.model.users.findByName(msg.get('name'));            if (!user) {                return;            }            if (user.get('isStaff')) {                icon = $(' ', { 'class': 'stafficon', 'src': this.staffIcon });           } else if (user.get('isModerator')) {                icon = $(' ', { 'class': 'modicon', 'src': this.modIcon });           }            if (icon && window.ChatHacksNoStar !== true) {                vd.chatUL                  .children                  .last                  .children('.username')                  .append(' ', icon);            }        },        handlePing: function(msg) {            if ( !window.mainRoom.isInitialized || msg.get('name') === config.wgUserName || msg.get('isInlineAlert') ) {               return;            }            var text = msg.get('text').toLowerCase;            if ( this.$pings .val .trim .split('\n') .some(function(ping) {                       var p = ping.trim.toLowerCase;                        return p && text.indexOf(p) !== -1;                    }) ) {               if (!this.hasFocus) {                    if (window.ChatHacksPingSound !== false) {                        this.$sound.html( $(' ', {                               autoplay: true,                                src: this.pingSound                            }) );                   }                    if (!this.dinged) {                        this.dinged = true;                        this.ding = setInterval( $.proxy(this.flashTitle, this), 500                       );                    }                }                this.vd.scrollToBottom;                this.vd.chatUL                    .children                    .last                    .children('.message')                    .addClass('ping');            }        },        handleEmoticons: function {            this.vd.chatUL                .children                .last                .find('.message img')                .each($.proxy(this.killEmote, this));        },        killEmote: function(_, el) {            var $this = $(el),                html = $this.prop('outerHTML');            $this.replaceWith( $(' ', {                   'class': 'killed-emote',                    'click': function {                        this.outerHTML = html;                    },                    'text': $this.attr('title'),                    'title': this.i18n.msg('emote').plain                }) );       },        iconPing: function(msg) {            this.handleIcon(msg);            this.handlePing(msg);            this.handleEmoticons;        },        setAway: function {            this.inlineAlert(ChatHacks.i18n.msg('away').escape);            window.mainRoom.socket.send(new window.models.SetStatusCommand({                statusState: window.STATUS_STATE_AWAY,                statusMessage: ''            }).xport);        },        setBack: function {            /**             * If we have sent this command (but just haven't finished coming * back yet), don't keep spamming the server with this command            */            if (this.comingBackFromAway) {                return;            }            this.comingBackFromAway = true;            this.inlineAlert(ChatHacks.i18n.msg('back').escape);            window.mainRoom.socket.send(new window.models.SetStatusCommand({                statusState: window.STATUS_STATE_PRESENT,                statusMessage: ''            }).xport);        },        sendMessage: function(event) {            if (!this.active) {                return true;            }            if (event.which !== 13 || event.shiftKey) {                return false;            }            event.preventDefault;            window.mainRoom.resetActivityTimer;            var $input = this.viewDiscussion.getTextInput,                send = ChatHacks.preparse($input.val.trim),                value = $input.val.trim; if (value && send && value.length <= this.maxCharacterLimit) { var entry = new window.models.ChatEntry({                   name: config.wgUserName,                    text: value                }); if (this.isMain) { this.socket.send(entry.xport); } else { if (                       this.afterInitQueue.length < 1 ||                        this.model.users.length < 2                    ) { this.mainController.socket.send(                           this.model.privateRoom.xport                        ); }                   if (this.isInitialized) { this.socket.send(entry.xport); } else { this.afterInitQueue.push(entry.xport); // temp chat entry in case of slow connection time entry.set({                           avatarSrc: config.wgChatMyAvatarUrl,                            temp: true                        }); this.model.chats.add(entry); }               }            }            $input.val('').focus; $('body').removeClass('warn limit-near limit-reached'); },       inlineAlert: function(text) { text.split('\n').forEach(function(line) {               window.mainRoom.model.chats.add( new window.models.InlineAlert({                       text: line                    }) );           });            window.mainRoom.viewDiscussion.scrollToBottom; },       flashTitle: function { if (document.title === this.titleorig) { document.title = this.i18n.msg(                   'activity', config.wgSiteName                ).plain; } else { document.title = this.titleorig; }       },        preparse: function(input) { var commands = this.commands, com = input.slice(1) .trim .replace(/\s+/g, ' ') .split(' '), ref = com.shift;

if (input.charAt(0) === '/' && ref.length > 0) { while (typeof commands[ref] === 'string') { ref = commands[ref]; }               if (                    typeof commands[ref] === 'object' &&                    // /me does not have a handler                    typeof commands[ref].handler === 'function'                ) { var param = com.join(' '); if (commands[ref].user && !param.trim) { this.inlineAlert(this.i18n.msg( 'erruser', input.split(' ')[0] ).escape); return false; }                   var ret = commands[ref].handler.call(this, param); if (typeof ret === 'string') { $('#Write [name="message"]').val(ret); return true; }                   return ret; }           }            return true; },       baseMod: function(user, action) { $.getJSON(mw.util.wikiScript('api'), {               action: 'query',                list: 'users',                ustoken: 'userrights',                ususers: user,                format: 'json'            }, $.proxy(function(token) { var params = { format: 'json', action: 'userrights', user: user, token: token.query.users[0].userrightstoken };               params[action] = 'chatmoderator'; $.post(                   mw.util.wikiScript('api'),                    params,                    $.proxy( function(result) { this.inlineAlert(this.i18n.msg.apply( this.i18n, this.getModMsg(result, action, user) ).escape); },                       this )               );            }, this)); },       getModMsg: function(result, action, user) { if (action === 'remove') { if (result.userrights.removed[0] === 'chatmoderator') { return ['demodded', user]; }               return ['notmod', result.userrights.user]; } else if (result.userrights.added[0] === 'chatmoderator') { return ['modded', user]; }           return ['alreadymod', result.userrights.user]; },       commands: { // Contains data about the /me command 'me': { msg: true },           'away': 'afk', 'afk': { handler: function { // If you're away, hitting enter has already sent you back if (!$('#ChatHeader .User').hasClass('away')) { this.toggleAway; }               }            },            // Clear the active chat window 'clear': { handler: function { this.clearWindow; }           },            // Nobody cares 'nc': { msg: true, handler: function(com) { return  + (com || this.i18n.msg('nobodycares').plain) +                          ; }           },            // IRCpwnt 'devoice': { handler: function(com) { return '* ChanServ set channel mode -v ' + (com || config.wgUserName); }           },            // Too young 'coppa': { handler: function(com) { return 'http://coppa.org/ ' + (com || this.i18n.msg('coppa').plain); }           },            // Idle 'silence': function { return 'People idle, enjoy the silence. ' +                      'https://youtu.be/diT3FvDHMyo'; },           // ¯\_(ツ)_/¯ 'shrug': { handler: function(com) { return (com || '') + ' ¯\\_(ツ)_/¯'; }           },            // Kick a user 'kick': { user: true, handler: function(com) { window.mainRoom.kick({                       name: com                    }); }           },            'kickban': 'ban', 'kb': 'ban', // Ban a user 'ban': { user: true, handler: function(com) { window.mainRoom.socket.send(new window.models.BanCommand({ userToBan: com, // 1 day is enough, idk, no time specified time: '36400', // TODO: i18n reason: 'Misbehaving in chat' }).xport); }           },            // Unban a user 'unban': { user: true, handler: function(com) { window.mainRoom.socket.send(new window.models.BanCommand({ // Empty ban command === unban userToBan: com }).xport); }           },            // Make a user a mod 'mod': { handler: function(com) { this.baseMod(com, 'add'); }           },            // Remove a user's mod right 'demod': { user: true, handler: function(com) { this.baseMod(com, 'remove'); }           },            // Block a user from private chatting you 'block': { user: true, handler: function(com) { window.mainRoom.blockPrivate({name: com}); }           },            // Unblock a user from private chatting you 'unblock': { user: true, handler: function(com) { window.mainRoom.allowPrivate({name: com}); }           },            'chat': 'private', 'room': 'private', // Invoke a private room 'private': { user: true, handler: function(com) { var users = com.replace(/\s*,\s*/g, ',').split(','), curRoom = window.mainRoom.model.privateUsers .findByName(users[0]); if (curRoom) { window.mainRoom.showRoom(curRoom.attributes.roomId); } else { window.mainRoom.openPrivateChat(users); }               }            },            'roomid': 'id', 'id': { handler: function { this.inlineAlert(                       this.i18n.msg('id', window.mainRoom.roomId).escape                    ); }           },            // Send a message to yourself 'self': { handler: function(com) { var ar = window.mainRoom.activeRoom, room = ar === null ? window.mainRoom : window.mainRoom.chats.privates[ar]; room.model.chats.add(new window.models.ChatEntry({ name: config.wgUserName, text: this.i18n.msg('self').plain + ' ' + com, avatarSrc: config.wgChatMyAvatarUrl }));                   this.viewDiscussion.scrollToBottom; }           },            'help': { handler: function(com) { if (com) { var ref = com; while (typeof this.commands[ref] === 'string') { ref = this.commands[ref]; }                       if (this.i18n.msg('help-' + ref).exists) { var cmd = this.commands[ref], example = '/' + ref; if (cmd.msg) { example += ' ' + this.i18n.msg(                                              'help-' + ref + '-example'                                           ).plain; } else if (cmd.user) { example += ' ' + this.i18n.msg('exampleuser').plain; }                           this.inlineAlert(                                this.i18n.msg( 'help', ref, this.i18n.msg('help-' + ref).plain ).parse +                               '\n' +                                this.i18n.msg('example').escape +                                ': ' +                                $(' ', { 'class': 'chathacks-example', 'text': example }).prop('outerHTML')                           ); window.mainRoom.viewDiscussion.chatUL .children('li') .last .children('span.chathacks-example') .click(this.exampleClick); } else { this.inlineAlert(                               this.i18n.msg('nohelp', ref).escape                            ); }                   } else { var str = []; for (var i in this.commands) { if (typeof this.commands[i] === 'object') { str.push(i); }                       }                        this.inlineAlert(                            this.i18n.msg('commands', str.join(', ')).escape                        ); }               }            }        },        focus: function { if (this.ding) { clearInterval(this.ding); this.ding = 0; }           document.title = this.titleorig; this.hasFocus = true; this.dinged = false; },       blur: function { this.hasFocus = false; },       toggleAway: function(msg) { if ($('#ChatHeader .User').hasClass('away')) { window.mainRoom.setBack; } else { window.mainRoom.setAway(msg || ''); }       },        clearWindow: function { this.vd.chatUL.empty; window.mainRoom.inlineAlert(this.i18n.msg('cleared').escape); this.vd.chatUL.find(               '#entry-' +                window.mainRoom.model.chats.models.slice(-1)[0].cid            ).removeClass('continued'); },       openPings: function { this.$pings.removeClass('hidden'); },       closePings: function { this.$pings.addClass('hidden'); $.storage.set('pingphrases', $('#pings').val.split('\n'), {               expires: 99999,                path: '/'            }); },       initVars: function { this.hasFocus = document.hasFocus; this.dinged = false; this.ding = 0; this.titleorig = document.title; this.vd = window.mainRoom.viewDiscussion; },       initBinding: function { window.mainRoom.model.chats.bind(               'afteradd',                $.proxy(this.iconPing, this)            ); window.NodeChatController.prototype.setAway = this.setAway; window.NodeChatController.prototype.setBack = this.setBack; window.NodeChatController.prototype.sendMessage = this.sendMessage; window.NodeChatController.prototype.inlineAlert = this.inlineAlert; this.vd.unbind('sendMessage'); this.vd.bind(               'sendMessage',                $.proxy(window.mainRoom.sendMessage, window.mainRoom)            ); },       initExamples: function { mw.util.addCSS(               '.inline-alert span.chathacks-example {' +                    'color: ' + config.wgSassParams['color-links'] + ';' +                '}'            ); },       exampleClick: function { window.mainRoom.viewDiscussion .getTextInput .val($(this).text); },       initButtons: function { this.buttons = { toggleAway: new window.dev.chat.Button({                   name: 'ChatHacks AFK',                    attr: {                        click: $.proxy(this.toggleAway, this),                        text: this.i18n.msg('afk').plain                    }                }), clearWindow: new window.dev.chat.Button({                   name: 'ChatHacks clear',                    attr: {                        click: $.proxy(this.clearWindow, this),                        text: this.i18n.msg('clear').plain                    }                }), pingPhrases: new window.dev.chat.Button({                   name: 'ChatHacks ping phrases',                    attr: {                        id: 'pingspan',                        text: this.i18n.msg('pingphrases').plain,                        append: [                            $(' ', { 'id': 'pings', 'class': 'hidden', 'text': $.storage.get('pingphrases') ? $.storage.get('pingphrases').join('\n') : config.wgUserName })                       ]                    }                })            };        },        initPings: function { this.$pings = $('#pings'); $('#pingspan') .on('mouseover', $.proxy(this.openPings, this)) .on('mouseout', $.proxy(this.closePings, this)); },       initialized: function { this.initVars; this.initBinding; this.initExamples; this.initButtons; this.initPings; window.mainRoom.inlineAlert(this.i18n.msg('init').parse); mw.hook('chathacks.loaded').fire(this); },       initImports: function { importArticles(               {                    type: 'script',                    articles: [                        'u:dev:MediaWiki:Chat-js.js',                        'u:dev:MediaWiki:I18n-js/code.js'                    ]                },                {                    type: 'style',                    articles: ['u:dev:MediaWiki:ChatHacks.css']                }            ); },       initWindow: function { $(window) .unbind('mousemove') .unbind('focus') .unbind('keypress') .bind('focus', $.proxy(this.focus, this)) .bind('blur', $.proxy(this.blur, this)); },       initSound: function { this.$sound = $(' ', {               id: 'sound'            }).appendTo(document.body); },       initPreload: function { mw.hook('dev.i18n').add($.proxy(this.preloadI18n, this)); mw.hook('dev.chat.render').add($.proxy(this.preload, this)); },       preloadI18n: function(i18n) { i18n.loadMessages('ChatHacks').then(               $.proxy(this.preloadedI18n, this)            ); },       preloadedI18n: function(i18n) { this.i18n = i18n; this.preload; },       preload: function { if (++this._loaded === 2) { this.initialized; }       },        initChat: function { this.initImports; this.initWindow; this.initSound; this.initPreload; mw.hook('chathacks.commands').fire(this.commands); },       chatCheck: function(e) { if (               typeof e === 'object' &&                Object.prototype.hasOwnProperty.call(e, 'preventDefault')            ) { e.preventDefault; }           $(document.body) .find('.WikiaChatLink, .start-a-chat-button') .each($.proxy(this.convertChatLink)); },       convertChatLink: function(_, el) { $(el) .removeClass('WikiaChatLink start-a-chat-button') .removeAttr('href') .click($.proxy(this.openChatWindow, this)); },       openChatWindow: function { this.chatwindow = window.open('/wiki/Special:Chat', 'chat'); this.chatwindow.onload = $.proxy(this.onChatWindowLoad, this); },       onChatWindowLoad: function { this.chatwindow.importArticles({               type: 'script',                articles: [                    'u:c:User:' + config.wgUserName + '/global.js',                    'User:' + config.wgUserName + '/wikia.js'                ]            }); },       initNotChat: function { var check = $.proxy(this.chatCheck, this); $(document.body).on(               'click',                'a[href^="/wiki/Special:Chat"]',                check            ); mw.hook('wikipage.content').add(check); $('#WikiaRail').on('afterLoad.rail', check); mw.hook('chathacks.loaded').fire(this); }   };    window.ChatHacks = ChatHacks; if (config.wgCanonicalSpecialPageName === 'Chat') { ChatHacks.initChat; } else { ChatHacks.initNotChat; } })(mediaWiki);