User:Godisme/ChatHacks.js

/* * ChatHacks.js, by Monchoman45. * Version 5.dontUseThisYetBecauseItMightExplodeAndThatWouldBeBad * * 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 or any other specified phrases */ $(function {		$('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:100px;\n\tdisplay:block;\n}\n#pingspan div span {\n\tfont-size:55%;\n}\n ');		//Add a 'go afk' button and a 'clear chat' button		$('#Write').append('AFKClear');		//Unbind all of the window 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 (?) ' + ((readCookie('pingphrases')) ? readCookie('pingphrases').split('\\n').join('\n') : 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'; createCookie('pingphrases', document.getElementById('pings').value.split('\n').join('\\n'), 99999);}*/ }); if(wgPageName == 'Special:Chat') {	/*window.canding = false; //to prevent pinging people with scrollback	setTimeout('window.canding = true', 10000); //lazy load quick fix	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).bind('focus', Unding);	window.ding = 0;*/	window.staff = [];	window.mods = [];	//Make a list of mods and staff	NodeRoomController.prototype.onInitial = function(message) {		if(!this.isInitialized){			_.each(this.model.chats.models, $.proxy(function(data) {				this.model.chats.remove(data);			},this)); 			this.model.chats.trigger('clear');			// 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"){					$.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. }		for(var i in this.afterInitQueue) { this.socket.send(this.afterInitQueue[i]); } 		this.afterInitQueue = []; window.staff = []; window.mods = []; var list = document.getElementById('WikiChatList').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); }			}		}		//window.canding = true; }	//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); }				}			}			//window.canding = true; }		else { //Run the giant switch statement msgReceived.apply(this, arguments); }	}*/	//Add/remove mods when people join/leave NodeChatUsers.prototype.addUser = 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}); var list = (user.attributes.isPrivate) ? $('#PrivateChatList') : $('#WikiChatList'); var el = $(view.render.el); // For private chats, show private headline and possibly select the chat if(user.get('isPrivate')) { $('#Rail h1.private').show; if(user.get('active')) { el.addClass('selected'); }		}		// Add users to list if (list.children.length) { // The list is not empty. Arrange alphabetically. var compareA = el.data('user').toUpperCase; var wasAdded = false; list.children.each(function(idx, itm) {				compareB = $(itm).data('user').toUpperCase;				if (compareA < compareB) {					$(itm).before(el);					wasAdded = true;					return false;				}			}); if (!wasAdded) { list.append(el); }		} else { // The list is empty. Append this user. list.append(el); }		// Scroll the list down if a new private chat is being added if (user.get('isPrivate')) { $.log('UserView SCROLL DOWN!!!'); $('#Rail').scrollTop($('#Rail').get(0).scrollHeight); }		// Only show chevron in public chat if there is anyone to talk to		if (list.children.length > 1) { $('#Rail .public .chevron').show; } else { $('#Rail .public .chevron').hide; }			}	NodeChatUsers.prototype.removeUser = function (user) { 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);}} var view = new UserView({model: user}); view.getUserElement.remove; }	/*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 NodeChatDiscussion.prototype.addChat = function (chat) { // Determine if chat view is presently scrolled to the bottom var isAtBottom = false; if (( this.chatDiv.scrollTop + 1) >= (this.chatUL.outerHeight - this.chatDiv.height)) { isAtBottom = true; }		// Add message to chat var view = new ChatView({model: chat}); this.chatUL.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(window.canding && chat.attributes.name != wgUserName && !chat.attributes.isInlineAlert) { var pings = document.getElementById('pings').value.split('\n'); for(var i = 0; i < pings.length; i++) { if(chat.attributes.text.toLowerCase.indexOf(pings[i].toLowerCase) != -1) { $('#sound').html(''); if(document.hasFocus == false) {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) { this.scrollToBottom; }	}	/*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(window.canding && chat.attributes.name != wgUserName && !chat.attributes.isInlineAlert) { var pings = document.getElementById('pings').value.split('\n'); for(var i = 0; i < pings.length; i++) { if(chat.attributes.text.toLowerCase.indexOf(pings[i].toLowerCase) != -1) { $('#sound').html(''); if(document.hasFocus == false) {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.prototype.setAway = function (msg){ if(!msg) {var msg = '';} $.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.prototype.setBack = function { if( ! this.comingBackFromAway){ // if we have sent this command (but just haven't finished coming back yet), don't keep spamming the server w/this command $.log("Telling the server that I'm back."); this.comingBackFromAway = true; 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 - fail for not working, but at least it doesn't bork anything NodeChatController.prototype.sendMessage = function (event) { if(!this.active) { return true; }		if (event.which == 13 && !event.shiftKey) { event.preventDefault; mainRoom.resetActivityTimer; mainRoom.setBack; var inputField = this.viewDiscussion.getTextInput; var send = Preparse(inputField.val); if (inputField.val && send) { var chatEntry = new models.ChatEntry({roomId: this.roomId, name: wgUserName, text: inputField.val}); if( this.mainController != null ) { //is prive if( this.afterInitQueue.length < 1 || this.model.users.length < 2 ){ this.mainController.socket.send( this.model.privateRoom.xport ); }					if( !this.isInitialized ) { this.afterInitQueue.push(chatEntry.xport); //temp chat entry in case of slow connection time chatEntry.set({temp : true, avatarSrc: wgAvatarUrl }); this.model.chats.add(chatEntry); } else { this.socket.send(chatEntry.xport); }				} else { this.socket.send(chatEntry.xport); }				event.preventDefault; }			inputField.val(''); $.log('submitting form'); inputField.focus; }	}	mainRoom.viewDiscussion.unbind('sendMessage'); //Old callback goes away mainRoom.viewDiscussion.bind('sendMessage', $.proxy(mainRoom.sendMessage, mainRoom)); //New callback goes in } /*function InlineAlert(text) { for(var i = 0; i < $('.Chat').length; i++) { if($('.Chat')[i].style.display == 'block') {} }	//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': ClearWindow; return false; break; case '/kickban': var mod = new models.KickBanCommand({userToBan: build(text, 1)}); this.socket.send(mod.xport); return false; break; /*case '/self': for(var i = 0; i < $('.Chat').length; i++) { if($('.Chat')[i].style.display == 'block') {var ref = i; break;} }			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 + '</a>'; i = k;							} break; default: newstr += str.charAt(i); break; }				}				$('.Chat ul').append('<li><img class="avatar" src="' + $('#ChatHeader .User img').attr('src') + '"> ' + wgUserName + ' (self) ' + newstr + ' </li>'); }			else { $('.Chat ul').append('<li><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) { mainRoom.setBack; }	else { mainRoom.setAway; } } function ClearWindow { for(var i = 0; i < $('.Chat').length; i++) { if($('.Chat')[i].style.display == 'block') {$('.Chat')[i].getElementsByTagName('ul')[0].innerHTML = '';} }	InlineAlert('Window cleared.'); } function createCookie(name,value,days) { if (days) { var date = new Date; date.setTime(date.getTime+(days*24*60*60*1000)); var expires = "; expires="+date.toGMTString; }	else var expires = ""; document.cookie = name+"="+value+expires+"; path=/"; } function readCookie(name) { var nameEQ = name + "="; var ca = document.cookie.split(';'); for(var i=0;i < ca.length;i++) { var c = ca[i]; while (c.charAt(0)==' ') c = c.substring(1,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); }	return null; }