ajax-chat/public/js/chat.js

3005 lines
86 KiB
JavaScript

/*
* @package AJAX_Chat
* @author Sebastian Tschan
* @copyright (c) Sebastian Tschan
* @license GNU Affero General Public License
* @link https://blueimp.net/ajax/
*
* The SELFHTML documentation has been used throughout this project:
* http://selfhtml.org
*
* Stylesheet and cookie methods have been inspired by Paul Sowden (A List Apart):
* http://www.alistapart.com/stories/alternate/
*
* Modified for Flashii Chat
*/
// AJAX Chat client side logic:
var ajaxChat = {
settingsInitiated: null,
styleInitiated: null,
initializeFunction: null,
finalizeFunction: null,
loginChannelID: null,
loginChannelName: null,
timerRate: null,
timer: null,
ajaxURL: null,
baseURL: null,
regExpMediaUrl: null,
dirs: null,
startChatOnLoad: null,
chatStarted: null,
domIDs: null,
dom: null,
settings: null,
nonPersistentSettings: null,
unusedSettings: null,
bbCodeTags: null,
colorCodes: null,
emoticonCodes: null,
emoticonFiles: null,
soundFiles: null,
sounds: null,
soundTransform: null,
sessionName: null,
cookieExpiration: null,
cookiePath: null,
cookieDomain: null,
cookieSecure: null,
chatBotName: null,
chatBotID: null,
allowUserMessageDelete: null,
inactiveTimeout: null,
privateChannelDiff: null,
privateMessageDiff: null,
showChannelMessages: null,
messageTextMaxLength: null,
socketServerEnabled: null,
socketServerHost: null,
socketServerPort: null,
socketServerChatID: null,
socket: null,
socketIsConnected: null,
socketTimerRate: null,
socketReconnectTimer: null,
socketRegistrationID: null,
userID: null,
userName: null,
userRole: null,
channelID: null,
channelName: null,
channelSwitch: null,
usersList: null,
userNamesList: null,
userMenuCounter: null,
encodedUserName: null,
userNodeString: null,
ignoredUserNames: null,
lastID: null,
localID: null,
lang: null,
langCode: null,
baseDirection: null,
originalDocumentTitle: null,
blinkInterval: null,
httpRequest: null,
retryTimer:null,
retryTimerDelay:null,
DOMbuffering: null,
DOMbuffer: null,
DOMbufferRowClass: 'rowOdd',
imageID: 0,
init: function(config, lang, initSettings, initStyle, initialize, initializeFunction, finalizeFunction) {
this.httpRequest = new Object();
this.usersList = new Array();
this.userNamesList = new Array();
this.userMenuCounter = 0;
this.lastID = 0;
this.localID = 0;
this.lang = lang;
this.initConfig(config);
this.initDirectories();
if(initSettings) {
this.initSettings();
}
if(initStyle) {
this.initStyle();
}
this.initializeFunction = initializeFunction;
this.finalizeFunction = finalizeFunction;
if(initialize) {
this.setLoadHandler();
}
},
initConfig: function(config) {
this.loginChannelID = config['loginChannelID'];
this.loginChannelName = config['loginChannelName'];
this.timerRate = config['timerRate'];
this.ajaxURL = config['ajaxURL'];
this.baseURL = config['baseURL'];
this.regExpMediaUrl = config['regExpMediaUrl'];
this.startChatOnLoad = config['startChatOnLoad'];
this.domIDs = config['domIDs'];
this.settings = config['settings'];
this.nonPersistentSettings = config['nonPersistentSettings'];
this.bbCodeTags = config['bbCodeTags'];
this.colorCodes = config['colorCodes'];
this.emoticonCodes = config['emoticonCodes'];
this.emoticonFiles = config['emoticonFiles'];
this.soundFiles = config['soundFiles'];
this.sessionName = config['sessionName'];
this.cookieExpiration = config['cookieExpiration'];
this.cookiePath = config['cookiePath'];
this.cookieDomain = config['cookieDomain'];
this.cookieSecure = config['cookieSecure'];
this.chatBotName = config['chatBotName'];
this.chatBotID = config['chatBotID'];
this.allowUserMessageDelete = config['allowUserMessageDelete'];
this.inactiveTimeout = config['inactiveTimeout'];
this.privateChannelDiff = config['privateChannelDiff'];
this.privateMessageDiff = config['privateMessageDiff'];
this.showChannelMessages = config['showChannelMessages'];
this.messageTextMaxLength = config['messageTextMaxLength'];
this.socketServerEnabled = config['socketServerEnabled'];
this.socketServerHost = config['socketServerHost'];
this.socketServerPort = config['socketServerPort'];
this.socketServerChatID = config['socketServerChatID'];
this.DOMbuffering = false;
this.DOMbuffer = "";
this.retryTimerDelay = this.timerRate + (((this.inactiveTimeout*6000) - this.timerRate)/4);
},
initDirectories: function() {
this.dirs = new Object();
//this.dirs['emoticons'] = 'http://cdn.flashii.net/img/emoticons/';
//this.dirs['sounds'] = 'http://cdn.flashii.net/snd/chat/';
//this.dirs['emoticons'] = 'https://static.flash.moe/emoticons/';
this.dirs['emoticons'] = '';
//this.dirs['sounds'] = 'sounds/';
this.dirs['sounds'] = '';
},
initSettings: function() {
this.settingsInitiated = true;
this.unusedSettings = new Object();
var cookie = this.readCookie(this.sessionName + '_settings');
if(cookie) {
var settingsArray = cookie.split('&');
var setting,key,value,number;
for(var i=0; i<settingsArray.length; i++) {
setting = settingsArray[i].split('=');
if(setting.length == 2) {
key = setting[0];
value = this.decodeText(setting[1]);
switch(value) {
case 'true':
value = true;
break;
case 'false':
value = false;
break;
case 'null':
value = null;
break;
default:
number = parseFloat(value);
if(!isNaN(number)) {
if(parseInt(number) == number) {
value = parseInt(number);
} else {
value = number;
}
}
}
if(this.inArray(this.nonPersistentSettings, key)) {
// The setting is not used, store it for the persistSettings method:
this.unusedSettings[key] = value;
} else {
this.settings[key] = value;
}
}
}
}
},
persistSettings: function() {
if(this.settingsInitiated) {
var settingsArray = new Array();
for(var property in this.settings) {
if(this.inArray(this.nonPersistentSettings, property)) {
if(this.unusedSettings && this.unusedSettings[property]) {
// Store the unusedSetting previously stored:
this.settings[property] = this.unusedSettings[property];
} else {
continue;
}
}
settingsArray.push(property + '=' + this.encodeText(this.settings[property]));
}
this.createCookie(this.sessionName + '_settings', settingsArray.join('&'), this.cookieExpiration);
}
},
getSettings: function() {
return this.settings;
},
getSetting: function(key) {
// Only return null if setting is null or undefined, not if it is false:
for(var property in this.settings) {
if(property == key) {
return this.settings[key];
}
}
return null;
},
setSetting: function(key, value) {
this.settings[key] = value;
},
initializeSettings: function() {
if(this.settings['persistFontColor'] && this.settings['fontColor']) {
// Set the inputField font color to the font color:
if(this.dom['inputField']) {
this.dom['inputField'].className = this.settings['fontColor'];
}
}
},
initialize: function() {
this.setUnloadHandler();
this.initializeDocumentNodes();
this.loadPageAttributes();
this.initEmoticons();
this.initColorCodes();
this.initializeSettings();
this.setSelectedStyle();
this.customInitialize();
//preload the Alert icon (it can't display if there's no connection unless it's cached!)
this.setStatus('Alert');
if(typeof this.initializeFunction == 'function') {
this.initializeFunction();
}
if(!this.isCookieEnabled()) {
this.addChatBotMessageToChatList('/error CookiesRequired');
} else {
if(this.startChatOnLoad) {
this.startChat();
} else {
this.setStartChatHandler();
this.requestTeaserContent();
}
}
},
requestTeaserContent: function() {
var params = '&view=teaser';
params += '&getInfos=' + this.encodeText('userID,userName,userRole');
if(!isNaN(parseInt(this.loginChannelID))) {
params += '&channelID='+this.loginChannelID;
} else if(this.loginChannelName !== null) {
params += '&channelName='+this.encodeText(this.loginChannelName);
}
this.updateChat(params);
},
setStartChatHandler: function() {
if(this.dom['inputField']) {
this.dom['inputField'].onfocus = function() {
ajaxChat.startChat();
// Reset the onfocus event on first call:
ajaxChat.dom['inputField'].onfocus = '';
}
}
},
startChat: function() {
this.chatStarted = true;
if(this.dom['inputField'] && this.settings['autoFocus']) {
this.dom['inputField'].focus();
}
this.loadHTML5Sounds();
this.startChatUpdate();
},
loadPageAttributes: function() {
var htmlTag = document.getElementsByTagName('html')[0];
this.langCode = htmlTag.getAttribute('lang') ? htmlTag.getAttribute('lang') : 'en';
this.baseDirection = htmlTag.getAttribute('dir') ? htmlTag.getAttribute('dir') : 'ltr';
},
setLoadHandler: function() {
// Make sure initialize() is called on page load:
var onload = window.onload;
if(typeof onload != 'function') {
window.onload = function() {
ajaxChat.initialize();
}
} else {
window.onload = function() {
onload();
ajaxChat.initialize();
}
}
},
setUnloadHandler: function() {
// Make sure finalize() is called on page unload:
var onunload = window.onunload;
if(typeof onunload != 'function') {
window.onunload = function() {
ajaxChat.finalize();
}
} else {
window.onunload = function() {
ajaxChat.finalize();
onunload();
}
}
},
updateDOM: function(id, str, prepend, overwrite) {
var domNode = this.dom[id] ? this.dom[id] : document.getElementById(id);
if(!domNode) {
return;
}
try {
// Test for validity before adding the string to the DOM:
domNode.cloneNode(false).innerHTML = str;
if(overwrite) {
domNode.innerHTML = str;
} else if(prepend) {
domNode.innerHTML = str + domNode.innerHTML;
} else {
domNode.innerHTML += str;
}
} catch(e) {
this.addChatBotMessageToChatList('/error DOMSyntax '+id);
this.updateChatlistView();
}
},
initializeDocumentNodes: function() {
this.dom = new Object();
for(var key in this.domIDs) {
this.dom[key] = document.getElementById(this.domIDs[key]);
}
},
initEmoticons: function() {
this.DOMbuffer = "";
for(var i=0; i<this.emoticonCodes.length; i++) {
// Replace specials characters in emoticon codes:
this.emoticonCodes[i] = this.encodeSpecialChars(this.emoticonCodes[i]);
this.DOMbuffer = this.DOMbuffer
+ '<a href="javascript:ajaxChat.insertText(\''
+ this.scriptLinkEncode(this.emoticonCodes[i])
+ '\');"><img src="'
+ this.dirs['emoticons']
+ this.emoticonFiles[i]
+ '" alt="'
+ this.emoticonCodes[i]
+ '" title="'
+ this.emoticonCodes[i]
+ '"/></a>';
}
if(this.dom['emoticonsContainer']) {
this.updateDOM('emoticonsContainer', this.DOMbuffer);
}
this.DOMbuffer = "";
},
initColorCodes: function() {
if(this.dom['colorCodesContainer']) {
this.DOMbuffer = "";
for(var i=0; i<this.colorCodes.length; i++) {
this.DOMbuffer = this.DOMbuffer
+ '<a class="'
+ this.colorCodes[i]
+ '" '
+ 'href="javascript:ajaxChat.setFontColor(\''
+ this.colorCodes[i]
+ '\');" title="'
+ this.colorCodes[i]
+ '"></a>'
+ "\r\n"
}
this.updateDOM('colorCodesContainer', this.DOMbuffer);
this.DOMbuffer = "";
}
},
setStatus: function(currentStatus) {
//Make sure the status container div exists before changing its class.
if (document.getElementById('statusIconContainer') != null ) {
//currentStatus options are: Off for green, On for orange, and Alert for red.
document.getElementById('statusIconContainer').className = 'statusContainer' + currentStatus;
}
},
startChatUpdate: function() {
// Start the chat update and retrieve current user and channel info and set the login channel:
var infos = 'userID,userName,userRole,channelID,channelName';
if(this.socketServerEnabled) {
infos += ',socketRegistrationID';
}
var params = '&getInfos=' + this.encodeText(infos);
if(!isNaN(parseInt(this.loginChannelID))) {
params += '&channelID='+this.loginChannelID;
} else if(this.loginChannelName !== null) {
params += '&channelName='+this.encodeText(this.loginChannelName);
}
this.updateChat(params);
},
updateChat: function(paramString) {
var requestUrl = this.ajaxURL
+ '&lastID='
+ this.lastID;
if(paramString) {
requestUrl += paramString;
}
this.makeRequest(requestUrl,'GET',null);
},
loadFlashInterface: function() {
if(this.dom['flashInterfaceContainer']) {
this.updateDOM(
'flashInterfaceContainer',
'<object id="ajaxChatFlashInterface" style="position:absolute; left:-100px;" '
+'classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" '
+'codebase="'
+ window.location.protocol
+'//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" '
+'height="1" width="1">'
+'<param name="flashvars" value="bridgeName=ajaxChat"/>'
+'<param name="src" value="FABridge.swf"/>'
+'<embed name="ajaxChatFlashInterface" pluginspage="'
+ window.location.protocol
+'//www.macromedia.com/go/getflashplayer" '
+'src="FABridge.swf" height="1" width="1" flashvars="bridgeName=ajaxChat"/>'
+'</object>'
);
FABridge.addInitializationCallback('ajaxChat', this.flashInterfaceLoadCompleteHandler);
}
},
flashInterfaceLoadCompleteHandler: function() {
ajaxChat.initializeFlashInterface();
},
initializeFlashInterface: function() {
if(this.socketServerEnabled) {
this.socketTimerRate = (this.inactiveTimeout-1)*60*1000;
this.socketConnect();
}
this.loadSounds();
this.initializeCustomFlashInterface();
},
socketConnect: function() {
if(!this.socketIsConnected) {
try {
if(!this.socket && FABridge.ajaxChat) {
this.socket = FABridge.ajaxChat.create('flash.net.XMLSocket');
this.socket.addEventListener('connect', this.socketConnectHandler);
this.socket.addEventListener('close', this.socketCloseHandler);
this.socket.addEventListener('data', this.socketDataHandler);
this.socket.addEventListener('ioError', this.socketIOErrorHandler);
this.socket.addEventListener('securityError', this.socketSecurityErrorHandler);
}
this.socket.connect(this.socketServerHost, this.socketServerPort);
} catch(e) {
//alert(e);
}
}
clearTimeout(this.socketReconnectTimer);
this.socketReconnectTimer = null;
},
socketConnectHandler: function(event) {
ajaxChat.socketIsConnected = true;
// setTimeout is needed to avoid calling the flash interface recursively:
setTimeout('ajaxChat.socketRegister()', 0);
},
socketCloseHandler: function(event) {
ajaxChat.socketIsConnected = false;
if(ajaxChat.socket) {
clearTimeout(ajaxChat.timer);
ajaxChat.updateChat(null);
}
},
socketDataHandler: function(event) {
ajaxChat.socketUpdate(event.getData());
},
socketIOErrorHandler: function(event) {
// setTimeout is needed to avoid calling the flash interface recursively (e.g. sound on new messages):
setTimeout('ajaxChat.addChatBotMessageToChatList(\'/error SocketIO\')', 0);
setTimeout('ajaxChat.updateChatlistView()', 1);
},
socketSecurityErrorHandler: function(event) {
// setTimeout is needed to avoid calling the flash interface recursively (e.g. sound on new messages):
setTimeout('ajaxChat.addChatBotMessageToChatList(\'/error SocketSecurity\')', 0);
setTimeout('ajaxChat.updateChatlistView()', 1);
},
socketRegister: function() {
if(this.socket && this.socketIsConnected) {
try {
this.socket.send(
'<register chatID="'
+this.socketServerChatID
+'" userID="'
+this.userID
+'" regID="'
+this.socketRegistrationID
+'"/>'
);
} catch(e) {
//alert(e);
}
}
},
loadXML: function(str) {
if(!arguments.callee.parser) {
try {
// DOMParser native implementation (Mozilla, Opera):
arguments.callee.parser = new DOMParser();
} catch(e) {
var customDOMParser = function() {}
if(navigator.appName == 'Microsoft Internet Explorer') {
// IE implementation:
customDOMParser.prototype.parseFromString = function(str, contentType) {
if(!arguments.callee.XMLDOM) {
arguments.callee.XMLDOM = new ActiveXObject('Microsoft.XMLDOM');
}
arguments.callee.XMLDOM.loadXML(str);
return arguments.callee.XMLDOM;
}
} else {
// Safari, Konqueror:
customDOMParser.prototype.parseFromString = function(str, contentType) {
if(!arguments.callee.httpRequest) {
arguments.callee.httpRequest = new XMLHttpRequest();
}
arguments.callee.httpRequest.open(
'GET',
'data:text/xml;charset=utf-8,'+encodeURIComponent(str),
false
);
arguments.callee.httpRequest.send(null);
return arguments.callee.httpRequest.responseXML;
}
}
arguments.callee.parser = new customDOMParser();
}
}
return arguments.callee.parser.parseFromString(str, 'text/xml');
},
socketUpdate: function(data) {
var xmlDoc = this.loadXML(data);
if(xmlDoc) {
this.handleOnlineUsers(xmlDoc.getElementsByTagName('user'));
// If the root node has the attribute "mode" set to "1" it is a channel message:
if((this.showChannelMessages || xmlDoc.firstChild.getAttribute('mode') != '1') && !this.channelSwitch) {
var channelID = xmlDoc.firstChild.getAttribute('channelID');
if(channelID == this.channelID ||
parseInt(channelID) == parseInt(this.userID)+this.privateMessageDiff
) {
this.handleChatMessages(xmlDoc.getElementsByTagName('message'));
}
}
}
},
setAudioVolume: function(volume) {
volume = parseFloat(volume);
if(!isNaN(volume)) {
if(volume < 0) {
volume = 0.0;
} else if(volume > 1) {
volume = 1.0;
}
this.settings['audioVolume'] = volume;
try {
if(!this.soundTransform) {
this.soundTransform = FABridge.ajaxChat.create('flash.media.SoundTransform');
}
this.soundTransform.setVolume(volume);
} catch(e) {
//alert(e);
}
}
return ajaxChat.setHTML5SoundVolume(volume);
},
loadSounds: function() {
try {
this.setAudioVolume(this.settings['audioVolume']);
this.sounds = new Object();
var sound,urlRequest;
for(var key in this.soundFiles) {
sound = FABridge.ajaxChat.create('flash.media.Sound');
sound.addEventListener('complete', this.soundLoadCompleteHandler);
sound.addEventListener('ioError', this.soundIOErrorHandler);
urlRequest = FABridge.ajaxChat.create('flash.net.URLRequest');
urlRequest.setUrl(this.dirs['sounds']+this.soundFiles[key]);
sound.load(urlRequest);
}
} catch(e) {
alert(e);
}
},
soundLoadCompleteHandler: function(event) {
var sound = event.getTarget();
for(var key in ajaxChat.soundFiles) {
// Get the sound key by matching the sound URL with the sound filename:
if((new RegExp(ajaxChat.soundFiles[key])).test(sound.getUrl())) {
// Add the loaded sound to the sounds list:
ajaxChat.sounds[key] = sound;
}
}
},
soundIOErrorHandler: function(event) {
// setTimeout is needed to avoid calling the flash interface recursively (e.g. sound on new messages):
setTimeout('ajaxChat.addChatBotMessageToChatList(\'/error SoundIO\')', 0);
setTimeout('ajaxChat.updateChatlistView()', 1);
},
soundPlayCompleteHandler: function(event) {
// soundChannel event 'soundComplete'
},
playSound: function(soundID) {
if(this.sounds && this.sounds[soundID]) {
try {
// play() parameters are
// startTime:Number (default = 0),
// loops:int (default = 0) and
// sndTransform:SoundTransform (default = null)
//return this.sounds[soundID].play(0, 0, this.soundTransform);
return ajaxChat.playHTML5Sound(soundID,this.sounds[soundID]);
} catch(e) {
//alert(e);
}
}
return null;
},
playSoundOnNewMessage: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
if(this.settings['audio'] && this.sounds && this.lastID && !this.channelSwitch) {
switch(userID) {
case this.chatBotID:
var messageParts = messageText.split(' ', 1);
switch(messageParts[0]) {
case '/login':
case '/channelEnter':
this.playSound(this.settings['soundEnter']);
break;
case '/logout':
case '/channelLeave':
case '/kick':
this.playSound(this.settings['soundLeave']);
break;
case '/error':
this.playSound(this.settings['soundError']);
break;
case '/unban':
this.playSound(this.settings['soundKick']);
break;
default:
this.playSound(this.settings['soundChatBot']);
}
break;
case this.userID:
this.playSound(this.settings['soundSend']);
break;
default:
var messageParts = messageText.split(' ', 1);
switch(messageParts[0]) {
case '/privmsg':
this.playSound(this.settings['soundPrivate']);
break;
default:
this.playSound(this.settings['soundReceive']);
}
break;
}
}
},
fillSoundSelection: function(selectionID, selectedSound) {
var selection = document.getElementById(selectionID);
// Skip the first, empty selection:
var i = 1;
for(var key in this.soundFiles) {
selection.options[i] = new Option(key, key);
if(key == selectedSound){
selection.options[i].selected = true;
}
i++;
}
},
getHttpRequest: function(identifier) {
if(!this.httpRequest[identifier]) {
if (window.XMLHttpRequest) {
this.httpRequest[identifier] = new XMLHttpRequest();
if (this.httpRequest[identifier].overrideMimeType) {
this.httpRequest[identifier].overrideMimeType('text/xml');
}
} else if (window.ActiveXObject) {
try {
this.httpRequest[identifier] = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
this.httpRequest[identifier] = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
}
}
}
}
return this.httpRequest[identifier];
},
makeRequest: function(url, method, data) {
ajaxChat.setStatus('On');
ajaxChat.retryTimer = setTimeout("ajaxChat.updateChat(null); ajaxChat.setStatus('Alert');", this.retryTimerDelay);
try {
var identifier;
if(data) {
// Create up to 50 HTTPRequest objects:
if(!arguments.callee.identifier || arguments.callee.identifier > 50) {
arguments.callee.identifier = 1;
} else {
arguments.callee.identifier++;
}
identifier = arguments.callee.identifier;
} else {
identifier = 0;
}
this.getHttpRequest(identifier).open(method, url, true);
this.getHttpRequest(identifier).onreadystatechange = function() {
try {
ajaxChat.handleResponse(identifier);
} catch(e) {
try {
clearTimeout(ajaxChat.timer);
} catch(e) {
//alert(e);
}
try {
if(data) {
ajaxChat.addChatBotMessageToChatList('/error ConnectionTimeout');
ajaxChat.setStatus('Alert');
ajaxChat.updateChatlistView();
}
} catch(e) {
//alert(e);
}
try {
ajaxChat.timer = setTimeout('ajaxChat.updateChat(null);', ajaxChat.timerRate);
} catch(e) {
//alert(e);
}
}
};
if(method == 'POST') {
this.getHttpRequest(identifier).setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
this.getHttpRequest(identifier).send(data);
} catch(e) {
clearTimeout(this.timer);
if(data) {
this.addChatBotMessageToChatList('/error ConnectionTimeout');
ajaxChat.setStatus('Alert');
this.updateChatlistView();
}
this.timer = setTimeout('ajaxChat.updateChat(null);', this.timerRate);
}
},
handleResponse: function(identifier) {
if (this.getHttpRequest(identifier).readyState == 4) {
if (this.getHttpRequest(identifier).status == 200) {
clearTimeout(ajaxChat.retryTimer);
var xmlDoc = this.getHttpRequest(identifier).responseXML;
ajaxChat.setStatus('Off');
} else {
// Connection status 0 can be ignored.
if (this.getHttpRequest(identifier).status == 0) {
ajaxChat.setStatus('On');
this.updateChatlistView();
return false;
} else {
this.addChatBotMessageToChatList('/error ConnectionStatus '+this.getHttpRequest(identifier).status);
ajaxChat.setStatus('Alert');
this.updateChatlistView();
return false;
}
}
}
if(!xmlDoc) {
return false;
}
this.handleXML(xmlDoc);
return true;
},
handleXML: function(xmlDoc) {
this.handleInfoMessages(xmlDoc.getElementsByTagName('info'));
this.handleOnlineUsers(xmlDoc.getElementsByTagName('user'));
this.handleChatMessages(xmlDoc.getElementsByTagName('message'));
this.channelSwitch = null;
this.setChatUpdateTimer();
},
setChatUpdateTimer: function() {
clearTimeout(this.timer);
if(this.chatStarted) {
var timeout;
if(this.socketIsConnected) {
timeout = this.socketTimerRate;
} else {
timeout = this.timerRate;
if(this.socketServerEnabled && !this.socketReconnectTimer) {
// If the socket connection fails try to reconnect once in a minute:
this.socketReconnectTimer = setTimeout('ajaxChat.socketConnect();', 60000);
}
}
this.timer = setTimeout('ajaxChat.updateChat(null);', timeout);
}
},
handleInfoMessages: function(infoNodes) {
var infoType, infoData;
for(var i=0; i<infoNodes.length; i++) {
infoType = infoNodes[i].getAttribute('type');
infoData = infoNodes[i].firstChild ? infoNodes[i].firstChild.nodeValue : '';
this.handleInfoMessage(infoType, infoData);
}
},
handleInfoMessage: function(infoType, infoData) {
switch(infoType) {
case 'channelSwitch':
this.clearChatList();
this.clearOnlineUsersList();
this.setSelectedChannel(infoData);
this.channelName = infoData;
this.channelSwitch = true;
break;
case 'channelName':
this.setSelectedChannel(infoData);
this.channelName = infoData;
break;
case 'channelID':
this.channelID = infoData;
break;
case 'userID':
this.userID = infoData;
break;
case 'userName':
this.userName = infoData;
this.encodedUserName = this.scriptLinkEncode(this.userName);
this.userNodeString = null;
break;
case 'userRole':
this.userRole = infoData;
break;
case 'logout':
this.handleLogout(infoData);
return;
case 'socketRegistrationID':
this.socketRegistrationID = infoData;
this.socketRegister();
default:
this.handleCustomInfoMessage(infoType, infoData);
}
},
handleOnlineUsers: function(userNodes) {
if(userNodes.length) {
var index,userID,userName,userRole;
var onlineUsers = new Array();
for(var i=0; i<userNodes.length; i++) {
userID = userNodes[i].getAttribute('userID');
userName = userNodes[i].firstChild ? userNodes[i].firstChild.nodeValue : '';
userRole = userNodes[i].getAttribute('userRole');
onlineUsers.push(userID);
index = this.arraySearch(userID, this.usersList);
if(index === false) {
this.addUserToOnlineList(
userID,
userName,
userRole
);
} else if(this.userNamesList[index] != userName) {
this.removeUserFromOnlineList(userID, index);
this.addUserToOnlineList(
userID,
userName,
userRole
);
}
}
// Clear the offline users from the online users list:
for(var i=0; i<this.usersList.length; i++) {
if(!this.inArray(onlineUsers, this.usersList[i])) {
this.removeUserFromOnlineList(this.usersList[i], i);
}
}
this.setOnlineListRowClasses();
}
},
handleChatMessages: function(messageNodes) {
if(messageNodes.length) {
var userNode,userName,textNode,messageText;
for(var i=0; i<messageNodes.length; i++) {
this.DOMbuffering = true;
userNode = messageNodes[i].getElementsByTagName('username')[0];
userName = userNode.firstChild ? userNode.firstChild.nodeValue : '';
textNode = messageNodes[i].getElementsByTagName('text')[0];
messageText = textNode.firstChild ? textNode.firstChild.nodeValue : '';
if (i == (messageNodes.length - 1)) {this.DOMbuffering = false;}
this.addMessageToChatList(
new Date(messageNodes[i].getAttribute('dateTime')),
messageNodes[i].getAttribute('userID'),
userName,
messageNodes[i].getAttribute('userRole'),
messageNodes[i].getAttribute('id'),
messageText,
messageNodes[i].getAttribute('channelID'),
messageNodes[i].getAttribute('ip')
);
}
this.DOMbuffering = false;
this.updateChatlistView();
this.lastID = messageNodes[messageNodes.length-1].getAttribute('id');
}
},
setSelectedChannel: function(channel) {
if(this.dom['channelSelection']) {
// Replace the entities in the channel name with their character equivalent:
channel = this.decodeSpecialChars(channel);
var channelSelected = false;
for(var i=0; i<this.dom['channelSelection'].options.length; i++) {
if(this.dom['channelSelection'].options[i].value == channel) {
this.dom['channelSelection'].options[i].selected = true;
channelSelected = true;
break;
}
}
// The given channel is not in the list, add it:
if(!channelSelected) {
var option = document.createElement('option');
var text = document.createTextNode(channel);
option.appendChild(text);
option.setAttribute('value', channel);
option.setAttribute('selected', 'selected');
this.dom['channelSelection'].appendChild(option);
}
}
},
removeUserFromOnlineList: function(userID, index) {
this.usersList.splice(index, 1);
this.userNamesList.splice(index, 1);
if(this.dom['onlineList']) {
this.dom['onlineList'].removeChild(this.getUserNode(userID));
}
},
addUserToOnlineList: function(userID, userName, userRole) {
this.usersList.push(userID);
this.userNamesList.push(userName);
if(this.dom['onlineList']) {
this.updateDOM(
'onlineList',
this.getUserNodeString(userID, userName, userRole),
(this.userID == userID)
);
}
},
getUserNodeString: function(userID, userName, userRole) {
if(this.userNodeString && userID == this.userID) {
return this.userNodeString;
} else {
var encodedUserName = this.scriptLinkEncode(userName);
var str = '<div id="'
+ this.getUserDocumentID(userID)
+ '"><a href="javascript:ajaxChat.toggleUserMenu(\''
+ this.getUserMenuDocumentID(userID)
+ '\', \''
+ encodedUserName
+ '\', '
+ userID
+ ');" class="'
+ this.getRoleClass(userRole)
+ '" title="'
+ this.lang['toggleUserMenu'].replace(/%s/, userName)
+ '">'
+ userName
+ '</a>'
+ '<ul class="userMenu" id="'
+ this.getUserMenuDocumentID(userID)
+ '"'
+ ((userID == this.userID) ?
'>'+this.getUserNodeStringItems(encodedUserName, userID, false) :
' style="display:none;">')
+ '</ul>'
+'</div>';
if(userID == this.userID) {
this.userNodeString = str;
}
return str;
}
},
toggleUserMenu: function(menuID, userName, userID) {
// If the menu is empty, fill it with user node menu items before toggling it.
var isInline = false;
if (menuID.indexOf('ium') >= 0 ) {
isInline = true;
}
if(!document.getElementById(menuID).firstChild) {
this.updateDOM(
menuID,
this.getUserNodeStringItems(
this.encodeText(this.addSlashes(this.getScriptLinkValue(userName))),
userID,
isInline
),
false,
true
)
}
this.showHide(menuID);
this.dom['chatList'].scrollTop = this.dom['chatList'].scrollHeight;
},
getUserNodeStringItems: function(encodedUserName, userID, isInline) {
var menu;
if(encodedUserName != this.encodedUserName) {
menu = '<li><a href="https://flashii.net/profile.php?u='
+ userID
+ '" target="_blank">'
+ this.lang['userMenuViewProfile']
+ '</a></li>'
+ '<li><a href="javascript:ajaxChat.insertMessageWrapper(\'/msg '
+ encodedUserName
+ ' \');">'
+ this.lang['userMenuSendPrivateMessage']
+ '</a></li>'
+ '<li><a href="javascript:ajaxChat.insertMessageWrapper(\'/describe '
+ encodedUserName
+ ' \');">'
+ this.lang['userMenuDescribe']
+ '</a></li>'
+ '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/query '
+ encodedUserName
+ '\');">'
+ this.lang['userMenuOpenPrivateChannel']
+ '</a></li>'
+ '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/query\');">'
+ this.lang['userMenuClosePrivateChannel']
+ '</a></li>'
+ '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/ignore '
+ encodedUserName
+ '\');">'
+ this.lang['userMenuIgnore']
+ '</a></li>';
if (isInline) {
menu += '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/invite '
+ encodedUserName
+ '\');">'
+ this.lang['userMenuInvite']
+ '</a></li>'
+ '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/uninvite '
+ encodedUserName
+ '\');">'
+ this.lang['userMenuUninvite']
+ '</a></li>'
+ '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/whereis '
+ encodedUserName
+ '\');">'
+ this.lang['userMenuWhereis']
+ '</a></li>';
}
if(this.userRole == 2 || this.userRole == 3 || this.userRole == 6) {
menu += '<li><a href="javascript:ajaxChat.insertMessageWrapper(\'/kick '
+ encodedUserName
+ ' \');">'
+ this.lang['userMenuKick']
+ '</a></li>'
+ '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/whois '
+ encodedUserName
+ '\');">'
+ this.lang['userMenuWhois']
+ '</a></li>';
}
} else {
menu = '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/quit\');">'
+ this.lang['userMenuLogout']
+ '</a></li>'
+ '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/who\');">'
+ this.lang['userMenuWho']
+ '</a></li>'
+ '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/ignore\');">'
+ this.lang['userMenuIgnoreList']
+ '</a></li>'
+ '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/list\');">'
+ this.lang['userMenuList']
+ '</a></li>'
+ '<li><a href="javascript:ajaxChat.insertMessageWrapper(\'/action \');">'
+ this.lang['userMenuAction']
+ '</a></li>'
+ '<li><a href="javascript:ajaxChat.insertMessageWrapper(\'/nick \');">'
+ this.lang['userMenuNick']
+ '</a></li>';
if(this.userRole == 2 || this.userRole == 3 || this.userRole == 4 || this.userRole == 6 || this.userRole == 9) {
menu += '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/join\');">'
+ this.lang['userMenuEnterPrivateRoom']
+ '</a></li>'
+ '<li><a href="?view=logs">'
+ this.lang['userMenuLogs']
+ '</a></li>';
if(this.userRole == 2 || this.userRole == 3 || this.userRole == 6) {
menu += '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/bans\');">'
+ this.lang['userMenuBans']
+ '</a></li>';
}
}
}
menu += this.getCustomUserMenuItems(encodedUserName, userID);
return menu;
},
setOnlineListRowClasses: function() {
if(this.dom['onlineList']) {
var node = this.dom['onlineList'].firstChild;
var rowEven = false;
while(node) {
this.setClass(node, (rowEven ? 'rowEven' : 'rowOdd'))
node = node.nextSibling;
rowEven = !rowEven;
}
}
},
clearChatList: function() {
while(this.dom['chatList'].hasChildNodes()) {
this.dom['chatList'].removeChild(this.dom['chatList'].firstChild);
}
},
clearOnlineUsersList: function() {
this.usersList = new Array();
this.userNamesList = new Array();
if(this.dom['onlineList']) {
while(this.dom['onlineList'].hasChildNodes()) {
this.dom['onlineList'].removeChild(this.dom['onlineList'].firstChild);
}
}
},
getEncodedChatBotName: function() {
if(typeof arguments.callee.encodedChatBotName == 'undefined') {
arguments.callee.encodedChatBotName = this.encodeSpecialChars(this.chatBotName);
}
return arguments.callee.encodedChatBotName;
},
addChatBotMessageToChatList: function(messageText) {
this.addMessageToChatList(
new Date(),
this.chatBotID,
this.getEncodedChatBotName(),
5,
null,
messageText,
null
);
},
addMessageToChatList: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
// Prevent adding the same message twice:
if(this.getMessageNode(messageID)) {
return;
}
if(!this.onNewMessage(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip)) {
return;
}
this.DOMbufferRowClass = this.DOMbufferRowClass == 'rowEven' ? 'rowOdd' : 'rowEven';
this.DOMbuffer = this.DOMbuffer +
this.getChatListMessageString(
dateObject, userID, userName, userRole, messageID, messageText, channelID, ip
);
if(!this.DOMbuffering){
this.updateDOM('chatList', this.DOMbuffer)
this.DOMbuffer = "";
}
},
getChatListMessageString: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
var rowClass = this.DOMbufferRowClass;
var userClass = this.getRoleClass(userRole);
var colon;
if(messageText.indexOf('/action') == 0 || messageText.indexOf('/me') == 0 || messageText.indexOf('/privaction') == 0) {
userClass += ' action';
colon = ' ';
} else {
colon = ': ';
}
var dateTime = this.settings['dateFormat'] ? '<span class="dateTime">'
+ this.formatDate(this.settings['dateFormat'], dateObject) + '</span> ' : '';
return '<div id="'
+ this.getMessageDocumentID(messageID)
+ '" class="'
+ rowClass
+ '">'
+ this.getDeletionLink(messageID, userID, userRole, channelID)
+ dateTime
+ '<span class="'
+ userClass
+ '"'
+ this.getChatListUserNameTitle(userID, userName, userRole, ip)
+ ' dir="'
+ this.baseDirection
+ '" onclick="ajaxChat.insertText(this.firstChild.nodeValue);">'
+ userName
+ '</span>'
+ colon
+ this.replaceText(messageText)
+ '</div>';
},
getChatListUserNameTitle: function(userID, userName, userRole, ip) {
return (ip != null) ? ' title="IP: ' + ip + '"' : '';
},
getMessageDocumentID: function(messageID) {
return ((messageID === null) ? 'ajaxChat_lm_'+(this.localID++) : 'ajaxChat_m_'+messageID);
},
getMessageNode: function(messageID) {
return ((messageID === null) ? null : document.getElementById(this.getMessageDocumentID(messageID)));
},
getUserDocumentID: function(userID) {
return 'ajaxChat_u_'+userID;
},
getUserNode: function(userID) {
return document.getElementById(this.getUserDocumentID(userID));
},
getUserMenuDocumentID: function(userID) {
return 'ajaxChat_um_'+userID;
},
getInlineUserMenuDocumentID: function(menuID, index) {
return 'ajaxChat_ium_'+menuID+'_'+index;
},
getDeletionLink: function(messageID, userID, userRole, channelID) {
if(messageID !== null && this.isAllowedToDeleteMessage(messageID, userID, userRole, channelID)) {
if(!arguments.callee.deleteMessage) {
arguments.callee.deleteMessage = this.encodeSpecialChars(this.lang['deleteMessage']);
}
return '<a class="delete" title="'
+ arguments.callee.deleteMessage
+ '" href="javascript:ajaxChat.deleteMessage('
+ messageID
+ ');"> </a>' // Adding a space - without any content Opera messes up the chatlist display
}
return '';
},
isAllowedToDeleteMessage: function(messageID, userID, userRole, channelID) {
if((((this.userRole == 1 && this.allowUserMessageDelete && (userID == this.userID ||
parseInt(channelID) == parseInt(this.userID)+this.privateMessageDiff ||
parseInt(channelID) == parseInt(this.userID)+this.privateChannelDiff)) ||
this.userRole == 7 || this.userRole == 5 || this.userRole == 2) && userRole != 3 && userRole != 4) || this.userRole == 3) {
return true;
}
return false;
},
onNewMessage: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
if(!this.customOnNewMessage(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip)) {
return false;
}
if(this.ignoreMessage(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip)) {
return false;
}
if(this.parseDeleteMessageCommand(messageText)) {
return false;
}
this.blinkOnNewMessage(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip);
this.playSoundOnNewMessage(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip);
return true;
},
parseDeleteMessageCommand: function(messageText) {
if(messageText.indexOf('/delete') == 0) {
var messageID = messageText.substr(8);
var messageNode = this.getMessageNode(messageID);
if(messageNode) {
var nextSibling = messageNode.nextSibling;
try {
this.dom['chatList'].removeChild(messageNode);
if(nextSibling) {
this.updateChatListRowClasses(nextSibling);
}
} catch(e) {
}
}
return true;
}
return false;
},
blinkOnNewMessage: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
if(this.settings['blink'] && this.lastID && !this.channelSwitch && userID != this.userID) {
clearInterval(this.blinkInterval);
this.blinkInterval = setInterval(
'ajaxChat.blinkUpdate(\''+this.addSlashes(this.decodeSpecialChars(userName))+'\')',
this.settings['blinkInterval']
);
}
},
blinkUpdate: function(blinkStr) {
if(!this.originalDocumentTitle) {
this.originalDocumentTitle = document.title;
}
if(!arguments.callee.blink) {
document.title = '[@ ] '+blinkStr+' - '+this.originalDocumentTitle;
arguments.callee.blink = 1;
} else if(arguments.callee.blink > this.settings['blinkIntervalNumber']) {
clearInterval(this.blinkInterval);
document.title = this.originalDocumentTitle;
arguments.callee.blink = 0;
} else {
if(arguments.callee.blink % 2 != 0) {
document.title = '[@ ] '+blinkStr+' - '+this.originalDocumentTitle;
} else {
document.title = '[ @] '+blinkStr+' - '+this.originalDocumentTitle;
}
arguments.callee.blink++;
}
},
updateChatlistView: function() {
if(this.dom['chatList'].childNodes && this.settings['maxMessages']) {
while(this.dom['chatList'].childNodes.length > this.settings['maxMessages']) {
this.dom['chatList'].removeChild(this.dom['chatList'].firstChild);
}
}
if(this.settings['autoScroll']) {
this.dom['chatList'].scrollTop = this.dom['chatList'].scrollHeight;
}
},
encodeText: function(text) {
return encodeURIComponent(text);
},
decodeText: function(text) {
return decodeURIComponent(text);
},
utf8Encode: function(plainText) {
var utf8Text = '';
for(var i=0; i<plainText.length; i++) {
var c=plainText.charCodeAt(i);
if(c<128) {
utf8Text += String.fromCharCode(c);
} else if((c>127) && (c<2048)) {
utf8Text += String.fromCharCode((c>>6)|192);
utf8Text += String.fromCharCode((c&63)|128);
} else {
utf8Text += String.fromCharCode((c>>12)|224);
utf8Text += String.fromCharCode(((c>>6)&63)|128);
utf8Text += String.fromCharCode((c&63)|128);
}
}
return utf8Text;
},
utf8Decode: function(utf8Text) {
var plainText = '';
var c,c2,c3;
var i=0;
while(i<utf8Text.length) {
c = utf8Text.charCodeAt(i);
if(c<128) {
plainText += String.fromCharCode(c);
i++;
} else if((c>191) && (c<224)) {
c2 = utf8Text.charCodeAt(i+1);
plainText += String.fromCharCode(((c&31)<<6) | (c2&63));
i+=2;
} else {
c2 = utf8Text.charCodeAt(i+1);
c3 = utf8Text.charCodeAt(i+2);
plainText += String.fromCharCode(((c&15)<<12) | ((c2&63)<<6) | (c3&63));
i+=3;
}
}
return plainText;
},
encodeSpecialChars: function(text) {
if (!arguments.callee.regExp) {
arguments.callee.regExp = new RegExp('[&<>\'"]', 'g');
}
return text.replace(
arguments.callee.regExp,
this.encodeSpecialCharsCallback
);
},
encodeSpecialCharsCallback: function(str) {
switch(str) {
case '&':
return '&amp;';
case '<':
return '&lt;';
case '>':
return '&gt;';
case '\'':
// As &apos; is not supported by IE, we use &#39; as replacement for ('):
return '&#39;';
case '"':
return '&quot;';
default:
return str;
}
},
decodeSpecialChars: function(text) {
if (!arguments.callee.regExp) {
arguments.callee.regExp = new RegExp('(&amp;)|(&lt;)|(&gt;)|(&#39;)|(&quot;)', 'g');
}
return text.replace(
arguments.callee.regExp,
this.decodeSpecialCharsCallback
);
},
decodeSpecialCharsCallback: function(str) {
switch(str) {
case '&amp;':
return '&';
case '&lt;':
return '<';
case '&gt;':
return '>';
case '&#39;':
return '\'';
case '&quot;':
return '"';
default:
return str;
}
},
inArray: function(haystack, needle) {
var i = haystack.length;
while(i--) {
if(haystack[i] === needle) {
return true;
}
}
return false;
},
arraySearch: function(needle, haystack) {
var i = haystack.length;
while(i--) {
if(haystack[i] === needle) {
return i;
}
}
return false;
},
stripTags: function(str) {
if (!arguments.callee.regExp) {
arguments.callee.regExp = new RegExp('<\\/?[^>]+?>', 'g');
}
return str.replace(arguments.callee.regExp, '');
},
stripBBCodeTags: function(str) {
if (!arguments.callee.regExp) {
arguments.callee.regExp = new RegExp('\\[\\/?[^\\]]+?\\]', 'g');
}
return str.replace(arguments.callee.regExp, '');
},
escapeRegExp: function(text) {
if (!arguments.callee.regExp) {
var specials = new Array(
'^', '$', '*', '+', '?', '.', '|', '/',
'(', ')', '[', ']', '{', '}', '\\'
);
arguments.callee.regExp = new RegExp(
'(\\' + specials.join('|\\') + ')', 'g'
);
}
return text.replace(arguments.callee.regExp, '\\$1');
},
addSlashes: function(text) {
// Adding slashes in front of apostrophs and backslashes to ensure a valid JavaScript expression:
return text.replace(/\\/g, '\\\\').replace(/\'/g, '\\\'');
},
removeSlashes: function(text) {
// Removing slashes added by calling addSlashes(text) previously:
return text.replace(/\\\\/g, '\\').replace(/\\\'/g, '\'');
},
formatDate: function(format, date) {
date = (date == null) ? new date() : date;
return format
.replace(/%Y/g, date.getFullYear())
.replace(/%m/g, this.addLeadingZero(date.getMonth()+1))
.replace(/%d/g, this.addLeadingZero(date.getDate()))
.replace(/%H/g, this.addLeadingZero(date.getHours()))
.replace(/%i/g, this.addLeadingZero(date.getMinutes()))
.replace(/%s/g, this.addLeadingZero(date.getSeconds()));
},
addLeadingZero: function(number) {
number = number.toString();
if(number.length < 2) {
number = '0'+number;
}
return number;
},
getUserIDFromUserName: function(userName) {
var index = this.arraySearch(userName, this.userNamesList);
if(index !== false) {
return this.usersList[index];
}
return null;
},
getUserNameFromUserID: function(userID) {
var index = this.arraySearch(userID, this.usersList);
if(index !== false) {
return this.userNamesList[index];
}
return null;
},
getRoleClass: function(roleID) {
switch(parseInt(roleID)) {
case 0:
return 'guest';
case 1:
return 'user';
case 2:
return 'moderator';
case 3:
return 'admin';
case 4:
return 'purple';
case 5:
return 'chatBot';
case 6:
return 'cmod';
case 7:
return 'bots';
case 8:
return 'dokuro';
case 9:
return 'donator';
default:
return 'default';
}
},
handleInputFieldKeyPress: function(event) {
if(event.keyCode == 13 && !event.shiftKey) {
this.sendMessage();
try {
event.preventDefault();
} catch(e) {
event.returnValue = false; // IE
}
return false;
}
return true;
},
handleInputFieldKeyUp: function(event) {
this.updateMessageLengthCounter();
},
updateMessageLengthCounter: function() {
if(this.dom['messageLengthCounter']) {
this.updateDOM(
'messageLengthCounter',
this.dom['inputField'].value.length + '/' + this.messageTextMaxLength,
false,
true
)
}
},
sendMessage: function(text) {
text = text ? text : this.dom['inputField'].value;
if(!text) {
return;
}
text = this.parseInputMessage(text);
if(text) {
clearTimeout(this.timer);
var message = 'lastID='
+ this.lastID
+ '&text='
+ this.encodeText(text);
this.makeRequest(this.ajaxURL,'POST',message);
}
this.dom['inputField'].value = '';
this.dom['inputField'].focus();
this.updateMessageLengthCounter();
},
parseInputMessage: function(text) {
if(text.charAt(0) == '/') {
var textParts = text.split(' ');
switch(textParts[0]) {
case '/ignore':
text = this.parseIgnoreInputCommand(text, textParts);
break;
default:
text = this.parseCustomInputCommand(text, textParts);
}
if(text && this.settings['persistFontColor'] && this.settings['fontColor']) {
text = this.assignFontColorToCommandMessage(text, textParts);
}
} else {
text = this.parseCustomInputMessage(text);
if(text && this.settings['persistFontColor'] && this.settings['fontColor']) {
text = this.assignFontColorToMessage(text);
}
}
return text;
},
assignFontColorToMessage: function(text) {
return '[color='+this.settings['fontColor']+']'+text+'[/color]';
},
assignFontColorToCommandMessage: function(text, textParts) {
switch(textParts[0]) {
case '/msg':
case '/describe':
if(textParts.length > 2) {
return textParts[0]+' '+textParts[1]+' '
+ '[color='+this.settings['fontColor']+']'
+ textParts.slice(2).join(' ')
+ '[/color]';
}
break;
case '/me':
case '/action':
if(textParts.length > 1) {
return textParts[0]+' '
+ '[color='+this.settings['fontColor']+']'
+ textParts.slice(1).join(' ')
+ '[/color]';
}
break;
}
return text;
},
parseIgnoreInputCommand: function(text, textParts) {
var ignoredUserNames = this.getIgnoredUserNames();
if(textParts.length > 1) {
var userName = this.encodeSpecialChars(textParts[1]);
// Prevent adding the chatBot or current user to the list:
if(userName == this.userName || userName == this.getEncodedChatBotName()) {
// Display the list of ignored users instead:
return this.parseIgnoreInputCommand(null, new Array('/ignore'));
}
if(ignoredUserNames.length > 0) {
var i = ignoredUserNames.length;
while(i--) {
if(ignoredUserNames[i] === userName) {
ignoredUserNames.splice(i,1);
this.addChatBotMessageToChatList('/ignoreRemoved '+userName);
this.setIgnoredUserNames(ignoredUserNames);
this.updateChatlistView();
return null;
}
}
}
ignoredUserNames.push(userName);
this.addChatBotMessageToChatList('/ignoreAdded '+userName);
this.setIgnoredUserNames(ignoredUserNames);
} else {
if(ignoredUserNames.length == 0) {
this.addChatBotMessageToChatList('/ignoreListEmpty -');
} else {
this.addChatBotMessageToChatList('/ignoreList '+ignoredUserNames.join(' '));
}
}
this.updateChatlistView();
return null;
},
parseSilentIgnoreInputCommand: function(text, textParts) {
var ignoredUserNames = this.getIgnoredUserNames();
if(textParts.length > 1) {
var userName = this.encodeSpecialChars(textParts[1]);
// Prevent adding the chatBot or current user to the list:
if(userName == this.userName || userName == this.getEncodedChatBotName()) {
// Display the list of ignored users instead:
return this.parseIgnoreInputCommand(null, new Array('/ignore'));
}
if(ignoredUserNames.length > 0) {
var i = ignoredUserNames.length;
while(i--) {
if(ignoredUserNames[i] === userName) {
this.updateChatlistView();
return null;
}
}
}
ignoredUserNames.push(userName);
this.setIgnoredUserNames(ignoredUserNames);
}
this.updateChatlistView();
return null;
},
getIgnoredUserNames: function() {
if(!this.ignoredUserNames) {
var ignoredUserNamesString = this.getSetting('ignoredUserNames');
if(ignoredUserNamesString) {
this.ignoredUserNames = ignoredUserNamesString.split(' ');
} else {
this.ignoredUserNames = new Array();
}
}
return this.ignoredUserNames;
},
setIgnoredUserNames: function(ignoredUserNames) {
this.ignoredUserNames = ignoredUserNames;
this.setSetting('ignoredUserNames', ignoredUserNames.join(' '));
},
ignoreMessage: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
if(userID == this.chatBotID && messageText.charAt(0) == '/') {
var textParts = messageText.split(' ');
if(textParts.length > 1) {
switch(textParts[0]) {
case '/invite':
case '/uninvite':
case '/roll':
userName = textParts[1];
break;
}
}
}
if(this.inArray(this.getIgnoredUserNames(), userName)) {
return true;
}
return false;
},
deleteMessage: function(messageID) {
var messageNode = this.getMessageNode(messageID);
if(messageNode) {
var originalClass = this.getClass(messageNode);
this.setClass(messageNode, originalClass+' deleteSelected');
if(confirm(this.lang['deleteMessageConfirm'])) {
var nextSibling = messageNode.nextSibling;
try {
this.dom['chatList'].removeChild(messageNode);
if(nextSibling) {
this.updateChatListRowClasses(nextSibling);
}
this.updateChat('&delete='+messageID);
} catch(e) {
this.setClass(messageNode, originalClass);
}
} else {
this.setClass(messageNode, originalClass);
}
}
},
updateChatListRowClasses: function(node) {
if(!node) {
node = this.dom['chatList'].firstChild;
}
if(node) {
var previousNode = node.previousSibling;
var rowEven = (previousNode && this.getClass(previousNode) == 'rowOdd') ? true : false;
while(node) {
this.setClass(node, (rowEven ? 'rowEven' : 'rowOdd'))
node = node.nextSibling;
rowEven = !rowEven;
}
}
},
getClass: function(node) {
if(typeof node.className != 'undefined') {
return node.className; // IE
} else {
return node.getAttribute('class');
}
},
setClass: function(node, className) {
if(typeof node.className != 'undefined') {
node.className = className; // IE
} else {
node.setAttribute('class', className);
}
},
scriptLinkEncode: function(text) {
return this.encodeText(this.addSlashes(this.decodeSpecialChars(text)));
},
scriptLinkDecode: function(text) {
return this.encodeSpecialChars(this.removeSlashes(this.decodeText(text)));
},
getScriptLinkValue: function(value) {
// This method returns plainText encoded values from javascript links
// The value has to be utf8Decoded for MSIE and Opera:
if(typeof arguments.callee.utf8Decode == 'undefined') {
switch(navigator.appName) {
case 'Microsoft Internet Explorer':
case 'Opera':
arguments.callee.utf8Decode = true;
return this.utf8Decode(value);
default:
arguments.callee.utf8Decode = false;
return value;
}
} else if(arguments.callee.utf8Decode) {
return this.utf8Decode(value);
} else {
return value;
}
},
sendMessageWrapper: function(text) {
this.sendMessage(this.getScriptLinkValue(text));
},
insertMessageWrapper: function(text) {
this.insertText(this.getScriptLinkValue(text), true);
},
switchChannel: function(channel) {
if(!this.chatStarted) {
this.clearChatList();
this.channelSwitch = true;
this.loginChannelID = null;
this.loginChannelName = channel;
this.requestTeaserContent();
return;
}
clearTimeout(this.timer);
var message = 'lastID='
+ this.lastID
+ '&channelName='
+ this.encodeText(channel);
this.makeRequest(this.ajaxURL,'POST',message);
if(this.dom['inputField'] && this.settings['autoFocus']) {
this.dom['inputField'].focus();
}
},
logout: function() {
clearTimeout(this.timer);
var message = 'logout=true';
this.makeRequest(this.ajaxURL,'POST',message);
},
handleLogout: function(url) {
window.location.href = url;
},
toggleSetting: function(setting, buttonID) {
this.setSetting(setting, !this.getSetting(setting));
if(buttonID) {
this.updateButton(setting, buttonID);
}
},
updateButton: function(setting, buttonID) {
var node = document.getElementById(buttonID);
if(node) {
this.setClass(node, (this.getSetting(setting) ? 'button' : 'button off'))
}
},
showHide: function(id, styleDisplay, displayInline) {
var node = document.getElementById(id);
if(node) {
if(styleDisplay) {
node.style.display = styleDisplay;
} else {
if(node.style.display == 'none') {
node.style.display = (displayInline ? 'inline' : 'block');
} else {
node.style.display = 'none';
}
}
}
},
setPersistFontColor: function(bool) {
this.settings['persistFontColor'] = bool;
if(!this.settings['persistFontColor']) {
this.settings['fontColor'] = null;
if(this.dom['inputField']) {
this.dom['inputField'].className = '';
}
}
},
setFontColor: function(color) {
if(this.settings['persistFontColor']) {
this.settings['fontColor'] = color;
if(this.dom['inputField']) {
this.dom['inputField'].className = color;
}
if(this.dom['colorCodesContainer']) {
this.dom['colorCodesContainer'].style.display = 'none';
if(this.dom['inputField']) {
this.dom['inputField'].focus();
}
}
} else {
this.insert('[color=' + color + ']', '[/color]');
}
},
insertText: function(text, clearInputField) {
if(clearInputField) {
this.dom['inputField'].value = '';
}
this.insert(text, '');
},
insertBBCode: function(bbCode) {
switch(bbCode) {
case 'url':
var url = prompt(this.lang['urlDialog'], 'http://');
if(url)
this.insert('[url=' + url + ']', '[/url]');
else
this.dom['inputField'].focus();
break;
default:
this.insert('[' + bbCode + ']', '[/' + bbCode + ']');
}
},
insert: function(startTag, endTag) {
this.dom['inputField'].focus();
// Internet Explorer:
if(typeof document.selection != 'undefined') {
// Insert the tags:
var range = document.selection.createRange();
var insText = range.text;
range.text = startTag + insText + endTag;
// Adjust the cursor position:
range = document.selection.createRange();
if (insText.length == 0) {
range.move('character', -endTag.length);
} else {
range.moveStart('character', startTag.length + insText.length + endTag.length);
}
range.select();
}
// Firefox, etc. (Gecko based browsers):
else if(typeof this.dom['inputField'].selectionStart != 'undefined') {
// Insert the tags:
var start = this.dom['inputField'].selectionStart;
var end = this.dom['inputField'].selectionEnd;
var insText = this.dom['inputField'].value.substring(start, end);
this.dom['inputField'].value = this.dom['inputField'].value.substr(0, start)
+ startTag
+ insText
+ endTag
+ this.dom['inputField'].value.substr(end);
// Adjust the cursor position:
var pos;
if (insText.length == 0) {
pos = start + startTag.length;
} else {
pos = start + startTag.length + insText.length + endTag.length;
}
this.dom['inputField'].selectionStart = pos;
this.dom['inputField'].selectionEnd = pos;
}
// Other browsers:
else {
var pos = this.dom['inputField'].value.length;
this.dom['inputField'].value = this.dom['inputField'].value.substr(0, pos)
+ startTag
+ endTag
+ this.dom['inputField'].value.substr(pos);
}
},
replaceText: function(text) {
try{
text = this.replaceLineBreaks(text);
if(text.charAt(0) == '/') {
text = this.replaceCommands(text);
} else {
text = this.replaceBBCode(text);
text = this.replaceHyperLinks(text);
text = this.replaceEmoticons(text);
}
text = this.breakLongWords(text);
text = this.replaceCustomText(text);
} catch(e){
//alert(e);
}
return text;
},
replaceCommands: function(text) {
try {
if(text.charAt(0) != '/') {
return text;
}
var textParts = text.split(' ');
switch(textParts[0]) {
case '/login':
return this.replaceCommandLogin(textParts);
case '/logout':
return this.replaceCommandLogout(textParts);
case '/channelEnter':
return this.replaceCommandChannelEnter(textParts);
case '/channelLeave':
return this.replaceCommandChannelLeave(textParts);
case '/privmsg':
return this.replaceCommandPrivMsg(textParts);
case '/privmsgto':
return this.replaceCommandPrivMsgTo(textParts);
case '/privaction':
return this.replaceCommandPrivAction(textParts);
case '/privactionto':
return this.replaceCommandPrivActionTo(textParts);
case '/me':
case '/action':
return this.replaceCommandAction(textParts);
case '/invite':
return this.replaceCommandInvite(textParts);
case '/inviteto':
return this.replaceCommandInviteTo(textParts);
case '/uninvite':
return this.replaceCommandUninvite(textParts);
case '/uninviteto':
return this.replaceCommandUninviteTo(textParts);
case '/queryOpen':
return this.replaceCommandQueryOpen(textParts);
case '/queryClose':
return this.replaceCommandQueryClose(textParts);
case '/ignoreAdded':
return this.replaceCommandIgnoreAdded(textParts);
case '/ignoreRemoved':
return this.replaceCommandIgnoreRemoved(textParts);
case '/ignoreList':
return this.replaceCommandIgnoreList(textParts);
case '/ignoreListEmpty':
return this.replaceCommandIgnoreListEmpty(textParts);
case '/kick':
return this.replaceCommandKick(textParts);
case '/who':
return this.replaceCommandWho(textParts);
case '/whoChannel':
return this.replaceCommandWhoChannel(textParts);
case '/whoEmpty':
return this.replaceCommandWhoEmpty(textParts);
case '/list':
return this.replaceCommandList(textParts);
case '/bans':
return this.replaceCommandBans(textParts);
case '/bansEmpty':
return this.replaceCommandBansEmpty(textParts);
case '/unban':
return this.replaceCommandUnban(textParts);
case '/whois':
return this.replaceCommandWhois(textParts);
case '/whereis':
return this.replaceCommandWhereis(textParts);
case '/roll':
return this.replaceCommandRoll(textParts);
case '/nick':
return this.replaceCommandNick(textParts);
case '/error':
return this.replaceCommandError(textParts);
default:
return this.replaceCustomCommands(text, textParts);
}
} catch(e) {
//alert(e);
}
return text;
},
replaceCommandLogin: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['login'].replace(/%s/, textParts[1])
+ '</span>';
},
replaceCommandLogout: function(textParts) {
var type = '';
if(textParts.length == 3)
type = textParts[2];
return '<span class="chatBotMessage">'
+ this.lang['logout' + type].replace(/%s/, textParts[1])
+ '</span>';
},
replaceCommandChannelEnter: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['channelEnter'].replace(/%s/, textParts[1])
+ '</span>';
},
replaceCommandChannelLeave: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['channelLeave'].replace(/%s/, textParts[1])
+ '</span>';
},
replaceCommandPrivMsg: function(textParts) {
var privMsgText = textParts.slice(1).join(' ');
privMsgText = this.replaceBBCode(privMsgText);
privMsgText = this.replaceHyperLinks(privMsgText);
privMsgText = this.replaceEmoticons(privMsgText);
return '<span class="privmsg">'
+ this.lang['privmsg']
+ '</span> '
+ privMsgText;
},
replaceCommandPrivMsgTo: function(textParts) {
var privMsgText = textParts.slice(2).join(' ');
privMsgText = this.replaceBBCode(privMsgText);
privMsgText = this.replaceHyperLinks(privMsgText);
privMsgText = this.replaceEmoticons(privMsgText);
return '<span class="privmsg">'
+ this.lang['privmsgto'].replace(/%s/, textParts[1])
+ '</span> '
+ privMsgText;
},
replaceCommandPrivAction: function(textParts) {
var privActionText = textParts.slice(1).join(' ');
privActionText = this.replaceBBCode(privActionText);
privActionText = this.replaceHyperLinks(privActionText);
privActionText = this.replaceEmoticons(privActionText);
return '<span class="action">'
+ privActionText
+ '</span> <span class="privmsg">'
+ this.lang['privmsg']
+ '</span> ';
},
replaceCommandPrivActionTo: function(textParts) {
var privActionText = textParts.slice(2).join(' ');
privActionText = this.replaceBBCode(privActionText);
privActionText = this.replaceHyperLinks(privActionText);
privActionText = this.replaceEmoticons(privActionText);
return '<span class="action">'
+ privActionText
+ '</span> <span class="privmsg">'
+ this.lang['privmsgto'].replace(/%s/, textParts[1])
+ '</span> ';
},
replaceCommandAction: function(textParts) {
var actionText = textParts.slice(1).join(' ');
actionText = this.replaceBBCode(actionText);
actionText = this.replaceHyperLinks(actionText);
actionText = this.replaceEmoticons(actionText);
return '<span class="action">'
+ actionText
+ '</span>';
},
replaceCommandInvite: function(textParts) {
var inviteText = this.lang['invite']
.replace(/%s/, textParts[1])
.replace(
/%s/,
'<a href="javascript:ajaxChat.sendMessageWrapper(\'/join '
+ this.scriptLinkEncode(textParts[2])
+ '\');" title="'
+ this.lang['joinChannel'].replace(/%s/, textParts[2])
+ '">'
+ textParts[2]
+ '</a>'
);
return '<span class="chatBotMessage">'
+ inviteText
+ '</span>';
},
replaceCommandInviteTo: function(textParts) {
var inviteText = this.lang['inviteto']
.replace(/%s/, textParts[1])
.replace(/%s/, textParts[2]);
return '<span class="chatBotMessage">'
+ inviteText
+ '</span>';
},
replaceCommandUninvite: function(textParts) {
var uninviteText = this.lang['uninvite']
.replace(/%s/, textParts[1])
.replace(/%s/, textParts[2]);
return '<span class="chatBotMessage">'
+ uninviteText
+ '</span>';
},
replaceCommandUninviteTo: function(textParts) {
var uninviteText = this.lang['uninviteto']
.replace(/%s/, textParts[1])
.replace(/%s/, textParts[2]);
return '<span class="chatBotMessage">'
+ uninviteText
+ '</span>';
},
replaceCommandQueryOpen: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['queryOpen'].replace(/%s/, textParts[1])
+ '</span>';
},
replaceCommandQueryClose: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['queryClose'].replace(/%s/, textParts[1])
+ '</span>';
},
replaceCommandIgnoreAdded: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['ignoreAdded'].replace(/%s/, textParts[1])
+ '</span>';
},
replaceCommandIgnoreRemoved: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['ignoreRemoved'].replace(/%s/, textParts[1])
+ '</span>';
},
replaceCommandIgnoreList: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['ignoreList'] + ' '
+ this.getInlineUserMenu(textParts.slice(1))
+ '</span>';
},
replaceCommandIgnoreListEmpty: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['ignoreListEmpty']
+ '</span>';
},
replaceCommandKick: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['logoutKicked'].replace(/%s/, textParts[1])
+ '</span>';
},
replaceCommandWho: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['who'] + ' '
+ this.getInlineUserMenu(textParts.slice(1))
+ '</span>';
},
replaceCommandWhoChannel: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['whoChannel'].replace(/%s/, textParts[1]) + ' '
+ this.getInlineUserMenu(textParts.slice(2))
+ '</span>';
},
replaceCommandWhoEmpty: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['whoEmpty']
+ '</span>';
},
replaceCommandList: function(textParts) {
var channels = textParts.slice(1);
var listChannels = new Array();
var channelName;
for(var i=0; i<channels.length; i++) {
channelName = (channels[i] == this.channelName) ? '<b>'+channels[i]+'</b>' : channels[i];
listChannels.push(
'<a href="javascript:ajaxChat.sendMessageWrapper(\'/join '
+ this.scriptLinkEncode(channels[i])
+ '\');" title="'
+ this.lang['joinChannel'].replace(/%s/, channels[i])
+ '">'
+ channelName
+ '</a>'
);
}
return '<span class="chatBotMessage">'
+ this.lang['list'] + ' '
+ listChannels.join(', ')
+ '</span>';
},
replaceCommandBans: function(textParts) {
var users = textParts.slice(1);
var listUsers = new Array();
for(var i=0; i<users.length; i++) {
listUsers.push(
'<a href="javascript:ajaxChat.sendMessageWrapper(\'/unban '
+ this.scriptLinkEncode(users[i])
+ '\');" title="'
+ this.lang['unbanUser'].replace(/%s/, users[i])
+ '">'
+ users[i]
+ '</a>'
);
}
return '<span class="chatBotMessage">'
+ this.lang['bans'] + ' '
+ listUsers.join(', ')
+ '</span>';
},
replaceCommandBansEmpty: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['bansEmpty']
+ '</span>';
},
replaceCommandUnban: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['unban'].replace(/%s/, textParts[1])
+ '</span>';
},
replaceCommandWhois: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['whois'].replace(/%s/, textParts[1]) + ' <a target="_blank" href="//flash.moe/whois/'
+ textParts[2]
+ '">'
+ textParts[2]
+ '</a></span>';
},
replaceCommandWhereis: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['whereis'].replace(/%s/, textParts[1]).replace(
/%s/,
'<a href="javascript:ajaxChat.sendMessageWrapper(\'/join '
+ this.scriptLinkEncode(textParts[2])
+ '\');" title="'
+ this.lang['joinChannel'].replace(/%s/, textParts[2])
+ '">'
+ textParts[2]
+ '</a>'
)
+ '</span>';
},
replaceCommandRoll: function(textParts) {
var rollText = this.lang['roll'].replace(/%s/, textParts[1]);
rollText = rollText.replace(/%s/, textParts[2]);
rollText = rollText.replace(/%s/, textParts[3]);
return '<span class="chatBotMessage">'
+ rollText
+ '</span>';
},
replaceCommandNick: function(textParts) {
return '<span class="chatBotMessage">'
+ this.lang['nick'].replace(/%s/, textParts[1]).replace(/%s/, textParts[2])
+ '</span>';
},
replaceCommandError: function(textParts) {
var errorMessage = this.lang['error'+textParts[1]];
if(!errorMessage) {
errorMessage = 'Error: Unknown.';
} else if(textParts.length > 2) {
errorMessage = errorMessage.replace(/%s/, textParts.slice(2).join(' '));
}
return '<span class="chatBotErrorMessage">'
+ errorMessage
+ '</span>';
},
getInlineUserMenu: function(users) {
var menu = '';
for(var i=0; i<users.length; i++) {
if(i>0) {
menu += ', ';
}
menu += '<a href="javascript:ajaxChat.toggleUserMenu(\''
+ this.getInlineUserMenuDocumentID(this.userMenuCounter, i)
+ '\', \''
+ this.scriptLinkEncode(users[i])
+ '\', null);" title="'
+ this.lang['toggleUserMenu'].replace(/%s/, users[i])
+ '" dir="'
+ this.baseDirection
+ '">'
+ ((users[i] == this.userName) ? '<b>'+users[i]+'</b>' : users[i])
+ '</a>'
+ '<ul class="inlineUserMenu" id="'
+ this.getInlineUserMenuDocumentID(this.userMenuCounter, i)
+ '" style="display:none;">'
+ '</ul>';
}
this.userMenuCounter++;
return menu;
},
containsUnclosedTags: function(str) {
if (!arguments.callee.regExpOpenTags || !arguments.callee.regExpCloseTags) {
arguments.callee.regExpOpenTags = new RegExp('<[^>\\/]+?>', 'gm');
arguments.callee.regExpCloseTags = new RegExp('<\\/[^>]+?>', 'gm');
}
var openTags = str.match(arguments.callee.regExpOpenTags);
var closeTags = str.match(arguments.callee.regExpCloseTags);
// Return true if the number of tags doesn't match:
if((!openTags && closeTags) ||
(openTags && !closeTags) ||
(openTags && closeTags && (openTags.length != closeTags.length))) {
return true;
}
return false;
},
breakLongWords: function(text) {
if(!this.settings['wordWrap'])
return text;
var newText = '';
var charCounter = 0;
var currentChar, withinTag, withinEntity;
for(var i=0; i<text.length; i++) {
currentChar = text.charAt(i);
// Check if we are within a tag or entity:
if(currentChar == '<') {
withinTag = true;
// Reset the charCounter after newline tags (<br/>):
if(i>5 && text.substr(i-5,4) == '<br/')
charCounter = 0;
} else if(withinTag && i>0 && text.charAt(i-1) == '>') {
withinTag = false;
// Reset the charCounter after newline tags (<br/>):
if(i>4 && text.substr(i-5,4) == '<br/')
charCounter = 0;
} else if(currentChar == '&') {
withinEntity = true;
} else if(withinEntity && i>0 && text.charAt(i-1) == ';') {
withinEntity = false;
// We only increase the charCounter once for the whole entiy:
charCounter++;
}
if(!withinTag && !withinEntity) {
// Reset the charCounter if we encounter a word boundary:
if(currentChar == ' ' || currentChar == '\n' || currentChar == '\t') {
charCounter = 0;
} else {
// We are not within a tag or entity, increase the charCounter:
charCounter++;
}
if(charCounter > this.settings['maxWordLength']) {
// maxWordLength has been reached, break here and reset the charCounter:
newText += this.getBreakString();
charCounter = 0;
}
}
// Add the current char to the text:
newText += currentChar;
}
return newText;
},
getBreakString: function() {
// Returns the character sequence used to wrap long words
if(typeof arguments.callee.breakString == 'undefined') {
arguments.callee.breakString = '&#8203;';
}
return arguments.callee.breakString;
},
replaceBBCode: function(text) {
if(!this.settings['bbCode']) {
// If BBCode is disabled, just strip the text from BBCode tags:
if (!arguments.callee.regExpStripBBCode) {
arguments.callee.regExpStripBBCode = new RegExp(
'\\[(?:\\/)?(\\w+)(?:=([^<>]*?))?\\]',
'gm'
);
}
return text.replace(
arguments.callee.regExpStripBBCode,
''
);
}
// Remove the BBCode tags:
if (!arguments.callee.regExp) {
arguments.callee.regExp = new RegExp(
'\\[(\\w+)(?:=([^<>]*?))?\\](.+?)\\[\\/\\1\\]',
'gm'
);
}
return text.replace(
arguments.callee.regExp,
this.replaceBBCodeCallback
);
},
replaceBBCodeCallback: function(str, p1, p2, p3) {
// Only replace predefined BBCode tags:
if(!ajaxChat.inArray(ajaxChat.bbCodeTags, p1)) {
return str;
}
// Avoid invalid XHTML (unclosed tags):
if(ajaxChat.containsUnclosedTags(p3)) {
return str;
}
switch(p1) {
case 'color':
return ajaxChat.replaceBBCodeColor(p3, p2);
case 'url':
return ajaxChat.replaceBBCodeUrl(p3, p2);
case 'img':
return ajaxChat.replaceBBCodeImage(p3);
case 'quote':
return ajaxChat.replaceBBCodeQuote(p3, p2);
case 'code':
return ajaxChat.replaceBBCodeCode(p3);
case 'u':
return ajaxChat.replaceBBCodeUnderline(p3);
default:
return ajaxChat.replaceCustomBBCode(p1, p2, p3);
}
},
replaceBBCodeColor: function(content, attribute) {
if(this.settings['bbCodeColors']) {
// Only allow predefined color codes:
if(!attribute || !this.inArray(ajaxChat.colorCodes, attribute))
return content;
return '<span class="'
+ attribute + '">'
+ this.replaceBBCode(content)
+ '</span>';
}
return content;
},
replaceBBCodeUrl: function(content, attribute) {
var url;
if(attribute)
url = attribute.replace(/\s/gm, this.encodeText(' '));
else
url = this.stripBBCodeTags(content.replace(/\s/gm, this.encodeText(' ')));
if (!arguments.callee.regExpUrl) {
arguments.callee.regExpUrl = new RegExp(
'^(?:(?:http)|(?:https)|(?:ftp)|(?:irc)):\\/\\/',
''
);
}
if(!url || !url.match(arguments.callee.regExpUrl))
return content;
return '<a href="'
+ url
+ '" onclick="window.open(this.href); return false;">'
+ this.replaceBBCode(content)
+ '</a>';
},
replaceBBCodeImage: function(url) {
++this.imageID;
if(this.settings['bbCodeImages']) {
if (!arguments.callee.regExpUrl) {
arguments.callee.regExpUrl = new RegExp(
this.regExpMediaUrl,
''
);
}
if(!url || !url.match(arguments.callee.regExpUrl))
return url;
url = this.stripTags(url.replace(/\s/gm, this.encodeText(' ')));
url = this.stripTags(url.replace(/\r/gm, this.encodeText(' ')));
url = this.stripTags(url.replace(/\n/gm, this.encodeText(' ')));
//return '<a href="'+url+'" onclick="window.open(this.href); return false;">'+'<img class="bbCodeImage" style="max-width:'+maxWidth+'px; max-height:'+maxHeight+'px;" src="'+url+'" alt="" onload="ajaxChat.updateChatlistView();"/></a>';
return '<a href="'+url+'" onclick="window.open(this.href); return false;" id="img'+this.imageID+'">'+url+'</a> [<a href="javascript:;" id="imge'+this.imageID+'" onclick="ajaxChat.parseEmbedImage(\''+this.imageID+'\',0);">Embed</a>] ';
}
return url;
},
parseEmbedImage: function(id,mode) {
var image = document.getElementById('img'+id);
var url = image.getAttribute('href');
var embed = document.getElementById('imge'+id);
var maxWidth = this.dom['chatList'].offsetWidth-50;
var maxHeight = this.dom['chatList'].offsetHeight-50;
if(mode) {
image.innerHTML = url;
embed.innerHTML = 'Embed';
embed.setAttribute('onclick','ajaxChat.parseEmbedImage(\''+id+'\',0);');
} else {
image.innerHTML = '<img class="bbCodeImage" style="max-width:'+maxWidth+'px; max-height:'+maxHeight+'px;" src="'+url+'" alt="" onload="ajaxChat.updateChatlistView();"/>';
embed.innerHTML = 'Remove';
embed.setAttribute('onclick','ajaxChat.parseEmbedImage(\''+id+'\',1);');
}
},
replaceBBCodeQuote: function(content, attribute) {
if(attribute)
return '<span class="quote"><cite>'
+ this.lang['cite'].replace(/%s/, attribute)
+ '</cite><q>'
+ this.replaceBBCode(content)
+ '</q></span>';
return '<span class="quote"><q>'
+ this.replaceBBCode(content)
+ '</q></span>';
},
replaceBBCodeCode: function(content) {
// Replace vertical tabs and multiple spaces with two non-breaking space characters:
return '<code>'
+ this.replaceBBCode(content.replace(/\t|(?: )/gm, '&#160;&#160;'))
+ '</code>';
},
replaceBBCodeUnderline: function(content) {
return '<span style="text-decoration:underline;">'
+ this.replaceBBCode(content)
+ '</span>';
},
replaceHyperLinks: function(text) {
if(!this.settings['hyperLinks']) {
return text;
}
if(!arguments.callee.regExp) {
arguments.callee.regExp = new RegExp(
'(^|\\s|>)((?:(?:http)|(?:https)|(?:ftp)|(?:irc)):\\/\\/[^\\s<>]+)(<\\/a>)?',
'gm'
);
}
return text.replace(
arguments.callee.regExp,
// Specifying an anonymous function as second parameter:
function(str, p1, p2, p3) {
// Do not replace URL's inside URL's:
if(p3) {
return str;
}
return p1
+ '<a href="'
+ p2
+ '" onclick="window.open(this.href); return false;">'
+ p2
+ '</a>';
}
);
},
replaceLineBreaks: function(text) {
if (!arguments.callee.regExp) {
arguments.callee.regExp = new RegExp('\\n', 'g');
}
if(!this.settings['lineBreaks']) {
return text.replace(arguments.callee.regExp, ' ');
} else {
return text.replace(arguments.callee.regExp, '<br/>');
}
},
replaceEmoticons: function(text) {
if(!this.settings['emoticons']) {
return text;
}
if(!arguments.callee.regExp) {
var regExpStr = '^(.*)(';
for(var i=0; i<this.emoticonCodes.length; i++) {
if(i!=0)
regExpStr += '|';
regExpStr += '(?:' + this.escapeRegExp(this.emoticonCodes[i]) + ')';
}
regExpStr += ')(.*)$';
arguments.callee.regExp = new RegExp(regExpStr, 'gm');
}
return text.replace(
arguments.callee.regExp,
this.replaceEmoticonsCallback
);
},
replaceEmoticonsCallback: function(str, p1, p2, p3) {
if (!arguments.callee.regExp) {
arguments.callee.regExp = new RegExp('(="[^"]*$)|(&[^;]*$)', '');
}
// Avoid replacing emoticons in tag attributes or XHTML entities:
if(p1.match(arguments.callee.regExp)) {
return str;
}
if(p2) {
var index = ajaxChat.arraySearch(p2, ajaxChat.emoticonCodes);
return ajaxChat.replaceEmoticons(p1)
+ '<img src="'
+ ajaxChat.dirs['emoticons']
+ ajaxChat.emoticonFiles[index]
+ '" alt="'
+ p2
+ '" />'
+ ajaxChat.replaceEmoticons(p3);
}
return str;
},
getActiveStyle: function() {
var cookie = this.readCookie(this.sessionName + '_style');
var style = cookie ? cookie : this.getPreferredStyleSheet();
return style;
},
initStyle: function() {
this.styleInitiated = true;
this.setActiveStyleSheet(this.getActiveStyle());
},
persistStyle: function() {
if(this.styleInitiated) {
this.createCookie(this.sessionName + '_style', this.getActiveStyleSheet(), this.cookieExpiration);
}
},
setSelectedStyle: function() {
if(this.dom['styleSelection']) {
var style = this.getActiveStyle();
var styleOptions = this.dom['styleSelection'].getElementsByTagName('option');
for(var i=0; i<styleOptions.length; i++) {
if(styleOptions[i].value == style) {
styleOptions[i].selected = true;
break;
}
}
}
},
getSelectedStyle: function() {
var styleOptions = this.dom['styleSelection'].getElementsByTagName('option');
if(this.dom['styleSelection'].selectedIndex == -1) {
return styleOptions[0].value;
} else {
return styleOptions[this.dom['styleSelection'].selectedIndex].value;
}
},
setActiveStyleSheet: function(title) {
var i, a, main;
var titleFound = false;
for(i=0; (a = document.getElementsByTagName('link')[i]); i++) {
if(a.getAttribute('rel').indexOf('style') != -1 && a.getAttribute('title')) {
a.disabled = true;
if(a.getAttribute('title') == title) {
a.disabled = false;
titleFound = true;
}
}
}
if(!titleFound && title != null) {
this.setActiveStyleSheet(this.getPreferredStyleSheet());
}
},
getActiveStyleSheet: function() {
var i, a;
for(i=0; (a = document.getElementsByTagName('link')[i]); i++) {
if(a.getAttribute('rel').indexOf('style') != -1 && a.getAttribute('title') && !a.disabled) {
return a.getAttribute('title');
}
}
return null;
},
getPreferredStyleSheet: function() {
var i,a;
for(i=0; (a = document.getElementsByTagName('link')[i]); i++) {
if(a.getAttribute('rel').indexOf('style') != -1
&& a.getAttribute('rel').indexOf('alt') == -1
&& a.getAttribute('title')
) {
return a.getAttribute('title');
}
}
return null;
},
switchLanguage: function(langCode) {
window.location.search = '?lang='+langCode;
},
createCookie: function(name,value,days) {
var expires = '';
if(days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
expires = '; expires='+date.toGMTString();
}
var path = '; path='+this.cookiePath;
var domain = this.cookieDomain ? '; domain='+this.cookieDomain : '';
var secure = this.cookieSecure ? '; secure' : '';
document.cookie = name+'='+encodeURIComponent(value)+expires+path+domain+secure;
},
readCookie: function(name) {
if(!document.cookie)
return null;
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 decodeURIComponent(c.substring(nameEQ.length, c.length));
}
}
return null;
},
isCookieEnabled: function() {
this.createCookie(this.sessionName + '_cookie_test', true, 1);
var cookie = this.readCookie(this.sessionName + '_cookie_test');
if(cookie) {
// Unset the test cookie:
this.createCookie(this.sessionName + '_cookie_test', true, -1);
// Cookie test successfull, return true:
return true;
}
return false;
},
finalize: function() {
if(typeof this.finalizeFunction == 'function') {
this.finalizeFunction();
}
// Ensure the socket connection is closed on unload:
if(this.socket) {
try {
this.socket.close();
this.socket = null;
} catch(e) {
//alert(e);
}
}
this.persistSettings();
this.persistStyle();
this.customFinalize();
},
// Override to perform custom actions on flash initialization:
initializeCustomFlashInterface: function() {
},
// Override to handle custom info messages
handleCustomInfoMessage: function(infoType, infoData) {
},
// Override to add custom initialization code
// This method is called on page load
customInitialize: function() {
},
// Override to add custom finalization code
// This method is called on page unload
customFinalize: function() {
},
// Override to add custom user menu items:
// Return a string with list items ( <li>menuItem</li> )
// encodedUserName contains the userName ready to be used for javascript links
// userID is only available for the online users menu - not for the inline user menu
// use (encodedUserName == this.encodedUserName) to check for the current user
getCustomUserMenuItems: function(encodedUserName, userID) {
return '';
},
// Override to parse custom input messages:
// Return replaced text
// text contains the whole message
parseCustomInputMessage: function(text) {
return text;
},
// Override to parse custom input commands:
// Return parsed text
// text contains the whole message, textParts the message split up as words array
parseCustomInputCommand: function(text, textParts) {
return text;
},
// Override to replace custom text:
// Return replaced text
// text contains the whole message
replaceCustomText: function(text) {
return text;
},
// Override to replace custom commands:
// Return replaced text for custom commands
// text contains the whole message, textParts the message split up as words array
replaceCustomCommands: function(text, textParts) {
return text;
},
// Override to replace custom BBCodes:
// Return replaced text and call replaceBBCode recursively for the content text
// tag contains the BBCode tag, attribute the BBCode attribute and content the content text
// This method is only called for BBCode tags which are in the bbCodeTags list
replaceCustomBBCode: function(tag, attribute, content) {
return '<' + tag + '>' + this.replaceBBCode(content) + '</' + tag + '>';
},
// Override to perform custom actions on new messages:
// Return true if message is to be added to the chatList, else false
customOnNewMessage: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
return true;
}
}