User:Robyn Grayson/chat.js

// Yeah I stole everything from Doru- go there if you want the most recent version

importArticles({   type: 'script',    articles: [        'u:dev:PrivateHistory/code.js',        'u:dev:FaviconNotifier/code.js',        'u:dev:IsTyping/code.js',        'u:dev:Tabinsert.js', // yeah this irks me too, ThisCaseFtw        'u:dev:ExtendedPrivateMessaging/code.js',        'u:dev:PrivateMessageAlert/code.js',        'u:dev:EscapeEmoticons/code.js',        'u:dev:EmoticonsWindow/code.js',        'u:dev:CapsFirst/code.js', // Makes my typing more intelligible,        'u:dev:ChatButtonsCollectionDeluxe.js'    ] });

importScriptPage('User:Robyn Grayson/chat.js', 'clockwork-planet'); importScriptPage('ChatScript', 'gmods-hideout');

/* Pings */ window.PING_REGEX = /robyn|gmod|\brob\b|cassaltdra|k_os/i;

(function reload {   if (!window.mainRoom) {        setTimeout(reload, 200);        return;    }    mainRoom.model.chats.bind('afteradd', function { var div = mainRoom.viewDiscussion.chatDiv.get(0); if (div.scrollHeight - div.scrollTop - div.clientHeight < 200) { mainRoom.viewDiscussion.scrollToBottom; }   });

mainRoom.model.privateUsers.bind('add', function(u) {       var room = mainRoom.chats.privates[u.attributes.roomId];        room.model.chats.bind('afteradd', function { var div = room.viewDiscussion.chatDiv.get(0); if (div.scrollHeight - div.scrollTop - div.clientHeight < 500) { room.viewDiscussion.scrollToBottom; }       });    });

// My homegrown LightBlock which actually removes continued messages var blocks = JSON.parse(localStorage.getItem('chat-blocks') || '[]'); mainRoom.viewDiscussion.getTextInput.on('keypress', function(e) {       if (e.which != 13) return;        var split = this.value.split(' '),        command = split[0],        rest = split.slice(1).join(' ');        switch (command) {            case '/block':                e.preventDefault;                this.value = ;                if (blocks.includes(rest)) {                    inline(rest + ' is already blocked.');                } else {                    blocks.push(rest);                    localStorage.setItem('chat-blocks', JSON.stringify(blocks));                    inline('Blocked ' + rest + '.');                    inline('Currently blocked users: ' + blocks.join(', '));                }                break;            case '/unblock':                e.preventDefault;                this.value = ;                var index = blocks.indexOf(rest);                if (index === -1) { inline(rest + ' is not blocked.'); } else { blocks.splice(index, 1); localStorage.setItem('chat-blocks', JSON.stringify(blocks)); inline('Unblocked ' + rest + '.'); inline('Currently blocked users: ' + blocks.join(', ')); }               break; case '/blocks': e.preventDefault; this.value = ''; inline('Currently blocked users: ' + blocks.join(', ')); break; }   });    mainRoom.model.chats.bind('afteradd', function(model) { if (blocks.includes(model.attributes.name)) { mainRoom.model.chats.remove(model); // No backing out }   });    function inline(text) {        mainRoom.model.chats.add(new models.InlineAlert({            text: text,            synthetic: true        }));    }    ['main', 'private'].forEach(function(scope) { mainRoom.viewUsers.bind(scope + 'ListClick', function(e) {           $('#UserStatsMenu img').attr('src', function(_, src) { return src.replace('/scale-to-width-down/28', '/scale-to-width-down/150'); });           var user = mainRoom.model.users.findByName(e.name);			if (!user) return; // wtf			$('#UserStatsMenu .info').append(' ');			user.attributes.groups.forEach(function(group) { $('#UserStatsMenu .groups').append($(' ', { 'class': 'group', 'data-group': group }));           });            $('#UserStatsMenu').offset({ top: $('#UserStatsMenu').offset.top - $('#UserStatsMenu .groups').height - 4 });       });    }); });

mw.hook('dev.chat.render').add(function {   var button = new dev.chat.Button({ name: 'AFKButton', attr: { text: 'AFK', click: toggleAway }   }).el;    mainRoom.model.chats.bind('afteradd', function(model) { var userMain = mainRoom.model.users.findByName(wgUserName); if (model.attributes.name == wgUserName && userMain && userMain.attributes.statusState == 'away') { setBack; }   });    var sb = mainRoom.setBack;    function toggleAway {        var current = mainRoom.model.users.findByName(wgUserName).attributes.statusState; // No, mainRoom.userMain doesn't work        if (current == 'away') {            setBack;        } else {            setAway;        }    }    function setAway {        mainRoom.setAway;        clearTimeout(mainRoom.activityTimeout);        mainRoom.setBack = $.noop;        button.textContent = 'Back';    }    function setBack {        mainRoom.setBack;        mainRoom.activityTimer = setTimeout($.proxy(mainRoom.setAway, mainRoom), 5 * 60 * 1000);        mainRoom.setBack = sb;        mainRoom.setBack;        button.textContent = 'AFK';    }    mainRoom.socket.on("updateUser", function(msg) { var data = JSON.parse(msg.data).attrs, type = data.statusMessage, status = data.statusState, user = data.name; if (user == wgUserName && status != 'away') { mainRoom.setBack = sb; button.textContent = 'AFK'; }   });    /* Pings */    var avatars = {};

if (Notification.permission === 'default') { Notification.requestPermission; }

function parseInlineAlertRegex(elem) { // We could probably make it prettier, but as long as it's abstracted inside this function we probably won't need to deal with it again var msg = mw.messages.get(elem) .replace(/[-[\]{}*+?.,\\^$|#\s]/g, '\\$&') //escape regex .replace(/(\\\$\d)(?!.*\1)/g, '(.+?)') //place capturing groups .replace(/\\\$\d/g, '.+?'); //replace remaining $Ns

return new RegExp(msg); }

function notify(title, text, icon) {

if (Notification.permission !== 'granted') { return; }       var notification = new Notification(title, {            body: text,            icon: icon        }); notification.onclick = function { window.focus; notification.close; };   }

function formatAvi(avatar) { // Aaanyways, this regex matches only the last occurrence of 28 in the string // (?!) means a negative lookahead, so it looks ahead of the match for any occurrences of (any character) times 0 to infinity // immediately followed by 28 return avatar.replace(/28(?!.*28)/, '150'); }

function highlight($elem, match) { var $message = $elem, html = $message.html, lastIndex = match.index + match[0].length, text = html.slice(match.index, lastIndex), span = $(' ', {               id: 'ping',                text: text,                css: {                    color: 'red'                }            }).get(0);

html = html.slice(0, match.index) + span.outerHTML + html.slice(lastIndex); $message.html(html); }

function saveAvatar(user) { avatars[user.attributes.name] = formatAvi(user.attributes.avatarSrc); }

var kick_regex = parseInlineAlertRegex('chat-user-was-kicked'), ban_regex = parseInlineAlertRegex('chat-user-was-banned');

function afterChat(chat) { var $elem = $('#entry-' + chat.cid).find('.message'), html = $elem.html, text = chat.attributes.text, name = chat.attributes.name, icon = formatAvi(chat.attributes.avatarSrc), inline = chat.attributes.isInlineAlert || false, match; if (document.hasFocus && mainRoom.active) return;

if (name !== mw.config.get('wgUserName') && !inline) { if (match = html.match(PING_REGEX)) { notify(name + ' pinged you!', text, icon); highlight($elem, match); }       } else if (inline) { if (match = text.match(kick_regex)) { notify(match[1] + ' was kicked!', '', avatars[match[1]]); } else if (match = text.match(ban_regex)) { notify(match[1] + ' was banned!', '', avatars[match[1]]); }       }    }    mainRoom.model.chats.bind('afteradd', afterChat); mainRoom.model.users.models.forEach(saveAvatar); mainRoom.model.users.bind('add', saveAvatar); });

/* ChatPlugins */ var ChatPlugins = { release: { version: 1.1, branch: "Stable" },	models: { feature: function(id, name, access, script) { this.enabled = false; this.id = id; this.name = name; this.access = access; this.script = script; },		alert: function(text) { newInlineAlert = new models.InlineAlert; newInlineAlert.attributes.text = text; mainRoom.model.chats.add(newInlineAlert); },		command: function(command, script) { this.command = command; this.script = script; }	},	features: {}, settings: { release: { version: 1.0, branch: "Stable" },		icons: { staffIcon: "http://img1.wikia.nocookie.net/__cb20140626173406/gamedezyner/images/6/60/StaffIcon.png", modIcon: "http://img1.wikia.nocookie.net/__cb20140626173343/gamedezyner/images/8/89/ModIcon.png" },		sounds: { pingSound: "https://notificationsounds.com/soundfiles/9461cce28ebe3e76fb4b931c35a169b0/file-sounds-1044-inquisitiveness.mp3" },		features: { pings: true }	},	save: function { ChatPlugins.settings.features.pings = ChatPlugins.features.pings.enabled; api.functions.editPage("User:" + wgUserName + "/ChatPlugins.js", JSON.stringify(ChatPlugins.settings)); },	load: function { new ChatPlugins.models.alert("Welcome to Chat Plugins 1.0!"); pagecontents = api.functions.getPageContents("User:" + wgUserName + "/ChatPlugins.js"); if (pagecontents == "error") { new ChatPlugins.models.alert("There seems to be something wrong with your settings file, or it doesn't exist yet. Default settings have been saved."); ChatPlugins.save; } else { ChatPlugins.settings = JSON.parse(pagecontents); ChatPlugins.features.pings.enabled = ChatPlugins.settings.features.pings; ChatPlugins.features.pings.words = ChatPlugins.settings.pings; }		pagecontents = api.functions.getPageContents("MediaWiki:ChatPluginsSettings.js"); if (pagecontents != "error") { wikicustom = JSON.parse(pagecontents); if (typeof(wikicustom.settings) != "object") { new ChatPlugins.models.alert("This wiki has a custom settings page, but it is broken."); } else { ChatPlugins.settings.icons = wikicustom.settings.icons; //Load Wiki-specific icons ChatPlugins.settings.sounds = wikicustom.settings.sounds; //Load Wiki-specific sounds new ChatPlugins.models.alert("This wiki has custom settings and they have been applied."); }		}	} }; // Call API function callAPI(data, method, callback) { data.format = 'json'; $.ajax({		data: data,		dataType: 'json',		url: wgScriptPath + '/api.php',		type: method,		success: function(response) {			if (response.error) showError('API error: ' + response.error.info);			else callback(response);		},		error: function(xhr, error) {			showError('AJAX error: ' + error);		}	}); } //Inline-mod tools function scrollToBottom { var chat = document.getElementById('Chat_' + mainRoom.roomId); chat.scrollTop = chat.scrollHeight; } ChatPlugins.features.modIcons = new ChatPlugins.models.feature(null, "Mod Icons", 0, function(chat) {	var time = new Date;	var hours = time.getHours;	var minutes = time.getMinutes;	var seconds = time.getSeconds;	if (hours < 10) hours = '0' + hours;	if (minutes < 10) minutes = "0" + minutes;	if (seconds < 10) seconds = "0" + seconds;	mainRoom.viewDiscussion.chatUL.children.last.children(".message").attr('msg-source', chat.attributes.text);	mainRoom.viewDiscussion.chatUL.children.last.children(".message").attr('msg-time', hours + ':' + minutes + ':' + seconds);	var icon = ;		mainRoom.viewDiscussion.chatUL.children.last.children('.message').hover(function { thistarget = this; username = $(thistarget).parent.attr("data-user"); timestamp = $(thistarget).attr('msg-time'); message = $(thistarget).attr('msg-source'); $(thistarget).append(' Quote '); $(thistarget).children('.inline-quote').click(function(e) {			if (e.shiftKey) {				$('.message textarea').val($('.message textarea').val + '[' + timestamp + '] ' + username + ": " + message.replace(/^\/me/, "* " + username) + '\n');			} else {				$('.message textarea').val('[' + timestamp + '] ' + username + ": " + message.replace(/^\/me/, "* " + username) + '\n');				scrollToBottom;			}			$(".message textarea").focus;		}); }, function { $(this).children('.inline-quote').remove; }); }); //Bind function to chat updates setTimeout(function {	mainRoom.model.chats.bind('afteradd', ChatPlugins.features.modIcons.script, mainRoom.viewDiscussion); }, 15000);

$('[name="message"]').keypress(function (e) {   if (e.which == 32 || e.which == 13) {        switch (this.value) {        case 'h':            var messages = [                'Hey',                 'Sup',                 'Yo',                 'Heyo',                 'Hi',                 'o/',                 'Hiya'                ],            greetWith = messages[Math.floor(Math.random * messages.length)];            this.value = greetWith;            break;        case '/logs':            this.value = 'You can view the chat logs here.';            break;            case '/emotes':            this.value = 'You can view the emoticons here.';            break;        case '/tou':            this.value = 'Wikia\'s Terms of Use can be found here.';            break;         case '/shrug':            this.value = '¯\\_(ツ)_/¯'; break; }       var test = "/google"; if (this.value.indexOf(test) > -1 && this.value.indexOf(test) < 8) { var query = this.value.replace('/google ', ''); query = query.replace(/ /g, "+"); this.value = "http://www.lmgtfy.com/?q=" + query; }   } });

// DiscordizeChat function change_room { var room = mainRoom.chats.privates[mainRoom.activeRoom]; if (!room) return; $('#ChatHeader .private').text(room.model.privateRoom.attributes.users.filter(function(n) { return n != wgUserName; })); } mainRoom.viewUsers.bind('privateListClick', change_room); mainRoom.model.room.bind('change', $.debounce(0, change_room)); mainRoom.model.privateUsers.bind('add', change_room);