/*
-* Salesforce.com Interaction Toolkit 40.0
-* Copyright, 2015, salesforce.com, inc.
-* All Rights Reserved
-*/
+ * Copyright 2017 salesforce.com, inc.
+ * All Rights Reserved
+ * Company Confidential
+ */
'use strict';
window.sforce = window.sforce || {};
sforce.interaction = (function() {
- var apiVersion = 40;
- var INTERACTION_API = 'interactionApi/';
- var ENTITY_FEED_API = 'entityFeedApi/';
- var frameOrigin = null;
- var nonce = null;
- var callbacks = {};
- var GET_CALL_CENTER_SETTINGS = 'getCallCenterSettings';
- var GET_SOFTPHONE_LAYOUT = 'getSoftphoneLayout';
- var GET_PAGE_INFO = 'getPageInfo';
- var SET_SOFTPHONE_HEIGHT = 'setSoftphoneHeight';
- var SET_SOFTPHONE_WIDTH = 'setSoftphoneWidth';
- var IS_IN_CONSOLE = 'isInConsole';
- var SCREEN_POP = 'screenPop';
- var SEARCH_AND_GET_SCREEN_POP_URL = 'searchAndGetScreenPopUrl';
- var SEARCH_AND_SCREEN_POP = 'searchAndScreenPop';
- var ENABLE_CLICK_TO_DIAL = 'enableClickToDial';
- var DISABLE_CLICK_TO_DIAL = 'disableClickToDial';
- var RUN_APEX_QUERY = 'runApex';
- var SAVE_LOG = 'saveLog';
- var SET_VISIBLE = 'setVisible';
- var IS_VISIBLE = 'isVisible';
- var AVAILABLE = 'available';
- var CONNECT = 'connect';
- var DISCONNECT = 'disconnect';
- var REFRESH_OBJECT = 'refreshObject';
- var RELOAD_FRAME = 'reloadFrame';
- var REFRESH_PAGE = 'refreshPage';
- var REFRESH_RELATED_LIST = 'refreshRelatedList';
- var NOTIFY_INITIALIZATION_COMPLETE = 'notifyInitializationComplete';
- var GET_DIRECTORY_NUMBERS = "getDirectoryNumbers";
- var listeners = {onClickToDial:'onClickToDial', onFocus:'onFocus', onObjectUpdate:'onObjectUpdate'};
- var methodId = 0;
- var entityFeedApi = null;
- var servedFromCanvas = false;
-
- function isApiMessage(event, apiEndPoint) {
- return event.data && event.data.indexOf(apiEndPoint) === 0;
- }
-
- function parseAuthParams(params) {
- // initialize if sfdcIFrameOrigin and nonce are present
- if (params['sfdcIFrameOrigin'] && params['nonce']) {
- frameOrigin = params['sfdcIFrameOrigin'] ? params['sfdcIFrameOrigin'].toLowerCase():null;
- nonce = params['nonce'];
- } else {
- // we may use canvas
- if (typeof Sfdc !== "undefined" && Sfdc.canvas && Sfdc.canvas.client) {
- var sr = Sfdc.canvas.client.signedrequest();
- var parsedRequest;
- if (sr) {
- if (typeof sr === "string") {
- parsedRequest = JSON.parse(sr);
- } else {
- // assume we're using OAuth
- parsedRequest = sr;
- }
- }
- if (parsedRequest) {
- var environment;
- if (parsedRequest.context) {
- environment = parsedRequest.context.environment;
- } else if (parsedRequest.payload) {
- environment = parsedRequest.payload.environment;
- }
- if (environment && environment.parameters) {
- frameOrigin = environment.parameters.sfdcIframeOrigin;
- nonce = environment.parameters.nonce;
- servedFromCanvas = environment.parameters.servedFromCanvas;
- }
- }
- }
+ var apiVersion = 46;
+ var INTERACTION_API = 'interactionApi/';
+ var ENTITY_FEED_API = 'entityFeedApi/';
+ var frameOrigin = null;
+ var nonce = null;
+ var callbacks = {};
+ var GET_CALL_CENTER_SETTINGS = 'getCallCenterSettings';
+ var GET_SOFTPHONE_LAYOUT = 'getSoftphoneLayout';
+ var GET_PAGE_INFO = 'getPageInfo';
+ var SET_SOFTPHONE_HEIGHT = 'setSoftphoneHeight';
+ var SET_SOFTPHONE_WIDTH = 'setSoftphoneWidth';
+ var IS_IN_CONSOLE = 'isInConsole';
+ var SCREEN_POP = 'screenPop';
+ var SEARCH_AND_GET_SCREEN_POP_URL = 'searchAndGetScreenPopUrl';
+ var SEARCH_AND_SCREEN_POP = 'searchAndScreenPop';
+ var ENABLE_CLICK_TO_DIAL = 'enableClickToDial';
+ var DISABLE_CLICK_TO_DIAL = 'disableClickToDial';
+ var RUN_APEX_QUERY = 'runApex';
+ var SAVE_LOG = 'saveLog';
+ var SET_VISIBLE = 'setVisible';
+ var IS_VISIBLE = 'isVisible';
+ var AVAILABLE = 'available';
+ var CONNECT = 'connect';
+ var DISCONNECT = 'disconnect';
+ var REFRESH_OBJECT = 'refreshObject';
+ var RELOAD_FRAME = 'reloadFrame';
+ var REFRESH_PAGE = 'refreshPage';
+ var REFRESH_RELATED_LIST = 'refreshRelatedList';
+ var NOTIFY_INITIALIZATION_COMPLETE = 'notifyInitializationComplete';
+ var GET_DIRECTORY_NUMBERS = "getDirectoryNumbers";
+ var listeners = {onClickToDial:'onClickToDial', onFocus:'onFocus', onObjectUpdate:'onObjectUpdate'};
+ var methodId = 0;
+ var entityFeedApi = null;
+ var servedFromCanvas = false;
+
+ function isApiMessage(event, apiEndPoint) {
+ return event.data && event.data.indexOf(apiEndPoint) === 0;
}
- }
-
- /**
- * Process messages received from SFDC by executing callbacks, if any.
- * The event object contains the following fields:
- * method: the API method that was called.
- * result: result returned from the call.
- * error: an error message if any errors were encountered.
- */
- function processPostMessage(event) {
- var params;
- try {
- // Check if call is for entity feed
- if (isApiMessage(event, ENTITY_FEED_API)) {
- if (entityFeedApi && entityFeedApi.processPostMessage) {
- params = entityFeedApi.processPostMessage(event);
- }
- if (!params) {
- return;
- }
- } else if (isApiMessage(event, INTERACTION_API)) {
- if (event.origin !== frameOrigin || !frameOrigin) {
- // Only trust messages from the adapter frame
- return;
- }
-
- var message = event.data.replace(INTERACTION_API, ''); // strip off API target
- params = parseUrlQueryString(message);
- // convert string true/false to boolean for methods that needs to return boolean values.
- if (params && (params.result === 'true' || params.result === 'false')) {
- params.result = params.result === 'true';
- }
- } else {
- // return if postMessage is not targeted to interaction API
- return;
- }
-
- // execute callbacks registered for the method called
- for (var methodName in callbacks) {
- if (callbacks.hasOwnProperty(methodName)) {
- if (params.method === methodName) {
- for (var i in callbacks[methodName]) {
- callbacks[methodName][i](params);
- }
- if (!listeners[methodName]) {
- delete callbacks[methodName];
+ function parseAuthParams(params) {
+ // initialize if sfdcIFrameOrigin and nonce are present
+ if (params['sfdcIFrameOrigin'] && params['nonce']) {
+ frameOrigin = params['sfdcIFrameOrigin'] ? params['sfdcIFrameOrigin'].toLowerCase():null;
+ nonce = params['nonce'];
+ } else {
+ // we may use canvas
+ if (typeof Sfdc !== "undefined" && Sfdc.canvas && Sfdc.canvas.client) {
+ var sr = Sfdc.canvas.client.signedrequest();
+ var parsedRequest;
+ if (sr) {
+ if (typeof sr === "string") {
+ parsedRequest = JSON.parse(sr);
+ } else {
+ // assume we're using OAuth
+ parsedRequest = sr;
+ }
+ }
+ if (parsedRequest) {
+ var environment;
+ if (parsedRequest.context) {
+ environment = parsedRequest.context.environment;
+ } else if (parsedRequest.payload) {
+ environment = parsedRequest.payload.environment;
+ }
+ if (environment && environment.parameters) {
+ frameOrigin = environment.parameters.sfdcIframeOrigin;
+ nonce = environment.parameters.nonce;
+ servedFromCanvas = environment.parameters.servedFromCanvas;
+ }
+ }
}
- }
}
- }
- } catch(e) {
- consoleLog("Failed to process API response.");
}
- }
-
- /**
- * Makes an API call to SFDC domain.
- */
- function doPostMessage(params, callback) {
- if (callback) {
- params.method = registerCallback(params.method, callback);
- }
-
- // add nonce to params
- params.nonce = nonce;
- // add version
- params.apiVersion = apiVersion;
+ /**
+ * Process messages received from SFDC by executing callbacks, if any.
+ * The event object contains the following fields:
+ * method: the API method that was called.
+ * result: result returned from the call.
+ * error: an error message if any errors were encountered.
+ */
+ function processPostMessage(event) {
+ var params;
+ try {
+ // Check if call is for entity feed
+ if (isApiMessage(event, ENTITY_FEED_API)) {
+ if (entityFeedApi && entityFeedApi.processPostMessage) {
+ params = entityFeedApi.processPostMessage(event);
+ }
+ if (!params) {
+ return;
+ }
+ } else if (isApiMessage(event, INTERACTION_API)) {
+ if (event.origin !== frameOrigin || !frameOrigin) {
+ // Only trust messages from the adapter frame
+ return;
+ }
+
+ var message = event.data.replace(INTERACTION_API, ''); // strip off API target
+ params = parseUrlQueryString(message);
+
+ // convert string true/false to boolean for methods that needs to return boolean values.
+ if (params && (params.result === 'true' || params.result === 'false')) {
+ params.result = params.result === 'true';
+ }
+ } else {
+ // return if postMessage is not targeted to interaction API
+ return;
+ }
- if (frameOrigin) {
- var targetWindow = servedFromCanvas ? window.top : window.parent;
- targetWindow.postMessage(INTERACTION_API + buildQueryString(params), frameOrigin);
- }
- }
-
- function registerCallback(method, callback) {
- if (listeners[method]) {
- if (callbacks[method]) {
- callbacks[method].push(callback);
- } else {
- callbacks[method] = [callback];
- }
- } else {
- // API methods that are not listeners needs an ID in case they are call multiple times in an async manner.
- method += '_' + methodId;
- callbacks[method] = [callback];
- methodId++;
- }
- return method;
- }
-
- /**
- * Utility method to create a query string object.
- */
- function parseUrlQueryString(queryString) {
- var params = {};
- if (typeof queryString !== 'string') {
- return params;
+ // execute callbacks registered for the method called
+ for (var methodName in callbacks) {
+ if (callbacks.hasOwnProperty(methodName)) {
+ if (params.method === methodName) {
+ for (var i in callbacks[methodName]) {
+ callbacks[methodName][i](params);
+ }
+ if (!listeners[methodName]) {
+ delete callbacks[methodName];
+ }
+ }
+ }
+ }
+ } catch(e) {
+ //consoleLog("Failed to process API response.");
+ }
}
- if (queryString.charAt(0) === '?') {
- queryString = queryString.slice(1);
- }
+ /**
+ * Makes an API call to SFDC domain.
+ */
+ function doPostMessage(params, callback) {
+ if (callback) {
+ params.method = registerCallback(params.method, callback);
+ }
- if (queryString.length === 0) {
- return params;
- }
+ // add nonce to params
+ params.nonce = nonce;
- var pairs = queryString.split('&');
- for (var i = 0; i < pairs.length; i++) {
- var pair = pairs[i].split('=');
- params[pair[0]] = !!pair[1] ? decodeURIComponent(pair[1]) : null;
- }
+ // add version
+ params.apiVersion = apiVersion;
- return params;
- }
-
- /**
- * Utility method to build a query string from key/value object.
- */
- function buildQueryString(params) {
- var qs = '';
- for (var key in params) {
- if (params.hasOwnProperty(key)) {
- qs += key + '=' + encodeURIComponent(params[key]) + '&';
- }
+ if (frameOrigin) {
+ var targetWindow = servedFromCanvas ? window.top : window.parent;
+ targetWindow.postMessage(INTERACTION_API + buildQueryString(params), frameOrigin);
+ }
}
- qs = qs.length > 0 ? qs.substr(0, qs.length-1) : qs;
- return qs;
- }
- function consoleLog(message) {
- if (window.console && console.log) {
- console.log(message);
+ function registerCallback(method, callback) {
+ if (listeners[method]) {
+ if (callbacks[method]) {
+ callbacks[method].push(callback);
+ } else {
+ callbacks[method] = [callback];
+ }
+ } else {
+ // API methods that are not listeners needs an ID in case they are call multiple times in an async manner.
+ method += '_' + methodId;
+ callbacks[method] = [callback];
+ methodId++;
+ }
+ return method;
}
- }
- function jsonStringify(object) {
- if (typeof Sfdc !== "undefined" && Sfdc.JSON) {
- return Sfdc.JSON.stringify(object);
- } else {
- return JSON.stringify(object);
- }
- }
+ /**
+ * Utility method to create a query string object.
+ */
+ function parseUrlQueryString(queryString) {
+ var params = {};
+ if (typeof queryString !== 'string') {
+ return params;
+ }
- function jsonParse(json) {
- if (typeof Sfdc !== "undefined" && Sfdc.JSON) {
- return Sfdc.JSON.parse(json);
- } else {
- return JSON.parse(json);
- }
- }
+ if (queryString.charAt(0) === '?') {
+ queryString = queryString.slice(1);
+ }
- /**
- * Entity Feed API implementation.
- */
- function EntityFeedApi(params) {
- var that = this;
- var nonce = null;
- var apiFrame;
- var apiOrigin;
- var readyQueue = [];
- this.processPostMessage;
+ if (queryString.length === 0) {
+ return params;
+ }
- function processApiResponse(event) {
- return decodeMessage(event);
- }
+ var pairs = queryString.split('&');
+ for (var i = 0; i < pairs.length; i++) {
+ var pair = pairs[i].split('=');
+ params[pair[0]] = !!pair[1] ? decodeURIComponent(pair[1]) : null;
+ }
- function decodeMessage(event) {
- if (isApiMessage(event, ENTITY_FEED_API)) {
- // Decode message and check authenticity
- var wrapper = jsonParse(event.data.substr(ENTITY_FEED_API.length));
+ return params;
+ }
- // Check that message source is the API and that nonce is present unless it is an AVAILABLE broadcast
- if (wrapper.message.fromApi && (wrapper.nonce === nonce || (!wrapper.nonce && wrapper.message.method === AVAILABLE))) {
- return wrapper.message;
+ /**
+ * Utility method to build a query string from key/value object.
+ */
+ function buildQueryString(params) {
+ var qs = '';
+ for (var key in params) {
+ if (params.hasOwnProperty(key)) {
+ qs += key + '=' + encodeURIComponent(params[key]) + '&';
+ }
}
- }
- return null;
+ qs = qs.length > 0 ? qs.substr(0, qs.length-1) : qs;
+ return qs;
}
- function doPostMessage(frames, targetOrigin, message, callback, connect) {
- if (!nonce) {
- consoleLog("API is not supported in this configuration.");
- return;
- }
-
- // Register callback if any
- if (callback) {
- message.method = registerCallback(message.method, callback);
- }
-
- // Encode message
- message.toApi = true;
- message.version = apiVersion;
- var messageContainer = {message: message, sourceFrameName: window.name};
- if (connect) {
- messageContainer.connect = true;
- } else {
- messageContainer.nonce = nonce;
- }
- var postData = ENTITY_FEED_API + jsonStringify(messageContainer);
-
- for (var i = 0, len = frames.length; i < len; i++) {
- frames[i].postMessage(postData, targetOrigin);
- }
+ function consoleLog(message) {
+ if (window.console && console.log) {
+ console.log(message);
+ }
}
- this.callApi = function(message, callback) {
- if (apiFrame) {
- doPostMessage([apiFrame], apiOrigin, message, callback, false);
- } else {
- readyQueue.push(function() {
- that.callApi(message, callback);
- });
- }
- };
-
- this.reloadFrame = function() {
- if (apiFrame) {
- if (params.frameName) {
- that.callApi({method: RELOAD_FRAME, objectId: params.id, frameName: params.frameName});
+ function jsonStringify(object) {
+ if (typeof Sfdc !== "undefined" && Sfdc.JSON) {
+ return Sfdc.JSON.stringify(object);
} else {
- location.reload();
- }
- }
- };
-
- function initialize() {
- nonce = params.entityFeedNonce;
-
- that.processPostMessage = function(event) {
- var message = decodeMessage(event);
- if (message == null) {
- return;
- } else if (message.method === CONNECT && (!params.id || message.objectId === params.id)) { // Inline page frames do not have an id param
- apiFrame = event.source;
- apiOrigin = event.origin;
- that.processPostMessage = processApiResponse;
-
- for (var i = 0, len = readyQueue.length; i < len; i++) {
- readyQueue[i]();
- }
- readyQueue = null;
- } else if (message.method === AVAILABLE && message.objectId === params.id) {
- // Detail page frame in console is notifying that API is available, try to connect
- doPostMessage([event.source], '*', {method: CONNECT, objectId: params.id}, null, true);
- }
- };
-
- var loadHandler = function() {
- // Remove load handler
- if (window.removeEventListener) {
- window.removeEventListener("load", arguments.callee, false);
- } else if (window.detachEvent) {
- window.detachEvent("onload", arguments.callee);
+ return JSON.stringify(object);
}
+ }
- // Search for api connection point.
- var frames = [];
- // Connect to current frame if api is available
- if (typeof entityFeedPage != "undefined") {
- frames.push(window);
+ function jsonParse(json) {
+ if (typeof Sfdc !== "undefined" && Sfdc.JSON) {
+ return Sfdc.JSON.parse(json);
} else {
- // Attach to parent if VF custom publisher
- frames.push(window.parent);
-
- // Attach to siblings for console frames if this is not an inline VF page in the entity feed page
- if (!params.isCEFP) {
- for (var parentFrames = window.parent.frames, i = 0, len = parentFrames.length; i < len; i++) {
- if (parentFrames[i] !== window.self) {
- frames.push(parentFrames[i]);
- }
- }
- }
- }
- // Call frames to connect
- doPostMessage(frames, '*', {method: CONNECT, objectId: params.id}, null, true);
- };
-
- var unloadHandler = function() {
- // Remove unload handler
- if (window.removeEventListener) {
- window.removeEventListener("unload", arguments.callee, false);
- } else if (window.detachEvent) {
- window.detachEvent("onunload", arguments.callee);
- }
- if (apiFrame) {
- doPostMessage([apiFrame], apiOrigin, {method: DISCONNECT}, null, false);
- apiFrame = null;
+ return JSON.parse(json);
}
- };
-
- if (window.addEventListener) {
- window.addEventListener("load", loadHandler, false);
- window.addEventListener("unload", unloadHandler, false);
- } else if (window.attachEvent) {
- window.attachEvent("onload", loadHandler);
- window.attachEvent("onunload", unloadHandler);
- }
- };
- initialize();
- }
-
- return {
+ }
/**
- * Initializes API to listen for responses from SFDC.
+ * Entity Feed API implementation.
*/
- initialize : function() {
- // set sfdc frame origin and nonce needed to call API methods
- var params = parseUrlQueryString(location.search);
-
- parseAuthParams(params);
-
- // initialize entity feed api
- if (!entityFeedApi && params.entityFeedNonce && typeof window.postMessage !== "undefined") {
- entityFeedApi = new EntityFeedApi(params);
- }
-
- if (frameOrigin || entityFeedApi) {
- // attach postMessage event to handler
- if (window.attachEvent) {
- window.attachEvent('onmessage', processPostMessage);
- } else {
- window.addEventListener('message', processPostMessage, false);
+ function EntityFeedApi(params) {
+ var that = this;
+ var nonce = null;
+ var apiFrame;
+ var apiOrigin;
+ var readyQueue = [];
+ this.processPostMessage;
+
+ function processApiResponse(event) {
+ return decodeMessage(event);
}
- }
- },
+ function decodeMessage(event) {
+ if (isApiMessage(event, ENTITY_FEED_API)) {
+ // Decode message and check authenticity
+ var wrapper = jsonParse(event.data.substr(ENTITY_FEED_API.length));
- /**
- * Returns true if is in console, false otherwise
- */
- isInConsole : function (callback) {
- doPostMessage({method:IS_IN_CONSOLE}, callback);
- },
+ // Check that message source is the API and that nonce is present unless it is an AVAILABLE broadcast
+ if (wrapper.message.fromApi && (wrapper.nonce === nonce || (!wrapper.nonce && wrapper.message.method === AVAILABLE))) {
+ return wrapper.message;
+ }
+ }
+ return null;
+ }
- /**
- * Screen pops to targetUrl and returns true if screen pop was successfully called, false otherwise.
- * Parameter force must be a boolean. Set this value to true to force screen pop, i.e.: to force screen pop on an edit page.
- */
- screenPop : function (targetUrl, force, callback) {
- doPostMessage({method:SCREEN_POP, targetUrl:targetUrl, force:!!force}, callback);
- },
+ function doPostMessage(frames, targetOrigin, message, callback, connect) {
+ if (!nonce) {
+ consoleLog("API is not supported in this configuration.");
+ return;
+ }
- searchAndGetScreenPopUrl : function (searchParams, queryParams, callType, callback) {
- doPostMessage({method:SEARCH_AND_GET_SCREEN_POP_URL, searchParams:searchParams, queryParams:queryParams, callType:callType}, callback);
- },
+ // Register callback if any
+ if (callback) {
+ message.method = registerCallback(message.method, callback);
+ }
- searchAndScreenPop : function (searchParams, queryParams, callType, callback) {
- doPostMessage({method:SEARCH_AND_SCREEN_POP, searchParams:searchParams, queryParams:queryParams, callType:callType}, callback);
- },
+ // Encode message
+ message.toApi = true;
+ message.version = apiVersion;
+ var messageContainer = {message: message, sourceFrameName: window.name};
+ if (connect) {
+ messageContainer.connect = true;
+ } else {
+ messageContainer.nonce = nonce;
+ }
+ var postData = ENTITY_FEED_API + jsonStringify(messageContainer);
- /**
- * Returns the current page info parameters: page Url, object Id (if applicable), object Name (if applicable), object (if applicable) as a JSON String.
- */
- getPageInfo : function (callback) {
- doPostMessage({method:GET_PAGE_INFO}, callback);
- },
+ for (var i = 0, len = frames.length; i < len; i++) {
+ frames[i].postMessage(postData, targetOrigin);
+ }
+ }
- /**
- * Registers a callback to be fired when the page gets focused.
- * When the callback is fired, it returns the current page info parameters: page Url, entity Id (if applicable), entity Name (if applicable) as a JSON String.
- */
- onFocus : function (callback) {
- doPostMessage({method:listeners.onFocus}, callback);
- },
+ this.callApi = function(message, callback) {
+ if (apiFrame) {
+ doPostMessage([apiFrame], apiOrigin, message, callback, false);
+ } else {
+ readyQueue.push(function() {
+ that.callApi(message, callback);
+ });
+ }
+ };
+
+ this.reloadFrame = function() {
+ if (apiFrame) {
+ if (params.frameName) {
+ that.callApi({method: RELOAD_FRAME, objectId: params.id, frameName: params.frameName});
+ } else {
+ location.reload();
+ }
+ }
+ };
+
+ function initialize() {
+ nonce = params.entityFeedNonce;
+
+ that.processPostMessage = function(event) {
+ var message = decodeMessage(event);
+ if (message == null) {
+ return;
+ } else if (message.method === CONNECT && (!params.id || message.objectId === params.id)) { // Inline page frames do not have an id param
+ apiFrame = event.source;
+ apiOrigin = event.origin;
+ that.processPostMessage = processApiResponse;
+
+ for (var i = 0, len = readyQueue.length; i < len; i++) {
+ readyQueue[i]();
+ }
+ readyQueue = null;
+ } else if (message.method === AVAILABLE && message.objectId === params.id) {
+ // Detail page frame in console is notifying that API is available, try to connect
+ doPostMessage([event.source], '*', {method: CONNECT, objectId: params.id}, null, true);
+ }
+ };
+
+ var loadHandler = function() {
+ // Remove load handler
+ if (window.removeEventListener) {
+ window.removeEventListener("load", arguments.callee, false);
+ } else if (window.detachEvent) {
+ window.detachEvent("onload", arguments.callee);
+ }
+
+ // Search for api connection point.
+ var frames = [];
+ // Connect to current frame if api is available
+ if (typeof entityFeedPage != "undefined") {
+ frames.push(window);
+ } else {
+ // Attach to parent if VF custom publisher
+ frames.push(window.parent);
+
+ // Attach to siblings for console frames if this is not an inline VF page in the entity feed page
+ if (!params.isCEFP) {
+ for (var parentFrames = window.parent.frames, i = 0, len = parentFrames.length; i < len; i++) {
+ if (parentFrames[i] !== window.self) {
+ frames.push(parentFrames[i]);
+ }
+ }
+ }
+ }
+ // Call frames to connect
+ doPostMessage(frames, '*', {method: CONNECT, objectId: params.id}, null, true);
+ };
+
+ var unloadHandler = function() {
+ // Remove unload handler
+ if (window.removeEventListener) {
+ window.removeEventListener("unload", arguments.callee, false);
+ } else if (window.detachEvent) {
+ window.detachEvent("onunload", arguments.callee);
+ }
+ if (apiFrame) {
+ doPostMessage([apiFrame], apiOrigin, {method: DISCONNECT}, null, false);
+ apiFrame = null;
+ }
+ };
+
+ if (window.addEventListener) {
+ window.addEventListener("load", loadHandler, false);
+ window.addEventListener("unload", unloadHandler, false);
+ } else if (window.attachEvent) {
+ window.attachEvent("onload", loadHandler);
+ window.attachEvent("onunload", unloadHandler);
+ }
+ };
+ initialize();
+ }
- /**
- * Save object to database and return true if object was saved successfully, false otherwise.
- * objectName is the API name of an object
- * saveParams is a query string representing a key-value pair of object fields to save.
- * Example:
- * // to save a new record
- * sforce.interaction.saveLog('Account', 'Name=Acme&Phone=4152125555', callback);
- * // to update a new record
- * sforce.interaction.saveLog('Account', 'Id=001D000000J6qIX&Name=UpdatedAcmeName', callback);
- */
- saveLog : function(objectName, saveParams, callback) {
- doPostMessage({method:SAVE_LOG, objectName:objectName, saveParams:encodeURIComponent(saveParams)}, callback);
- },
+ return {
- /**
- * Runs an Apex method from a class with supplied parameters.
- */
- runApex : function(apexClass, methodName, methodParams, callback) {
- doPostMessage({method:RUN_APEX_QUERY, apexClass:apexClass, methodName:methodName, methodParams:methodParams}, callback);
- },
+ /**
+ * Initializes API to listen for responses from SFDC.
+ */
+ initialize : function() {
+ // set sfdc frame origin and nonce needed to call API methods
+ var params = parseUrlQueryString(location.search);
- /**
- * Returns true if widget was successfully shown or hidden, false otherwise.
- * Parameter value must be a boolean.
- * Parameter callback must be a function.
- * If false is returned, an error message is also returned.
- */
- setVisible : function (value, callback) {
- doPostMessage({method:SET_VISIBLE, value:value}, callback);
- },
+ parseAuthParams(params);
- /**
- * Returns true if widget is visible, false otherwise.
- */
- isVisible : function (callback) {
- doPostMessage({method:IS_VISIBLE}, callback);
- },
+ // initialize entity feed api
+ if (!entityFeedApi && params.entityFeedNonce && typeof window.postMessage !== "undefined") {
+ entityFeedApi = new EntityFeedApi(params);
+ }
- /**
- * Returns true if page refresh is invoked, false otherwise.
- */
- refreshPage : function (callback) {
- doPostMessage({method:REFRESH_PAGE}, callback);
- },
+ if (frameOrigin || entityFeedApi) {
+ // attach postMessage event to handler
+ if (window.attachEvent) {
+ window.attachEvent('onmessage', processPostMessage);
+ } else {
+ window.addEventListener('message', processPostMessage, false);
+ }
+ }
- /**
- * Returns true if the related list with the given name is refreshed, false otherwise.
- */
- refreshRelatedList : function (listName, callback) {
- doPostMessage({method:REFRESH_RELATED_LIST, listName:listName}, callback);
- },
-
- cti: {
- /**
- * Gets Call Center Settings.
- */
- getCallCenterSettings : function (callback) {
- doPostMessage({method:GET_CALL_CENTER_SETTINGS}, callback);
- },
-
- /**
- * Gets Softphone Layout.
- */
- getSoftphoneLayout : function (callback) {
- doPostMessage({method:GET_SOFTPHONE_LAYOUT}, callback);
- },
-
- /**
- * Sets softphone height. Height must be greater or equal than zero
- */
- setSoftphoneHeight : function (height, callback) {
- doPostMessage({method:SET_SOFTPHONE_HEIGHT, height:height}, callback);
- },
-
- /**
- * Sets softphone width. Width must be greater or equal than zero.
- */
- setSoftphoneWidth : function (width, callback) {
- doPostMessage({method:SET_SOFTPHONE_WIDTH, width:width}, callback);
- },
-
- /**
- * Enables click to dial.
- */
- enableClickToDial : function (callback) {
- doPostMessage({method:ENABLE_CLICK_TO_DIAL}, callback);
- },
-
- /**
- * Disables click to dial.
- */
- disableClickToDial : function (callback) {
- doPostMessage({method:DISABLE_CLICK_TO_DIAL}, callback);
- },
-
- /**
- * Registers callback to be fired when user clicks to dial.
- */
- onClickToDial : function (callback) {
- doPostMessage({method:listeners.onClickToDial}, callback);
- },
-
- /**
- * Notifies that the adapter url has been successfully loaded.
- * Should be used if the standby url has been initialized.
- */
- notifyInitializationComplete: function() {
- doPostMessage({method:NOTIFY_INITIALIZATION_COMPLETE});
- },
-
- /**
- * Returns a list of phone numbers from a call center directory.
- */
- getDirectoryNumbers : function (isGlobal, callCenterName, callback, resultSetPage, resultSetPageSize) {
- var params = {method:GET_DIRECTORY_NUMBERS, isGlobal: isGlobal};
- if (callCenterName) {
- params.callCenterName = callCenterName;
- }
- if (resultSetPage) {
- params.resultSetPage = resultSetPage;
- }
- if (resultSetPageSize) {
- params.resultSetPageSize = resultSetPageSize;
+ },
+
+ /**
+ * Returns true if is in console, false otherwise
+ */
+ isInConsole : function (callback) {
+ doPostMessage({method:IS_IN_CONSOLE}, callback);
+ },
+
+ /**
+ * Screen pops to targetUrl and returns true if screen pop was successfully called, false otherwise.
+ * Parameter force must be a boolean. Set this value to true to force screen pop, i.e.: to force screen pop on an edit page.
+ */
+ screenPop : function (targetUrl, force, callback) {
+ doPostMessage({method:SCREEN_POP, targetUrl:targetUrl, force:!!force}, callback);
+ },
+
+ searchAndGetScreenPopUrl : function (searchParams, queryParams, callType, callback) {
+ doPostMessage({method:SEARCH_AND_GET_SCREEN_POP_URL, searchParams:searchParams, queryParams:queryParams, callType:callType}, callback);
+ },
+
+ searchAndScreenPop : function (searchParams, queryParams, callType, callback) {
+ doPostMessage({method:SEARCH_AND_SCREEN_POP, searchParams:searchParams, queryParams:queryParams, callType:callType}, callback);
+ },
+
+ /**
+ * Returns the current page info parameters: page Url, object Id (if applicable), object Name (if applicable), object (if applicable) as a JSON String.
+ */
+ getPageInfo : function (callback) {
+ doPostMessage({method:GET_PAGE_INFO}, callback);
+ },
+
+ /**
+ * Registers a callback to be fired when the page gets focused.
+ * When the callback is fired, it returns the current page info parameters: page Url, entity Id (if applicable), entity Name (if applicable) as a JSON String.
+ */
+ onFocus : function (callback) {
+ doPostMessage({method:listeners.onFocus}, callback);
+ },
+
+ /**
+ * Save object to database and return true if object was saved successfully, false otherwise.
+ * objectName is the API name of an object
+ * saveParams is a query string representing a key-value pair of object fields to save.
+ * Example:
+ * // to save a new record
+ * sforce.interaction.saveLog('Account', 'Name=Acme&Phone=4152125555', callback);
+ * // to update a new record
+ * sforce.interaction.saveLog('Account', 'Id=001D000000J6qIX&Name=UpdatedAcmeName', callback);
+ */
+ saveLog : function(objectName, saveParams, callback) {
+ doPostMessage({method:SAVE_LOG, objectName:objectName, saveParams:encodeURIComponent(saveParams)}, callback);
+ },
+
+ /**
+ * Runs an Apex method from a class with supplied parameters.
+ */
+ runApex : function(apexClass, methodName, methodParams, callback) {
+ doPostMessage({method:RUN_APEX_QUERY, apexClass:apexClass, methodName:methodName, methodParams:methodParams}, callback);
+ },
+
+ /**
+ * Returns true if widget was successfully shown or hidden, false otherwise.
+ * Parameter value must be a boolean.
+ * Parameter callback must be a function.
+ * If false is returned, an error message is also returned.
+ */
+ setVisible : function (value, callback) {
+ doPostMessage({method:SET_VISIBLE, value:value}, callback);
+ },
+
+ /**
+ * Returns true if widget is visible, false otherwise.
+ */
+ isVisible : function (callback) {
+ doPostMessage({method:IS_VISIBLE}, callback);
+ },
+
+ /**
+ * Returns true if page refresh is invoked, false otherwise.
+ */
+ refreshPage : function (callback) {
+ doPostMessage({method:REFRESH_PAGE}, callback);
+ },
+
+ /**
+ * Returns true if the related list with the given name is refreshed, false otherwise.
+ */
+ refreshRelatedList : function (listName, callback) {
+ doPostMessage({method:REFRESH_RELATED_LIST, listName:listName}, callback);
+ },
+
+ cti: {
+ /**
+ * Gets Call Center Settings.
+ */
+ getCallCenterSettings : function (callback) {
+ doPostMessage({method:GET_CALL_CENTER_SETTINGS}, callback);
+ },
+
+ /**
+ * Gets Softphone Layout.
+ */
+ getSoftphoneLayout : function (callback) {
+ doPostMessage({method:GET_SOFTPHONE_LAYOUT}, callback);
+ },
+
+ /**
+ * Sets softphone height. Height must be greater or equal than zero
+ */
+ setSoftphoneHeight : function (height, callback) {
+ doPostMessage({method:SET_SOFTPHONE_HEIGHT, height:height}, callback);
+ },
+
+ /**
+ * Sets softphone width. Width must be greater or equal than zero.
+ */
+ setSoftphoneWidth : function (width, callback) {
+ doPostMessage({method:SET_SOFTPHONE_WIDTH, width:width}, callback);
+ },
+
+ /**
+ * Enables click to dial.
+ */
+ enableClickToDial : function (callback) {
+ doPostMessage({method:ENABLE_CLICK_TO_DIAL}, callback);
+ },
+
+ /**
+ * Disables click to dial.
+ */
+ disableClickToDial : function (callback) {
+ doPostMessage({method:DISABLE_CLICK_TO_DIAL}, callback);
+ },
+
+ /**
+ * Registers callback to be fired when user clicks to dial.
+ */
+ onClickToDial : function (callback) {
+ doPostMessage({method:listeners.onClickToDial}, callback);
+ },
+
+ /**
+ * Notifies that the adapter url has been successfully loaded.
+ * Should be used if the standby url has been initialized.
+ */
+ notifyInitializationComplete: function() {
+ doPostMessage({method:NOTIFY_INITIALIZATION_COMPLETE});
+ },
+
+ /**
+ * Returns a list of phone numbers from a call center directory.
+ */
+ getDirectoryNumbers : function (isGlobal, callCenterName, callback, resultSetPage, resultSetPageSize) {
+ var params = {method:GET_DIRECTORY_NUMBERS, isGlobal: isGlobal};
+ if (callCenterName) {
+ params.callCenterName = callCenterName;
+ }
+ if (resultSetPage) {
+ params.resultSetPage = resultSetPage;
+ }
+ if (resultSetPageSize) {
+ params.resultSetPageSize = resultSetPageSize;
+ }
+ doPostMessage(params, callback);
+ }
+ },
+
+ /**
+ * Public API for Entity feed
+ */
+ entityFeed: {
+ /**
+ * Notifies that the object has been updated and its display need to be refreshed
+ */
+ refreshObject : function(objectId, refreshFields, refreshRelatedLists, refreshFeed, callback) {
+ entityFeedApi && entityFeedApi.callApi({method: REFRESH_OBJECT, objectId: objectId || params.id, refreshFields: refreshFields, refreshRelatedLists: refreshRelatedLists, refreshFeed: refreshFeed}, callback);
+ },
+
+ /**
+ * Registers a callback to be fired when the object has been updated.
+ */
+ onObjectUpdate : function(callback) {
+ entityFeedApi && entityFeedApi.callApi({method: listeners.onObjectUpdate}, callback);
+ },
+
+ /**
+ * Reloads the frame containing this page
+ */
+ reloadFrame : function() {
+ entityFeedApi && entityFeedApi.reloadFrame();
+ }
}
- doPostMessage(params, callback);
- }
- },
-
- /**
- * Public API for Entity feed
- */
- entityFeed: {
- /**
- * Notifies that the object has been updated and its display need to be refreshed
- */
- refreshObject : function(objectId, refreshFields, refreshRelatedLists, refreshFeed, callback) {
- entityFeedApi && entityFeedApi.callApi({method: REFRESH_OBJECT, objectId: objectId || params.id, refreshFields: refreshFields, refreshRelatedLists: refreshRelatedLists, refreshFeed: refreshFeed}, callback);
- },
-
- /**
- * Registers a callback to be fired when the object has been updated.
- */
- onObjectUpdate : function(callback) {
- entityFeedApi && entityFeedApi.callApi({method: listeners.onObjectUpdate}, callback);
- },
-
- /**
- * Reloads the frame containing this page
- */
- reloadFrame : function() {
- entityFeedApi && entityFeedApi.reloadFrame();
- }
- }
- };
+ };
})();
-sforce.interaction.initialize();
+sforce.interaction.initialize();
\ No newline at end of file