Advertisement
Guest User

Interaction

a guest
Jul 16th, 2019
280
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.92 KB | None | 0 0
  1. /*
  2. * Salesforce.com Interaction Toolkit 33.0
  3. * Copyright, 2014, salesforce.com, inc.
  4. * All Rights Reserved
  5. */
  6.  
  7. window.sforce = window.sforce || {};
  8.  
  9. sforce.interaction = (function() {
  10. var apiVersion = 33;
  11. var INTERACTION_API = 'interactionApi/';
  12. var ENTITY_FEED_API = 'entityFeedApi/';
  13. var frameOrigin = null;
  14. var nonce = null;
  15. var callbacks = {};
  16. var GET_CALL_CENTER_SETTINGS = 'getCallCenterSettings';
  17. var GET_SOFTPHONE_LAYOUT = 'getSoftphoneLayout';
  18. var GET_PAGE_INFO = 'getPageInfo';
  19. var SET_SOFTPHONE_HEIGHT = 'setSoftphoneHeight';
  20. var SET_SOFTPHONE_WIDTH = 'setSoftphoneWidth';
  21. var IS_IN_CONSOLE = 'isInConsole';
  22. var SCREEN_POP = 'screenPop';
  23. var SEARCH_AND_GET_SCREEN_POP_URL = 'searchAndGetScreenPopUrl';
  24. var SEARCH_AND_SCREEN_POP = 'searchAndScreenPop';
  25. var ENABLE_CLICK_TO_DIAL = 'enableClickToDial';
  26. var DISABLE_CLICK_TO_DIAL = 'disableClickToDial';
  27. var RUN_APEX_QUERY = 'runApex';
  28. var SAVE_LOG = 'saveLog';
  29. var SET_VISIBLE = 'setVisible';
  30. var IS_VISIBLE = 'isVisible';
  31. var CONNECT = 'connect';
  32. var REFRESH_OBJECT = 'refreshObject';
  33. var REFRESH_PAGE = 'refreshPage';
  34. var REFRESH_RELATED_LIST = 'refreshRelatedList';
  35. var NOTIFY_INITIALIZATION_COMPLETE = 'notifyInitializationComplete';
  36. var GET_DIRECTORY_NUMBERS = "getDirectoryNumbers";
  37. var listeners = {onClickToDial:'onClickToDial', onFocus:'onFocus', onObjectUpdate:'onObjectUpdate'};
  38. var methodId = 0;
  39. var entityFeedApi = null;
  40. var servedFromCanvas = false;
  41.  
  42. function isApiMessage(event, apiEndPoint) {
  43. return event.data && event.data.indexOf(apiEndPoint) === 0;
  44. }
  45.  
  46. function parseAuthParams(params) {
  47. // initialize if sfdcIFrameOrigin and nonce are present
  48. if (params['sfdcIFrameOrigin'] && params['nonce']) {
  49. frameOrigin = params['sfdcIFrameOrigin'] ? params['sfdcIFrameOrigin'].toLowerCase():null;
  50. nonce = params['nonce'];
  51. } else {
  52. // we may use canvas
  53. if (typeof Sfdc !== "undefined" && Sfdc.canvas && Sfdc.canvas.client) {
  54. var sr = Sfdc.canvas.client.signedrequest();
  55. var parsedRequest;
  56. if (sr) {
  57. if (typeof sr === "string") {
  58. parsedRequest = JSON.parse(sr);
  59. } else {
  60. // assume we're using OAuth
  61. parsedRequest = sr;
  62. }
  63. }
  64. if (parsedRequest) {
  65. var environment;
  66. if (parsedRequest.context) {
  67. environment = parsedRequest.context.environment;
  68. } else if (parsedRequest.payload) {
  69. environment = parsedRequest.payload.environment;
  70. }
  71. if (environment && environment.parameters) {
  72. frameOrigin = environment.parameters.sfdcIframeOrigin;
  73. nonce = environment.parameters.nonce;
  74. servedFromCanvas = environment.parameters.servedFromCanvas;
  75. }
  76. }
  77. }
  78. }
  79. }
  80.  
  81. /**
  82. * Process messages received from SFDC by executing callbacks, if any.
  83. * The event object contains the following fields:
  84. * method: the API method that was called.
  85. * result: result returned from the call.
  86. * error: an error message if any errors were encountered.
  87. */
  88. function processPostMessage(event) {
  89. var params;
  90. try {
  91. // Check if call is for entity feed
  92. if (isApiMessage(event, ENTITY_FEED_API)) {
  93. if (entityFeedApi && entityFeedApi.processPostMessage) {
  94. params = entityFeedApi.processPostMessage(event);
  95. }
  96. if (!params) {
  97. return;
  98. }
  99. } else if (isApiMessage(event, INTERACTION_API)) {
  100. if (event.origin !== frameOrigin || !frameOrigin) {
  101. // Only trust messages from the adapter frame
  102. return;
  103. }
  104.  
  105. var message = event.data.replace(INTERACTION_API, ''); // strip off API target
  106. params = parseUrlQueryString(message);
  107.  
  108. // convert string true/false to boolean for methods that needs to return boolean values.
  109. if (params && (params.result === 'true' || params.result === 'false')) {
  110. params.result = params.result === 'true';
  111. }
  112. } else {
  113. // return if postMessage is not targeted to interaction API
  114. return;
  115. }
  116.  
  117. // execute callbacks registered for the method called
  118. for (var methodName in callbacks) {
  119. if (callbacks.hasOwnProperty(methodName)) {
  120. if (params.method === methodName) {
  121. for (var i in callbacks[methodName]) {
  122. callbacks[methodName][i](params);
  123. }
  124. if (!listeners[methodName]) {
  125. delete callbacks[methodName];
  126. }
  127. }
  128. }
  129. }
  130. } catch(e) {
  131. consoleLog("Failed to process API response.");
  132. }
  133. }
  134.  
  135. /**
  136. * Makes an API call to SFDC domain.
  137. */
  138. function doPostMessage(params, callback) {
  139. if (callback) {
  140. params.method = registerCallback(params.method, callback);
  141. }
  142.  
  143. // add nonce to params
  144. params.nonce = nonce;
  145.  
  146. // add version
  147. params.apiVersion = apiVersion;
  148.  
  149. if (frameOrigin) {
  150. var targetWindow = servedFromCanvas ? window.top : window.parent;
  151. targetWindow.postMessage(INTERACTION_API + buildQueryString(params), frameOrigin);
  152. }
  153. }
  154.  
  155. function registerCallback(method, callback) {
  156. if (listeners[method]) {
  157. if (callbacks[method]) {
  158. callbacks[method].push(callback);
  159. } else {
  160. callbacks[method] = [callback];
  161. }
  162. } else {
  163. // API methods that are not listeners needs an ID in case they are call multiple times in an async manner.
  164. method += '_' + methodId;
  165. callbacks[method] = [callback];
  166. methodId++;
  167. }
  168. return method;
  169. }
  170.  
  171. /**
  172. * Utility method to create a query string object.
  173. */
  174. function parseUrlQueryString(queryString) {
  175. var params = {};
  176. if (typeof queryString !== 'string') {
  177. return params;
  178. }
  179.  
  180. if (queryString.charAt(0) === '?') {
  181. queryString = queryString.slice(1);
  182. }
  183.  
  184. if (queryString.length === 0) {
  185. return params;
  186. }
  187.  
  188. var pairs = queryString.split('&');
  189. for (var i = 0; i < pairs.length; i++) {
  190. var pair = pairs[i].split('=');
  191. params[pair[0]] = !!pair[1] ? decodeURIComponent(pair[1]) : null;
  192. }
  193.  
  194. return params;
  195. }
  196.  
  197. /**
  198. * Utility method to build a query string from key/value object.
  199. */
  200. function buildQueryString(params) {
  201. var qs = '';
  202. for (var key in params) {
  203. if (params.hasOwnProperty(key)) {
  204. qs += key + '=' + encodeURIComponent(params[key]) + '&';
  205. }
  206. }
  207. qs = qs.length > 0 ? qs.substr(0, qs.length-1) : qs;
  208. return qs;
  209. }
  210.  
  211. function consoleLog(message) {
  212. if (window.console && console.log) {
  213. console.log(message);
  214. }
  215. }
  216.  
  217. function jsonStringify(object) {
  218. if (typeof Sfdc !== "undefined" && Sfdc.JSON) {
  219. return Sfdc.JSON.stringify(object);
  220. } else {
  221. return JSON.stringify(object);
  222. }
  223. }
  224.  
  225. function jsonParse(json) {
  226. if (typeof Sfdc !== "undefined" && Sfdc.JSON) {
  227. return Sfdc.JSON.parse(json);
  228. } else {
  229. return JSON.parse(json);
  230. }
  231. }
  232.  
  233. /**
  234. * Entity Feed API implementation.
  235. */
  236. function EntityFeedApi(params) {
  237. var that = this;
  238. var nonce = null;
  239. var apiFrame;
  240. var apiOrigin;
  241. var readyQueue = [];
  242. this.processPostMessage;
  243.  
  244. function processApiResponse(event) {
  245. return decodeMessage(event);
  246. }
  247.  
  248. function decodeMessage(event) {
  249. if (isApiMessage(event, ENTITY_FEED_API)) {
  250. // Decode message and check authenticity
  251. var wrapper = jsonParse(event.data.substr(ENTITY_FEED_API.length));
  252.  
  253. if (wrapper.message.fromApi && wrapper.nonce === nonce) {
  254. return wrapper.message;
  255. }
  256. }
  257. return null;
  258. }
  259.  
  260. function doPostMessage(frames, targetOrigin, message, callback, connect) {
  261. if (!nonce) {
  262. consoleLog("API is not supported in this configuration.");
  263. return;
  264. }
  265.  
  266. // Register callback if any
  267. if (callback) {
  268. message.method = registerCallback(message.method, callback);
  269. }
  270.  
  271. // Encode message
  272. message.toApi = true;
  273. message.version = apiVersion;
  274. var messageContainer = {message: message, sourceFrameName: window.name};
  275. if (connect) {
  276. messageContainer.connect = true;
  277. } else {
  278. messageContainer.nonce = nonce;
  279. }
  280. var postData = ENTITY_FEED_API + jsonStringify(messageContainer);
  281.  
  282. for (var i = 0, len = frames.length; i < len; i++) {
  283. frames[i].postMessage(postData, targetOrigin);
  284. }
  285. }
  286.  
  287. this.callApi = function(message, callback) {
  288. if (apiFrame) {
  289. doPostMessage([apiFrame], apiOrigin, message, callback, false);
  290. } else {
  291. readyQueue.push(function() {
  292. that.callApi(message, callback);
  293. });
  294. }
  295. };
  296.  
  297. function initialize() {
  298. nonce = params.entityFeedNonce;
  299.  
  300. that.processPostMessage = function(event) {
  301. var message = decodeMessage(event);
  302. if (message != null && message.method === CONNECT) {
  303. apiFrame = event.source;
  304. apiOrigin = event.origin;
  305. that.processPostMessage = processApiResponse;
  306.  
  307. for (var i = 0, len = readyQueue.length; i < len; i++) {
  308. readyQueue[i]();
  309. }
  310. readyQueue = null;
  311. }
  312. };
  313.  
  314. var loadHandler = function() {
  315. // Remove load handler
  316. if (window.removeEventListener) {
  317. window.removeEventListener("load", arguments.callee, false);
  318. } else if (window.detachEvent) {
  319. window.detachEvent("onload", arguments.callee);
  320. }
  321.  
  322. // Search for api connection point.
  323. var frames = [];
  324. // Connect to current frame if api is available
  325. if (typeof entityFeedPage != "undefined") {
  326. frames.push(window);
  327. } else {
  328. // Attach to parent if VF custom publisher
  329. frames.push(window.parent);
  330.  
  331. // Attach to siblings for console frames
  332. for (var parentFrames = window.parent.frames, i = 0, len = parentFrames.length; i < len; i++) {
  333. if (parentFrames[i] !== window.self) {
  334. frames.push(parentFrames[i]);
  335. }
  336. }
  337. }
  338. // call frames to connect
  339. doPostMessage(frames, '*', {method: CONNECT}, null, true);
  340. };
  341.  
  342. if (window.addEventListener) {
  343. window.addEventListener("load", loadHandler, false);
  344. } else if (window.attachEvent) {
  345. window.attachEvent("onload", loadHandler);
  346. }
  347. };
  348. initialize();
  349. }
  350.  
  351. return {
  352.  
  353. /**
  354. * Initializes API to listen for responses from SFDC.
  355. */
  356. initialize : function() {
  357. // set sfdc frame origin and nonce needed to call API methods
  358. var params = parseUrlQueryString(location.search);
  359.  
  360. parseAuthParams(params);
  361.  
  362. // initialize entity feed api
  363. if (!entityFeedApi && params.entityFeedNonce && typeof window.postMessage !== "undefined") {
  364. entityFeedApi = new EntityFeedApi(params);
  365. }
  366.  
  367. if (frameOrigin || entityFeedApi) {
  368. // attach postMessage event to handler
  369. if (window.attachEvent) {
  370. window.attachEvent('onmessage', processPostMessage);
  371. } else {
  372. window.addEventListener('message', processPostMessage, false);
  373. }
  374. }
  375.  
  376. },
  377.  
  378. /**
  379. * Returns true if is in console, false otherwise
  380. */
  381. isInConsole : function (callback) {
  382. doPostMessage({method:IS_IN_CONSOLE}, callback);
  383. },
  384.  
  385. /**
  386. * Screen pops to targetUrl and returns true if screen pop was successfully called, false otherwise.
  387. * 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.
  388. */
  389. screenPop : function (targetUrl, force, callback) {
  390. doPostMessage({method:SCREEN_POP, targetUrl:targetUrl, force:!!force}, callback);
  391. },
  392.  
  393. searchAndGetScreenPopUrl : function (searchParams, queryParams, callType, callback) {
  394. doPostMessage({method:SEARCH_AND_GET_SCREEN_POP_URL, searchParams:searchParams, queryParams:queryParams, callType:callType}, callback);
  395. },
  396.  
  397. searchAndScreenPop : function (searchParams, queryParams, callType, callback) {
  398. doPostMessage({method:SEARCH_AND_SCREEN_POP, searchParams:searchParams, queryParams:queryParams, callType:callType}, callback);
  399. },
  400.  
  401. /**
  402. * Returns the current page info parameters: page Url, object Id (if applicable), object Name (if applicable), object (if applicable) as a JSON String.
  403. */
  404. getPageInfo : function (callback) {
  405. doPostMessage({method:GET_PAGE_INFO}, callback);
  406. },
  407.  
  408. /**
  409. * Registers a callback to be fired when the page gets focused.
  410. * 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.
  411. */
  412. onFocus : function (callback) {
  413. doPostMessage({method:listeners.onFocus}, callback);
  414. },
  415.  
  416. /**
  417. * Save object to database and return true if object was saved successfully, false otherwise.
  418. * objectName is the API name of an object
  419. * saveParams is a query string representing a key-value pair of object fields to save.
  420. * Example:
  421. * // to save a new record
  422. * sforce.interaction.saveLog('Account', 'Name=Acme&Phone=4152125555', callback);
  423. * // to update a new record
  424. * sforce.interaction.saveLog('Account', 'Id=001D000000J6qIX&Name=UpdatedAcmeName', callback);
  425. */
  426. saveLog : function(objectName, saveParams, callback) {
  427. doPostMessage({method:SAVE_LOG, objectName:objectName, saveParams:encodeURIComponent(saveParams)}, callback);
  428. },
  429.  
  430. /**
  431. * Runs an Apex method from a class with supplied parameters.
  432. */
  433. runApex : function(apexClass, methodName, methodParams, callback) {
  434. doPostMessage({method:RUN_APEX_QUERY, apexClass:apexClass, methodName:methodName, methodParams:methodParams}, callback);
  435. },
  436.  
  437. /**
  438. * Returns true if widget was successfully shown or hidden, false otherwise.
  439. * Parameter value must be a boolean.
  440. * Parameter callback must be a function.
  441. * If false is returned, an error message is also returned.
  442. */
  443. setVisible : function (value, callback) {
  444. doPostMessage({method:SET_VISIBLE, value:value}, callback);
  445. },
  446.  
  447. /**
  448. * Returns true if widget is visible, false otherwise.
  449. */
  450. isVisible : function (callback) {
  451. doPostMessage({method:IS_VISIBLE}, callback);
  452. },
  453.  
  454. /**
  455. * Returns true if page refresh is invoked, false otherwise.
  456. */
  457. refreshPage : function (callback) {
  458. doPostMessage({method:REFRESH_PAGE}, callback);
  459. },
  460.  
  461. /**
  462. * Returns true if the related list with the given name is refreshed, false otherwise.
  463. */
  464. refreshRelatedList : function (listName, callback) {
  465. doPostMessage({method:REFRESH_RELATED_LIST, listName:listName}, callback);
  466. },
  467.  
  468. cti: {
  469. /**
  470. * Gets Call Center Settings.
  471. */
  472. getCallCenterSettings : function (callback) {
  473. doPostMessage({method:GET_CALL_CENTER_SETTINGS}, callback);
  474. },
  475.  
  476. /**
  477. * Gets Softphone Layout.
  478. */
  479. getSoftphoneLayout : function (callback) {
  480. doPostMessage({method:GET_SOFTPHONE_LAYOUT}, callback);
  481. },
  482.  
  483. /**
  484. * Sets softphone height. Height must be greater or equal than zero
  485. */
  486. setSoftphoneHeight : function (height, callback) {
  487. doPostMessage({method:SET_SOFTPHONE_HEIGHT, height:height}, callback);
  488. },
  489.  
  490. /**
  491. * Sets softphone width. Width must be greater or equal than zero.
  492. */
  493. setSoftphoneWidth : function (width, callback) {
  494. doPostMessage({method:SET_SOFTPHONE_WIDTH, width:width}, callback);
  495. },
  496.  
  497. /**
  498. * Enables click to dial.
  499. */
  500. enableClickToDial : function (callback) {
  501. doPostMessage({method:ENABLE_CLICK_TO_DIAL}, callback);
  502. },
  503.  
  504. /**
  505. * Disables click to dial.
  506. */
  507. disableClickToDial : function (callback) {
  508. doPostMessage({method:DISABLE_CLICK_TO_DIAL}, callback);
  509. },
  510.  
  511. /**
  512. * Registers callback to be fired when user clicks to dial.
  513. */
  514. onClickToDial : function (callback) {
  515. doPostMessage({method:listeners.onClickToDial}, callback);
  516. },
  517.  
  518. /**
  519. * Notifies that the adapter url has been successfully loaded.
  520. * Should be used if the standby url has been initialized.
  521. */
  522. notifyInitializationComplete: function() {
  523. doPostMessage({method:NOTIFY_INITIALIZATION_COMPLETE});
  524. },
  525.  
  526. /**
  527. * Returns a list of phone numbers from a call center directory.
  528. */
  529. getDirectoryNumbers : function (isGlobal, callCenterName, callback, resultSetPage, resultSetPageSize) {
  530. var params = {method:GET_DIRECTORY_NUMBERS, isGlobal: isGlobal};
  531. if (callCenterName) {
  532. params.callCenterName = callCenterName;
  533. }
  534. if (resultSetPage) {
  535. params.resultSetPage = resultSetPage;
  536. }
  537. if (resultSetPageSize) {
  538. params.resultSetPageSize = resultSetPageSize;
  539. }
  540. doPostMessage(params, callback);
  541. }
  542. },
  543.  
  544. /**
  545. * Public API for Entity feed
  546. */
  547. entityFeed: {
  548. /**
  549. * Notifies that the object has been updated and its display need to be refreshed
  550. */
  551. refreshObject : function(objectId, refreshFields, refreshRelatedLists, refreshFeed, callback) {
  552. entityFeedApi && entityFeedApi.callApi({method: REFRESH_OBJECT, objectId: objectId, refreshFields: refreshFields, refreshRelatedLists: refreshRelatedLists, refreshFeed: refreshFeed}, callback);
  553. },
  554.  
  555. /**
  556. * Registers a callback to be fired when the object has been updated.
  557. */
  558. onObjectUpdate : function(callback) {
  559. entityFeedApi && entityFeedApi.callApi({method: listeners.onObjectUpdate}, callback);
  560. }
  561. }
  562. };
  563. })();
  564.  
  565. sforce.interaction.initialize();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement