mirror of
https://github.com/Mibew/i18n.git
synced 2025-01-22 21:40:28 +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
|
default_app_js - Build JavaScript files related to default application
|
||||||
chat_app_js - Build JavaScript files related to chat 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
|
core_handlebars - Compile Handlebars templates of the Core
|
||||||
|
|
||||||
@ -263,6 +264,14 @@
|
|||||||
<echo>Chat JavaScript application built.</echo>
|
<echo>Chat JavaScript application built.</echo>
|
||||||
</target>
|
</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 -->
|
<!-- Compile Handlebars templates of the Core -->
|
||||||
<target name="core_handlebars">
|
<target name="core_handlebars">
|
||||||
<echo>Compile Handlebars templates of the Core</echo>
|
<echo>Compile Handlebars templates of the Core</echo>
|
||||||
@ -292,7 +301,7 @@
|
|||||||
</target>
|
</target>
|
||||||
|
|
||||||
<!-- Build all project -->
|
<!-- 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>
|
<echo>Mibew Messenger built.</echo>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
@ -86,6 +86,10 @@ a {
|
|||||||
height:40px;
|
height:40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inline-block {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
#footer {
|
#footer {
|
||||||
background: white url(images/footer.gif) bottom repeat-x;
|
background: white url(images/footer.gif) bottom repeat-x;
|
||||||
font-size:11px;
|
font-size:11px;
|
||||||
@ -557,8 +561,11 @@ table.awaiting td.visitor {
|
|||||||
border-bottom: 1px solid #ccc;
|
border-bottom: 1px solid #ccc;
|
||||||
padding: 10px 8px;
|
padding: 10px 8px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
table.awaiting .no-threads, table.awaiting .no-visitors {
|
||||||
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.awaiting .visitor a { color: #296685; }
|
.awaiting .visitor a { color: #296685; }
|
||||||
.awaiting tr:hover .visitor, .awaiting tr:hover .visitor a { color: #1D485E; }
|
.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:hover .visitor, .awaiting tr.inchat:hover .visitor a { color: #444; }
|
||||||
.awaiting tr.inchat a { text-decoration: none; }
|
.awaiting tr.inchat a { text-decoration: none; }
|
||||||
|
|
||||||
.firstmessage {
|
.first-message {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.firstmessage a {
|
.first-message a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.firstmessage a:hover {
|
.first-message a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#status-panel-region {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
#connstatus {
|
#connstatus {
|
||||||
float:right;
|
float:right;
|
||||||
margin: 10px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#connlinks {
|
|
||||||
margin: 10px 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#connlinks a {
|
#connlinks a {
|
||||||
@ -603,12 +609,64 @@ table.awaiting td.visitor {
|
|||||||
text-decoration: underline;
|
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 */
|
/* online operators */
|
||||||
|
|
||||||
#onlineoperators {
|
#agents-region {
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
float: right;
|
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 */
|
/* 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(
|
$config += array(
|
||||||
'history' => array(
|
'history' => array(
|
||||||
'window_params' => ''
|
'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.came.from=Vistor came from page {0}
|
||||||
chat.client.changename=Change name
|
chat.client.changename=Change name
|
||||||
chat.client.name=You are
|
chat.client.name=You are
|
||||||
chat.client.spam.prefix=[spam]
|
chat.client.spam.prefix=[spam]
|
||||||
chat.client.visited.page=Visitor navigated to {0}
|
chat.client.visited.page=Visitor navigated to {0}
|
||||||
chat.close.confirmation=Are you sure want to leave chat?
|
chat.close.confirmation=Are you sure want to leave chat?
|
||||||
chat.default.username=Guest
|
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.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.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.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.contactid=Visitor's address
|
||||||
visitors.table.head.etc=Misc
|
visitors.table.head.etc=Misc
|
||||||
visitors.table.head.firsttimeonsite=First seen
|
visitors.table.head.firsttimeonsite=First seen
|
||||||
|
@ -40,7 +40,7 @@ char.redirect.operator.online_suff=(
|
|||||||
chat.came.from=Посетитель пришел со страницы {0}
|
chat.came.from=Посетитель пришел со страницы {0}
|
||||||
chat.client.changename=Изменить имя
|
chat.client.changename=Изменить имя
|
||||||
chat.client.name=Вы
|
chat.client.name=Вы
|
||||||
chat.client.spam.prefix=[ñïàì]
|
chat.client.spam.prefix=[ñïàì]
|
||||||
chat.client.visited.page=Посетитель перешел на {0}
|
chat.client.visited.page=Посетитель перешел на {0}
|
||||||
chat.close.confirmation=Вы действительно хотите покинуть диалог?
|
chat.close.confirmation=Вы действительно хотите покинуть диалог?
|
||||||
chat.default.username=Посетитель
|
chat.default.username=Посетитель
|
||||||
@ -617,6 +617,7 @@ updates.title=
|
|||||||
visitors.how_to=Для приглашения посетителя к диалогу кликните на его или её имя в списке.
|
visitors.how_to=Для приглашения посетителя к диалогу кликните на его или её имя в списке.
|
||||||
visitors.intro=В расположенной ниже таблице представлен список готовых к диалогу посетителей на Вашем сайте.
|
visitors.intro=В расположенной ниже таблице представлен список готовых к диалогу посетителей на Вашем сайте.
|
||||||
visitors.no_visitors=В настоящее время на Вашем сайте нет готовых к диалогу посетителей
|
visitors.no_visitors=В настоящее время на Вашем сайте нет готовых к диалогу посетителей
|
||||||
|
visitors.table.head.actions=Äåéñòâèÿ
|
||||||
visitors.table.head.contactid=Адрес посетителя
|
visitors.table.head.contactid=Адрес посетителя
|
||||||
visitors.table.head.etc=Разное
|
visitors.table.head.etc=Разное
|
||||||
visitors.table.head.firsttimeonsite=Впервые замечен
|
visitors.table.head.firsttimeonsite=Впервые замечен
|
||||||
|
@ -22,298 +22,14 @@ require_once('../libs/operator.php');
|
|||||||
require_once('../libs/groups.php');
|
require_once('../libs/groups.php');
|
||||||
require_once('../libs/track.php');
|
require_once('../libs/track.php');
|
||||||
require_once('../libs/classes/thread.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();
|
$processor = UsersProcessor::getInstance();
|
||||||
if (!$operator) {
|
$processor->receiveRequest($_POST['data']);
|
||||||
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;
|
|
||||||
|
|
||||||
?>
|
?>
|
@ -35,6 +35,22 @@ $page['frequency'] = Settings::get('updatefrequency_operator');
|
|||||||
$page['istatus'] = $status;
|
$page['istatus'] = $status;
|
||||||
$page['showonline'] = Settings::get('showonlineoperators') == '1' ? "1" : "0";
|
$page['showonline'] = Settings::get('showonlineoperators') == '1' ? "1" : "0";
|
||||||
$page['showvisitors'] = Settings::get('enabletracking') == '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);
|
prepare_menu($operator);
|
||||||
start_html_output();
|
start_html_output();
|
||||||
|
@ -4,3 +4,22 @@
|
|||||||
[history]
|
[history]
|
||||||
; window_param use as param string in JavaScript window.open method
|
; 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"
|
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") ?>
|
<?php echo $page['title'] ?> - <?php echo getlocal("app.title") ?>
|
||||||
</title>
|
</title>
|
||||||
<link href="<?php echo $webimroot ?>/default.css" rel="stylesheet" type="text/css" />
|
<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]-->
|
<!--[if lte IE 6]><script language="JavaScript" type="text/javascript" src="<?php echo $webimroot ?>/<?php echo jspath() ?>/ie.js"></script><![endif]-->
|
||||||
</head>
|
</head>
|
||||||
<body<?php if(!function_exists('tpl_menu')) { ?> style="min-width: 400px;"<?php } ?>>
|
<body<?php if(!function_exists('tpl_menu')) { ?> style="min-width: 400px;"<?php } ?>>
|
||||||
|
@ -22,28 +22,97 @@ $page['menuid'] = "users";
|
|||||||
|
|
||||||
function tpl_header() { global $page, $webimroot;
|
function tpl_header() { global $page, $webimroot;
|
||||||
?>
|
?>
|
||||||
<script type="text/javascript" language="javascript" src="<?php echo $webimroot ?>/js/compiled/common.js"></script>
|
<!-- External libs -->
|
||||||
<script type="text/javascript" language="javascript"><!--
|
<script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/jquery.min.js"></script>
|
||||||
var localized = new Array(
|
<script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/json2.js"></script>
|
||||||
"<?php echo getlocal("pending.table.speak") ?>",
|
<script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/underscore-min.js"></script>
|
||||||
"<?php echo getlocal("pending.table.view") ?>",
|
<script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/backbone-min.js"></script>
|
||||||
"<?php echo getlocal("pending.table.ban") ?>",
|
<script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/backbone.marionette.min.js"></script>
|
||||||
"<?php echo htmlspecialchars(getlocal("pending.menu.show")) ?>",
|
<script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/handlebars.js"></script>
|
||||||
"<?php echo htmlspecialchars(getlocal("pending.menu.hide")) ?>",
|
|
||||||
"<?php echo htmlspecialchars(getlocal("pending.popup_notification")) ?>",
|
<!-- Application files -->
|
||||||
"<?php echo getlocal("pending.table.tracked") ?>",
|
<script type="text/javascript" src="<?php echo $webimroot ?>/js/compiled/mibewapi.js"></script>
|
||||||
"<?php echo getlocal("pending.table.invite") ?>",
|
<script type="text/javascript" src="<?php echo $webimroot ?>/js/compiled/default_app.js"></script>
|
||||||
"<?php echo getlocal("pending.status.away") ?>",
|
<script type="text/javascript" src="<?php echo $webimroot ?>/js/compiled/users_app.js"></script>
|
||||||
"<?php echo getlocal("pending.status.online") ?>"
|
|
||||||
);
|
<script type="text/javascript"><!--
|
||||||
var updaterOptions = {
|
Mibew.Localization.set({
|
||||||
url:"<?php echo $webimroot ?>/operator/update.php",wroot:"<?php echo $webimroot ?>",
|
'pending.table.speak': "<?php echo getlocal('pending.table.speak') ?>",
|
||||||
agentservl:"<?php echo $webimroot ?>/operator/agent.php", frequency:<?php echo $page['frequency'] ?>, istatus:<?php echo $page['istatus'] ?>,
|
'pending.table.view': "<?php echo getlocal('pending.table.view') ?>",
|
||||||
noclients:"<?php echo getlocal("clients.no_clients") ?>", havemenu: <?php echo $page['havemenu'] ?>, showpopup: <?php echo $page['showpopup'] ?>,
|
'pending.table.ban': "<?php echo getlocal('pending.table.ban') ?>",
|
||||||
showonline: <?php echo $page['showonline'] ?>, showvisitors: <?php echo $page['showvisitors'] ?>, novisitors: "<?php echo getlocal("visitors.no_visitors") ?>",
|
'pending.menu.show': "<?php echo htmlspecialchars(getlocal('pending.menu.show')) ?>",
|
||||||
trackedservl:"<?php echo $webimroot ?>/operator/tracked.php", inviteservl:"<?php echo $webimroot ?>/operator/invite.php" };
|
'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>
|
||||||
<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
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,89 +120,27 @@ function tpl_content() { global $page, $webimroot;
|
|||||||
?>
|
?>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div id="togglediv">
|
|
||||||
<a href="#" id="togglemenu"></a>
|
|
||||||
</div>
|
|
||||||
<?php echo getlocal("clients.intro") ?>
|
<?php echo getlocal("clients.intro") ?>
|
||||||
<br/>
|
<br/>
|
||||||
<?php echo getlocal("clients.how_to") ?>
|
<?php echo getlocal("clients.how_to") ?>
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<table id="threadlist" class="awaiting" border="0">
|
<div id="threads-region"></div>
|
||||||
<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>
|
|
||||||
|
|
||||||
<?php if ($page['showvisitors']) { ?>
|
<?php if ($page['showvisitors']) { ?>
|
||||||
<div class="tabletitle"><?php echo getlocal("visitors.title") ?></div>
|
<div class="tabletitle"><?php echo getlocal("visitors.title") ?></div>
|
||||||
<?php echo getlocal("visitors.intro") ?>
|
<?php echo getlocal("visitors.intro") ?>
|
||||||
<br/>
|
<br/>
|
||||||
<?php echo getlocal("visitors.how_to") ?>
|
<?php echo getlocal("visitors.how_to") ?>
|
||||||
<table id="visitorslist" class="awaiting" border="0">
|
<div id="visitors-region"></div>
|
||||||
<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>
|
|
||||||
<hr/>
|
<hr/>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
|
|
||||||
<div id="connstatus">
|
<div id="status-panel-region"></div>
|
||||||
</div>
|
<div id="agents-region"></div>
|
||||||
|
<div id="sound-region"></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 } ?>
|
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
} /* content */
|
} /* content */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user