mirror of
				https://github.com/Mibew/i18n.git
				synced 2025-11-01 01:36:57 +03:00 
			
		
		
		
	Completely rewrite invitations
This commit is contained in:
		
							parent
							
								
									a2db90289a
								
							
						
					
					
						commit
						3994b924de
					
				| @ -334,14 +334,6 @@ | ||||
|     </target> | ||||
| 
 | ||||
| 
 | ||||
|     <!-- Compile and concatenate JavaScript files related to invite application --> | ||||
|     <target name="invite_app_js" depends="default_app_js" description="Build JavaScript files related to invite application"> | ||||
|         <antcall target="app_js"> | ||||
|             <param name="app_name" value="invite" /> | ||||
|         </antcall> | ||||
|         <echo>Invite JavaScript application built.</echo> | ||||
|     </target> | ||||
| 
 | ||||
| 
 | ||||
|     <!-- Compile and concatenate JavaScript files related to users application --> | ||||
|     <target name="users_app_js" depends="default_app_js" description="Build JavaScript files related to users application"> | ||||
| @ -430,7 +422,7 @@ | ||||
| 
 | ||||
| 
 | ||||
|     <!-- Build all project --> | ||||
|     <target name="all" depends="chat_app_js,invite_app_js,thread_log_app_js,users_app_js,styles_all" description="Build everything"> | ||||
|     <target name="all" depends="chat_app_js,thread_log_app_js,users_app_js,styles_all" description="Build everything"> | ||||
|         <echo>Mibew Messenger built.</echo> | ||||
|     </target> | ||||
| 
 | ||||
|  | ||||
| @ -47,6 +47,24 @@ if (get_remote_level($_SERVER['HTTP_USER_AGENT']) == 'old') { | ||||
| 	exit; | ||||
| } | ||||
| 
 | ||||
| if (verifyparam("act", "/^(invitation)$/", "default") == 'invitation') { | ||||
| 	// Check if user invited to chat
 | ||||
| 	$invitation_state = invitation_state($_SESSION['visitorid']); | ||||
| 
 | ||||
| 	if ($invitation_state['invited'] && $invitation_state['threadid']) { | ||||
| 		$thread = Thread::load($invitation_state['threadid']); | ||||
| 
 | ||||
| 		// Prepare page
 | ||||
| 		$page = setup_invitation_view($thread); | ||||
| 
 | ||||
| 		// Build js application options
 | ||||
| 		$page['invitationOptions'] = json_encode($page['invitation']); | ||||
| 		// Expand page
 | ||||
| 		expand("styles/dialogs", getchatstyle(), "chat.tpl"); | ||||
| 		exit; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| if( !isset($_GET['token']) || !isset($_GET['thread']) ) { | ||||
| 
 | ||||
| 	$thread = NULL; | ||||
| @ -107,8 +125,7 @@ if( !isset($_GET['token']) || !isset($_GET['thread']) ) { | ||||
| 		// Get invitation info
 | ||||
| 		if (Settings::get('enabletracking')) { | ||||
| 			$invitation_state = invitation_state($_SESSION['visitorid']); | ||||
| 			$visitor_is_invited = $invitation_state['invited'] | ||||
| 				&& !$invitation_state['threadid']; | ||||
| 			$visitor_is_invited = $invitation_state['invited']; | ||||
| 		} else { | ||||
| 			$visitor_is_invited = false; | ||||
| 		} | ||||
|  | ||||
| @ -986,17 +986,3 @@ table.awaiting .no-threads, table.awaiting .no-visitors  { | ||||
| 	float:left; | ||||
| 	padding-left:10px; | ||||
| } | ||||
| 
 | ||||
| /* invitation wait */ | ||||
| 
 | ||||
| .ajaxWait { | ||||
|     z-index: -1; | ||||
|     position: absolute; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     background-image: url(images/ajax-loader.gif); | ||||
|     background-repeat: no-repeat; | ||||
|     background-position: center; | ||||
| } | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 6.7 KiB | 
| @ -42,6 +42,7 @@ $dbtables = array( | ||||
| 		"dtmmodified" => "int NOT NULL DEFAULT 0", | ||||
| 		"lrevision" => "int NOT NULL DEFAULT 0", | ||||
| 		"istate" => "int NOT NULL DEFAULT 0", | ||||
| 		"invitationstate" => "int NOT NULL DEFAULT 0", | ||||
| 		"ltoken" => "int NOT NULL", | ||||
| 		"remote" => "varchar(255)", | ||||
| 		"referer" => "text", | ||||
| @ -167,15 +168,12 @@ $dbtables = array( | ||||
| 
 | ||||
| 	"${mysqlprefix}chatsitevisitor" => array( | ||||
| 		"visitorid" => "INT NOT NULL auto_increment PRIMARY KEY", | ||||
| 		"userid" => "varchar(64) NOT NULL", | ||||
| 		"username" => "varchar(255)", | ||||
| 		"userid" => "varchar(255) NOT NULL", | ||||
| 		"username" => "varchar(64)", | ||||
| 		"firsttime" => "int NOT NULL DEFAULT 0", | ||||
| 		"lasttime" => "int NOT NULL DEFAULT 0", | ||||
| 		"entry" => "text NOT NULL", | ||||
| 		"details" => "text NOT NULL", | ||||
| 		"invited" => "tinyint(1) NOT NULL DEFAULT 0", | ||||
| 		"invitationtime" => "int NOT NULL DEFAULT 0", | ||||
| 		"invitedby" => "INT references ${mysqlprefix}chatoperator(operatorid) on delete set null", | ||||
| 		"invitations" => "INT NOT NULL DEFAULT 0", | ||||
| 		"chats" => "INT NOT NULL DEFAULT 0", | ||||
| 		"threadid" => "INT references ${mysqlprefix}chatthread(threadid) on delete set null" | ||||
| @ -233,7 +231,7 @@ $dbtables_indexes = array( | ||||
| $memtables = array(); | ||||
| 
 | ||||
| $dbtables_can_update = array( | ||||
| 	"${mysqlprefix}chatthread" => array("agentId", "userTyping", "agentTyping", "messageCount", "nextagent", "shownmessageid", "userid", "userAgent", "groupid", "dtmchatstarted"), | ||||
| 	"${mysqlprefix}chatthread" => array("agentId", "userTyping", "agentTyping", "messageCount", "nextagent", "shownmessageid", "userid", "userAgent", "groupid", "dtmchatstarted", "invitationstate"), | ||||
| 	"${mysqlprefix}chatthreadstatistics" => array(), | ||||
| 	"${mysqlprefix}requestbuffer" => array("requestid", "requestkey", "request"), | ||||
| 	"${mysqlprefix}chatmessage" => array("agentId"), | ||||
|  | ||||
| @ -128,6 +128,10 @@ if ($act == "silentcreateall") { | ||||
| 			runsql("ALTER TABLE ${mysqlprefix}chatthread ADD userid varchar(255) DEFAULT \"\"", $link); | ||||
| 		} | ||||
| 
 | ||||
| 		if (in_array("${mysqlprefix}chatthread.invitationstate", $absent_columns)) { | ||||
| 			runsql("ALTER TABLE ${mysqlprefix}chatthread ADD invitationstate int NOT NULL DEFAULT 0 AFTER istate", $link); | ||||
| 		} | ||||
| 
 | ||||
| 		if (in_array("${mysqlprefix}chatoperator.iperm", $absent_columns)) { | ||||
| 			runsql("ALTER TABLE ${mysqlprefix}chatoperator ADD iperm int DEFAULT 65535", $link); | ||||
| 		} | ||||
|  | ||||
| @ -5,5 +5,5 @@ | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| (function(a,d){var c=a.Application;c.addRegions({mainRegion:"#main-region"});c.addInitializer(function(b){a.PluginOptions=b.plugins||{};a.Objects.server=new a.Server(d.extend({interactionType:MibewAPIChatInteraction},b.server));a.Objects.Models.page=new a.Models.Page(b.page);switch(b.startFrom){case "chat":c.Chat.start(b.chatOptions);break;case "survey":c.Survey.start(b.surveyOptions);break;case "leaveMessage":c.LeaveMessage.start(b.leaveMessageOptions);break;default:throw Error("Dont know how to start!"); | ||||
| }});c.on("start",function(){a.Objects.server.runUpdater()})})(Mibew,_); | ||||
| (function(b,d){var c=b.Application;c.addRegions({mainRegion:"#main-region"});c.addInitializer(function(a){b.PluginOptions=a.plugins||{};b.Objects.server=new b.Server(d.extend({interactionType:MibewAPIChatInteraction},a.server));b.Objects.Models.page=new b.Models.Page(a.page);switch(a.startFrom){case "chat":c.Chat.start(a.chatOptions);break;case "survey":c.Survey.start(a.surveyOptions);break;case "leaveMessage":c.LeaveMessage.start(a.leaveMessageOptions);break;case "invitation":c.Invitation.start(a.invitationOptions); | ||||
| break;default:throw Error("Dont know how to start!");}});c.on("start",function(){b.Objects.server.runUpdater()})})(Mibew,_); | ||||
|  | ||||
| @ -0,0 +1,8 @@ | ||||
| /* | ||||
|  Copyright 2005-2013 the original author or authors. | ||||
| 
 | ||||
|  Licensed under the Apache License, Version 2.0 (the "License"). | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| (function(a,b){a.Layouts.Invitation=b.Marionette.Layout.extend({template:Handlebars.templates.invitation_layout,regions:{messagesRegion:{selector:"#invitation-messages-region",regionType:a.Regions.Messages}}})})(Mibew,Backbone); | ||||
							
								
								
									
										10
									
								
								src/messenger/webim/js/compiled/chat/modules/invitation.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/messenger/webim/js/compiled/chat/modules/invitation.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| /* | ||||
|  Copyright 2005-2013 the original author or authors. | ||||
| 
 | ||||
|  Licensed under the Apache License, Version 2.0 (the "License"). | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| (function(a){var d=[],e=a.Application,b=e.module("Invitation",{startWithParent:!1});b.addInitializer(function(f){var c=a.Objects,b=a.Objects.Models;b.thread=new a.Models.Thread(f.thread);b.user=new a.Models.ChatUser(f.user);c.invitationLayout=new a.Layouts.Invitation;e.mainRegion.show(c.invitationLayout);c.Collections.messages=new a.Collections.Messages;c.invitationLayout.messagesRegion.show(new a.Views.MessagesCollection({collection:c.Collections.messages}));d.push(c.server.callFunctionsPeriodically(function(){var b= | ||||
| a.Objects.Models.thread;return[{"function":"update",arguments:{"return":{},references:{},threadId:b.get("id"),token:b.get("token"),lastId:b.get("lastId"),typed:!1,user:!0}}]},function(){}))});b.on("start",function(){a.Objects.server.restartUpdater()});b.addFinalizer(function(){a.Objects.invitationLayout.close();for(var b=0;b<d.length;b++)a.Objects.server.stopCallFunctionsPeriodically(d[b]);a.Objects.Collections.messages.finalize();delete a.Objects.invitationLayout;delete a.Objects.Models.thread;delete a.Objects.Models.user; | ||||
| delete a.Objects.Collections.messages})})(Mibew); | ||||
| @ -341,6 +341,13 @@ disableInput:function(){this.ui.message.attr("disabled","disabled")},clearInput: | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| (function(a,b){a.Layouts.Invitation=b.Marionette.Layout.extend({template:Handlebars.templates.invitation_layout,regions:{messagesRegion:{selector:"#invitation-messages-region",regionType:a.Regions.Messages}}})})(Mibew,Backbone); | ||||
| /* | ||||
|  Copyright 2005-2013 the original author or authors. | ||||
|  Licensed under the Apache License, Version 2.0 (the "License"). | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| (function(a,b){a.Layouts.LeaveMessage=b.Marionette.Layout.extend({template:Handlebars.templates.leave_message_layout,regions:{leaveMessageFormRegion:"#content-wrapper",descriptionRegion:"#description-region"},serializeData:function(){return{page:a.Objects.Models.page.toJSON()}}})})(Mibew,Backbone); | ||||
| /* | ||||
|  Copyright 2005-2013 the original author or authors. | ||||
| @ -368,6 +375,15 @@ delete a.Objects.Collections.messages;delete a.Objects.Collections.controls;dele | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| (function(a){var d=[],e=a.Application,b=e.module("Invitation",{startWithParent:!1});b.addInitializer(function(f){var c=a.Objects,b=a.Objects.Models;b.thread=new a.Models.Thread(f.thread);b.user=new a.Models.ChatUser(f.user);c.invitationLayout=new a.Layouts.Invitation;e.mainRegion.show(c.invitationLayout);c.Collections.messages=new a.Collections.Messages;c.invitationLayout.messagesRegion.show(new a.Views.MessagesCollection({collection:c.Collections.messages}));d.push(c.server.callFunctionsPeriodically(function(){var b= | ||||
| a.Objects.Models.thread;return[{"function":"update",arguments:{"return":{},references:{},threadId:b.get("id"),token:b.get("token"),lastId:b.get("lastId"),typed:!1,user:!0}}]},function(){}))});b.on("start",function(){a.Objects.server.restartUpdater()});b.addFinalizer(function(){a.Objects.invitationLayout.close();for(var b=0;b<d.length;b++)a.Objects.server.stopCallFunctionsPeriodically(d[b]);a.Objects.Collections.messages.finalize();delete a.Objects.invitationLayout;delete a.Objects.Models.thread;delete a.Objects.Models.user; | ||||
| delete a.Objects.Collections.messages})})(Mibew); | ||||
| /* | ||||
|  Copyright 2005-2013 the original author or authors. | ||||
|  Licensed under the Apache License, Version 2.0 (the "License"). | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| (function(a){var e=a.Application,f=e.module("LeaveMessage",{startWithParent:!1});f.addInitializer(function(d){var b=a.Objects,c=a.Objects.Models;d.page&&c.page.set(d.page);b.leaveMessageLayout=new a.Layouts.LeaveMessage;e.mainRegion.show(b.leaveMessageLayout);c.leaveMessageForm=new a.Models.LeaveMessageForm(d.leaveMessageForm);b.leaveMessageLayout.leaveMessageFormRegion.show(new a.Views.LeaveMessageForm({model:c.leaveMessageForm}));b.leaveMessageLayout.descriptionRegion.show(new a.Views.LeaveMessageDescription); | ||||
| c.leaveMessageForm.on("submit:complete",function(){b.leaveMessageLayout.leaveMessageFormRegion.close();b.leaveMessageLayout.descriptionRegion.close();b.leaveMessageLayout.descriptionRegion.show(new a.Views.LeaveMessageSentDescription)})});f.addFinalizer(function(){a.Objects.leaveMessageLayout.close();delete a.Objects.Models.leaveMessageForm})})(Mibew); | ||||
| /* | ||||
| @ -383,5 +399,5 @@ c.leaveMessageForm.on("submit:complete",function(){b.leaveMessageLayout.leaveMes | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| (function(a,d){var c=a.Application;c.addRegions({mainRegion:"#main-region"});c.addInitializer(function(b){a.PluginOptions=b.plugins||{};a.Objects.server=new a.Server(d.extend({interactionType:MibewAPIChatInteraction},b.server));a.Objects.Models.page=new a.Models.Page(b.page);switch(b.startFrom){case "chat":c.Chat.start(b.chatOptions);break;case "survey":c.Survey.start(b.surveyOptions);break;case "leaveMessage":c.LeaveMessage.start(b.leaveMessageOptions);break;default:throw Error("Dont know how to start!"); | ||||
| }});c.on("start",function(){a.Objects.server.runUpdater()})})(Mibew,_); | ||||
| (function(b,d){var c=b.Application;c.addRegions({mainRegion:"#main-region"});c.addInitializer(function(a){b.PluginOptions=a.plugins||{};b.Objects.server=new b.Server(d.extend({interactionType:MibewAPIChatInteraction},a.server));b.Objects.Models.page=new b.Models.Page(a.page);switch(a.startFrom){case "chat":c.Chat.start(a.chatOptions);break;case "survey":c.Survey.start(a.surveyOptions);break;case "leaveMessage":c.LeaveMessage.start(a.leaveMessageOptions);break;case "invitation":c.Invitation.start(a.invitationOptions); | ||||
| break;default:throw Error("Dont know how to start!");}});c.on("start",function(){b.Objects.server.runUpdater()})})(Mibew,_); | ||||
|  | ||||
| @ -5,4 +5,4 @@ | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| (function(a){a.Models.Thread=a.Models.Base.extend({defaults:{id:0,token:0,lastId:0,state:null},STATE_QUEUE:0,STATE_WAITING:1,STATE_CHATTING:2,STATE_CLOSED:3,STATE_LOADING:4,STATE_LEFT:5})})(Mibew); | ||||
| (function(a){a.Models.Thread=a.Models.Base.extend({defaults:{id:0,token:0,lastId:0,state:null},STATE_QUEUE:0,STATE_WAITING:1,STATE_CHATTING:2,STATE_CLOSED:3,STATE_LOADING:4,STATE_LEFT:5,STATE_INVITED:6})})(Mibew); | ||||
|  | ||||
| @ -87,7 +87,7 @@ b.Utils.playSound=function(a){c("body").append('<audio autoplay style="display: | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| (function(a){a.Models.Thread=a.Models.Base.extend({defaults:{id:0,token:0,lastId:0,state:null},STATE_QUEUE:0,STATE_WAITING:1,STATE_CHATTING:2,STATE_CLOSED:3,STATE_LOADING:4,STATE_LEFT:5})})(Mibew); | ||||
| (function(a){a.Models.Thread=a.Models.Base.extend({defaults:{id:0,token:0,lastId:0,state:null},STATE_QUEUE:0,STATE_WAITING:1,STATE_CHATTING:2,STATE_CLOSED:3,STATE_LOADING:4,STATE_LEFT:5,STATE_INVITED:6})})(Mibew); | ||||
| /* | ||||
|  Copyright 2005-2013 the original author or authors. | ||||
|  Licensed under the Apache License, Version 2.0 (the "License"). | ||||
|  | ||||
| @ -1,9 +0,0 @@ | ||||
| /* | ||||
|  Copyright 2005-2013 the original author or authors. | ||||
| 
 | ||||
|  Licensed under the Apache License, Version 2.0 (the "License"). | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| (function(c,a,e){a=new a.Marionette.Application;a.addInitializer(function(a){var d=new c.Server(e.extend({interactionType:MibewAPIInviteInteraction},a.server));d.callFunctionsPeriodically(function(){return[{"function":"invitationState",arguments:{"return":{invited:"invited",threadId:"threadId"},references:{},visitorId:a.visitorId}}]},function(b){0==b.errorCode&&(b.invited||window.close(),b.threadId&&(window.name="ImCenter"+b.threadId,window.location=a.chatLink+"?thread="+b.threadId))});d.runUpdater(); | ||||
| c.Objects.server=d});c.Application=a})(Mibew,Backbone,_); | ||||
| @ -1,8 +0,0 @@ | ||||
| /* | ||||
|  Copyright 2005-2013 the original author or authors. | ||||
| 
 | ||||
|  Licensed under the Apache License, Version 2.0 (the "License"). | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| MibewAPIInviteInteraction=function(){this.obligatoryArguments={"*":{"return":{},references:{},visitorId:null},result:{errorCode:0}};this.reservedFunctionNames=["result"]};MibewAPIInviteInteraction.prototype=new MibewAPIInteraction; | ||||
| @ -1,15 +0,0 @@ | ||||
| /* | ||||
|  Copyright 2005-2013 the original author or authors. | ||||
|  Licensed under the Apache License, Version 2.0 (the "License"). | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| MibewAPIInviteInteraction=function(){this.obligatoryArguments={"*":{"return":{},references:{},visitorId:null},result:{errorCode:0}};this.reservedFunctionNames=["result"]};MibewAPIInviteInteraction.prototype=new MibewAPIInteraction; | ||||
| /* | ||||
|  Copyright 2005-2013 the original author or authors. | ||||
|  Licensed under the Apache License, Version 2.0 (the "License"). | ||||
|  You may obtain a copy of the License at | ||||
|      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| */ | ||||
| (function(c,a,e){a=new a.Marionette.Application;a.addInitializer(function(a){var d=new c.Server(e.extend({interactionType:MibewAPIInviteInteraction},a.server));d.callFunctionsPeriodically(function(){return[{"function":"invitationState",arguments:{"return":{invited:"invited",threadId:"threadId"},references:{},visitorId:a.visitorId}}]},function(b){0==b.errorCode&&(b.invited||window.close(),b.threadId&&(window.name="ImCenter"+b.threadId,window.location=a.chatLink+"?thread="+b.threadId))});d.runUpdater(); | ||||
| c.Objects.server=d});c.Application=a})(Mibew,Backbone,_); | ||||
| @ -12,6 +12,6 @@ return b.join("&")};a.Widget.prototype.sendToServer=function(b){for(var c in b)i | ||||
| this.loadScript(f));for(var h in b)b.hasOwnProperty(h)&&(h in this.handlersDependences||(this.handlersDependences[h]=b[h]));for(c=0;c<d.length;c++){var g=d[c];if(this.canRunHandler(g))a.APIFunctions[g](e);else g in this.handlers||(this.handlers[g]=function(){a.APIFunctions[g](e)})}this.cleanUpAfterRequest();window.setTimeout(function(){j.makeRequest()},this.requestTimeout)};a.Widget.prototype.cleanUpAfterRequest=function(){document.getElementsByTagName("head")[0].removeChild(document.getElementById("responseScript"))}; | ||||
| a.Widget.prototype.loadScript=function(b){var c=this,a=this.doLoadScript(this.requestedScripts[b].url,b);a.onload=function(){c.scriptReady(b)};a.onreadystatechange=function(){("complete"==this.readyState||"loaded"==this.readyState)&&c.scriptReady(b)}};a.Widget.prototype.doLoadScript=function(b,c){var a=document.createElement("script");a.setAttribute("type","text/javascript");a.setAttribute("src",b);a.setAttribute("id",c);document.getElementsByTagName("head")[0].appendChild(a);return a};a.Widget.prototype.scriptReady= | ||||
| function(b){this.requestedScripts[b].status="ready";for(var a in this.handlers)this.handlers.hasOwnProperty(a)&&this.canRunHandler(a)&&(this.handlers[a](),delete this.handlers[a])};a.Widget.prototype.canRunHandler=function(b){b=this.handlersDependences[b];for(var a=0;a<b.length;a++)if("ready"!=this.requestedScripts[b[a]].status)return!1;return!0};a.Widget.init=function(b){a.Objects.widget=new a.Widget(b);a.Objects.widget.makeRequest()};a.Utils={};a.Utils.createCookie=function(b,a){var d=/([^\.]+\.[^\.]+)$/.exec(document.location.hostname)[1]; | ||||
| document.cookie=""+b+"="+a+"; path=/; "+(d?"domain="+d+";":"")};a.Utils.readCookie=function(b){var a=document.cookie.split("; ");b+="=";for(var d=!1,e=0;e<a.length;e++)if(-1!=a[e].indexOf(b)){d=a[e].substr(b.length);break}return d};a.APIFunctions={};a.APIFunctions.updateUserId=function(b){a.Utils.createCookie(a.Objects.widget.visitorCookieName,b.user.id)};a.APIFunctions.inviteOnResponse=function(b){var a=b.invitation.message,d=b.invitation.operator,e=b.invitation.avatar;b='<div id="mibewinvitationpopup"><div id="mibewinvitationclose"><a href="javascript:void(0);" onclick="Mibew.Invitation.reject();">×</a></div>'; | ||||
| d&&(b+='<h1 onclick="Mibew.Invitation.accept();">'+d+"</h1>");e&&(b+='<img id="mibewinvitationavatar" src="'+e+'" title="'+d+'" alt="'+d+'" onclick="Mibew.Invitation.accept();" />');b=b+('<p onclick="Mibew.Invitation.accept();">'+a+"</p>")+'<div style="clear: both;"></div></div>';if(a=document.getElementById("mibewinvitation"))a.innerHTML=b};a.Invitation={};a.Invitation.hide=function(){var a=document.getElementById("mibewinvitationpopup");a&&(a.style.display="none")};a.Invitation.accept=function(){document.getElementById("mibewAgentButton")&& | ||||
| (document.getElementById("mibewAgentButton").onclick(),a.Invitation.hide())};a.Invitation.reject=function(){a.Objects.widget.sendToServer({invitation_rejected:1});a.Invitation.hide()}})(Mibew); | ||||
| document.cookie=""+b+"="+a+"; path=/; "+(d?"domain="+d+";":"")};a.Utils.readCookie=function(b){var a=document.cookie.split("; ");b+="=";for(var d=!1,e=0;e<a.length;e++)if(-1!=a[e].indexOf(b)){d=a[e].substr(b.length);break}return d};a.APIFunctions={};a.APIFunctions.updateUserId=function(b){a.Utils.createCookie(a.Objects.widget.visitorCookieName,b.user.id)};a.APIFunctions.inviteOnResponse=function(b){var a=b.invitation.operator,d=b.invitation.avatar,e=b.invitation.url;b='<div id="mibewinvitationpopup" style="display: none;"><div id="mibewinvitationclose"><a href="javascript:void(0);" onclick="Mibew.Invitation.reject();">×</a></div>'; | ||||
| a&&(b+='<h1 onclick="Mibew.Invitation.accept();">'+a+"</h1>");d&&(b+='<img id="mibewinvitationavatar" src="'+d+'" title="'+a+'" alt="'+a+'" onclick="Mibew.Invitation.accept();" />');e&&(b+='<iframe id="mibewinvitationframe" src="'+e+'" onload="Mibew.Invitation.show();"></iframe>');b+='<div style="clear: both;"></div></div>';if(a=document.getElementById("mibewinvitation"))a.innerHTML=b};a.Invitation={};a.Invitation.hide=function(){var a=document.getElementById("mibewinvitationpopup");a&&a.parentNode.removeChild(a)}; | ||||
| a.Invitation.show=function(){var a=document.getElementById("mibewinvitationpopup");a&&(a.style.display="block")};a.Invitation.accept=function(){document.getElementById("mibewAgentButton")&&(document.getElementById("mibewAgentButton").onclick(),a.Invitation.hide())};a.Invitation.reject=function(){a.Objects.widget.sendToServer({invitation_rejected:1});a.Invitation.hide()}})(Mibew); | ||||
|  | ||||
| @ -40,6 +40,9 @@ | ||||
|             case 'leaveMessage': | ||||
|                 app.LeaveMessage.start(options.leaveMessageOptions); | ||||
|                 break; | ||||
|             case 'invitation': | ||||
|                 app.Invitation.start(options.invitationOptions); | ||||
|                 break; | ||||
|             default: | ||||
|                 throw new Error('Dont know how to start!'); | ||||
|                 break; | ||||
|  | ||||
							
								
								
									
										36
									
								
								src/messenger/webim/js/source/chat/layouts/invitation.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/messenger/webim/js/source/chat/layouts/invitation.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| /** | ||||
|  * @preserve Copyright 2005-2013 the original author or authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"). | ||||
|  * You may obtain a copy of the License at | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Backbone){ | ||||
| 
 | ||||
|     /** | ||||
|      * Represents invitation layout | ||||
|      */ | ||||
|     Mibew.Layouts.Invitation = Backbone.Marionette.Layout.extend( | ||||
|         /** @lends Mibew.Layouts.Invitation.prototype */ | ||||
|         { | ||||
|             /** | ||||
|              * Template function | ||||
|              * @type Function | ||||
|              */ | ||||
|             template: Handlebars.templates.invitation_layout, | ||||
| 
 | ||||
|             /** | ||||
|              * Regions list | ||||
|              * @type Object | ||||
|              */ | ||||
|             regions: { | ||||
|                 messagesRegion: { | ||||
|                     selector: '#invitation-messages-region', | ||||
|                     regionType: Mibew.Regions.Messages | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
| })(Mibew, Backbone); | ||||
							
								
								
									
										114
									
								
								src/messenger/webim/js/source/chat/modules/invitation.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/messenger/webim/js/source/chat/modules/invitation.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,114 @@ | ||||
| /** | ||||
|  * @preserve Copyright 2005-2013 the original author or authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"). | ||||
|  * You may obtain a copy of the License at | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew){ | ||||
| 
 | ||||
|     /** | ||||
|      * Contains ids of periodically called functions | ||||
|      * @type Array | ||||
|      */ | ||||
|     var periodicallyCalled = []; | ||||
| 
 | ||||
| 
 | ||||
|     // Create shortcut for Application object
 | ||||
|     var app = Mibew.Application; | ||||
| 
 | ||||
|     // Create Invite module
 | ||||
|     var invitation = app.module('Invitation', {startWithParent: false}); | ||||
| 
 | ||||
|     // Add module initializer
 | ||||
|     invitation.addInitializer(function(options) { | ||||
|         // Create some shortcuts
 | ||||
|         var objs = Mibew.Objects; | ||||
|         var models = Mibew.Objects.Models; | ||||
| 
 | ||||
|         // Initialize Thread and User
 | ||||
|         models.thread = new Mibew.Models.Thread(options.thread); | ||||
|         models.user = new Mibew.Models.ChatUser(options.user); | ||||
| 
 | ||||
|         // Create instance of the Invitation layout
 | ||||
|         objs.invitationLayout = new Mibew.Layouts.Invitation(); | ||||
| 
 | ||||
|         // Show layout at page
 | ||||
|         app.mainRegion.show(objs.invitationLayout); | ||||
| 
 | ||||
|         // Initialize Messages area
 | ||||
|         // Create messages collection and store it
 | ||||
|         objs.Collections.messages = new Mibew.Collections.Messages(); | ||||
| 
 | ||||
|         // Display messages
 | ||||
|         objs.invitationLayout.messagesRegion.show(new Mibew.Views.MessagesCollection({ | ||||
|             collection: objs.Collections.messages | ||||
|         })); | ||||
| 
 | ||||
| 
 | ||||
|         // Periodically call update function at the server side
 | ||||
|         periodicallyCalled.push( | ||||
|             objs.server.callFunctionsPeriodically( | ||||
|                 function() { | ||||
|                     // Get thread object
 | ||||
|                     var thread = Mibew.Objects.Models.thread; | ||||
| 
 | ||||
|                     // Build functions list
 | ||||
|                     return [ | ||||
|                         { | ||||
|                             "function": "update", | ||||
|                             "arguments": { | ||||
|                                 "return": {}, | ||||
|                                 "references": {}, | ||||
|                                 "threadId": thread.get('id'), | ||||
|                                 "token": thread.get('token'), | ||||
|                                 "lastId": thread.get('lastId'), | ||||
|                                 "typed": false, | ||||
|                                 "user": true | ||||
|                             } | ||||
|                         } | ||||
|                     ] | ||||
|                 }, | ||||
|                 function() {} | ||||
|             ) | ||||
|         ); | ||||
| 
 | ||||
|     }); | ||||
| 
 | ||||
|     invitation.on('start', function() { | ||||
|         // Restart server updater because module just started and there are no
 | ||||
|         // reasons to wait refresh time to get results of previous request
 | ||||
|         Mibew.Objects.server.restartUpdater(); | ||||
|     }) | ||||
| 
 | ||||
|     // Add module finalizer
 | ||||
|     invitation.addFinalizer(function() { | ||||
|         // Close layout
 | ||||
|         Mibew.Objects.invitationLayout.close(); | ||||
| 
 | ||||
| 
 | ||||
|         // Stop call functions periodically
 | ||||
|         for (var i = 0; i < periodicallyCalled.length; i++) { | ||||
|             Mibew.Objects.server.stopCallFunctionsPeriodically( | ||||
|                 periodicallyCalled[i] | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         // Run collections finalizers
 | ||||
|         // Finalize messages collection
 | ||||
|         Mibew.Objects.Collections.messages.finalize(); | ||||
| 
 | ||||
|         // Clean up memory
 | ||||
|         // Delete layout
 | ||||
|         delete Mibew.Objects.invitationLayout; | ||||
| 
 | ||||
|         // Delete models
 | ||||
|         delete Mibew.Objects.Models.thread; | ||||
|         delete Mibew.Objects.Models.user; | ||||
| 
 | ||||
|         // Delete collections
 | ||||
|         delete Mibew.Objects.Collections.messages; | ||||
|     }); | ||||
| 
 | ||||
| })(Mibew); | ||||
| @ -70,7 +70,11 @@ | ||||
|             /** | ||||
|              * User left message without starting a conversation | ||||
|              */ | ||||
|             STATE_LEFT: 5 | ||||
|             STATE_LEFT: 5, | ||||
|             /** | ||||
|              * Visitor was invited to chat by operator | ||||
|              */ | ||||
|             STATE_INVITED: 6 | ||||
| 
 | ||||
|             /** End of thread state constants */ | ||||
|         } | ||||
|  | ||||
| @ -1,67 +0,0 @@ | ||||
| /** | ||||
|  * @preserve Copyright 2005-2013 the original author or authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"). | ||||
|  * You may obtain a copy of the License at | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  */ | ||||
| 
 | ||||
| (function(Mibew, Backbone, _){ | ||||
| 
 | ||||
|     // Create application instance
 | ||||
|     var App = new Backbone.Marionette.Application(); | ||||
| 
 | ||||
|     // Initialize application
 | ||||
|     App.addInitializer(function(options){ | ||||
| 
 | ||||
|         // Initialize Server
 | ||||
|         var server =  new Mibew.Server(_.extend( | ||||
|             { | ||||
|                 'interactionType': MibewAPIInviteInteraction | ||||
|             }, | ||||
|             options.server | ||||
|         )); | ||||
| 
 | ||||
|         // Periodically call update function at the server side
 | ||||
|         server.callFunctionsPeriodically( | ||||
|             function() { | ||||
|                 // Build functions list
 | ||||
|                 return [ | ||||
|                     { | ||||
|                         "function": "invitationState", | ||||
|                         "arguments": { | ||||
|                             "return": { | ||||
|                                 'invited': 'invited', | ||||
|                                 'threadId': 'threadId' | ||||
|                             }, | ||||
|                             "references": {}, | ||||
|                             "visitorId": options.visitorId | ||||
|                         } | ||||
|                     } | ||||
|                 ]; | ||||
|             }, | ||||
|             function(args) { | ||||
|                 if (args.errorCode == 0) { | ||||
|                     if (!args.invited) { | ||||
|                         // Visitor not invited any more.
 | ||||
|                         // Invitation vindow should be closed.
 | ||||
|                         window.close(); | ||||
|                     } | ||||
|                     if (args.threadId) { | ||||
|                         // Invitation accepted.
 | ||||
|                         // Redirect agent to chat page
 | ||||
|                         window.name = 'ImCenter' + args.threadId; | ||||
|                         window.location= options.chatLink | ||||
|                             + '?thread=' + args.threadId; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         ); | ||||
| 
 | ||||
|         server.runUpdater(); | ||||
|         Mibew.Objects.server = server; | ||||
|     }); | ||||
| 
 | ||||
|     Mibew.Application = App; | ||||
| 
 | ||||
| })(Mibew, Backbone, _); | ||||
| @ -1,30 +0,0 @@ | ||||
| /** | ||||
|  * @preserve Copyright 2005-2013 the original author or authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"). | ||||
|  * You may obtain a copy of the License at | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Represents Invitation waiting Window to core interaction type | ||||
|  * | ||||
|  * @constructor | ||||
|  */ | ||||
| MibewAPIInviteInteraction = function() { | ||||
|     this.obligatoryArguments = { | ||||
|         '*': { | ||||
|             'return': {}, | ||||
|             'references': {}, | ||||
|             'visitorId': null | ||||
|         }, | ||||
|         'result': { | ||||
|             'errorCode': 0 | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     this.reservedFunctionNames = [ | ||||
|         'result' | ||||
|     ]; | ||||
| } | ||||
| MibewAPIInviteInteraction.prototype = new MibewAPIInteraction(); | ||||
| @ -380,28 +380,36 @@ var Mibew = {}; | ||||
|      * @param {Object} response Data passed from server | ||||
|      */ | ||||
|     Mibew.APIFunctions.inviteOnResponse = function(response) { | ||||
|         var message = response.invitation.message; | ||||
|         var operator = response.invitation.operator; | ||||
|         var avatar = response.invitation.avatar; | ||||
|         var url = response.invitation.url; | ||||
| 
 | ||||
|         var popuptext = '<div id="mibewinvitationpopup">'; | ||||
|         var popuptext = '<div id="mibewinvitationpopup" style="display: none;">'; | ||||
|         popuptext += '<div id="mibewinvitationclose">' | ||||
|             + '<a href="javascript:void(0);" onclick="Mibew.Invitation.reject();">' | ||||
|             + '×</a></div>'; | ||||
| 
 | ||||
|         // Add operator name
 | ||||
|         if (operator) { | ||||
|             popuptext += '<h1 onclick="Mibew.Invitation.accept();">' | ||||
|                 + operator | ||||
|                 + '</h1>'; | ||||
|         } | ||||
| 
 | ||||
|         // Add operator avatar
 | ||||
|         if (avatar) { | ||||
|             popuptext += '<img id="mibewinvitationavatar" src="' + avatar | ||||
|                 + '" title="' + operator | ||||
|                 + '" alt="' + operator | ||||
|                 + '" onclick="Mibew.Invitation.accept();" />'; | ||||
|         } | ||||
|         popuptext += '<p onclick="Mibew.Invitation.accept();">' | ||||
|             + message | ||||
|             + '</p>'; | ||||
| 
 | ||||
|         // Translate message from the thread related with invitation into iframe
 | ||||
|         if (url) { | ||||
|             popuptext += '<iframe id="mibewinvitationframe" src="' + url | ||||
|                 + '" onload="Mibew.Invitation.show();"></iframe>'; | ||||
|         } | ||||
| 
 | ||||
|         popuptext += '<div style="clear: both;"></div></div>'; | ||||
| 
 | ||||
|         var invitationdiv = document.getElementById("mibewinvitation"); | ||||
| @ -416,12 +424,22 @@ var Mibew = {}; | ||||
|     Mibew.Invitation = {}; | ||||
| 
 | ||||
|     /** | ||||
|      * Hide invitation popup | ||||
|      * Hide invitation popup and remove it from DOM | ||||
|      */ | ||||
|     Mibew.Invitation.hide = function() { | ||||
|         var invitationPopup = document.getElementById('mibewinvitationpopup'); | ||||
|         if (invitationPopup) { | ||||
|             invitationPopup.style.display = 'none'; | ||||
|             invitationPopup.parentNode.removeChild(invitationPopup); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Display invitation popup | ||||
|      */ | ||||
|     Mibew.Invitation.show = function() { | ||||
|         var invitationPopup = document.getElementById('mibewinvitationpopup'); | ||||
|         if (invitationPopup) { | ||||
|             invitationPopup.style.display = 'block'; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -642,8 +642,30 @@ function chat_start_for_user($group_id, $visitor_id, $visitor_name, $referrer, $ | ||||
| 		die("number of connections from your IP is exceeded, try again later"); | ||||
| 	} | ||||
| 
 | ||||
| 	// Create thread
 | ||||
| 	$thread = Thread::create(); | ||||
| 	// Check if visitor was invited to chat
 | ||||
| 	$is_invited = false; | ||||
| 	if (Settings::get('enabletracking')) { | ||||
| 		$invitation_state = invitation_state($_SESSION['visitorid']); | ||||
| 		if ($invitation_state['invited']) { | ||||
| 			$is_invited = true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Get thread object
 | ||||
| 	if ($is_invited) { | ||||
| 		// Get thread from invitation
 | ||||
| 		$thread = invitation_accept($_SESSION['visitorid']); | ||||
| 		if (! $thread) { | ||||
| 			die("Cannot start thread"); | ||||
| 		} | ||||
| 		$thread->state = Thread::STATE_CHATTING; | ||||
| 	} else { | ||||
| 		// Create thread
 | ||||
| 		$thread = Thread::create(); | ||||
| 		$thread->state = Thread::STATE_LOADING; | ||||
| 	} | ||||
| 
 | ||||
| 	// Update thread fields
 | ||||
| 	$thread->groupId = $group_id; | ||||
| 	$thread->userName = $visitor_name; | ||||
| 	$thread->remote = $remote_host; | ||||
| @ -651,36 +673,31 @@ function chat_start_for_user($group_id, $visitor_id, $visitor_name, $referrer, $ | ||||
| 	$thread->locale = $current_locale; | ||||
| 	$thread->userId = $visitor_id; | ||||
| 	$thread->userAgent = $user_browser; | ||||
| 	$thread->state = Thread::STATE_LOADING; | ||||
| 	$thread->save(); | ||||
| 
 | ||||
| 	$_SESSION['threadid'] = $thread->id; | ||||
| 
 | ||||
| 	// Check if invitation accept
 | ||||
| 	if (Settings::get('enabletracking')) { | ||||
| 		$operator = invitation_accept($_SESSION['visitorid'], $thread->id); | ||||
| 		if ($operator) { | ||||
| 			$operator = operator_by_id($operator); | ||||
| 			$operator_name = get_operator_name($operator); | ||||
| 			$thread->postMessage( | ||||
| 				Thread::KIND_FOR_AGENT, | ||||
| 				getstring2( | ||||
| 					'chat.visitor.invitation.accepted', | ||||
| 					array($operator_name) | ||||
| 				) | ||||
| 			); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Send some messages
 | ||||
| 	if ($referrer) { | ||||
| 	// Send several messages
 | ||||
| 	if ($is_invited) { | ||||
| 		$operator = operator_by_id($thread->agentId); | ||||
| 		$operator_name = get_operator_name($operator); | ||||
| 		$thread->postMessage( | ||||
| 			Thread::KIND_FOR_AGENT, | ||||
| 			getstring2('chat.came.from',array($referrer)) | ||||
| 			getstring2( | ||||
| 				'chat.visitor.invitation.accepted', | ||||
| 				array($operator_name) | ||||
| 			) | ||||
| 		); | ||||
| 	} | ||||
| 	} else { | ||||
| 		if ($referrer) { | ||||
| 			$thread->postMessage( | ||||
| 				Thread::KIND_FOR_AGENT, | ||||
| 				getstring2('chat.came.from',array($referrer)) | ||||
| 			); | ||||
| 		} | ||||
| 
 | ||||
| 	$thread->postMessage(Thread::KIND_INFO, getstring('chat.wait')); | ||||
| 		$thread->postMessage(Thread::KIND_INFO, getstring('chat.wait')); | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: May be move sending this message somewhere else?
 | ||||
| 	if ($info) { | ||||
|  | ||||
| @ -61,6 +61,31 @@ Class Thread { | ||||
| 	 * User left message without starting a conversation | ||||
| 	 */ | ||||
| 	const STATE_LEFT = 5; | ||||
| 	/** | ||||
| 	 * Visitor was invited to chat by operator | ||||
| 	 */ | ||||
| 	const STATE_INVITED = 6; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Visitor was not invited to chat | ||||
| 	 */ | ||||
| 	const INVITATION_NOT_INVITED = 0; | ||||
| 	/** | ||||
| 	 * Operator invited visitor and wait for reaction. | ||||
| 	 */ | ||||
| 	const INVITATION_WAIT = 1; | ||||
| 	/** | ||||
| 	 * Invitation was accepted by visitor | ||||
| 	 */ | ||||
| 	const INVITATION_ACCEPTED = 2; | ||||
| 	/** | ||||
| 	 * Invitation was rejected by visitor | ||||
| 	 */ | ||||
| 	const INVITATION_REJECTED = 3; | ||||
| 	/** | ||||
| 	 * Invitation was ignored by visitor. Invitation was automatically closed. | ||||
| 	 */ | ||||
| 	const INVITATION_IGNORED = 4; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Message sent by user | ||||
| @ -106,6 +131,8 @@ Class Thread { | ||||
| 	 *  - 'id': id of the thread | ||||
| 	 *  - 'lastRevision': last revision number | ||||
| 	 *  - 'state': state of the thread. See Thread::STATE_* | ||||
| 	 *  - 'invitationState': state of invitation. See INVITATION_* constants, | ||||
| 	 *    defined in libs/invitation.php | ||||
| 	 *  - 'lastToken': last chat token | ||||
| 	 *  - 'nextAgent': id of the next agent(agent that change current agent in the chat) | ||||
| 	 *  - 'groupId': id of the group related to the thread | ||||
| @ -138,6 +165,7 @@ Class Thread { | ||||
| 
 | ||||
| 		'lastRevision' => 'lrevision', | ||||
| 		'state' => 'istate', | ||||
| 		'invitationState' => 'invitationstate', | ||||
| 		'lastToken' => 'ltoken', | ||||
| 
 | ||||
| 		'nextAgent' => 'nextagent', | ||||
|  | ||||
| @ -183,6 +183,7 @@ class UsersProcessor extends ClientSideProcessor { | ||||
| 			" from {chatthread} t left outer join {chatgroup} g on " . | ||||
| 			" t.groupid = g.groupid " . | ||||
| 			" where t.lrevision > :since " . | ||||
| 			" AND t.istate <> " . Thread::STATE_INVITED . | ||||
| 			($since == 0 | ||||
| 				// Select only active threads at first time when lrevision = 0
 | ||||
| 				? " AND t.istate <> " . Thread::STATE_CLOSED . | ||||
| @ -377,19 +378,35 @@ class UsersProcessor extends ClientSideProcessor { | ||||
| 			// Load visitors list
 | ||||
| 			$db = Database::getInstance(); | ||||
| 			// 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 = "SELECT v.visitorid, " . | ||||
| 					"v.userid, " . | ||||
| 					"v.username, " . | ||||
| 					"v.firsttime, " . | ||||
| 					"v.lasttime, " . | ||||
| 					"v.entry, " . | ||||
| 					"v.details, " . | ||||
| 					"t.invitationstate, " . | ||||
| 					"t.dtmcreated AS invitationtime, " . | ||||
| 					"t.agentId AS invitedby, " . | ||||
| 					"v.invitations, " . | ||||
| 					"v.chats " . | ||||
| 				"FROM {chatsitevisitor} v " . | ||||
| 					"LEFT OUTER JOIN {chatthread} t " . | ||||
| 						"ON t.threadid = v.threadid " . | ||||
| 				"WHERE v.threadid IS NULL " . | ||||
| 					"OR (t.istate = :state_invited " . | ||||
| 						"AND t.invitationstate = :invitation_wait)" . | ||||
| 				"ORDER BY t.invitationstate, v.lasttime DESC, v.invitations"; | ||||
| 			$query .= (Settings::get('visitors_limit') == '0') | ||||
| 				? "" | ||||
| 				: " LIMIT " . Settings::get('visitors_limit'); | ||||
| 
 | ||||
| 			$rows = $db->query( | ||||
| 				$query, | ||||
| 				NULL, | ||||
| 				array( | ||||
| 					':state_invited' => Thread::STATE_INVITED, | ||||
| 					':invitation_wait' => Thread::INVITATION_WAIT | ||||
| 				), | ||||
| 				array('return_rows' => Database::RETURN_ALL_ROWS) | ||||
| 			); | ||||
| 
 | ||||
| @ -410,6 +427,7 @@ class UsersProcessor extends ClientSideProcessor { | ||||
| 				} | ||||
| 
 | ||||
| 				// Get invitation info
 | ||||
| 				$row['invited'] = ($row['invitationstate'] == Thread::INVITATION_WAIT); | ||||
| 				if ($row['invited']) { | ||||
| 					$agent_name  = get_operator_name( | ||||
| 						operator_by_id($row['invitedby']) | ||||
|  | ||||
| @ -15,71 +15,193 @@ | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| function invitation_state($visitorid) | ||||
| { | ||||
| /** | ||||
|  * Check invitation state for specified visitior | ||||
|  * | ||||
|  * @param int $visitor_id ID of the visitor to check | ||||
|  * @return array Array of invitation info. It contains following items: | ||||
|  *  - 'invited': boolean, indicates if the visitor was invited by an operator; | ||||
|  *  - 'threadid': int, ID of the thread, related with visitor or boolean false | ||||
|  *    if visitor with specfied ID does not exist. | ||||
|  */ | ||||
| function invitation_state($visitor_id) { | ||||
| 	$db = Database::getInstance(); | ||||
| 	$result = $db->query( | ||||
| 		"select invited, threadid from {chatsitevisitor} where visitorid = ?", | ||||
| 		array($visitorid), | ||||
| 	$db_result = $db->query( | ||||
| 		"SELECT t.threadid, t.invitationstate, t.istate " . | ||||
| 		"FROM {chatsitevisitor} v, {chatthread} t " . | ||||
| 		"WHERE visitorid = ? " . | ||||
| 			"AND t.threadid = v.threadid", | ||||
| 		array($visitor_id), | ||||
| 		array('return_rows' => Database::RETURN_ONE_ROW) | ||||
| 	); | ||||
| 	if (!$result) { | ||||
| 	    $result['invited'] = 0; | ||||
| 	    $result['threadid'] = 0; | ||||
| 	} | ||||
| 	return $result; | ||||
| } | ||||
| 
 | ||||
| function invitation_invite($visitorid, $operatorid) | ||||
| { | ||||
| 	if (!invitation_check($visitorid)) { | ||||
| 		$db = Database::getInstance(); | ||||
| 		$db->query( | ||||
| 			"update {chatsitevisitor} set invited = 1, invitedby = :operatorid, " . | ||||
| 			"invitationtime = :now, invitations = invitations + 1 where visitorid = :visitorid", | ||||
| 			array( | ||||
| 				':operatorid' => $operatorid, | ||||
| 				':visitorid' => $visitorid, | ||||
| 				':now' => time() | ||||
| 			) | ||||
| 		); | ||||
| 		return invitation_check($visitorid); | ||||
| 	$ret = array(); | ||||
| 	if (!$db_result) { | ||||
| 	    $ret['invited'] = false; | ||||
| 	    $ret['threadid'] = false; | ||||
| 	} else { | ||||
| 		return FALSE; | ||||
| 		$ret['invited'] = ($db_result['istate'] == Thread::STATE_INVITED) | ||||
| 			&& ($db_result['invitationstate'] == Thread::INVITATION_WAIT); | ||||
| 		$ret['threadid'] = $db_result['threadid']; | ||||
| 	} | ||||
| 	return $ret; | ||||
| } | ||||
| 
 | ||||
| function invitation_check($visitorid) | ||||
| { | ||||
| 	$db = Database::getInstance(); | ||||
| 	$result = $db->query( | ||||
| 		"select invitedby from {chatsitevisitor} where invited and visitorid = ? " . | ||||
| 		 " and lasttime < invitationtime and threadid is null", | ||||
| 		array($visitorid), | ||||
| 		array('return_rows' => Database::RETURN_ONE_ROW) | ||||
| 	); | ||||
| 	return ($result && isset($result['invitedby']) && $result['invitedby']) ? $result['invitedby'] : FALSE; | ||||
| } | ||||
| /** | ||||
|  * Invite visitor by operator | ||||
|  * | ||||
|  * @global string $current_locale Current locale code | ||||
|  * @param int $visitor_id ID of the visitor, who must be invited. | ||||
|  * @param array $operator Info for operator  who invite the visitor | ||||
|  * @return Thread|boolean Thread object related with invitation or boolean | ||||
|  * false on failure | ||||
|  */ | ||||
| function invitation_invite($visitor_id, $operator) { | ||||
| 	global $current_locale; | ||||
| 
 | ||||
| 	// The visitor already invited
 | ||||
| 	if (invitation_check($visitor_id)) { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	// Get visitor info
 | ||||
| 	$visitor = track_get_visitor_by_id($visitor_id); | ||||
| 
 | ||||
| 	// Get last page visited by the visitor
 | ||||
| 	$visitor_path = track_get_path($visitor); | ||||
| 	ksort($visitor_path); | ||||
| 	$last_visited_page = array_pop($visitor_path); | ||||
| 
 | ||||
| 	// Get visitor details
 | ||||
| 	$visitor_details = track_retrieve_details($visitor); | ||||
| 
 | ||||
| 	// Get some operator's info
 | ||||
| 	$operator_name = get_operator_name($operator); | ||||
| 
 | ||||
| 	// Create thread for invitation
 | ||||
| 	$thread = Thread::create(); | ||||
| 	if (! $thread) { | ||||
| 		// Something went wrong
 | ||||
| 		return false; | ||||
| 	} | ||||
| 	// Populate thread and save it
 | ||||
| 	$thread->agentId = $operator['operatorid']; | ||||
| 	$thread->agentName = $operator_name; | ||||
| 	$thread->userName = $visitor['username']; | ||||
| 	$thread->remote = $visitor_details['remote_host']; | ||||
| 	$thread->referer = $last_visited_page; | ||||
| 	// User's locale is unknown, set operator locale to the thread
 | ||||
| 	$thread->locale = $current_locale; | ||||
| 	$thread->userId = $visitor['userid']; | ||||
| 	$thread->userAgent = $visitor_details['user_agent']; | ||||
| 	$thread->state = Thread::STATE_INVITED; | ||||
| 	$thread->invitationState = Thread::INVITATION_WAIT; | ||||
| 	$thread->save(); | ||||
| 
 | ||||
| function invitation_accept($visitorid, $threadid) | ||||
| { | ||||
| 	$db = Database::getInstance(); | ||||
| 	$db->query( | ||||
| 		"update {chatsitevisitor} set threadid = ?, chats = chats + 1 where visitorid = ?", | ||||
| 		array($threadid, $visitorid) | ||||
| 		"UPDATE {chatsitevisitor} set " . | ||||
| 			"invitations = invitations + 1, " . | ||||
| 			"threadid = :thread_id " . | ||||
| 		"WHERE visitorid = :visitor_id", | ||||
| 		array( | ||||
| 			':thread_id' => $thread->id, | ||||
| 			':visitor_id' => $visitor_id | ||||
| 		) | ||||
| 	); | ||||
| 
 | ||||
| 	// Send some messages
 | ||||
| 	$thread->postMessage( | ||||
| 		Thread::KIND_FOR_AGENT, | ||||
| 		getlocal2( | ||||
| 			'chat.visitor.invitation.sent', | ||||
| 			array($operator_name, $last_visited_page) | ||||
| 		) | ||||
| 	); | ||||
| 	$thread->postMessage( | ||||
| 		Thread::KIND_AGENT, | ||||
| 		getlocal("invitation.message"), | ||||
| 		$operator_name | ||||
| 	); | ||||
| 
 | ||||
| 	return $thread; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Check if visitor already invited | ||||
|  * | ||||
|  * @param int $visitor_id ID of the visitor to check | ||||
|  * @return int|boolean ID of the operator who invite the visitor or boolean | ||||
|  * false if the visitor was not invited. | ||||
|  */ | ||||
| function invitation_check($visitor_id) { | ||||
| 	$db = Database::getInstance(); | ||||
| 	$result = $db->query( | ||||
| 		"select invitedby from {chatsitevisitor} where visitorid = ?", | ||||
| 		array($visitorid), | ||||
| 		"SELECT t.agentId AS invitedby " . | ||||
| 		"FROM {chatsitevisitor} v, {chatthread} t " . | ||||
| 		"WHERE v.threadid = t.threadid " . | ||||
| 			"AND v.visitorid = :visitor_id " . | ||||
| 			// Check only for new invitations. Refactor this place later
 | ||||
| 			"AND v.lasttime < t.dtmcreated " . | ||||
| 			"AND t.istate = :state_invited " . | ||||
| 			"AND t.invitationstate = :invitation_wait ", | ||||
| 		array( | ||||
| 			':visitor_id' => $visitor_id, | ||||
| 			':state_invited' => Thread::STATE_INVITED, | ||||
| 			':invitation_wait' => Thread::INVITATION_WAIT | ||||
| 		), | ||||
| 		array('return_rows' => Database::RETURN_ONE_ROW) | ||||
| 	); | ||||
| 	return empty($result['invitedby']) ? false : $result['invitedby']; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Invitation was accepted by visitor | ||||
|  * | ||||
|  * @param int $visitor_id ID of the visitor who accept invitation | ||||
|  * @return Thread|boolean Thread object or boolean false on failure | ||||
|  */ | ||||
| function invitation_accept($visitor_id) { | ||||
| 	// Check if visitor was invited
 | ||||
| 	$invitation_state = invitation_state($visitor_id); | ||||
| 	if (! $invitation_state['invited']) { | ||||
| 		// Visitor was not invited
 | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	// Get thread related with the visitor
 | ||||
| 	$db = Database::getInstance(); | ||||
| 	$result = $db->query( | ||||
| 		"SELECT threadid FROM {chatsitevisitor} WHERE visitorid = :visitor_id", | ||||
| 		array(':visitor_id' => $visitor_id), | ||||
| 		array('return_rows' => Database::RETURN_ONE_ROW) | ||||
| 	); | ||||
| 
 | ||||
| 	if ($result && isset($result['invitedby']) && $result['invitedby']) { | ||||
| 		return $result['invitedby']; | ||||
| 	} else { | ||||
| 		return FALSE; | ||||
| 	if (empty($result['threadid'])) { | ||||
| 		// Something went wrong. There is no thread related with the visitor.
 | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	$thread = Thread::load($result['threadid']); | ||||
| 	if (! $thread) { | ||||
| 		// Something went wrong. Cannot load thread.
 | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	// Update thread info
 | ||||
| 	$thread->state = Thread::STATE_LOADING; | ||||
| 	$thread->invitationState = Thread::INVITATION_ACCEPTED; | ||||
| 	$thread->save(); | ||||
| 
 | ||||
| 	// Update visitor info
 | ||||
| 	$db->query( | ||||
| 		"UPDATE {chatsitevisitor} SET chats = chats + 1 " . | ||||
| 		"WHERE visitorid = :visitor_id", | ||||
| 		array(':visitor_id' => $visitor_id) | ||||
| 	); | ||||
| 
 | ||||
| 	return $thread; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
| @ -88,12 +210,30 @@ function invitation_accept($visitorid, $threadid) | ||||
|  * @param int $visitor_id ID of the visitor | ||||
|  */ | ||||
| function invitation_reject($visitor_id) { | ||||
| 	$visitor = track_get_visitor_by_id($visitor_id); | ||||
| 
 | ||||
| 	// Send message to operator
 | ||||
| 	$thread = Thread::load($visitor['threadid']); | ||||
| 	if ($thread) { | ||||
| 		$thread->postMessage( | ||||
| 			Thread::KIND_FOR_AGENT, | ||||
| 			getlocal('chat.visitor.invitation.rejected') | ||||
| 		); | ||||
| 	} | ||||
| 
 | ||||
| 	$db = Database::getInstance(); | ||||
| 	$db->query( | ||||
| 		"UPDATE {chatsitevisitor} SET invited = 0, " . | ||||
| 			"invitationtime = NULL, invitedby = NULL " . | ||||
| 		"WHERE visitorid = ?", | ||||
| 		array($visitor_id) | ||||
| 		"UPDATE {chatsitevisitor} v, {chatthread} t SET " . | ||||
| 			"v.threadid = NULL, " . | ||||
| 			"t.invitationstate = :invitation_rejected, " . | ||||
| 			"t.istate = :state_closed " . | ||||
| 		"WHERE t.threadid = v.threadid " . | ||||
| 			"AND visitorid = :visitor_id", | ||||
| 		array( | ||||
| 			':invitation_rejected' => Thread::INVITATION_REJECTED, | ||||
| 			':state_closed' => Thread::STATE_CLOSED, | ||||
| 			':visitor_id' => $visitor_id | ||||
| 		) | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| @ -105,14 +245,56 @@ function invitation_close_old() { | ||||
| 
 | ||||
| 	// Remove old invitations
 | ||||
| 	$db->query( | ||||
| 		"UPDATE {chatsitevisitor} SET invited = 0, " . | ||||
| 			"invitationtime = NULL, invitedby = NULL". | ||||
| 		" WHERE threadid IS NULL AND (:now - invitationtime) > :lifetime", | ||||
| 		"UPDATE {chatsitevisitor} v, {chatthread} t SET " . | ||||
| 			"t.invitationstate = :invitation_ignored, " . | ||||
| 			"t.istate = :state_closed, " . | ||||
| 			"v.threadid = NULL " . | ||||
| 		"WHERE t.istate = :state_invited " . | ||||
| 			"AND t.invitationstate = :invitation_wait " . | ||||
| 			"AND (:now - t.dtmcreated) > :lifetime", | ||||
| 		array( | ||||
| 			':invitation_ignored' => Thread::INVITATION_IGNORED, | ||||
| 			':invitation_wait' => Thread::INVITATION_WAIT, | ||||
| 			':state_closed' => Thread::STATE_CLOSED, | ||||
| 			':state_invited' => Thread::STATE_INVITED, | ||||
| 			':lifetime' => Settings::get('invitation_lifetime'), | ||||
| 			':now' => time() | ||||
| 		) | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Prepare data to dispaly invitation | ||||
|  * | ||||
|  * @param Thread $thread Thread object related with invitation | ||||
|  * @return array Array of invitation data | ||||
|  */ | ||||
| function setup_invitation_view(Thread $thread) { | ||||
| 	$data = array(); | ||||
| 
 | ||||
| 	// Set refresh frequency
 | ||||
| 	$data['frequency'] = Settings::get('updatefrequency_chat'); | ||||
| 
 | ||||
| 	// Load JavaScript plugins and JavaScripts, CSS files required by them
 | ||||
| 	$data = array_merge_recursive($data, get_plugins_data('client_chat_window')); | ||||
| 
 | ||||
| 	// Create some empty arrays
 | ||||
| 	$data['invitation'] = array(); | ||||
| 
 | ||||
| 	$data['invitation']['thread'] = array( | ||||
| 		'id' => $thread->id, | ||||
| 		'token' => $thread->lastToken | ||||
| 	); | ||||
| 
 | ||||
| 	$data['invitation']['user'] = array( | ||||
| 		'name' => htmlspecialchars(topage($thread->userName)), | ||||
| 		'canChangeName' => false, | ||||
| 		'isAgent' => false | ||||
| 	); | ||||
| 
 | ||||
| 	$data['startFrom'] = 'invitation'; | ||||
| 
 | ||||
| 	return $data; | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
| @ -81,6 +81,8 @@ chat.thread.state_wait_for_another_agent=Waiting for operator | ||||
| chat.visitor.email=E-Mail: {0} | ||||
| chat.visitor.info=Info: {0} | ||||
| chat.visitor.invitation.accepted=Visitor accepted invitation from operator {0} | ||||
| chat.visitor.invitation.rejected=Visitor rejected invitation | ||||
| chat.visitor.invitation.sent=Operator {0} invites visitor at {1} page | ||||
| chat.wait=Thank you for contacting us. An operator will be with you shortly. | ||||
| chat.window.chatting_with=You are chatting with: | ||||
| chat.window.close_title=Close chat | ||||
|  | ||||
| @ -81,6 +81,8 @@ chat.thread.state_wait_for_another_agent= | ||||
| chat.visitor.email=E-Mail: {0} | ||||
| chat.visitor.info=Î Ïîñåòèòåëå: {0} | ||||
| chat.visitor.invitation.accepted=Ïîñåòèòåëü ïðèíÿë ïðèãëàøåíèå îò îïåðàòîðà {0} | ||||
| chat.visitor.invitation.rejected=Ïîñåòèòåëü îòêëîíèë ïðèãëàøåíèå | ||||
| chat.visitor.invitation.sent=Îïåðàòîð {0} ïðèãëàñèë ïîñåòèòåëÿ íà ñòðàíèöå {1} | ||||
| chat.wait=Ïîæàëóéñòà, ïîäîæäèòå íåìíîãî, ê Âàì ïðèñîåäèíèòñÿ îïåðàòîð.. | ||||
| chat.window.chatting_with=Âû îáùàåòåñü ñ: | ||||
| chat.window.close_title=Çàêðûòü äèàëîã | ||||
|  | ||||
| @ -17,20 +17,23 @@ | ||||
| 
 | ||||
| require_once('../libs/init.php'); | ||||
| require_once('../libs/invitation.php'); | ||||
| require_once('../libs/track.php'); | ||||
| require_once('../libs/operator.php'); | ||||
| require_once('../libs/classes/thread.php'); | ||||
| 
 | ||||
| $operator = check_login(); | ||||
| 
 | ||||
| $visitorid = verifyparam("visitor", "/^\d{1,8}$/"); | ||||
| 
 | ||||
| if (!invitation_invite($visitorid, $operator['operatorid'])) { | ||||
| $thread = invitation_invite($visitorid, $operator); | ||||
| if (!$thread) { | ||||
|     die("Invitation failed!"); | ||||
| } | ||||
| 
 | ||||
| $page = array(); | ||||
| $page['visitor'] = $visitorid; | ||||
| $page['frequency'] = Settings::get('updatefrequency_operator'); | ||||
| // Open chat window for operator
 | ||||
| $redirect_to = $webimroot . | ||||
| 	'/operator/agent.php?thread=' . $thread->id . | ||||
| 	'&token=' . $thread->lastToken; | ||||
| header('Location: ' . $redirect_to); | ||||
| 
 | ||||
| start_html_output(); | ||||
| require('../view/invite.php'); | ||||
| ?>
 | ||||
| @ -459,4 +459,41 @@ ul li { | ||||
|     top: 200px; | ||||
|     left: 250px; | ||||
| } | ||||
| /* ----- */ | ||||
| /* ----- */ | ||||
| 
 | ||||
| /* Invitations */ | ||||
| #invitation-messages-region { | ||||
|     height: 150px; | ||||
|     min-height: 150px; | ||||
|     width: 398px; | ||||
|     overflow-y: auto; | ||||
|     padding: 0px; | ||||
|     font: normal 10px Tahoma; | ||||
|     line-height: 1.8em; | ||||
|     color: #999; | ||||
|     background-color: #FFFFFF; | ||||
| } | ||||
| #invitation-messages-region .minf { | ||||
|     font-size: 1.1em; | ||||
|     color: #7BAA0F; | ||||
| } | ||||
| #invitation-messages-region .mhidden, | ||||
| #invitation-messages-region .mevent { | ||||
|     font-size: 1.1em; | ||||
| } | ||||
| #invitation-messages-region .nagent { | ||||
|     font-size: 1.1em; | ||||
|     font-weight: bold; | ||||
|     color: #000; | ||||
| } | ||||
| #invitation-messages-region .nuser { | ||||
|     font-size: 1.1em; | ||||
|     font-weight: bold; | ||||
|     color: #DA251D; | ||||
| } | ||||
| #invitation-messages-region .magent, | ||||
| #invitation-messages-region .muser { | ||||
|     font-size: 1.1em; | ||||
|     color: #000; | ||||
| } | ||||
| /* ----- */ | ||||
|  | ||||
| @ -0,0 +1 @@ | ||||
| <div id="invitation-messages-region"></div> | ||||
| @ -27,13 +27,13 @@ d;d={hash:{},data:c};return q((b=f.apply,b?b.call(a,a.message,"urlReplace, nl2br | ||||
| a.helpers;c=c||{};var p,r="function",h=this.escapeExpression,l=f.helperMissing,k=this;a='<div id="message">\n';if((b=f["if"].call(d,(p=d.user,null==p||!1===p?p:p.canPost),{hash:{},inverse:k.noop,fn:k.program(1,function(){return'\n    <div class="bgc"><div class="bgl"><div class="bgr">\n        <textarea id="message-input" class="message" tabindex="0" rows="4" cols="10"></textarea>\n    </div></div></div>\n'},c),data:c}))||0===b)a+=b;a+='\n</div>\n\n<div id="send">\n';if((b=f["if"].call(d,(p=d.user, | ||||
| null==p||!1===p?p:p.canPost),{hash:{},inverse:k.noop,fn:k.program(3,function(a,c){var j,e,b;j='\n    <div id="postmessage">\n        <div id="predefined-wrapper">\n            ';if((b=f["if"].call(a,(e=a.user,null==e||!1===e?e:e.isAgent),{hash:{},inverse:k.noop,fn:k.program(4,g,c),data:c}))||0===b)j+=b;b={hash:{},data:c};j=j+'\n        </div>\n        <a href="javascript:void(0)" id="send-message" title="'+(h((e=f.L10n,e?e.call(a,"chat.window.send_message",b):l.call(a,"L10n","chat.window.send_message", | ||||
| b)))+'">');b={hash:{},data:c};return j+=h((e=f.L10n,e?e.call(a,"chat.window.send_message_short_and_shortcut",b):l.call(a,"L10n","chat.window.send_message_short_and_shortcut",b)))+"</a>\n    </div>\n"},c),data:c}))||0===b)a+=b;return a+'\n</div>\n<div class="clear"></div>'});s.chat_status_base=r(function(a,d,f,b,c){this.compilerInfo=[3,">= 1.0.0-rc.4"];f=f||a.helpers;c=c||{};a=this.escapeExpression;(f=f.title)?f=f.call(d,{hash:{},data:c}):(f=d.title,f="function"===typeof f?f.apply(d):f);return a(f)}); | ||||
| s.chat_status_message=r(function(a,d,f,b,c){this.compilerInfo=[3,">= 1.0.0-rc.4"];f=f||a.helpers;c=c||{};a=this.escapeExpression;(f=f.message)?f=f.call(d,{hash:{},data:c}):(f=d.message,f="function"===typeof f?f.apply(d):f);return a(f)});s.chat_status_typing=r(function(a,d,f,b,c){this.compilerInfo=[3,">= 1.0.0-rc.4"];f=f||a.helpers;c=c||{};var g;a=f.helperMissing;b=this.escapeExpression;c={hash:{},data:c};return b((g=f.L10n,g?g.call(d,"typing.remote",c):a.call(d,"L10n","typing.remote",c)))});s.leave_message_description= | ||||
| r(function(a,d,f,b,c){this.compilerInfo=[3,">= 1.0.0-rc.4"];f=f||a.helpers;c=c||{};var g,q=f.helperMissing,p=this.escapeExpression;b={hash:{},data:c};a='<div class="buttons">\n    <a href="javascript:window.close();" title="'+(p((g=f.L10n,g?g.call(d,"leavemessage.close",b):q.call(d,"L10n","leavemessage.close",b)))+'">\n        <img class="tpl-image iclosewin" src="'+p((g=(g=d.page,null==g||!1===g?g:g.webimRoot),"function"===typeof g?g.apply(d):g))+'/images/free.gif" alt="');b={hash:{},data:c};a+= | ||||
| p((g=f.L10n,g?g.call(d,"leavemessage.close",b):q.call(d,"L10n","leavemessage.close",b)))+'" />\n    </a>\n</div>\n<div class="messagetxt">';b={hash:{},data:c};return a+=p((g=f.L10n,g?g.call(d,"leavemessage.descr",b):q.call(d,"L10n","leavemessage.descr",b)))+"</div>"});s.leave_message_form=r(function(a,d,f,b,c){function g(e,a){var c,b;c='<input type="hidden" name="group" value="';(b=f.groupId)?b=b.call(e,{hash:{},data:a}):(b=e.groupId,b=typeof b===k?b.apply(e):b);return c+=m(b)+'"/>'}function q(e, | ||||
| a){var c,b,j;c=""+('\n                        <option value="'+m((b=e.id,typeof b===k?b.apply(e):b))+'" ');if((j=f["if"].call(e,e.selected,{hash:{},inverse:n.noop,fn:n.program(6,p,a),data:a}))||0===j)c+=j;return c+=">"+m((b=e.name,typeof b===k?b.apply(e):b))+"</option>\n                    "}function p(){return'selected="selected"'}function r(e,a){var b;return(b=f["if"].call(e,e.selected,{hash:{},inverse:n.noop,fn:n.program(9,h,a),data:a}))||0===b?b:""}function h(e){var a;return m((a=e.description, | ||||
| typeof a===k?a.apply(e):a))}this.compilerInfo=[3,">= 1.0.0-rc.4"];f=f||a.helpers;c=c||{};var l,k="function",m=this.escapeExpression,n=this,j=f.helperMissing;a=""+('<form name="leaveMessageForm" method="post" action="">\n    <input type="hidden" name="style" value="'+m((l=(l=d.page,null==l||!1===l?l:l.style),typeof l===k?l.apply(d):l))+'"/>\n    <input type="hidden" name="info" value="');(b=f.info)?b=b.call(d,{hash:{},data:c}):(b=d.info,b=typeof b===k?b.apply(d):b);a+=m(b)+'"/>\n    <input type="hidden" name="referrer" value="'; | ||||
| (b=f.referrer)?b=b.call(d,{hash:{},data:c}):(b=d.referrer,b=typeof b===k?b.apply(d):b);a+=m(b)+'"/>\n    ';if((b=f.unless.call(d,d.groups,{hash:{},inverse:n.noop,fn:n.program(1,function(e,a){var b;return(b=f["if"].call(e,e.groupId,{hash:{},inverse:n.noop,fn:n.program(2,g,a),data:a}))||0===b?b:""},c),data:c}))||0===b)a+=b;b={hash:{},data:c};a=a+'\n\n    <div class="errors"></div>\n\n    <table cellspacing="1" cellpadding="5" border="0" class="form">\n        <tr>\n            <td><strong>'+(m((l=f.L10n, | ||||
| l?l.call(d,"form.field.email",b):j.call(d,"L10n","form.field.email",b)))+':</strong></td>\n            <td><input type="text" name="email" size="50" value="');(b=f.email)?b=b.call(d,{hash:{},data:c}):(b=d.email,b=typeof b===k?b.apply(d):b);a+=m(b)+'" class="username"/></td>\n        </tr>\n        <tr>\n            <td><strong>';b={hash:{},data:c};a+=m((l=f.L10n,l?l.call(d,"form.field.name",b):j.call(d,"L10n","form.field.name",b)))+':</strong></td>\n            <td><input type="text" name="name" size="50" value="'; | ||||
| s.chat_status_message=r(function(a,d,f,b,c){this.compilerInfo=[3,">= 1.0.0-rc.4"];f=f||a.helpers;c=c||{};a=this.escapeExpression;(f=f.message)?f=f.call(d,{hash:{},data:c}):(f=d.message,f="function"===typeof f?f.apply(d):f);return a(f)});s.chat_status_typing=r(function(a,d,f,b,c){this.compilerInfo=[3,">= 1.0.0-rc.4"];f=f||a.helpers;c=c||{};var g;a=f.helperMissing;b=this.escapeExpression;c={hash:{},data:c};return b((g=f.L10n,g?g.call(d,"typing.remote",c):a.call(d,"L10n","typing.remote",c)))});s.invitation_layout= | ||||
| r(function(){this.compilerInfo=[3,">= 1.0.0-rc.4"];return'<div id="invitation-messages-region"></div>'});s.leave_message_description=r(function(a,d,f,b,c){this.compilerInfo=[3,">= 1.0.0-rc.4"];f=f||a.helpers;c=c||{};var g,q=f.helperMissing,p=this.escapeExpression;b={hash:{},data:c};a='<div class="buttons">\n    <a href="javascript:window.close();" title="'+(p((g=f.L10n,g?g.call(d,"leavemessage.close",b):q.call(d,"L10n","leavemessage.close",b)))+'">\n        <img class="tpl-image iclosewin" src="'+ | ||||
| p((g=(g=d.page,null==g||!1===g?g:g.webimRoot),"function"===typeof g?g.apply(d):g))+'/images/free.gif" alt="');b={hash:{},data:c};a+=p((g=f.L10n,g?g.call(d,"leavemessage.close",b):q.call(d,"L10n","leavemessage.close",b)))+'" />\n    </a>\n</div>\n<div class="messagetxt">';b={hash:{},data:c};return a+=p((g=f.L10n,g?g.call(d,"leavemessage.descr",b):q.call(d,"L10n","leavemessage.descr",b)))+"</div>"});s.leave_message_form=r(function(a,d,f,b,c){function g(e,a){var c,b;c='<input type="hidden" name="group" value="'; | ||||
| (b=f.groupId)?b=b.call(e,{hash:{},data:a}):(b=e.groupId,b=typeof b===k?b.apply(e):b);return c+=m(b)+'"/>'}function q(e,a){var c,b,j;c=""+('\n                        <option value="'+m((b=e.id,typeof b===k?b.apply(e):b))+'" ');if((j=f["if"].call(e,e.selected,{hash:{},inverse:n.noop,fn:n.program(6,p,a),data:a}))||0===j)c+=j;return c+=">"+m((b=e.name,typeof b===k?b.apply(e):b))+"</option>\n                    "}function p(){return'selected="selected"'}function r(e,a){var b;return(b=f["if"].call(e,e.selected, | ||||
| {hash:{},inverse:n.noop,fn:n.program(9,h,a),data:a}))||0===b?b:""}function h(e){var a;return m((a=e.description,typeof a===k?a.apply(e):a))}this.compilerInfo=[3,">= 1.0.0-rc.4"];f=f||a.helpers;c=c||{};var l,k="function",m=this.escapeExpression,n=this,j=f.helperMissing;a=""+('<form name="leaveMessageForm" method="post" action="">\n    <input type="hidden" name="style" value="'+m((l=(l=d.page,null==l||!1===l?l:l.style),typeof l===k?l.apply(d):l))+'"/>\n    <input type="hidden" name="info" value="'); | ||||
| (b=f.info)?b=b.call(d,{hash:{},data:c}):(b=d.info,b=typeof b===k?b.apply(d):b);a+=m(b)+'"/>\n    <input type="hidden" name="referrer" value="';(b=f.referrer)?b=b.call(d,{hash:{},data:c}):(b=d.referrer,b=typeof b===k?b.apply(d):b);a+=m(b)+'"/>\n    ';if((b=f.unless.call(d,d.groups,{hash:{},inverse:n.noop,fn:n.program(1,function(e,a){var b;return(b=f["if"].call(e,e.groupId,{hash:{},inverse:n.noop,fn:n.program(2,g,a),data:a}))||0===b?b:""},c),data:c}))||0===b)a+=b;b={hash:{},data:c};a=a+'\n\n    <div class="errors"></div>\n\n    <table cellspacing="1" cellpadding="5" border="0" class="form">\n        <tr>\n            <td><strong>'+ | ||||
| (m((l=f.L10n,l?l.call(d,"form.field.email",b):j.call(d,"L10n","form.field.email",b)))+':</strong></td>\n            <td><input type="text" name="email" size="50" value="');(b=f.email)?b=b.call(d,{hash:{},data:c}):(b=d.email,b=typeof b===k?b.apply(d):b);a+=m(b)+'" class="username"/></td>\n        </tr>\n        <tr>\n            <td><strong>';b={hash:{},data:c};a+=m((l=f.L10n,l?l.call(d,"form.field.name",b):j.call(d,"L10n","form.field.name",b)))+':</strong></td>\n            <td><input type="text" name="name" size="50" value="'; | ||||
| (b=f.name)?b=b.call(d,{hash:{},data:c}):(b=d.name,b=typeof b===k?b.apply(d):b);a+=m(b)+'" class="username"/></td>\n        </tr>\n    ';if((b=f["if"].call(d,d.groups,{hash:{},inverse:n.noop,fn:n.program(4,function(e,a){var b,c,d;d={hash:{},data:a};b='\n        <tr>\n            <td class="text"><strong>'+(m((c=f.L10n,c?c.call(e,"form.field.department",d):j.call(e,"L10n","form.field.department",d)))+'</strong></td>\n            <td>\n                <select name="group" style="min-width:200px;">\n                    '); | ||||
| if((d=f.each.call(e,e.groups,{hash:{},inverse:n.noop,fn:n.program(5,q,a),data:a}))||0===d)b+=d;b+='\n                </select>\n            </td>\n        </tr>\n        <tr>\n            <td class="text"><strong>';d={hash:{},data:a};b+=m((c=f.L10n,c?c.call(e,"form.field.department.description",d):j.call(e,"L10n","form.field.department.description",d)))+'</strong></td>\n            <td class="text" id="groupDescription">\n                ';if((d=f.each.call(e,e.groups,{hash:{},inverse:n.noop,fn:n.program(8, | ||||
| r,a),data:a}))||0===d)b+=d;return b+="\n            </td>\n        </tr>\n    "},c),data:c}))||0===b)a+=b;a+="\n        <tr>\n            <td><strong>";b={hash:{},data:c};a+=m((l=f.L10n,l?l.call(d,"form.field.message",b):j.call(d,"L10n","form.field.message",b)))+':</strong></td>\n            <td valign="top">\n                <textarea name="message" tabindex="0" cols="40" rows="5">';(b=f.message)?b=b.call(d,{hash:{},data:c}):(b=d.message,b=typeof b===k?b.apply(d):b);a+=m(b)+"</textarea>\n            </td>\n        </tr>\n    "; | ||||
|  | ||||
| @ -103,6 +103,9 @@ | ||||
|                     ${if:leaveMessageOptions} | ||||
|                         leaveMessageOptions: ${page:leaveMessageOptions}, | ||||
|                     ${endif:leaveMessageOptions} | ||||
|                     ${if:invitationOptions} | ||||
|                         invitationOptions: ${page:invitationOptions}, | ||||
|                     ${endif:invitationOptions} | ||||
|                     startFrom: "${page:startFrom}", | ||||
|                     plugins: ${page:js_plugin_options} | ||||
|                 }); | ||||
|  | ||||
| @ -80,3 +80,10 @@ | ||||
|     cursor: pointer !important; | ||||
|     float: left !important; | ||||
| } | ||||
| 
 | ||||
| #mibewinvitationframe { | ||||
|     width: 398px; | ||||
|     height: 150px; | ||||
|     overflow: hidden; | ||||
|     border: 1px solid #000; | ||||
| } | ||||
|  | ||||
| @ -1,67 +0,0 @@ | ||||
| <?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. | ||||
|  */ | ||||
| 
 | ||||
| $page['title'] = getlocal("invitation.title"); | ||||
| 
 | ||||
| function tpl_header() { global $page, $webimroot; | ||||
| ?>
 | ||||
| 
 | ||||
| <!-- External libs --> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/jquery.min.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/json2.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/underscore-min.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/backbone-min.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/backbone.marionette.min.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/handlebars.js"></script> | ||||
| 
 | ||||
| <!-- Application files --> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/compiled/mibewapi.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/compiled/default_app.js"></script> | ||||
| <script type="text/javascript" src="<?php echo $webimroot ?>/js/compiled/invite_app.js"></script> | ||||
| 
 | ||||
| 
 | ||||
| <script type="text/javascript"><!-- | ||||
| 	jQuery(document).ready(function(){ | ||||
| 		Mibew.Application.start({ | ||||
| 			server: { | ||||
| 				url: "<?php echo $webimroot ?>/operator/invitationstate.php", | ||||
| 				requestsFrequency: <?php echo $page['frequency'] ?>
 | ||||
| 			}, | ||||
| 
 | ||||
| 			visitorId: "<?php echo $page['visitor'] ?>", | ||||
| 
 | ||||
| 			chatLink: "<?php echo $webimroot ?>/operator/agent.php" | ||||
| 		}); | ||||
| 	}); | ||||
| //--></script>
 | ||||
| 
 | ||||
| 
 | ||||
| <?php | ||||
| } | ||||
| 
 | ||||
| function tpl_content() { global $page, $webimroot; | ||||
| ?>
 | ||||
| 
 | ||||
| <?php echo getlocal("invitation.sent"); ?>
 | ||||
| 
 | ||||
| <div class="ajaxWait"></div> | ||||
| 
 | ||||
| <?php | ||||
| } /* content */ | ||||
| 
 | ||||
| require_once('inc_main.php'); | ||||
| ?>
 | ||||
| @ -71,9 +71,12 @@ if (Settings::get('enabletracking') == '1') { | ||||
| 		$operatorName = ($locale == $home_locale) | ||||
| 			? $operator['vclocalename'] | ||||
| 			: $operator['vccommonname']; | ||||
| 		$response['data']['invitation']['operator'] = htmlspecialchars($operatorName); | ||||
| 		$response['data']['invitation']['message'] = getlocal("invitation.message"); | ||||
| 		$response['data']['invitation']['avatar'] = htmlspecialchars($operator['vcavatar']); | ||||
| 		$response['data']['invitation'] = array( | ||||
| 			'operator' => htmlspecialchars($operatorName), | ||||
| 			'avatar' => htmlspecialchars($operator['vcavatar']), | ||||
| 			'url' => get_app_location(true, is_secure_request()) | ||||
| 				. '/client.php?act=invitation' | ||||
| 		); | ||||
| 	} | ||||
| 
 | ||||
| 	// Check if visitor reject invitation
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user