UNPKG

chronosjs

Version:

JS Channels Mechanism

375 lines (326 loc) 12.8 kB
;(function (root, chronosRoot, factory) { "use strict"; /* istanbul ignore if */ //<amd> if ("function" === typeof define && define.amd) { // AMD. Register as an anonymous module. define("Chronos.PostMessageUtilities", [], function () { return factory(root, chronosRoot, true); }); return; } //</amd> /* istanbul ignore next */ if ("object" !== typeof exports) { chronosRoot.Chronos = chronosRoot.Chronos || {}; factory(root, chronosRoot.Chronos); } }(this, typeof ChronosRoot === "undefined" ? this : ChronosRoot, function (root, exports, hide) { "use strict"; var SEQUENCE_FORMAT = "_xxxxxx-4xxx-yxxx"; /** * This function was added because of incompatibility between the JSON.stringify and Prototype.js library * When a customer uses Prototype.js library, It overrides the Array.prototype.toJSON function of the native JSON * uses. This causes arrays to be double quoted and Shark to fail on those SDEs. * The function accepts a value and uses the native JSON.stringify * Can throw an exception (same as JSON.stringify). * @returns {String} the strigified object */ function stringify() { var stringified; var toJSONPrototype; if ("function" === typeof Array.prototype.toJSON) { toJSONPrototype = Array.prototype.toJSON; Array.prototype.toJSON = void 0; try { stringified = JSON.stringify.apply(null, arguments); } catch (ex) { /* istanbul ignore next */ Array.prototype.toJSON = toJSONPrototype; /* istanbul ignore next */ throw ex; } Array.prototype.toJSON = toJSONPrototype; } else { stringified = JSON.stringify.apply(null, arguments); } return stringified; } /** * Method to identify whether the browser supports passing object references to postMessage API * @returns {Boolean} whether the browser supports passing object references to postMessage API */ function hasPostMessageObjectsSupport() { var hasObjectsSupport = true; try { root.postMessage({ toString:function() { hasObjectsSupport = false; } }, "*"); } catch (ex) { // Browsers which has postMessage Objects support sends messages using // the structured clone algorithm - https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm // In which Error and Function objects cannot be duplicated by the structured clone algorithm; attempting to do so will throw a DATA_CLONE_ERR exception. if (ex && 'DataCloneError' !== ex.name) { hasObjectsSupport = false; } } return hasObjectsSupport; } /** * Method to create a unique sequence * @param {String} format - the format for the unique name eg. xxxxx-xx4xxx-yxxxx * @returns {String} the unique iFrame name */ function createUniqueSequence(format) { return format && format.replace(/[xy]/g, function(chr) { var rnd = Math.random() * 16 | 0; var val = chr === "x" ? rnd : (rnd & 0x3 | 0x8); return val.toString(16); }); } /** * Method to validate and parse an input number * @param {Number} input - the input value to parse * @param {Number} defaultValue - the default value to return in case of invalid input * @returns {Number} the number to return */ function parseNumber(input, defaultValue) { return !isNaN(input) && 0 < input ? parseInt(input, 10) : defaultValue; } /** * Method to validate and parse a function reference * @param {Function} input - the input value to parse * @param {Function|Boolean} defaultValue - the default value to return in case of invalid input or true for empty function * @returns {Function} the function to return */ function parseFunction(input, defaultValue) { return (("function" === typeof input) ? input : (true === defaultValue ? function() {} : defaultValue)); } /** * Function to extract the host domain from any URL * @param {String} url - the url to resolve the host for * @param {Object} [win] - the window to resolve the host for * @param {Boolean} [top] - boolean indication for using helper of the top window if needed * @returns {String} the host */ function getHost(url, win, top) { var domainRegEx = new RegExp(/(http{1}s{0,1}?:\/\/)([^\/\?]+)(\/?)/ig); var matches; var domain; var frame; if (url && 0 === url.indexOf("http")) { matches = domainRegEx.exec(url); } else { // This is a partial url so we assume it's relative, this is mainly nice for tests frame = top ? (win.top || (win.contentWindow && win.contentWindow.parent) || window) : win; return frame.location.protocol + "//" + frame.location.host; } if (matches && 3 <= matches.length && "" !== matches[2]) { domain = matches[1].toLowerCase() + matches[2].toLowerCase(); // 0 - full match 1- HTTPS 2- domain } return domain; } /** * Method to resolve the needed origin parameters from url * @param {String} [hostParam] - string to represent the name of the host parameter in querystring * @param {String} [url] - string to represent the url to resolve parameters from * @returns {String} the parameter from the url */ function resolveParameters(hostParam, url) { var param; var value = getURLParameter("lpHost", url); if (!value) { param = getURLParameter("hostParam", url) || hostParam; if (param) { value = getURLParameter(param, url); } } return value; } /** * Method to resolve the needed origin * @param {Object} [target] - the target to resolve the host for * @param {Boolean} [top] - boolean indication for using helper of the top window if needed * @param {String} [hostParam] - string to represent the name of the host parameter in querystring * @returns {String} the origin for the target */ function resolveOrigin(target, top, hostParam) { var origin; var url; var ref; try { url = target && target.contentWindow && "undefined" !== typeof Window && !(target instanceof Window) && target.getAttribute && target.getAttribute("src"); } catch(ex) {} try { if (!url) { url = resolveParameters(hostParam); } if (!url) { url = document.referrer; ref = true; } if (url) { url = decodeURIComponent(url); if (ref) { url = resolveParameters(hostParam, url); } } origin = getHost(url, target, top); } catch(ex) { log("Cannot parse origin", "ERROR", "PostMessageUtilities"); } return origin || "*"; } /** * Method to retrieve a url parameter from querystring by name * @param {String} name - the name of the parameter * @param {String} [url] - optional url to parse * @returns {String} the url parameter value */ function getURLParameter(name, url) { return decodeURIComponent((new RegExp("[?|&]" + name + "=" + "([^&;]+?)(&|#|;|$)").exec(url || document.location.search) || [void 0, ""])[1].replace(/\+/g, "%20")) || null; } /** * Method to delay a message execution (async) * @param {Function} method - the function to delay * @param {Number} [milliseconds] - optional milliseconds to delay or false to run immediately */ function delay(method, milliseconds) { var timer; /* istanbul ignore if */ if ("undefined" !== typeof setImmediate && (isNaN(milliseconds) || 0 >= milliseconds)) { timer = setImmediate(method); } else if (false === milliseconds) { method(); } else { timer = setTimeout(method, (isNaN(milliseconds) || 0 >= milliseconds) ? 0 : parseInt(milliseconds, 10)); } return function() { clearDelay(timer); }; } /** * Method to clear the delay of a message execution (async) * @param {Number} id - the id of the timer to clear */ function clearDelay(timer) { var timerId = parseNumber(timer); if (timerId) { /* istanbul ignore if */ if ("undefined" !== typeof clearImmediate) { clearImmediate(timerId); } else { clearTimeout(timerId); } } } /** * Method to add DOM events listener to an element * @param {Object} element - the element we're binding to * @param {String} event - the event we want to bind * @param {Function} callback - the function to execute */ function addEventListener(element, event, callback) { /* istanbul ignore else: IE9- only */ if (element.addEventListener) { element.addEventListener(event, callback, false); } else { element.attachEvent("on" + event, callback); } return function() { removeEventListener(element, event, callback); }; } /** * Method to add DOM events listener to an element * @param {Object} element - the element we're binding to * @param {String} event - the event we want to bind * @param {Function} callback - the function to execute */ function removeEventListener(element, event, callback) { /* istanbul ignore else: IE9- only */ if (element.removeEventListener) { element.removeEventListener(event, callback, false); } else { element.detachEvent("on" + event, callback); } } /** * Method to implement a simple logging based on lptag * @param {String} msg - the message to log * @param {String} level - the logging level of the message * @param {String} app - the app which logs */ /* istanbul ignore next */ function log(msg, level, app) { if (root && "function" === typeof root.log) { root.log(msg, level, app); } } /** * Method to polyfill bind native functionality in case it does not exist * Based on implementation from: * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind * @param {Object} object - the object to bind to * @returns {Function} the bound function */ /* istanbul ignore next */ function bind(object) { /*jshint validthis:true */ var args; var fn; if ("function" !== typeof this) { // Closest thing possible to the ECMAScript 5 // Internal IsCallable function throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } args = Array.prototype.slice.call(arguments, 1); fn = this; function Empty() {} function bound() { return fn.apply(this instanceof Empty && object ? this : object, args.concat(Array.prototype.slice.call(arguments))); } Empty.prototype = this.prototype; bound.prototype = new Empty(); return bound; } /* istanbul ignore if */ if (!Function.prototype.bind) { Function.prototype.bind = bind; } // attach properties to the exports object to define // the exported module properties. var ret = { SEQUENCE_FORMAT: SEQUENCE_FORMAT, stringify: stringify, hasPostMessageObjectsSupport: hasPostMessageObjectsSupport, createUniqueSequence: createUniqueSequence, parseNumber: parseNumber, parseFunction: parseFunction, getHost: getHost, resolveOrigin: resolveOrigin, getURLParameter: getURLParameter, delay: delay, addEventListener: addEventListener, removeEventListener: removeEventListener, log: log, bind: bind }; if (!hide) { exports.PostMessageUtilities = exports.PostMessageUtilities || ret; } return ret; }));