<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="Headless Gadget Servisbot TCP" description="ServisBOT Transcription Co Pilot" >
<Require feature="settitle" />
<Require feature="dynamic-height" />
<Require feature="pubsub-2" />
<Require feature="setprefs" />
<Require feature="loadingindicator">
<Param name="manual-dismiss">false</Param>
<Param name="loading-timeout">10</Param>
</Require>
</ModulePrefs>
<!--Uncomment the below 3 lines if NOT hosting on Finesse server.-->
<UserPref name="scheme" display_name="scheme" default_value=""/>
<UserPref name="host" display_name="host" default_value=""/>
<UserPref name="hostPort" display_name="hostPort" default_value=""/>
<Content type="html">
<![CDATA[
<!DOCTYPE html>
<!-- jQuery -->
<!--<script type="text/javascript" src="/desktop/assets/js/jquery.min.js"></script>--?
<!-- Finesse Library -->
<!--<script type="text/javascript" src="/desktop/assets/js/finesse.js"></script>-->
<!-- jQuery - uncomment if NOT hosting on Finesse server -->
<script type="text/javascript" src="__UP_scheme__://__UP_host__:__UP_hostPort__/desktop/assets/js/jquery.min.js"></script>
<!-- Finesse Library - uncomment if NOT hosting on Finesse server -->
<script type="text/javascript" src="__UP_scheme__://__UP_host__:__UP_hostPort__/desktop/assets/js/finesse.js"></script>
<!-- Gadget Business Logic -->
<script type="text/javascript" src="HeadlessGadgetServisbotTCP.js"></script>
<body class="claro">
</body>
<script type="text/javascript">
gadgets.HubSettings.onConnect = function () {
finesse.modules.HeadlessGadgetServisbotTCP.init();
};
</script>
]]>
</Content>
</Module>
/**
* Test Gadget GOR
*
* Logs Cisco Finesse dialog events for voice calls and for ECE chats, so you
* can see exactly when a chat starts, changes and ends.
*
* Based on the Cisco DevNet samples: github.com/CiscoDEVNet/finesse-Test-code
*
* Event sources:
* - user.getDialogs() -> voice dialogs only
* - new Media({id: 5000}) -> the ECE chat media, loaded directly by id
* media.getMediaDialogs() -> ECE chat dialogs (new and already active)
*
* Note: onCollectionAdd only fires for dialogs created AFTER a collection has
* loaded. Dialogs that already exist (e.g. after a browser refresh) are found
* in the onLoad handlers.
*/
var finesse = finesse || {};
finesse.gadget = finesse.gadget || {};
finesse.container = finesse.container || {};
finesse.modules = finesse.modules || {};
finesse.modules.TestGadgetGOR = (function ($) {
"use strict";
// ------------------------------------------------------------------
// Constants
// ------------------------------------------------------------------
var GADGET_ID = "TestGadgetGOR";
var ECE_MEDIA_ID = "5000"; // Media Routing Domain id used by ECE chat
// ------------------------------------------------------------------
// Module state
// ------------------------------------------------------------------
var _logger; // finesse.cslogger.ClientLogger (set in init)
var _user; // finesse.restservices.User
var _dialogs; // voice dialogs collection
var _eceMedia; // finesse.restservices.Media for the ECE chat media
var _currentDialog = null; // voice dialog where this agent is ACTIVE
// ------------------------------------------------------------------
// Helpers
// ------------------------------------------------------------------
/** Log through the Finesse client logger, prefixed with the calling function. */
function _log(source, message) {
if (_logger) {
_logger.log(source + "(): " + message);
}
}
/** Turn a failed REST response into a readable string. */
function _errText(rsp) {
return rsp ? (rsp.status + " " + rsp.content) : "no response";
}
/** Log the commonly useful properties of a dialog. */
function _logDialogDetails(source, dialog) {
var callVars = dialog.getMediaProperties() || {};
_log(source, "dialog id: " + dialog.getId());
_log(source, "MediaType: " + dialog.getMediaType());
_log(source, "State: " + dialog.getState());
_log(source, "callType: " + (callVars.callType || ""));
_log(source, "from (ani): " + dialog.getFromAddress());
_log(source, "to: " + dialog.getToAddress());
}
/**
* Find this agent's participant entry in a dialog (matched by extension).
* @returns the participant object, or null if the agent isn't in the dialog
*/
function _getParticipant(dialog) {
var participants = dialog.getParticipants();
var extension = _user.getExtension();
for (var key in participants) {
if (participants.hasOwnProperty(key) &&
participants[key].mediaAddress === extension) {
return participants[key];
}
}
return null;
}
// ------------------------------------------------------------------
// Voice dialogs (user.getDialogs)
// ------------------------------------------------------------------
/** A voice dialog was added (or already existed when the gadget loaded). */
function _handleNewDialog(dialog) {
_log("_handleNewDialog", "--------");
_logDialogDetails("_handleNewDialog", dialog);
var participant = _getParticipant(dialog);
_log("_handleNewDialog", "participant state: " + (participant ? participant.state : "none"));
// Call variables may not have arrived yet, so keep listening for changes.
dialog.addHandler("change", _updateDialog);
}
/** A voice dialog changed (call variables, participant state, etc.). */
function _updateDialog(dialog) {
_log("_updateDialog", "--------");
_logDialogDetails("_updateDialog", dialog);
var participant = _getParticipant(dialog);
_log("_updateDialog", "participant state: " + (participant ? participant.state : "none"));
// Remember the dialog the agent is actively on.
if (participant && participant.state === "ACTIVE") {
_currentDialog = dialog;
}
}
/** A voice dialog ended. */
function _handleEndDialog(dialog) {
_log("_handleEndDialog", "--------");
_logDialogDetails("_handleEndDialog", dialog);
if (_currentDialog && _currentDialog.getId() === dialog.getId()) {
_currentDialog = null;
}
}
/** The voice dialog collection has loaded: process any existing dialogs. */
function _handleDialogsLoaded() {
_log("_handleDialogsLoaded", "--------");
var collection = _dialogs.getCollection();
for (var id in collection) {
if (collection.hasOwnProperty(id)) {
_handleNewDialog(collection[id]);
}
}
}
// ------------------------------------------------------------------
// ECE chat dialogs (media 5000)
// ------------------------------------------------------------------
/** A chat dialog was added (or already existed when the gadget loaded). */
function _handleNewMediaDialog(dialog) {
_log("_handleNewMediaDialog", "--------");
_log("_handleNewMediaDialog", "dialog id: " + dialog.getId());
_log("_handleNewMediaDialog", "MediaType: " + dialog.getMediaType());
_log("_handleNewMediaDialog", "State: " + dialog.getState());
dialog.addHandler("change", _updateMediaDialog);
}
/** A chat dialog changed. */
function _updateMediaDialog(dialog) {
_log("_updateMediaDialog", "--------");
_log("_updateMediaDialog", "dialog id: " + dialog.getId());
_log("_updateMediaDialog", "MediaType: " + dialog.getMediaType());
_log("_updateMediaDialog", "State: " + dialog.getState());
}
/** A chat dialog ended. */
function _handleEndMediaDialog(dialog) {
_log("_handleEndMediaDialog", "dialog id: " + dialog.getId());
}
/** The chat dialogs have loaded: process any that are already active. */
function _handleMediaDialogsLoaded(mediaDialogs) {
var collection = mediaDialogs.getCollection();
var count = 0;
for (var id in collection) {
if (collection.hasOwnProperty(id)) {
count++;
_handleNewMediaDialog(collection[id]);
}
}
_log("_handleMediaDialogsLoaded", "existing chat dialogs: " + count);
}
/** The ECE media object has loaded: subscribe to its chat dialogs. */
function _handleEceMediaLoaded(media) {
_log("_handleEceMediaLoaded", "media id: " + ECE_MEDIA_ID + ", name: " + media.getName());
// getMediaDialogs() throws unless the media is loaded, which is why
// it is called from the media's onLoad handler.
media.getMediaDialogs({
onCollectionAdd: _handleNewMediaDialog,
onCollectionDelete: _handleEndMediaDialog,
onLoad: _handleMediaDialogsLoaded,
onError: function (rsp) {
_log("_handleEceMediaLoaded", "dialogs ERROR: " + _errText(rsp));
}
});
}
// ------------------------------------------------------------------
// User events
// ------------------------------------------------------------------
/** The user object has loaded: start listening for dialogs. */
function _handleUserLoad() {
_log("_handleUserLoad", "agent state: " + _user.getState());
// 1. Voice dialogs
_dialogs = _user.getDialogs({
onCollectionAdd: _handleNewDialog,
onCollectionDelete: _handleEndDialog,
onLoad: _handleDialogsLoaded
});
// 2. ECE chat dialogs. Load the ECE media directly by id; its parent
// is the user, so the REST path is .../User/<id>/Media/5000
_eceMedia = new finesse.restservices.Media({
id: ECE_MEDIA_ID,
parentObj: _user,
onLoad: _handleEceMediaLoaded,
onError: function (rsp) {
_log("_handleUserLoad", "ECE media ERROR: " + _errText(rsp));
}
});
}
/** Any change to the user (e.g. agent state). */
function _handleUserChange() {
_log("_handleUserChange", "agent state: " + _user.getState());
}
// ------------------------------------------------------------------
// Public API
// ------------------------------------------------------------------
return {
/** Performs all initialization for this gadget. */
init: function () {
var config = finesse.gadget.Config;
// Set up the Finesse client logger. The gadget id is included in each message.
_logger = finesse.cslogger.ClientLogger;
_logger.init(gadgets.Hub, GADGET_ID, config);
_log("init", "Initializing...");
// Initialise ClientServices with the current config, then load the user.
finesse.clientservices.ClientServices.init(config, false);
_user = new finesse.restservices.User({
id: config.id,
onLoad: _handleUserLoad,
onChange: _handleUserChange
});
// When this gadget's tab becomes visible, re-adjust the height.
// adjustHeight only works on a visible tab, so without this the
// gadget is the wrong size on load until the page is refreshed.
var containerServices = finesse.containerservices.ContainerServices.init();
containerServices.addHandler(
finesse.containerservices.ContainerServices.Topics.ACTIVE_TAB,
function () {
_log("init", "Gadget is now visible");
gadgets.window.adjustHeight();
}
);
containerServices.makeActiveTabReq();
_log("init", "Initialization finished.");
}
};
}(jQuery));