mirror of
https://github.com/Mibew/i18n.git
synced 2025-01-22 13:30:29 +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