mirror of
				https://github.com/Mibew/java.git
				synced 2025-10-31 18:41:09 +03:00 
			
		
		
		
	Implement new chat system
This commit is contained in:
		
							parent
							
								
									f1224a98ee
								
							
						
					
					
						commit
						30cb668a73
					
				| @ -1,25 +1,30 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
|   | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| var FrameUtils={getDocument:function(a){return a.contentDocument?a.contentDocument:a.contentWindow?a.contentWindow.document:a.document?a.document:null},initFrame:function(a){var b=this.getDocument(a);b.open();b.write("<html><head>");b.write('<link rel="stylesheet" type="text/css" media="all" href="'+Chat.cssfile+'">');b.write("</head><body bgcolor='#FFFFFF' text='#000000' link='#C28400' vlink='#C28400' alink='#C28400'>");b.write("<table width='100%' cellspacing='0' cellpadding='0' border='0'><tr><td valign='top' class='message' id='content'></td></tr></table><a id='bottom' name='bottom'></a>"); | ||||
| b.write("</body></html>");b.close();a.onload=function(){a.myHtml&&(FrameUtils.getDocument(a).getElementById("content").innerHTML+=a.myHtml,FrameUtils.scrollDown(a))}},insertIntoFrame:function(a,b){var c=this.getDocument(a).getElementById("content");if(null==c){if(!a.myHtml)a.myHtml="";a.myHtml+=b}else c.innerHTML+=b},scrollDown:function(a){var b=this.getDocument(a).getElementById("bottom");if("opera"==myAgent)try{a.contentWindow.scrollTo(0,this.getDocument(a).getElementById("content").clientHeight)}catch(c){}b&& | ||||
| b.scrollIntoView(!1)}};Ajax.ChatThreadUpdater=Class.create(); | ||||
| Class.inherit(Ajax.ChatThreadUpdater,Ajax.Base,{initialize:function(a){this.setOptions(a);this._options.onComplete=this.requestComplete.bind(this);this._options.onException=this.handleException.bind(this);this._options.onTimeout=this.handleTimeout.bind(this);this._options.timeout=5E3;this.updater={};this.frequency=this._options.frequency||2;this.lastupdate=0;this.focused=this.skipNextsound=this.cansend=!0;this.ownThread=null!=this._options.message;FrameUtils.initFrame(this._options.container);if(this._options.message)this._options.message.onkeydown= | ||||
| this.handleKeyDown.bind(this),this._options.message.onfocus=function(){this.focused=!0}.bind(this),this._options.message.onblur=function(){this.focused=!1}.bind(this);this.update()},handleException:function(){this.setStatus("offline, reconnecting");this.stopUpdate();this.timer=setTimeout(this.update.bind(this),1E3)},handleTimeout:function(){this.setStatus("timeout, reconnecting");this.stopUpdate();this.timer=setTimeout(this.update.bind(this),1E3)},updateOptions:function(a){this._options.parameters= | ||||
| "act="+a+"&thread="+(this._options.threadid||0)+"&token="+(this._options.token||0)+"&lastid="+(this._options.lastid||0);this._options.user&&(this._options.parameters+="&user=true");"refresh"==a&&this._options.message&&""!=this._options.message.value&&(this._options.parameters+="&typed=1")},enableInput:function(a){if(this._options.message)this._options.message.disabled=!a},stopUpdate:function(){this.enableInput(!0);if(this.updater._options)this.updater._options.onComplete=void 0;clearTimeout(this.timer)}, | ||||
| update:function(){this.updateOptions("refresh");this.updater=new Ajax.Request(this._options.servl,this._options)},requestComplete:function(a){try{this.enableInput(!0);this.cansend=!0;var b=Ajax.getXml(a);b&&"thread"==b.tagName?this.updateContent(b):this.handleError(a,b,"refresh messages failed")}catch(c){}this.skipNextsound=!1;this.timer=setTimeout(this.update.bind(this),1E3*this.frequency)},postMessage:function(a){if(""!=a&&this.cansend){this.cansend=!1;this.stopUpdate();this.skipNextsound=!0;this.updateOptions("post"); | ||||
| var b={}.extend(this._options);b.parameters+="&message="+encodeURIComponent(a);b.onComplete=function(a){this.requestComplete(a);if(this._options.message)this._options.message.value="",this._options.message.focus()}.bind(this);"opera"!=myRealAgent&&this.enableInput(!1);this.updater=new Ajax.Request(this._options.servl,b)}},changeName:function(a){this.skipNextsound=!0;new Ajax.Request(this._options.servl,{parameters:"act=rename&thread="+(this._options.threadid||0)+"&token="+(this._options.token||0)+ | ||||
| "&name="+encodeURIComponent(a)})},onThreadClosed:function(a){var b=Ajax.getXml(a);b&&"closed"==b.tagName?setTimeout("window.close()",2E3):this.handleError(a,b,"cannot close")},closeThread:function(){if("undefined"!=typeof Chat.localizedStrings.closeConfirmation&&Chat.localizedStrings.closeConfirmation&&!confirm(Chat.localizedStrings.closeConfirmation))return!1;var a="act=close&thread="+(this._options.threadid||0)+"&token="+(this._options.token||0);this._options.user&&(a+="&user=true");new Ajax.Request(this._options.servl, | ||||
| {parameters:a,onComplete:this.onThreadClosed.bind(this)})},processMessage:function(a,b){var c=NodeUtils.getNodeText(b);FrameUtils.insertIntoFrame(a,c)},showTyping:function(a){if($("typingdiv"))$("typingdiv").style.display=a?"inline":"none"},setupAvatar:function(a){a=NodeUtils.getNodeText(a);if(this._options.avatar&&this._options.user)this._options.avatar.innerHTML=""!=a?'<img src="'+Chat.webimRoot+'/images/free.gif" width="7" height="1" border="0" alt="" /><img src="'+a+'" border="0" alt=""/>':""}, | ||||
| updateContent:function(a){var b=!1,c=this._options.container,d=NodeUtils.getAttrValue(a,"lastid");if(d)this._options.lastid=d;(d=NodeUtils.getAttrValue(a,"typing"))&&this.showTyping("1"==d);if((d=NodeUtils.getAttrValue(a,"canpost"))&&("1"==d&&!this.ownThread||this.ownThread&&"1"!=d))window.location.href=window.location.href;for(d=0;d<a.childNodes.length;d++){var e=a.childNodes[d];"message"==e.tagName?(b=!0,this.processMessage(c,e)):"avatar"==e.tagName&&this.setupAvatar(e)}0<=window.location.search.indexOf("trace=on")? | ||||
| (a="updated",0<this.lastupdate&&(c=((new Date).getTime()-this.lastupdate)/1E3,a=a+", "+c+" secs",10<c&&alert(a)),this.lastupdate=(new Date).getTime(),this.setStatus(a)):this.clearStatus();b&&(FrameUtils.scrollDown(this._options.container),this.skipNextsound||(b=$("soundimg"),(null==b||b.className.match(/\bisound\b/))&&playSound(Chat.webimRoot+"/sounds/new_message.wav")),this.focused||window.focus())},isSendkey:function(a,b){return 13==b&&(a||this._options.ignorectrl)||10==b},handleKeyDown:function(a){a? | ||||
| (ctrl=a.ctrlKey,a=a.which):(a=event.keyCode,ctrl=event.ctrlKey);return this._options.message&&this.isSendkey(ctrl,a)?(a=this._options.message.value,this._options.ignorectrl&&(a=a.replace(/[\r\n]+$/,"")),this.postMessage(a),!1):!0},handleError:function(a,b){b&&"error"==b.tagName?this.setStatus(NodeUtils.getNodeValue(b,"descr")):this.setStatus("reconnecting")},showStatusDiv:function(a){if($("engineinfo"))$("engineinfo").style.display="inline",$("engineinfo").innerHTML=a},setStatus:function(a){this.statusTimeout&& | ||||
| clearTimeout(this.statusTimeout);this.showStatusDiv(a);this.statusTimeout=setTimeout(this.clearStatus.bind(this),4E3)},clearStatus:function(){$("engineinfo").style.display="none"}}); | ||||
| b.write("</body></html>");b.close();a.onload=function(){a.myHtml&&(FrameUtils.getDocument(a).getElementById("content").innerHTML+=a.myHtml,FrameUtils.scrollDown(a))}},insertIntoFrame:function(a,b){var c=this.getDocument(a).getElementById("content");null==c?(a.myHtml||(a.myHtml=""),a.myHtml+=b):c.innerHTML+=b},scrollDown:function(a){var b=this.getDocument(a).getElementById("bottom");if("opera"==myAgent)try{a.contentWindow.scrollTo(0,this.getDocument(a).getElementById("content").clientHeight)}catch(c){}b&& | ||||
| b.scrollIntoView(!1)}};ChatServer=Class.create(); | ||||
| ChatServer.prototype={initialize:function(a){this.updateTimer=null;this.options={servl:"",requestsFrequency:2,onTimeout:function(){},onTransportError:function(){},onCallError:function(){},onUpdateError:function(){},onResponseError:function(){}}.extend(a);this.callbacks={};this.callPeriodically=[];this.ajaxOptions={_method:"post",asynchronous:!0,timeout:5E3,onComplete:this.receiveResponse.bind(this),onException:this.onTransportError.bind(this),onTimeout:this.onTimeout.bind(this)};this.ajaxRequest= | ||||
| null;this.buffer=[];this.functions={};this.mibewAPI=new MibewAPI(new MibewAPICoreInteraction)},callFunctions:function(a,b,c){try{if(!(a instanceof Array))throw Error("The first arguments must be an array");for(var d in a)a.hasOwnProperty(d)&&this.mibewAPI.checkFunction(a[d],!1);var e=this.generateToken();this.callbacks[e]=b;this.buffer.push({token:e,functions:a});c&&this.update()}catch(f){return this.options.onCallError(f),!1}return!0},callFunctionsPeriodically:function(a,b){this.callPeriodically.push({functionsListBuilder:a, | ||||
| callbackFunction:b})},generateToken:function(){var a;do a="wnd"+(new Date).getTime().toString()+Math.round(50*Math.random()).toString();while(a in this.callbacks);return a},processRequest:function(a){var b=new MibewAPIExecutionContext,c=this.mibewAPI.getResultFunction(a.functions,this.callbacks.hasOwnProperty(a.token));if(null===c)for(var d in a.functions)a.functions.hasOwnProperty(d)&&(this.processFunction(a.functions[d],b),this.buffer.push(this.mibewAPI.buildResult(b.getResults(),a.token)));else this.callbacks.hasOwnProperty(a.token)&& | ||||
| (this.callbacks[a.token](c.arguments),delete this.callbacks[a.token])},processFunction:function(a,b){if(this.functions.hasOwnProperty(a["function"])){var c=b.getArgumentsList(a),d={},e;for(e in this.functions[a["function"]])this.functions[a["function"]].hasOwnProperty(e)&&d.extend(this.functions[a["function"]][e](c));b.storeFunctionResults(a,d)}},sendRequests:function(a){this.ajaxRequest=new Ajax.Request(this.options.servl,this.ajaxOptions.extend({parameters:"data="+this.mibewAPI.encodePackage(a)}))}, | ||||
| runUpdater:function(){null==this.updateTimer&&this.update();this.updateTimer=setTimeout(this.update.bind(this),1E3*this.options.requestsFrequency)},restartUpdater:function(){this.updateTimer&&clearTimeout(this.updateTimer);this.ajaxRequest._options&&(this.ajaxRequest._options.onComplete=void 0);this.update();this.updateTimer=setTimeout(this.update.bind(this),1E3)},update:function(){this.updateTimer&&clearTimeout(this.updateTimer);for(var a=0;a<this.callPeriodically.length;a++)this.callFunctions(this.callPeriodically[a].functionsListBuilder(), | ||||
| this.callPeriodically[a].callbackFunction);if(0==this.buffer.length)this.runUpdater();else try{this.sendRequests(this.buffer),this.buffer=[]}catch(b){this.options.onUpdateError(b)}},receiveResponse:function(a){""==a.response&&this.runUpdater();try{var b=this.mibewAPI.decodePackage(a.response),c;for(c in b.requests)this.processRequest(b.requests[c])}catch(d){this.options.onResponseError(d)}finally{this.runUpdater()}},registerFunction:function(a,b){a in this.functions||(this.functions[a]=[]);this.functions[a].push(b)}, | ||||
| onTransportError:function(a,b){this.restartUpdater();this.options.onTransportError(b)},onTimeout:function(){this.restartUpdater();this.options.onTimeout()}};ChatThreadUpdater=Class.create(); | ||||
| ChatThreadUpdater.prototype={initialize:function(a,b,c){this._options=c;this.thread={threadid:0,token:0,lastid:0,user:!1}.extend(b||{});this.chatServer=a;this.focused=this.skipNextsound=this.cansend=!0;this.ownThread=null!=this._options.message;FrameUtils.initFrame(this._options.container);this._options.message&&(this._options.message.onkeydown=this.handleKeyDown.bind(this),this._options.message.onfocus=function(){this.focused=!0}.bind(this),this._options.message.onblur=function(){this.focused=!1}.bind(this)); | ||||
| this.chatServer.callFunctionsPeriodically(this.updateFunctionBuilder.bind(this),this.updateChatState.bind(this));this.chatServer.registerFunction("updateMessages",this.updateMessages.bind(this));this.chatServer.registerFunction("setupAvatar",this.setupAvatar.bind(this));this.chatServer.runUpdater()},handleException:function(){this.setStatus("offline, reconnecting");this.enableInput(!0)},handleTimeout:function(){this.setStatus("timeout, reconnecting");this.enableInput(!0)},enableInput:function(a){this._options.message&& | ||||
| (this._options.message.disabled=!a)},refresh:function(){this.chatServer.restartUpdater()},postMessage:function(a){""!=a&&this.cansend&&(this.cansend=!1,this.skipNextsound=!0,"opera"!=myRealAgent&&this.enableInput(!1),this.chatServer.callFunctions([{"function":"post",arguments:{references:{},"return":{},message:a,threadId:this.thread.threadid,token:this.thread.token,user:this.thread.user}}],function(){this.enableInput(!0);this.cansend=!0;this.skipNextsound=!1;this._options.message&&(this._options.message.value= | ||||
| "",this._options.message.focus())}.bind(this),!0))},changeName:function(a){this.skipNextsound=!0;this.chatServer.callFunctions([{"function":"rename",arguments:{references:{},"return":{},threadId:this.thread.threadid,token:this.thread.token,name:a}}],function(a){a.errorCode&&this.handleError(a,"cannot rename")}.bind(this),!0)},closeThread:function(){(!this._options.localizedStrings.closeConfirmation||confirm(this._options.localizedStrings.closeConfirmation))&&this.chatServer.callFunctions([{"function":"close", | ||||
| arguments:{references:{},"return":{closed:"closed"},threadId:this.thread.threadid,token:this.thread.token,lastId:this.thread.lastid,user:this.thread.user}}],this.onThreadClosed.bind(this),!0)},onThreadClosed:function(a){a.closed?window.close():this.handleError(a,"cannot close")},processMessage:function(a,b){FrameUtils.insertIntoFrame(a,b)},showTyping:function(a){$("typingdiv")&&($("typingdiv").style.display=a?"inline":"none")},setupAvatar:function(a){this._options.avatar&&this.thread.user&&(this._options.avatar.innerHTML= | ||||
| ""!=a.imageLink?'<img src="'+this._options.webimRoot+'/images/free.gif" width="7" height="1" border="0" alt="" /><img src="'+a.imageLink+'" border="0" alt=""/>':"")},updateMessages:function(a){a.lastId&&(this.thread.lastid=a.lastId);for(var b=0;b<a.messages.length;b++)this.processMessage(this._options.container,a.messages[b]);this.clearStatus();0<a.messages.length&&(FrameUtils.scrollDown(this._options.container),this.skipNextsound||(a=$("soundimg"),(null==a||a.className.match(/\bisound\b/))&&playSound(this._options.webimRoot+ | ||||
| "/sounds/new_message.wav")),this.focused||window.focus());this.skipNextsound=!1},updateFunctionBuilder:function(){return[{"function":"update",arguments:{"return":{typing:"typing",canPost:"canPost"},references:{},threadId:this.thread.threadid,token:this.thread.token,lastId:this.thread.lastid,typed:this._options.message&&""!=this._options.message.value,user:this.thread.user}}]},updateChatState:function(a){if(a.errorCode)this.handleError(a,"refresh failed");else if("undefined"!=typeof a.typing&&this.showTyping(a.typing), | ||||
| "undefined"!=typeof a.canPost&&(a.canPost&&!this.ownThread||this.ownThread&&!a.canPost))window.location.href=window.location.href},isSendkey:function(a,b){return 13==b&&(a||this._options.ignorectrl)||10==b},handleKeyDown:function(a){a?(ctrl=a.ctrlKey,a=a.which):(a=event.keyCode,ctrl=event.ctrlKey);return this._options.message&&this.isSendkey(ctrl,a)?(a=this._options.message.value,this._options.ignorectrl&&(a=a.replace(/[\r\n]+$/,"")),this.postMessage(a),!1):!0},handleError:function(a){a.errorCode? | ||||
| this.setStatus(a.errorMessage):this.setStatus("reconnecting")},showStatusDiv:function(a){$("engineinfo")&&($("engineinfo").style.display="inline",$("engineinfo").innerHTML=a)},setStatus:function(a){this.statusTimeout&&clearTimeout(this.statusTimeout);this.showStatusDiv(a);this.statusTimeout=setTimeout(this.clearStatus.bind(this),4E3)},clearStatus:function(){$("engineinfo").style.display="none"}}; | ||||
| var Chat={threadUpdater:{},applyName:function(){Chat.threadUpdater.changeName($("uname").value);$("changename1").style.display="none";$("changename2").style.display="inline";$("unamelink").innerHTML=htmlescape($("uname").value)},showNameField:function(){$("changename1").style.display="inline";$("changename2").style.display="none"}}; | ||||
| Behaviour.register({"#postmessage a":function(a){a.onclick=function(){var a=$("msgwnd");a&&Chat.threadUpdater.postMessage(a.value)}},"select#predefined":function(a){a.onchange=function(){var a=$("msgwnd");if(0!=this.selectedIndex)a.value=Chat.predefinedAnswers[this.selectedIndex-1];this.selectedIndex=0;a.focus()}},"div#changename2 a":function(a){a.onclick=function(){Chat.showNameField();return!1}},"div#changename1 a":function(a){a.onclick=function(){Chat.applyName();return!1}},"div#changename1 input#uname":function(a){a.onkeydown= | ||||
| function(a){13==(a||event).keyCode&&Chat.applyName()}},"a#refresh":function(a){a.onclick=function(){Chat.threadUpdater.stopUpdate();Chat.threadUpdater.update()}},"a#togglesound":function(a){a.onclick=function(){var a=$("soundimg");if(a)a.className=a.className.match(/\bisound\b/)?"tplimage inosound":"tplimage isound",(a=$("msgwnd"))&&a.focus()}},"a.closethread":function(a){a.onclick=function(){Chat.threadUpdater.closeThread()}}}); | ||||
| EventHelper.register(window,"onload",function(){Chat.webimRoot=threadParams.wroot;Chat.cssfile=threadParams.cssfile;Chat.predefinedAnswers="undefined"!=typeof predefinedAnswers?predefinedAnswers:[];Chat.localizedStrings=localizedStrings;Chat.threadUpdater=new Ajax.ChatThreadUpdater({ignorectrl:-1,container:"safari"==myRealAgent?self.frames[0]:$("chatwnd"),avatar:$("avatarwnd"),message:$("msgwnd")}.extend(threadParams||{}))}); | ||||
| Behaviour.register({"#postmessage a":function(a){a.onclick=function(){var a=$("msgwnd");a&&Chat.threadUpdater.postMessage(a.value)}},"select#predefined":function(a){a.onchange=function(){var a=$("msgwnd");0!=this.selectedIndex&&(a.value=Chat.predefinedAnswers[this.selectedIndex-1]);this.selectedIndex=0;a.focus()}},"div#changename2 a":function(a){a.onclick=function(){Chat.showNameField();return!1}},"div#changename1 a":function(a){a.onclick=function(){Chat.applyName();return!1}},"div#changename1 input#uname":function(a){a.onkeydown= | ||||
| function(a){13==(a||event).keyCode&&Chat.applyName()}},"a#refresh":function(a){a.onclick=function(){Chat.threadUpdater.refresh()}},"a#togglesound":function(a){a.onclick=function(){var a=$("soundimg");a&&(a.className=a.className.match(/\bisound\b/)?"tplimage inosound":"tplimage isound",(a=$("msgwnd"))&&a.focus())}},"a.closethread":function(a){a.onclick=function(){Chat.threadUpdater.closeThread()}}}); | ||||
| EventHelper.register(window,"onload",function(){Chat.cssfile=chatParams.cssfile;Chat.predefinedAnswers=chatParams.predefinedAnswers||[];Chat.localizedStrings=chatParams.localizedStrings;Chat.threadUpdater=new ChatThreadUpdater(new ChatServer(chatParams.serverParams),chatParams.threadParams,{ignorectrl:-1,container:"safari"==myRealAgent?self.frames[0]:$("chatwnd"),avatar:$("avatarwnd"),message:$("msgwnd")}.extend(chatParams.threadUpdaterParams||{}))}); | ||||
|  | ||||
| @ -59,220 +59,734 @@ var FrameUtils = { | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| Ajax.ChatThreadUpdater = Class.create(); | ||||
| Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, { | ||||
| ChatServer = Class.create(); | ||||
| /** | ||||
|  * @todo Think about error handling | ||||
|  */ | ||||
| ChatServer.prototype = { | ||||
|   /** | ||||
|    * @constructor | ||||
|    */ | ||||
|   initialize: function(options) { | ||||
|       var chatServer = this; | ||||
| 
 | ||||
|   initialize: function(_options) { | ||||
|     this.setOptions(_options); | ||||
|     this._options.onComplete = this.requestComplete.bind(this); | ||||
|     this._options.onException = this.handleException.bind(this); | ||||
|     this._options.onTimeout = this.handleTimeout.bind(this); | ||||
|     this._options.timeout = 5000; | ||||
|     this.updater = {}; | ||||
|     this.frequency = (this._options.frequency || 2); | ||||
|     this.lastupdate = 0; | ||||
|     this.cansend = true; | ||||
|     this.skipNextsound = true; | ||||
|     this.focused = true; | ||||
|     this.ownThread = this._options.message != null; | ||||
| 	FrameUtils.initFrame(this._options.container); | ||||
|     if( this._options.message ) { | ||||
| 		this._options.message.onkeydown = this.handleKeyDown.bind(this); | ||||
| 		this._options.message.onfocus = (function() { this.focused = true; }).bind(this); | ||||
| 		this._options.message.onblur = (function() { this.focused = false; }).bind(this) | ||||
| 	} | ||||
|     this.update(); | ||||
|       /** | ||||
|        * Update timer | ||||
|        */ | ||||
|       this.updateTimer = null; | ||||
| 
 | ||||
|       /** | ||||
|        * Options for the ChatServer object | ||||
|        * @private | ||||
|        * @todo Check onResponseError handler | ||||
|        */ | ||||
|       this.options = { | ||||
|           // Server gateway URL
 | ||||
|           servl: "", | ||||
|           // Frequency for automatic updater
 | ||||
|           requestsFrequency: 2, | ||||
|           // Call on request timeout
 | ||||
|           onTimeout: function() {}, | ||||
|           // Call when transport error was caught
 | ||||
|           onTransportError: function(e) {}, | ||||
|           // Call when callFunctions related error was caught
 | ||||
|           onCallError: function(e) {}, | ||||
|           // Call when update related error was caught
 | ||||
|           onUpdateError: function(e) {}, | ||||
|           // Call when response related error was caught
 | ||||
|           onResponseError: function(e) {} | ||||
|       }.extend(options); | ||||
| 
 | ||||
|       /** | ||||
|        * Binds request's token and callback function | ||||
|        * @type Object | ||||
|        * @private | ||||
|        */ | ||||
|       this.callbacks = {}; | ||||
| 
 | ||||
|       /** | ||||
|        * Array of periodically called functions | ||||
|        * @type Array | ||||
|        * @private | ||||
|        */ | ||||
|       this.callPeriodically = []; | ||||
| 
 | ||||
|       /** | ||||
|        * Options for an Ajax.Request object | ||||
|        * @type Array | ||||
|        * @private | ||||
|        */ | ||||
|       this.ajaxOptions = { | ||||
|           _method: 'post', | ||||
|           asynchronous: true, | ||||
|           timeout: 5000, | ||||
|           onComplete: chatServer.receiveResponse.bind(chatServer), | ||||
|           onException: chatServer.onTransportError.bind(chatServer), | ||||
|           onTimeout: chatServer.onTimeout.bind(chatServer) | ||||
|       } | ||||
| 
 | ||||
|       /** | ||||
|        * An object of the Ajax.Request class | ||||
|        * @type Ajax.Request | ||||
|        * @private | ||||
|        */ | ||||
|       this.ajaxRequest = null; | ||||
| 
 | ||||
|       /** | ||||
|        * This buffer store requests and responses between sending packages | ||||
|        * @private | ||||
|        */ | ||||
|       this.buffer = []; | ||||
| 
 | ||||
|       /** | ||||
|        * Contains object of registered functions handlers | ||||
|        * @private | ||||
|        */ | ||||
|       this.functions = {} | ||||
| 
 | ||||
|       /** | ||||
|        * An instance of the MibewAPI class | ||||
|        * @type MibewAPI | ||||
|        * @private | ||||
|        */ | ||||
|       this.mibewAPI = new MibewAPI(new MibewAPICoreInteraction()); | ||||
|   }, | ||||
| 
 | ||||
|   handleException: function(_request, ex) { | ||||
|   	this.setStatus("offline, reconnecting"); | ||||
| 	this.stopUpdate(); | ||||
| 	this.timer = setTimeout(this.update.bind(this), 1000); | ||||
|   /** | ||||
|    * Make call to the chat server | ||||
|    * | ||||
|    * @param {Oblect[]} functionsList List of the function objects. See Mibew API | ||||
|    * for details. | ||||
|    * @param {Function} callbackFunction | ||||
|    * @param {Boolean} forceSend Force requests buffer send right after call | ||||
|    * @returns {Boolean} boolean true on success and false on failure | ||||
|    */ | ||||
|   callFunctions: function(functionsList, callbackFunction, forceSend) { | ||||
|       try { | ||||
|         // Check function objects
 | ||||
|         if (!(functionsList instanceof Array)) { | ||||
|             throw new Error("The first arguments must be an array"); | ||||
|         } | ||||
|         for (var i in functionsList) { | ||||
|             // Filter 'Prototype' properties
 | ||||
|             if (! functionsList.hasOwnProperty(i)) { | ||||
|                 continue; | ||||
|             } | ||||
|             this.mibewAPI.checkFunction(functionsList[i], false); | ||||
|         } | ||||
| 
 | ||||
|         // Generate request token
 | ||||
|         var token = this.generateToken(); | ||||
|         // Store callback function
 | ||||
|         this.callbacks[token] = callbackFunction; | ||||
| 
 | ||||
|         // Add request to buffer
 | ||||
|         this.buffer.push({ | ||||
|             'token': token, | ||||
|             'functions': functionsList | ||||
|         }); | ||||
|         if (forceSend) { | ||||
|             // Force update
 | ||||
|             this.update(); | ||||
|         } | ||||
|       } catch (e) { | ||||
|           // Handle errors
 | ||||
|           this.options.onCallError(e); | ||||
|           return false; | ||||
|       } | ||||
|       return true; | ||||
|   }, | ||||
| 
 | ||||
|   handleTimeout: function(_request) { | ||||
|   	this.setStatus("timeout, reconnecting"); | ||||
| 	this.stopUpdate(); | ||||
| 	this.timer = setTimeout(this.update.bind(this), 1000); | ||||
|   /** | ||||
|    * Call function at every request to build functions list | ||||
|    * | ||||
|    * @param {Function} functionsListBuilder Call before every request to build a | ||||
|    * list of functions that must be called | ||||
|    * @param {Function} callbackFunction Call after response received | ||||
|    */ | ||||
|   callFunctionsPeriodically: function(functionsListBuilder, callbackFunction) { | ||||
|       this.callPeriodically.push({ | ||||
|           functionsListBuilder: functionsListBuilder, | ||||
|           callbackFunction: callbackFunction | ||||
|       }); | ||||
|   }, | ||||
| 
 | ||||
|   updateOptions: function(act) { | ||||
|     this._options.parameters = 'act='+act+'&thread=' + (this._options.threadid || 0) + | ||||
| 			'&token=' + (this._options.token || 0)+ | ||||
|     		'&lastid=' + (this._options.lastid || 0); | ||||
|     if( this._options.user ) | ||||
|     	this._options.parameters += "&user=true"; | ||||
| 	if( act == 'refresh' && this._options.message && this._options.message.value != '' ) | ||||
|     	this._options.parameters += "&typed=1"; | ||||
|   /** | ||||
|    * Generates unique request token | ||||
|    * | ||||
|    * @private | ||||
|    * @returns {String} Request token | ||||
|    */ | ||||
|   generateToken: function() { | ||||
|       var token; | ||||
|       do { | ||||
|           // Create token
 | ||||
|           token = "wnd" + | ||||
|               (new Date()).getTime().toString() + | ||||
|               (Math.round(Math.random() * 50)).toString(); | ||||
|       // Check token uniqueness
 | ||||
|       } while(token in this.callbacks); | ||||
|       return token; | ||||
|   }, | ||||
| 
 | ||||
|   enableInput: function(val) { | ||||
| 	if( this._options.message ) | ||||
| 		this._options.message.disabled = !val; | ||||
|   /** | ||||
|    * Process request | ||||
|    * | ||||
|    * @param {Object} requestObject Request object. See Mibew API for details. | ||||
|    * @private | ||||
|    */ | ||||
|   processRequest: function(requestObject) { | ||||
|       var context = new MibewAPIExecutionContext(); | ||||
| 
 | ||||
|       // Get result function
 | ||||
|       var resultFunction = this.mibewAPI.getResultFunction( | ||||
|         requestObject.functions, | ||||
|         this.callbacks.hasOwnProperty(requestObject.token) | ||||
|       ); | ||||
| 
 | ||||
|       if (resultFunction === null) { | ||||
|           // Result function not found
 | ||||
|           for (var i in requestObject.functions) { | ||||
|               if (! requestObject.functions.hasOwnProperty(i)) { | ||||
|                   continue; | ||||
|               } | ||||
|               // Execute functions
 | ||||
|               this.processFunction(requestObject.functions[i], context); | ||||
|               // Build and store result
 | ||||
|               this.buffer.push(this.mibewAPI.buildResult( | ||||
|                 context.getResults(), | ||||
|                 requestObject.token | ||||
|               )); | ||||
|           } | ||||
|       } else { | ||||
|           // Result function found
 | ||||
|           if (this.callbacks.hasOwnProperty(requestObject.token)) { | ||||
|               // Invoke callback
 | ||||
|               this.callbacks[requestObject.token](resultFunction.arguments); | ||||
|               // Remove callback
 | ||||
|               delete this.callbacks[requestObject.token]; | ||||
|           } | ||||
|       } | ||||
|   }, | ||||
| 
 | ||||
|   stopUpdate: function() { | ||||
|     this.enableInput(true); | ||||
|   	if( this.updater._options ) | ||||
| 	    this.updater._options.onComplete = undefined; | ||||
|     clearTimeout(this.timer); | ||||
|   /** | ||||
|    * Process function | ||||
|    * | ||||
|    * @param {Object} functionObject Function object. See Mibew API for details | ||||
|    * @param {MibewAPIExecutionContext} context Execution context | ||||
|    * @private | ||||
|    */ | ||||
|   processFunction: function(functionObject, context) { | ||||
|       if (! this.functions.hasOwnProperty(functionObject["function"])) { | ||||
|           return; | ||||
|       } | ||||
|       // Get function arguments with replaced refences
 | ||||
|       var functionArguments = context.getArgumentsList(functionObject); | ||||
| 
 | ||||
|       var results = {}; | ||||
|       for (var i in this.functions[functionObject["function"]]) { | ||||
|           if (! this.functions[functionObject["function"]].hasOwnProperty(i)) { | ||||
|               continue; | ||||
|           } | ||||
|           // Get results
 | ||||
|           results.extend(this.functions[functionObject["function"]][i]( | ||||
|             functionArguments | ||||
|           )); | ||||
|       } | ||||
| 
 | ||||
|       // Add function results to the execution context
 | ||||
|       context.storeFunctionResults(functionObject, results); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Send the request to the chat server | ||||
|    * | ||||
|    * @param {Object[]} requestsList Array of requests that must be sent to the | ||||
|    * chat server | ||||
|    * @private | ||||
|    */ | ||||
|   sendRequests: function(requestsList) { | ||||
|       // Create new AJAX request
 | ||||
|       this.ajaxRequest = new Ajax.Request( | ||||
|         this.options.servl, | ||||
|         this.ajaxOptions.extend({ | ||||
|             parameters: 'data=' + this.mibewAPI.encodePackage(requestsList) | ||||
|         }) | ||||
|       ); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Sets up next automatic updater iteration | ||||
|    */ | ||||
|   runUpdater: function() { | ||||
|       if (this.updateTimer == null) { | ||||
|         this.update(); | ||||
|       } | ||||
|       this.updateTimer = setTimeout( | ||||
|         this.update.bind(this), | ||||
|         this.options.requestsFrequency * 1000 | ||||
|       ); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Restarts the automatic updater | ||||
|    */ | ||||
|   restartUpdater: function() { | ||||
|       // Clear timeout
 | ||||
|       if (this.updateTimer) { | ||||
|           clearTimeout(this.updateTimer); | ||||
|       } | ||||
|       // Clear request onComplete callback
 | ||||
|       if (this.ajaxRequest._options) { | ||||
|           this.ajaxRequest._options.onComplete = undefined; | ||||
|       } | ||||
|       // Update thread
 | ||||
|       this.update(); | ||||
|       // Restart updater. Try to reconnect after a while
 | ||||
|       this.updateTimer = setTimeout( | ||||
|         this.update.bind(this), | ||||
|         1000 | ||||
|       ); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Send request for update thread and client code's requests | ||||
|    * @private | ||||
|    */ | ||||
|   update: function() { | ||||
|     this.updateOptions("refresh"); | ||||
|     this.updater = new Ajax.Request(this._options.servl, this._options); | ||||
|       if (this.updateTimer) { | ||||
|           clearTimeout(this.updateTimer); | ||||
|       } | ||||
|       for (var i = 0; i < this.callPeriodically.length; i++) { | ||||
|           this.callFunctions( | ||||
|             this.callPeriodically[i].functionsListBuilder(), | ||||
|             this.callPeriodically[i].callbackFunction | ||||
|           ); | ||||
|       } | ||||
|       // Check buffer length
 | ||||
|       if (this.buffer.length == 0) { | ||||
|           // Rerun updater later
 | ||||
|           this.runUpdater(); | ||||
|           return; | ||||
|       } | ||||
|       try { | ||||
|           // Send requests
 | ||||
|           this.sendRequests(this.buffer); | ||||
|           // Clear requests buffer
 | ||||
|           this.buffer = []; | ||||
|       } catch (e) { | ||||
|           // Handle errors
 | ||||
|           this.options.onUpdateError(e); | ||||
|       } | ||||
|   }, | ||||
| 
 | ||||
|   requestComplete: function(_response) { | ||||
|     try { | ||||
|   /** | ||||
|    * Process response from the Core | ||||
|    * | ||||
|    * @param {String} responseObject The response object provided by | ||||
|    * Ajax.Request class | ||||
|    * @private | ||||
|    */ | ||||
|   receiveResponse: function(responseObject) { | ||||
|       // Do not parse empty responses
 | ||||
|       if (responseObject.response == '') { | ||||
|           this.runUpdater(); | ||||
|       } | ||||
|       try { | ||||
|           var packageObject = this.mibewAPI.decodePackage(responseObject.response); | ||||
|           for (var i in packageObject.requests) { | ||||
|               this.processRequest(packageObject.requests[i]); | ||||
|           } | ||||
|       } catch (e) { | ||||
|           this.options.onResponseError(e); | ||||
|       } finally { | ||||
|           this.runUpdater(); | ||||
|       } | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Add function that can be called by the Core | ||||
|    * | ||||
|    * @param {String} functionName Name of the function | ||||
|    * @param {Function} handler Provided function | ||||
|    */ | ||||
|   registerFunction: function(functionName, handler) { | ||||
|       if (!(functionName in this.functions)) { | ||||
|           this.functions[functionName] = []; | ||||
|       } | ||||
|       this.functions[functionName].push(handler); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Call on all AJAX transport errors | ||||
|    * @param {Ajax.Request} transport AJAX Transport object | ||||
|    * @param {Error} e Error object | ||||
|    */ | ||||
|   onTransportError: function (transport, e) { | ||||
|       this.restartUpdater(); | ||||
|       this.options.onTransportError(e); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Call on all timeouts | ||||
|    */ | ||||
|   onTimeout: function(transport) { | ||||
|       this.restartUpdater(); | ||||
|       this.options.onTimeout() | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| ChatThreadUpdater = Class.create(); | ||||
| ChatThreadUpdater.prototype = { | ||||
|   /** | ||||
|    * @constructor | ||||
|    * @todo Add error handlers to chatServer | ||||
|    * @todo Think about code format | ||||
|    */ | ||||
|   initialize: function(chatServer, thread, options) { | ||||
|     /** | ||||
|      * Array of options | ||||
|      * @type Array | ||||
|      * @private | ||||
|      */ | ||||
|     this._options = options; | ||||
| 
 | ||||
|     /** | ||||
|      * An instance of the Thread class | ||||
|      * @type ChatThread | ||||
|      */ | ||||
|     this.thread = { | ||||
|         threadid: 0, | ||||
|         token: 0, | ||||
|         lastid: 0, | ||||
|         user: false | ||||
|     }.extend(thread || {}); | ||||
| 
 | ||||
|     /** | ||||
|      * An instance of the ChatServer class | ||||
|      * @type ChatServer | ||||
|      */ | ||||
|     this.chatServer = chatServer; | ||||
| 
 | ||||
|     /** | ||||
|      * Indicates if user can post messages | ||||
|      * @type Boolean | ||||
|      */ | ||||
|     this.cansend = true; | ||||
| 
 | ||||
|     /** | ||||
|      * Indicates if next message's sound must be skipped | ||||
|      * @type Boolean | ||||
|      */ | ||||
|     this.skipNextsound = true; | ||||
| 
 | ||||
|     /** | ||||
|      * Indicates if message input area ihn focus | ||||
|      * @type Boolean | ||||
|      */ | ||||
|     this.focused = true; | ||||
| 
 | ||||
|     /** | ||||
|      * Indicates the thread belong to this operator | ||||
|      * @type Boolean | ||||
|      */ | ||||
|     this.ownThread = this._options.message != null; | ||||
| 
 | ||||
|     FrameUtils.initFrame(this._options.container); | ||||
|     if (this._options.message) { | ||||
|         this._options.message.onkeydown = this.handleKeyDown.bind(this); | ||||
|         this._options.message.onfocus = (function() {this.focused = true;}).bind(this); | ||||
|         this._options.message.onblur = (function() {this.focused = false;}).bind(this); | ||||
|     } | ||||
| 
 | ||||
|     // Add periodic functions
 | ||||
|     this.chatServer.callFunctionsPeriodically( | ||||
|         this.updateFunctionBuilder.bind(this), | ||||
|         this.updateChatState.bind(this) | ||||
|     ); | ||||
| 
 | ||||
|     // Register functions
 | ||||
|     this.chatServer.registerFunction( | ||||
|         'updateMessages', | ||||
|         this.updateMessages.bind(this) | ||||
|     ); | ||||
|     this.chatServer.registerFunction( | ||||
|         'setupAvatar', | ||||
|         this.setupAvatar.bind(this) | ||||
|     ); | ||||
| 
 | ||||
|     this.chatServer.runUpdater(); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Exception handler. Updates status message | ||||
|    */ | ||||
|   handleException: function(e) { | ||||
|         this.setStatus("offline, reconnecting"); | ||||
|         this.enableInput(true); | ||||
|     	this.cansend = true; | ||||
|     	var xmlRoot = Ajax.getXml(_response); | ||||
|         if( xmlRoot && xmlRoot.tagName == 'thread' ) { | ||||
|           this.updateContent( xmlRoot ); | ||||
|     	} else { | ||||
|     	  this.handleError(_response, xmlRoot, 'refresh messages failed'); | ||||
|     	} | ||||
| 	} catch (e) { | ||||
|     } | ||||
|     this.skipNextsound = false; | ||||
|     this.timer = setTimeout(this.update.bind(this), this.frequency * 1000); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Timeout handler. Updates status message | ||||
|    */ | ||||
|   handleTimeout: function() { | ||||
|         this.setStatus("timeout, reconnecting"); | ||||
|         this.enableInput(true); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Enables or disables input field | ||||
|    * @param {Boolean} val Use boolean true for enable input and false otherwise | ||||
|    */ | ||||
|   enableInput: function(val) { | ||||
|       if( this._options.message ) { | ||||
|           this._options.message.disabled = !val; | ||||
|       } | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Load new messages by restarting thread updater. | ||||
|    */ | ||||
|   refresh: function() { | ||||
|     this.chatServer.restartUpdater(); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Sends message to the chat server | ||||
|    * @param {String} msg Message for send | ||||
|    */ | ||||
|   postMessage: function(msg) { | ||||
|     if( msg == "" || !this.cansend) { | ||||
| 		return; | ||||
|     } | ||||
|     this.cansend = false; | ||||
|     this.stopUpdate(); | ||||
|     this.skipNextsound = true; | ||||
|     this.updateOptions("post"); | ||||
|     var postOptions = {}.extend(this._options); | ||||
|     postOptions.parameters += "&message=" + encodeURIComponent(msg); | ||||
|     postOptions.onComplete = (function(presponse) { | ||||
|     	this.requestComplete( presponse ); | ||||
|     	if( this._options.message ) { | ||||
|     		this._options.message.value = ''; | ||||
|     		this._options.message.focus(); | ||||
|     	} | ||||
|     }).bind(this); | ||||
|     if( myRealAgent != 'opera' ) | ||||
|     	this.enableInput(false); | ||||
|     this.updater = new Ajax.Request(this._options.servl, postOptions); | ||||
|       // Check if message can be sent
 | ||||
|       if(msg == "" || !this.cansend) { | ||||
|           return; | ||||
|       } | ||||
|       // Disable message sending
 | ||||
|       this.cansend = false; | ||||
|       // Disable next sound
 | ||||
|       this.skipNextsound = true; | ||||
|       // Disable input
 | ||||
|       if(myRealAgent != 'opera') { | ||||
|           this.enableInput(false); | ||||
|       } | ||||
|       // Post message
 | ||||
|       this.chatServer.callFunctions( | ||||
|         [{ | ||||
|             "function": "post", | ||||
|             "arguments": { | ||||
|                 "references": {}, | ||||
|                 "return": {}, | ||||
|                 "message": msg, | ||||
|                 "threadId": this.thread.threadid, | ||||
|                 "token": this.thread.token, | ||||
|                 "user": this.thread.user | ||||
|             } | ||||
|         }], | ||||
|         (function(){ | ||||
|             this.enableInput(true); | ||||
|             this.cansend = true; | ||||
|             this.skipNextsound = false; | ||||
|             if(this._options.message) { | ||||
|                 this._options.message.value = ''; | ||||
|                 this._options.message.focus(); | ||||
|             } | ||||
|         }).bind(this), | ||||
|         true | ||||
|       ); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Change user name | ||||
|    * @param {String} newname A new user name | ||||
|    */ | ||||
|   changeName: function(newname) { | ||||
|     this.skipNextsound = true; | ||||
|     new Ajax.Request(this._options.servl, {parameters:'act=rename&thread=' + (this._options.threadid || 0) + | ||||
|     	'&token=' + (this._options.token || 0) + '&name=' + encodeURIComponent(newname)}); | ||||
|   }, | ||||
| 
 | ||||
|   onThreadClosed: function(_response) { | ||||
| 	var xmlRoot = Ajax.getXml(_response); | ||||
|     if( xmlRoot && xmlRoot.tagName == 'closed' ) { | ||||
| 	  setTimeout('window.close()', 2000); | ||||
| 	} else { | ||||
| 	  this.handleError(_response, xmlRoot, 'cannot close'); | ||||
| 	} | ||||
|       this.skipNextsound = true; | ||||
|       this.chatServer.callFunctions( | ||||
|         [{ | ||||
|             "function": "rename", | ||||
|             "arguments": { | ||||
|                 "references": {}, | ||||
|                 "return": {}, | ||||
|                 "threadId": this.thread.threadid, | ||||
|                 "token": this.thread.token, | ||||
|                 "name": newname | ||||
|             } | ||||
|         }], | ||||
|         (function(args){ | ||||
|             if (args.errorCode) { | ||||
|                 this.handleError(args, 'cannot rename'); | ||||
|             } | ||||
|         }).bind(this), | ||||
|         true | ||||
|       ); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Send request for close chat to the core | ||||
|    */ | ||||
|   closeThread: function() { | ||||
| 	if(typeof Chat.localizedStrings.closeConfirmation != 'undefined' && Chat.localizedStrings.closeConfirmation){ | ||||
| 		if(! confirm(Chat.localizedStrings.closeConfirmation)){ | ||||
| 		    return false; | ||||
| 		} | ||||
| 	} | ||||
| 	var _params = 'act=close&thread=' + (this._options.threadid || 0) + '&token=' + (this._options.token || 0); | ||||
| 	if( this._options.user ) | ||||
|     	_params += "&user=true"; | ||||
|     new Ajax.Request(this._options.servl, {parameters:_params, onComplete: this.onThreadClosed.bind(this)}); | ||||
|       // Show confirmation message if can
 | ||||
|       if(this._options.localizedStrings.closeConfirmation){ | ||||
|           if(! confirm(this._options.localizedStrings.closeConfirmation)){ | ||||
|               return; | ||||
|           } | ||||
|       } | ||||
|       // Send request
 | ||||
|       this.chatServer.callFunctions( | ||||
|         [{ | ||||
|             "function": "close", | ||||
|             "arguments": { | ||||
|                 "references": {}, | ||||
|                 "return": {"closed": "closed"}, | ||||
|                 "threadId": this.thread.threadid, | ||||
|                 "token": this.thread.token, | ||||
|                 "lastId": this.thread.lastid, | ||||
|                 "user": this.thread.user | ||||
|             } | ||||
|         }], | ||||
|         this.onThreadClosed.bind(this), | ||||
|         true | ||||
|       ); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Callback function for close chat request. | ||||
|    * | ||||
|    * Close chat window if closing success or warn on fail | ||||
|    */ | ||||
|   onThreadClosed: function(args) { | ||||
|       if (args.closed) { | ||||
|           window.close(); | ||||
|       } else { | ||||
|           this.handleError(args, 'cannot close'); | ||||
|       } | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Add message to the message window | ||||
|    * @param {Object} _target Target DOM element | ||||
|    * @param {String} message HTML message to insert | ||||
|    */ | ||||
|   processMessage: function(_target, message) { | ||||
| 	var destHtml = NodeUtils.getNodeText(message); | ||||
| 	FrameUtils.insertIntoFrame(_target, destHtml ); | ||||
|       FrameUtils.insertIntoFrame(_target, message); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Displays typing status | ||||
|    * @param {Boolean} istyping Indicates the other side of conversation is | ||||
|    * typing a message or not | ||||
|    */ | ||||
|   showTyping: function(istyping) { | ||||
|   	if( $("typingdiv") ) { | ||||
| 		$("typingdiv").style.display=istyping ? 'inline' : 'none'; | ||||
|   	} | ||||
|   }, | ||||
| 
 | ||||
|   setupAvatar: function(avatar) { | ||||
| 	var imageLink = NodeUtils.getNodeText(avatar); | ||||
| 	if( this._options.avatar && this._options.user ) { | ||||
| 		this._options.avatar.innerHTML = imageLink != "" | ||||
| 			? "<img src=\""+Chat.webimRoot+"/images/free.gif\" width=\"7\" height=\"1\" border=\"0\" alt=\"\" /><img src=\"" | ||||
| 				+imageLink+ "\" border=\"0\" alt=\"\"/>" | ||||
| 			: ""; | ||||
|   /** | ||||
|    * Update operator's avatar | ||||
|    * @param {Array} args Array of arguments passed from the core | ||||
|    */ | ||||
|   setupAvatar: function(args) { | ||||
|       if (this._options.avatar && this.thread.user) { | ||||
|           this._options.avatar.innerHTML = args.imageLink != "" | ||||
|               ? "<img src=\""+this._options.webimRoot+"/images/free.gif\" width=\"7\" height=\"1\" border=\"0\" alt=\"\" /><img src=\"" | ||||
|                     +args.imageLink+ "\" border=\"0\" alt=\"\"/>" | ||||
|               : ""; | ||||
| 	} | ||||
|   }, | ||||
| 
 | ||||
|   updateContent: function(xmlRoot) { | ||||
| 	var haveMessage = false; | ||||
| 
 | ||||
|    	var result_div = this._options.container; | ||||
| 	var _lastid = NodeUtils.getAttrValue(xmlRoot, "lastid"); | ||||
| 	if( _lastid ) { | ||||
| 		this._options.lastid = _lastid; | ||||
| 	} | ||||
| 
 | ||||
| 	var typing = NodeUtils.getAttrValue(xmlRoot, "typing"); | ||||
| 	if( typing ) { | ||||
| 		this.showTyping(typing == '1'); | ||||
| 	} | ||||
| 
 | ||||
| 	var canpost = NodeUtils.getAttrValue(xmlRoot, "canpost"); | ||||
| 	if( canpost ) { | ||||
| 		if( canpost == '1' && !this.ownThread || this.ownThread && canpost != '1' ) { | ||||
| 			window.location.href = window.location.href; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for( var i = 0; i < xmlRoot.childNodes.length; i++ ) { | ||||
| 		var node = xmlRoot.childNodes[i]; | ||||
| 		if( node.tagName == 'message' ) { | ||||
|         	haveMessage = true; | ||||
| 			this.processMessage(result_div, node); | ||||
| 		} else if( node.tagName == 'avatar' ) { | ||||
| 			this.setupAvatar(node); | ||||
|         } | ||||
| 	} | ||||
| 	if(window.location.search.indexOf('trace=on')>=0) { | ||||
| 		var val = "updated"; | ||||
| 		if(this.lastupdate > 0) { | ||||
| 			var seconds = ((new Date()).getTime() - this.lastupdate)/1000; | ||||
| 			val = val + ", " + seconds + " secs"; | ||||
| 			if(seconds > 10) { | ||||
| 				alert(val); | ||||
| 			} | ||||
| 		} | ||||
| 		this.lastupdate = (new Date()).getTime(); | ||||
| 		this.setStatus(val); | ||||
| 	} else { | ||||
| 		this.clearStatus(); | ||||
| 	} | ||||
| 	if( haveMessage ) { | ||||
| 		FrameUtils.scrollDown(this._options.container); | ||||
| 		if(!this.skipNextsound) { | ||||
| 			var tsound = $('soundimg'); | ||||
| 			if(tsound == null || tsound.className.match(new RegExp("\\bisound\\b")) ) { | ||||
| 				playSound(Chat.webimRoot+'/sounds/new_message.wav'); | ||||
| 			} | ||||
| 		} | ||||
| 		if( !this.focused ) { | ||||
| 			window.focus(); | ||||
| 		} | ||||
| 	} | ||||
|   /** | ||||
|    * Add new messages to chat window | ||||
|    * @param {Object} args object of function arguments passed from the server | ||||
|    * @todo Fix skipNextSound | ||||
|    */ | ||||
|   updateMessages: function(args){ | ||||
|       // Update last message id
 | ||||
|       if (args.lastId) { | ||||
|           this.thread.lastid = args.lastId; | ||||
|       } | ||||
|       // Add messages
 | ||||
|       for (var i = 0; i < args.messages.length; i++) { | ||||
|           // TODO: Add template engine
 | ||||
|           this.processMessage(this._options.container, args.messages[i]); | ||||
|       } | ||||
|       // Clear status string
 | ||||
|       this.clearStatus(); | ||||
|       // There are some new messages
 | ||||
|       if (args.messages.length > 0) { | ||||
|           FrameUtils.scrollDown(this._options.container); | ||||
|           if (!this.skipNextsound) { | ||||
|               var tsound = $('soundimg'); | ||||
|               if (tsound == null || tsound.className.match(new RegExp("\\bisound\\b"))) { | ||||
|                   playSound(this._options.webimRoot+'/sounds/new_message.wav'); | ||||
|               } | ||||
|           } | ||||
|           if (!this.focused) { | ||||
|               window.focus(); | ||||
|           } | ||||
|       } | ||||
|       this.skipNextsound = false; | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Build update function to call at the core | ||||
|    */ | ||||
|   updateFunctionBuilder: function() { | ||||
|       return [ | ||||
|           { | ||||
|               "function": "update", | ||||
|               "arguments": { | ||||
|                   "return": {'typing': 'typing', 'canPost': 'canPost'}, | ||||
|                   "references": {}, | ||||
|                   "threadId": this.thread.threadid, | ||||
|                   "token": this.thread.token, | ||||
|                   "lastId": this.thread.lastid, | ||||
|                   "typed": (this._options.message && this._options.message.value != ''), | ||||
|                   "user": this.thread.user | ||||
|               } | ||||
|           } | ||||
|       ]; | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Set current chat state message | ||||
|    * @param {Array} args Array of arguments passed from the core | ||||
|    */ | ||||
|   updateChatState: function(args) { | ||||
|       if (args.errorCode) { | ||||
|           // Something went wrong
 | ||||
|           this.handleError(args, 'refresh failed'); | ||||
|           return; | ||||
|       } | ||||
|       // Update typing indicator
 | ||||
|       if (typeof args.typing != 'undefined') { | ||||
|           this.showTyping(args.typing); | ||||
|       } | ||||
| 
 | ||||
|       // Check if user can post messages
 | ||||
|       if (typeof args.canPost != 'undefined') { | ||||
|           if ((args.canPost && !this.ownThread) || (this.ownThread && ! args.canPost)) { | ||||
|               // Refresh the page
 | ||||
|               window.location.href = window.location.href; | ||||
|           } | ||||
|       } | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Check if send key (Enter or Ctrl+Enter) pressed | ||||
|    * @param {Boolean} ctrlpressed Indicates ctrl key is pressed or not | ||||
|    * @param {Number} key Key code | ||||
|    */ | ||||
|   isSendkey: function(ctrlpressed, key) { | ||||
| 	  return ((key==13 && (ctrlpressed || this._options.ignorectrl)) || (key==10)); | ||||
|   }, | ||||
|    | ||||
| 
 | ||||
|   /** | ||||
|    * Key down handler | ||||
|    * | ||||
|    * @param {Object} k Event object | ||||
|    */ | ||||
|   handleKeyDown: function(k) { | ||||
| 	if( k ){ ctrl=k.ctrlKey;k=k.which; } else { k=event.keyCode;ctrl=event.ctrlKey;	} | ||||
| 	if( k ){ctrl=k.ctrlKey;k=k.which;} else {k=event.keyCode;ctrl=event.ctrlKey;} | ||||
| 	if( this._options.message && this.isSendkey(ctrl, k) ) { | ||||
| 		var mmsg = this._options.message.value; | ||||
| 		if( this._options.ignorectrl ) { | ||||
| @ -284,14 +798,26 @@ Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, { | ||||
| 	return true; | ||||
|   }, | ||||
| 
 | ||||
|   handleError: function(_response, xmlRoot, _action) { | ||||
| 	if( xmlRoot && xmlRoot.tagName == 'error' ) { | ||||
| 	  this.setStatus(NodeUtils.getNodeValue(xmlRoot,"descr")); | ||||
| 	} else { | ||||
| 	  this.setStatus("reconnecting"); | ||||
| 	} | ||||
|   /** | ||||
|    * Update status message | ||||
|    * | ||||
|    * @param {Array} args Array of arguments. Must contain 'errorCode' and | ||||
|    * 'errorMessage' keys | ||||
|    * @param {String} descr Error description | ||||
|    */ | ||||
|   handleError: function(args, descr) { | ||||
|       if (args.errorCode) { | ||||
|           this.setStatus(args.errorMessage); | ||||
|       } else { | ||||
|           this.setStatus('reconnecting'); | ||||
|       } | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Displays status div and sets the status string into it | ||||
|    * | ||||
|    * @param {String} k Status string | ||||
|    */ | ||||
|   showStatusDiv: function(k) { | ||||
|   	if( $("engineinfo") ) { | ||||
| 		$("engineinfo").style.display='inline'; | ||||
| @ -299,6 +825,11 @@ Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, { | ||||
|   	} | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Sets the status | ||||
|    * | ||||
|    * @param {String} k Status string | ||||
|    */ | ||||
|   setStatus: function(k) { | ||||
| 	if( this.statusTimeout ) | ||||
| 		clearTimeout(this.statusTimeout); | ||||
| @ -306,11 +837,13 @@ Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, { | ||||
| 	this.statusTimeout = setTimeout(this.clearStatus.bind(this), 4000); | ||||
|   }, | ||||
| 
 | ||||
|   /** | ||||
|    * Hide the status string | ||||
|    */ | ||||
|   clearStatus: function() { | ||||
| 	$("engineinfo").style.display='none'; | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| var Chat = { | ||||
|   threadUpdater : {}, | ||||
| @ -368,8 +901,7 @@ Behaviour.register({ | ||||
| 	}, | ||||
| 	'a#refresh' : function(el) { | ||||
| 		el.onclick = function() { | ||||
| 		    Chat.threadUpdater.stopUpdate(); | ||||
| 			Chat.threadUpdater.update(); | ||||
|                     Chat.threadUpdater.refresh(); | ||||
| 		}; | ||||
| 	}, | ||||
| 	'a#togglesound' : function(el) { | ||||
| @ -396,9 +928,17 @@ Behaviour.register({ | ||||
| }); | ||||
| 
 | ||||
| EventHelper.register(window, 'onload', function(){ | ||||
|   Chat.webimRoot = threadParams.wroot; | ||||
|   Chat.cssfile = threadParams.cssfile; | ||||
|   Chat.predefinedAnswers = (typeof predefinedAnswers != 'undefined')?predefinedAnswers:Array(); | ||||
|   Chat.localizedStrings = localizedStrings; | ||||
|   Chat.threadUpdater = new Ajax.ChatThreadUpdater(({ignorectrl:-1,container:myRealAgent=='safari'?self.frames[0]:$("chatwnd"),avatar:$("avatarwnd"),message:$("msgwnd")}).extend( threadParams || {} )); | ||||
|   Chat.cssfile = chatParams.cssfile; | ||||
|   Chat.predefinedAnswers = chatParams.predefinedAnswers || []; | ||||
|   Chat.localizedStrings = chatParams.localizedStrings; | ||||
|   Chat.threadUpdater = new ChatThreadUpdater( | ||||
|     new ChatServer(chatParams.serverParams), | ||||
|     chatParams.threadParams, | ||||
|     { | ||||
|         ignorectrl: -1, | ||||
|         container: myRealAgent=='safari'?self.frames[0]:$("chatwnd"), | ||||
|         avatar: $("avatarwnd"), | ||||
|         message: $("msgwnd") | ||||
|     }.extend(chatParams.threadUpdaterParams || {}) | ||||
|   ); | ||||
| }); | ||||
| @ -26,33 +26,6 @@ function get_user_id() | ||||
| 	return (time() + microtime()) . rand(0, 99999999); | ||||
| } | ||||
| 
 | ||||
| function prepare_html_message($text, $allow_formating) | ||||
| { | ||||
| 	$escaped_text = htmlspecialchars($text); | ||||
| 	$text_w_links = preg_replace('/(https?|ftp):\/\/\S*/', '<a href="$0" target="_blank">$0</a>', $escaped_text); | ||||
| 	$multiline = str_replace("\n", "<br/>", $text_w_links); | ||||
| 	if (! $allow_formating) { | ||||
| 		return $multiline; | ||||
| 	} | ||||
| 	$formated = preg_replace('/<(span|strong)>(.*)<\/\1>/U', '<$1>$2</$1>', $multiline); | ||||
| 	$formated = preg_replace('/<span class="(.*)">(.*)<\/span>/U', '<span class="$1">$2</span>', $formated); | ||||
| 	return $formated; | ||||
| } | ||||
| 
 | ||||
| function message_to_html($msg) | ||||
| { | ||||
| 	if ($msg['ikind'] == Thread::KIND_AVATAR) { | ||||
| 		return ""; | ||||
| 	} | ||||
| 	$message = "<span>" . date("H:i:s", $msg['created']) . "</span> "; | ||||
| 	$kind = Thread::kindToString($msg['ikind']); | ||||
| 	if ($msg['tname']) | ||||
| 		$message .= "<span class='n$kind'>" . htmlspecialchars($msg['tname']) . "</span>: "; | ||||
| 	$allow_formating = ($msg['ikind'] != Thread::KIND_USER && $msg['ikind'] != Thread::KIND_AGENT); | ||||
| 	$message .= "<span class='m$kind'>" . prepare_html_message($msg['tmessage'], $allow_formating) . "</span><br/>"; | ||||
| 	return $message; | ||||
| } | ||||
| 
 | ||||
| function message_to_text($msg) | ||||
| { | ||||
| 	if ($msg['ikind'] == Thread::KIND_AVATAR) { | ||||
| @ -71,93 +44,6 @@ function message_to_text($msg) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function get_messages($threadid, $meth, $isuser, &$lastid) | ||||
| { | ||||
| 	global $webim_encoding; | ||||
| 	$db = Database::getInstance(); | ||||
| 
 | ||||
| 	$msgs = $db->query( | ||||
| 		"select messageid,ikind,dtmcreated as created,tname,tmessage from {chatmessage} " . | ||||
| 		"where threadid = :threadid and messageid > :lastid " . | ||||
| 		($isuser ? "and ikind <> ". Thread::KIND_FOR_AGENT : "") . | ||||
| 		" order by messageid", | ||||
| 		array( | ||||
| 			':threadid' => $threadid, | ||||
| 			':lastid' => $lastid, | ||||
| 		), | ||||
| 		array('return_rows' => Database::RETURN_ALL_ROWS) | ||||
| 		 | ||||
| 	); | ||||
| 
 | ||||
| 	$messages = array(); | ||||
| 	foreach ($msgs as $msg) { | ||||
| 		$message = ""; | ||||
| 		if ($meth == 'xml') { | ||||
| 			switch ($msg['ikind']) { | ||||
| 				case Thread::KIND_AVATAR: | ||||
| 					$message = "<avatar>" . myiconv($webim_encoding, "utf-8", escape_with_cdata($msg['tmessage'])) . "</avatar>"; | ||||
| 					break; | ||||
| 				default: | ||||
| 					$message = "<message>" . myiconv($webim_encoding, "utf-8", escape_with_cdata(message_to_html($msg))) . "</message>\n"; | ||||
| 			} | ||||
| 		} else { | ||||
| 			if ($msg['ikind'] != Thread::KIND_AVATAR) { | ||||
| 				$message = (($meth == 'text') ? message_to_text($msg) : topage(message_to_html($msg))); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		$messages[] = $message; | ||||
| 		if ($msg['messageid'] > $lastid) { | ||||
| 			$lastid = $msg['messageid']; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return $messages; | ||||
| } | ||||
| 
 | ||||
| function print_thread_messages($thread, $token, $lastid, $isuser, $format, $agentid = null) | ||||
| { | ||||
| 	global $webim_encoding, $webimroot; | ||||
| 	$threadid = $thread->id; | ||||
| 	$istyping = abs(time() - $isuser ? $thread->lastPingAgent : $thread->lastPingUser) < Thread::CONNECTION_TIMEOUT | ||||
| 				&& (($isuser ? $thread->agentTyping : $thread->userTyping) == "1") ? "1" : "0"; | ||||
| 
 | ||||
| 	if ($format == "xml") { | ||||
| 		$output = get_messages($threadid, "xml", $isuser, $lastid); | ||||
| 
 | ||||
| 		start_xml_output(); | ||||
| 		print("<thread lastid=\"$lastid\" typing=\"" . $istyping . "\" canpost=\"" . (($isuser || $agentid != null && $agentid == $thread->agentId) ? 1 : 0) . "\">"); | ||||
| 		foreach ($output as $msg) { | ||||
| 			print $msg; | ||||
| 		} | ||||
| 		print("</thread>"); | ||||
| 	} else if ($format == "html") { | ||||
| 		$output = get_messages($threadid, "html", $isuser, $lastid); | ||||
| 
 | ||||
| 		start_html_output(); | ||||
| 		$url = "$webimroot/thread.php?act=refresh&thread=$threadid&token=$token&html=on&user=" . ($isuser ? "true" : "false"); | ||||
| 
 | ||||
| 		print( | ||||
| 				"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">" . | ||||
| 				"<html>\n<head>\n" . | ||||
| 				"<link href=\"$webimroot/styles/default/chat.css\" rel=\"stylesheet\" type=\"text/css\">\n" . | ||||
| 				"<meta http-equiv=\"Refresh\" content=\"" . Settings::get('updatefrequency_oldchat') . "; URL=$url&sn=11\">\n" . | ||||
| 				"<meta http-equiv=\"Pragma\" content=\"no-cache\">\n" . | ||||
| 				"<title>chat</title>\n" . | ||||
| 				"</head>\n" . | ||||
| 				"<body bgcolor='#FFFFFF' text='#000000' link='#C28400' vlink='#C28400' alink='#C28400' onload=\"if( location.hash != '#aend' ){location.hash='#aend';}\">" . | ||||
| 				"<table width='100%' cellspacing='0' cellpadding='0' border='0'><tr><td valign='top' class='message'>"); | ||||
| 
 | ||||
| 		foreach ($output as $msg) { | ||||
| 			print $msg; | ||||
| 		} | ||||
| 
 | ||||
| 		print( | ||||
| 				"</td></tr></table><a name='aend'></a>" . | ||||
| 				"</body></html>"); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function get_user_name($username, $addr, $id) | ||||
| { | ||||
| 	return str_replace( | ||||
|  | ||||
| @ -1,89 +0,0 @@ | ||||
| <?php | ||||
| /* | ||||
|  * Copyright 2005-2013 the original author or authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| function demo_print_message($msg, $format) | ||||
| { | ||||
| 	global $webim_encoding; | ||||
| 	if ($format == "xml") { | ||||
| 		print "<message>" . myiconv($webim_encoding, "utf-8", escape_with_cdata(message_to_html($msg))) . "</message>\n"; | ||||
| 	} else { | ||||
| 		print topage(message_to_html($msg)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function demo_process_thread($act, $outformat, $lastid, $isuser, $canpost, $istyping, $postmessage) | ||||
| { | ||||
| 	global $webimroot; | ||||
| 	if ($act == "refresh" || $act == "post") { | ||||
| 		$lastid++; | ||||
| 		if ($outformat == "xml") { | ||||
| 			start_xml_output(); | ||||
| 			print("<thread lastid=\"$lastid\" typing=\"" . ($istyping ? 1 : 0) . "\" canpost=\"" . ($canpost ? 1 : 0) . "\">"); | ||||
| 		} else { | ||||
| 			start_html_output(); | ||||
| 			$url = "$webimroot/thread.php?act=refresh&thread=0&token=123&html=on&user=" . ($isuser ? "true" : "false"); | ||||
| 
 | ||||
| 			print( | ||||
| 					"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">" . | ||||
| 					"<html>\n<head>\n" . | ||||
| 					"<link href=\"$webimroot/styles/default/chat.css\" rel=\"stylesheet\" type=\"text/css\">\n" . | ||||
| 					"<meta http-equiv=\"Refresh\" content=\"" . Settings::get('updatefrequency_oldchat') . "; URL=$url&sn=11\">\n" . | ||||
| 					"<meta http-equiv=\"Pragma\" content=\"no-cache\">\n" . | ||||
| 					"<title>chat</title>\n" . | ||||
| 					"</head>\n" . | ||||
| 					"<body bgcolor='#FFFFFF' text='#000000' link='#C28400' vlink='#C28400' alink='#C28400'>" . | ||||
| 					"<table width='100%' cellspacing='0' cellpadding='0' border='0'><tr><td valign='top' class='message'>"); | ||||
| 
 | ||||
| 		} | ||||
| 		if ($lastid == 1) { | ||||
| 			demo_print_message( | ||||
| 				array('ikind' => Thread::KIND_FOR_AGENT, 'created' => time() - 15, 'tname' => '', | ||||
| 					 'tmessage' => getstring2('chat.came.from', array("http://google.com"))), $outformat); | ||||
| 			demo_print_message( | ||||
| 				array('ikind' => Thread::KIND_INFO, 'created' => time() - 15, 'tname' => '', | ||||
| 					 'tmessage' => getstring('chat.wait')), $outformat); | ||||
| 			demo_print_message( | ||||
| 				array('ikind' => Thread::KIND_EVENTS, 'created' => time() - 10, 'tname' => '', | ||||
| 					 'tmessage' => getstring2("chat.status.operator.joined", array("Administrator"))), $outformat); | ||||
| 			demo_print_message( | ||||
| 				array('ikind' => Thread::KIND_AGENT, 'created' => time() - 9, 'tname' => 'Administrator', | ||||
| 					 'tmessage' => getstring("demo.chat.welcome")), $outformat); | ||||
| 			demo_print_message( | ||||
| 				array('ikind' => Thread::KIND_USER, 'created' => time() - 5, 'tname' => getstring("chat.default.username"), | ||||
| 					 'tmessage' => getstring("demo.chat.question")), $outformat); | ||||
| 			if ($canpost && $outformat == 'xml') { | ||||
| 				demo_print_message( | ||||
| 					array('ikind' => Thread::KIND_INFO, 'created' => time() - 5, 'tname' => '', | ||||
| 						 'tmessage' => 'Hint: type something in message field to see typing notification'), $outformat); | ||||
| 			} | ||||
| 		} | ||||
| 		if ($act == 'post') { | ||||
| 			demo_print_message( | ||||
| 				array('ikind' => $isuser ? Thread::KIND_USER : Thread::KIND_AGENT, 'created' => time(), 'tmessage' => $postmessage, | ||||
| 					 'tname' => $isuser ? getstring("chat.default.username") : "Administrator"), $outformat); | ||||
| 		} | ||||
| 		if ($outformat == "xml") { | ||||
| 			print("</thread>"); | ||||
| 		} else { | ||||
| 			print( | ||||
| 					"</td></tr></table><a name='aend'></a>" . | ||||
| 					"</body></html>"); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
| @ -53,10 +53,10 @@ if( count($errors) > 0 ) { | ||||
| } | ||||
| 
 | ||||
| $history = ""; | ||||
| $lastid = -1; | ||||
| $output = get_messages( $threadid,"text",true,$lastid ); | ||||
| foreach( $output as $msg ) { | ||||
| 	$history .= $msg; | ||||
| $last_id = -1; | ||||
| $messages = $thread->getMessages(true, $last_id); | ||||
| foreach ($messages as $msg) { | ||||
| 	$history .= message_to_text($msg); | ||||
| } | ||||
| 
 | ||||
| $subject = getstring("mail.user.history.subject"); | ||||
|  | ||||
| @ -45,10 +45,20 @@ function thread_info($id) | ||||
| 
 | ||||
| 
 | ||||
| if (isset($_GET['threadid'])) { | ||||
| 	// Load thread info
 | ||||
| 	$threadid = verifyparam("threadid", "/^(\d{1,9})?$/", ""); | ||||
| 	$thread_info = thread_info($threadid); | ||||
| 	$page['thread_info'] = $thread_info; | ||||
| 
 | ||||
| 	// Build messages list
 | ||||
| 	$lastid = -1; | ||||
| 	$page['threadMessages'] = get_messages($threadid, "html", false, $lastid); | ||||
| 	$page['thread_info'] = thread_info($threadid); | ||||
| 	$messages = $thread_info['thread']->getMessages(false, $lastid); | ||||
| 	foreach ($messages as $msg) { | ||||
| 		if ($msg['ikind'] == Thread::KIND_AVATAR) { | ||||
| 			continue; | ||||
| 		} | ||||
| 		$page['threadMessages'][] = Thread::themeMessage($msg); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| prepare_menu($operator, false); | ||||
|  | ||||
| @ -5,13 +5,30 @@ | ||||
| <link rel="shortcut icon" href="${webimroot}/images/favicon.ico" type="image/x-icon"> | ||||
| <link rel="stylesheet" type="text/css" href="${tplroot}/chat.css"> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/common.js"></script> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/mibewapi.js"></script> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/json2.js"></script> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/brws.js"></script> | ||||
| <script type="text/javascript" language="javascript"><!-- | ||||
| var localizedStrings = {closeConfirmation:"${page:chat.close.confirmation}"}; | ||||
| ${if:agent}${if:canpost} | ||||
| var predefinedAnswers = ${page:fullPredefinedAnswers}; | ||||
| ${endif:canpost}${endif:agent} | ||||
| var threadParams = { servl:"${webimroot}/thread.php",wroot:"${webimroot}",frequency:${page:frequency},${if:user}user:"true",${endif:user}threadid:${page:ct.chatThreadId},token:${page:ct.token},cssfile:"${tplroot}/chat.css",ignorectrl:${page:ignorectrl} }; | ||||
| var chatParams = { | ||||
|     cssfile: "${tplroot}/chat.css", | ||||
|     ${if:agent}${if:canpost} | ||||
|     predefinedAnswers: ${page:fullPredefinedAnswers}, | ||||
|     ${endif:canpost}${endif:agent} | ||||
|     threadParams: { | ||||
|         user:${if:user}true${else:user}false${endif:user}, | ||||
|         threadid:${page:ct.chatThreadId}, | ||||
|         token:${page:ct.token} | ||||
|     }, | ||||
|     serverParams: { | ||||
|         servl: "${webimroot}/thread.php", | ||||
|         requestsFrequency: ${page:frequency} | ||||
|     }, | ||||
|     threadUpdaterParams: { | ||||
|         webimRoot: "${webimroot}", | ||||
|         ignorectrl:${page:ignorectrl}, | ||||
|         localizedStrings: {closeConfirmation:"${page:chat.close.confirmation}"} | ||||
|     } | ||||
| } | ||||
| //--> | ||||
| </script> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/chat.js"></script> | ||||
|  | ||||
| @ -5,13 +5,30 @@ | ||||
| <link rel="shortcut icon" href="${webimroot}/images/favicon.ico" type="image/x-icon"> | ||||
| <link rel="stylesheet" type="text/css" href="${tplroot}/chat.css"> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/common.js"></script> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/mibewapi.js"></script> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/json2.js"></script> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/brws.js"></script> | ||||
| <script type="text/javascript" language="javascript"><!-- | ||||
| var localizedStrings = {closeConfirmation:"${page:chat.close.confirmation}"}; | ||||
| ${if:agent}${if:canpost} | ||||
| var predefinedAnswers = ${page:fullPredefinedAnswers}; | ||||
| ${endif:canpost}${endif:agent} | ||||
| var threadParams = { servl:"${webimroot}/thread.php",wroot:"${webimroot}",frequency:${page:frequency},${if:user}user:"true",${endif:user}threadid:${page:ct.chatThreadId},token:${page:ct.token},cssfile:"${tplroot}/chat.css",ignorectrl:${page:ignorectrl} }; | ||||
| var chatParams = { | ||||
|     cssfile: "${tplroot}/chat.css", | ||||
|     ${if:agent}${if:canpost} | ||||
|     predefinedAnswers: ${page:fullPredefinedAnswers}, | ||||
|     ${endif:canpost}${endif:agent} | ||||
|     threadParams: { | ||||
|         user:${if:user}true${else:user}false${endif:user}, | ||||
|         threadid:${page:ct.chatThreadId}, | ||||
|         token:${page:ct.token} | ||||
|     }, | ||||
|     serverParams: { | ||||
|         servl: "${webimroot}/thread.php", | ||||
|         requestsFrequency: ${page:frequency} | ||||
|     }, | ||||
|     threadUpdaterParams: { | ||||
|         webimRoot: "${webimroot}", | ||||
|         ignorectrl:${page:ignorectrl}, | ||||
|         localizedStrings: {closeConfirmation:"${page:chat.close.confirmation}"} | ||||
|     } | ||||
| } | ||||
| //--> | ||||
| </script> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/chat.js"></script> | ||||
|  | ||||
| @ -6,16 +6,31 @@ | ||||
| 	<link rel="shortcut icon" href="${webimroot}/images/favicon.ico" type="image/x-icon" /> | ||||
| 	<link rel="stylesheet" type="text/css" href="${tplroot}/chat.css" media="all" /> | ||||
| 	<script type="text/javascript" src="${webimroot}/js/${jsver}/common.js"></script> | ||||
|         <script type="text/javascript" src="${webimroot}/js/${jsver}/mibewapi.js"></script> | ||||
|         <script type="text/javascript" src="${webimroot}/js/${jsver}/json2.js"></script> | ||||
| 	<script type="text/javascript" src="${webimroot}/js/${jsver}/brws.js"></script> | ||||
| 	<script type="text/javascript"> | ||||
| 		<!-- | ||||
| 		var localizedStrings = {closeConfirmation:"${page:chat.close.confirmation}"}; | ||||
| ${if:agent}${if:canpost} | ||||
| 		var predefinedAnswers = ${page:fullPredefinedAnswers}; | ||||
| ${endif:canpost}${endif:agent} | ||||
| 		var threadParams = { | ||||
| 			servl:"${webimroot}/thread.php",wroot:"${webimroot}",frequency:${page:frequency},${if:user}user:"true",${endif:user}threadid:${page:ct.chatThreadId},token:${page:ct.token},cssfile:"${tplroot}/chat.css",ignorectrl:${page:ignorectrl} | ||||
| 		}; | ||||
|                 var chatParams = { | ||||
|                     cssfile: "${tplroot}/chat.css", | ||||
|                     ${if:agent}${if:canpost} | ||||
|                     predefinedAnswers: ${page:fullPredefinedAnswers}, | ||||
|                     ${endif:canpost}${endif:agent} | ||||
|                     threadParams: { | ||||
|                         user:${if:user}true${else:user}false${endif:user}, | ||||
|                         threadid:${page:ct.chatThreadId}, | ||||
|                         token:${page:ct.token} | ||||
|                     }, | ||||
|                     serverParams: { | ||||
|                         servl: "${webimroot}/thread.php", | ||||
|                         requestsFrequency: ${page:frequency} | ||||
|                     }, | ||||
|                     threadUpdaterParams: { | ||||
|                         webimRoot: "${webimroot}", | ||||
|                         ignorectrl:${page:ignorectrl}, | ||||
|                         localizedStrings: {closeConfirmation:"${page:chat.close.confirmation}"} | ||||
|                     } | ||||
|                 } | ||||
| 		var stxt = 10; | ||||
| 		function getClientHeight() { | ||||
| 			return document.compatMode=='CSS1Compat' || !window.opera?document.documentElement.clientHeight:document.body.clientHeight; | ||||
|  | ||||
| @ -5,13 +5,30 @@ | ||||
| <link rel="shortcut icon" href="${webimroot}/images/favicon.ico" type="image/x-icon"> | ||||
| <link rel="stylesheet" type="text/css" href="${tplroot}/chat.css"> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/common.js"></script> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/mibewapi.js"></script> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/json2.js"></script> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/brws.js"></script> | ||||
| <script type="text/javascript" language="javascript"><!-- | ||||
| var localizedStrings = {closeConfirmation:"${page:chat.close.confirmation}"}; | ||||
| ${if:agent}${if:canpost} | ||||
| var predefinedAnswers = ${page:fullPredefinedAnswers}; | ||||
| ${endif:canpost}${endif:agent} | ||||
| var threadParams = { servl:"${webimroot}/thread.php",wroot:"${webimroot}",frequency:${page:frequency},${if:user}user:"true",${endif:user}threadid:${page:ct.chatThreadId},token:${page:ct.token},cssfile:"${tplroot}/chat.css",ignorectrl:${page:ignorectrl} }; | ||||
| var chatParams = { | ||||
|     cssfile: "${tplroot}/chat.css", | ||||
|     ${if:agent}${if:canpost} | ||||
|     predefinedAnswers: ${page:fullPredefinedAnswers}, | ||||
|     ${endif:canpost}${endif:agent} | ||||
|     threadParams: { | ||||
|         user:${if:user}true${else:user}false${endif:user}, | ||||
|         threadid:${page:ct.chatThreadId}, | ||||
|         token:${page:ct.token} | ||||
|     }, | ||||
|     serverParams: { | ||||
|         servl: "${webimroot}/thread.php", | ||||
|         requestsFrequency: ${page:frequency} | ||||
|     }, | ||||
|     threadUpdaterParams: { | ||||
|         webimRoot: "${webimroot}", | ||||
|         ignorectrl:${page:ignorectrl}, | ||||
|         localizedStrings: {closeConfirmation:"${page:chat.close.confirmation}"} | ||||
|     } | ||||
| } | ||||
| //--> | ||||
| </script> | ||||
| <script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/chat.js"></script> | ||||
|  | ||||
| @ -19,97 +19,13 @@ require_once('libs/init.php'); | ||||
| require_once('libs/chat.php'); | ||||
| require_once('libs/operator.php'); | ||||
| require_once('libs/classes/thread.php'); | ||||
| require_once('libs/classes/mibew_api.php'); | ||||
| require_once('libs/classes/mibew_api_interaction.php'); | ||||
| require_once('libs/classes/mibew_api_window_interaction.php'); | ||||
| require_once('libs/classes/mibew_api_execution_context.php'); | ||||
| require_once('libs/classes/thread_processor.php'); | ||||
| 
 | ||||
| $act = verifyparam( "act", "/^(refresh|post|rename|close|ping)$/"); | ||||
| $token = verifyparam( "token", "/^\d{1,9}$/"); | ||||
| $threadid = verifyparam( "thread", "/^\d{1,9}$/"); | ||||
| $isuser = verifyparam( "user", "/^true$/", "false") == 'true'; | ||||
| $outformat = ((verifyparam( "html", "/^on$/", "off") == 'on') ? "html" : "xml"); | ||||
| $istyping = verifyparam( "typed", "/^1$/", "") == '1'; | ||||
| 
 | ||||
| if($threadid == 0 && ($token == 123 || $token == 124)) { | ||||
| 	require_once('libs/demothread.php'); | ||||
| 	$lastid = verifyparam( "lastid", "/^\d{1,9}$/", 0); | ||||
| 	demo_process_thread($act,$outformat,$lastid,$isuser,$token == 123,$istyping,$act=="post"?getrawparam('message') : ""); | ||||
| 	exit; | ||||
| } | ||||
| 
 | ||||
| $thread = Thread::load($threadid, $token); | ||||
| if (! $thread) { | ||||
| 	die("wrong thread"); | ||||
| } | ||||
| 
 | ||||
| function show_ok_result($resid) { | ||||
| 	start_xml_output(); | ||||
| 	echo "<$resid></$resid>"; | ||||
| 	exit; | ||||
| } | ||||
| 
 | ||||
| function show_error($message) { | ||||
| 	start_xml_output(); | ||||
| 	echo "<error><descr>$message</descr></error>"; | ||||
| 	exit; | ||||
| } | ||||
| 
 | ||||
| $thread->ping($isuser, $istyping); | ||||
| 
 | ||||
| if( !$isuser && $act != "rename" ) { | ||||
| 	$operator = check_login(); | ||||
| 	$thread->checkForReassign($operator); | ||||
| } | ||||
| 
 | ||||
| if( $act == "refresh" ) { | ||||
| 	$lastid = verifyparam( "lastid", "/^\d{1,9}$/", -1); | ||||
| 	print_thread_messages($thread, $token, $lastid, $isuser,$outformat, $isuser ? null : $operator['operatorid']); | ||||
| 	exit; | ||||
| 
 | ||||
| } else if( $act == "post" ) { | ||||
| 	$lastid = verifyparam( "lastid", "/^\d{1,9}$/", -1); | ||||
| 	$message = getrawparam('message'); | ||||
| 
 | ||||
| 	$kind = $isuser ? Thread::KIND_USER : Thread::KIND_AGENT; | ||||
| 	$from = $isuser ? $thread->userName : $thread->agentName; | ||||
| 
 | ||||
| 	if(!$isuser && $operator['operatorid'] != $thread->agentId) { | ||||
| 		show_error("cannot send"); | ||||
| 	} | ||||
| 
 | ||||
| 	$postedid = $thread->postMessage( | ||||
| 		$kind, | ||||
| 		$message, | ||||
| 		$from, | ||||
| 		$isuser ? null : $operator['operatorid'] | ||||
| 	); | ||||
| 	if($isuser && $thread->shownMessageId == 0) { | ||||
| 		$thread->shownMessageId = $postedid; | ||||
| 		$thread->save(); | ||||
| 	} | ||||
| 	print_thread_messages($thread, $token, $lastid, $isuser, $outformat, $isuser ? null : $operator['operatorid']); | ||||
| 	exit; | ||||
| 
 | ||||
| } else if( $act == "rename" ) { | ||||
| 
 | ||||
| 	if( Settings::get('usercanchangename') != "1" ) { | ||||
| 		show_error("server: forbidden to change name"); | ||||
| 	} | ||||
| 
 | ||||
| 	$newname = getrawparam('name'); | ||||
| 
 | ||||
| 	$thread->renameUser($newname); | ||||
| 	$data = strtr(base64_encode(myiconv($webim_encoding,"utf-8",$newname)), '+/=', '-_,'); | ||||
| 	setcookie($namecookie, $data, time()+60*60*24*365); | ||||
| 	show_ok_result("rename"); | ||||
| 
 | ||||
| } else if( $act == "ping" ) { | ||||
| 	show_ok_result("ping"); | ||||
| 
 | ||||
| } else if( $act == "close" ) { | ||||
| 
 | ||||
| 	if( $isuser || $thread->agentId == $operator['operatorid']) { | ||||
| 		$thread->close($isuser); | ||||
| 	} | ||||
| 	show_ok_result("closed"); | ||||
| 
 | ||||
| } | ||||
| $processor = ThreadProcessor::getInstance(); | ||||
| $processor->receiveRequest($_POST['data']); | ||||
| 
 | ||||
| ?>
 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user