User:Monchoman45/ChatHacks.js

/* * ChatHacks.js, by Monchoman45. * * Features: *  Ability to clear your chat window *  A message preparser with /me, /afk, /away, /clear, /self, and /kickban *  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 */ $(function {	if(wgPageName == 'Special:Chat') {		$('body').prepend('\n.stafficon {\n\tmargin-bottom:-4px;\n}\n.modicon {\n\tmargin-bottom:-2px;\n}\n.UserStatsMenu {\n\tcolor:#000;\n}\n.Chat .continued {\n\ttop:0;\n\tmargin-bottom:0;\n}\n.Write [name="message"] {\n\twidth:93%;\n}\naudio {display:none;}\n#pingspan {\n\tposition:absolute;\n\tz-index:5;\n\ttop:23px;\n\tmargin-left:15px;\n\tfont-size:15px;\n\tfont-weight:normal;\n\tline-height:15px;\n}\n#pings {\n\tresize:none;\n\tmargin-left:0;\n\tfont-size:12px;\n\theight:60px;\n\tdisplay:block;\n}\n ');		//Add a 'go afk' button and a 'clear chat' button		$('#Write').append('AFKClear');		//Unbind all of the listeners that set your status to back $(window).unbind('mousemove').unbind('focus').unbind('keypress'); //Add the sound space $('body').append(' '); //Add the area for adding more pings $('#ChatHeader .wordmark').append(' Ping phrases ' + wgUserName + ' '); document.getElementById('pingspan').onmouseover = function(event) {document.getElementById('pings').style.display = 'block';} document.getElementById('pingspan').onmouseout = function(event) {document.getElementById('pings').style.display = 'none';} window.titleorig = document.title; function Unding { //for fixing the title after you've been dinged document.getElementsByTagName('title')[0].innerHTML = window.titleorig; clearInterval(window.ding); }		window.onfocus = Unding; window.onclick = Unding; //This better not lag epicly window.ding = 0; window.staff = []; window.mods = [];

//Make a list of mods and staff msgReceived = NodeChatController.view.msgReceived; //Store the big switch statement NodeChatController.view.msgReceived = function(message) { //Instead of putting the whole switch statement here just to change one small piece, we change the piece and if it isn't relevant, we run the original statement. if(message.event == 'initial') { if(!this.isInitialized){ // On first connection, just update the entire model. this.model.mport(message.data); this.isInitialized = true; } else { // If this is a reconnect... go through the model that was given and selectively, only add ChatEntries that were not already in the collection of chats. var jsonObj = JSON.parse(message.data); var chatEntries = this.model.chats; _.each(jsonObj.collections.chats.models, function(item, index){						var match = chatEntries.get(item.id);						if(typeof match == "undefined"){							NodeChatHelper.log("Found a ChatEntry that must have occurred during reconnection. Adding it to the model...");							var additionalEntry = new models.ChatEntry;							additionalEntry.mport( JSON.stringify(item) );							chatEntries.add(additionalEntry);						}					}); // TODO: update the entire userlist (if the server went down or something, you're not going to get "part" messages for the users who are gone). // See BugzId 6107 for more info & partially completed code. }				window.staff = []; window.mods = []; var list = document.getElementById('Users').getElementsByTagName('ul')[0].getElementsByTagName('li'); for(var i in list) { if(list[i].className) { var classes = list[i].className.split(' '); var user = false; var isstaff = false; var mod = false; for(var j in classes) { if(classes[j] == 'User') {user = true;} if(classes[j] == 'staff') {isstaff = true;} if(classes[j] == 'chat-mod') {mod = true;} }						if(isstaff && user) { staff.push(list[i].getElementsByTagName('span')[0].innerHTML); }						else if(mod && user) { mods.push(list[i].getElementsByTagName('span')[0].innerHTML); }					}				}			}			else { //Run the giant switch statement msgReceived.apply(this, arguments); }		}		//Add/remove mods when people join/leave NodeChatController.view.model.users._callbacks.add[0] = function(user) { if(user.attributes.isStaff == true) { var isstaff = true; for(var i in staff) {if(staff[i] == user.attributes.name) {isstaff = false;}} if(isstaff == true) {staff.push(user.attributes.name);} }			else if(user.attributes.isModerator == true) { var mod = true; for(var i in mods) {if(mods[i] == user.attributes.name) {mod = false;}} if(mod == true) {mods.push(user.attributes.name);} }			var view = new UserView({model: user}); $('#Users > ul').append(view.render.el); }		NodeChatController.view.model.users._callbacks.remove[0] = function(user) { NodeChatHelper.log("Trying to remove " + user.get('name') + " from the list."); NodeChatHelper.log("Matches found: " + $('[id="' + NodeChatHelper.liIdByUsername( user.get('name') ) + '"]').length); for(var i in mods) {if(mods[i] == user.attributes.name) {mods.splice(i, 1);}} for(var i in staff) {if(staff[i] == user.attributes.name) {staff.splice(i, 1);}} $('[id="' + NodeChatHelper.liIdByUsername( user.get('name') ) + '"]').remove; }		//Put images on mod and staff posts when they're added, ping if you've been mentioned NodeChatController.view.model.chats._callbacks.add[0] = function (chat) { // Determine if chat view is presently scrolled to the bottom var isAtBottom = false; if (($("#Chat").scrollTop + 1) >= ($("#Chat ul").outerHeight - $("#Chat").height)) { isAtBottom = true; }			// Add message to chat var view = new ChatView({model: chat}); $('#Chat ul').append(view.render.el); var icon = ''; for(var i in staff) {if(staff[i] == chat.attributes.name) {icon = ' '}} for(var i in mods) {if(mods[i] == chat.attributes.name) {icon = ' '}} if(icon) {$('#Chat ul li:last-child .username').html($('#Chat ul li:last-child .username').html + icon);} if(chat.attributes.name != wgUserName && !chat.attributes.isInlineAlert) { var pings = document.getElementById('pings').value.split('\n'); for(var i in pings) { if(chat.attributes.text.toLowerCase.indexOf(pings[i].toLowerCase) != -1) { $('#sound').html(''); window.ding = setInterval('FlashTitle', 500); NodeChatHelper.scrollToBottom; var text = chat.attributes.text; var ref = text.toLowerCase.indexOf(pings[i].toLowerCase); var phrase = text.slice(ref, ref + pings[i].length); $('#Chat ul li:last-child .message').html(text.replace(phrase, ' ' + phrase + ' ')); }				}			}			// Scroll chat to bottom if (chat.attributes.name == wgUserName || isAtBottom) { NodeChatHelper.scrollToBottom; }		}		//Add a custom inline alert that tells you when your status changes NodeChatController.view.setAway = function { var msg = ''; //var msg = $(e.target).parent.find('.user').html; //if(!msg){msg = '';} NodeChatHelper.log("Attempting to go away with message: " + msg); var setStatusCommand = new models.SetStatusCommand({				statusState: STATUS_STATE_AWAY,				statusMessage: msg			}); InlineAlert('You are now away.'); this.socket.send(setStatusCommand.xport); }		NodeChatController.view.setBack = function { NodeChatHelper.log("Attempting to come BACK from away."); var setStatusCommand = new models.SetStatusCommand({				statusState: STATUS_STATE_PRESENT,				statusMessage: ''			}); InlineAlert('You are no longer away.'); this.socket.send(setStatusCommand.xport); }		//Parse messages before they're sent $('#Write [name="message"]').unbind('keypress'); $('#Write [name="message"]').keypress(function(event) {			if (event.which == 13 && !event.shiftKey) {				event.preventDefault;				NodeChatHelper.resetActivityTimer;				var send = Preparse(this.value);				if(send == true) {					NodeChatHelper.log('submitting form');					$(event.target).closest('form').submit;				}				this.value = '';			}		}); } });

function InlineAlert(text) { $('.Chat ul').append('' + text + ''); NodeChatHelper.scrollToBottom; }

function FlashTitle { if(document.getElementsByTagName('title')[0].innerHTML == window.titleorig) { document.getElementsByTagName('title')[0].innerHTML = 'Activity - ' + wgSiteName + ' chat'; }	else { document.getElementsByTagName('title')[0].innerHTML = window.titleorig; } }

function Preparse(input) { var text = input.split(' '); switch(text[0]) { case '/away': case '/afk': if($('#ChatHeader .User').hasClass('away') == false) {ToggleAway;} //if you're away, hitting enter has already sent you back return false; break; case '/clear': $('.Chat ul').html(''); InlineAlert('Window cleared.'); return false; break; case '/kickban': var mod = new models.KickBanCommand({userToBan: build(text, 1)}); NodeChatController.socket.send(mod.xport); return false; break; case '/self': if(text[1] != undefined) { str = build(text, 1); newstr = ''; for(var i = 0; i < str.length; i++) { switch(str.charAt(i)) { case '[': if(str.charAt(i + 1) == '[') { var k = str.indexOf(']', i); if(str.charAt(k + 1) == ']') { var substr = str.substring(i + 2, k); if(substr.indexOf('|') != -1) { var link = substr.substring(0, substr.indexOf('|')); var linktext = substr.substring(substr.indexOf('|') + 1, substr.length); }									else { var link = substr; var linktext = link; }									var linkspl = link.split(' '); link = ''; for(var j in linkspl) {link += linkspl[j] + '_';} link = link.substring(0, link.length - 1); newstr += '' + linktext + ''; i = k + 1; }							}							else if(str.substring(i + 1, i + 8) == 'http://') { var k = str.indexOf(']', i); var splstr = str.substring(i + 1, k).split(' '); if(splstr == str.substring(i + 1, k)) { var text = '[1]'; }								else { var text = build(splstr, 1); }								newstr += '' + text + ''; i = k;							} break; default: newstr += str.charAt(i); break; }				}				$('.Chat ul').append('<img class="avatar" src="' + $('#ChatHeader .User img').attr('src') + '"> ' + wgUserName + '  (self) ' + newstr + ' </li>'); }			else { $('.Chat ul').append('<img class="avatar" src="' + $('#ChatHeader .User img').attr('src') + '"> ' + wgUserName + '  (self) </li>'); }			NodeChatHelper.scrollToBottom; return false; break; case '/me': if(text[1] != undefined) {$('#Write [name="message"]').val('* ' + wgUserName + ' ' + build(text, 1));} else {$('#Write [name="message"]').val('* ' + wgUserName);} return true; break; default: return true; break; } }

//Parser helping function - takes an array of text created with .split(' '), //and an index number for where to start, then rebuilds the string. //Can also accept an index value for where to stop. function build(text, index, stop) { var newtext = ''; if(stop == undefined || stop == 0) {stop = text.length} else if(stop < 0) {stop += text.length} if(index == stop || index == text.length - 1) {return text[index];} for(var i = index; i < stop; i++) { newtext += text[i] + ' '; }	return newtext; }

function ToggleAway { if($('#ChatHeader .User').hasClass('away') == true) { NodeChatController.view.setBack; }	else { NodeChatController.view.setAway; } }