From c2206ec72b01c604a7a65d40c65b39ae31fa3e3e Mon Sep 17 00:00:00 2001 From: Evgeny Gryaznov Date: Mon, 29 Sep 2008 16:10:06 +0000 Subject: [PATCH] move js git-svn-id: https://webim.svn.sourceforge.net/svnroot/webim/trunk@106 c66351dc-e62f-0410-b875-e3a5c0b9693f --- src/messenger/js/brws.js | 30 +++ src/messenger/js/chat.js | 368 ++++++++++++++++++++++++++ src/messenger/js/common.js | 526 +++++++++++++++++++++++++++++++++++++ src/messenger/js/users.js | 310 ++++++++++++++++++++++ 4 files changed, 1234 insertions(+) create mode 100644 src/messenger/js/brws.js create mode 100644 src/messenger/js/chat.js create mode 100644 src/messenger/js/common.js create mode 100644 src/messenger/js/users.js diff --git a/src/messenger/js/brws.js b/src/messenger/js/brws.js new file mode 100644 index 00000000..9a895eb0 --- /dev/null +++ b/src/messenger/js/brws.js @@ -0,0 +1,30 @@ +var myAgent = ""; +var myVer = 0; +var myRealAgent = ""; + +function detectAgent() { + var AGENTS = ["opera","msie","safari","firefox","netscape","mozilla"]; + var agent = navigator.userAgent.toLowerCase(); + for (var i = 0; i < AGENTS.length; i++) { + var agentStr = AGENTS[i]; + if (agent.indexOf(agentStr) != -1) { + myAgent = agentStr; + if (!window.RegExp) + break; + + var versionExpr = new RegExp(agentStr + "[ \/]?([0-9]+(\.[0-9]+)?)"); + if (versionExpr.exec(agent) != null) { + myVer = parseFloat(RegExp.$1); + } + break; + } + } + myRealAgent = myAgent; + if( navigator.product == "Gecko") + myAgent = "moz"; +} +detectAgent(); + +function getEl(name) { + return document.getElementById(name); +} diff --git a/src/messenger/js/chat.js b/src/messenger/js/chat.js new file mode 100644 index 00000000..ddcfb53a --- /dev/null +++ b/src/messenger/js/chat.js @@ -0,0 +1,368 @@ +var FrameUtils = { + getDocument: function(frm) { + if (frm.contentDocument) { + return frm.contentDocument; + } else if (frm.contentWindow) { + return frm.contentWindow.document; + } else if (frm.document) { + return frm.document; + } else { + alert( myRealAgent + ": cannot find document in frame " + frm); + //for( var a in frm ) + // alert( a ); + return null; + } + }, + + initFrame: function(frm) { + var doc = this.getDocument(frm); + doc.open(); + doc.write(""); + doc.write(""); + doc.write(""); + doc.write("
"); + doc.write(""); + doc.close(); + frm.onload = function() { + if( frm./**/myHtml ) { + FrameUtils.getDocument(frm).getElementById('content').innerHTML += frm.myHtml; + FrameUtils.scrollDown(frm); + } + }; + }, + + insertIntoFrame: function(frm, htmlcontent) { + var vcontent = this.getDocument(frm).getElementById('content'); + if( vcontent == null ) { + if( !frm.myHtml ) frm.myHtml = ""; + frm.myHtml += htmlcontent; + } else { + vcontent.innerHTML += htmlcontent; + } + }, + + scrollDown: function(frm) { + var vbottom = this.getDocument(frm).getElementById('bottom'); + if( myAgent == 'opera' ) { + frm.contentWindow.scrollTo(0,this.getDocument(frm).getElementById('content').clientHeight); + } else if( vbottom ) + vbottom.scrollIntoView(false); + } +}; + +Ajax.ChatThreadUpdater = Class.create(); +Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, { + + initialize: function(_options) { + this.setOptions(_options); + this._options.onComplete = this.requestComplete.bind(this); + this._options.onException = this.handleException.bind(this); + this.updater = {}; + this.frequency = (this._options.frequency || 2); + this.cansend = true; + 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(); + }, + + handleException: function(_request, ex) { + this.setStatus(ex.name + " occured: " + ex.message); + this.stopUpdate(); + this.timer = setTimeout(this.update.bind(this), this.frequency * 1000); + }, + + updateOptions: function(act) { + this._options.parameters = 'act='+act+'&thread=' + (this._options.threadid || -1) + + '&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"; + }, + + enableInput: function(val) { + if( this._options.message ) + this._options.message.disabled = !val; + }, + + stopUpdate: function() { + this.enableInput(true); + if( this.updater._options ) + this.updater._options.onComplete = undefined; + clearTimeout(this.timer); + }, + + update: function() { + this.updateOptions("refresh"); + this.updater = new Ajax.Request(this._options.servl, this._options); + }, + + requestComplete: function(_response) { + 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'); + } + + this.timer = setTimeout(this.update.bind(this), this.frequency * 1000); + }, + + postMessage: function(msg) { + if( msg == "" || !this.cansend) { + return; + } + this.cansend = false; + this.stopUpdate(); + 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); + }, + + changeName: function(newname) { + new Ajax.Request(this._options.servl, {parameters:'act=rename&thread=' + (this._options.threadid || -1) + + '&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'); + } + }, + + closeThread: function() { + var _params = 'act=close&thread=' + (this._options.threadid || -1) + '&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)}); + }, + + processMessage: function(_target, message) { + var destHtml = NodeUtils.getNodeText(message); + FrameUtils.insertIntoFrame(_target, destHtml ); + }, + + 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 != "" + ? "\"\"\"\"/" + : ""; + } + }, + + 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'); + } + + 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); + } + // TODO thread events + } + if( haveMessage ) { + FrameUtils.scrollDown(this._options.container); + if( !this.focused ) + window.focus(); + } + }, + + handleKeyDown: function(k) { + if( k ){ ctrl=k.ctrlKey;k=k.which; } else { k=event.keyCode;ctrl=event.ctrlKey; } + if( this._options.message && ((k==13 && (ctrl || myRealAgent == 'opera')) || (k==10)) ) { + var mmsg = this._options.message.value; + if( myRealAgent == 'opera' ) { + mmsg = mmsg.replace(/[\r\n]+$/,''); + } + this.postMessage( mmsg ); + return false; + } + return true; + }, + + handleError: function(_response, xmlRoot, _action) { + if( xmlRoot && xmlRoot.tagName == 'error' ) { + this.setStatus(NodeUtils.getNodeValue(xmlRoot,"descr")); + } else { + this.setStatus(_action+', ' + Ajax.getError(_response)); + } + }, + + setStatus: function(k) { + if( this.statusTimeout ) + clearTimeout(this.statusTimeout); + window.status = k; + this.statusTimeout = setTimeout(this.clearStatus.bind(this), 4000); + }, + + clearStatus: function() { + window.status = ""; + } +}); + + +HSplitter = Class.create(); +HSplitter.prototype = { + initialize: function(_options) { + this._options = _options; + this.captured = 0; + if( this._options.first && this._options.second && this._options.control ) { + this._options.control.onmousedown = this.onmousedownEvent.bind(this); + this._options.control.onmouseup = this.onmouseupEvent.bind(this); + this._options.control.onmousemove = this.onmouseMoveEvent.bind(this); + } + }, + + onmousedownEvent: function(e) { + var ev = e || event; + + if( this._options.control.setCapture ) + this._options.control.setCapture(); + this.start_height = this._options.first.style.pixelHeight || this._options.first.clientHeight; + this.start_offset = ev.screenY; + this._options.maxfirst = this._options.first.style.pixelHeight + this._options.second.clientHeight - this._options.minsec; + this.captured = 1; + }, + + onmouseupEvent: function() { + if( this.captured ) { + if( this._options.control.releaseCapture ) + this._options.control.releaseCapture(); + this.captured = 0; + } + }, + + onmouseMoveEvent: function(e) { + var ev = e || event; + + if( this.captured ) { + var new_height = this.start_height - (ev.screenY - this.start_offset); + if( new_height > this._options.maxfirst ) + new_height = this._options.maxfirst; + else if( new_height < this._options.minfirst ) + new_height = this._options.minfirst; + if( myAgent == 'moz' ) + this._options.first.style.height=new_height+'px'; + else + this._options.first.style.pixelHeight = new_height; + } + } +}; + +var Chat = { + threadUpdater : {}, + hSplitter : {}, + + applyName: function() { + Chat.threadUpdater.changeName($('uname').value); + $('changename1').style.display='none'; + $('changename2').style.display='inline'; + }, + + showNameField: function() { + $('changename1').style.display='inline'; + $('changename2').style.display='none'; + } +}; + +Behaviour.register({ + '#postmessage a' : function(el) { + el.onclick = function() { + var message = $('msgwnd'); + if( message ) + Chat.threadUpdater.postMessage(message.value); + }; + }, + 'a#sndmessagelnk' : function(el) { + if( myRealAgent == 'opera' ) { + el.innerHTML = el.innerHTML.replace('Ctrl-',''); + } + }, + 'select#predefined' : function(el) { + el.onchange = function() { + var message = $('msgwnd'); + message.value = this.options[this.selectedIndex].innerText || this.options[this.selectedIndex].innerHTML; + this.selectedIndex = 0; + message.focus(); + }; + }, + 'div#changename2 a' : function(el) { + el.onclick = function() { + Chat.showNameField(); + return false; + }; + }, + 'div#changename1 a' : function(el) { + el.onclick = function() { + Chat.applyName(); + return false; + }; + }, + 'div#changename1 input#uname' : function(el) { + el.onkeydown = function(e) { + var ev = e || event; + if( ev.keyCode == 13 ) { + Chat.applyName(); + } + }; + }, + 'a#refresh' : function(el) { + el.onclick = function() { + Chat.threadUpdater.stopUpdate(); + Chat.threadUpdater.update(); + }; + }, + 'a.closethread' : function(el) { + el.onclick = function() { + Chat.threadUpdater.closeThread(); + }; + } +}); + +EventHelper.register(window, 'onload', function(){ + Chat.webimRoot = threadParams.wroot; + Chat.hSplitter = new HSplitter({control:$("spl1"), first:$("msgwndtd"), second:$("chatwndtd"), minfirst:30, minsec:30}); + Chat.threadUpdater = new Ajax.ChatThreadUpdater(({container:myRealAgent=='safari'?self.frames[0]:$("chatwnd"),avatar:$("avatarwnd"),message:$("msgwnd")}).extend( threadParams || {} )); +}); diff --git a/src/messenger/js/common.js b/src/messenger/js/common.js new file mode 100644 index 00000000..bc9ff3d3 --- /dev/null +++ b/src/messenger/js/common.js @@ -0,0 +1,526 @@ +/* + * Web Messenger common script + * http://sourceforge.net/projects/webim + * + * Based on Prototype JavaScript framework, version 1.3.1 + * http://prototype.conio.net/ (c) 2005 Sam Stephenson + */ + +//- getEl, myAgent, myRealAgent + +//- localized + +//- onComplete, obj, params, $apply$ +//- threadParams, servl, frequency, user, threadid, token +//- updaterOptions, url, company, agentservl, noclients, wroot + + +var Class = { + create: function() { + return function() { + this./**/initialize./**/apply(this, arguments); + }; + }, + + inherit: function(child,parent,body) { + Object./**/extend(Object.extend(child.prototype, parent.prototype), body ); + } +}; + +Object.extend = function(destination, source) { + for (property in source) { + destination[property] = source[property]; + } + return destination; +}; + +Object.prototype.extend = function(_object) { + return Object.extend.apply(this, [this, _object]); +}; + +Function.prototype./**/bind = function(_object) { + var __method = this; + return function() { + return __method.apply(_object, arguments); + } +}; + +Function.prototype./**/bindAsEventListener = function(_object) { + var __method = this; + return function(event) { + __method.call(_object, event || window.event); + } +}; + +Number.prototype./**/toColorPart = function() { + var digits = this.toString(16); + if (this < 16) return '0' + digits; + return digits; +}; + +var Try = { + these: function() { + var returnValue; + + for (var i = 0; i < arguments.length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) {} + } + + return returnValue; + } +}; + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create(); +PeriodicalExecuter.prototype = { + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this./**/currentlyExecuting = false; + + this./**/registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.callback(); + } finally { + this.currentlyExecuting = false; + } + } + } +}; + +/*--------------------------------------------------------------------------*/ + +function findObj( id ) +{ + var x; + if( !( x = document[ id ] ) && document.all ) x = document.all[ id ]; + if( !x && document.getElementById ) x = document.getElementById( id ); + if( !x && !document.all && document.getElementsByName ) + { + x = document.getElementsByName( id ); + if( x.length == 0 ) return null; + if( x.length == 1 ) return x[ 0 ]; + } + + return x; +} + +if (!Array.prototype./**/push) { + Array.prototype.push = function() { + var startLength = this.length; + for (var i = 0; i < arguments.length; i++) + this[startLength + i] = arguments[i]; + return this.length; + }; +} + +function $() { + var elems = new Array(); + + for (var i = 0; i < arguments.length; i++) { + var elem = arguments[i]; + if (typeof elem == 'string') + elem = findObj(elem); + + if (arguments.length == 1) + return elem; + + elems.push(elem); + } + + return elems; +} + +if (!Function.prototype.apply) { + Function.prototype.apply = function(obj, params) { + var parameterStrings = new Array(); + if (!obj) obj = window; + if (!params) params = new Array(); + + for (var i = 0; i < params.length; i++) + parameterStrings[i] = 'params[' + i + ']'; + + obj.$apply$ = this; + var result = eval('obj.$apply$(' + + parameterStrings.join(', ') + ')'); + obj.$apply$ = null; + + return result; + }; +} + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')}, + function() {return new XMLHttpRequest()} + ) || false; + }, + + getXml: function(_response) { + if( _response && + _response.status >= 200 && + _response.status < 300 ) { + var xmlDoc = _response.responseXML; + if( xmlDoc && xmlDoc.documentElement ) + return xmlDoc.documentElement; + } + return null; + }, + + getError: function(_response) { + return _response.statusText || "connection error N" + _response.status; + }, + + emptyFunction: function() {} +}; + +Ajax./**/Base = function() {}; +Ajax.Base.prototype = { + setOptions: function(_options) { + this._options = { + _method: 'post', + asynchronous: true, + parameters: '' + }.extend(_options || {}); + }, + + responseIsSuccess: function() { + return this./**/transport.status == undefined + || this.transport.status == 0 + || (this.transport.status >= 200 && this.transport.status < 300); + }, + + responseIsFailure: function() { + return !this.responseIsSuccess(); + } +}; + +Ajax./**/Request = Class.create(); +Ajax.Request./**/Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Class.inherit( Ajax.Request, Ajax.Base, { + initialize: function(url, _options) { + this.transport = Ajax.getTransport(); + this.setOptions(_options); + this.request(url); + }, + + request: function(url) { + var parameters = this._options.parameters || ''; + if (parameters.length > 0) parameters += '&_='; + + try { + if (this._options._method == 'get' && parameters.length > 0) + url += '?' + parameters; + + this.transport.open(this._options._method, url, this._options.asynchronous); + + if (this._options.asynchronous) { + this.transport.onreadystatechange = this.onStateChange.bind(this); + setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); + } + + this.setRequestHeaders(); + + var pbody = this._options.postBody ? this._options.postBody : parameters; + this.transport.send(this._options._method == 'post' ? pbody : null); + + } catch (e) { + this.dispatchException(e); + } + }, + + setRequestHeaders: function() { + var requestHeaders = + ['X-Requested-With', 'XMLHttpRequest']; + + if (this._options._method == 'post') { + requestHeaders.push('Content-type', + 'application/x-www-form-urlencoded'); + + /* Force "Connection: close" for Mozilla browsers to work around + * a bug where XMLHttpReqeuest sends an incorrect Content-length + * header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType) + requestHeaders.push('Connection', 'close'); + } + + if (this._options.requestHeaders) + requestHeaders.push.apply(requestHeaders, this._options.requestHeaders); + + for (var i = 0; i < requestHeaders.length; i += 2) + this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); + }, + + onStateChange: function() { + var readystate = this.transport.readyState; + if (readystate != 1) + this.respondToReadyState(this.transport.readyState); + }, + + header: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) {} + }, + + evalResponse: function() { + try { + return eval(this.transport.responseText); + } catch (e) { + this.dispatchException(e); + } + }, + + respondToReadyState: function(readystate) { + var event = Ajax.Request.Events[readystate]; + + if (event == 'Complete') { + try { + (this._options['on' + this.transport.status] + || this._options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] + || Ajax.emptyFunction)(this.transport); + } catch (e) { + this.dispatchException(e); + } + + if ((this.header('Content-type') || '').match("text\\/javascript")) + this.evalResponse(); + } + + try { + (this._options['on' + event] || Ajax.emptyFunction)(this.transport); + } catch (e) { + this.dispatchException(e); + } + + /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ + if (event == 'Complete') + this.transport.onreadystatechange = Ajax.emptyFunction; + }, + + dispatchException: function(exception) { + (this._options.onException || Ajax.emptyFunction)(this, exception); + } +}); + +var EventHelper = { + register : function(obj, ev,func){ + var oldev = obj[ev]; + + if (typeof oldev != 'function') { + obj[ev] = func; + } else { + obj[ev] = function() { + oldev(); + func(); + } + } + } +}; + +/* + Behaviour v1.1 by Ben Nolan, June 2005. Based largely on the work + of Simon Willison (see comments by Simon below). + http://ripcord.co.nz/behaviour/ +*/ + +var Behaviour = { + list : new Array, + + register : function(sheet){ + Behaviour.list.push(sheet); + }, + + init : function(){ + EventHelper.register(window, 'onload', function(){ + Behaviour.apply(); + }); + }, + + apply : function(){ + for (h=0;sheet=Behaviour.list[h];h++){ + for (selector in sheet) { + list = document.getElementsBySelector(selector); + if (!list) + continue; + for( i = 0; element = list[i]; i++ ) { + sheet[selector]( element ); + } + } + } + } +}; + +Behaviour.init(); + +function getAllChildren(e) { + // Returns all children of element. Workaround required for IE5/Windows. Ugh. + return e.all ? e.all : e.getElementsByTagName('*'); +} + +document.getElementsBySelector = function(selector) { + // Attempt to fail gracefully in lesser browsers + if (!document.getElementsByTagName) { + return new Array(); + } + // Split selector in to tokens + var tokens = selector.split(' '); + var currentContext = new Array(document); + for (var i = 0; i < tokens.length; i++) { + token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');; + if (token.indexOf('#') > -1) { + // Token is an ID selector + var bits = token.split('#'); + var tag_name = bits[0]; + var id = bits[1]; + var element = document.getElementById(id); + if (element == null || tag_name && element.nodeName.toLowerCase() != tag_name ) { + // tag with that ID not found, return false + return new Array(); + } + // Set currentContext to contain just this element + currentContext = new Array(element); + continue; // Skip to next token + } + if (token.indexOf('.') > -1) { + // Token contains a class selector + var bits = token.split('.'); + var tag_name = bits[0]; + var class_name = bits[1]; + if (!tag_name) { + tag_name = '*'; + } + // Get elements matching tag, filter them for class selector + var found = new Array; + var foundCount = 0; + for (var h = 0; h < currentContext.length; h++) { + var elements; + if (tag_name == '*') { + elements = getAllChildren(currentContext[h]); + } else { + elements = currentContext[h].getElementsByTagName(tag_name); + } + if( elements == null ) + continue; + for (var j = 0; j < elements.length; j++) { + found[foundCount++] = elements[j]; + } + } + currentContext = new Array; + var currentContextIndex = 0; + for (var k = 0; k < found.length; k++) { + if (found[k].className && found[k].className.match(new RegExp("\\b"+class_name+"\\b"))) { + currentContext[currentContextIndex++] = found[k]; + } + } + continue; // Skip to next token + } + + // [evgeny] code for attribute selection is removed... + + if (!currentContext[0]){ + return; + } + + // If we get here, token is JUST an element (not a class or ID selector) + tag_name = token; + var found = new Array; + var foundCount = 0; + for (var h = 0; h < currentContext.length; h++) { + var elements = currentContext[h].getElementsByTagName(tag_name); + for (var j = 0; j < elements.length; j++) { + found[foundCount++] = elements[j]; + } + } + currentContext = found; + } + return currentContext; +}; + +var NodeUtils = { + + getNodeValue: function(parent,name) { + var nodes = parent.getElementsByTagName( name ); + if( nodes.length == 0 ) + return ""; + nodes = nodes[0].childNodes; + var reslt = ""; + for( i = 0; i < nodes.length; i++ ) + reslt += nodes[i].nodeValue; + return reslt; + }, + + getNodeText: function(_node) { + var _nodes = _node.childNodes; + var _text = ""; + for( i = 0; i < _nodes.length; i++ ) + _text += _nodes[i].nodeValue; + return _text; + }, + + getAttrValue: function(parent,name) { + for( k=0; k < parent.attributes.length; k++ ) + if( parent.attributes[k].nodeName == name ) + return parent.attributes[k].nodeValue; + return null; + } +}; + +var CommonUtils = { + getRow: function(_id,_table) { + var _row = _table.rows[_id]; + if( _row != null ) + return _row; + if( _table.rows['head'] != null ) + return null; + + for( k=0; k < _table.rows.length; k++ ) { + if( _table.rows[k].id == _id ) + return _table.rows[k]; + } + return null; + }, + + getCell: function(_id,_row,_table) { + var _cell = _row.cells[_id]; + if( _cell != null ) + return _cell; + if( _table.rows['head'] != null ) + return null; + for( k=0; k < _row.cells.length; k++ ) { + if( _row.cells[k].id == _id ) + return _row.cells[k]; + } + return null; + }, + + insertCell: function(_row,_id,_className,_align,_height, _inner) { + var cell = _row.insertCell(-1); + cell.id = _id; + if(_align) + cell.align = _align; + cell.className = _className; + if(_height) + cell.height = _height; + cell.innerHTML = _inner; + } +}; diff --git a/src/messenger/js/users.js b/src/messenger/js/users.js new file mode 100644 index 00000000..af115a46 --- /dev/null +++ b/src/messenger/js/users.js @@ -0,0 +1,310 @@ +Ajax.PeriodicalUpdater = Class.create(); +Class.inherit( Ajax.PeriodicalUpdater, Ajax.Base, { + + initialize: function(_options) { + this.setOptions(_options); + this._options.onComplete = this.requestComplete.bind(this); + this._options.onException = this.handleException.bind(this); + this.frequency = (this._options.frequency || 2); + this.updater = {}; + this.update(); + }, + + handleException: function(_request, ex) { + if( this._options.handleError ) + this._options.handleError( ex.name + " occured: " + ex.message ); + this.stopUpdate(); + this.timer = setTimeout(this.update.bind(this), this.frequency * 1000); + }, + + stopUpdate: function() { + if( this.updater._options ) + this.updater._options.onComplete = undefined; + clearTimeout(this.timer); + }, + + update: function() { + if( this._options.updateParams ) + this._options.parameters = (this._options.updateParams)(); + this.updater = new Ajax.Request(this._options.url, this._options); + }, + + requestComplete: function(presponse) { + if (presponse != null && presponse.status == 200 ) { + var xmlDoc = presponse.responseXML; + (this._options.updateContent || Ajax.emptyFunction)( xmlDoc ); + } else { + if( this._options.handleError ) + this._options.handleError(Ajax.getError(_response)); + } + + this.timer = setTimeout(this.update.bind(this), this.frequency * 1000); + } +}); + +var HtmlGenerationUtils = { + + insertSplitter: function( _row ) { + var cell = _row.insertCell(-1); + cell.style.backgroundImage = 'url('+webimRoot+'/images/tablediv3.gif)'; + cell.innerHTML = ''; + }, + + removeHr: function(_table, _index ) { + _table.deleteRow(_index+2); + _table.deleteRow(_index+1); + _table.deleteRow(_index); + }, + + insertHr: function(_table, _index) { + var row = _table.insertRow(_index); + var cell = row.insertCell(-1); + cell.colSpan = 13; + cell.height = 2; + + row = _table.insertRow(_index); + cell = row.insertCell(-1); + cell.colSpan = 13; + cell.style.backgroundColor = '#E1E1E1'; + cell.innerHTML = ''; + + row = _table.insertRow(_index); + cell = row.insertCell(-1); + cell.colSpan = 13; + cell.height = 2; + }, + + popupLink: function(link, title, wndid, inner, width, height) { + return ''+ + inner+''; + }, + + generateOneRowTable: function(content) { + return '' + content + '
'; + }, + + viewOpenCell: function(username,servlet,id,canview,canopen,ban,message) { + var cellsCount = 2; + var link = servlet+"?thread="+id; + var innerContent = ( ban == "full" ) ? ""+username+"" : ( ( ban == "other" ) ? ""+username+"" : username ); + var gen = ''; + gen += HtmlGenerationUtils.popupLink( canopen ? link : link+"&viewonly=true", localized[canopen ? 0 : 1], "ImCenter"+id, innerContent, 600, 420); + gen += ''; + if( canopen ) { + gen += ''; + gen += HtmlGenerationUtils.popupLink( link, localized[0], "ImCenter"+id, ''+localized[0]+'', 600, 420); + gen += ''; + cellsCount++; + } + + return HtmlGenerationUtils.generateOneRowTable(gen); + } + + +}; + +Ajax.ThreadListUpdater = Class.create(); +Class.inherit( Ajax.ThreadListUpdater, Ajax.Base, { + + initialize: function(_options) { + this.setOptions(_options); + this._options.updateParams = this.updateParams.bind(this); + this._options.handleError = this.handleError.bind(this); + this._options.updateContent = this.updateContent.bind(this); + this._options.lastrevision = 0; + this.threadTimers = new Object(); + this.delta = 0; + this.t = this._options.table; + this.periodicalUpdater = new Ajax.PeriodicalUpdater(this._options); + }, + + updateParams: function() { + return "company=" + this._options.company + "&since=" + this._options.lastrevision; + }, + + setStatus: function(msg) { + this._options.status.innerHTML = msg; + }, + + handleError: function(s) { + this.setStatus( s ); + }, + + updateThread: function(node) { + var id, stateid, vstate, canview = false, canopen = false, ban = null; + + for( var i = 0; i < node.attributes.length; i++ ) { + var attr = node.attributes[i]; + if( attr.nodeName == "id" ) + id = attr.nodeValue; + else if( attr.nodeName == "stateid" ) + stateid = attr.nodeValue; + else if( attr.nodeName == "state" ) + vstate = attr.nodeValue; + else if( attr.nodeName == "canopen" ) + canopen = true; + + } + + function setcell(_table, row,id,pcontent) { + var cell = CommonUtils.getCell( id, row, _table ); + if( cell ) + cell.innerHTML = pcontent; + } + + var row = CommonUtils.getRow("thr"+id, this.t); + if( stateid == "closed" ) { + if( row ) { + HtmlGenerationUtils.removeHr(this.t, row.rowIndex+1); + this.t.deleteRow(row.rowIndex); + } + this.threadTimers[id] = null; + return; + } + + var vname = NodeUtils.getNodeValue(node,"name"); + var vaddr = NodeUtils.getNodeValue(node,"addr"); + var vtime = NodeUtils.getNodeValue(node,"time"); + var agent = NodeUtils.getNodeValue(node,"agent"); + var modified = NodeUtils.getNodeValue(node,"modified"); + var message = NodeUtils.getNodeValue(node,"message"); + var etc = ""; + + + + var startRow = CommonUtils.getRow(stateid, this.t); + var endRow = CommonUtils.getRow(stateid+"end", this.t); + + if( row != null && (row.rowIndex <= startRow.rowIndex || row.rowIndex >= endRow.rowIndex ) ) { + HtmlGenerationUtils.removeHr(this.t, row.rowIndex+1); + this.t.deleteRow(row.rowIndex); + this.threadTimers[id] = null; + row = null; + } + if( row == null ) { + row = this.t.insertRow(startRow.rowIndex+1); + HtmlGenerationUtils.insertHr(this.t, startRow.rowIndex+2); + row.id = "thr"+id; + this.threadTimers[id] = new Array(vtime,modified,stateid); + CommonUtils.insertCell(row, "name", "table", null, 30, HtmlGenerationUtils.viewOpenCell(vname,this._options.agentservl,id,canview,canopen,ban,message) ); + HtmlGenerationUtils.insertSplitter(row); + CommonUtils.insertCell(row, "contid", "table", "center", null, vaddr ); + HtmlGenerationUtils.insertSplitter(row); + CommonUtils.insertCell(row, "state", "table", "center", null, vstate ); + HtmlGenerationUtils.insertSplitter(row); + CommonUtils.insertCell(row, "op", "table", "center", null, agent ); + HtmlGenerationUtils.insertSplitter(row); + CommonUtils.insertCell(row, "time", "table", "center", null, this.getTimeSince(vtime) ); + HtmlGenerationUtils.insertSplitter(row); + CommonUtils.insertCell(row, "wait", "table", "center", null, (stateid!='chat' ? this.getTimeSince(modified) : '-') ); + HtmlGenerationUtils.insertSplitter(row); + CommonUtils.insertCell(row, "etc", "table", "center", null, etc ); + + if( stateid == 'wait' || stateid == 'prio' ) + return true; + } else { + this.threadTimers[id] = new Array(vtime,modified,stateid); + setcell(this.t, row,"name",HtmlGenerationUtils.viewOpenCell(vname,this._options.agentservl,id,canview,canopen,ban,message)); + setcell(this.t, row,"contid",vaddr); + setcell(this.t, row,"state",vstate); + setcell(this.t, row,"op",agent); + setcell(this.t, row,"time",this.getTimeSince(vtime)); + setcell(this.t, row,"wait",(stateid!='chat' ? this.getTimeSince(modified) : '-')); + setcell(this.t, row,"etc",etc); + } + return false; + }, + + updateQueueMessages: function() { + function updateQueue(t,id,nclients) { + var startRow = t.rows[id]; + var endRow = t.rows[id+"end"]; + if( startRow == null || endRow == null ) + return; + var _status = endRow.cells["status"]; + if( _status == null ) + return; + _status.innerHTML = (startRow.rowIndex + 1 == endRow.rowIndex) ? nclients : ""; + _status.height = (startRow.rowIndex + 1 == endRow.rowIndex) ? 30 : 10; + } + + updateQueue(this.t, "wait", this._options.noclients); + updateQueue(this.t, "prio", this._options.noclients); + updateQueue(this.t, "chat", this._options.noclients); + }, + + getTimeSince: function(srvtime) { + var secs = Math.floor(((new Date()).getTime()-srvtime-this.delta)/1000); + var minutes = Math.floor(secs/60); + var prefix = ""; + secs = secs % 60; + if( secs < 10 ) + secs = "0" + secs; + if( minutes >= 60 ) { + var hours = Math.floor(minutes/60); + minutes = minutes % 60; + if( minutes < 10 ) + minutes = "0" + minutes; + prefix = hours + ":"; + } + + return prefix + minutes+":"+secs; + }, + + updateTimers: function() { + for (var i in this.threadTimers) { + if (this.threadTimers[i] != null) { + var value = this.threadTimers[i]; + var row = CommonUtils.getRow("thr"+i, this.t); + if( row != null ) { + function setcell(_table, row,id,pcontent) { + var cell = CommonUtils.getCell( id, row, _table ); + if( cell ) + cell.innerHTML = pcontent; + } + setcell(this.t, row,"time",this.getTimeSince(value[0])); + setcell(this.t, row,"wait",(value[2]!='chat' ? this.getTimeSince(value[1]) : '-')); + } + } + } + }, + + updateContent: function(xmldoc) { + var root = xmldoc.documentElement; + var newAdded = false; + if( root.tagName == 'threads' ) { + var _time = NodeUtils.getAttrValue(root, "time"); + var _revision = NodeUtils.getAttrValue(root, "revision" ); + + if( _time ) + this.delta = (new Date()).getTime() - _time; + if( _revision ) + this._options.lastrevision = _revision; + + for( var i = 0; i < root.childNodes.length; i++ ) { + var node = root.childNodes[i]; + if( node.tagName == 'thread' ) + if( this.updateThread(node) ) + newAdded = true; + } + this.updateQueueMessages(); + this.updateTimers(); + this.setStatus( "Up to date" ); + if( newAdded ) + window.focus(); + } else if( root.tagName == 'error' ) { + this.setStatus( "error: " + NodeUtils.getNodeValue(root,"descr") ); + } else { + this.setStatus( "wrong response" ); + } + } +}); + +var webimRoot = ""; + +EventHelper.register(window, 'onload', function(){ + webimRoot = updaterOptions.wroot; + new Ajax.ThreadListUpdater(({table:$("threadlist"),status:$("connstatus")}).extend(updaterOptions || {})); +}); +