PageRenderTime 55ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/files/easyxdm/2.4.18/easyXDM.debug.js

https://gitlab.com/Mirros/jsdelivr
JavaScript | 1293 lines | 710 code | 68 blank | 515 comment | 178 complexity | 08755e04cc9487ce4a6ebd2d23f00ee4 MD5 | raw file
  1. /**
  2. * easyXDM
  3. * http://easyxdm.net/
  4. * Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. (function (window, document, location, setTimeout, decodeURIComponent, encodeURIComponent) {
  25. /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
  26. /*global JSON, XMLHttpRequest, window, escape, unescape, ActiveXObject */
  27. //
  28. // easyXDM
  29. // http://easyxdm.net/
  30. // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
  31. //
  32. // Permission is hereby granted, free of charge, to any person obtaining a copy
  33. // of this software and associated documentation files (the "Software"), to deal
  34. // in the Software without restriction, including without limitation the rights
  35. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  36. // copies of the Software, and to permit persons to whom the Software is
  37. // furnished to do so, subject to the following conditions:
  38. //
  39. // The above copyright notice and this permission notice shall be included in
  40. // all copies or substantial portions of the Software.
  41. //
  42. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  43. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  44. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  45. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  46. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  47. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  48. // THE SOFTWARE.
  49. //
  50. var global = this;
  51. var channelId = Math.floor(Math.random() * 10000); // randomize the initial id in case of multiple closures loaded
  52. var emptyFn = Function.prototype;
  53. var reURI = /^((http.?:)\/\/([^:\/\s]+)(:\d+)*)/; // returns groups for protocol (2), domain (3) and port (4)
  54. var reParent = /[\-\w]+\/\.\.\//; // matches a foo/../ expression
  55. var reDoubleSlash = /([^:])\/\//g; // matches // anywhere but in the protocol
  56. var namespace = ""; // stores namespace under which easyXDM object is stored on the page (empty if object is global)
  57. var easyXDM = {};
  58. var _easyXDM = window.easyXDM; // map over global easyXDM in case of overwrite
  59. var IFRAME_PREFIX = "easyXDM_";
  60. var HAS_NAME_PROPERTY_BUG;
  61. var useHash = false; // whether to use the hash over the query
  62. var flashVersion; // will be set if using flash
  63. var HAS_FLASH_THROTTLED_BUG;
  64. var _trace = emptyFn;
  65. // http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting
  66. function isHostMethod(object, property){
  67. var t = typeof object[property];
  68. return t == 'function' ||
  69. (!!(t == 'object' && object[property])) ||
  70. t == 'unknown';
  71. }
  72. function isHostObject(object, property){
  73. return !!(typeof(object[property]) == 'object' && object[property]);
  74. }
  75. // end
  76. // http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
  77. function isArray(o){
  78. return Object.prototype.toString.call(o) === '[object Array]';
  79. }
  80. // end
  81. function hasFlash(){
  82. var name = "Shockwave Flash", mimeType = "application/x-shockwave-flash";
  83. if (!undef(navigator.plugins) && typeof navigator.plugins[name] == "object") {
  84. // adapted from the swfobject code
  85. var description = navigator.plugins[name].description;
  86. if (description && !undef(navigator.mimeTypes) && navigator.mimeTypes[mimeType] && navigator.mimeTypes[mimeType].enabledPlugin) {
  87. flashVersion = description.match(/\d+/g);
  88. }
  89. }
  90. if (!flashVersion) {
  91. var flash;
  92. try {
  93. flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
  94. flashVersion = Array.prototype.slice.call(flash.GetVariable("$version").match(/(\d+),(\d+),(\d+),(\d+)/), 1);
  95. flash = null;
  96. }
  97. catch (notSupportedException) {
  98. }
  99. }
  100. if (!flashVersion) {
  101. return false;
  102. }
  103. var major = parseInt(flashVersion[0], 10), minor = parseInt(flashVersion[1], 10);
  104. HAS_FLASH_THROTTLED_BUG = major > 9 && minor > 0;
  105. return true;
  106. }
  107. /*
  108. * Cross Browser implementation for adding and removing event listeners.
  109. */
  110. var on, un;
  111. if (isHostMethod(window, "addEventListener")) {
  112. on = function(target, type, listener){
  113. _trace("adding listener " + type);
  114. target.addEventListener(type, listener, false);
  115. };
  116. un = function(target, type, listener){
  117. _trace("removing listener " + type);
  118. target.removeEventListener(type, listener, false);
  119. };
  120. }
  121. else if (isHostMethod(window, "attachEvent")) {
  122. on = function(object, sEvent, fpNotify){
  123. _trace("adding listener " + sEvent);
  124. object.attachEvent("on" + sEvent, fpNotify);
  125. };
  126. un = function(object, sEvent, fpNotify){
  127. _trace("removing listener " + sEvent);
  128. object.detachEvent("on" + sEvent, fpNotify);
  129. };
  130. }
  131. else {
  132. throw new Error("Browser not supported");
  133. }
  134. /*
  135. * Cross Browser implementation of DOMContentLoaded.
  136. */
  137. var domIsReady = false, domReadyQueue = [], readyState;
  138. if ("readyState" in document) {
  139. // If browser is WebKit-powered, check for both 'loaded' (legacy browsers) and
  140. // 'interactive' (HTML5 specs, recent WebKit builds) states.
  141. // https://bugs.webkit.org/show_bug.cgi?id=45119
  142. readyState = document.readyState;
  143. domIsReady = readyState == "complete" || (~ navigator.userAgent.indexOf('AppleWebKit/') && (readyState == "loaded" || readyState == "interactive"));
  144. }
  145. else {
  146. // If readyState is not supported in the browser, then in order to be able to fire whenReady functions apropriately
  147. // when added dynamically _after_ DOM load, we have to deduce wether the DOM is ready or not.
  148. // We only need a body to add elements to, so the existence of document.body is enough for us.
  149. domIsReady = !!document.body;
  150. }
  151. function dom_onReady(){
  152. if (domIsReady) {
  153. return;
  154. }
  155. domIsReady = true;
  156. _trace("firing dom_onReady");
  157. for (var i = 0; i < domReadyQueue.length; i++) {
  158. domReadyQueue[i]();
  159. }
  160. domReadyQueue.length = 0;
  161. }
  162. if (!domIsReady) {
  163. if (isHostMethod(window, "addEventListener")) {
  164. on(document, "DOMContentLoaded", dom_onReady);
  165. }
  166. else {
  167. on(document, "readystatechange", function(){
  168. if (document.readyState == "complete") {
  169. dom_onReady();
  170. }
  171. });
  172. if (document.documentElement.doScroll && window === top) {
  173. var doScrollCheck = function(){
  174. if (domIsReady) {
  175. return;
  176. }
  177. // http://javascript.nwbox.com/IEContentLoaded/
  178. try {
  179. document.documentElement.doScroll("left");
  180. }
  181. catch (e) {
  182. setTimeout(doScrollCheck, 1);
  183. return;
  184. }
  185. dom_onReady();
  186. };
  187. doScrollCheck();
  188. }
  189. }
  190. // A fallback to window.onload, that will always work
  191. on(window, "load", dom_onReady);
  192. }
  193. /**
  194. * This will add a function to the queue of functions to be run once the DOM reaches a ready state.
  195. * If functions are added after this event then they will be executed immediately.
  196. * @param {function} fn The function to add
  197. * @param {Object} scope An optional scope for the function to be called with.
  198. */
  199. function whenReady(fn, scope){
  200. if (domIsReady) {
  201. fn.call(scope);
  202. return;
  203. }
  204. domReadyQueue.push(function(){
  205. fn.call(scope);
  206. });
  207. }
  208. /**
  209. * Returns an instance of easyXDM from the parent window with
  210. * respect to the namespace.
  211. *
  212. * @return An instance of easyXDM (in the parent window)
  213. */
  214. function getParentObject(){
  215. var obj = parent;
  216. if (namespace !== "") {
  217. for (var i = 0, ii = namespace.split("."); i < ii.length; i++) {
  218. if (!obj) {
  219. throw new Error(ii.slice(0, i + 1).join('.') + ' is not an object');
  220. }
  221. obj = obj[ii[i]];
  222. }
  223. }
  224. if (!obj || !obj.easyXDM) {
  225. throw new Error('Could not find easyXDM in parent.' + namespace);
  226. }
  227. return obj.easyXDM;
  228. }
  229. /**
  230. * Removes easyXDM variable from the global scope. It also returns control
  231. * of the easyXDM variable to whatever code used it before.
  232. *
  233. * @param {String} ns A string representation of an object that will hold
  234. * an instance of easyXDM.
  235. * @return An instance of easyXDM
  236. */
  237. function noConflict(ns){
  238. if (typeof ns != "string" || !ns) {
  239. throw new Error('namespace must be a non-empty string');
  240. }
  241. _trace("Settings namespace to '" + ns + "'");
  242. window.easyXDM = _easyXDM;
  243. namespace = ns;
  244. if (namespace) {
  245. IFRAME_PREFIX = "easyXDM_" + namespace.replace(".", "_") + "_";
  246. }
  247. return easyXDM;
  248. }
  249. /*
  250. * Methods for working with URLs
  251. */
  252. /**
  253. * Get the domain name from a url.
  254. * @param {String} url The url to extract the domain from.
  255. * @return The domain part of the url.
  256. * @type {String}
  257. */
  258. function getDomainName(url){
  259. if (!url) {
  260. throw new Error("url is undefined or empty");
  261. }
  262. return url.match(reURI)[3];
  263. }
  264. /**
  265. * Get the port for a given URL, or "" if none
  266. * @param {String} url The url to extract the port from.
  267. * @return The port part of the url.
  268. * @type {String}
  269. */
  270. function getPort(url){
  271. if (!url) {
  272. throw new Error("url is undefined or empty");
  273. }
  274. return url.match(reURI)[4] || "";
  275. }
  276. /**
  277. * Returns a string containing the schema, domain and if present the port
  278. * @param {String} url The url to extract the location from
  279. * @return {String} The location part of the url
  280. */
  281. function getLocation(url){
  282. if (!url) {
  283. throw new Error("url is undefined or empty");
  284. }
  285. if (/^file/.test(url)) {
  286. throw new Error("The file:// protocol is not supported");
  287. }
  288. var m = url.toLowerCase().match(reURI);
  289. var proto = m[2], domain = m[3], port = m[4] || "";
  290. if ((proto == "http:" && port == ":80") || (proto == "https:" && port == ":443")) {
  291. port = "";
  292. }
  293. return proto + "//" + domain + port;
  294. }
  295. /**
  296. * Resolves a relative url into an absolute one.
  297. * @param {String} url The path to resolve.
  298. * @return {String} The resolved url.
  299. */
  300. function resolveUrl(url){
  301. if (!url) {
  302. throw new Error("url is undefined or empty");
  303. }
  304. // replace all // except the one in proto with /
  305. url = url.replace(reDoubleSlash, "$1/");
  306. // If the url is a valid url we do nothing
  307. if (!url.match(/^(http||https):\/\//)) {
  308. // If this is a relative path
  309. var path = (url.substring(0, 1) === "/") ? "" : location.pathname;
  310. if (path.substring(path.length - 1) !== "/") {
  311. path = path.substring(0, path.lastIndexOf("/") + 1);
  312. }
  313. url = location.protocol + "//" + location.host + path + url;
  314. }
  315. // reduce all 'xyz/../' to just ''
  316. while (reParent.test(url)) {
  317. url = url.replace(reParent, "");
  318. }
  319. _trace("resolved url '" + url + "'");
  320. return url;
  321. }
  322. /**
  323. * Appends the parameters to the given url.<br/>
  324. * The base url can contain existing query parameters.
  325. * @param {String} url The base url.
  326. * @param {Object} parameters The parameters to add.
  327. * @return {String} A new valid url with the parameters appended.
  328. */
  329. function appendQueryParameters(url, parameters){
  330. if (!parameters) {
  331. throw new Error("parameters is undefined or null");
  332. }
  333. var hash = "", indexOf = url.indexOf("#");
  334. if (indexOf !== -1) {
  335. hash = url.substring(indexOf);
  336. url = url.substring(0, indexOf);
  337. }
  338. var q = [];
  339. for (var key in parameters) {
  340. if (parameters.hasOwnProperty(key)) {
  341. q.push(key + "=" + encodeURIComponent(parameters[key]));
  342. }
  343. }
  344. return url + (useHash ? "#" : (url.indexOf("?") == -1 ? "?" : "&")) + q.join("&") + hash;
  345. }
  346. // build the query object either from location.query, if it contains the xdm_e argument, or from location.hash
  347. var query = (function(input){
  348. input = input.substring(1).split("&");
  349. var data = {}, pair, i = input.length;
  350. while (i--) {
  351. pair = input[i].split("=");
  352. data[pair[0]] = decodeURIComponent(pair[1]);
  353. }
  354. return data;
  355. }(/xdm_e=/.test(location.search) ? location.search : location.hash));
  356. /*
  357. * Helper methods
  358. */
  359. /**
  360. * Helper for checking if a variable/property is undefined
  361. * @param {Object} v The variable to test
  362. * @return {Boolean} True if the passed variable is undefined
  363. */
  364. function undef(v){
  365. return typeof v === "undefined";
  366. }
  367. /**
  368. * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.
  369. * @return {JSON} A valid JSON conforming object, or null if not found.
  370. */
  371. var getJSON = function(){
  372. var cached = {};
  373. var obj = {
  374. a: [1, 2, 3]
  375. }, json = "{\"a\":[1,2,3]}";
  376. if (typeof JSON != "undefined" && typeof JSON.stringify === "function" && JSON.stringify(obj).replace((/\s/g), "") === json) {
  377. // this is a working JSON instance
  378. return JSON;
  379. }
  380. if (Object.toJSON) {
  381. if (Object.toJSON(obj).replace((/\s/g), "") === json) {
  382. // this is a working stringify method
  383. cached.stringify = Object.toJSON;
  384. }
  385. }
  386. if (typeof String.prototype.evalJSON === "function") {
  387. obj = json.evalJSON();
  388. if (obj.a && obj.a.length === 3 && obj.a[2] === 3) {
  389. // this is a working parse method
  390. cached.parse = function(str){
  391. return str.evalJSON();
  392. };
  393. }
  394. }
  395. if (cached.stringify && cached.parse) {
  396. // Only memoize the result if we have valid instance
  397. getJSON = function(){
  398. return cached;
  399. };
  400. return cached;
  401. }
  402. return null;
  403. };
  404. /**
  405. * Applies properties from the source object to the target object.<br/>
  406. * @param {Object} target The target of the properties.
  407. * @param {Object} source The source of the properties.
  408. * @param {Boolean} noOverwrite Set to True to only set non-existing properties.
  409. */
  410. function apply(destination, source, noOverwrite){
  411. var member;
  412. for (var prop in source) {
  413. if (source.hasOwnProperty(prop)) {
  414. if (prop in destination) {
  415. member = source[prop];
  416. if (typeof member === "object") {
  417. apply(destination[prop], member, noOverwrite);
  418. }
  419. else if (!noOverwrite) {
  420. destination[prop] = source[prop];
  421. }
  422. }
  423. else {
  424. destination[prop] = source[prop];
  425. }
  426. }
  427. }
  428. return destination;
  429. }
  430. // This tests for the bug in IE where setting the [name] property using javascript causes the value to be redirected into [submitName].
  431. function testForNamePropertyBug(){
  432. var form = document.body.appendChild(document.createElement("form")), input = form.appendChild(document.createElement("input"));
  433. input.name = IFRAME_PREFIX + "TEST" + channelId; // append channelId in order to avoid caching issues
  434. HAS_NAME_PROPERTY_BUG = input !== form.elements[input.name];
  435. document.body.removeChild(form);
  436. _trace("HAS_NAME_PROPERTY_BUG: " + HAS_NAME_PROPERTY_BUG);
  437. }
  438. /**
  439. * Creates a frame and appends it to the DOM.
  440. * @param config {object} This object can have the following properties
  441. * <ul>
  442. * <li> {object} prop The properties that should be set on the frame. This should include the 'src' property.</li>
  443. * <li> {object} attr The attributes that should be set on the frame.</li>
  444. * <li> {DOMElement} container Its parent element (Optional).</li>
  445. * <li> {function} onLoad A method that should be called with the frames contentWindow as argument when the frame is fully loaded. (Optional)</li>
  446. * </ul>
  447. * @return The frames DOMElement
  448. * @type DOMElement
  449. */
  450. function createFrame(config){
  451. _trace("creating frame: " + config.props.src);
  452. if (undef(HAS_NAME_PROPERTY_BUG)) {
  453. testForNamePropertyBug();
  454. }
  455. var frame;
  456. // This is to work around the problems in IE6/7 with setting the name property.
  457. // Internally this is set as 'submitName' instead when using 'iframe.name = ...'
  458. // This is not required by easyXDM itself, but is to facilitate other use cases
  459. if (HAS_NAME_PROPERTY_BUG) {
  460. frame = document.createElement("<iframe name=\"" + config.props.name + "\"/>");
  461. }
  462. else {
  463. frame = document.createElement("IFRAME");
  464. frame.name = config.props.name;
  465. }
  466. frame.id = frame.name = config.props.name;
  467. delete config.props.name;
  468. if (typeof config.container == "string") {
  469. config.container = document.getElementById(config.container);
  470. }
  471. if (!config.container) {
  472. // This needs to be hidden like this, simply setting display:none and the like will cause failures in some browsers.
  473. apply(frame.style, {
  474. position: "absolute",
  475. top: "-2000px",
  476. // Avoid potential horizontal scrollbar
  477. left: "0px"
  478. });
  479. config.container = document.body;
  480. }
  481. // HACK: IE cannot have the src attribute set when the frame is appended
  482. // into the container, so we set it to "javascript:false" as a
  483. // placeholder for now. If we left the src undefined, it would
  484. // instead default to "about:blank", which causes SSL mixed-content
  485. // warnings in IE6 when on an SSL parent page.
  486. var src = config.props.src;
  487. config.props.src = "javascript:false";
  488. // transfer properties to the frame
  489. apply(frame, config.props);
  490. frame.border = frame.frameBorder = 0;
  491. frame.allowTransparency = true;
  492. config.container.appendChild(frame);
  493. if (config.onLoad) {
  494. on(frame, "load", config.onLoad);
  495. }
  496. // set the frame URL to the proper value (we previously set it to
  497. // "javascript:false" to work around the IE issue mentioned above)
  498. if(config.usePost) {
  499. var form = config.container.appendChild(document.createElement('form')), input;
  500. form.target = frame.name;
  501. form.action = src;
  502. form.method = 'POST';
  503. if (typeof(config.usePost) === 'object') {
  504. for (var i in config.usePost) {
  505. if (config.usePost.hasOwnProperty(i)) {
  506. if (HAS_NAME_PROPERTY_BUG) {
  507. input = document.createElement('<input name="' + i + '"/>');
  508. } else {
  509. input = document.createElement("INPUT");
  510. input.name = i;
  511. }
  512. input.value = config.usePost[i];
  513. form.appendChild(input);
  514. }
  515. }
  516. }
  517. form.submit();
  518. form.parentNode.removeChild(form);
  519. } else {
  520. frame.src = src;
  521. }
  522. config.props.src = src;
  523. return frame;
  524. }
  525. /**
  526. * Check whether a domain is allowed using an Access Control List.
  527. * The ACL can contain * and ? as wildcards, or can be regular expressions.
  528. * If regular expressions they need to begin with ^ and end with $.
  529. * @param {Array/String} acl The list of allowed domains
  530. * @param {String} domain The domain to test.
  531. * @return {Boolean} True if the domain is allowed, false if not.
  532. */
  533. function checkAcl(acl, domain){
  534. // normalize into an array
  535. if (typeof acl == "string") {
  536. acl = [acl];
  537. }
  538. var re, i = acl.length;
  539. while (i--) {
  540. re = acl[i];
  541. re = new RegExp(re.substr(0, 1) == "^" ? re : ("^" + re.replace(/(\*)/g, ".$1").replace(/\?/g, ".") + "$"));
  542. if (re.test(domain)) {
  543. return true;
  544. }
  545. }
  546. return false;
  547. }
  548. /*
  549. * Functions related to stacks
  550. */
  551. /**
  552. * Prepares an array of stack-elements suitable for the current configuration
  553. * @param {Object} config The Transports configuration. See easyXDM.Socket for more.
  554. * @return {Array} An array of stack-elements with the TransportElement at index 0.
  555. */
  556. function prepareTransportStack(config){
  557. var protocol = config.protocol, stackEls;
  558. config.isHost = config.isHost || undef(query.xdm_p);
  559. useHash = config.hash || false;
  560. _trace("preparing transport stack");
  561. if (!config.props) {
  562. config.props = {};
  563. }
  564. if (!config.isHost) {
  565. _trace("using parameters from query");
  566. config.channel = query.xdm_c.replace(/["'<>\\]/g, "");
  567. config.secret = query.xdm_s;
  568. config.remote = query.xdm_e.replace(/["'<>\\]/g, "");
  569. ;
  570. protocol = query.xdm_p;
  571. if (config.acl && !checkAcl(config.acl, config.remote)) {
  572. throw new Error("Access denied for " + config.remote);
  573. }
  574. }
  575. else {
  576. config.remote = resolveUrl(config.remote);
  577. config.channel = config.channel || "default" + channelId++;
  578. config.secret = Math.random().toString(16).substring(2);
  579. if (undef(protocol)) {
  580. if (getLocation(location.href) == getLocation(config.remote)) {
  581. /*
  582. * Both documents has the same origin, lets use direct access.
  583. */
  584. protocol = "4";
  585. }
  586. else if (isHostMethod(window, "postMessage") || isHostMethod(document, "postMessage")) {
  587. /*
  588. * This is supported in IE8+, Firefox 3+, Opera 9+, Chrome 2+ and Safari 4+
  589. */
  590. protocol = "1";
  591. }
  592. else if (config.swf && isHostMethod(window, "ActiveXObject") && hasFlash()) {
  593. /*
  594. * The Flash transport superseedes the NixTransport as the NixTransport has been blocked by MS
  595. */
  596. protocol = "6";
  597. }
  598. else if (navigator.product === "Gecko" && "frameElement" in window && navigator.userAgent.indexOf('WebKit') == -1) {
  599. /*
  600. * This is supported in Gecko (Firefox 1+)
  601. */
  602. protocol = "5";
  603. }
  604. else if (config.remoteHelper) {
  605. /*
  606. * This is supported in all browsers that retains the value of window.name when
  607. * navigating from one domain to another, and where parent.frames[foo] can be used
  608. * to get access to a frame from the same domain
  609. */
  610. protocol = "2";
  611. }
  612. else {
  613. /*
  614. * This is supported in all browsers where [window].location is writable for all
  615. * The resize event will be used if resize is supported and the iframe is not put
  616. * into a container, else polling will be used.
  617. */
  618. protocol = "0";
  619. }
  620. _trace("selecting protocol: " + protocol);
  621. }
  622. else {
  623. _trace("using protocol: " + protocol);
  624. }
  625. }
  626. config.protocol = protocol; // for conditional branching
  627. switch (protocol) {
  628. case "0":// 0 = HashTransport
  629. apply(config, {
  630. interval: 100,
  631. delay: 2000,
  632. useResize: true,
  633. useParent: false,
  634. usePolling: false
  635. }, true);
  636. if (config.isHost) {
  637. if (!config.local) {
  638. _trace("looking for image to use as local");
  639. // If no local is set then we need to find an image hosted on the current domain
  640. var domain = location.protocol + "//" + location.host, images = document.body.getElementsByTagName("img"), image;
  641. var i = images.length;
  642. while (i--) {
  643. image = images[i];
  644. if (image.src.substring(0, domain.length) === domain) {
  645. config.local = image.src;
  646. break;
  647. }
  648. }
  649. if (!config.local) {
  650. _trace("no image found, defaulting to using the window");
  651. // If no local was set, and we are unable to find a suitable file, then we resort to using the current window
  652. config.local = window;
  653. }
  654. }
  655. var parameters = {
  656. xdm_c: config.channel,
  657. xdm_p: 0
  658. };
  659. if (config.local === window) {
  660. // We are using the current window to listen to
  661. config.usePolling = true;
  662. config.useParent = true;
  663. config.local = location.protocol + "//" + location.host + location.pathname + location.search;
  664. parameters.xdm_e = config.local;
  665. parameters.xdm_pa = 1; // use parent
  666. }
  667. else {
  668. parameters.xdm_e = resolveUrl(config.local);
  669. }
  670. if (config.container) {
  671. config.useResize = false;
  672. parameters.xdm_po = 1; // use polling
  673. }
  674. config.remote = appendQueryParameters(config.remote, parameters);
  675. }
  676. else {
  677. apply(config, {
  678. channel: query.xdm_c,
  679. remote: query.xdm_e,
  680. useParent: !undef(query.xdm_pa),
  681. usePolling: !undef(query.xdm_po),
  682. useResize: config.useParent ? false : config.useResize
  683. });
  684. }
  685. stackEls = [new easyXDM.stack.HashTransport(config), new easyXDM.stack.ReliableBehavior({}), new easyXDM.stack.QueueBehavior({
  686. encode: true,
  687. maxLength: 4000 - config.remote.length
  688. }), new easyXDM.stack.VerifyBehavior({
  689. initiate: config.isHost
  690. })];
  691. break;
  692. case "1":
  693. stackEls = [new easyXDM.stack.PostMessageTransport(config)];
  694. break;
  695. case "2":
  696. if (config.isHost) {
  697. config.remoteHelper = resolveUrl(config.remoteHelper);
  698. }
  699. stackEls = [new easyXDM.stack.NameTransport(config), new easyXDM.stack.QueueBehavior(), new easyXDM.stack.VerifyBehavior({
  700. initiate: config.isHost
  701. })];
  702. break;
  703. case "3":
  704. stackEls = [new easyXDM.stack.NixTransport(config)];
  705. break;
  706. case "4":
  707. stackEls = [new easyXDM.stack.SameOriginTransport(config)];
  708. break;
  709. case "5":
  710. stackEls = [new easyXDM.stack.FrameElementTransport(config)];
  711. break;
  712. case "6":
  713. if (!flashVersion) {
  714. hasFlash();
  715. }
  716. stackEls = [new easyXDM.stack.FlashTransport(config)];
  717. break;
  718. }
  719. // this behavior is responsible for buffering outgoing messages, and for performing lazy initialization
  720. stackEls.push(new easyXDM.stack.QueueBehavior({
  721. lazy: config.lazy,
  722. remove: true
  723. }));
  724. return stackEls;
  725. }
  726. /**
  727. * Chains all the separate stack elements into a single usable stack.<br/>
  728. * If an element is missing a necessary method then it will have a pass-through method applied.
  729. * @param {Array} stackElements An array of stack elements to be linked.
  730. * @return {easyXDM.stack.StackElement} The last element in the chain.
  731. */
  732. function chainStack(stackElements){
  733. var stackEl, defaults = {
  734. incoming: function(message, origin){
  735. this.up.incoming(message, origin);
  736. },
  737. outgoing: function(message, recipient){
  738. this.down.outgoing(message, recipient);
  739. },
  740. callback: function(success){
  741. this.up.callback(success);
  742. },
  743. init: function(){
  744. this.down.init();
  745. },
  746. destroy: function(){
  747. this.down.destroy();
  748. }
  749. };
  750. for (var i = 0, len = stackElements.length; i < len; i++) {
  751. stackEl = stackElements[i];
  752. apply(stackEl, defaults, true);
  753. if (i !== 0) {
  754. stackEl.down = stackElements[i - 1];
  755. }
  756. if (i !== len - 1) {
  757. stackEl.up = stackElements[i + 1];
  758. }
  759. }
  760. return stackEl;
  761. }
  762. /**
  763. * This will remove a stackelement from its stack while leaving the stack functional.
  764. * @param {Object} element The elment to remove from the stack.
  765. */
  766. function removeFromStack(element){
  767. element.up.down = element.down;
  768. element.down.up = element.up;
  769. element.up = element.down = null;
  770. }
  771. /*
  772. * Export the main object and any other methods applicable
  773. */
  774. /**
  775. * @class easyXDM
  776. * A javascript library providing cross-browser, cross-domain messaging/RPC.
  777. * @version 2.4.18.25
  778. * @singleton
  779. */
  780. apply(easyXDM, {
  781. /**
  782. * The version of the library
  783. * @type {string}
  784. */
  785. version: "2.4.18.25",
  786. /**
  787. * This is a map containing all the query parameters passed to the document.
  788. * All the values has been decoded using decodeURIComponent.
  789. * @type {object}
  790. */
  791. query: query,
  792. /**
  793. * @private
  794. */
  795. stack: {},
  796. /**
  797. * Applies properties from the source object to the target object.<br/>
  798. * @param {object} target The target of the properties.
  799. * @param {object} source The source of the properties.
  800. * @param {boolean} noOverwrite Set to True to only set non-existing properties.
  801. */
  802. apply: apply,
  803. /**
  804. * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.
  805. * @return {JSON} A valid JSON conforming object, or null if not found.
  806. */
  807. getJSONObject: getJSON,
  808. /**
  809. * This will add a function to the queue of functions to be run once the DOM reaches a ready state.
  810. * If functions are added after this event then they will be executed immediately.
  811. * @param {function} fn The function to add
  812. * @param {object} scope An optional scope for the function to be called with.
  813. */
  814. whenReady: whenReady,
  815. /**
  816. * Removes easyXDM variable from the global scope. It also returns control
  817. * of the easyXDM variable to whatever code used it before.
  818. *
  819. * @param {String} ns A string representation of an object that will hold
  820. * an instance of easyXDM.
  821. * @return An instance of easyXDM
  822. */
  823. noConflict: noConflict
  824. });
  825. // Expose helper functions so we can test them
  826. apply(easyXDM, {
  827. checkAcl: checkAcl,
  828. getDomainName: getDomainName,
  829. getLocation: getLocation,
  830. appendQueryParameters: appendQueryParameters
  831. });
  832. /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
  833. /*global console, _FirebugCommandLine, easyXDM, window, escape, unescape, isHostObject, undef, _trace, domIsReady, emptyFn, namespace */
  834. //
  835. // easyXDM
  836. // http://easyxdm.net/
  837. // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
  838. //
  839. // Permission is hereby granted, free of charge, to any person obtaining a copy
  840. // of this software and associated documentation files (the "Software"), to deal
  841. // in the Software without restriction, including without limitation the rights
  842. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  843. // copies of the Software, and to permit persons to whom the Software is
  844. // furnished to do so, subject to the following conditions:
  845. //
  846. // The above copyright notice and this permission notice shall be included in
  847. // all copies or substantial portions of the Software.
  848. //
  849. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  850. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  851. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  852. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  853. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  854. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  855. // THE SOFTWARE.
  856. //
  857. var debug = {
  858. _deferred: [],
  859. flush: function(){
  860. this.trace("... deferred messages ...");
  861. for (var i = 0, len = this._deferred.length; i < len; i++) {
  862. this.trace(this._deferred[i]);
  863. }
  864. this._deferred.length = 0;
  865. this.trace("... end of deferred messages ...");
  866. },
  867. getTime: function(){
  868. var d = new Date(), h = d.getHours() + "", m = d.getMinutes() + "", s = d.getSeconds() + "", ms = d.getMilliseconds() + "", zeros = "000";
  869. if (h.length == 1) {
  870. h = "0" + h;
  871. }
  872. if (m.length == 1) {
  873. m = "0" + m;
  874. }
  875. if (s.length == 1) {
  876. s = "0" + s;
  877. }
  878. ms = zeros.substring(ms.length) + ms;
  879. return h + ":" + m + ":" + s + "." + ms;
  880. },
  881. /**
  882. * Logs the message to console.log if available
  883. * @param {String} msg The message to log
  884. */
  885. log: function(msg){
  886. // Uses memoizing to cache the implementation
  887. if (!isHostObject(window, "console") || undef(console.log)) {
  888. /**
  889. * Sets log to be an empty function since we have no output available
  890. * @ignore
  891. */
  892. this.log = emptyFn;
  893. }
  894. else {
  895. /**
  896. * Sets log to be a wrapper around console.log
  897. * @ignore
  898. * @param {String} msg
  899. */
  900. this.log = function(msg){
  901. console.log(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ": " + msg);
  902. };
  903. }
  904. this.log(msg);
  905. },
  906. /**
  907. * Will try to trace the given message either to a DOMElement with the id "log",
  908. * or by using console.info.
  909. * @param {String} msg The message to trace
  910. */
  911. trace: function(msg){
  912. // Uses memoizing to cache the implementation
  913. if (!domIsReady) {
  914. if (this._deferred.length === 0) {
  915. easyXDM.whenReady(debug.flush, debug);
  916. }
  917. this._deferred.push(msg);
  918. this.log(msg);
  919. }
  920. else {
  921. var el = document.getElementById("log");
  922. // is there a log element present?
  923. if (el) {
  924. /**
  925. * Sets trace to be a function that outputs the messages to the DOMElement with id "log"
  926. * @ignore
  927. * @param {String} msg
  928. */
  929. this.trace = function(msg){
  930. try {
  931. el.appendChild(document.createElement("div")).appendChild(document.createTextNode(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg));
  932. el.scrollTop = el.scrollHeight;
  933. }
  934. catch (e) {
  935. //In case we are unloading
  936. }
  937. };
  938. }
  939. else if (isHostObject(window, "console") && !undef(console.info)) {
  940. /**
  941. * Sets trace to be a wrapper around console.info
  942. * @ignore
  943. * @param {String} msg
  944. */
  945. this.trace = function(msg){
  946. console.info(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg);
  947. };
  948. }
  949. else {
  950. /**
  951. * Create log window
  952. * @ignore
  953. */
  954. var domain = location.host, windowname = domain.replace(/[\-.:]/g, "") + "easyxdm_log", logWin;
  955. try {
  956. logWin = window.open("", windowname, "width=800,height=200,status=0,navigation=0,scrollbars=1");
  957. }
  958. catch (e) {
  959. }
  960. if (logWin) {
  961. var doc = logWin.document;
  962. el = doc.getElementById("log");
  963. if (!el) {
  964. doc.write("<html><head><title>easyXDM log " + domain + "</title></head>");
  965. doc.write("<body><div id=\"log\"></div></body></html>");
  966. doc.close();
  967. el = doc.getElementById("log");
  968. }
  969. this.trace = function(msg){
  970. try {
  971. el.appendChild(doc.createElement("div")).appendChild(doc.createTextNode(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg));
  972. el.scrollTop = el.scrollHeight;
  973. }
  974. catch (e) {
  975. //In case we are unloading
  976. }
  977. };
  978. this.trace("---- new logger at " + location.href);
  979. }
  980. if (!el) {
  981. // We are unable to use any logging
  982. this.trace = emptyFn;
  983. }
  984. }
  985. this.trace(msg);
  986. }
  987. },
  988. /**
  989. * Creates a method usable for tracing.
  990. * @param {String} name The name the messages should be marked with
  991. * @return {Function} A function that accepts a single string as argument.
  992. */
  993. getTracer: function(name){
  994. return function(msg){
  995. debug.trace(name + ": " + msg);
  996. };
  997. }
  998. };
  999. debug.log("easyXDM present on '" + location.href);
  1000. easyXDM.Debug = debug;
  1001. _trace = debug.getTracer("{Private}");
  1002. /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
  1003. /*global easyXDM, window, escape, unescape, isHostObject, isHostMethod, un, on, createFrame, debug */
  1004. //
  1005. // easyXDM
  1006. // http://easyxdm.net/
  1007. // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
  1008. //
  1009. // Permission is hereby granted, free of charge, to any person obtaining a copy
  1010. // of this software and associated documentation files (the "Software"), to deal
  1011. // in the Software without restriction, including without limitation the rights
  1012. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  1013. // copies of the Software, and to permit persons to whom the Software is
  1014. // furnished to do so, subject to the following conditions:
  1015. //
  1016. // The above copyright notice and this permission notice shall be included in
  1017. // all copies or substantial portions of the Software.
  1018. //
  1019. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1020. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1021. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1022. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  1023. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  1024. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  1025. // THE SOFTWARE.
  1026. //
  1027. /**
  1028. * @class easyXDM.DomHelper
  1029. * Contains methods for dealing with the DOM
  1030. * @singleton
  1031. */
  1032. easyXDM.DomHelper = {
  1033. /**
  1034. * Provides a consistent interface for adding eventhandlers
  1035. * @param {Object} target The target to add the event to
  1036. * @param {String} type The name of the event
  1037. * @param {Function} listener The listener
  1038. */
  1039. on: on,
  1040. /**
  1041. * Provides a consistent interface for removing eventhandlers
  1042. * @param {Object} target The target to remove the event from
  1043. * @param {String} type The name of the event
  1044. * @param {Function} listener The listener
  1045. */
  1046. un: un,
  1047. /**
  1048. * Checks for the presence of the JSON object.
  1049. * If it is not present it will use the supplied path to load the JSON2 library.
  1050. * This should be called in the documents head right after the easyXDM script tag.
  1051. * http://json.org/json2.js
  1052. * @param {String} path A valid path to json2.js
  1053. */
  1054. requiresJSON: function(path){
  1055. if (!isHostObject(window, "JSON")) {
  1056. debug.log("loading external JSON");
  1057. // we need to encode the < in order to avoid an illegal token error
  1058. // when the script is inlined in a document.
  1059. document.write('<' + 'script type="text/javascript" src="' + path + '"><' + '/script>');
  1060. }
  1061. else {
  1062. debug.log("native JSON found");
  1063. }
  1064. }
  1065. };
  1066. /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
  1067. /*global easyXDM, window, escape, unescape, debug */
  1068. //
  1069. // easyXDM
  1070. // http://easyxdm.net/
  1071. // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
  1072. //
  1073. // Permission is hereby granted, free of charge, to any person obtaining a copy
  1074. // of this software and associated documentation files (the "Software"), to deal
  1075. // in the Software without restriction, including without limitation the rights
  1076. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  1077. // copies of the Software, and to permit persons to whom the Software is
  1078. // furnished to do so, subject to the following conditions:
  1079. //
  1080. // The above copyright notice and this permission notice shall be included in
  1081. // all copies or substantial portions of the Software.
  1082. //
  1083. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1084. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1085. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1086. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  1087. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  1088. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  1089. // THE SOFTWARE.
  1090. //
  1091. (function(){
  1092. // The map containing the stored functions
  1093. var _map = {};
  1094. /**
  1095. * @class easyXDM.Fn
  1096. * This contains methods related to function handling, such as storing callbacks.
  1097. * @singleton
  1098. * @namespace easyXDM
  1099. */
  1100. easyXDM.Fn = {
  1101. /**
  1102. * Stores a function using the given name for reference
  1103. * @param {String} name The name that the function should be referred by
  1104. * @param {Function} fn The function to store
  1105. * @namespace easyXDM.fn
  1106. */
  1107. set: function(name, fn){
  1108. this._trace("storing function " + name);
  1109. _map[name] = fn;
  1110. },
  1111. /**
  1112. * Retrieves the function referred to by the given name
  1113. * @param {String} name The name of the function to retrieve
  1114. * @param {Boolean} del If the function should be deleted after retrieval
  1115. * @return {Function} The stored function
  1116. * @namespace easyXDM.fn
  1117. */
  1118. get: function(name, del){
  1119. this._trace("retrieving function " + name);
  1120. var fn = _map[name];
  1121. if (!fn) {
  1122. this._trace(name + " not found");
  1123. }
  1124. if (del) {
  1125. delete _map[name];
  1126. }
  1127. return fn;
  1128. }
  1129. };
  1130. easyXDM.Fn._trace = debug.getTracer("easyXDM.Fn");
  1131. }());
  1132. /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
  1133. /*global easyXDM, window, escape, unescape, chainStack, prepareTransportStack, getLocation, debug */
  1134. //
  1135. // easyXDM
  1136. // http://easyxdm.net/
  1137. // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
  1138. //
  1139. // Permission is hereby granted, free of charge, to any person obtaining a copy
  1140. // of this software and associated documentation files (the "Software"), to deal
  1141. // in the Software without restriction, including without limitation the rights
  1142. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  1143. // copies of the Software, and to permit persons to whom the Software is
  1144. // furnished to do so, subject to the following conditions:
  1145. //
  1146. // The above copyright notice and this permission notice shall be included in
  1147. // all copies or substantial portions of the Software.
  1148. //
  1149. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1150. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1151. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1152. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  1153. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  1154. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  1155. // THE SOFTWARE.
  1156. //
  1157. /**
  1158. * @class easyXDM.Socket
  1159. * This class creates a transport channel between two domains that is usable for sending and receiving string-based messages.<br/>
  1160. * The channel is reliable, supports queueing, and ensures that the message originates from the expected domain.<br/>
  1161. * Internally different stacks will be used depending on the browsers features and the available parameters.
  1162. * <h2>How to set up</h2>
  1163. * Setting up the provider:
  1164. * <pre><code>
  1165. * var socket = new easyXDM.Socket({
  1166. * &nbsp; local: "name.html",
  1167. * &nbsp; onReady: function(){
  1168. * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket
  1169. * &nbsp; &nbsp; socket.postMessage("foo-message");
  1170. * &nbsp; },
  1171. * &nbsp; onMessage: function(message, origin) {
  1172. * &nbsp;&nbsp; alert("received " + message + " from " + origin);
  1173. * &nbsp; }
  1174. * });
  1175. * </code></pre>
  1176. * Setting up the consumer:
  1177. * <pre><code>
  1178. * var socket = new easyXDM.Socket({
  1179. * &nbsp; remote: "http:&#47;&#47;remotedomain/page.html",
  1180. * &nbsp; remoteHelper: "http:&#47;&#47;remotedomain/name.html",
  1181. * &nbsp; onReady: function(){
  1182. * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket
  1183. * &nbsp; &nbsp; socket.postMessage("foo-message");
  1184. * &nbsp; },
  1185. * &nbsp; onMessage: function(message, origin) {
  1186. * &nbsp;&nbsp; alert("received " + message + " from " + origin);
  1187. * &nbsp; }
  1188. * });
  1189. * </code></pre>
  1190. * If you are unable to upload the <code>name.html</code> file to the consumers domain then remove the <code>remoteHelper</code> property
  1191. * and easyXDM will fall back to using the HashTransport instead of the NameTransport when not able to use any of the primary transports.
  1192. * @namespace easyXDM
  1193. * @constructor
  1194. * @cfg {String/Window} local The url to the local name.html document, a local static file, or a reference to the local window.
  1195. * @cfg {Boolean} lazy (Consumer only) Set this to true if you want easyXDM to defer creating the transport until really needed.
  1196. * @cfg {String} remote (Consumer only) The url to the providers document.
  1197. * @cfg {String} remoteHelper (Consumer only) The url to the remote name.html file. This is to support NameTransport as a fallback. Optional.
  1198. * @cfg {Number} delay The number of milliseconds easyXDM should try to get a reference to the local window. Optional, defaults to 2000.
  1199. * @cfg {Number} interval The interval used when polling for messages. Optional, defaults to 300.
  1200. * @cfg {String} channel (Consumer only) The name of the channel to use. Can be used to set consistent iframe names. Must be unique. Optional.
  1201. * @cfg {Function} onMessage The method that should handle incoming messages.<br/> This method should accept two arguments, the message as a string, and the origin as a string. Optional.
  1202. * @cfg {Function} onReady A method that should be called when the transport is ready. Optional.
  1203. * @cfg {DOMElement|String} container (Consumer only) The element, or the id of the element that the primary iframe should be inserted into. If not set then the iframe will be positioned off-screen. Optional.
  1204. * @cfg {Array/String} acl (Provider only) Here you can specify which '[protocol]://[domain]' patterns that should be allowed to act as the consumer towards this provider.<br/>
  1205. * This can contain the wildcards ? and *. Examples are 'http://example.com', '*.foo.com' and '*dom?.com'. If you want to use reqular expressions then you pattern needs to start with ^ and end with $.
  1206. * If none of the patterns match an Error will be thrown.
  1207. * @cfg {Object} props (Consumer only) Additional properties that should be applied to the iframe. This can also contain nested objects e.g: <code>{style:{width:"100px", height:"100px"}}</code>.
  1208. * Properties such as 'name' and 'src' will be overrided. Optional.
  1209. */
  1210. easyXDM.Socket = function(config){
  1211. var trace = debug.getTracer("easyXDM.Socket");
  1212. trace("constructor");
  1213. // create the stack
  1214. var stack = chainStack(prepareTransportStack(config).concat([{
  1215. incoming: function(message, origin){
  1216. config.onMessage(message, origin);
  1217. },
  1218. callback: function(success){
  1219. if (config.onReady) {
  1220. config.onReady(success);
  1221. }
  1222. }
  1223. }])), recipient = getLocation(config.remote);
  1224. // set the origin
  1225. this.origin = getLocation(config.remot