1 /**
  2 * Copyright (c) 2014, salesforce.com, inc.
  3 * All rights reserved.
  4 *
  5 * Redistribution and use in source and binary forms, with or without modification, are permitted provided
  6 * that the following conditions are met:
  7 *
  8 * Redistributions of source code must retain the above copyright notice, this list of conditions and the
  9 * following disclaimer.
 10 *
 11 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
 12 * the following disclaimer in the documentation and/or other materials provided with the distribution.
 13 *
 14 * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
 15 * promote products derived from this software without specific prior written permission.
 16 *
 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 19 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 21 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 23 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 24 * POSSIBILITY OF SUCH DAMAGE.
 25 */
 26 
 27 
 28 (function ($$, window) {
 29 
 30     "use strict";
 31 
 32     var module =   (function() {
 33 
 34         var internalCallback;
 35 
 36         /**
 37         * @description Pass a message to the target url
 38         * @param {String} message The message to send
 39         * @param {String} target_url Specifies what the origin of the target must be for the event to be dispatched.
 40         * @param {String} [target] The window that is the message's target. Defaults to the parent of the current window.
 41         */
 42         function postMessage(message, target_url, target) {
 43 			var sfdcJson = Sfdc.JSON || JSON;
 44 
 45             // If target url was not supplied (client may have lost it), we could default to '*',
 46             // However there are security implications here as other canvas apps could receive this
 47             // canvas apps oauth token.
 48             if ($$.isNil(target_url)) {
 49                 throw "ERROR: target_url was not supplied on postMessage";
 50             }
 51             var otherWindow = $$.stripUrl(target_url);
 52 
 53             target = target || parent;  // default to parent
 54             if (window.postMessage) {
 55                 // the browser supports window.postMessage, so call it with a targetOrigin
 56                 // set appropriately, based on the target_url parameter.
 57 
 58                 // Add the targetModule as Canvas so we are the only ones interested in these events
 59                 if ($$.isObject(message)) {message.targetModule = "Canvas";}
 60                 message = sfdcJson.stringify(message);
 61                 $$.console.log("Sending Post Message ", message);
 62                 target.postMessage(message, otherWindow);
 63             }
 64         }
 65         
 66         /**
 67         * @name Sfdc.canvas.xd#receive
 68         * @description Runs the callback function when the message event is received.
 69         * @param {Function} callback Function to run when the message event is received 
 70             if the event origin is acceptable.
 71         * @param {String} source_origin The origin of the desired events
 72         */
 73         function receiveMessage(callback, source_origin) {
 74 
 75             // browser supports window.postMessage (if not not supported for pilot - removed per securities request)
 76             if (window.postMessage) {
 77                 // bind the callback to the actual event associated with window.postMessage
 78                 if (callback) {
 79                     internalCallback = function(e) {
 80 
 81                         var data, r;
 82 						var sfdcJson = Sfdc.JSON || JSON;
 83 
 84                         $$.console.log("Post Message Got callback", e);
 85 
 86                         if (!$$.isNil(e)) {
 87                             if (typeof source_origin === 'string' && e.origin !== source_origin) {
 88                                 $$.console.log("source origin's don't match", e.origin, source_origin);
 89                                 return false;
 90                             }
 91                             if ($$.isFunction(source_origin)) {
 92                                 r = source_origin(e.origin, e.data);
 93                                 if (r === false) {
 94                                     $$.console.log("source origin's function returning false", e.origin, e.data);
 95                                     return false;
 96                                 }
 97                             }
 98                             if ($$.appearsJson(e.data))  {
 99                                 try {
100                                     data = sfdcJson.parse(e.data);
101                                 } catch (ignore) {
102                                     // Ignore parsing errors of any non json objects sent from other frames
103                                 }
104                                 // If we could parse the data and there is a targetModule make sure it is for us
105                                 if (!$$.isNil(data) && ($$.isNil(data.targetModule) || data.targetModule === "Canvas")) {
106                                     $$.console.log("Invoking callback");
107                                     callback(data, r);
108                                 }
109                             }
110                         }
111                     };
112                 }
113                 if (window.addEventListener) {
114                     window.addEventListener('message', internalCallback, false);
115                 } else {
116                     window.attachEvent('onmessage', internalCallback);
117                 }
118             }
119         }
120         
121         /**
122         * @description Removes the message event listener
123         * @public     
124         */
125         function removeListener() {
126 
127             // browser supports window.postMessage
128             if (window.postMessage) {
129                 if (window.removeEventListener) {
130                     window.removeEventListener('message', internalCallback, false);
131                 } else {
132                     window.detachEvent('onmessage', internalCallback);
133                 }
134             }
135         }
136 
137         return {
138             post : postMessage,
139             receive : receiveMessage,
140             remove : removeListener
141         };
142     }());
143 
144     $$.module('Sfdc.canvas.xd', module);
145 
146 }(Sfdc.canvas, this));