/**
* yalst-trunk: shouldInvite.js
*
* Created by Matthias Seemann on 4.06.2014.
* Copyright (c) 2014 Visisoft OHG. All rights reserved.
*
*/
/**
* The callback taken by {@link LiveSupport.VisitorAPI.shouldInvite}.
*
* @callback shouldInviteCallback
* @param {boolean} shouldDisplayActiveInvitation If `true` the calling web page should present an visual layer to invite the visitor to a chat.
* @param {Error} error Error set if a network error has occurred.
*/
define(['underscore', 'api/errorCodes', 'api/configuration', 'api/ManagedError', 'lib/DataFormats','lib/ajax']
, function(_, ErrorCode, Configuration, ManagedError, DataFormats, ajax)
{
var
jsonPScriptTag;
/**
* Checks whether the embedding page should present a chat invitation layer at this time.<br>
* Using this method allows such a distribution of chat invitations among all visitors so that
* the chat load for the operators is kept constant. <br>
* The result of the call depends on the number of available operators, number of running chats
* , the priority parameter and the number of chat invitations given by yalst recently
* to other visitors.
* For optimal chat workload of the support agents
* the caller should always present a chat invitation to the visitor if the result is <tt>true</tt>.
* <br><strong>Throws</strong> {@link LiveSupport.ManagedError} in case any or a single parameter is given which is neither a number nor a function
*
* @memberof LiveSupport.VisitorAPI
*
* @param {Number} [priority=0] a number from 0 to 100.
* If invitation priority is enabled, and the number of available chat slots is below
* the configured threshold, the importance of a chat invitation
* is assessed by this parameter.
*
* @param {shouldInviteCallback} onResult result callback
*
* @since 2.1
*
* @example
// check if a web page visitor of highest priority should receive an invitation for a support chat
LiveSupport.VisitorAPI.shouldInvite(100
, function(shouldInvite, error){
if (error)
{
// deal with the error, description in error.message
}
else
{
if (shouldInvite){
$('#invitationLayer').show();
}
}
}
);
*
*/
function shouldInvite(priority, onResult)
{
var priorityPercent = 0;
var callback = function(yesno, error){};
/// Parameter Inspection
switch (arguments.length)
{
case 0:
throw new ManagedError(ErrorCode.ParameterTypeError
, "Call to shouldInvite has no parameters!");
case 1:
if (typeof priority == "number")
{
priorityPercent = priority;
}
else if (typeof priority == "function")
{
//noinspection JSValidateTypes
callback = priority;
}
else
{
throw new ManagedError(ErrorCode.ParameterTypeError
, "Call to shouldInvite has wrong parameter!");
}
break;
case 2:
if (typeof priority == "number" && typeof onResult == "function")
{
priorityPercent = priority;
//noinspection JSValidateTypes
callback = onResult;
}
else
{
throw new ManagedError(ErrorCode.ParameterTypeError
, "Call to shouldInvite has wrong parameter types!");
}
break;
}
/// Check our Sanity
if (!Configuration.configuration.IS_ASSOCIATED)
{
_.defer(_.bind(callback, null, undefined
, new ManagedError(ErrorCode.ServerNotYetAssociated
, "Illegal API use. Attempt to call a method before associated to a live support product.")
));
return;
}
if (priorityPercent < 0 || 100 < priorityPercent)
{
_.defer(_.bind(callback, null, undefined
, new ManagedError(ErrorCode.ParameterTypeError, "Parameter out of range.")
));
return;
}
/// Wire Result Reception Handlers
function onApiResult(response)
{
if (response["shouldInvite"] !== undefined
&& typeof response["shouldInvite"] == "boolean")
{
callback(response["shouldInvite"]);
return;
}
var errorText = response["error"] || "Unknown error";
callback(undefined, new ManagedError(ErrorCode.InternalError, errorText));
}
var queryParameters = {rnd: Math.random()
, site: Configuration.configuration.PRODUCT_SITE
, priority: priorityPercent
};
/// Network Request
if (ajax.isCORSSupported() && ajax.isJsonSupported()) /// JSON (IE10+)
{
var didAbortAjaxRequest = false;
var responseDurationTimer;
var request = ajax.getJson(
Configuration.configuration.PRODUCT_URL + 'visitor-api.shouldinvite.php?'
+ DataFormats.urlQueryStringFromObject(queryParameters)
, function(response, error)
{
clearTimeout(responseDurationTimer);
if (error)
{
if (!didAbortAjaxRequest)
{
callback(undefined, new ManagedError(ErrorCode.NetworkError
, "Network error: " + error.message)
);
}
return;
}
onApiResult(response);
}
);
responseDurationTimer = setTimeout(function()
{
didAbortAjaxRequest = true;
request.abort();
callback(undefined, new ManagedError(ErrorCode.TimeoutError
, "The shouldInvite request has timed out!"));
}, Configuration.configuration.SERVER_TIMEOUT_SECS * 1000);
}
else
{
/// JSONP for non CORS browsers IE9-
var jsonPCallbackName = _.uniqueId('_shouldInviteCallback');
/// introduce a globally visible callback function for the returned script
/// which is just a curried version of the general _availabilityCallback
/// for JSONP we must use global variables even if loaded as RequireJS module
var namespace = window[Configuration.configuration.GLOBAL_NAMESPACE]
= window[Configuration.configuration.GLOBAL_NAMESPACE] || {};
namespace.VisitorAPI = namespace.VisitorAPI || {};
namespace.VisitorAPI[jsonPCallbackName] =
function(response)
{
clearTimeout(responseDurationTimer);
onApiResult(response);
};
queryParameters.callback = Configuration.configuration.GLOBAL_NAMESPACE
+ ".VisitorAPI." + jsonPCallbackName;
if (jsonPScriptTag)
{
jsonPScriptTag.parentNode.removeChild(jsonPScriptTag);
}
jsonPScriptTag = document.createElement("script");
var siblingElement = document.getElementsByTagName("script")[0];
siblingElement.parentNode.insertBefore(jsonPScriptTag, siblingElement);
jsonPScriptTag.src = Configuration.configuration.PRODUCT_URL + 'visitor-api.shouldinvite.php?'
+ DataFormats.urlQueryStringFromObject(queryParameters);
responseDurationTimer = setTimeout(function()
{
callback(undefined, new ManagedError(ErrorCode.TimeoutError
, "The shouldInvite request has timed out!"));
/// in case the network request eventually completes,
// prevent result callbacks being called a second time
queryParameters.callback = function(){};
}
, Configuration.configuration.SERVER_TIMEOUT_SECS * 1000
);
}
}
return shouldInvite;
});