Completely rewrite Invite JavaScript application

This commit is contained in:
Dmitriy Simushev 2013-02-12 11:41:04 +00:00
parent d357e505c9
commit d24daf52eb
12 changed files with 357 additions and 129 deletions

View File

@ -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
invite_app_js - Build JavaScript files related to invite application
thread_log_app_js - Build JavaScript files related to thread log application thread_log_app_js - Build JavaScript files related to thread log application
users_app_js - Build JavaScript files related to users application users_app_js - Build JavaScript files related to users application
@ -270,6 +271,16 @@
<echo>Chat JavaScript application built.</echo> <echo>Chat JavaScript application built.</echo>
</target> </target>
<!-- Compile and concatenate JavaScript files related to invite application -->
<target name="invite_app_js" depends="default_app_js">
<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 --> <!-- Compile and concatenate JavaScript files related to users application -->
<target name="users_app_js" depends="default_app_js"> <target name="users_app_js" depends="default_app_js">
<antcall target="app_js"> <antcall target="app_js">
@ -338,7 +349,7 @@
</target> </target>
<!-- Build all project --> <!-- Build all project -->
<target name="all" depends="chat_app_js,thread_log_app_js,users_app_js,styles_all"> <target name="all" depends="chat_app_js,invite_app_js,thread_log_app_js,users_app_js,styles_all">
<echo>Mibew Messenger built.</echo> <echo>Mibew Messenger built.</echo>
</target> </target>

View File

@ -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(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,_);

View 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
*/
MibewAPIInviteInteraction=function(){this.obligatoryArguments={"*":{"return":{},references:{},visitorId:null},result:{errorCode:0}};this.reservedFunctionNames=["result"]};MibewAPIInviteInteraction.prototype=new MibewAPIInteraction;

View File

@ -0,0 +1,15 @@
/*
This file is part of Mibew Messenger project.
http://mibew.org
Copyright (c) 2005-2011 Mibew Messenger Community
License: http://mibew.org/license.php
*/
MibewAPIInviteInteraction=function(){this.obligatoryArguments={"*":{"return":{},references:{},visitorId:null},result:{errorCode:0}};this.reservedFunctionNames=["result"]};MibewAPIInviteInteraction.prototype=new MibewAPIInteraction;
/*
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,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,_);

View File

@ -1,12 +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.InviteUpdater=Class.create();
Class.inherit(Ajax.InviteUpdater,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.updateParams=this.updateParams.bind(this);this._options.handleError=this.handleError.bind(this);this._options.updateContent=this.updateContent.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(){if(this.updater._options)this.updater._options.onComplete=void 0;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(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),this.frequency*1E3)},updateParams:function(){return"visitor="+this._options.visitor},handleError:function(){},updateContent:function(a){if(a.tagName=="invitation"){var b=NodeUtils.getNodeValue(a,
"invited"),a=NodeUtils.getNodeValue(a,"threadid");if(b=="0")this.stopUpdate(),window.close();else if(a!="0")this.stopUpdate(),window.name="ImCenter"+a,window.location=this._options.agentservl+"?thread="+a}}});EventHelper.register(window,"onload",function(){new Ajax.InviteUpdater({}.extend(updaterOptions||{}))});

View File

@ -0,0 +1,67 @@
/**
* @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();
// 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, _);

View File

@ -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 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();

View File

@ -1,95 +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.InviteUpdater = Class.create();
Class.inherit( Ajax.InviteUpdater, 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.updateParams = this.updateParams.bind(this);
this._options.handleError = this.handleError.bind(this);
this._options.updateContent = this.updateContent.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);
},
updateParams: function() {
return "visitor=" + this._options.visitor;
},
handleError: function(s) {
},
updateContent: function(root) {
if( root.tagName == 'invitation' ) {
var invited = NodeUtils.getNodeValue(root, "invited");
var threadid = NodeUtils.getNodeValue(root, "threadid");
if (invited == "0") {
this.stopUpdate();
window.close();
}
else if (threadid != "0") {
this.stopUpdate();
window.name = 'ImCenter' + threadid;
window.location=this._options.agentservl + '?thread=' + threadid;
}
}
}
});
EventHelper.register(window, 'onload', function(){
new Ajax.InviteUpdater(({}).extend(updaterOptions || {}));
});

View File

@ -0,0 +1,130 @@
<?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 invitation awaiting related api functions.
*
* Events triggered by the class (see description of the RequestProcessor class
* for details):
* - inviteRequestReceived
* - inviteReceiveRequestError
* - inviteCallError
* - inviteFunctionCall
*
* Implements Singleton pattern
*/
class InviteProcessor extends ClientSideProcessor {
/**
* An instance of the InviteProcessor class
* @var InviteProcessor
*/
protected static $instance = null;
/**
* Return an instance of the InviteProcessor class.
* @return InviteProcessor
*/
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
* InviteProcessor::getInstance() instead!
* @todo Think about why the method is not protected
*/
public function __construct() {
parent::__construct(array(
'signature' => '',
'trusted_signatures' => array(''),
'event_prefix' => 'invite'
));
}
/**
* Creates and returns an instance of the MibewAPI class.
*
* @return MibewAPI
*/
protected function getMibewAPIInstance() {
return MibewAPI::getAPI('MibewAPIInviteInteraction');
}
/**
* Stub for sendAsyncRequest method.
*
* Actually request not send to client side. This method is ONLY STUB.
* @return boolean Always true
*/
protected function sendAsyncRequest() {
return true;
}
/**
* Stub for call method.
*
* Actually nothing can be called at client side. This method is ONLY STUB.
* @return boolean Always false.
*/
public function call() {
return false;
}
/**
* Returns visitor invitation state. API function
*
* @param array $args Associative array of arguments. It must contains
* following keys:
* - 'visitorId': Id of the invited visitor
* @return array Array of results. It contains following keys:
* - 'invited': boolean, indicates if visitor is invited
* - 'threadId': thread id related to visitor or false if there is no thread
*/
protected function apiInvitationState($args) {
$operator = get_logged_in();
if (!$operator) {
throw new ThreadProcessorException(
"Operator not logged in!",
InviteProcessorException::ERROR_AGENT_NOT_LOGGED_IN
);
}
$invitation = invitation_state($args['visitorId']);
return array(
'invited' => (bool)$invitation['invited'],
'threadId' => ($invitation['threadid'] ? $invitation['threadid'] : false)
);
}
}
/**
* Class for invite processor exceptions
*/
class InviteProcessorException extends RequestProcessorException {
/**
* Operator is not logged in
*/
const ERROR_AGENT_NOT_LOGGED_IN = 1;
}
?>

View File

@ -0,0 +1,48 @@
<?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 invitation waiting window interaction
*/
class MibewAPIInviteInteraction extends MibewAPIInteraction {
/**
* Defines obligatory arguments and default values for them
* @var array
* @see MibewAPIInteraction::$obligatoryArgumnents
*/
protected $obligatoryArguments = array(
'*' => array(
'references' => array(),
'return' => array(),
'visitorId' => null
),
'result' => array(
'errorCode' => 0
)
);
/**
* Reserved function's names
* @var array
* @see MibewAPIInteraction::$reservedFunctionNames
*/
public $reservedFunctionNames = array(
'result'
);
}
?>

View File

@ -18,20 +18,14 @@
require_once('../libs/init.php'); require_once('../libs/init.php');
require_once('../libs/invitation.php'); require_once('../libs/invitation.php');
require_once('../libs/operator.php'); require_once('../libs/operator.php');
require_once('../libs/classes/mibew_api.php');
require_once('../libs/classes/mibew_api_interaction.php');
require_once('../libs/classes/mibew_api_invite_interaction.php');
require_once('../libs/classes/mibew_api_execution_context.php');
require_once('../libs/classes/client_side_processor.php');
require_once('../libs/classes/invite_processor.php');
$operator = check_login(); $processor = InviteProcessor::getInstance();
$processor->receiveRequest($_POST['data']);
$visitorid = verifyparam("visitor", "/^\d{1,8}$/");
$errors = array();
$invitation = invitation_state($visitorid);
start_xml_output();
echo '<invitation>';
echo '<invited>' . ($invitation['invited'] ? $invitation['invited'] : '0') . '</invited>';
echo '<threadid>' . ($invitation['threadid'] ? $invitation['threadid'] : '0') . '</threadid>';
echo '</invitation>';
exit;
?> ?>

View File

@ -19,14 +19,37 @@ $page['title'] = getlocal("invitation.title");
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>
<script type="text/javascript" language="javascript"><!-- <!-- External libs -->
var updaterOptions = { <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/jquery.min.js"></script>
url:"<?php echo $webimroot ?>/operator/invitationstate.php",wroot:"<?php echo $webimroot ?>", <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/json2.js"></script>
agentservl:"<?php echo $webimroot ?>/operator/agent.php", frequency:<?php echo $page['frequency'] ?>, <script type="text/javascript" src="<?php echo $webimroot ?>/js/libs/underscore-min.js"></script>
visitor: "<?php echo $page['visitor'] ?>" }; <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> //--></script>
<script type="text/javascript" language="javascript" src="<?php echo $webimroot ?>/js/compiled/invite_op.js"></script>
<?php <?php
} }