-
-
Save waqaskhan137/0950232d4dc9645c4c3992d830f9bf1f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var finesse = finesse || {}; | |
finesse.gadget = finesse.gadget || {}; | |
finesse.container = finesse.container || {}; | |
// Gadget Config needed for instantiating ClientServices | |
/** @namespace */ | |
finesse.gadget.Config = (function () { | |
var _prefs = new gadgets.Prefs(); | |
/** @scope finesse.gadget.Config */ | |
return { | |
authorization: _prefs.getString("authorization"), | |
country: _prefs.getString("country"), | |
language: _prefs.getString("language"), | |
locale: _prefs.getString("locale"), | |
host: _prefs.getString("host"), | |
hostPort: _prefs.getString("hostPort"), | |
extension: _prefs.getString("extension"), | |
mobileAgentMode: _prefs.getString("mobileAgentMode"), | |
mobileAgentDialNumber: _prefs.getString("mobileAgentDialNumber"), | |
xmppDomain: _prefs.getString("xmppDomain"), | |
pubsubDomain: _prefs.getString("pubsubDomain"), | |
restHost: _prefs.getString("restHost"), | |
scheme: _prefs.getString("scheme"), | |
localhostFQDN: _prefs.getString("localhostFQDN"), | |
localhostPort: _prefs.getString("localhostPort"), | |
teamId: _prefs.getString("teamId"), | |
teamName: _prefs.getString("teamName"), | |
clientDriftInMillis: _prefs.getInt("clientDriftInMillis"), | |
compatibilityMode: _prefs.getString("compatibilityMode") | |
}; | |
}()); | |
/** @namespace */ | |
finesse.modules = finesse.modules || {}; | |
finesse.modules.SparkTeamAnnouncementsGadget = (function ($) { | |
var clientLogs = finesse.cslogger.ClientLogger; // for logging | |
var gadgetParams = {gadgetTitle:"Spark Team Announcements", sparkRoom:"Spark Team Announcements", maxMessages:"5", token: "", lastMsgTimestamp:0}; // Default values | |
var user; | |
var imagesPrefixURL; | |
var roomMembershipMap = []; | |
var forceGadgetUpdate = false; | |
/* Finesse Container Timer Variables */ | |
var _lastProcessedTimerTick = null; | |
var _maxTimerCallbackThreshold = 1500; // Timer is called back every 1.5 seconds | |
var _forceTickProcessingEvery = 15000; // Timer for querying Spark every 15 seconds | |
///////////////////// FILL OUT THIS SECTION ///////////////////// | |
var finesseDomain = "192.168.1.61"; // Fill in your Finesse domain | |
// Fill in the OAuth Authorization URI from the Spark Integration Details page | |
var OAuthAuthorizationURL = "https://api.ciscospark.com/v1/authorize?client_id=C2cdaaecafa2126ee7d24d3bdf37f4cecfe988d7694af2f558ca3060915ced930&response_type=code&redirect_uri=http%3A%2F%2F192.168.1.88%3A7070%2Foauth.html&scope=spark%3Amessages_write%20spark%3Arooms_read%20spark%3Ateams_read%20spark%3Amessages_read%20spark%3Arooms_write%20spark%3Apeople_read%20spark%3Akms%20spark%3Ateams_write&state=set_state_here"; | |
//////////////////////////////////////////////////////////////// | |
/** | |
* Using the URL from the Gadget iFrame, find the URL param, and attempt to find URL params set on that URL | |
*/ | |
_initializeGadgetURLParams = function () { | |
clientLogs.log("_initializeGadgetURLParams()"); | |
var iFrameURLParams = document.location.href.split("?")[1].split("&"); | |
clientLogs.log("_initializeGadgetURLParams() - iFrameURLParams: " + iFrameURLParams); | |
// Save the up_host | |
var upLocalhost; | |
for (i = 0; i < iFrameURLParams.length; i++) { | |
iFrameURLParam = iFrameURLParams[i]; | |
var URLparamKey = iFrameURLParam.split("=")[0]; | |
if (URLparamKey === "url") { | |
var gadgetURL = decodeURIComponent(iFrameURLParam.split("=")[1].split("#")[0]); | |
clientLogs.log("_initializeGadgetURLParams() - gadgetURL: " + gadgetURL); | |
var gadgetFolder = gadgetURL | |
if (gadgetURL.split("?").length > 1) { | |
var gadgetURLParams = gadgetURL.split("?")[1]; | |
clientLogs.log("_initializeGadgetURLParams() - gadgetURLParams: " + gadgetURLParams); | |
gadgetURLParams = gadgetURLParams.split("&"); | |
for (j = 0; j < gadgetURLParams.length; j++) { | |
gadgetURLParam = gadgetURLParams[j]; | |
gadgetParams[gadgetURLParam.split("=")[0]] = decodeURIComponent(gadgetURLParam.split("=")[1]); | |
} | |
} | |
// Parse the url to get the prefix path for the images | |
imagesPrefixURL = gadgetURL.substring(0, gadgetURL.lastIndexOf("/")); | |
} else if (URLparamKey === "up_localhostFQDN") { | |
upLocalhost = iFrameURLParam.split("=")[1]; | |
} | |
} | |
// Replace "localhost" with the upHost | |
if(imagesPrefixURL.indexOf("localhost") != -1) { | |
// Replace the localhost with the fqdn | |
imagesPrefixURL = imagesPrefixURL.replace("localhost", upLocalhost); | |
} | |
clientLogs.log("_initializeGadgetURLParams() - imagesPrefixURL: " + imagesPrefixURL); | |
}, | |
/** | |
* Take a single message (Announcement) and build the HTML to put it in the container | |
* in the appropriate format. | |
* | |
* - If the personData is not yet available, it will show a default avatar and "Unknown" as the name | |
* - Messages that were posted < 60 seconds are highlighted in blue | |
* | |
* Adjust the height of the gadget to fit the messages. | |
*/ | |
handleRepaintGadget = function (item, personData, currTime, monthNames) { | |
clientLogs.log("handleRepaintGadget() - message is: " + item.text); | |
var gadgetContent = ''; | |
var created = ""; | |
// Figure out the time for the message | |
var msgDate = new Date(item.created); | |
var msgTime = msgDate.getTime(); | |
var sec = ((currTime - msgTime) / 1000); //How long has it been since this message arrived | |
var min = Math.round(sec / 60); | |
var hou = Math.round(min / 60); | |
if (sec < 60) created = "Just Now"; | |
else if (min < 2) created = min + " minute ago"; | |
else if (min < 60) created = min + " minutes ago"; | |
else if (hou < 2) created = hou + " hour ago"; | |
else if (hou < 12) created = hou + " hours ago"; | |
else created = monthNames[msgDate.getMonth()] + " " + msgDate.getDate() + ", " + msgDate. getFullYear(); | |
// Figure out the avatar and name for the message. | |
// If the people details API has not completed yet, just show default information that will be updated later. | |
var personImage = imagesPrefixURL + "/images/Default-Avatar.png"; // Default avatar | |
var personName = "Unknown"; | |
if (personData) { | |
if (personData.avatar) personImage = personData.avatar; | |
personName = personData.displayName; | |
} | |
// If the Annoucement is new, ensure that it is displayed with a blue background else a white background | |
var messageBackgroundColor = "#FFFFFF"; | |
if (sec < 60) messageBackgroundColor = "#E0FFFF"; | |
// Build the message HTML | |
gadgetContent += '<tr style="outline: 1px solid #B5B5B5; background-color: ' + messageBackgroundColor + '"class="autoRow">'; | |
// Figure out the message | |
var message = item.text; | |
if (message) { | |
// Special formatting for important messages | |
if (message.indexOf("#IMPORTANT") === 0) { | |
// Strip off the hash tag | |
message = message.substring("#IMPORTANT".length); | |
gadgetContent += '<td class="priority important"></td><td class="message">'; | |
gadgetContent += '<img src="' + imagesPrefixURL + '/images/Alert-ToggleOn.png" title="This is an Important Announcement." style="width: 18px; height: 18px; float: left;"/>'; | |
gadgetContent += '<div style="margin-left: 25px;">' + message + '</div></td>'; | |
} else { | |
gadgetContent += '<td class="priority"></td><td class="message">' + message + '</td>'; | |
} | |
} | |
if (item.files) { | |
jQuery.each(item.files, function(index, item) { | |
gadgetContent += '<td class="priority"></td><td class="message"><i>Downloading attachments and images are not supported at this time.</i></td>'; // Future enhancement to support downloads | |
}); | |
} | |
gadgetContent += '<td class="created" valign="top">' + created + '</td>'; | |
gadgetContent += '<td class="person" valign="top"><div>'; | |
//Make the avatar of the person show up in a circle of 20px | |
gadgetContent += '<div style="width: 20px; height: 20px; border-radius: 50%; background: url(' + personImage + '); background-size: 20px 20px; float:left;"></div>'; | |
gadgetContent += '<div> by ' + personName + '</div></div></td></tr>'; | |
//Leave a 6px gap to make each Annoucement Card look prominent | |
gadgetContent += '<tr style="height: 6px" class="autoRow"><td style="height: 6px; padding-top: 6px"></td></tr>'; | |
$('#announce tbody:first-child').prepend(gadgetContent); | |
// Adjust the height of the gadget | |
gadgets.window.adjustHeight(); | |
}, | |
/** | |
* Determine whether the gadget needs to be updated. | |
* - There are new messages in the room | |
* - There was a message with a blue highlight and it is after ~ 1 min | |
* - There was a request to force an update (e.g. person details are available, access token wasn't available) | |
* If the above criterias are not met, do not refresh the gadget. | |
*/ | |
handleMessageData = function (data) { | |
var contentChanged = false; | |
var currTime = new Date().getTime(); | |
var timeSinceLastPost = (currTime - gadgetParams.lastMsgTimestamp) / 1000; | |
//Need this extra check to remove the blue highlighting on the announcement card (after a ~ min) even if there are no new announcements | |
if ((timeSinceLastPost > 60) && (timeSinceLastPost < 75)) contentChanged = true; | |
//Check if there are new messages | |
if (contentChanged === false) { | |
jQuery.each(data.items, function(index, item) { | |
//FOR EACH Message - check if item.created is > gadgetParams.lastMsgTimestamp | |
if (Date.parse(item.created) > gadgetParams.lastMsgTimestamp) { | |
contentChanged = true; | |
gadgetParams.lastMsgTimestamp = Date.parse(item.created); | |
} | |
}); | |
} | |
if (forceGadgetUpdate || (contentChanged === true)) { | |
$('#announce .autoRow').remove(); | |
var monthNames = [ | |
"Jan", "Feb", "Mar", "Apr", "May", "Jun", | |
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" | |
]; | |
jQuery.each(data.items, function(index, item) { | |
handleRepaintGadget(item, _getRoomMember(item.personId), currTime, monthNames); | |
}); | |
forceGadgetUpdate = false; | |
} | |
}, | |
/** | |
* Get the messages (Announcements) using the messages API. The number of | |
* messages retrieved is determined by the maxMessages parameter. Then, | |
* update the gadget with these messages. | |
*/ | |
_updateGadget = function () { | |
clientLogs.log("_updateGadget(): Spark Room Id: " + gadgetParams.sparkRoom); | |
if (_getAccessToken()) { | |
// Get the 'Messages' from the Spark Room (from the roomId) | |
$.ajax({ | |
url: 'https://api.ciscospark.com/v1/messages', | |
type: "get", | |
headers: { 'Authorization': 'Bearer ' + gadgetParams.token }, | |
data: { 'roomId': gadgetParams.sparkRoom, 'max': gadgetParams.maxMessages }, | |
success: function(data) { | |
$('#gadgetNotification').hide(); | |
handleMessageData(data); | |
}, | |
error: function(data) { | |
clientLogs.log("_updateGadget(): An error occurred while retrieving the messages for the room."); | |
$('#gadgetNotification').html("<font color=\"red\">An error occurred while retrieving the messages for the room.</font></div>"); | |
$('#gadgetNotification').show(); | |
} | |
}); | |
} else { | |
forceGadgetUpdate = true; | |
clientLogs.log("_updateGadget(): The access token is not available yet. Try again in the next iteration."); | |
} | |
}, | |
/** | |
* Post messages (Announcements) to the room. Update the gadget after posting. | |
*/ | |
_postData = function () { | |
var className = $('#msg').attr('class'); | |
var msgData = $('#msg').val(); | |
if (className.indexOf("myinputimp") !== -1) msgData = "#IMPORTANT " + msgData; | |
$.ajax({ | |
url: 'https://api.ciscospark.com/v1/messages', | |
type: "post", | |
headers: { 'Authorization': 'Bearer ' + gadgetParams.token, 'Content-Type': 'application/json' }, | |
data: JSON.stringify({ "roomId": gadgetParams.sparkRoom, "text": msgData}), | |
success: function(data) { | |
clientLogs.log("Message Created: " + data.id); | |
$('#msg').val(""); | |
if (className.indexOf("myinputimp") !== -1) { | |
$('#msg').removeClass("myinputimp"); | |
$('#msg').addClass("myinputnotimp"); | |
} | |
_updateGadget(); | |
}, | |
error: function(data) { | |
clientLogs.log("_postData(): An error occurred while sending the messages to the room."); | |
$('#gadgetNotification').html("<font color=\"red\">An error occurred while sending the messages to the room.</font></div>"); | |
$('#gadgetNotification').show(); | |
} | |
}); | |
}, | |
/** | |
* Toggles the Background URL to Important and Normal. | |
*/ | |
_toggleImportant = function() { | |
var inputPlaceholder = "Type your announcement here and hit enter to send."; | |
var inputImpAddPlaceholder = "Your announcement will be marked as important."; | |
var className = $('#msg').attr('class'); | |
var origImgSrc = $('#impIcon').prop('src'); | |
if (className.indexOf("myinputnotimp") !== -1) { | |
$('#msg').removeClass("myinputnotimp"); | |
$('#msg').addClass("myinputimp"); | |
$('#msg').attr("placeholder", inputPlaceholder + " " + inputImpAddPlaceholder); | |
$('#impIcon').attr("src", imagesPrefixURL + "/images/Alert-ToggleOn-02.png"); | |
} else { | |
$('#msg').removeClass("myinputimp"); | |
$('#msg').addClass("myinputnotimp"); | |
$('#msg').attr("placeholder", inputPlaceholder); | |
$('#impIcon').attr("src", imagesPrefixURL + "/images/Alert-ToggleOff-02.png"); | |
} | |
}, | |
/** | |
* Delete messages (Announcements). This is currently not used in the UI. | |
* Be aware of the Spark rules on who can delete whose messages. Rules vary based on locked / unlocked rooms. | |
*/ | |
_deleteMessage = function (msgId) { | |
$.ajax({ | |
url: 'https://api.ciscospark.com/v1/messages/' + msgId, | |
type: "delete", | |
headers: { 'Authorization': 'Bearer ' + gadgetParams.token }, | |
success: function(data) { | |
clientLogs.log("Message Deleted: " + msgId); | |
} | |
}); | |
}, | |
/** | |
* Call the people details API for the given personId. | |
* Store the response in a map that will be used for the | |
* messages. When the response from this API comes back | |
* force an update to the gadget so that this information | |
* can be updated on the gadget. | |
*/ | |
_getRoomMember = function (personId) { | |
var member = roomMembershipMap[personId]; | |
if (member) { | |
return member; | |
} else { | |
// Call the Person Details API to get the 'Display Name' and 'Avatar' of the person who posted the 'Message' | |
$.ajax({ | |
url: 'https://api.ciscospark.com/v1/people/' + personId, | |
type: "get", | |
headers: { 'Authorization': 'Bearer ' + gadgetParams.token }, | |
success: function(personData) { | |
roomMembershipMap[personId] = personData; | |
// The Person Details are now available, so flag it | |
// to update the UI again. | |
forceGadgetUpdate = true; | |
}, | |
error: function(personData) { | |
clientLogs.log("_getRoomMember(): An error occurred while retrieving the person details for " + personId); | |
} | |
}); | |
} | |
}, | |
/** | |
* Get the name of the room from the given roomId. Update the gadget's title | |
* with this room name. | |
*/ | |
_getRoomName = function () { | |
clientLogs.log("_getRoomName(): Spark Room Id: " + gadgetParams.sparkRoom); | |
// Try to get the room name a max of 5 times | |
var done = false; | |
for(var i = 0; i < 5; i++) { | |
if(_getAccessToken()) { | |
// Get the 'Title' of the Spark Room (from the roomId given while configuring the finesse gadget) | |
$.ajax({ | |
url: 'https://api.ciscospark.com/v1/rooms/' + gadgetParams.sparkRoom, | |
type: "get", | |
headers: { 'Authorization': 'Bearer ' + gadgetParams.token }, | |
success: function(data) { | |
gadgets.window.setTitle(gadgetParams.gadgetTitle + " - " + data.title); | |
done = true; | |
}, | |
error: function(data) { | |
// Log the error and let it loop back around | |
clientLogs.log("_getRoomName(): An error occurred while retrieving the room name for room id: " + gadgetParams.sparkRoom); | |
} | |
}); | |
} else { | |
// Wait a second before trying again | |
clientLogs.log("_getRoomName(): The access token is not available yet. Try again in the next iteration."); | |
setTimeout(function(){}, 1000); | |
} | |
// Break out of the loop if the room name was found | |
if(done) break; | |
} | |
}, | |
/** | |
* Get the access token from the cookie that was set by the | |
* OAuth. Return true if a token is found. False otherwise. | |
*/ | |
_getAccessToken = function () { | |
clientLogs.log("_getAccessToken(): Getting the access token"); | |
// Get the access token from the cookie that was set by the oauth | |
var value = "; " + document.cookie; | |
var parts = value.split("; " + "spark_access_token" + "="); | |
if (parts.length == 2) gadgetParams.token = parts.pop().split(";").shift(); | |
// Return true if found. False otherwise. | |
if(gadgetParams.token) { | |
clientLogs.log("_getAccessToken(): Successfully retrieved the access token"); | |
return true; | |
} else { | |
clientLogs.log("_getAccessToken(): Unable to retrieve the access token"); | |
return false; | |
} | |
}, | |
/** | |
* Handler for the onLoad of a User object. This occurs when the User object is initially read | |
* from the Finesse server. Any once only initialization should be done within this function. | |
*/ | |
_handleUserLoad = function (user) { }, | |
/** | |
* Handler for all User updates | |
*/ | |
_handleUserChange = function(user) { | |
clientLogs.log("_handleUserChange() - " + user.getState()); | |
// Remove the Spark Cookie of the User when the agent logs out. | |
// Right now there is no mechanism to log out the Spark user unless all the cookies are cleared from the browswer | |
if (user.getState() == "LOGOUT") document.cookie = 'spark_access_token=;domain=.' + finesseDomain + ';path=/;expires=Thu, 01 Jan 1970 00:00:01 GMT;'; | |
}, | |
/* | |
* The following runs when the Tab becomes active. | |
* Update the gadget and adjust the height of the gadget | |
*/ | |
_handleActiveTab = function () { | |
clientLogs.log("_handleActiveTab(): The tab with the Spark team announcements gadget is now active."); | |
_updateGadget(); | |
// Adjust the height of the gadget | |
gadgets.window.adjustHeight(); | |
}, | |
/** | |
* Timer tick callback handler. | |
* @param data | |
*/ | |
_timerTickHandler = function (timerTickEvent) { | |
var start, end, diff, discardThreshold, processed; | |
start = (new Date()).getTime(); | |
// Update the gadget if it is the first time, an update has been requested, or is at the _forceTickProcessingEvery interval | |
if ((_lastProcessedTimerTick === null) || forceGadgetUpdate || ((_lastProcessedTimerTick + _forceTickProcessingEvery) <= start)) { | |
_updateGadget(); | |
_lastProcessedTimerTick = start; | |
} | |
end = (new Date()).getTime(); | |
diff = end - start; | |
if (diff > _maxTimerCallbackThreshold) { | |
_clientLogs.log("Spark Team Announcement Gadget took too long to process timer tick (_maxTimerCallbackThreshold exceeded)."); | |
} | |
}; | |
/** @scope finesse.modules.SparkTeamAnnouncementsGadget */ | |
return { | |
/** | |
* Performs all initialization for this gadget | |
*/ | |
init : function () { | |
var prefs = new gadgets.Prefs(), | |
id = prefs.getString("id"); | |
var cfg = finesse.gadget.Config; | |
clientLogs.init(gadgets.Hub, "SparkTeamAnnouncementsGadget", finesse.gadget.Config); //this gadget id will be logged as a part of the message | |
_initializeGadgetURLParams(); | |
clientLogs.log("init() - gadgetParams.gadgetTitle: " + gadgetParams.gadgetTitle); | |
clientLogs.log("init() - gadgetParams.sparkRoom: " + gadgetParams.sparkRoom); | |
// Set the title to the name from the desktop layout parameter | |
gadgets.window.setTitle(gadgetParams.gadgetTitle); | |
// Initiate the ClientServices and the logger and then load the user object. ClientServices are | |
// initialized with a reference to the current configuration. | |
finesse.clientservices.ClientServices.init(finesse.gadget.Config); | |
user = new finesse.restservices.User({ | |
id: id, | |
onLoad : _handleUserLoad, | |
onChange : _handleUserChange | |
}); | |
containerServices = finesse.containerservices.ContainerServices.init(); | |
clientLogs.log("Adding Tab Visible Handler..."); | |
containerServices.addHandler(finesse.containerservices.ContainerServices.Topics.ACTIVE_TAB, _handleActiveTab); | |
clientLogs.log("Adding a timer handler..."); | |
finesse.containerservices.ContainerServices.addHandler(finesse.containerservices.ContainerServices.Topics.TIMER_TICK_EVENT, _timerTickHandler); | |
// Check if there is already an access token store | |
// If so, load the gadget. If not, launch the OAuth | |
if(_getAccessToken()) { | |
_getRoomName(); | |
_updateGadget(); | |
} else { | |
// Get the access token by launching the Spark OAuth | |
var win = window.open(OAuthAuthorizationURL + "&service=spark"); | |
win.focus(); | |
} | |
// This requests to be notified of the currently active tab (in case we are already on it). | |
finesse.containerservices.ContainerServices.makeActiveTabReq(); | |
} | |
}; | |
}(jQuery)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment