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 '';
+ },
+
+ 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, '', 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 || {}));
+});
+