mirror of
				https://github.com/Mibew/mibew.git
				synced 2025-10-26 00:06:55 +03:00 
			
		
		
		
	Completely rewrite User's JavaScript application
This commit is contained in:
		
							parent
							
								
									d2531a526d
								
							
						
					
					
						commit
						6b9f2bd789
					
				| @ -16,6 +16,7 @@ | ||||
| 
 | ||||
|         default_app_js - Build JavaScript files related to default application | ||||
|         chat_app_js - Build JavaScript files related to chat application | ||||
|         users_app_js - Build JavaScript files related to users application | ||||
| 
 | ||||
|         core_handlebars - Compile Handlebars templates of the Core | ||||
| 
 | ||||
| @ -263,6 +264,14 @@ | ||||
|         <echo>Chat JavaScript application built.</echo> | ||||
|     </target> | ||||
| 
 | ||||
|     <!-- Compile and concatenate JavaScript files related to users application --> | ||||
|     <target name="users_app_js" depends="default_app_js"> | ||||
|         <antcall target="app_js"> | ||||
|             <param name="app_name" value="users" /> | ||||
|         </antcall> | ||||
|         <echo>Users JavaScript application built.</echo> | ||||
|     </target> | ||||
| 
 | ||||
|     <!-- Compile Handlebars templates of the Core --> | ||||
|     <target name="core_handlebars"> | ||||
|         <echo>Compile Handlebars templates of the Core</echo> | ||||
| @ -292,7 +301,7 @@ | ||||
|     </target> | ||||
| 
 | ||||
|     <!-- Build all project --> | ||||
|     <target name="all" depends="core_handlebars,chat_app_js,styles_all"> | ||||
|     <target name="all" depends="chat_app_js,users_app_js,styles_all"> | ||||
|         <echo>Mibew Messenger built.</echo> | ||||
|     </target> | ||||
| 
 | ||||
|  | ||||
| @ -86,6 +86,10 @@ a { | ||||
| 	height:40px; | ||||
| } | ||||
| 
 | ||||
| .inline-block { | ||||
| 	display: inline-block; | ||||
| } | ||||
| 
 | ||||
| #footer { | ||||
| 	background: white url(images/footer.gif) bottom repeat-x; | ||||
| 	font-size:11px; | ||||
| @ -557,8 +561,11 @@ table.awaiting td.visitor { | ||||
| 	border-bottom: 1px solid #ccc; | ||||
| 	padding: 10px 8px; | ||||
| 	margin: 0px; | ||||
|         text-align: center; | ||||
| } | ||||
| table.awaiting .no-threads, table.awaiting .no-visitors  { | ||||
|     height: 30px; | ||||
| } | ||||
| 
 | ||||
| .awaiting .visitor a { color: #296685; } | ||||
| .awaiting tr:hover .visitor, .awaiting tr:hover .visitor a { color: #1D485E; } | ||||
| 
 | ||||
| @ -571,27 +578,26 @@ table.awaiting td.visitor { | ||||
| .awaiting tr.inchat:hover .visitor, .awaiting tr.inchat:hover .visitor a { color: #444; }  | ||||
| .awaiting tr.inchat a { text-decoration: none; } | ||||
| 
 | ||||
| .firstmessage { | ||||
| .first-message { | ||||
| 	text-align: right; | ||||
| 	font-size: 0.8em; | ||||
| 	padding-right: 10px; | ||||
| } | ||||
| 
 | ||||
| .firstmessage a { | ||||
| .first-message a { | ||||
| 	text-decoration: none; | ||||
| } | ||||
| 
 | ||||
| .firstmessage a:hover { | ||||
| .first-message a:hover { | ||||
| 	text-decoration: underline; | ||||
| } | ||||
| 
 | ||||
| #status-panel-region { | ||||
|     margin: 10px; | ||||
| } | ||||
| 
 | ||||
| #connstatus { | ||||
| 	float:right; | ||||
| 	margin: 10px 10px; | ||||
| } | ||||
| 
 | ||||
| #connlinks { | ||||
| 	margin: 10px 10px; | ||||
| } | ||||
| 
 | ||||
| #connlinks a { | ||||
| @ -603,12 +609,64 @@ table.awaiting td.visitor { | ||||
| 	text-decoration: underline; | ||||
| } | ||||
| 
 | ||||
| .default-thread-controls { | ||||
| 	width: 100px; | ||||
| } | ||||
| 
 | ||||
| .default-visitor-controls { | ||||
| 	width: 20px; | ||||
| } | ||||
| 
 | ||||
| .default-thread-controls .control, | ||||
| .default-visitor-controls .control { | ||||
| 	height: 15px; | ||||
| 	width: 15px; | ||||
| 	margin: 0 2px; | ||||
| 	border: none; | ||||
| 	cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| .open-control { | ||||
| 	background: no-repeat top left url('images/tbliclspeak.gif'); | ||||
| } | ||||
| 
 | ||||
| .view-control { | ||||
| 	background: no-repeat top left url('images/tbliclread.gif'); | ||||
| } | ||||
| 
 | ||||
| .track-control { | ||||
| 	background: no-repeat top left url('images/tblictrack.gif'); | ||||
| } | ||||
| 
 | ||||
| .ban-control { | ||||
| 	background: no-repeat top left url('images/ban.gif'); | ||||
| } | ||||
| 
 | ||||
| #sound-region { | ||||
| 	display: none; | ||||
| } | ||||
| 
 | ||||
| /* online operators */ | ||||
| 
 | ||||
| #onlineoperators { | ||||
| #agents-region { | ||||
| 	padding-right: 10px; | ||||
| 	float: right; | ||||
| } | ||||
| .agent-status-away, .agent-status-online { | ||||
| 	display: inline-block; | ||||
| 	height: 12px; | ||||
| 	width: 12px; | ||||
| 	border: none; | ||||
| 	background-repeat: no-repeat; | ||||
|         margin-left: 5px; | ||||
|         margin-right: 2px; | ||||
| } | ||||
| .agent-status-away { | ||||
| 	background-image: url("images/opaway.gif"); | ||||
| } | ||||
| .agent-status-online { | ||||
| 	background-image: url("images/oponline.gif"); | ||||
| } | ||||
| 
 | ||||
| /* search */ | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										21
									
								
								src/messenger/webim/default_ie.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/messenger/webim/default_ie.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| /* | ||||
|   This file is part of Mibew Messenger project. | ||||
| 
 | ||||
|   Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|   All rights reserved. The contents of this file are subject to the terms of | ||||
|   the Eclipse Public License v1.0 which accompanies this distribution, and | ||||
|   is available at http://www.eclipse.org/legal/epl-v10.html | ||||
| 
 | ||||
|   Alternatively, the contents of this file may be used under the terms of | ||||
|   the GNU General Public License Version 2 or later (the "GPL"), in which case | ||||
|   the provisions of the GPL are applicable instead of those above. If you wish | ||||
|   to allow use of your version of this file only under the terms of the GPL, and | ||||
|   not to allow others to use your version of this file under the terms of the | ||||
|   EPL, indicate your decision by deleting the provisions above and replace them | ||||
|   with the notice and other provisions required by the GPL. | ||||
| */ | ||||
| 
 | ||||
| .inline-block { | ||||
|     display: inline; | ||||
|     zoom: 1; | ||||
| } | ||||
| @ -1,35 +0,0 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| Ajax.PeriodicalUpdater=Class.create(); | ||||
| Class.inherit(Ajax.PeriodicalUpdater,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.frequency=this._options.frequency||2;this.updater={};this.update()},handleException:function(){this._options.handleError&&this._options.handleError("offline, reconnecting");this.stopUpdate();this.timer=setTimeout(this.update.bind(this), | ||||
| 1E3)},handleTimeout:function(){this._options.handleError&&this._options.handleError("timeout, reconnecting");this.stopUpdate();this.timer=setTimeout(this.update.bind(this),1E3)},stopUpdate:function(){this.updater._options&&(this.updater._options.onComplete=void 0);clearTimeout(this.timer)},update:function(){this._options.updateParams&&(this._options.parameters=this._options.updateParams());this.updater=new Ajax.Request(this._options.url,this._options)},requestComplete:function(a){try{var b=Ajax.getXml(a); | ||||
| b?(this._options.updateContent||Ajax.emptyFunction)(b):this._options.handleError&&this._options.handleError("reconnecting")}catch(c){}this.timer=setTimeout(this.update.bind(this),1E3*this.frequency)}}); | ||||
| var HtmlGenerationUtils={popupLink:function(a,b,c,d,h,f,e){return'<a href="'+a+'"'+(null!=e?' class="'+e+'"':"")+' target="_blank" title="'+b+'" onclick="this.newWindow = window.open(\''+a+"', '"+c+"', 'toolbar=0,scrollbars=0,location=0,status=1,menubar=0,width="+h+",height="+f+",resizable=1');this.newWindow.focus();this.newWindow.opener=window;return false;\">"+d+"</a>"},generateOneRowTable:function(a){return'<table class="inner"><tr>'+a+"</tr></table>"},viewOpenCell:function(a,b,c,d,h,f,e,m){b= | ||||
| b+"?thread="+c;f="<td>";f=h||d?f+HtmlGenerationUtils.popupLink(m||!d?b:b+"&viewonly=true",localized[h?0:1],"ImCenter"+c,a,640,480,null):f+('<a href="#">'+a+"</a>");f+="</td>";""!=e&&(f=f+('</tr><tr><td class="firstmessage" colspan="2"><a href="javascript:void(0)" title="'+e+'" onclick="alert(this.title);return false;">')+(30<e.length?e.substring(0,30)+"...":e),f+="</a></td>");return HtmlGenerationUtils.generateOneRowTable(f)},viewActionsCell:function(a,b,c,d,h,f){a=a+"?thread="+b;var e="";d&&(e=e+ | ||||
| '<td class="icon">'+HtmlGenerationUtils.popupLink(a,localized[0],"ImCenter"+b,'<img src="'+webimRoot+'/images/tbliclspeak.gif" width="15" height="15" border="0" alt="'+localized[0]+'">',640,480,null),e+="</td>");c&&(e+='<td class="icon">',e+=HtmlGenerationUtils.popupLink(a+"&viewonly=true",localized[1],"ImCenter"+b,'<img src="'+webimRoot+'/images/tbliclread.gif" width="15" height="15" border="0" alt="'+localized[1]+'">',640,480,null),e+="</td>");h&&(e+='<td class="icon">',e+=HtmlGenerationUtils.popupLink(f+ | ||||
| "?thread="+b,localized[6],"ImTracked"+b,'<img src="'+webimRoot+'/images/tblictrack.gif" width="15" height="15" border="0" alt="'+localized[6]+'">',640,480,null),e+="</td>");return e},banCell:function(a,b){return'<td class="icon">'+HtmlGenerationUtils.popupLink(webimRoot+"/operator/ban.php?"+(b?"id="+b:"thread="+a),localized[2],"ban"+a,'<img src="'+webimRoot+'/images/ban.gif" width="15" height="15" border="0" alt="'+localized[2]+'">',720,480,null)+"</td>"},viewVisOpenCell:function(a,b,c,d,h){var f= | ||||
| "<td>",f=h?f+HtmlGenerationUtils.popupLink(b+"?visitor="+c,localized[7],"ImCenter"+c,a,640,480,null):f+('<a href="#">'+a+"</a>"),f=f+'</td><td class="icon">';a=HtmlGenerationUtils.popupLink(d+"?visitor="+c,localized[6],"ImTracked"+c,'<img src="'+webimRoot+'/images/tblictrack.gif" width="15" height="15" border="0" alt="'+localized[6]+'">',640,480,null);a=a.replace("scrollbars=0","scrollbars=1");f+=a;f+="</td>";return HtmlGenerationUtils.generateOneRowTable(f)}};Ajax.ThreadListUpdater=Class.create(); | ||||
| Class.inherit(Ajax.ThreadListUpdater,Ajax.Base,{initialize:function(a){this.setOptions(a);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={};this.delta=0;this.t=this._options.table;this.t2=this._options.visitors_table;this.periodicalUpdater=new Ajax.PeriodicalUpdater(this._options);this.old_visitors={};this.visitors={};this.visitorTimers= | ||||
| {}},updateParams:function(){return"since="+this._options.lastrevision+"&status="+this._options.istatus+(this._options.showonline?"&showonline=1":"")+(this._options.showvisitors?"&showvisitors=1":"")},setStatus:function(a){this._options.status.innerHTML=a},handleError:function(a){this.setStatus(a)},updateThread:function(a){function b(a,b,d,c){if(a=CommonUtils.getCell(d,b,a))a.innerHTML=c}for(var c,d,h,f=!1,e=!1,m=!1,n=null,p=null,g=0;g<a.attributes.length;g++){var j=a.attributes[g];"id"==j.nodeName? | ||||
| c=j.nodeValue:"stateid"==j.nodeName?d=j.nodeValue:"state"==j.nodeName?h=j.nodeValue:"canopen"==j.nodeName?e=!0:"canview"==j.nodeName?f=!0:"canban"==j.nodeName?m=!0:"ban"==j.nodeName?n=j.nodeValue:"banid"==j.nodeName&&(p=j.nodeValue)}g=CommonUtils.getRow("thr"+c,this.t);if("closed"==d)g&&this.t.deleteRow(g.rowIndex),this.threadTimers[c]=null;else{var j=NodeUtils.getNodeValue(a,"name"),k=HtmlGenerationUtils.viewActionsCell(this._options.agentservl,c,f,e,this._options.showvisitors,this._options.trackedservl), | ||||
| l=NodeUtils.getNodeValue(a,"addr"),r=NodeUtils.getNodeValue(a,"time"),t=NodeUtils.getNodeValue(a,"agent"),s=NodeUtils.getNodeValue(a,"modified"),u=NodeUtils.getNodeValue(a,"message"),q="<td>"+NodeUtils.getNodeValue(a,"useragent")+"</td>";null!=n&&(q="<td>"+NodeUtils.getNodeValue(a,"reason")+"</td>");m&&(k+=HtmlGenerationUtils.banCell(c,p));k=HtmlGenerationUtils.generateOneRowTable(k);q=HtmlGenerationUtils.generateOneRowTable(q);a=CommonUtils.getRow("t"+d,this.t);m=CommonUtils.getRow("t"+d+"end",this.t); | ||||
| if(null!=g&&(g.rowIndex<=a.rowIndex||g.rowIndex>=m.rowIndex))this.t.deleteRow(g.rowIndex),g=this.threadTimers[c]=null;if(null==g){if(g=this.t.insertRow(a.rowIndex+1),g.className="blocked"==n&&"chat"!=d?"ban":"in"+d,g.id="thr"+c,this.threadTimers[c]=[r,s,d],CommonUtils.insertCell(g,"name","visitor",null,null,HtmlGenerationUtils.viewOpenCell(j,this._options.agentservl,c,f,e,n,u,"chat"!=d,this._options.showvisitors,this._options.trackedservl)),CommonUtils.insertCell(g,"actions","visitor","center",null, | ||||
| k),CommonUtils.insertCell(g,"contid","visitor","center",null,l),CommonUtils.insertCell(g,"state","visitor","center",null,h),CommonUtils.insertCell(g,"op","visitor","center",null,t),CommonUtils.insertCell(g,"time","visitor","center",null,this.getTimeSince(r)),CommonUtils.insertCell(g,"wait","visitor","center",null,"chat"!=d?this.getTimeSince(s):"-"),CommonUtils.insertCell(g,"etc","visitor","center",null,q),"wait"==d||"prio"==d)return!0}else this.threadTimers[c]=[r,s,d],g.className="blocked"==n&&"chat"!= | ||||
| d?"ban":"in"+d,b(this.t,g,"name",HtmlGenerationUtils.viewOpenCell(j,this._options.agentservl,c,f,e,n,u,"chat"!=d,this._options.showvisitors,this._options.trackedservl)),b(this.t,g,"actions",k),b(this.t,g,"contid",l),b(this.t,g,"state",h),b(this.t,g,"op",t),b(this.t,g,"time",this.getTimeSince(r)),b(this.t,g,"wait","chat"!=d?this.getTimeSince(s):"-"),b(this.t,g,"etc",q);return!1}},updateQueueMessages:function(){function a(a,b){var c=$(b),e=$(b+"end");return null==c||null==e?!1:c.rowIndex+1<e.rowIndex} | ||||
| var b=$("statustd");if(b){var c=a(this.t,"twait")||a(this.t,"tprio")||a(this.t,"tchat");b.innerHTML=c?"":this._options.noclients;b.height=c?5:30}},getTimeSince:function(a){a=Math.floor(((new Date).getTime()-a-this.delta)/1E3);var b=Math.floor(a/60),c="";a%=60;10>a&&(a="0"+a);60<=b&&(c=Math.floor(b/60),b%=60,10>b&&(b="0"+b),c+=":");return c+b+":"+a},updateTimers:function(){for(var a in this.threadTimers)if(null!=this.threadTimers[a]){var b=this.threadTimers[a],c=CommonUtils.getRow("thr"+a,this.t); | ||||
| if(null!=c){var d=this.getTimeSince(b[0]),h=CommonUtils.getCell("time",c,this.t);h&&(h.innerHTML=d);b="chat"!=b[2]?this.getTimeSince(b[1]):"-";if(c=CommonUtils.getCell("wait",c,this.t))c.innerHTML=b}}},updateThreads:function(a){var b=!1,c=NodeUtils.getAttrValue(a,"time"),d=NodeUtils.getAttrValue(a,"revision");c&&(this.delta=(new Date).getTime()-c);d&&(this._options.lastrevision=d);for(c=0;c<a.childNodes.length;c++)d=a.childNodes[c],"thread"==d.tagName&&this.updateThread(d)&&(b=!0);this.updateQueueMessages(); | ||||
| this.updateTimers();this.setStatus(this._options.istatus?localized[8]:localized[9]);b&&(playSound(webimRoot+"/sounds/new_user.wav"),window.focus(),updaterOptions.showpopup&&alert(localized[5]))},updateOperators:function(a){var b=$("onlineoperators");if(b){for(var c=[],d=0;d<a.childNodes.length;d++){var h=a.childNodes[d];if("operator"==h.tagName){var f=NodeUtils.getAttrValue(h,"name"),h=null!=NodeUtils.getAttrValue(h,"away");c[c.length]='<img src="'+webimRoot+"/images/op"+(h?"away":"online")+'.gif" width="12" height="12" border="0" alt="'+ | ||||
| localized[1]+'"> '+f}}b.innerHTML=c.join(", ")}},updateVisitorsTimers:function(){for(var a in this.visitorTimers)if(null!=this.visitorTimers[a]){var b=this.visitorTimers[a],c=CommonUtils.getRow("vis"+a,this.t2);if(null!=c){var d=function(a,b,c,d){if(a=CommonUtils.getCell(c,b,a))a.innerHTML=d};d(this.t2,c,"time",this.getTimeSince(b[0]));d(this.t2,c,"modified",this.getTimeSince(b[1]));null!=b[2]&&d(this.t2,c,"invitationtime",this.getTimeSince(b[2]))}}},updateVisitor:function(a){function b(a,b,c,d){if(a= | ||||
| CommonUtils.getCell(c,b,a))a.innerHTML=d}for(var c,d=0;d<a.attributes.length;d++){var h=a.attributes[d];"id"==h.nodeName&&(c=h.nodeValue)}var h=NodeUtils.getNodeValue(a,"addr"),f=NodeUtils.getNodeValue(a,"username"),e=NodeUtils.getNodeValue(a,"useragent"),m=NodeUtils.getNodeValue(a,"time"),n=NodeUtils.getNodeValue(a,"modified"),p=NodeUtils.getNodeValue(a,"invitations"),g=NodeUtils.getNodeValue(a,"chats"),j=null,k=null;a=a.getElementsByTagName("invitation")[0];for(d=0;d<a.childNodes.length;d++){var l= | ||||
| a.childNodes[d];"operator"==l.tagName?j=l.firstChild.nodeValue:"invitationtime"==l.tagName&&(k=l.firstChild.nodeValue)}l=null==j?"free":"invited";d=CommonUtils.getRow("vis"+c,this.t2);a=CommonUtils.getRow("vis"+l,this.t2);l=CommonUtils.getRow("vis"+l+"end",this.t2);if(null!=d&&(d.rowIndex<=a.rowIndex||d.rowIndex>=l.rowIndex))this.t2.deleteRow(d.rowIndex),d=this.visitorTimers[c]=null;null==d?(d=this.t2.insertRow(a.rowIndex+1),d.id="vis"+c,this.visitorTimers[c]=[m,n,k],CommonUtils.insertCell(d,"username", | ||||
| "visitor",null,null,HtmlGenerationUtils.viewVisOpenCell(f,this._options.inviteservl,c,this._options.trackedservl,null==j)),CommonUtils.insertCell(d,"addr","visitor","center",null,h),CommonUtils.insertCell(d,"time","visitor","center",null,this.getTimeSince(m)),CommonUtils.insertCell(d,"modified","visitor","center",null,this.getTimeSince(n)),CommonUtils.insertCell(d,"operator","visitor","center",null,null!=j?j:"-"),CommonUtils.insertCell(d,"invitationtime","visitor","center",null,null!=j?this.getTimeSince(k): | ||||
| "-"),CommonUtils.insertCell(d,"invitations","visitor","center",null,p+" / "+g),CommonUtils.insertCell(d,"useragent","visitor","center",null,e)):(this.visitorTimers[c]=[m,n,k],b(this.t2,d,"username",HtmlGenerationUtils.viewVisOpenCell(f,this._options.inviteservl,c,this._options.trackedservl,null==j)),b(this.t2,d,"addr",h),b(this.t2,d,"operator",null!=j?j:"-"),b(this.t2,d,"time",this.getTimeSince(m)),b(this.t2,d,"modified",this.getTimeSince(n)),b(this.t2,d,"invitationtime",null!=j?this.getTimeSince(k): | ||||
| "-"),b(this.t2,d,"invitations",p+" / "+g),b(this.t2,d,"useragent",e));this.visitors[c]=1;return!1},removeOldVisitors:function(){for(id in this.old_visitors)if(void 0===this.visitors[id]){var a=CommonUtils.getRow("vis"+id,this.t2);a&&this.t2.deleteRow(a.rowIndex);this.visitorTimers[id]=null}},updateVisitorsList:function(a){var b=$("visstatustd");b&&(b.innerHTML=0<a?"":this._options.novisitors,b.height=0<a?5:30)},updateVisitors:function(a){this.old_visitors=this.visitors;this.visitors={};for(var b= | ||||
| 0,c=0;c<a.childNodes.length;c++){var d=a.childNodes[c];"visitor"==d.tagName&&(b++,this.updateVisitor(d))}this.updateVisitorsTimers();this.removeOldVisitors();this.updateVisitorsList(b)},updateContent:function(a){if("update"==a.tagName)for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];"threads"==c.tagName?this.updateThreads(c):"operators"==c.tagName?this.updateOperators(c):"visitors"==c.tagName&&this.updateVisitors(c)}else"error"==a.tagName?this.setStatus(NodeUtils.getNodeValue(a,"descr")): | ||||
| this.setStatus("reconnecting")}});function togglemenu(){$("sidebar")&&($("wcontent")&&$("togglemenu"))&&("contentnomenu"==$("wcontent").className?($("sidebar").style.display="block",$("wcontent").className="contentinner",$("togglemenu").innerHTML=localized[4]):($("sidebar").style.display="none",$("wcontent").className="contentnomenu",$("togglemenu").innerHTML=localized[3]))}var webimRoot="";Behaviour.register({"#togglemenu":function(a){a.onclick=function(){togglemenu()}}}); | ||||
| EventHelper.register(window,"onload",function(){webimRoot=updaterOptions.wroot;new Ajax.ThreadListUpdater({table:$("threadlist"),status:$("connstatus"),istatus:0,visitors_table:$("visitorslist")}.extend(updaterOptions||{}));updaterOptions.havemenu||togglemenu()}); | ||||
							
								
								
									
										10
									
								
								src/messenger/webim/js/compiled/users/app.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/messenger/webim/js/compiled/users/app.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(a,g,h){var b=new g.Marionette.Application;b.addRegions({agentsRegion:"#agents-region",statusPanelRegion:"#status-panel-region",threadsRegion:"#threads-region",visitorsRegion:"#visitors-region",soundRegion:"#sound-region"});b.addInitializer(function(e){var f=a.Objects,c=a.Objects.Models,d=a.Objects.Collections;f.server=new a.Server(h.extend({interactionType:MibewAPIUsersInteraction},e.server));c.page=new a.Models.Page(e.page);c.agent=new a.Models.Agent(e.agent);d.threads=new a.Collections.Threads; | ||||
| b.threadsRegion.show(new a.Views.ThreadsCollection({collection:d.threads}));e.page.showOnlineOperators&&(d.visitors=new a.Collections.Visitors,b.visitorsRegion.show(new a.Views.VisitorsCollection({collection:d.visitors})));c.statusPanel=new a.Models.StatusPanel;b.statusPanelRegion.show(new a.Views.StatusPanel({model:c.statusPanel}));e.page.showOnlineOperators&&(d.agents=new a.Collections.Agents,b.agentsRegion.show(new a.Views.AgentsCollection({collection:d.agents})));c.sound=new a.Models.Sound;b.soundRegion.show(new a.Views.Sound({model:c.sound})); | ||||
| f.server.callFunctionsPeriodically(function(){return[{"function":"update",arguments:{"return":{},references:{},agentId:c.agent.id}}]},function(){})});b.on("start",function(){a.Objects.server.runUpdater()});a.Application=b})(Mibew,Backbone,_); | ||||
| @ -0,0 +1,8 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(a){a.Views.AgentsCollection=a.Views.CollectionBase.extend({itemView:a.Views.Agent,className:"agents-collection",collectionEvents:{"sort add remove reset":"render"},initialize:function(){this.on("itemview:before:render",this.updateIndexes,this)},updateIndexes:function(a){var b=this.collection,c=a.model;c&&(a.isModelFirst=0==b.indexOf(c),a.isModelLast=b.indexOf(c)==b.length-1)}})})(Mibew); | ||||
| @ -0,0 +1,11 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(d,h,j,k){d.Views.ThreadsCollection=h.Marionette.CompositeView.extend({template:j.templates.threads_collection,itemView:d.Views.QueuedThread,itemViewContainer:"#threads-container",emptyView:d.Views.NoThreads,className:"threads-collection",collectionEvents:{sort:"renderCollection","sort:field":"createSortField",add:"threadAdded"},itemViewOptions:function(a){return{tagName:d.Objects.Models.page.get("threadTag"),collection:a.get("controls")}},initialize:function(){window.setInterval(k.bind(this.renderCollection, | ||||
| this),2E3);this.on("itemview:before:render",this.updateStyles,this)},updateStyles:function(a){var b=this.collection,c=a.model,d=this;if(c.id){var e=this.getQueueCode(c),f=!1,g=!1,b=b.filter(function(a){return d.getQueueCode(a)==e});0<b.length&&(g=b[0].id==c.id,f=b[b.length-1].id==c.id);if(0<a.lastStyles.length){c=0;for(b=a.lastStyles.length;c<b;c++)a.$el.removeClass(a.lastStyles[c]);a.lastStyles=[]}c=(e!=this.QUEUE_BAN?"in":"")+this.queueCodeToString(e);a.lastStyles.push(c);g&&a.lastStyles.push(c+ | ||||
| "-first");f&&a.lastStyles.push(c+"-last");c=0;for(b=a.lastStyles.length;c<b;c++)a.$el.addClass(a.lastStyles[c])}},createSortField:function(a,b){var c=this.getQueueCode(a)||"Z";b.field=c.toString()+"_"+a.get("waitingTime").toString()},threadAdded:function(){var a=d.Objects.Models.page.get("webimRoot");a&&d.Objects.Models.sound.play(a+"/sounds/new_user.wav")},getQueueCode:function(a){var b=a.get("state");return!1!=a.get("ban")&&b!=a.STATE_CHATTING?this.QUEUE_BAN:b==a.STATE_QUEUE||b==a.STATE_LOADING? | ||||
| this.QUEUE_WAITING:b==a.STATE_CLOSED||b==a.STATE_LEFT?this.QUEUE_CLOSED:b==a.STATE_WAITING?this.QUEUE_PRIO:b==a.STATE_CHATTING?this.QUEUE_CHATTING:!1},queueCodeToString:function(a){return a==this.QUEUE_PRIO?"prio":a==this.QUEUE_WAITING?"wait":a==this.QUEUE_CHATTING?"chat":a==this.QUEUE_BAN?"ban":a==this.QUEUE_CLOSED?"closed":""},QUEUE_PRIO:1,QUEUE_WAITING:2,QUEUE_CHATTING:3,QUEUE_BAN:4,QUEUE_CLOSED:5})})(Mibew,Backbone,Handlebars,_); | ||||
| @ -0,0 +1,9 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(a,b,c,d){a.Views.VisitorsCollection=b.Marionette.CompositeView.extend({template:c.templates.visitors_collection,itemView:a.Views.Visitor,itemViewContainer:"#visitors-container",emptyView:a.Views.NoVisitors,className:"visitors-collection",collectionEvents:{sort:"renderCollection"},itemViewOptions:function(b){return{tagName:a.Objects.Models.page.get("visitorTag"),collection:b.get("controls")}},initialize:function(){window.setInterval(d.bind(this.renderCollection,this),2E3);this.on("itemview:before:render", | ||||
| this.updateStyles,this)}})})(Mibew,Backbone,Handlebars,_); | ||||
| @ -0,0 +1,8 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(b,c,d){b.Collections.Agents=c.Collection.extend({model:b.Models.Agent,comparator:function(a){return a.get("name")},initialize:function(){var a=b.Objects.Models.agent;b.Objects.server.callFunctionsPeriodically(function(){return[{"function":"updateOperators",arguments:{agentId:a.id,"return":{operators:"operators"},references:{}}}]},d.bind(this.updateOperators,this))},updateOperators:function(a){this.update(a.operators)}})})(Mibew,Backbone,_); | ||||
							
								
								
									
										10
									
								
								src/messenger/webim/js/compiled/users/collections/threads.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/messenger/webim/js/compiled/users/collections/threads.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(c,e,f){c.Collections.Threads=e.Collection.extend({model:c.Models.QueuedThread,initialize:function(){this.revision=0;var a=this,b=c.Objects.Models.agent;c.Objects.server.callFunctionsPeriodically(function(){return[{"function":"currentTime",arguments:{agentId:b.id,"return":{time:"currentTime"},references:{}}},{"function":"updateThreads",arguments:{agentId:b.id,revision:a.revision,"return":{threads:"threads",lastRevision:"lastRevision"},references:{}}}]},f.bind(this.updateThreads,this))},comparator:function(a){var b= | ||||
| {field:a.get("waitingTime").toString()};this.trigger("sort:field",a,b);return b.field},updateThreads:function(a){if(0==a.errorCode){if(0<a.threads.length){var b;b=a.currentTime?Math.round((new Date).getTime()/1E3)-a.currentTime:0;for(var d=0,e=a.threads.length;d<e;d++)a.threads[d].totalTime=parseInt(a.threads[d].totalTime)+b,a.threads[d].waitingTime=parseInt(a.threads[d].waitingTime)+b;this.trigger("before:update:threads",a.threads);var f=c.Models.Thread.prototype.STATE_CLOSED,g=c.Models.Thread.prototype.STATE_LEFT; | ||||
| b=[];this.update(a.threads,{remove:!1,sort:!1});b=this.filter(function(a){return a.get("state")==f||a.get("state")==g});0<b.length&&this.remove(b);this.sort();this.trigger("after:update:threads")}this.revision=a.lastRevision}}})})(Mibew,Backbone,_); | ||||
| @ -0,0 +1,9 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(b,e,f){b.Collections.Visitors=e.Collection.extend({model:b.Models.Visitor,initialize:function(){var a=b.Objects.Models.agent;b.Objects.server.callFunctionsPeriodically(function(){return[{"function":"currentTime",arguments:{agentId:a.id,"return":{time:"currentTime"},references:{}}},{"function":"updateVisitors",arguments:{agentId:a.id,"return":{visitors:"visitors"},references:{}}}]},f.bind(this.updateVisitors,this))},comparator:function(a){var c={field:a.get("firstTime").toString()};this.trigger("sort:field", | ||||
| a,c);return c.field},updateVisitors:function(a){if(0==a.errorCode){var c;c=a.currentTime?Math.round((new Date).getTime()/1E3)-a.currentTime:0;for(var d=0,b=a.visitors.length;d<b;d++)a.visitors[d].lastTime=parseInt(a.visitors[d].lastTime)+c,a.visitors[d].firstTime=parseInt(a.visitors[d].firstTime)+c;this.trigger("before:update:visitors",a.visitors);this.update(a.visitors);this.trigger("after:update:visitors")}}})})(Mibew,Backbone,_); | ||||
| @ -0,0 +1,8 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(e){e.registerHelper("formatTimeSince",function(b){var a=Math.round((new Date).getTime()/1E3)-b;b=a%60;var d=Math.floor(a/60)%60,a=Math.floor(a/3600),c=[];0<a&&c.push(a);c.push(10>d?"0"+d:d);c.push(10>b?"0"+b:b);return c.join(":")})})(Handlebars); | ||||
							
								
								
									
										8
									
								
								src/messenger/webim/js/compiled/users/init.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/messenger/webim/js/compiled/users/init.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(a){a.Regions={};a.Popup={};a.Popup.open=function(b,a,c){b=window.open(b,a,c);b.focus();b.opener=window}})(Mibew); | ||||
| @ -0,0 +1,8 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| MibewAPIUsersInteraction=function(){this.obligatoryArguments={"*":{agentId:null,"return":{},references:{}},result:{errorCode:0}};this.reservedFunctionNames=["result"]};MibewAPIUsersInteraction.prototype=new MibewAPIInteraction; | ||||
| @ -0,0 +1,8 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(b,c,d){b.Views.Agent=c.Marionette.ItemView.extend({template:d.templates.agent,tagName:"span",className:"agent",modelEvents:{change:"render"},initialize:function(){this.isModelLast=this.isModelFirst=!1},serializeData:function(){var a=this.model.toJSON();a.isFirst=this.isModelFirst;a.isLast=this.isModelLast;return a}})})(Mibew,Backbone,Handlebars); | ||||
| @ -0,0 +1,8 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(a,b,c){a.Views.NoThreads=b.Marionette.ItemView.extend({template:c.templates.no_threads,initialize:function(a){this.tagName=a.tagName}})})(Mibew,Backbone,Handlebars); | ||||
| @ -0,0 +1,8 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(a,b,c){a.Views.NoVisitors=b.Marionette.ItemView.extend({template:c.templates.no_visitors,initialize:function(a){this.tagName=a.tagName}})})(Mibew,Backbone,Handlebars); | ||||
| @ -0,0 +1,12 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(d,e){d.Views.QueuedThread=d.Views.CompositeBase.extend({template:e.templates.queued_thread,itemView:d.Views.Control,itemViewContainer:".thread-controls",className:"thread",modelEvents:{change:"render"},events:{"click .open-dialog":"openDialog","click .view-control":"viewDialog","click .track-control":"showTrack","click .ban-control":"showBan","click .geo-link":"showGeoInfo","click .first-message a":"showFirstMessage"},initialize:function(){this.lastStyles=[]},serializeData:function(){var a= | ||||
| this.model,b=d.Objects.Models.page,c=a.toJSON();c.stateDesc=this.stateToDesc(a.get("state"));c.chatting=a.get("state")==a.STATE_CHATTING;c.tracked=b.get("showVisitors");c.firstMessage&&(c.firstMessagePreview=30<c.firstMessage.length?c.firstMessage.substring(0,30)+"...":c.firstMessage);return c},stateToDesc:function(a){var b=d.Localization;return a==this.model.STATE_QUEUE?b.get("chat.thread.state_wait"):a==this.model.STATE_WAITING?b.get("chat.thread.state_wait_for_another_agent"):a==this.model.STATE_CHATTING? | ||||
| b.get("chat.thread.state_chatting_with_agent"):a==this.model.STATE_CLOSED?b.get("chat.thread.state_closed"):a==this.model.STATE_LOADING?b.get("chat.thread.state_loading"):""},showGeoInfo:function(){var a=this.model.get("userIp");if(a){var b=d.Objects.Models.page,c=b.get("geoLink").replace("{ip}",a);d.Popup.open(c,"ip"+a,b.get("geoWindowParams"))}},openDialog:function(){var a=this.model,a=a.get("state")==a.STATE_CHATTING&&a.get("canView");this.showDialogWindow(a)},viewDialog:function(){this.showDialogWindow(!0)}, | ||||
| showDialogWindow:function(a){var b=this.model.id,c=d.Objects.Models.page;d.Popup.open(c.get("agentLink")+"?thread="+b+(a?"&viewonly=true":""),"ImCenter"+b,c.get("chatWindowParams"))},showTrack:function(){var a=this.model.id,b=d.Objects.Models.page;d.Popup.open(b.get("trackedLink")+"?thread="+a,"ImTracked"+a,b.get("trackedUserWindowParams"))},showBan:function(){var a=this.model,b=a.get("ban"),c=d.Objects.Models.page;d.Popup.open(c.get("banLink")+"?"+(!1!==b?"id="+b.id:"thread="+a.id),"ImBan"+b.id, | ||||
| c.get("banWindowParams"))},showFirstMessage:function(){var a=this.model.get("firstMessage");a&&alert(a)}})})(Mibew,Handlebars); | ||||
| @ -0,0 +1,8 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(a,c,d){a.Views.StatusPanel=c.Marionette.ItemView.extend({template:d.templates.status_panel,modelEvents:{change:"render"},ui:{changeStatus:"#change-status"},events:{"click #change-status":"changeAgentStatus"},initialize:function(){a.Objects.Models.agent.on("change",this.render,this)},changeAgentStatus:function(){this.model.changeAgentStatus()},serializeData:function(){var b=this.model.toJSON();b.agent=a.Objects.Models.agent.toJSON();return b}})})(Mibew,Backbone,Handlebars); | ||||
| @ -0,0 +1,9 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(a,d){a.Views.Visitor=a.Views.CompositeBase.extend({template:d.templates.visitor,itemView:a.Views.Control,itemViewContainer:".visitor-controls",className:"visitor",modelEvents:{change:"render"},events:{"click .invite-link":"inviteUser","click .geo-link":"showGeoInfo","click .track-control":"showTrack"},inviteUser:function(){if(!this.model.get("invitationInfo")){var b=this.model.id,c=a.Objects.Models.page;a.Popup.open(c.get("inviteLink")+"?visitor="+b,"ImCenter"+b,c.get("inviteWindowParams"))}}, | ||||
| showTrack:function(){var b=this.model.id,c=a.Objects.Models.page;a.Popup.open(c.get("trackedLink")+"?visitor="+b,"ImTracked"+b,c.get("trackedVisitorWindowParams"))},showGeoInfo:function(){var b=this.model.get("userIp");if(b){var c=a.Objects.Models.page,d=c.get("geoLink").replace("{ip}",b);a.Popup.open(d,"ip"+b,c.get("geoWindowParams"))}}})})(Mibew,Handlebars); | ||||
							
								
								
									
										8
									
								
								src/messenger/webim/js/compiled/users/models/agent.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/messenger/webim/js/compiled/users/models/agent.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(a,b){a.Models.Agent=a.Models.User.extend({defaults:b.extend({},a.Models.User.prototype.defaults,{id:null,isAgent:!0,away:!1}),away:function(){this.setAvailability(!1)},available:function(){this.setAvailability(!0)},setAvailability:function(c){var b=this;a.Objects.server.callFunctions([{"function":c?"available":"away",arguments:{agentId:this.id,references:{},"return":{}}}],function(a){0==a.errorCode&&b.set({away:!c})},!0)}})})(Mibew,_); | ||||
| @ -0,0 +1,9 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(a,c){var b=[],f=a.Models.QueuedThread=a.Models.Thread.extend({defaults:c.extend({},a.Models.Thread.prototype.defaults,{controls:null,userName:"",userIp:"",remote:"",userAgent:"",agentName:"",canOpen:!1,canView:!1,canBan:!1,ban:!1,totalTime:0,waitingTime:0,firstMessage:null}),initialize:function(){for(var e=[],b=f.getControls(),d=0,c=b.length;d<c;d++)e.push(new b[d]({thread:this}));this.set({controls:new a.Collections.Controls(e)})}},{addControl:function(a){b.push(a)},getControls:function(){return b}})})(Mibew, | ||||
| _); | ||||
| @ -0,0 +1,8 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(b){b.Models.StatusPanel=b.Models.Base.extend({defaults:{message:""},setStatus:function(a){this.set({message:a})},changeAgentStatus:function(){var a=b.Objects.Models.agent;a.get("away")?a.available():a.away()}})})(Mibew); | ||||
							
								
								
									
										8
									
								
								src/messenger/webim/js/compiled/users/models/visitor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/messenger/webim/js/compiled/users/models/visitor.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| /* | ||||
|  This file is part of Mibew Messenger project. | ||||
|  http://mibew.org
 | ||||
| 
 | ||||
|  Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  License: http://mibew.org/license.php
 | ||||
| */ | ||||
| (function(a,c){var b=[],f=a.Models.Visitor=a.Models.User.extend({defaults:c.extend({},a.Models.User.prototype.defaults,{controls:null,userName:"",userIp:"",remote:"",userAgent:"",firstTime:0,lastTime:0,invitations:0,chats:0,invitationInfo:!1}),initialize:function(){for(var e=[],b=f.getControls(),d=0,c=b.length;d<c;d++)e.push(new b[d]({visitor:this}));this.set({controls:new a.Collections.Controls(e)})}},{addControl:function(a){b.push(a)},getControls:function(){return b}})})(Mibew,_); | ||||
							
								
								
									
										41
									
								
								src/messenger/webim/js/compiled/users_app.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/messenger/webim/js/compiled/users_app.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -1,556 +0,0 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| 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._options.onTimeout = this.handleTimeout.bind(this); | ||||
|     this._options.timeout = 5000; | ||||
|     this.frequency = (this._options.frequency || 2); | ||||
|     this.updater = {}; | ||||
|     this.update(); | ||||
|   }, | ||||
| 
 | ||||
|   handleException: function(_request, ex) { | ||||
| 	if( this._options.handleError ) | ||||
| 	  this._options.handleError("offline, reconnecting"); | ||||
| 	this.stopUpdate(); | ||||
| 	this.timer = setTimeout(this.update.bind(this), 1000); | ||||
|   }, | ||||
| 
 | ||||
|   handleTimeout: function(_request) { | ||||
| 	if( this._options.handleError ) | ||||
| 	  this._options.handleError("timeout, reconnecting"); | ||||
| 	this.stopUpdate(); | ||||
| 	this.timer = setTimeout(this.update.bind(this), 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) { | ||||
|   	try { | ||||
| 		var xmlRoot = Ajax.getXml(presponse); | ||||
| 		if( xmlRoot ) { | ||||
| 	      (this._options.updateContent || Ajax.emptyFunction)( xmlRoot ); | ||||
| 		} else { | ||||
| 		    if( this._options.handleError ) | ||||
| 				this._options.handleError("reconnecting"); | ||||
| 		} | ||||
| 	} catch(e) { | ||||
| 	} | ||||
|     this.timer = setTimeout(this.update.bind(this), this.frequency * 1000); | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| var HtmlGenerationUtils = { | ||||
| 
 | ||||
|   popupLink: function(link, title, wndid, inner, width, height,linkclass) { | ||||
|   	return '<a href="'+link+'"'+(linkclass != null ? ' class="'+linkclass+'"' : '')+' target="_blank" title="'+title+'" onclick="this.newWindow = window.open(\''+link+'\', \''+ | ||||
|   			wndid+'\', \'toolbar=0,scrollbars=0,location=0,status=1,menubar=0,width='+width+',height='+height+',resizable=1\');this.newWindow.focus();this.newWindow.opener=window;return false;">'+ | ||||
|   			inner+'</a>'; | ||||
|   }, | ||||
| 
 | ||||
|   generateOneRowTable: function(content) { | ||||
|   	return '<table class="inner"><tr>' + content + '</tr></table>'; | ||||
|   }, | ||||
| 
 | ||||
|   viewOpenCell: function(username,servlet,id,canview,canopen,ban,message,cantakenow,tracked,trackedlink) { | ||||
|   		var link = servlet+"?thread="+id; | ||||
|  		var gen = '<td>'; | ||||
|  		if(canopen || canview ) { | ||||
| 			gen += HtmlGenerationUtils.popupLink( (cantakenow||!canview) ? link : link+"&viewonly=true", localized[canopen ? 0 : 1], "ImCenter"+id, username, 640, 480, null); | ||||
| 		} else { | ||||
| 			gen += '<a href="#">' + username + '</a>'; | ||||
| 		} | ||||
| 		gen += '</td>'; | ||||
| 		if( message != "" ) { | ||||
| 			gen += '</tr><tr><td class="firstmessage" colspan="2"><a href="javascript:void(0)" title="'+message+'" onclick="alert(this.title);return false;">'; | ||||
| 			gen += message.length > 30 ? message.substring(0,30) + '...' : message; | ||||
| 			gen += '</a></td>'; | ||||
| 		} | ||||
| 
 | ||||
|   		return HtmlGenerationUtils.generateOneRowTable(gen); | ||||
|   }, | ||||
|   viewActionsCell: function(servlet,id,canview,canopen,tracked,trackedlink) { | ||||
| 		var link = servlet+"?thread="+id; | ||||
| 		var gen = ''; | ||||
| 		if( canopen ) { | ||||
| 			gen += '<td class="icon">'; | ||||
| 			gen += HtmlGenerationUtils.popupLink( link, localized[0], "ImCenter"+id, '<img src="'+webimRoot+'/images/tbliclspeak.gif" width="15" height="15" border="0" alt="'+localized[0]+'">', 640, 480, null); | ||||
| 			gen += '</td>'; | ||||
| 		} | ||||
| 		if( canview ) { | ||||
| 			gen += '<td class="icon">'; | ||||
| 			gen += HtmlGenerationUtils.popupLink( link+"&viewonly=true", localized[1], "ImCenter"+id, '<img src="'+webimRoot+'/images/tbliclread.gif" width="15" height="15" border="0" alt="'+localized[1]+'">', 640, 480, null); | ||||
| 			gen += '</td>'; | ||||
| 		} | ||||
| 		if ( tracked ) { | ||||
| 			gen += '<td class="icon">'; | ||||
| 			gen += HtmlGenerationUtils.popupLink( trackedlink+"?thread="+id, localized[6], "ImTracked"+id, '<img src="'+webimRoot+'/images/tblictrack.gif" width="15" height="15" border="0" alt="'+localized[6]+'">', 640, 480, null); | ||||
| 			gen += '</td>'; | ||||
| 		} | ||||
|  		return gen; | ||||
|   }, | ||||
|   banCell: function(id,banid){ | ||||
|       return '<td class="icon">'+ | ||||
|           HtmlGenerationUtils.popupLink( webimRoot+'/operator/ban.php?'+(banid ? 'id='+banid : 'thread='+id), localized[2], "ban"+id, '<img src="'+webimRoot+'/images/ban.gif" width="15" height="15" border="0" alt="'+localized[2]+'">', 720, 480, null)+ | ||||
|           '</td>'; | ||||
|   }, | ||||
|   viewVisOpenCell: function(username, inviteservlet, userid, trackedservlet, caninvite) { | ||||
|   		var cellsCount = 2; | ||||
|  		var gen = '<td>'; | ||||
|  		if(caninvite) { | ||||
| 			gen += HtmlGenerationUtils.popupLink( inviteservlet+"?visitor="+userid, localized[7], "ImCenter"+userid, username, 640, 480, null); | ||||
| 		} else { | ||||
| 			gen += '<a href="#">' + username + '</a>'; | ||||
| 		} | ||||
| 		gen += '</td>'; | ||||
| 		gen += '<td class="icon">'; | ||||
| 		var tr_link = HtmlGenerationUtils.popupLink( trackedservlet+"?visitor="+userid, localized[6], "ImTracked"+userid, '<img src="'+webimRoot+'/images/tblictrack.gif" width="15" height="15" border="0" alt="'+localized[6]+'">', 640, 480, null); | ||||
| 		tr_link = tr_link.replace("scrollbars=0","scrollbars=1"); | ||||
| 		gen += tr_link; | ||||
| 		gen += '</td>'; | ||||
|   		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.t2 = this._options.visitors_table; | ||||
|     this.periodicalUpdater = new Ajax.PeriodicalUpdater(this._options); | ||||
|     this.old_visitors = new Object(); | ||||
|     this.visitors = new Object(); | ||||
|     this.visitorTimers = new Object(); | ||||
|   }, | ||||
| 
 | ||||
|   updateParams: function() { | ||||
|   	return "since=" + this._options.lastrevision + "&status=" + this._options.istatus + (this._options.showonline ? "&showonline=1" : "") + (this._options.showvisitors ? "&showvisitors=1" : ""); | ||||
|   }, | ||||
| 
 | ||||
|   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, canban = false, ban = null, banid = 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; | ||||
| 		else if( attr.nodeName == "canview" ) | ||||
| 			canview = true; | ||||
| 		else if( attr.nodeName == "canban" ) | ||||
| 			canban = true; | ||||
| 		else if( attr.nodeName == "ban" ) | ||||
| 			ban = attr.nodeValue; | ||||
| 		else if( attr.nodeName == "banid" ) | ||||
| 			banid = attr.nodeValue; | ||||
| 	} | ||||
| 
 | ||||
| 	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 ) { | ||||
| 			this.t.deleteRow(row.rowIndex); | ||||
| 		} | ||||
| 		this.threadTimers[id] = null; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	var vname = NodeUtils.getNodeValue(node,"name"); | ||||
| 	var actions = HtmlGenerationUtils.viewActionsCell(this._options.agentservl,id,canview,canopen,this._options.showvisitors, this._options.trackedservl); | ||||
| 	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 = '<td>'+NodeUtils.getNodeValue(node,"useragent")+'</td>'; | ||||
| 
 | ||||
| 	if(ban != null) { | ||||
| 		etc = '<td>'+NodeUtils.getNodeValue(node,"reason")+'</td>'; | ||||
| 	} | ||||
| 
 | ||||
| 	if(canban) { | ||||
| 		actions += HtmlGenerationUtils.banCell(id,banid); | ||||
| 	} | ||||
| 	actions = HtmlGenerationUtils.generateOneRowTable(actions); | ||||
| 	etc = HtmlGenerationUtils.generateOneRowTable(etc); | ||||
| 
 | ||||
| 	var startRow = CommonUtils.getRow("t"+stateid, this.t); | ||||
| 	var endRow = CommonUtils.getRow("t"+stateid+"end", this.t); | ||||
| 
 | ||||
| 	if( row != null && (row.rowIndex <= startRow.rowIndex || row.rowIndex >= endRow.rowIndex ) ) { | ||||
| 		this.t.deleteRow(row.rowIndex); | ||||
| 		this.threadTimers[id] = null; | ||||
| 		row = null; | ||||
| 	} | ||||
| 	if( row == null ) { | ||||
| 		row = this.t.insertRow(startRow.rowIndex+1); | ||||
| 		row.className = (ban == "blocked" && stateid != "chat") ? "ban" : "in"+stateid; | ||||
| 		row.id = "thr"+id; | ||||
| 		this.threadTimers[id] = new Array(vtime,modified,stateid); | ||||
| 		CommonUtils.insertCell(row, "name", "visitor", null, null, HtmlGenerationUtils.viewOpenCell(vname,this._options.agentservl,id,canview,canopen,ban,message,stateid!='chat',this._options.showvisitors, this._options.trackedservl)); | ||||
| 		CommonUtils.insertCell(row, "actions", "visitor", "center", null, actions); | ||||
| 		CommonUtils.insertCell(row, "contid", "visitor", "center", null, vaddr ); | ||||
| 		CommonUtils.insertCell(row, "state", "visitor", "center", null, vstate ); | ||||
| 		CommonUtils.insertCell(row, "op", "visitor", "center", null, agent ); | ||||
| 		CommonUtils.insertCell(row, "time", "visitor", "center", null, this.getTimeSince(vtime) ); | ||||
| 		CommonUtils.insertCell(row, "wait", "visitor", "center", null, (stateid!='chat' ? this.getTimeSince(modified) : '-') ); | ||||
| 		CommonUtils.insertCell(row, "etc", "visitor", "center", null, etc ); | ||||
| 
 | ||||
| 		if( stateid == 'wait' || stateid == 'prio' ) | ||||
| 			return true; | ||||
| 	} else { | ||||
| 		this.threadTimers[id] = new Array(vtime,modified,stateid); | ||||
| 		row.className = (ban == "blocked" && stateid != "chat") ? "ban" : "in"+stateid; | ||||
| 		setcell(this.t, row,"name",HtmlGenerationUtils.viewOpenCell(vname,this._options.agentservl,id,canview,canopen,ban,message,stateid!='chat',this._options.showvisitors, this._options.trackedservl)); | ||||
| 		setcell(this.t, row, "actions", actions); | ||||
| 		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 queueNotEmpty(t,id) { | ||||
| 		var startRow = $(id); | ||||
| 		var endRow = $(id+"end"); | ||||
| 		if( startRow == null || endRow == null ) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		return startRow.rowIndex+1 < endRow.rowIndex; | ||||
|   	} | ||||
| 	var _status = $("statustd"); | ||||
| 	if( _status) { | ||||
| 		var notempty = queueNotEmpty(this.t, "twait") || queueNotEmpty(this.t, "tprio") || queueNotEmpty(this.t, "tchat"); | ||||
| 		_status.innerHTML = notempty ? "" : this._options.noclients; | ||||
| 		_status.height = notempty ? 5 : 30; | ||||
| 	} | ||||
|   }, | ||||
| 
 | ||||
|   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]) : '-')); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|   }, | ||||
|    | ||||
|   updateThreads: function(root) { | ||||
| 	var newAdded = false; | ||||
| 	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(this._options.istatus ? localized[8] : localized[9]); | ||||
| 	if( newAdded ) { | ||||
| 		playSound(webimRoot+'/sounds/new_user.wav'); | ||||
| 		window.focus(); | ||||
| 		if(updaterOptions.showpopup) { | ||||
| 			alert(localized[5]); | ||||
| 		} | ||||
| 	} | ||||
|   }, | ||||
|    | ||||
|   updateOperators: function(root) { | ||||
|   	var div = $('onlineoperators'); | ||||
|   	if (!div) | ||||
|   		return; | ||||
| 
 | ||||
| 	var names = []; | ||||
| 	 | ||||
| 	for( var i = 0; i < root.childNodes.length; i++ ) { | ||||
| 		var node = root.childNodes[i]; | ||||
| 		if(node.tagName != 'operator') | ||||
| 			continue; | ||||
| 		 | ||||
| 		var name = NodeUtils.getAttrValue(node, 'name'); | ||||
| 		var isAway = NodeUtils.getAttrValue(node, 'away') != null; | ||||
| 		 | ||||
| 		names[names.length] =  | ||||
| 			'<img src="'+webimRoot+'/images/op'+(isAway ? 'away' : 'online')+ | ||||
| 					'.gif" width="12" height="12" border="0" alt="'+localized[1]+'"> '+ name; | ||||
| 	} | ||||
| 
 | ||||
| 	div.innerHTML = names.join(', '); | ||||
|   }, | ||||
| 
 | ||||
|   updateVisitorsTimers: function() { | ||||
| 	for (var i in this.visitorTimers) { | ||||
| 		if (this.visitorTimers[i] != null) { | ||||
| 			var value = this.visitorTimers[i]; | ||||
| 			var row = CommonUtils.getRow("vis"+i, this.t2); | ||||
| 			if( row != null ) { | ||||
| 				function setcell(_table, row,id,pcontent) { | ||||
| 					var cell = CommonUtils.getCell( id, row, _table ); | ||||
| 					if( cell ) | ||||
| 						cell.innerHTML = pcontent; | ||||
| 				} | ||||
| 				setcell(this.t2, row,"time",this.getTimeSince(value[0])); | ||||
| 				setcell(this.t2, row,"modified",this.getTimeSince(value[1])); | ||||
| 				if (value[2] != null) | ||||
| 				    setcell(this.t2, row,"invitationtime",this.getTimeSince(value[2])); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|   }, | ||||
| 
 | ||||
|   updateVisitor: function(node) { | ||||
| 	var id, invited = false; | ||||
| 
 | ||||
| 	for( var i = 0; i < node.attributes.length; i++ ) { | ||||
| 		var attr = node.attributes[i]; | ||||
| 		if( attr.nodeName == "id" ) | ||||
| 			id = attr.nodeValue; | ||||
| 	} | ||||
| 
 | ||||
| 	function setcell(_table, row,id,pcontent) { | ||||
| 		var cell = CommonUtils.getCell( id, row, _table ); | ||||
| 		if( cell ) | ||||
| 			cell.innerHTML = pcontent; | ||||
| 	} | ||||
| 
 | ||||
| 	var addr = NodeUtils.getNodeValue(node,"addr"); | ||||
| 	var username = NodeUtils.getNodeValue(node,"username"); | ||||
| 	var useragent = NodeUtils.getNodeValue(node,"useragent"); | ||||
| 	var time = NodeUtils.getNodeValue(node,"time"); | ||||
| 	var modified = NodeUtils.getNodeValue(node,"modified"); | ||||
| 
 | ||||
| 	var invitations = NodeUtils.getNodeValue(node,"invitations"); | ||||
| 	var chats = NodeUtils.getNodeValue(node,"chats"); | ||||
| 
 | ||||
| 	var operator = null; | ||||
| 	var invitationtime = null; | ||||
| 	var invitation = node.getElementsByTagName("invitation")[0]; | ||||
| 	for( var i = 0; i < invitation.childNodes.length; i++ ) { | ||||
| 		var childnode = invitation.childNodes[i]; | ||||
| 		if( childnode.tagName == 'operator' ) { | ||||
| 		    operator = childnode.firstChild.nodeValue; | ||||
| 		} | ||||
| 		else if ( childnode.tagName == 'invitationtime' ) { | ||||
| 		    invitationtime = childnode.firstChild.nodeValue; | ||||
| 		} | ||||
| 	} | ||||
| 	var state = (operator == null) ? 'free' : 'invited'; | ||||
| 
 | ||||
| 	var row = CommonUtils.getRow("vis"+id, this.t2); | ||||
| 
 | ||||
| 	var startRow = CommonUtils.getRow("vis" + state, this.t2); | ||||
| 	var endRow = CommonUtils.getRow("vis" + state + "end", this.t2); | ||||
| 
 | ||||
| 	if( row != null && (row.rowIndex <= startRow.rowIndex || row.rowIndex >= endRow.rowIndex ) ) { | ||||
| 
 | ||||
| 	    this.t2.deleteRow(row.rowIndex); | ||||
| 	    this.visitorTimers[id] = null; | ||||
| 	    row = null; | ||||
| 	} | ||||
| 
 | ||||
| 	if (row == null) { | ||||
| 	    row = this.t2.insertRow(startRow.rowIndex+1); | ||||
| 	    row.id = "vis"+id; | ||||
| 	    this.visitorTimers[id] = new Array(time, modified, invitationtime); | ||||
| 	    CommonUtils.insertCell(row, "username", "visitor", null, null, HtmlGenerationUtils.viewVisOpenCell(username, this._options.inviteservl, id, this._options.trackedservl, operator==null)); | ||||
| 	    CommonUtils.insertCell(row, "addr", "visitor", "center", null, addr); | ||||
| 	    CommonUtils.insertCell(row, "time", "visitor", "center", null, this.getTimeSince(time) ); | ||||
| 	    CommonUtils.insertCell(row, "modified", "visitor", "center", null, this.getTimeSince(modified) ); | ||||
| 	    CommonUtils.insertCell(row, "operator", "visitor", "center", null, (operator != null) ? operator : '-'); | ||||
| 	    CommonUtils.insertCell(row, "invitationtime", "visitor", "center", null, (operator != null ? this.getTimeSince(invitationtime) : '-') ); | ||||
| 	    CommonUtils.insertCell(row, "invitations", "visitor", "center", null, invitations + ' / ' + chats); | ||||
| 	    CommonUtils.insertCell(row, "useragent", "visitor", "center", null, useragent); | ||||
| 	} | ||||
| 	else { | ||||
| 	    this.visitorTimers[id] = new Array(time, modified, invitationtime); | ||||
| 	    setcell(this.t2, row, "username",HtmlGenerationUtils.viewVisOpenCell(username, this._options.inviteservl, id, this._options.trackedservl, operator==null)); | ||||
| 	    setcell(this.t2, row, "addr", addr); | ||||
| 	    setcell(this.t2, row, "operator", (operator != null) ? operator : '-'); | ||||
| 	    setcell(this.t2, row, "time", this.getTimeSince(time) ); | ||||
| 	    setcell(this.t2, row, "modified", this.getTimeSince(modified) ); | ||||
| 	    setcell(this.t2, row, "invitationtime", (operator != null ? this.getTimeSince(invitationtime) : '-') ); | ||||
| 	    setcell(this.t2, row, "invitations", invitations + ' / ' + chats); | ||||
| 	    setcell(this.t2, row, "useragent", useragent); | ||||
| 	} | ||||
| 
 | ||||
| 	this.visitors[id] = 1; | ||||
| 
 | ||||
| 	return false; | ||||
|   }, | ||||
| 
 | ||||
|   removeOldVisitors: function() { | ||||
| 	for (id in this.old_visitors) { | ||||
| 	    if (this.visitors[id] === undefined) { | ||||
| 		var row = CommonUtils.getRow("vis"+id, this.t2); | ||||
| 		if( row ) { | ||||
| 			this.t2.deleteRow(row.rowIndex); | ||||
| 		} | ||||
| 		this.visitorTimers[id] = null; | ||||
| 	    } | ||||
| 	} | ||||
|   }, | ||||
| 
 | ||||
|   updateVisitorsList: function(visitors) { | ||||
| 	var _status = $("visstatustd"); | ||||
| 	if( _status) { | ||||
| 		_status.innerHTML = (visitors > 0) ? "" : this._options.novisitors; | ||||
| 		_status.height = (visitors > 0) ? 5 : 30; | ||||
| 	} | ||||
|   }, | ||||
| 
 | ||||
|   updateVisitors: function(root) { | ||||
| 
 | ||||
| 	this.old_visitors = this.visitors; | ||||
| 	this.visitors = new Object(); | ||||
| 
 | ||||
| 	var visitors_cnt = 0; | ||||
| 	for( var i = 0; i < root.childNodes.length; i++ ) { | ||||
| 		var node = root.childNodes[i]; | ||||
| 		if( node.tagName == 'visitor' ) { | ||||
| 			visitors_cnt++; | ||||
| 			this.updateVisitor(node); | ||||
| 		} | ||||
| 	} | ||||
| 	this.updateVisitorsTimers(); | ||||
| 	this.removeOldVisitors(); | ||||
| 	this.updateVisitorsList(visitors_cnt); | ||||
|   }, | ||||
| 
 | ||||
|   updateContent: function(root) { | ||||
| 	if( root.tagName == 'update' ) { | ||||
| 		for( var i = 0; i < root.childNodes.length; i++ ) { | ||||
| 			var node = root.childNodes[i]; | ||||
| 			 | ||||
| 			if (node.tagName == 'threads') { | ||||
| 				this.updateThreads(node); | ||||
| 			} else if (node.tagName == 'operators') { | ||||
| 				this.updateOperators(node); | ||||
| 			} else if (node.tagName == 'visitors') { | ||||
| 				this.updateVisitors(node); | ||||
| 			} | ||||
| 		} | ||||
| 	} else if( root.tagName == 'error' ) { | ||||
| 		this.setStatus(NodeUtils.getNodeValue(root,"descr") ); | ||||
| 	} else { | ||||
| 		this.setStatus( "reconnecting" ); | ||||
| 	} | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| function togglemenu() { | ||||
| if($("sidebar") && $("wcontent") && $("togglemenu")) { | ||||
|   if($("wcontent").className == "contentnomenu") { | ||||
|     $("sidebar").style.display = "block"; | ||||
|     $("wcontent").className = "contentinner"; | ||||
|     $("togglemenu").innerHTML = localized[4]; | ||||
|   } else { | ||||
|     $("sidebar").style.display = "none"; | ||||
|     $("wcontent").className = "contentnomenu";  | ||||
|     $("togglemenu").innerHTML = localized[3]; | ||||
|   } | ||||
| } | ||||
| } | ||||
| 
 | ||||
| var webimRoot = ""; | ||||
| 
 | ||||
| Behaviour.register({ | ||||
| 	'#togglemenu' : function(el) { | ||||
| 		el.onclick = function() { | ||||
| 			togglemenu(); | ||||
| 		}; | ||||
| 	} | ||||
| }); | ||||
| 
 | ||||
| EventHelper.register(window, 'onload', function(){ | ||||
|   webimRoot = updaterOptions.wroot; | ||||
|   new Ajax.ThreadListUpdater(({table:$("threadlist"),status:$("connstatus"),istatus:0,visitors_table:$("visitorslist")}).extend(updaterOptions || {})); | ||||
|   if(!updaterOptions.havemenu) { | ||||
| 	  togglemenu(); | ||||
|   }	  | ||||
| }); | ||||
							
								
								
									
										104
									
								
								src/messenger/webim/js/source/users/app.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/messenger/webim/js/source/users/app.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Backbone, _){ | ||||
| 
 | ||||
|     // Create application instance
 | ||||
|     var App = new Backbone.Marionette.Application(); | ||||
| 
 | ||||
|     // Define regions
 | ||||
|     App.addRegions({ | ||||
|         agentsRegion: '#agents-region', | ||||
|         statusPanelRegion: '#status-panel-region', | ||||
|         threadsRegion: '#threads-region', | ||||
|         visitorsRegion: '#visitors-region', | ||||
|         soundRegion: '#sound-region' | ||||
|     }); | ||||
| 
 | ||||
|     // Initialize application
 | ||||
|     App.addInitializer(function(options){ | ||||
| 
 | ||||
|         // Create some shortcuts
 | ||||
|         var objs = Mibew.Objects; | ||||
|         var models = Mibew.Objects.Models; | ||||
|         var colls = Mibew.Objects.Collections; | ||||
| 
 | ||||
|         // Initialize Server, Thread and User
 | ||||
|         objs.server = new Mibew.Server(_.extend( | ||||
|             {'interactionType': MibewAPIUsersInteraction}, | ||||
|             options.server | ||||
|         )); | ||||
| 
 | ||||
|         // Initialize Page
 | ||||
|         models.page = new Mibew.Models.Page(options.page); | ||||
| 
 | ||||
|         // Initialize Agent
 | ||||
|         models.agent = new Mibew.Models.Agent(options.agent); | ||||
| 
 | ||||
|         // Initialize threads collection
 | ||||
|         colls.threads = new Mibew.Collections.Threads(); | ||||
|         App.threadsRegion.show(new Mibew.Views.ThreadsCollection({ | ||||
|             collection: colls.threads | ||||
|         })); | ||||
| 
 | ||||
|         // Initialize visitors collection
 | ||||
|         if (options.page.showOnlineOperators) { | ||||
|             colls.visitors = new Mibew.Collections.Visitors(); | ||||
|             App.visitorsRegion.show(new Mibew.Views.VisitorsCollection({ | ||||
|                 collection: colls.visitors | ||||
|             })); | ||||
|         } | ||||
| 
 | ||||
|         // Initialize status panel
 | ||||
|         models.statusPanel = new Mibew.Models.StatusPanel(); | ||||
|         App.statusPanelRegion.show(new Mibew.Views.StatusPanel({ | ||||
|             model: models.statusPanel | ||||
|         })); | ||||
| 
 | ||||
|         // Initialize agents collection and show it
 | ||||
|         if (options.page.showOnlineOperators) { | ||||
|             colls.agents = new Mibew.Collections.Agents(); | ||||
|             App.agentsRegion.show(new Mibew.Views.AgentsCollection({ | ||||
|                 collection: colls.agents | ||||
|             })); | ||||
|         } | ||||
| 
 | ||||
|         // Initialize sounds
 | ||||
|         models.sound = new Mibew.Models.Sound(); | ||||
|         App.soundRegion.show(new Mibew.Views.Sound({ | ||||
|             model: models.sound | ||||
|         })); | ||||
| 
 | ||||
|         // Periodically call update function at the server side
 | ||||
|         objs.server.callFunctionsPeriodically( | ||||
|             function() { | ||||
|                 // Build functions list
 | ||||
|                 return [ | ||||
|                     { | ||||
|                         "function": "update", | ||||
|                         "arguments": { | ||||
|                             "return": {}, | ||||
|                             "references": {}, | ||||
|                             "agentId": models.agent.id | ||||
|                         } | ||||
|                     } | ||||
|                 ]; | ||||
|             }, | ||||
|             function(args) {} | ||||
|         ); | ||||
| 
 | ||||
|     }); | ||||
| 
 | ||||
|     App.on('start', function() { | ||||
|         // Run Server updater
 | ||||
|         Mibew.Objects.server.runUpdater(); | ||||
|     }); | ||||
| 
 | ||||
|     Mibew.Application = App; | ||||
| 
 | ||||
| })(Mibew, Backbone, _); | ||||
| @ -0,0 +1,66 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew) { | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents online agents bar | ||||
|      */ | ||||
|     Mibew.Views.AgentsCollection = Mibew.Views.CollectionBase.extend( | ||||
|         /** @lends Mibew.Views.AgentsCollection.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * Default item view constructor. | ||||
|              * @type Function | ||||
|              */ | ||||
|             itemView: Mibew.Views.Agent, | ||||
| 
 | ||||
|             /** | ||||
|              * Class name for view's DOM element | ||||
|              * @type String | ||||
|              */ | ||||
|             className: 'agents-collection', | ||||
| 
 | ||||
|             /** | ||||
|              * Map collection events to the view methods | ||||
|              * @type Object | ||||
|              */ | ||||
|             collectionEvents: { | ||||
|                 'sort add remove reset': 'render' | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * View initializer | ||||
|              */ | ||||
|             initialize: function() { | ||||
|                 // Register events
 | ||||
|                 this.on('itemview:before:render', this.updateIndexes, this); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Update 'isModelFirst' and 'isModelLast' child views fields on | ||||
|              * collection 'sort', 'add', 'remove' and 'reset' events.Indexies | ||||
|              */ | ||||
|             updateIndexes: function(childView) { | ||||
|                 // Create some shortcuts
 | ||||
|                 var collection = this.collection; | ||||
|                 var model = childView.model; | ||||
| 
 | ||||
|                 if (model) { | ||||
|                     // Update isModelFirst and isModelLast properties
 | ||||
|                     childView.isModelFirst = (collection.indexOf(model) == 0); | ||||
|                     childView.isModelLast = ( | ||||
|                         collection.indexOf(model) == (collection.length - 1) | ||||
|                     ); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew); | ||||
| @ -0,0 +1,244 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Backbone, Handlebars, _) { | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents threads list | ||||
|      */ | ||||
|     Mibew.Views.ThreadsCollection = Backbone.Marionette.CompositeView.extend( | ||||
|         /** @lends Mibew.Views.ThreadsCollection.prototype */ | ||||
|         { | ||||
|             template: Handlebars.templates.threads_collection, | ||||
| 
 | ||||
|             /** | ||||
|              * Default item view constructor. | ||||
|              * @type Function | ||||
|              */ | ||||
|             itemView: Mibew.Views.QueuedThread, | ||||
| 
 | ||||
|             /** | ||||
|              * DOM element for collection items | ||||
|              * @type String | ||||
|              */ | ||||
|             itemViewContainer: '#threads-container', | ||||
| 
 | ||||
|             /** | ||||
|              * Empty view constructor. | ||||
|              * @type Function | ||||
|              */ | ||||
|             emptyView: Mibew.Views.NoThreads, | ||||
| 
 | ||||
|             /** | ||||
|              * Class name for view's DOM element | ||||
|              * @type String | ||||
|              */ | ||||
|             className: 'threads-collection', | ||||
| 
 | ||||
|             /** | ||||
|              * Map collection events to the view methods | ||||
|              * @type Object | ||||
|              */ | ||||
|             collectionEvents: { | ||||
|                 'sort': 'renderCollection', | ||||
|                 'sort:field': 'createSortField', | ||||
|                 'add': 'threadAdded' | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Pass some options to item view | ||||
|              * @returns {Object} Options object | ||||
|              */ | ||||
|             itemViewOptions: function(model) { | ||||
|                 var page = Mibew.Objects.Models.page; | ||||
|                 return { | ||||
|                     tagName: page.get('threadTag'), | ||||
|                     collection: model.get('controls') | ||||
|                 } | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * View initializer. | ||||
|              * @todo Do something with timer. Do not render whole view! | ||||
|              */ | ||||
|             initialize: function() { | ||||
|                 // Rerender view to keep timers in items views working
 | ||||
|                 window.setInterval(_.bind(this.renderCollection, this), 2 * 1000); | ||||
|                 // Register events
 | ||||
|                 this.on('itemview:before:render', this.updateStyles, this); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Update thread DOM element classes depending on thread params. | ||||
|              * @param {Mibew.Views.QueuedThread} childView View instance for | ||||
|              * thread in the queue | ||||
|              */ | ||||
|             updateStyles: function(childView) { | ||||
|                 // Create some shortcuts
 | ||||
|                 var collection = this.collection; | ||||
|                 var thread = childView.model; | ||||
|                 var self = this; | ||||
| 
 | ||||
|                 if (thread.id) { | ||||
|                     var queueCode = this.getQueueCode(thread); | ||||
|                     var isLast = false, isFirst = false; | ||||
| 
 | ||||
|                     // Filter collection by queue type
 | ||||
|                     var filteredThreads = collection.filter(function(model) { | ||||
|                         return self.getQueueCode(model) == queueCode; | ||||
|                     }); | ||||
| 
 | ||||
|                     // Get isFirst and isLast flags
 | ||||
|                     if (filteredThreads.length > 0) { | ||||
|                         isFirst = (filteredThreads[0].id == thread.id); | ||||
|                         isLast = ( | ||||
|                             filteredThreads[filteredThreads.length-1].id == thread.id | ||||
|                         ); | ||||
|                     } | ||||
| 
 | ||||
|                     // Remove all old styles
 | ||||
|                     if (childView.lastStyles.length > 0) { | ||||
|                         for(var i = 0, l = childView.lastStyles.length; i < l; i++) { | ||||
|                             childView.$el.removeClass(childView.lastStyles[i]); | ||||
|                         } | ||||
|                         childView.lastStyles = []; | ||||
|                     } | ||||
| 
 | ||||
|                     // Create new style name
 | ||||
|                     var style = ((queueCode != this.QUEUE_BAN)?'in':'') | ||||
|                         + this.queueCodeToString(queueCode); | ||||
| 
 | ||||
|                     // Store new styles
 | ||||
|                     childView.lastStyles.push(style); | ||||
|                     if (isFirst) { | ||||
|                         childView.lastStyles.push(style + "-first"); | ||||
|                     } | ||||
|                     if (isLast) { | ||||
|                         childView.lastStyles.push(style + "-last"); | ||||
|                     } | ||||
| 
 | ||||
|                     // Add styles names to DOM element
 | ||||
|                     for(var i = 0, l = childView.lastStyles.length; i < l; i++) { | ||||
|                         childView.$el.addClass(childView.lastStyles[i]); | ||||
|                     } | ||||
|                 } | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * This is the 'sort:field' event handler. | ||||
|              * Make threads sort by queue code and waiting time. | ||||
|              * @param {Mibew.Models.QueuedThread} thread Thread model | ||||
|              * @param {Object} sort Sorting object that contains property | ||||
|              * 'field' - a string by which threads will be sorted | ||||
|              */ | ||||
|             createSortField: function(thread, sort) { | ||||
|                 var queueCode = this.getQueueCode(thread) || 'Z'; | ||||
|                 sort.field = queueCode.toString() | ||||
|                         + '_' | ||||
|                         + thread.get('waitingTime').toString() | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Play sound when new thread add to collection | ||||
|              */ | ||||
|             threadAdded: function() { | ||||
|                 // Build sound path
 | ||||
|                 var path = Mibew.Objects.Models.page.get('webimRoot'); | ||||
|                 if (path) { | ||||
|                     path += '/sounds/new_user.wav'; | ||||
|                     // Play sound
 | ||||
|                     Mibew.Objects.Models.sound.play(path); | ||||
|                 } | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Calculate queue code for thread | ||||
|              * @returns {Boolean|Number} Queue code or false if code is unknown | ||||
|              */ | ||||
|             getQueueCode: function(thread) { | ||||
|                 var state = thread.get('state'); | ||||
|                 if (thread.get('ban') != false | ||||
|                     && state != thread.STATE_CHATTING) { | ||||
|                     return this.QUEUE_BAN; | ||||
|                 } | ||||
|                 if (state == thread.STATE_QUEUE | ||||
|                     || state == thread.STATE_LOADING) { | ||||
|                     return this.QUEUE_WAITING; | ||||
|                 } | ||||
|                 if (state == thread.STATE_CLOSED | ||||
|                     || state == thread.STATE_LEFT) { | ||||
|                     return this.QUEUE_CLOSED; | ||||
|                 } | ||||
|                 if (state == thread.STATE_WAITING) { | ||||
|                     return this.QUEUE_PRIO; | ||||
|                 } | ||||
|                 if (state == thread.STATE_CHATTING) { | ||||
|                     return this.QUEUE_CHATTING; | ||||
|                 } | ||||
| 
 | ||||
|                 return false; | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Convert numeric queue code to string one | ||||
|              * @returns {String} | ||||
|              */ | ||||
|             queueCodeToString: function(code) { | ||||
|                 if (code == this.QUEUE_PRIO) { | ||||
|                     return "prio"; | ||||
|                 } | ||||
|                 if (code == this.QUEUE_WAITING) { | ||||
|                     return "wait"; | ||||
|                 } | ||||
|                 if (code == this.QUEUE_CHATTING) { | ||||
|                     return "chat"; | ||||
|                 } | ||||
|                 if (code == this.QUEUE_BAN) { | ||||
|                     return "ban"; | ||||
|                 } | ||||
|                 if (code == this.QUEUE_CLOSED) { | ||||
|                     return "closed"; | ||||
|                 } | ||||
|                 return ""; | ||||
|             }, | ||||
| 
 | ||||
|             /** Queues codes */ | ||||
| 
 | ||||
|             /** | ||||
|              * Priority queue. Includes threads with STATE_WAITING state | ||||
|              */ | ||||
|             QUEUE_PRIO: 1, | ||||
| 
 | ||||
|             /** | ||||
|              * Waiting queue. Includes threads with STATE_LOADING and | ||||
|              * STATE_WAITING states. | ||||
|              */ | ||||
|             QUEUE_WAITING: 2, | ||||
| 
 | ||||
|             /** | ||||
|              * Chatting queue. Includes threads with STATE_CHATTING state | ||||
|              */ | ||||
|             QUEUE_CHATTING: 3, | ||||
| 
 | ||||
|             /** | ||||
|              * Ban queue. Includes all blocked threads. | ||||
|              */ | ||||
|             QUEUE_BAN: 4, | ||||
| 
 | ||||
|             /** | ||||
|              * Closed queue. Includes all threads with STATE_CLOSED and | ||||
|              * STATE_LEFT states | ||||
|              */ | ||||
|             QUEUE_CLOSED: 5 | ||||
| 
 | ||||
|             /** End of queues codes */ | ||||
| 
 | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, Backbone, Handlebars, _); | ||||
| @ -0,0 +1,76 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Backbone, Handlebars, _) { | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents visitors list | ||||
|      */ | ||||
|     Mibew.Views.VisitorsCollection = Backbone.Marionette.CompositeView.extend( | ||||
|         /** @lends Mibew.Views.VisitorsCollection.prototype */ | ||||
|         { | ||||
|             template: Handlebars.templates.visitors_collection, | ||||
| 
 | ||||
|             /** | ||||
|              * Default item view constructor. | ||||
|              * @type Function | ||||
|              */ | ||||
|             itemView: Mibew.Views.Visitor, | ||||
| 
 | ||||
|             /** | ||||
|              * DOM element for collection items | ||||
|              * @type String | ||||
|              */ | ||||
|             itemViewContainer: '#visitors-container', | ||||
| 
 | ||||
|             /** | ||||
|              * Empty view constructor. | ||||
|              * @type Function | ||||
|              */ | ||||
|             emptyView: Mibew.Views.NoVisitors, | ||||
| 
 | ||||
|             /** | ||||
|              * Class name for view's DOM element | ||||
|              * @type String | ||||
|              */ | ||||
|             className: 'visitors-collection', | ||||
| 
 | ||||
|             /** | ||||
|              * Map collection events to the view methods | ||||
|              * @type Object | ||||
|              */ | ||||
|             collectionEvents: { | ||||
|                 'sort': 'renderCollection' | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Pass some options to item view | ||||
|              * @returns {Object} Options object | ||||
|              */ | ||||
|             itemViewOptions: function(model) { | ||||
|                 var page = Mibew.Objects.Models.page; | ||||
|                 return { | ||||
|                     tagName: page.get('visitorTag'), | ||||
|                     collection: model.get('controls') | ||||
|                 } | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * View initializer. | ||||
|              * @todo Do something with timer. Do not render whole view! | ||||
|              */ | ||||
|             initialize: function() { | ||||
|                 // Rerender view to keep timers in items views working
 | ||||
|                 window.setInterval(_.bind(this.renderCollection, this), 2 * 1000); | ||||
|                 // Register events
 | ||||
|                 this.on('itemview:before:render', this.updateStyles, this); | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, Backbone, Handlebars, _); | ||||
							
								
								
									
										69
									
								
								src/messenger/webim/js/source/users/collections/agents.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/messenger/webim/js/source/users/collections/agents.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Backbone, _){ | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents collection of agents | ||||
|      */ | ||||
|     Mibew.Collections.Agents = Backbone.Collection.extend( | ||||
|         /** @lends Mibew.Collections.Agents.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * Model type of the collection items | ||||
|              */ | ||||
|             model: Mibew.Models.Agent, | ||||
| 
 | ||||
|             /** | ||||
|              * Use for sort controls in collection | ||||
|              * @param {Backbone.Model} model Agent model | ||||
|              */ | ||||
|             comparator: function(model) { | ||||
|                 return model.get('name'); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Collection initializer | ||||
|              */ | ||||
|             initialize: function() { | ||||
|                 // Register some shortcuts
 | ||||
|                 var agent = Mibew.Objects.Models.agent; | ||||
| 
 | ||||
|                 // Call updateOperators periodically at the server
 | ||||
|                 Mibew.Objects.server.callFunctionsPeriodically( | ||||
|                     function(){ | ||||
|                         return [ | ||||
|                             { | ||||
|                                 'function': 'updateOperators', | ||||
|                                 'arguments': { | ||||
|                                     'agentId': agent.id, | ||||
|                                     'return': { | ||||
|                                         'operators': 'operators' | ||||
|                                     }, | ||||
|                                     'references': {} | ||||
|                                 } | ||||
|                             } | ||||
|                         ]; | ||||
|                     }, | ||||
|                     _.bind(this.updateOperators, this) | ||||
|                 ); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Update available agents. | ||||
|              * @param {Object} args Arguments from the server | ||||
|              */ | ||||
|             updateOperators: function(args) { | ||||
|                 this.update(args.operators); | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, Backbone, _); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										156
									
								
								src/messenger/webim/js/source/users/collections/threads.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								src/messenger/webim/js/source/users/collections/threads.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,156 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Backbone, _){ | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents threads collection | ||||
|      */ | ||||
|     Mibew.Collections.Threads = Backbone.Collection.extend( | ||||
|         /** @lends Mibew.Collections.Threads.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * Model type of the collection items | ||||
|              * @type Function | ||||
|              */ | ||||
|             model: Mibew.Models.QueuedThread, | ||||
| 
 | ||||
|             /** | ||||
|              * Collection initializer | ||||
|              */ | ||||
|             initialize: function() { | ||||
|                 // Initialize fields and methods
 | ||||
| 
 | ||||
|                 /** | ||||
|                  * Last threads revision number. Prevent transfering not | ||||
|                  * modified threads. | ||||
|                  * @type Number | ||||
|                  * @fieldOf Mibew.Collections.Threads | ||||
|                  */ | ||||
|                 this.revision = 0; | ||||
| 
 | ||||
|                 // Register some shortcuts
 | ||||
|                 var self = this; | ||||
|                 var agent = Mibew.Objects.Models.agent; | ||||
| 
 | ||||
|                 // Call updateThreads periodically at the server
 | ||||
|                 Mibew.Objects.server.callFunctionsPeriodically( | ||||
|                     function(){ | ||||
|                         return [ | ||||
|                             { | ||||
|                                 'function': 'currentTime', | ||||
|                                 'arguments': { | ||||
|                                     'agentId': agent.id, | ||||
|                                     'return': { | ||||
|                                         'time': 'currentTime' | ||||
|                                     }, | ||||
|                                     'references': {} | ||||
|                                 } | ||||
|                             }, | ||||
|                             { | ||||
|                                 'function': 'updateThreads', | ||||
|                                 'arguments': { | ||||
|                                     'agentId': agent.id, | ||||
|                                     'revision': self.revision, | ||||
|                                     'return': { | ||||
|                                         'threads': 'threads', | ||||
|                                         'lastRevision': 'lastRevision' | ||||
|                                     }, | ||||
|                                     'references': {} | ||||
|                                 } | ||||
|                             } | ||||
|                         ]; | ||||
|                     }, | ||||
|                     _.bind(this.updateThreads, this) | ||||
|                 ); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Use for sort threads in collection. | ||||
|              * By default threads sort by state and waiting time. | ||||
|              * Triggers 'sort:field' event after sort field generated. | ||||
|              * @param {Mibew.Models.QueuedThread} thread Thread model | ||||
|              */ | ||||
|             comparator: function(thread) { | ||||
|                 // Create default sort field
 | ||||
|                 var sort = { | ||||
|                     field: thread.get('waitingTime').toString() | ||||
|                 } | ||||
| 
 | ||||
|                 // Trigger event to provide an ability to change sorting order
 | ||||
|                 this.trigger('sort:field', thread, sort); | ||||
| 
 | ||||
|                 // Return sort field
 | ||||
|                 return sort.field; | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Update threads list. | ||||
|              * Trigger 'before:update:threads' event and pass array of raw | ||||
|              * threads data as argument to event handler. | ||||
|              * Also trigger 'after:update:threads' event. | ||||
|              * @param {Object} args Arguments returned from server | ||||
|              */ | ||||
|             updateThreads: function(args) { | ||||
|                 if (args.errorCode == 0) { | ||||
| 
 | ||||
|                     if (args.threads.length > 0) { | ||||
|                         // Fix time difference between server and client
 | ||||
|                         var delta; | ||||
|                         if (args.currentTime) { | ||||
|                             delta = Math.round((new Date()).getTime() / 1000) | ||||
|                                 - args.currentTime; | ||||
|                         } else { | ||||
|                             delta = 0; | ||||
|                         } | ||||
|                         for(var i = 0, l = args.threads.length; i < l; i++) { | ||||
|                             args.threads[i].totalTime | ||||
|                                 = parseInt(args.threads[i].totalTime) + delta; | ||||
|                             args.threads[i].waitingTime | ||||
|                                 = parseInt(args.threads[i].waitingTime) + delta; | ||||
|                         } | ||||
| 
 | ||||
|                         // Trigger event. Event handlers can change threads info
 | ||||
|                         this.trigger('before:update:threads', args.threads); | ||||
| 
 | ||||
|                         // Create shortcuts for thread states
 | ||||
|                         var stateClosed = Mibew.Models.Thread.prototype.STATE_CLOSED; | ||||
|                         var stateLeft = Mibew.Models.Thread.prototype.STATE_LEFT; | ||||
| 
 | ||||
|                         // Define empty array for threads that should be remove
 | ||||
|                         var remove = []; | ||||
| 
 | ||||
|                         // Update threads list
 | ||||
|                         this.update(args.threads, {remove: false, sort: false}); | ||||
| 
 | ||||
|                         // Get closed and left thread. Collect them into
 | ||||
|                         // remove array
 | ||||
|                         remove = this.filter(function(thread) { | ||||
|                             return (thread.get('state') == stateClosed | ||||
|                                 || thread.get('state') == stateLeft); | ||||
|                         }); | ||||
|                         // Remove closed and left threads
 | ||||
|                         if (remove.length > 0) { | ||||
|                             this.remove(remove); | ||||
|                         } | ||||
| 
 | ||||
|                         // Sort residual collection
 | ||||
|                         this.sort(); | ||||
| 
 | ||||
|                         // Trigger event
 | ||||
|                         this.trigger('after:update:threads'); | ||||
|                     } | ||||
|                     this.revision = args.lastRevision; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, Backbone, _); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										117
									
								
								src/messenger/webim/js/source/users/collections/visitors.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/messenger/webim/js/source/users/collections/visitors.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,117 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Backbone, _){ | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents visitors collection | ||||
|      */ | ||||
|     Mibew.Collections.Visitors = Backbone.Collection.extend( | ||||
|         /** @lends Mibew.Collections.Visitors.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * Model type of the collection items | ||||
|              * @type Function | ||||
|              */ | ||||
|             model: Mibew.Models.Visitor, | ||||
| 
 | ||||
|             /** | ||||
|              * Collection initializer | ||||
|              */ | ||||
|             initialize: function() { | ||||
|                 // Register some shortcuts
 | ||||
|                 var agent = Mibew.Objects.Models.agent; | ||||
| 
 | ||||
|                 // Call updateThreads periodically at the server
 | ||||
|                 Mibew.Objects.server.callFunctionsPeriodically( | ||||
|                     function(){ | ||||
|                         return [ | ||||
|                             { | ||||
|                                 'function': 'currentTime', | ||||
|                                 'arguments': { | ||||
|                                     'agentId': agent.id, | ||||
|                                     'return': { | ||||
|                                         'time': 'currentTime' | ||||
|                                     }, | ||||
|                                     'references': {} | ||||
|                                 } | ||||
|                             }, | ||||
|                             { | ||||
|                                 'function': 'updateVisitors', | ||||
|                                 'arguments': { | ||||
|                                     'agentId': agent.id, | ||||
|                                     'return': { | ||||
|                                         'visitors': 'visitors' | ||||
|                                     }, | ||||
|                                     'references': {} | ||||
|                                 } | ||||
|                             } | ||||
|                         ]; | ||||
|                     }, | ||||
|                     _.bind(this.updateVisitors, this) | ||||
|                 ); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Use for sort visitors in collection. | ||||
|              * By default visitors sort by firstTime field. | ||||
|              * Triggers 'sort:field' event after sort field generated. | ||||
|              * @param {Mibew.Models.Visitor} visitor Visitor model | ||||
|              */ | ||||
|             comparator: function(visitor) { | ||||
|                 // Create default sort field
 | ||||
|                 var sort = { | ||||
|                     field: visitor.get('firstTime').toString() | ||||
|                 } | ||||
| 
 | ||||
|                 // Trigger event to provide an ability to change sorting order
 | ||||
|                 this.trigger('sort:field', visitor, sort); | ||||
| 
 | ||||
|                 // Return sort field
 | ||||
|                 return sort.field; | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Update visitors list. | ||||
|              * Trigger 'before:update:visitors' event and pass array of raw | ||||
|              * visitors data as argument to event handler. | ||||
|              * Also trigger 'after:update:visitors' event. | ||||
|              * @param {Object} args Arguments returned from server | ||||
|              */ | ||||
|             updateVisitors: function(args) { | ||||
|                 if (args.errorCode == 0) { | ||||
|                     // Fix time difference between server and client
 | ||||
|                     var delta; | ||||
|                     if (args.currentTime) { | ||||
|                         delta = Math.round((new Date()).getTime() / 1000) | ||||
|                             - args.currentTime; | ||||
|                     } else { | ||||
|                         delta = 0; | ||||
|                     } | ||||
|                     for(var i = 0, l = args.visitors.length; i < l; i++) { | ||||
|                         args.visitors[i].lastTime = parseInt(args.visitors[i].lastTime) + delta; | ||||
|                         args.visitors[i].firstTime = parseInt(args.visitors[i].firstTime) + delta; | ||||
|                     } | ||||
| 
 | ||||
|                     // Trigger event. Event handlers can change visitors info
 | ||||
|                     this.trigger('before:update:visitors', args.visitors); | ||||
| 
 | ||||
|                     // Update collection
 | ||||
|                     this.update(args.visitors); | ||||
| 
 | ||||
|                     // Trigger event
 | ||||
|                     this.trigger('after:update:visitors'); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, Backbone, _); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										33
									
								
								src/messenger/webim/js/source/users/handlebars_helpers.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/messenger/webim/js/source/users/handlebars_helpers.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  * | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Handlebars){ | ||||
|     /** | ||||
|      * Register 'formatTimeToNow' Handlebars helper. | ||||
|      * | ||||
|      * This helper takes unix timestamp as argument and return difference | ||||
|      * between current timestamp and passed one in "HH:MM:SS" format. | ||||
|      */ | ||||
|     Handlebars.registerHelper('formatTimeSince', function(unixTimestamp){ | ||||
|         // Get time diff
 | ||||
|         var diff = Math.round((new Date()).getTime() / 1000) - unixTimestamp; | ||||
|         // Get time parts
 | ||||
|         var seconds = diff % 60; | ||||
|         var minutes = Math.floor(diff / 60) % 60; | ||||
|         var hours = Math.floor(diff / (60 * 60)); | ||||
|         // Get result parts
 | ||||
|         var result = []; | ||||
|         if (hours > 0) { | ||||
|             result.push(hours); | ||||
|         } | ||||
|         result.push(minutes < 10 ? '0' + minutes : minutes); | ||||
|         result.push(seconds < 10 ? '0' + seconds : seconds); | ||||
|         // Build result string
 | ||||
|         return result.join(':'); | ||||
|     }); | ||||
| })(Handlebars); | ||||
							
								
								
									
										33
									
								
								src/messenger/webim/js/source/users/init.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/messenger/webim/js/source/users/init.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew){ | ||||
| 
 | ||||
|     /** | ||||
|      * @namespace Holds application region constructors | ||||
|      */ | ||||
|     Mibew.Regions = {}; | ||||
| 
 | ||||
|     /** | ||||
|      * @namespace Holds popup windows control | ||||
|      */ | ||||
|     Mibew.Popup = {}; | ||||
| 
 | ||||
|     /** | ||||
|      * Open new window | ||||
|      * @param {String} link URL address of page to open | ||||
|      * @param {String} id Id of new window | ||||
|      * @param {String} params Window params passed to window.open method | ||||
|      */ | ||||
|     Mibew.Popup.open = function(link, id, params) { | ||||
|         var newWindow = window.open(link, id, params); | ||||
|         newWindow.focus(); | ||||
|         newWindow.opener = window; | ||||
|     } | ||||
| 
 | ||||
| })(Mibew); | ||||
| @ -0,0 +1,30 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Represents User list Window to core interaction type | ||||
|  * | ||||
|  * @constructor | ||||
|  */ | ||||
| MibewAPIUsersInteraction = function() { | ||||
|     this.obligatoryArguments = { | ||||
|         '*': { | ||||
|             'agentId': null, | ||||
|             'return': {}, | ||||
|             'references': {} | ||||
|         }, | ||||
|         'result': { | ||||
|             'errorCode': 0 | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     this.reservedFunctionNames = [ | ||||
|         'result' | ||||
|     ]; | ||||
| } | ||||
| MibewAPIUsersInteraction.prototype = new MibewAPIInteraction(); | ||||
							
								
								
									
										81
									
								
								src/messenger/webim/js/source/users/model_views/agent.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/messenger/webim/js/source/users/model_views/agent.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Backbone, Handlebars) { | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents agent view. | ||||
|      */ | ||||
|     Mibew.Views.Agent = Backbone.Marionette.ItemView.extend( | ||||
|         /** @lends Mibew.Views.Agent.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * Template function | ||||
|              * @type Function | ||||
|              */ | ||||
|             template: Handlebars.templates.agent, | ||||
| 
 | ||||
|             /** | ||||
|              * Name of wrapper tag for an agent view | ||||
|              * @type String | ||||
|              */ | ||||
|             tagName: 'span', | ||||
| 
 | ||||
|             /** | ||||
|              * CSS class name for view's DOM element | ||||
|              * @type String | ||||
|              */ | ||||
|             className: 'agent', | ||||
| 
 | ||||
|             /** | ||||
|              * Map model events to the view methods | ||||
|              * @type Object | ||||
|              */ | ||||
|             modelEvents: { | ||||
|                 'change': 'render' | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * View initializer | ||||
|              */ | ||||
|             initialize: function() { | ||||
|                 // Initialize fields and methods of the instance
 | ||||
| 
 | ||||
|                 /** | ||||
|                  * Indicates if model related to the view is first in collection | ||||
|                  * @type Boolean | ||||
|                  * @fieldOf Mibew.Views.Agent | ||||
|                  */ | ||||
|                 this.isModelFirst = false; | ||||
| 
 | ||||
|                 /** | ||||
|                  * Indicates if model related to the view is last in collection | ||||
|                  * @type Boolean | ||||
|                  * @fieldOf Mibew.Views.Agent | ||||
|                  */ | ||||
|                 this.isModelLast = false; | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Override Backbone.Marionette.ItemView.serializeData to pass some | ||||
|              * extra fields to template. Add 'isFirst' and 'isLast' values. | ||||
|              * Following additional values available in template: | ||||
|              *  - 'isFirst': indicates if model is first in collection | ||||
|              *  - 'isLast': indicates if model is last in collection | ||||
|              * @returns {Object} Template data | ||||
|              */ | ||||
|             serializeData: function() { | ||||
|                 var data = this.model.toJSON(); | ||||
|                 data.isFirst = this.isModelFirst; | ||||
|                 data.isLast = this.isModelLast; | ||||
|                 return data; | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, Backbone, Handlebars); | ||||
| @ -0,0 +1,34 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Backbone, Handlebars) { | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents empty thread view. | ||||
|      */ | ||||
|     Mibew.Views.NoThreads = Backbone.Marionette.ItemView.extend( | ||||
|         /** @lends Mibew.Views.NoThreads.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * Template function | ||||
|              * @type Function | ||||
|              */ | ||||
|             template: Handlebars.templates.no_threads, | ||||
| 
 | ||||
|             /** | ||||
|              * View initializer | ||||
|              * @param {Object} options Options object passed from | ||||
|              * {@link Mibew.Views.ThreadsCollection.prototype.itemViewOptions} | ||||
|              */ | ||||
|             initialize: function(options) { | ||||
|                 this.tagName = options.tagName; | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, Backbone, Handlebars); | ||||
| @ -0,0 +1,34 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Backbone, Handlebars) { | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents empty visitor view. | ||||
|      */ | ||||
|     Mibew.Views.NoVisitors = Backbone.Marionette.ItemView.extend( | ||||
|         /** @lends Mibew.Views.NoVisitors.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * Template function | ||||
|              * @type Function | ||||
|              */ | ||||
|             template: Handlebars.templates.no_visitors, | ||||
| 
 | ||||
|             /** | ||||
|              * View initializer | ||||
|              * @param {Object} options Options object passed from | ||||
|              * {@link Mibew.Views.VisitorsCollection.prototype.itemViewOptions} | ||||
|              */ | ||||
|             initialize: function(options) { | ||||
|                 this.tagName = options.tagName; | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, Backbone, Handlebars); | ||||
							
								
								
									
										240
									
								
								src/messenger/webim/js/source/users/model_views/queued_thread.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								src/messenger/webim/js/source/users/model_views/queued_thread.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,240 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Handlebars) { | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents thread view. | ||||
|      */ | ||||
|     Mibew.Views.QueuedThread = Mibew.Views.CompositeBase.extend( | ||||
|         /** @lends Mibew.Views.QueuedThread.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * Template function | ||||
|              * @type Function | ||||
|              */ | ||||
|             template: Handlebars.templates.queued_thread, | ||||
| 
 | ||||
|             /** | ||||
|              * Default item view constructor. | ||||
|              * @type Function | ||||
|              */ | ||||
|             itemView: Mibew.Views.Control, | ||||
| 
 | ||||
|             /** | ||||
|              * DOM element for collection items | ||||
|              * @type String | ||||
|              */ | ||||
|             itemViewContainer: '.thread-controls', | ||||
| 
 | ||||
|             /** | ||||
|              * CSS class name for view's DOM element | ||||
|              * @type String | ||||
|              */ | ||||
|             className: 'thread', | ||||
| 
 | ||||
|             /** | ||||
|              * Map model events to the view methods | ||||
|              * @type Object | ||||
|              */ | ||||
|             modelEvents: { | ||||
|                 'change': 'render' | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * UI events hash. | ||||
|              * Map UI events on the view methods. | ||||
|              * @type Object | ||||
|              */ | ||||
|             events: { | ||||
|                 'click .open-dialog': 'openDialog', | ||||
|                 'click .view-control': 'viewDialog', | ||||
|                 'click .track-control': 'showTrack', | ||||
|                 'click .ban-control': 'showBan', | ||||
|                 'click .geo-link': 'showGeoInfo', | ||||
|                 'click .first-message a': 'showFirstMessage' | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * View initializer | ||||
|              */ | ||||
|             initialize: function() { | ||||
|                 // Initialize fields and methods of the instance
 | ||||
| 
 | ||||
|                 /** | ||||
|                  * Contain list of last styles added to the thread DOM element. | ||||
|                  * Used by {@link Mibew.Views.ThreadsCollection} view. | ||||
|                  * @type Array | ||||
|                  * @fieldOf Mibew.Views.Thread | ||||
|                  */ | ||||
|                 this.lastStyles = []; | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Override Backbone.Marionette.ItemView.serializeData to pass some | ||||
|              * extra fields to template. | ||||
|              * Following additional values available in template: | ||||
|              *  - 'stateDesc': thread state description | ||||
|              *  - 'chatting': indicates if thread have STATE_CHATTING | ||||
|              *  - 'tracked': indicates if tracked system is enabled | ||||
|              *  - 'firstMessagePreview': first message limited by 30 characters | ||||
|              * @returns {Object} Template data | ||||
|              */ | ||||
|             serializeData: function() { | ||||
|                 var thread = this.model | ||||
|                 var page = Mibew.Objects.Models.page; | ||||
|                 var data = thread.toJSON(); | ||||
|                 data.stateDesc = this.stateToDesc(thread.get('state')); | ||||
|                 data.chatting = (thread.get('state') == thread.STATE_CHATTING); | ||||
|                 data.tracked = page.get('showVisitors'); | ||||
|                 if (data.firstMessage) { | ||||
|                     data.firstMessagePreview = data.firstMessage.length > 30 | ||||
|                         ? data.firstMessage.substring(0,30) + '...' | ||||
|                         : data.firstMessage | ||||
|                 } | ||||
|                 return data; | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Convert numeric thread state code to string description of a | ||||
|              * state | ||||
|              * @param {Number} state Thread state code | ||||
|              * @returns {String} Description of the thread state | ||||
|              */ | ||||
|             stateToDesc: function(state) { | ||||
|                 var l = Mibew.Localization; | ||||
|                 if (state == this.model.STATE_QUEUE) { | ||||
|                     return l.get('chat.thread.state_wait'); | ||||
|                 } | ||||
|                 if (state == this.model.STATE_WAITING) { | ||||
|                     return l.get('chat.thread.state_wait_for_another_agent'); | ||||
|                 } | ||||
|                 if (state == this.model.STATE_CHATTING) { | ||||
|                     return l.get('chat.thread.state_chatting_with_agent'); | ||||
|                 } | ||||
|                 if (state == this.model.STATE_CLOSED) { | ||||
|                     return l.get('chat.thread.state_closed'); | ||||
|                 } | ||||
|                 if (state == this.model.STATE_LOADING) { | ||||
|                     return l.get('chat.thread.state_loading'); | ||||
|                 } | ||||
|                 return ""; | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Open window with geo information | ||||
|              */ | ||||
|             showGeoInfo: function() { | ||||
|                 var ip = this.model.get('userIp'); | ||||
|                 if (ip) { | ||||
|                     var page = Mibew.Objects.Models.page; | ||||
|                     var geoLink = page.get('geoLink') | ||||
|                         .replace("{ip}", ip); | ||||
|                     Mibew.Popup.open( | ||||
|                         geoLink, | ||||
|                         'ip' + ip, | ||||
|                         page.get('geoWindowParams') | ||||
|                     ); | ||||
|                 } | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Open chat window in dialog mode | ||||
|              */ | ||||
|             openDialog: function() { | ||||
|                 // Create some shortcuts
 | ||||
|                 var thread = this.model; | ||||
|                 var viewOnly = (thread.get('state') == thread.STATE_CHATTING) | ||||
|                     && thread.get('canView'); | ||||
| 
 | ||||
|                 // Show dialog window
 | ||||
|                 this.showDialogWindow(viewOnly); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Open chat window in view mode | ||||
|              */ | ||||
|             viewDialog: function() { | ||||
|                 this.showDialogWindow(true); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Open chat window | ||||
|              * @param {Boolean} viewOnly Indicates if chat window should be open | ||||
|              * in view mode | ||||
|              */ | ||||
|             showDialogWindow: function(viewOnly) { | ||||
|                 // Create some shortcuts
 | ||||
|                 var thread = this.model; | ||||
|                 var threadId = thread.id; | ||||
|                 var page = Mibew.Objects.Models.page; | ||||
| 
 | ||||
|                 // Open chat window
 | ||||
|                 Mibew.Popup.open( | ||||
|                     page.get('agentLink') | ||||
|                         + '?thread=' | ||||
|                         + threadId | ||||
|                         + (viewOnly ? '&viewonly=true': ''), | ||||
|                     'ImCenter' + threadId, | ||||
|                     page.get('chatWindowParams') | ||||
|                 ); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Open tracked window | ||||
|              */ | ||||
|             showTrack: function() { | ||||
|                 // Create some shortcuts
 | ||||
|                 var threadId = this.model.id; | ||||
|                 var page = Mibew.Objects.Models.page; | ||||
| 
 | ||||
|                 // Open tracked window
 | ||||
|                 Mibew.Popup.open( | ||||
|                     page.get('trackedLink') | ||||
|                         + '?thread=' | ||||
|                         + threadId, | ||||
|                     'ImTracked' + threadId, | ||||
|                     page.get('trackedUserWindowParams') | ||||
|                 ); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Open ban window | ||||
|              */ | ||||
|             showBan: function() { | ||||
|                 // Create some shortcuts
 | ||||
|                 var thread = this.model; | ||||
|                 var ban = thread.get('ban'); | ||||
|                 var page = Mibew.Objects.Models.page; | ||||
| 
 | ||||
|                 // Open ban window
 | ||||
|                 Mibew.Popup.open( | ||||
|                     page.get('banLink') | ||||
|                         + '?' | ||||
|                         + (ban !== false | ||||
|                             ? 'id='+ban.id | ||||
|                             : 'thread='+ thread.id), | ||||
|                     'ImBan' + ban.id, | ||||
|                     page.get('banWindowParams') | ||||
|                 ); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Show first message from user to agent | ||||
|              */ | ||||
|             showFirstMessage: function() { | ||||
|                 var message = this.model.get('firstMessage'); | ||||
|                 if (message) { | ||||
|                     alert(message); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, Handlebars); | ||||
| @ -0,0 +1,74 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Backbone, Handlebars) { | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents status panel view. | ||||
|      */ | ||||
|     Mibew.Views.StatusPanel = Backbone.Marionette.ItemView.extend( | ||||
|         /** @lends Mibew.Views.StatusPanel.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * Template function | ||||
|              * @type Function | ||||
|              */ | ||||
|             template: Handlebars.templates.status_panel, | ||||
| 
 | ||||
|             /** | ||||
|              * Map model events to the view methods | ||||
|              * @type Object | ||||
|              */ | ||||
|             modelEvents: { | ||||
|                 'change': 'render' | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Shortcuts for ui elements | ||||
|              * @type Object | ||||
|              */ | ||||
|             ui: { | ||||
|                 changeStatus: '#change-status' | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Map ui events to view methods | ||||
|              * @type Object | ||||
|              */ | ||||
|             events: { | ||||
|                 'click #change-status': 'changeAgentStatus' | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * View initializer | ||||
|              */ | ||||
|             initialize: function() { | ||||
|                 Mibew.Objects.Models.agent.on('change', this.render, this); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Changes users status | ||||
|              */ | ||||
|             changeAgentStatus: function() { | ||||
|                 this.model.changeAgentStatus(); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Override Backbone.Marionette.ItemView.serializeData to pass some | ||||
|              * extra fields to template. | ||||
|              * @returns {Object} Template data | ||||
|              */ | ||||
|             serializeData: function() { | ||||
|                 var data = this.model.toJSON(); | ||||
|                 data.agent = Mibew.Objects.Models.agent.toJSON(); | ||||
|                 return data; | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, Backbone, Handlebars); | ||||
							
								
								
									
										117
									
								
								src/messenger/webim/js/source/users/model_views/visitor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/messenger/webim/js/source/users/model_views/visitor.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,117 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Handlebars) { | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents visitor view. | ||||
|      */ | ||||
|     Mibew.Views.Visitor = Mibew.Views.CompositeBase.extend( | ||||
|         /** @lends Mibew.Views.Visitor.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * Template function | ||||
|              * @type Function | ||||
|              */ | ||||
|             template: Handlebars.templates.visitor, | ||||
| 
 | ||||
|             /** | ||||
|              * Default item view constructor. | ||||
|              * @type Function | ||||
|              */ | ||||
|             itemView: Mibew.Views.Control, | ||||
| 
 | ||||
|             /** | ||||
|              * DOM element for collection items | ||||
|              * @type String | ||||
|              */ | ||||
|             itemViewContainer: '.visitor-controls', | ||||
| 
 | ||||
|             /** | ||||
|              * CSS class name for view's DOM element | ||||
|              * @type String | ||||
|              */ | ||||
|             className: 'visitor', | ||||
| 
 | ||||
|             /** | ||||
|              * Map model events to the view methods | ||||
|              * @type Object | ||||
|              */ | ||||
|             modelEvents: { | ||||
|                 'change': 'render' | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * UI events hash. | ||||
|              * Map UI events on the view methods. | ||||
|              * @type Object | ||||
|              */ | ||||
|             events: { | ||||
|                 'click .invite-link': 'inviteUser', | ||||
|                 'click .geo-link': 'showGeoInfo', | ||||
|                 'click .track-control': 'showTrack' | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Invite user to chat | ||||
|              */ | ||||
|             inviteUser: function() { | ||||
|                 if (! this.model.get('invitationInfo')) { | ||||
|                     // Create some shortcuts
 | ||||
|                     var visitorId = this.model.id; | ||||
|                     var page = Mibew.Objects.Models.page; | ||||
| 
 | ||||
|                     // Open invite window
 | ||||
|                     Mibew.Popup.open( | ||||
|                         page.get('inviteLink') | ||||
|                             + '?visitor=' | ||||
|                             + visitorId, | ||||
|                         'ImCenter' + visitorId, | ||||
|                         page.get('inviteWindowParams') | ||||
|                     ); | ||||
|                 } | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Open tracked window | ||||
|              */ | ||||
|             showTrack: function() { | ||||
|                 // Create some shortcuts
 | ||||
|                 var visitorId = this.model.id; | ||||
|                 var page = Mibew.Objects.Models.page; | ||||
| 
 | ||||
|                 // Open tracked window
 | ||||
|                 Mibew.Popup.open( | ||||
|                     page.get('trackedLink') | ||||
|                         + '?visitor=' | ||||
|                         + visitorId, | ||||
|                     'ImTracked' + visitorId, | ||||
|                     page.get('trackedVisitorWindowParams') | ||||
|                 ); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Open window with geo information | ||||
|              */ | ||||
|             showGeoInfo: function() { | ||||
|                 var ip = this.model.get('userIp'); | ||||
|                 if (ip) { | ||||
|                     var page = Mibew.Objects.Models.page; | ||||
|                     var geoLink = page.get('geoLink') | ||||
|                         .replace("{ip}", ip); | ||||
|                     Mibew.Popup.open( | ||||
|                         geoLink, | ||||
|                         'ip' + ip, | ||||
|                         page.get('geoWindowParams') | ||||
|                     ); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, Handlebars); | ||||
							
								
								
									
										95
									
								
								src/messenger/webim/js/source/users/models/agent.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/messenger/webim/js/source/users/models/agent.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, _){ | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents an agent | ||||
|      */ | ||||
|     Mibew.Models.Agent = Mibew.Models.User.extend( | ||||
|         /** @lends Mibew.Models.Agent.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * A list of default model values. | ||||
|              * Inherits values from Mibew.Models.User | ||||
|              * @type Object | ||||
|              */ | ||||
|             defaults: _.extend( | ||||
|                 {}, | ||||
|                 Mibew.Models.User.prototype.defaults, | ||||
|                 { | ||||
|                     /** | ||||
|                      * Agent id on the server | ||||
|                      * @type Number | ||||
|                      */ | ||||
|                     id: null, | ||||
| 
 | ||||
|                     /** | ||||
|                      * Indicates that user is agent. | ||||
|                      * Left only for compatibility with Mibew.Models.User | ||||
|                      * @type Boolean | ||||
|                      */ | ||||
|                     isAgent: true, | ||||
| 
 | ||||
|                     /** | ||||
|                      * Indicates if agent away or available at the moment | ||||
|                      * @type Boolean | ||||
|                      */ | ||||
|                     away: false | ||||
|                 } | ||||
|             ), | ||||
| 
 | ||||
|             /** | ||||
|              * Set user status to 'away' | ||||
|              * This is a shortcut for setAvailability method | ||||
|              */ | ||||
|             away: function() { | ||||
|                 this.setAvailability(false); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Set user status to 'available' | ||||
|              * This is a shortcut for setAvailability method | ||||
|              */ | ||||
|             available: function() { | ||||
|                 this.setAvailability(true); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Set agent status: 'away' or 'available' | ||||
|              * @param {Boolean} available true set agent's status to 'available' | ||||
|              * and false set agent's status to 'away' | ||||
|              */ | ||||
|             setAvailability: function(available) { | ||||
|                 var funcName = available?'available':'away'; | ||||
|                 var self = this; | ||||
|                 Mibew.Objects.server.callFunctions( | ||||
|                     [ | ||||
|                         { | ||||
|                             'function': funcName, | ||||
|                             'arguments': { | ||||
|                                 'agentId': this.id, | ||||
|                                 'references': {}, | ||||
|                                 'return': {} | ||||
|                             } | ||||
|                         } | ||||
|                     ], | ||||
|                     function(args){ | ||||
|                         if (args.errorCode == 0) { | ||||
|                             self.set({'away': !available}); | ||||
|                         } | ||||
|                     }, | ||||
|                     true | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, _); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										154
									
								
								src/messenger/webim/js/source/users/models/queued_thread.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/messenger/webim/js/source/users/models/queued_thread.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,154 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  * | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, _){ | ||||
| 
 | ||||
|     /** | ||||
|      * Holds thread controls constructors | ||||
|      * @type Array | ||||
|      */ | ||||
|     var controlsConstructors = []; | ||||
| 
 | ||||
|     /** | ||||
|      * Prepresent thread in users queue | ||||
|      * @class | ||||
|      */ | ||||
|     var QueuedThread = Mibew.Models.QueuedThread = Mibew.Models.Thread.extend( | ||||
|         /** @lends Mibew.Models.QueuedThread.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * A list of default model values. | ||||
|              * Inherits values from Mibew.Models.Thread | ||||
|              * @type Object | ||||
|              */ | ||||
|             defaults: _.extend( | ||||
|                 {}, | ||||
|                 Mibew.Models.Thread.prototype.defaults, | ||||
|                 { | ||||
|                     /** | ||||
|                      * Collection of thread controls | ||||
|                      * @type Mibew.Collections.Controls | ||||
|                      */ | ||||
|                     controls: null, | ||||
| 
 | ||||
|                     /** | ||||
|                      * Name of the user | ||||
|                      * @type String | ||||
|                      */ | ||||
|                     userName: '', | ||||
| 
 | ||||
|                     /** | ||||
|                      * Ip address of the user | ||||
|                      * @type String | ||||
|                      */ | ||||
|                     userIp: '', | ||||
| 
 | ||||
|                     /** | ||||
|                      * Full remote address returned by web server. Generally | ||||
|                      * equals to userIp. | ||||
|                      * @type String | ||||
|                      */ | ||||
|                     remote: '', | ||||
| 
 | ||||
|                     /** | ||||
|                      * User agent | ||||
|                      * @type String | ||||
|                      */ | ||||
|                     userAgent: '', | ||||
| 
 | ||||
|                     /** | ||||
|                      * Agent name | ||||
|                      * @type String | ||||
|                      */ | ||||
|                     agentName: '', | ||||
| 
 | ||||
|                     /** | ||||
|                      * Indicates if agent can open thread | ||||
|                      * @type Boolean | ||||
|                      */ | ||||
|                     canOpen: false, | ||||
| 
 | ||||
|                     /** | ||||
|                      * Indicates if agent can view thread | ||||
|                      * @type Boolean | ||||
|                      */ | ||||
|                     canView: false, | ||||
| 
 | ||||
|                     /** | ||||
|                      * Indicates if agent can ban the user | ||||
|                      * @type Boolean | ||||
|                      */ | ||||
|                     canBan: false, | ||||
| 
 | ||||
|                     /** | ||||
|                      * Contains ban info if user already blocked or boolean | ||||
|                      * false otherwise. | ||||
|                      * @type Boolean|Object | ||||
|                      */ | ||||
|                     ban: false, | ||||
| 
 | ||||
|                     /** | ||||
|                      * Unix timestamp when thread was started | ||||
|                      * @type Number | ||||
|                      */ | ||||
|                     totalTime: 0, | ||||
| 
 | ||||
|                     /** | ||||
|                      * Unix timestamp when user begin wait for agent | ||||
|                      * @type Number | ||||
|                      */ | ||||
|                     waitingTime: 0, | ||||
| 
 | ||||
|                     /** | ||||
|                      * First message from user to operator | ||||
|                      * @type String | ||||
|                      */ | ||||
|                     firstMessage: null | ||||
|                 } | ||||
|             ), | ||||
| 
 | ||||
|             /** | ||||
|              * Model initializer. | ||||
|              * Create controls collection and store it in the model field. | ||||
|              */ | ||||
|             initialize: function() { | ||||
|                 var self = this; | ||||
|                 var controls = []; | ||||
|                 var constructors = QueuedThread.getControls(); | ||||
|                 for (var i = 0, l = constructors.length; i < l; i++) { | ||||
|                     controls.push(new constructors[i]({thread: self})); | ||||
|                 } | ||||
|                 this.set({ | ||||
|                     controls: new Mibew.Collections.Controls(controls) | ||||
|                 }); | ||||
|             } | ||||
|         }, | ||||
| 
 | ||||
| 
 | ||||
|         /** @lends Mibew.Models.QueuedThread */ | ||||
|         { | ||||
|             /** | ||||
|              * Add thread control constructor | ||||
|              * @static | ||||
|              * @param {Function} Mibew.Models.Control or inherited constructor | ||||
|              */ | ||||
|             addControl: function(control) { | ||||
|                 controlsConstructors.push(control) | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Returns list of thread controls constructors | ||||
|              * @static | ||||
|              * @returns {Array} List of controls constructors | ||||
|              */ | ||||
|             getControls: function() { | ||||
|                 return controlsConstructors; | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| })(Mibew, _); | ||||
							
								
								
									
										53
									
								
								src/messenger/webim/js/source/users/models/status_panel.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/messenger/webim/js/source/users/models/status_panel.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew){ | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents a status panel | ||||
|      */ | ||||
|     Mibew.Models.StatusPanel = Mibew.Models.Base.extend( | ||||
|         /** @lends Mibew.Models.StatusPanel.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * A list of default model values. | ||||
|              * @type Object | ||||
|              */ | ||||
|             defaults: { | ||||
|                 /** | ||||
|                  * Status message | ||||
|                  * @type String | ||||
|                  */ | ||||
|                 message: '' | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Set status message | ||||
|              * @param {String} message New status message | ||||
|              */ | ||||
|             setStatus: function(message) { | ||||
|                 this.set({'message': message}); | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Changes agent status | ||||
|              */ | ||||
|             changeAgentStatus: function() { | ||||
|                 var agent = Mibew.Objects.Models.agent; | ||||
|                 if (agent.get('away')) { | ||||
|                     agent.available(); | ||||
|                 } else { | ||||
|                     agent.away(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										141
									
								
								src/messenger/webim/js/source/users/models/visitor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/messenger/webim/js/source/users/models/visitor.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,141 @@ | ||||
| /** | ||||
|  * @preserve This file is part of Mibew Messenger project. | ||||
|  * http://mibew.org
 | ||||
|  *  | ||||
|  * Copyright (c) 2005-2011 Mibew Messenger Community | ||||
|  * License: http://mibew.org/license.php
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, _){ | ||||
| 
 | ||||
|     /** | ||||
|      * Holds visitor controls constructors | ||||
|      * @type Array | ||||
|      */ | ||||
|     var controlsConstructors = []; | ||||
| 
 | ||||
|     /** | ||||
|      * @class Represents a visitor. | ||||
|      */ | ||||
|     var Visitor = Mibew.Models.Visitor = Mibew.Models.User.extend( | ||||
|         /** @lends Mibew.Models.Visitor.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * A list of default model values. | ||||
|              * Inherits values from Mibew.Models.User | ||||
|              * @type Object | ||||
|              */ | ||||
|             defaults: _.extend( | ||||
|                 {}, | ||||
|                 Mibew.Models.User.prototype.defaults, | ||||
|                 { | ||||
|                     /** | ||||
|                      * Collection of visitor controls | ||||
|                      * @type Mibew.Collections.Controls | ||||
|                      */ | ||||
|                     controls: null, | ||||
| 
 | ||||
|                     /** | ||||
|                      * Name of the user | ||||
|                      * @type String | ||||
|                      */ | ||||
|                     userName: '', | ||||
| 
 | ||||
|                     /** | ||||
|                      * Ip address of the user | ||||
|                      * @type String | ||||
|                      */ | ||||
|                     userIp: '', | ||||
| 
 | ||||
|                     /** | ||||
|                      * Full remote address returned by web server. Generally | ||||
|                      * equals to userIp. | ||||
|                      * @type String | ||||
|                      */ | ||||
|                     remote: '', | ||||
| 
 | ||||
|                     /** | ||||
|                      * User agent | ||||
|                      * @type String | ||||
|                      */ | ||||
|                     userAgent: '', | ||||
| 
 | ||||
|                     /** | ||||
|                      * Unix timestamp when visitor was first time observed | ||||
|                      * on site | ||||
|                      * @type Number | ||||
|                      */ | ||||
|                     firstTime: 0, | ||||
| 
 | ||||
|                     /** | ||||
|                      * Unix timestamp when visitor was first time observed | ||||
|                      * on site | ||||
|                      * @type Number | ||||
|                      */ | ||||
|                     lastTime: 0, | ||||
| 
 | ||||
|                     /** | ||||
|                      * Total invitations count | ||||
|                      * @type Number | ||||
|                      */ | ||||
|                     invitations: 0, | ||||
| 
 | ||||
|                     /** | ||||
|                      * Total chats count with visitor | ||||
|                      * @type Number | ||||
|                      */ | ||||
|                     chats: 0, | ||||
| 
 | ||||
|                     /** | ||||
|                      * Information about invitation or booean false if there is | ||||
|                      * no invitation yet. | ||||
|                      * | ||||
|                      * Information object contains following keys: | ||||
|                      *  - 'agentName': name of the agent who invited the visitor | ||||
|                      *  - 'time': invitation time | ||||
|                      * @type Object|Boolean | ||||
|                      */ | ||||
|                     invitationInfo: false | ||||
|                 } | ||||
|             ), | ||||
| 
 | ||||
|             /** | ||||
|              * Model initializer. | ||||
|              * Create controls collection and store it in the model field. | ||||
|              */ | ||||
|             initialize: function() { | ||||
|                 var self = this; | ||||
|                 var controls = []; | ||||
|                 var constructors = Visitor.getControls(); | ||||
|                 for (var i = 0, l = constructors.length; i < l; i++) { | ||||
|                     controls.push(new constructors[i]({visitor: self})); | ||||
|                 } | ||||
|                 this.set({ | ||||
|                     controls: new Mibew.Collections.Controls(controls) | ||||
|                 }); | ||||
|             } | ||||
|         }, | ||||
| 
 | ||||
|         /** @lends Mibew.Models.Visitor */ | ||||
|         { | ||||
|             /** | ||||
|              * Add visitor control constructor | ||||
|              * @static | ||||
|              * @param {Function} Mibew.Models.Control or inherited constructor | ||||
|              */ | ||||
|             addControl: function(control) { | ||||
|                 controlsConstructors.push(control) | ||||
|             }, | ||||
| 
 | ||||
|             /** | ||||
|              * Returns list of visitor controls constructors | ||||
|              * @static | ||||
|              * @returns {Array} List of controls constructors | ||||
|              */ | ||||
|             getControls: function() { | ||||
|                 return controlsConstructors; | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, _); | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -0,0 +1 @@ | ||||
| <span class="agent-status-{{#if away}}away{{else}}online{{/if}} inline-block" title="{{#if away}}{{L10n "pending.status.away"}}{{else}}{{L10n "pending.status.online"}}{{/if}}"></span>{{name}}{{#unless isLast}},{{/unless}} | ||||
| @ -0,0 +1 @@ | ||||
| <td class="no-threads" colspan="8">{{L10n "clients.no_clients"}}</td> | ||||
| @ -0,0 +1 @@ | ||||
| <td class="no-visitors" colspan="9">{{L10n "visitors.no_visitors"}}</td> | ||||
| @ -0,0 +1,27 @@ | ||||
| <td class="visitor"> | ||||
|     <div><a href="javascript:void(0);" class="user-name open-dialog" title="{{#if canOpen}}{{L10n "pending.table.speak"}}{{else}}{{L10n "pending.table.view"}}{{/if}}">{{#if ban}}{{L10n "chat.client.spam.prefix"}} {{/if}}{{userName}}</a></div> | ||||
|     {{#if firstMessage}}<div class="first-message"><a href="javascript:void(0);" title="{{firstMessage}}">{{firstMessagePreview}}</a></div>{{/if}} | ||||
| </td> | ||||
| <td class="visitor"> | ||||
|     <div class="default-thread-controls inline-block"> | ||||
|         {{#if canOpen}} | ||||
|             <div class="control open-dialog open-control inline-block" title="{{L10n "pending.table.speak"}}"></div> | ||||
|         {{/if}} | ||||
|         {{#if canView}} | ||||
|             <div class="control view-control inline-block" title="{{L10n "pending.table.view"}}"></div> | ||||
|         {{/if}} | ||||
|         {{#if tracked}} | ||||
|             <div class="control track-control inline-block" title="{{L10n "pending.table.tracked"}}"></div> | ||||
|         {{/if}} | ||||
|         {{#if canBan}} | ||||
|             <div class="control ban-control inline-block" title="{{L10n "pending.table.ban"}}"></div> | ||||
|         {{/if}} | ||||
|     </div> | ||||
|     <div class="thread-controls inline-block"></div> | ||||
| </td> | ||||
| <td class="visitor">{{#if userIp}}<a href="javascript:void(0);" class="geo-link" title="GeoLocation">{{remote}}</a>{{else}}{{remote}}{{/if}}</td> | ||||
| <td class="visitor">{{stateDesc}}</td> | ||||
| <td class="visitor">{{agentName}}</td> | ||||
| <td class="visitor">{{formatTimeSince totalTime}}</td> | ||||
| <td class="visitor">{{#unless chatting}}{{formatTimeSince waitingTime}}{{else}}-{{/unless}}</td> | ||||
| <td class="visitor">{{#if ban}}{{ban.reason}}{{else}}{{userAgent}}{{/if}}</td> | ||||
| @ -0,0 +1 @@ | ||||
| <div id="connstatus">{{message}}{{#if agent.away}}{{L10n "pending.status.away"}}{{else}}{{L10n "pending.status.online"}}{{/if}}</div><div id="connlinks"><a href="javascript:void(0);" id="change-status">{{#if agent.away}}{{L10n "pending.status.setonline"}}{{else}}{{L10n "pending.status.setaway"}}{{/if}}</a></div> | ||||
| @ -0,0 +1,17 @@ | ||||
| <table class="awaiting" border="0"> | ||||
| <thead> | ||||
| <tr> | ||||
|     <th class="first">{{L10n "pending.table.head.name"}}</th> | ||||
|     <th>{{L10n "pending.table.head.actions"}}</th> | ||||
|     <th>{{L10n "pending.table.head.contactid"}}</th> | ||||
|     <th>{{L10n "pending.table.head.state"}}</th> | ||||
|     <th>{{L10n "pending.table.head.operator"}}</th> | ||||
|     <th>{{L10n "pending.table.head.total"}}</th> | ||||
|     <th>{{L10n "pending.table.head.waittime"}}</th> | ||||
|     <th>{{L10n "pending.table.head.etc"}}</th> | ||||
| </tr> | ||||
| </thead> | ||||
| <tbody id="threads-container"> | ||||
| 
 | ||||
| </tbody> | ||||
| </table> | ||||
| @ -0,0 +1,16 @@ | ||||
| <td class="visitor"> | ||||
|     {{#unless invitationInfo}}<a href="javascript:void(0);" class="invite-link" title="{{L10n "pending.table.invite"}}">{{userName}}</a>{{else}}{{userName}}{{/unless}} | ||||
| </td> | ||||
| <td class="visitor"> | ||||
|     <div class="default-visitor-controls inline-block"> | ||||
|         <div class="control track-control inline-block" title="{{L10n "pending.table.tracked"}}"></div> | ||||
|     </div> | ||||
|     <div class="visitor-controls inline-block"></div> | ||||
| </td> | ||||
| <td class="visitor">{{#if userIp}}<a href="javascript:void(0);" class="geo-link" title="GeoLocation">{{remote}}</a>{{else}}{{remote}}{{/if}}</td> | ||||
| <td class="visitor">{{formatTimeSince firstTime}}</td> | ||||
| <td class="visitor">{{formatTimeSince lastTime}}</td> | ||||
| <td class="visitor">{{#if invitationInfo}}{{invitationInfo.agentName}}{{else}}-{{/if}}</td> | ||||
| <td class="visitor">{{#if invitationInfo}}{{formatTimeSince invitationInfo.time}}{{else}}-{{/if}}</td> | ||||
| <td class="visitor">{{invitations}} / {{chats}}</td> | ||||
| <td class="visitor">{{userAgent}}</td> | ||||
| @ -0,0 +1,17 @@ | ||||
| <table id="visitorslist" class="awaiting" border="0"> | ||||
| <thead> | ||||
| <tr> | ||||
|     <th class="first">{{L10n "visitors.table.head.name"}}</th> | ||||
|     <th>{{L10n "visitors.table.head.actions"}}</th> | ||||
|     <th>{{L10n "visitors.table.head.contactid"}}</th> | ||||
|     <th>{{L10n "visitors.table.head.firsttimeonsite"}}</th> | ||||
|     <th>{{L10n "visitors.table.head.lasttimeonsite"}}</th> | ||||
|     <th>{{L10n "visitors.table.head.invited.by"}}</th> | ||||
|     <th>{{L10n "visitors.table.head.invitationtime"}}</th> | ||||
|     <th>{{L10n "visitors.table.head.invitations"}}</th> | ||||
|     <th>{{L10n "visitors.table.head.etc"}}</th> | ||||
| </tr> | ||||
| </thead> | ||||
| <tbody id="visitors-container"> | ||||
| </tbody> | ||||
| </table> | ||||
| @ -0,0 +1,51 @@ | ||||
| <?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. | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Implements Mibew Core - Mibew Users list interaction | ||||
|  */ | ||||
| class MibewAPIUsersInteraction extends MibewAPIInteraction { | ||||
| 	/** | ||||
| 	 * Defines obligatory arguments and default values for them | ||||
| 	 * @var array | ||||
| 	 * @see MibewAPIInteraction::$obligatoryArgumnents | ||||
| 	 */ | ||||
| 	protected $obligatoryArguments = array( | ||||
| 		'*' => array( | ||||
| 			'agentId' => null, | ||||
| 			'references' => array(), | ||||
| 			'return' => array() | ||||
| 		), | ||||
| 		'updateThreads' => array( | ||||
| 			'revision' => 0 | ||||
| 		), | ||||
| 		'result' => array( | ||||
| 			'errorCode' => 0 | ||||
| 		) | ||||
| 	); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Reserved function's names | ||||
| 	 * @var array | ||||
| 	 * @see MibewAPIInteraction::$reservedFunctionNames | ||||
| 	 */ | ||||
| 	public $reservedFunctionNames = array( | ||||
| 		'result' | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
							
								
								
									
										578
									
								
								src/messenger/webim/libs/classes/users_processor.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										578
									
								
								src/messenger/webim/libs/classes/users_processor.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,578 @@ | ||||
| <?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. | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Incapsulates awaiting users list api related functions. | ||||
|  * | ||||
|  * Register events (see RequestProcessor::registerEvents() for details): | ||||
|  *  - usersRequestReceived | ||||
|  *  - usersReceiveRequestError | ||||
|  *  - usersCallError | ||||
|  *  - usersFunctionCall | ||||
|  * | ||||
|  * WARNING: | ||||
|  *  usersResponseReceived registered but never called because of asynchronous | ||||
|  *  nature of Core-to-Window interaction | ||||
|  * | ||||
|  * Implements Singleton pattern | ||||
|  */ | ||||
| class UsersProcessor extends ClientSideProcessor { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * An instance of the UsersProcessor class | ||||
| 	 * @var UsersProcessor | ||||
| 	 */ | ||||
| 	protected static $instance = null; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Return an instance of the ThreadProcessor class. | ||||
| 	 * @return UsersProcessor | ||||
| 	 */ | ||||
| 	public static function getInstance() { | ||||
| 		if (is_null(self::$instance)) { | ||||
| 			self::$instance = new self(); | ||||
| 		} | ||||
| 		return self::$instance; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Class constructor | ||||
| 	 * | ||||
| 	 * Do not use directly __construct method! Use ThreadProcessor::getInstance() instead! | ||||
| 	 * @todo Think about why the method is not protected | ||||
| 	 */ | ||||
| 	public function __construct() { | ||||
| 		parent::__construct(array( | ||||
| 			'signature' => '', | ||||
| 			'trusted_signatures' => array(''), | ||||
| 			'event_prefix' => 'users' | ||||
| 		)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Creates and returns an instance of the MibewAPI class. | ||||
| 	 * | ||||
| 	 * @return MibewAPI | ||||
| 	 */ | ||||
| 	protected function getMibewAPIInstance() { | ||||
| 		return MibewAPI::getAPI('MibewAPIUsersInteraction'); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Sends asynchronous request | ||||
| 	 * | ||||
| 	 * @param array $request The 'request' array. See Mibew API for details | ||||
| 	 * @return boolean true on success or false on failure | ||||
| 	 */ | ||||
| 	protected function sendAsyncRequest($request) { | ||||
| 		// Define empty agent id
 | ||||
| 		$agent_id = null; | ||||
| 		foreach ($request['functions'] as $function) { | ||||
| 			// Save agent id from first function in package
 | ||||
| 			if (is_null($agent_id)) { | ||||
| 				$agent_id = $function['arguments']['agentId']; | ||||
| 				continue; | ||||
| 			} | ||||
| 			// Check agent id for the remaining functions
 | ||||
| 			if ($agent_id != $function['arguments']['agentId']) { | ||||
| 				throw new UsersProcessorException( | ||||
| 					'Various agent ids in different functions in one package!', | ||||
| 					UsersProcessorException::VARIOUS_AGENT_ID | ||||
| 				); | ||||
| 			} | ||||
| 		} | ||||
| 		// Store request in buffer
 | ||||
| 		$this->addRequestToBuffer('users_'.$agent_id, $request); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Check operator id equals to $operatorId is current logged in operator | ||||
| 	 * | ||||
| 	 * @param int $operatorId Operator id to check | ||||
| 	 * @return array Operators info array | ||||
| 	 * | ||||
| 	 * @throws UsersProcessorException If operators not logged in or if | ||||
| 	 * $operatorId varies from current logged in operator. | ||||
| 	 */ | ||||
| 	protected static function checkOperator($operatorId) { | ||||
| 		$operator = get_logged_in(); | ||||
| 		if (!$operator) { | ||||
| 			throw new UsersProcessorException( | ||||
| 				getstring("agent.not_logged_in"), | ||||
| 				UsersProcessorException::ERROR_AGENT_NOT_LOGGED_IN | ||||
| 			); | ||||
| 		} | ||||
| 		if ($operatorId != $operator['operatorid']) { | ||||
| 			throw new UsersProcessorException( | ||||
| 				"Wrong agent id: '{$operatorId}' instead of {$operator['operatorid']}", | ||||
| 				UsersProcessorException::ERROR_WRONG_AGENT_ID | ||||
| 			); | ||||
| 		} | ||||
| 		return $operator; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Mark operator as away. API function
 | ||||
| 	 * | ||||
| 	 * @param array $args Associative array of arguments. It must contains | ||||
| 	 * following keys: | ||||
| 	 *  - 'agentId': Id of the agent related to users window | ||||
| 	 */ | ||||
| 	protected function apiAway($args) { | ||||
| 		$operator = self::checkOperator($args['agentId']); | ||||
| 		notify_operator_alive($operator['operatorid'], 1); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Mark operator as available. API function
 | ||||
| 	 * | ||||
| 	 * @param array $args Associative array of arguments. It must contains | ||||
| 	 * following keys: | ||||
| 	 *  - 'agentId': Id of the agent related to users window | ||||
| 	 */ | ||||
| 	protected function apiAvailable($args) { | ||||
| 		$operator = self::checkOperator($args['agentId']); | ||||
| 		notify_operator_alive($operator['operatorid'], 0); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Return updated threads list. API function
 | ||||
| 	 * | ||||
| 	 * @global string $mysqlprefix Database tables prefix | ||||
| 	 * @global int $can_viewthreads View threads permission code | ||||
| 	 * @global int $can_takeover Take threads over permission code | ||||
| 	 * @param array $args Associative array of arguments. It must contains | ||||
| 	 * following keys: | ||||
| 	 *  - 'agentId': Id of the agent related to users window | ||||
| 	 *  - 'revision': last revision number at client side | ||||
| 	 * @return array Array of results. It contains following keys: | ||||
| 	 *  - 'threads': array of threads changes | ||||
| 	 */ | ||||
| 	protected function apiUpdateThreads($args) { | ||||
| 		global $mysqlprefix, $can_viewthreads, $can_takeover; | ||||
| 
 | ||||
| 		$operator = self::checkOperator($args['agentId']); | ||||
| 
 | ||||
| 		$since = $args['revision']; | ||||
| 		// Get operator groups
 | ||||
| 		if (!isset($_SESSION["${mysqlprefix}operatorgroups"])) { | ||||
| 			$_SESSION["${mysqlprefix}operatorgroups"] | ||||
| 				= get_operator_groupslist($operator['operatorid']); | ||||
| 		} | ||||
| 		$groupids = $_SESSION["${mysqlprefix}operatorgroups"]; | ||||
| 
 | ||||
| 		$db = Database::getInstance(); | ||||
| 		$query = "select t.*, " . | ||||
| 			" g.vclocalname as group_localname, " . | ||||
| 			" g.vccommonname as group_commonname " . | ||||
| 			" from {chatthread} t left outer join {chatgroup} g on " . | ||||
| 			" t.groupid = g.groupid " . | ||||
| 			" where t.lrevision > :since " . | ||||
| 			($since == 0 | ||||
| 				// Select only active threads at first time when lrevision = 0
 | ||||
| 				? " AND t.istate <> " . Thread::STATE_CLOSED . | ||||
| 					" AND t.istate <> " . Thread::STATE_LEFT | ||||
| 				// Select all threads at when lrevision > 0. It provides the
 | ||||
| 				// ability to update(and probably hide) closed threads at the
 | ||||
| 				// clien side.
 | ||||
| 				: "" | ||||
| 			) . | ||||
| 			(Settings::get('enablegroups') == '1' | ||||
| 				// If groups are enabled select only threads with empty groupid
 | ||||
| 				// or groups related to current operator
 | ||||
| 				? " AND (g.groupid is NULL" . ($groupids | ||||
| 					? " OR g.groupid IN ($groupids) OR g.groupid IN " . | ||||
| 						"(SELECT parent FROM {chatgroup} " . | ||||
| 						"WHERE groupid IN ($groupids)) " | ||||
| 					: "") . | ||||
| 				") " | ||||
| 				: "" | ||||
| 			) . | ||||
| 			" ORDER BY t.threadid"; | ||||
| 		$rows = $db->query( | ||||
| 			$query, | ||||
| 			array(':since' => $since), | ||||
| 			array('return_rows' => Database::RETURN_ALL_ROWS) | ||||
| 		); | ||||
| 
 | ||||
| 		$revision = $since; | ||||
| 		$threads = array(); | ||||
| 		foreach($rows as $row) { | ||||
| 			// Create thread instance
 | ||||
| 			$thread = Thread::createFromDbInfo($row); | ||||
| 
 | ||||
| 			// Calculate agent permissions
 | ||||
| 			$can_open = !($thread->state == Thread::STATE_CHATTING | ||||
| 				&& $thread->agentId != $operator['operatorid'] | ||||
| 				&& !is_capable($can_takeover, $operator)); | ||||
| 
 | ||||
| 			$can_view = ($thread->agentId != $operator['operatorid'] | ||||
| 				&& $thread->nextAgent != $operator['operatorid'] | ||||
| 				&& is_capable($can_viewthreads, $operator)); | ||||
| 
 | ||||
| 			$can_ban = (Settings::get('enableban') == "1"); | ||||
| 
 | ||||
| 
 | ||||
| 			// Get ban info
 | ||||
| 			$ban_info = (Settings::get('enableban') == "1") | ||||
| 				? ban_for_addr($thread->remote) | ||||
| 				: false; | ||||
| 			if ($ban_info !== false) { | ||||
| 				$ban = array( | ||||
| 					'id' => $ban_info['banid'], | ||||
| 					'reason' => $ban_info['comment'] | ||||
| 				); | ||||
| 			} else { | ||||
| 				$ban = false; | ||||
| 			} | ||||
| 
 | ||||
| 			// Get user name
 | ||||
| 			$user_name = get_user_name( | ||||
| 				$thread->userName, | ||||
| 				$thread->remote, | ||||
| 				$thread->userId | ||||
| 			); | ||||
| 
 | ||||
| 			// Get user ip
 | ||||
| 			if (preg_match("/(\\d+\\.\\d+\\.\\d+\\.\\d+)/", $thread->remote, $matches) != 0) { | ||||
| 				$user_ip = $matches[1]; | ||||
| 			} else { | ||||
| 				$user_ip = false; | ||||
| 			} | ||||
| 
 | ||||
| 			// Get thread operartor name
 | ||||
| 			$nextagent = $thread->nextAgent != 0 | ||||
| 				? operator_by_id($thread->nextAgent) | ||||
| 				: false; | ||||
| 			if ($nextagent) { | ||||
| 				$agent_name = get_operator_name($nextagent); | ||||
| 			} else { | ||||
| 				if ($thread->agentName) { | ||||
| 					$agent_name = $thread->agentName; | ||||
| 				} else { | ||||
| 					$group_name = get_group_name(array( | ||||
| 						'vccommonname' => $row['group_commonname'], | ||||
| 						'vclocalname' => $row['group_localname'] | ||||
| 					)); | ||||
| 					if($group_name) { | ||||
| 						$agent_name = '-' . $group_name . '-'; | ||||
| 					} else { | ||||
| 						$agent_name = '-'; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Get first message
 | ||||
| 			$first_message = null; | ||||
| 			if ($thread->shownMessageId != 0) { | ||||
| 				$line = $db->query( | ||||
| 					"select tmessage from {chatmessage} " . | ||||
| 						" where messageid = ? limit 1", | ||||
| 					array($thread->shownMessageId), | ||||
| 					array('return_rows' => Database::RETURN_ONE_ROW) | ||||
| 				); | ||||
| 				if ($line) { | ||||
| 					$first_message = preg_replace( | ||||
| 						"/[\r\n\t]+/", | ||||
| 						" ", | ||||
| 						$line["tmessage"] | ||||
| 					); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			$threads[] = array( | ||||
| 				'id' => $thread->id, | ||||
| 				'token' => $thread->lastToken, | ||||
| 				'userName' => $user_name, | ||||
| 				'userIp' => $user_ip, | ||||
| 				'remote' => $thread->remote, | ||||
| 				'userAgent' => get_useragent_version($thread->userAgent), | ||||
| 				'agentName' => $agent_name, | ||||
| 				'canOpen' => $can_open, | ||||
| 				'canView' => $can_view, | ||||
| 				'canBan' => $can_ban, | ||||
| 				'ban' => $ban, | ||||
| 				'state' => $thread->state, | ||||
| 				'totalTime' => $thread->created, | ||||
| 				'waitingTime' => $thread->modified, | ||||
| 				'firstMessage' => $first_message | ||||
| 			); | ||||
| 
 | ||||
| 			// Get max revision
 | ||||
| 			if ($thread->lastRevision > $revision) { | ||||
| 				$revision = $thread->lastRevision; | ||||
| 			} | ||||
| 
 | ||||
| 			// Clean up
 | ||||
| 			unset($thread); | ||||
| 		} | ||||
| 
 | ||||
| 		// Send results back to the client
 | ||||
| 		return array( | ||||
| 			'threads' => $threads, | ||||
| 			'lastRevision' => $revision | ||||
| 		); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Return updated visitors list. API function
 | ||||
| 	 * | ||||
| 	 * @param array $args Associative array of arguments. It must contains | ||||
| 	 * following keys: | ||||
| 	 *  - 'agentId': Id of the agent related to users window | ||||
| 	 * @return array Array of results. It contains following keys: | ||||
| 	 *  - 'visitors': array of visitors on the site | ||||
| 	 */ | ||||
| 	protected function apiUpdateVisitors($args) { | ||||
| 		// Check access
 | ||||
| 		self::checkOperator($args['agentId']); | ||||
| 
 | ||||
| 		$db = Database::getInstance(); | ||||
| 
 | ||||
| 		// Remove old visitors
 | ||||
| 		$db->query( | ||||
| 			"DELETE FROM {chatsitevisitor} " . | ||||
| 			"WHERE (:now - lasttime) > :lifetime ". | ||||
| 			"AND (threadid IS NULL OR " . | ||||
| 			"(SELECT count(*) FROM {chatthread} " . | ||||
| 				"WHERE threadid = {chatsitevisitor}.threadid " . | ||||
| 				"AND istate <> " . Thread::STATE_CLOSED . " " . | ||||
| 				"AND istate <> " . Thread::STATE_LEFT . ") = 0)", | ||||
| 			array( | ||||
| 				':lifetime' => Settings::get('tracking_lifetime'), | ||||
| 				':now' => time() | ||||
| 			) | ||||
| 		); | ||||
| 
 | ||||
| 		// Remove old invitations
 | ||||
| 		$db->query( | ||||
| 			"UPDATE {chatsitevisitor} SET invited = 0, " . | ||||
| 				"invitationtime = NULL, invitedby = NULL". | ||||
| 			" WHERE threadid IS NULL AND (:now - invitationtime) > :lifetime", | ||||
| 			array( | ||||
| 				':lifetime' => Settings::get('invitation_lifetime'), | ||||
| 				':now' => time() | ||||
| 			) | ||||
| 		); | ||||
| 
 | ||||
| 		// Remove associations of visitors with closed threads
 | ||||
| 		$db->query( | ||||
| 			"UPDATE {chatsitevisitor} SET threadid = NULL " . | ||||
| 			"WHERE threadid IS NOT NULL AND " . | ||||
| 			" (SELECT count(*) FROM {chatthread} " . | ||||
| 				"WHERE threadid = {chatsitevisitor}.threadid" . | ||||
| 				" AND istate <> " . Thread::STATE_CLOSED . " " . | ||||
| 				" AND istate <> " . Thread::STATE_LEFT . ") = 0" | ||||
| 		); | ||||
| 
 | ||||
| 		// Remove old visitors' tracks
 | ||||
| 		$db->query( | ||||
| 			"DELETE FROM {visitedpage} WHERE (:now - visittime) > :lifetime " . | ||||
| 			" AND visitorid NOT IN (SELECT visitorid FROM {chatsitevisitor})", | ||||
| 			array( | ||||
| 				':lifetime' => Settings::get('tracking_lifetime'), | ||||
| 				':now' => time() | ||||
| 			) | ||||
| 		); | ||||
| 
 | ||||
| 		// Load visitors
 | ||||
| 		$query = "SELECT visitorid, userid, username, firsttime, lasttime, " . | ||||
| 			"entry, details, invited, invitationtime, invitedby, " . | ||||
| 			"invitations, chats " . | ||||
| 			"FROM {chatsitevisitor} " . | ||||
| 			"WHERE threadid IS NULL " . | ||||
| 			"ORDER BY invited, lasttime DESC, invitations"; | ||||
| 		$query .= (Settings::get('visitors_limit') == '0') | ||||
| 			? "" | ||||
| 			: " LIMIT " . Settings::get('visitors_limit'); | ||||
| 
 | ||||
| 		$rows = $db->query( | ||||
| 			$query, | ||||
| 			NULL, | ||||
| 			array('return_rows' => Database::RETURN_ALL_ROWS) | ||||
| 		); | ||||
| 
 | ||||
| 		$visitors = array(); | ||||
| 		foreach ($rows as $row) { | ||||
| 
 | ||||
| 			// Get visitor details
 | ||||
| 			$details = track_retrieve_details($row); | ||||
| 
 | ||||
| 			// Get user agent
 | ||||
| 			$user_agent = get_useragent_version($details['user_agent']); | ||||
| 
 | ||||
| 			// Get user ip
 | ||||
| 			if (preg_match("/(\\d+\\.\\d+\\.\\d+\\.\\d+)/", $details['remote_host'], $matches) != 0) { | ||||
| 				$user_ip = $matches[1]; | ||||
| 			} else { | ||||
| 				$user_ip = false; | ||||
| 			} | ||||
| 
 | ||||
| 			// Get invitation info
 | ||||
| 			if ($row['invited']) { | ||||
| 				$agent_name  = get_operator_name( | ||||
| 					operator_by_id($row['invitedby']) | ||||
| 				); | ||||
| 				$invitation_info = array( | ||||
| 					'time' => $row['invitationtime'], | ||||
| 					'agentName' => $agent_name | ||||
| 				); | ||||
| 			} else { | ||||
| 				$invitation_info = false; | ||||
| 			} | ||||
| 
 | ||||
| 			// Create resulting visitor structure
 | ||||
| 			$visitors[] = array( | ||||
| 				'id' => (int)$row['visitorid'], | ||||
| 				'userName' => $row['username'], | ||||
| 				'userAgent' => $user_agent, | ||||
| 				'userIp' => $user_ip, | ||||
| 				'remote' => $details['remote_host'], | ||||
| 				'firstTime' => $row['firsttime'], | ||||
| 				'lastTime' => $row['lasttime'], | ||||
| 				'invitations' => (int)$row['invitations'], | ||||
| 				'chats' => (int)$row['chats'], | ||||
| 				'invitationInfo' => $invitation_info | ||||
| 			); | ||||
| 		} | ||||
| 
 | ||||
| 		return array( | ||||
| 			'visitors' => $visitors | ||||
| 		); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Return updated operators list. API function
 | ||||
| 	 * | ||||
| 	 * @global string $webim_encoding Encoding for the current locale | ||||
| 	 * @param array $args Associative array of arguments. It must contains | ||||
| 	 * following keys: | ||||
| 	 *  - 'agentId': Id of the agent related to users window | ||||
| 	 * @return array Array of results. It contains following keys: | ||||
| 	 *  - 'operators': array of online operators | ||||
| 	 */ | ||||
| 	protected function apiUpdateOperators($args) { | ||||
| 		global $webim_encoding; | ||||
| 
 | ||||
| 		// Check access and get operators info
 | ||||
| 		$operator = self::checkOperator($args['agentId']); | ||||
| 
 | ||||
| 		// Return empty array if show operators option disabled
 | ||||
| 		if (Settings::get('showonlineoperators') != '1') { | ||||
| 			return array( | ||||
| 				'operators' => array() | ||||
| 			); | ||||
| 		} | ||||
| 
 | ||||
| 		// Check if curent operator is in isolation
 | ||||
| 		$list_options = in_isolation($operator) | ||||
| 			? array('isolated_operator_id' => $operator['operatorid']) | ||||
| 			: array(); | ||||
| 
 | ||||
| 		// Get operators list
 | ||||
| 		$operators = get_operators_list($list_options); | ||||
| 
 | ||||
| 		// Create resulting list of operators
 | ||||
| 		$result_list = array(); | ||||
| 		foreach ($operators as $item) { | ||||
| 			if (!operator_is_online($item)) { | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			$result_list[] = array( | ||||
| 				'id' => (int)$item['operatorid'], | ||||
| 				// Convert name to UTF-8
 | ||||
| 				'name' => myiconv( | ||||
| 					$webim_encoding, | ||||
| 					"utf-8", | ||||
| 					htmlspecialchars($item['vclocalename']) | ||||
| 				), | ||||
| 				'away' => (bool)operator_is_away($item) | ||||
| 			); | ||||
| 		} | ||||
| 
 | ||||
| 		// Send operators list to the client side
 | ||||
| 		return array( | ||||
| 			'operators' => $result_list | ||||
| 		); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Update chat window state. API function
 | ||||
| 	 * | ||||
| 	 * Call periodically by chat window | ||||
| 	 * @param array $args Associative array of arguments. It must contains | ||||
| 	 * following keys: | ||||
| 	 *  - 'agentId': Id of the agent related to users window | ||||
| 	 */ | ||||
| 	protected function apiUpdate($args) { | ||||
| 		// Check access and get operator array
 | ||||
| 		$operator = self::checkOperator($args['agentId']); | ||||
| 
 | ||||
| 		// Update operator status
 | ||||
| 		notify_operator_alive($operator['operatorid'], $operator['istatus']); | ||||
| 
 | ||||
| 		// Close old threads
 | ||||
| 		Thread::closeOldThreads(); | ||||
| 
 | ||||
| 		// Load stored requests
 | ||||
| 		$stored_requests = $this->getRequestsFromBuffer('users_'.$args['agentId']); | ||||
| 		if ($stored_requests !== false) { | ||||
| 			$this->responses = array_merge($this->responses, $stored_requests); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns current server time. API function
 | ||||
| 	 * | ||||
| 	 * @param array $args Associative array of arguments. It must contains | ||||
| 	 * following keys: | ||||
| 	 *  - 'agentId': Id of the agent related to users window | ||||
| 	 * @return array Array of results. It contains following keys: | ||||
| 	 *  - 'time': current server time | ||||
| 	 */ | ||||
| 	protected function apiCurrentTime($args) { | ||||
| 		// Check access
 | ||||
| 		self::checkOperator($args['agentId']); | ||||
| 
 | ||||
| 		// Return time
 | ||||
| 		return array( | ||||
| 			'time' => time() | ||||
| 		); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Class for users processor exceptions | ||||
|  */ | ||||
| class UsersProcessorException extends RequestProcessorException { | ||||
| 	/** | ||||
| 	 * Operator is not logged in | ||||
| 	 */ | ||||
| 	const ERROR_AGENT_NOT_LOGGED_IN = 1; | ||||
| 	/** | ||||
| 	 * Wrong agent id | ||||
| 	 */ | ||||
| 	const ERROR_WRONG_AGENT_ID = 2; | ||||
| 	/** | ||||
| 	 * Various agent ids in different functions in one package | ||||
| 	 */ | ||||
| 	const VARIOUS_AGENT_ID = 3; | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
| @ -46,6 +46,20 @@ function get_core_style_config() { | ||||
| 	$config += array( | ||||
| 		'history' => array( | ||||
| 			'window_params' => '' | ||||
| 		), | ||||
| 		'users' => array( | ||||
| 			'thread_tag' => 'div', | ||||
| 			'visitor_tag' => 'div' | ||||
| 		), | ||||
| 		'tracked' => array( | ||||
| 			'user_window_params' => '', | ||||
| 			'visitor_window_params' => '' | ||||
| 		), | ||||
| 		'invitation' => array( | ||||
| 			'window_params' => '' | ||||
| 		), | ||||
| 		'ban' => array( | ||||
| 			'window_params' => '' | ||||
| 		) | ||||
| 	); | ||||
| 
 | ||||
|  | ||||
| @ -40,7 +40,7 @@ char.redirect.operator.online_suff=(online) | ||||
| chat.came.from=Vistor came from page {0} | ||||
| chat.client.changename=Change name | ||||
| chat.client.name=You are  | ||||
| chat.client.spam.prefix=[spam]  | ||||
| chat.client.spam.prefix=[spam] | ||||
| chat.client.visited.page=Visitor navigated to {0} | ||||
| chat.close.confirmation=Are you sure want to leave chat? | ||||
| chat.default.username=Guest | ||||
| @ -615,6 +615,7 @@ updates.title=Updates | ||||
| visitors.how_to=To invite the visitor to chat click on his/her name in the list. | ||||
| visitors.intro=The table below represents a list of visitors ready to chat on your site. | ||||
| visitors.no_visitors=There are no visitors ready to chat on your site at present time  | ||||
| visitors.table.head.actions=Actions | ||||
| visitors.table.head.contactid=Visitor's address | ||||
| visitors.table.head.etc=Misc | ||||
| visitors.table.head.firsttimeonsite=First seen | ||||
|  | ||||
| @ -40,7 +40,7 @@ char.redirect.operator.online_suff=( | ||||
| chat.came.from=Посетитель пришел со страницы {0} | ||||
| chat.client.changename=Изменить имя | ||||
| chat.client.name=Вы  | ||||
| chat.client.spam.prefix=[ñïàì]  | ||||
| chat.client.spam.prefix=[ñïàì] | ||||
| chat.client.visited.page=Посетитель перешел на {0} | ||||
| chat.close.confirmation=Вы действительно хотите покинуть диалог? | ||||
| chat.default.username=Посетитель | ||||
| @ -617,6 +617,7 @@ updates.title= | ||||
| visitors.how_to=Для приглашения посетителя к диалогу кликните на его или её имя в списке. | ||||
| visitors.intro=В расположенной ниже таблице представлен список готовых к диалогу посетителей на Вашем сайте. | ||||
| visitors.no_visitors=В настоящее время на Вашем сайте нет готовых к диалогу посетителей | ||||
| visitors.table.head.actions=Äåéñòâèÿ | ||||
| visitors.table.head.contactid=Адрес посетителя | ||||
| visitors.table.head.etc=Разное | ||||
| visitors.table.head.firsttimeonsite=Впервые замечен | ||||
|  | ||||
| @ -22,298 +22,14 @@ require_once('../libs/operator.php'); | ||||
| require_once('../libs/groups.php'); | ||||
| require_once('../libs/track.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_users_interaction.php'); | ||||
| require_once('../libs/classes/mibew_api_execution_context.php'); | ||||
| require_once('../libs/classes/client_side_processor.php'); | ||||
| require_once('../libs/classes/users_processor.php'); | ||||
| 
 | ||||
| $operator = get_logged_in(); | ||||
| if (!$operator) { | ||||
| 	start_xml_output(); | ||||
| 	echo "<error><descr>" . myiconv($webim_encoding, "utf-8", escape_with_cdata(getstring("agent.not_logged_in"))) . "</descr></error>"; | ||||
| 	exit; | ||||
| } | ||||
| 
 | ||||
| $threadstate_to_string = array( | ||||
| 	Thread::STATE_QUEUE => "wait", | ||||
| 	Thread::STATE_WAITING => "prio", | ||||
| 	Thread::STATE_CHATTING => "chat", | ||||
| 	Thread::STATE_CLOSED => "closed", | ||||
| 	Thread::STATE_LOADING => "wait", | ||||
| 	Thread::STATE_LEFT => "closed" | ||||
| ); | ||||
| 
 | ||||
| $threadstate_key = array( | ||||
| 	Thread::STATE_QUEUE => "chat.thread.state_wait", | ||||
| 	Thread::STATE_WAITING => "chat.thread.state_wait_for_another_agent", | ||||
| 	Thread::STATE_CHATTING => "chat.thread.state_chatting_with_agent", | ||||
| 	Thread::STATE_CLOSED => "chat.thread.state_closed", | ||||
| 	Thread::STATE_LOADING => "chat.thread.state_loading" | ||||
| ); | ||||
| 
 | ||||
| function thread_to_xml($thread_info) | ||||
| { | ||||
| 	global $threadstate_to_string, $threadstate_key, | ||||
| 		$webim_encoding, $operator, $can_viewthreads, $can_takeover; | ||||
| 
 | ||||
| 	$thread = $thread_info['thread']; | ||||
| 
 | ||||
| 	$state = $threadstate_to_string[$thread->state]; | ||||
| 	$result = "<thread id=\"" . $thread->id . "\" stateid=\"$state\"";
 | ||||
| 	if ($state == "closed") | ||||
| 		return $result . "/>"; | ||||
| 
 | ||||
| 	$state = getstring($threadstate_key[$thread->state]); | ||||
| 	$nextagent = $thread->nextAgent != 0 ? operator_by_id($thread->nextAgent) : null; | ||||
| 	$threadoperator = $nextagent ? get_operator_name($nextagent) | ||||
| 			: ($thread->agentName ? $thread->agentName : "-"); | ||||
| 
 | ||||
| 	if ($threadoperator == "-" && ! empty($thread_info['groupname'])) { | ||||
| 		$threadoperator = "- " . $thread_info['groupname'] . " -"; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!($thread->state == Thread::STATE_CHATTING && $thread->agentId != $operator['operatorid'] && !is_capable($can_takeover, $operator))) { | ||||
| 		$result .= " canopen=\"true\""; | ||||
| 	} | ||||
| 	if ($thread->agentId != $operator['operatorid'] && $thread->nextAgent != $operator['operatorid'] | ||||
| 		&& is_capable($can_viewthreads, $operator)) { | ||||
| 		$result .= " canview=\"true\""; | ||||
| 	} | ||||
| 	if (Settings::get('enableban') == "1") { | ||||
| 		$result .= " canban=\"true\""; | ||||
| 	} | ||||
| 
 | ||||
| 	$banForThread = Settings::get('enableban') == "1" ? ban_for_addr($thread->remote) : false; | ||||
| 	if ($banForThread) { | ||||
| 		$result .= " ban=\"blocked\" banid=\"" . $banForThread['banid'] . "\""; | ||||
| 	} | ||||
| 
 | ||||
| 	$result .= " state=\"$state\" typing=\"" . $thread->userTyping . "\">"; | ||||
| 	$result .= "<name>"; | ||||
| 	if ($banForThread) { | ||||
| 		$result .= htmlspecialchars(getstring('chat.client.spam.prefix')); | ||||
| 	} | ||||
| 	$result .= htmlspecialchars( | ||||
| 		htmlspecialchars(get_user_name($thread->userName, $thread->remote, $thread->userId)) | ||||
| 	) . "</name>"; | ||||
| 	$result .= "<addr>" . htmlspecialchars(get_user_addr($thread->remote)) . "</addr>"; | ||||
| 	$result .= "<agent>" . htmlspecialchars(htmlspecialchars($threadoperator)) . "</agent>"; | ||||
| 	$result .= "<time>" . $thread->created . "000</time>"; | ||||
| 	$result .= "<modified>" . $thread->modified . "000</modified>"; | ||||
| 
 | ||||
| 	if ($banForThread) { | ||||
| 		$result .= "<reason>" . $banForThread['comment'] . "</reason>"; | ||||
| 	} | ||||
| 
 | ||||
| 	$userAgent = get_useragent_version($thread->userAgent); | ||||
| 	$result .= "<useragent>" . $userAgent . "</useragent>"; | ||||
| 	if ($thread->shownMessageId != 0) { | ||||
| 		$db = Database::getInstance(); | ||||
| 		$line = $db->query( | ||||
| 			"select tmessage from {chatmessage} where messageid = ?", | ||||
| 			array($thread->shownMessageId), | ||||
| 			array('return_rows' => Database::RETURN_ONE_ROW) | ||||
| 		); | ||||
| 		if ($line) { | ||||
| 			$message = preg_replace("/[\r\n\t]+/", " ", $line["tmessage"]); | ||||
| 			$result .= "<message>" . htmlspecialchars(htmlspecialchars($message)) . "</message>"; | ||||
| 		} | ||||
| 	} | ||||
| 	$result .= "</thread>"; | ||||
| 	return $result; | ||||
| } | ||||
| 
 | ||||
| function print_pending_threads($groupids, $since) | ||||
| { | ||||
| 	global $webim_encoding; | ||||
| 	$db = Database::getInstance(); | ||||
| 
 | ||||
| 	$revision = $since; | ||||
| 	$query = "select {chatthread}.*, " . | ||||
| 		"(select vclocalname from {chatgroup} where {chatgroup}.groupid = {chatthread}.groupid) as groupname " . | ||||
| 		"from {chatthread} where lrevision > :since " . | ||||
| 		($since <= 0 | ||||
| 			? "AND istate <> " . Thread::STATE_CLOSED . " AND istate <> " . Thread::STATE_LEFT . " " | ||||
| 			: "") . | ||||
| 		(Settings::get('enablegroups') == '1' | ||||
| 			? "AND (groupid is NULL" . ($groupids | ||||
| 				? " OR groupid IN ($groupids) OR groupid IN (SELECT parent FROM {chatgroup} WHERE groupid IN ($groupids)) " | ||||
| 				: "") . | ||||
| 			") " | ||||
| 			: "") . | ||||
| 		"ORDER BY threadid"; | ||||
| 	$rows = $db->query( | ||||
| 		$query, | ||||
| 		array(':since' => $since), | ||||
| 		array('return_rows' => Database::RETURN_ALL_ROWS) | ||||
| 	); | ||||
| 
 | ||||
| 	$output = array(); | ||||
| 	foreach ($rows as $row) { | ||||
| 		$thread = Thread::createFromDbInfo($row); | ||||
| 		$thread_info = array( | ||||
| 			'thread' => $thread, | ||||
| 			'groupname' => $row['groupname'] | ||||
| 		); | ||||
| 		$thread_as_xml = thread_to_xml($thread_info); | ||||
| 		$output[] = $thread_as_xml; | ||||
| 		if ($thread->lastRevision > $revision) { | ||||
| 			$revision = $thread->lastRevision; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	echo "<threads revision=\"$revision\" time=\"" . time() . "000\">"; | ||||
| 	foreach ($output as $thr) { | ||||
| 		print myiconv($webim_encoding, "utf-8", $thr); | ||||
| 	} | ||||
| 	echo "</threads>"; | ||||
| } | ||||
| 
 | ||||
| function print_operators($operator) | ||||
| { | ||||
| 	global $webim_encoding; | ||||
| 	echo "<operators>"; | ||||
| 
 | ||||
| 	$list_options = in_isolation($operator)?array('isolated_operator_id' => $operator['operatorid']):array(); | ||||
| 	$operators = get_operators_list($list_options); | ||||
| 
 | ||||
| 	foreach ($operators as $operator) { | ||||
| 		if (!operator_is_online($operator)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		$name = myiconv($webim_encoding, "utf-8", htmlspecialchars(htmlspecialchars($operator['vclocalename']))); | ||||
| 		$away = operator_is_away($operator) ? " away=\"1\"" : ""; | ||||
| 
 | ||||
| 		echo "<operator name=\"$name\"$away/>";
 | ||||
| 	} | ||||
| 	echo "</operators>"; | ||||
| } | ||||
| 
 | ||||
| function visitor_to_xml($visitor) | ||||
| { | ||||
|     $result = "<visitor id=\"" . $visitor['visitorid'] . "\">"; | ||||
| 
 | ||||
| //    $result .= "<userid>" . htmlspecialchars($visitor['userid']) . "</userid>";
 | ||||
|     $result .= "<username>" . htmlspecialchars($visitor['username']) . "</username>"; | ||||
| 
 | ||||
|     $result .= "<time>" . $visitor['firsttime'] . "000</time>"; | ||||
|     $result .= "<modified>" . $visitor['lasttime'] . "000</modified>"; | ||||
| //    $result .= "<entry>" . htmlspecialchars($visitor['entry']) . "</entry>";
 | ||||
| 
 | ||||
| //    $result .= "<path>";
 | ||||
| //    $path = track_retrieve_path($visitor);
 | ||||
| //    ksort($path);
 | ||||
| //    foreach ($path as $k => $v) {
 | ||||
| //	$result .= "<url visited=\"" . $k . "000\">" . htmlspecialchars($v) . "</url>";
 | ||||
| //    }
 | ||||
| //    $result .= "</path>";
 | ||||
| 
 | ||||
|     $details = track_retrieve_details($visitor); | ||||
|     $userAgent = get_useragent_version($details['user_agent']); | ||||
|     $result .= "<useragent>" . $userAgent . "</useragent>"; | ||||
|     $result .= "<addr>" . htmlspecialchars(get_user_addr($details['remote_host'])) . "</addr>"; | ||||
| 
 | ||||
|     $result .= "<invitations>" . $visitor['invitations'] . "</invitations>"; | ||||
|     $result .= "<chats>" . $visitor['chats'] . "</chats>"; | ||||
| 
 | ||||
|     $result .= "<invitation>"; | ||||
|     if ($visitor['invited']) { | ||||
| 	$result .= "<invitationtime>" . $visitor['invitationtime'] . "000</invitationtime>"; | ||||
| 	$operator = get_operator_name(operator_by_id($visitor['invitedby'])); | ||||
| 	$result .= "<operator>" . htmlspecialchars(htmlspecialchars($operator)) . "</operator>"; | ||||
|     } | ||||
|     $result .= "</invitation>"; | ||||
| 
 | ||||
|     $result .= "</visitor>"; | ||||
|     return $result; | ||||
| } | ||||
| 
 | ||||
| function print_visitors() | ||||
| { | ||||
| 	global $webim_encoding; | ||||
| 
 | ||||
| 	$db = Database::getInstance(); | ||||
| 
 | ||||
| // Remove old visitors
 | ||||
| 	$db->query( | ||||
| 		"DELETE FROM {chatsitevisitor} " . | ||||
| 		"WHERE (:now - lasttime) > :lifetime ". | ||||
| 		"AND (threadid IS NULL OR " . | ||||
| 		"(SELECT count(*) FROM {chatthread} WHERE threadid = {chatsitevisitor}.threadid " . | ||||
| 		"AND istate <> " . Thread::STATE_CLOSED . " AND istate <> " . Thread::STATE_LEFT . ") = 0)", | ||||
| 		array( | ||||
| 			':lifetime' => Settings::get('tracking_lifetime'), | ||||
| 			':now' => time() | ||||
| 		) | ||||
| 	); | ||||
| 
 | ||||
| // Remove old invitations
 | ||||
| 	$db->query( | ||||
| 		"UPDATE {chatsitevisitor} SET invited = 0, invitationtime = NULL, invitedby = NULL". | ||||
| 		" WHERE threadid IS NULL AND (:now - invitationtime) > :lifetime", | ||||
| 		array( | ||||
| 			':lifetime' => Settings::get('invitation_lifetime'), | ||||
| 			':now' => time() | ||||
| 		) | ||||
| 	); | ||||
| 
 | ||||
| // Remove associations of visitors with closed threads
 | ||||
| 	$db->query( | ||||
| 		"UPDATE {chatsitevisitor} SET threadid = NULL WHERE threadid IS NOT NULL AND" . | ||||
| 		" (SELECT count(*) FROM {chatthread} WHERE threadid = {chatsitevisitor}.threadid" . | ||||
| 		" AND istate <> " . Thread::STATE_CLOSED . " AND istate <> " . Thread::STATE_LEFT . ") = 0" | ||||
| 	); | ||||
| 
 | ||||
| // Remove old visitors' tracks
 | ||||
| 	$db->query( | ||||
| 		"DELETE FROM {visitedpage} WHERE (:now - visittime) > :lifetime " . | ||||
| 		" AND visitorid NOT IN (SELECT visitorid FROM {chatsitevisitor})", | ||||
| 		array( | ||||
| 			':lifetime' => Settings::get('tracking_lifetime'), | ||||
| 			':now' => time() | ||||
| 		) | ||||
| 	); | ||||
| 
 | ||||
| 	$query = "SELECT visitorid, userid, username, firsttime, lasttime, " . | ||||
| 			 "entry, details, invited, invitationtime, invitedby, invitations, chats " . | ||||
| 			 "FROM {chatsitevisitor} " . | ||||
| 			 "WHERE threadid IS NULL " . | ||||
| 			 "ORDER BY invited, lasttime DESC, invitations"; | ||||
| 	$query .= (Settings::get('visitors_limit') == '0') ? "" : " LIMIT " . Settings::get('visitors_limit'); | ||||
| 	 | ||||
| 	$rows = $db->query($query, NULL, array('return_rows' => Database::RETURN_ALL_ROWS)); | ||||
| 	 | ||||
| 	$output = array(); | ||||
| 	foreach ($rows as $row) { | ||||
| 		$visitor = visitor_to_xml($row); | ||||
| 		$output[] = $visitor; | ||||
| 	} | ||||
| 
 | ||||
| 	echo "<visitors>"; | ||||
| 	foreach ($output as $thr) { | ||||
| 		print myiconv($webim_encoding, "utf-8", $thr); | ||||
| 	} | ||||
| 	echo "</visitors>"; | ||||
| } | ||||
| 
 | ||||
| $since = verifyparam("since", "/^\d{1,9}$/", 0); | ||||
| $status = verifyparam("status", "/^\d{1,2}$/", 0); | ||||
| $showonline = verifyparam("showonline", "/^1$/", 0); | ||||
| $showvisitors = verifyparam("showvisitors", "/^1$/", 0); | ||||
| 
 | ||||
| if (!isset($_SESSION["${mysqlprefix}operatorgroups"])) { | ||||
| 	$_SESSION["${mysqlprefix}operatorgroups"] = get_operator_groupslist($operator['operatorid']); | ||||
| } | ||||
| Thread::closeOldThreads(); | ||||
| $groupids = $_SESSION["${mysqlprefix}operatorgroups"]; | ||||
| 
 | ||||
| start_xml_output(); | ||||
| echo '<update>'; | ||||
| if ($showonline) { | ||||
| 	print_operators($operator); | ||||
| } | ||||
| print_pending_threads($groupids, $since); | ||||
| if ($showvisitors) { | ||||
| 	print_visitors(); | ||||
| } | ||||
| echo '</update>'; | ||||
| notify_operator_alive($operator['operatorid'], $status); | ||||
| exit; | ||||
| $processor = UsersProcessor::getInstance(); | ||||
| $processor->receiveRequest($_POST['data']); | ||||
| 
 | ||||
| ?>
 | ||||
| @ -35,6 +35,22 @@ $page['frequency'] = Settings::get('updatefrequency_operator'); | ||||
| $page['istatus'] = $status; | ||||
| $page['showonline'] = Settings::get('showonlineoperators') == '1' ? "1" : "0"; | ||||
| $page['showvisitors'] = Settings::get('enabletracking') == '1' ? "1" : "0"; | ||||
| $page['agentId'] = $operator['operatorid']; | ||||
| $page['geoLink'] = Settings::get('geolink'); | ||||
| $page['geoWindowParams'] = Settings::get('geolinkparams'); | ||||
| 
 | ||||
| // Load dialogs style options
 | ||||
| $style_config = get_dialogs_style_config(getchatstyle()); | ||||
| $page['chatStyles.chatWindowParams'] = $style_config['chat']['window_params']; | ||||
| 
 | ||||
| // Load core style options
 | ||||
| $style_config = get_core_style_config(); | ||||
| $page['coreStyles.threadTag'] = $style_config['users']['thread_tag']; | ||||
| $page['coreStyles.visitorTag'] = $style_config['users']['visitor_tag']; | ||||
| $page['coreStyles.trackedUserWindowParams'] = $style_config['tracked']['user_window_params']; | ||||
| $page['coreStyles.trackedVisitorWindowParams'] = $style_config['tracked']['visitor_window_params']; | ||||
| $page['coreStyles.inviteWindowParams'] = $style_config['invitation']['window_params']; | ||||
| $page['coreStyles.banWindowParams'] = $style_config['ban']['window_params']; | ||||
| 
 | ||||
| prepare_menu($operator); | ||||
| start_html_output(); | ||||
|  | ||||
| @ -4,3 +4,22 @@ | ||||
| [history] | ||||
| ; window_param use as param string in JavaScript window.open method | ||||
| window_params = "toolbar=0,scrollbars=0,location=0,status=1,menubar=0,width=720,height=560,resizable=1" | ||||
| 
 | ||||
| [users] | ||||
| ; Use as wrap tag for the thread element | ||||
| thread_tag = "tr" | ||||
| ; Use as wrap tag for the visitor element | ||||
| visitor_tag = "tr" | ||||
| 
 | ||||
| [tracked] | ||||
| ; window_param use as param string in JavaScript window.open method | ||||
| user_window_params = "toolbar=0,scrollbars=0,location=0,status=1,menubar=0,width=640,height=480,resizable=1" | ||||
| visitor_window_params = "toolbar=0,scrollbars=1,location=0,status=1,menubar=0,width=640,height=480,resizable=1" | ||||
| 
 | ||||
| [invitation] | ||||
| ; window_param use as param string in JavaScript window.open method | ||||
| window_params = "toolbar=0,scrollbars=0,location=0,status=1,menubar=0,width=640,height=480,resizable=1" | ||||
| 
 | ||||
| [ban] | ||||
| ; window_param use as param string in JavaScript window.open method | ||||
| window_params = "toolbar=0,scrollbars=0,location=0,status=1,menubar=0,width=720,height=480,resizable=1" | ||||
|  | ||||
| @ -30,6 +30,7 @@ $isrtl = getlocal("localedirection") == 'rtl'; | ||||
| 	<?php echo $page['title'] ?> - <?php echo getlocal("app.title") ?>
 | ||||
| </title> | ||||
| <link href="<?php echo $webimroot ?>/default.css" rel="stylesheet" type="text/css" /> | ||||
| <!--[if lte IE 7]><link href="<?php echo $webimroot ?>/default_ie.css" rel="stylesheet" type="text/css" /><![endif] --> | ||||
| <!--[if lte IE 6]><script language="JavaScript" type="text/javascript" src="<?php echo $webimroot ?>/<?php echo jspath() ?>/ie.js"></script><![endif]--> | ||||
| </head> | ||||
| <body<?php if(!function_exists('tpl_menu')) { ?> style="min-width: 400px;"<?php } ?>>
 | ||||
|  | ||||
| @ -21,29 +21,98 @@ $page['menuid'] = "users"; | ||||
| 
 | ||||
| 
 | ||||
| function tpl_header() { global $page, $webimroot; | ||||
| ?>	
 | ||||
| <script type="text/javascript" language="javascript" src="<?php echo $webimroot ?>/js/compiled/common.js"></script> | ||||
| <script type="text/javascript" language="javascript"><!-- | ||||
| var localized = new Array( | ||||
|     "<?php echo getlocal("pending.table.speak") ?>", | ||||
|     "<?php echo getlocal("pending.table.view") ?>", | ||||
|     "<?php echo getlocal("pending.table.ban") ?>", | ||||
|     "<?php echo htmlspecialchars(getlocal("pending.menu.show")) ?>", | ||||
|     "<?php echo htmlspecialchars(getlocal("pending.menu.hide")) ?>", | ||||
|     "<?php echo htmlspecialchars(getlocal("pending.popup_notification")) ?>", | ||||
|     "<?php echo getlocal("pending.table.tracked") ?>", | ||||
|     "<?php echo getlocal("pending.table.invite") ?>", | ||||
|     "<?php echo getlocal("pending.status.away") ?>", | ||||
|     "<?php echo getlocal("pending.status.online") ?>" | ||||
| ); | ||||
| var updaterOptions = { | ||||
| 	url:"<?php echo $webimroot ?>/operator/update.php",wroot:"<?php echo $webimroot ?>", | ||||
| 	agentservl:"<?php echo $webimroot ?>/operator/agent.php", frequency:<?php echo $page['frequency'] ?>, istatus:<?php echo $page['istatus'] ?>,  
 | ||||
| 	noclients:"<?php echo getlocal("clients.no_clients") ?>", havemenu: <?php echo $page['havemenu'] ?>, showpopup: <?php echo $page['showpopup'] ?>,
 | ||||
| 	showonline: <?php echo $page['showonline'] ?>, showvisitors: <?php echo $page['showvisitors'] ?>, novisitors: "<?php echo getlocal("visitors.no_visitors") ?>",
 | ||||
| 	trackedservl:"<?php echo $webimroot ?>/operator/tracked.php", inviteservl:"<?php echo $webimroot ?>/operator/invite.php" }; | ||||
| ?>
 | ||||
| <!-- External libs --> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/jquery.min.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/json2.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/underscore-min.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/backbone-min.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/backbone.marionette.min.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/handlebars.js"></script> | ||||
| 
 | ||||
| <!-- Application files --> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/compiled/mibewapi.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/compiled/default_app.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/compiled/users_app.js"></script> | ||||
| 
 | ||||
| <script type="text/javascript"><!-- | ||||
| 	Mibew.Localization.set({ | ||||
| 		'pending.table.speak': "<?php echo getlocal('pending.table.speak') ?>", | ||||
| 		'pending.table.view': "<?php echo getlocal('pending.table.view') ?>", | ||||
| 		'pending.table.ban': "<?php echo getlocal('pending.table.ban') ?>", | ||||
| 		'pending.menu.show': "<?php echo htmlspecialchars(getlocal('pending.menu.show')) ?>", | ||||
| 		'pending.menu.hide': "<?php echo htmlspecialchars(getlocal('pending.menu.hide')) ?>", | ||||
| 		'pending.popup_notification': "<?php echo htmlspecialchars(getlocal('pending.popup_notification')) ?>", | ||||
| 		'pending.table.tracked': "<?php echo getlocal('pending.table.tracked') ?>", | ||||
| 		'pending.table.invite': "<?php echo getlocal('pending.table.invite') ?>", | ||||
| 		'pending.status.away': "<?php echo getlocal('pending.status.away') ?>", | ||||
| 		'pending.status.online': "<?php echo getlocal('pending.status.online') ?>", | ||||
| 		'pending.status.setonline': "<?php echo addslashes(getlocal('pending.status.setonline')) ?>", | ||||
| 		'pending.status.setaway': "<?php echo addslashes(getlocal('pending.status.setaway')) ?>", | ||||
| 		'pending.table.head.name': "<?php echo getlocal('pending.table.head.name') ?>", | ||||
| 		'pending.table.head.actions': "<?php echo getlocal('pending.table.head.actions') ?>", | ||||
| 		'pending.table.head.contactid': "<?php echo getlocal('pending.table.head.contactid') ?>", | ||||
| 		'pending.table.head.state': "<?php echo getlocal('pending.table.head.state') ?>", | ||||
| 		'pending.table.head.operator': "<?php echo getlocal('pending.table.head.operator') ?>", | ||||
| 		'pending.table.head.total': "<?php echo getlocal('pending.table.head.total') ?>", | ||||
| 		'pending.table.head.waittime': "<?php echo getlocal('pending.table.head.waittime') ?>", | ||||
| 		'pending.table.head.etc': "<?php echo getlocal('pending.table.head.etc') ?>", | ||||
| 		'visitors.table.head.actions': "<?php echo getlocal('visitors.table.head.actions') ?>", | ||||
| 		'visitors.table.head.name': "<?php echo getlocal('visitors.table.head.name') ?>", | ||||
| 		'visitors.table.head.contactid': "<?php echo getlocal('visitors.table.head.contactid') ?>", | ||||
| 		'visitors.table.head.firsttimeonsite': "<?php echo getlocal('visitors.table.head.firsttimeonsite') ?>", | ||||
| 		'visitors.table.head.lasttimeonsite': "<?php echo getlocal('visitors.table.head.lasttimeonsite') ?>", | ||||
| 		'visitors.table.head.invited.by': "<?php echo getlocal('visitors.table.head.invited.by') ?>", | ||||
| 		'visitors.table.head.invitationtime': "<?php echo getlocal('visitors.table.head.invitationtime') ?>", | ||||
| 		'visitors.table.head.invitations': "<?php echo getlocal('visitors.table.head.invitations') ?>", | ||||
| 		'visitors.table.head.etc': "<?php echo getlocal('visitors.table.head.etc') ?>", | ||||
| 		'visitors.no_visitors': "<?php echo getlocal('visitors.no_visitors') ?>", | ||||
| 		'clients.no_clients': "<?php echo getlocal('clients.no_clients') ?>", | ||||
| 		'chat.thread.state_wait': "<?php echo getlocal('chat.thread.state_wait'); ?>", | ||||
| 		'chat.thread.state_wait_for_another_agent': "<?php echo getlocal('chat.thread.state_wait_for_another_agent'); ?>", | ||||
| 		'chat.thread.state_chatting_with_agent': "<?php echo getlocal('chat.thread.state_chatting_with_agent'); ?>", | ||||
| 		'chat.thread.state_closed': "<?php echo getlocal('chat.thread.state_closed'); ?>", | ||||
| 		'chat.thread.state_loading': "<?php echo getlocal('chat.thread.state_loading'); ?>", | ||||
| 		'chat.client.spam.prefix': "<?php echo getstring('chat.client.spam.prefix'); ?>" | ||||
| 	}); | ||||
| //--></script>
 | ||||
| <script type="text/javascript" language="javascript" src="<?php echo $webimroot ?>/js/compiled/users.js"></script> | ||||
| 
 | ||||
| <script type="text/javascript"><!-- | ||||
| 	jQuery(document).ready(function(){ | ||||
| 		Mibew.Application.start({ | ||||
| 			server: { | ||||
| 				url: "<?php echo $webimroot ?>/operator/update.php", | ||||
| 				requestsFrequency: <?php echo $page['frequency'] ?>
 | ||||
| 			}, | ||||
| 
 | ||||
| 			agent: { | ||||
| 				id: <?php echo $page['agentId'] ?>
 | ||||
| 			}, | ||||
| 
 | ||||
| 			page: { | ||||
| 				showOnlineOperators: <?php echo($page['showonline']?'true':'false'); ?>,
 | ||||
| 				showVisitors: <?php echo ($page['showvisitors']?'true':'false'); ?>,
 | ||||
| 
 | ||||
| 				threadTag: "<?php echo $page['coreStyles.threadTag']; ?>", | ||||
| 				visitorTag: "<?php echo $page['coreStyles.visitorTag']; ?>", | ||||
| 
 | ||||
| 				agentLink: "<?php echo $webimroot ?>/operator/agent.php", | ||||
| 				geoLink: "<?php echo $page['geoLink']; ?>", | ||||
| 				trackedLink: "<?php echo $webimroot ?>/operator/tracked.php", | ||||
| 				banLink: "<?php echo $webimroot ?>/operator/ban.php", | ||||
| 				inviteLink: "<?php echo $webimroot ?>/operator/invite.php", | ||||
| 
 | ||||
| 				chatWindowParams: "<?php echo $page['chatStyles.chatWindowParams']; ?>", | ||||
| 				geoWindowParams: "<?php echo $page['geoWindowParams'];?>", | ||||
| 				trackedUserWindowParams: "<?php echo $page['coreStyles.trackedUserWindowParams']; ?>", | ||||
| 				trackedVisitorWindowParams: "<?php echo $page['coreStyles.trackedVisitorWindowParams']; ?>", | ||||
| 				banWindowParams: "<?php echo $page['coreStyles.banWindowParams']; ?>", | ||||
| 				inviteWindowParams: "<?php echo $page['coreStyles.inviteWindowParams']; ?>" | ||||
| 			} | ||||
| 		}); | ||||
| 	}); | ||||
| //--></script>
 | ||||
| 
 | ||||
| <?php | ||||
| } | ||||
| 
 | ||||
| @ -51,89 +120,27 @@ function tpl_content() { global $page, $webimroot; | ||||
| ?>
 | ||||
| 
 | ||||
| <div> | ||||
| <div id="togglediv"> | ||||
| <a href="#" id="togglemenu"></a> | ||||
| </div> | ||||
| 
 | ||||
| <?php echo getlocal("clients.intro") ?>
 | ||||
| <br/> | ||||
| <?php echo getlocal("clients.how_to") ?>
 | ||||
| </div> | ||||
| <br/> | ||||
| 
 | ||||
| <table id="threadlist" class="awaiting" border="0"> | ||||
| <thead> | ||||
| <tr> | ||||
| 	<th class="first"><?php echo getlocal("pending.table.head.name") ?></th>
 | ||||
| 	<th><?php echo getlocal("pending.table.head.actions") ?></th>
 | ||||
| 	<th><?php echo getlocal("pending.table.head.contactid") ?></th>
 | ||||
|     <th><?php echo getlocal("pending.table.head.state") ?></th>
 | ||||
|     <th><?php echo getlocal("pending.table.head.operator") ?></th>
 | ||||
|     <th><?php echo getlocal("pending.table.head.total") ?></th>
 | ||||
|     <th><?php echo getlocal("pending.table.head.waittime") ?></th>
 | ||||
|     <th><?php echo getlocal("pending.table.head.etc") ?></th>
 | ||||
| </tr> | ||||
| </thead> | ||||
| <tbody> | ||||
| <tr id="tprio"><td colspan="8"></td></tr> | ||||
| <tr id="tprioend"><td colspan="8"></td></tr> | ||||
| 
 | ||||
| <tr id="twait"><td colspan="8"></td></tr> | ||||
| <tr id="twaitend"><td colspan="8"></td></tr> | ||||
| 
 | ||||
| <tr id="tchat"><td colspan="8"></td></tr> | ||||
| <tr id="tchatend"><td colspan="8"></td></tr> | ||||
| 
 | ||||
| <tr><td id="statustd" colspan="8" height="30">Loading....</td></tr> | ||||
| </tbody> | ||||
| </table> | ||||
| <div id="threads-region"></div> | ||||
| 
 | ||||
| <?php if ($page['showvisitors']) { ?>
 | ||||
| <div class="tabletitle"><?php echo getlocal("visitors.title") ?></div>
 | ||||
| <?php echo getlocal("visitors.intro") ?>
 | ||||
| <br/> | ||||
| <?php echo getlocal("visitors.how_to") ?>
 | ||||
| <table id="visitorslist" class="awaiting" border="0"> | ||||
| <thead> | ||||
| <tr> | ||||
| 	<th class="first"><?php echo getlocal("visitors.table.head.name") ?></th>
 | ||||
|     <th><?php echo getlocal("visitors.table.head.contactid") ?></th>
 | ||||
|     <th><?php echo getlocal("visitors.table.head.firsttimeonsite") ?></th>
 | ||||
|     <th><?php echo getlocal("visitors.table.head.lasttimeonsite") ?></th>
 | ||||
|     <th><?php echo getlocal("visitors.table.head.invited.by") ?></th>
 | ||||
|     <th><?php echo getlocal("visitors.table.head.invitationtime") ?></th>
 | ||||
|     <th><?php echo getlocal("visitors.table.head.invitations") ?></th>
 | ||||
|     <th><?php echo getlocal("visitors.table.head.etc") ?></th>
 | ||||
| </tr> | ||||
| </thead> | ||||
| <tbody> | ||||
| <tr id="visfree"><td colspan="8"></td></tr> | ||||
| <tr id="visfreeend"><td colspan="8"></td></tr> | ||||
| 
 | ||||
| <tr id="visinvited"><td colspan="8"></td></tr> | ||||
| <tr id="visinvitedend"><td colspan="8"></td></tr> | ||||
| 
 | ||||
| <tr><td id="visstatustd" colspan="8" height="30">Loading....</td></tr> | ||||
| </tbody> | ||||
| </table> | ||||
| <div id="visitors-region"></div> | ||||
| <hr/> | ||||
| <?php } ?>
 | ||||
| 
 | ||||
| <div id="connstatus"> | ||||
| </div> | ||||
| 
 | ||||
| <div id="connlinks"> | ||||
| <?php if($page['istatus']) { ?>
 | ||||
| <a href="users.php<?php echo $page['havemenu'] ? "" : "?nomenu" ?>"><?php echo getlocal("pending.status.setonline") ?></a>
 | ||||
| <?php } else { ?>
 | ||||
| <a href="users.php?away<?php echo $page['havemenu'] ? "" : "&nomenu" ?>"><?php echo getlocal("pending.status.setaway") ?></a>
 | ||||
| <?php } ?>
 | ||||
| </div> | ||||
| 
 | ||||
| <?php if($page['showonline'] == "1") { ?>
 | ||||
| <div id="onlineoperators"> | ||||
| </div> | ||||
| <?php } ?>
 | ||||
| 
 | ||||
| <div id="status-panel-region"></div> | ||||
| <div id="agents-region"></div> | ||||
| <div id="sound-region"></div> | ||||
| <?php  | ||||
| } /* content */ | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user