From 078703b84078d200ac11f4ecf20e1450feab075c Mon Sep 17 00:00:00 2001 From: hassanelnajjar Date: Sat, 12 Jun 2021 23:51:48 +0300 Subject: [PATCH 1/6] search for http: and check the url using chrome and then chang the secure url to https relates #73 --- CONTRIBUTING.md | 4 +- js/pym.js | 1214 ++++++++++++++++++++++++----------------------- license.txt | 2 +- 3 files changed, 626 insertions(+), 594 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 68ede44..e0d68dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ We welcome contributions and suggestions to help us improve this project. Please 4. Push the changes to your fork (git push origin my-branch) 5. [Submit a pull request to the parent repo](https://help.github.com/articles/creating-a-pull-request). Please read our [guide to submitting pull requests](https://github.com/inn/docs/blob/master/how-to-work-with-us/pull-requests.md) to see what we expect in a good pull request message. 6. Pull request should be assigned to: - - [@benlk](http://github.com/benlk) (primary) + - [@benlk](https://github.com/benlk) (primary) We have [a helpful how-to](https://github.com/INN/docs/blob/master/how-to-work-with-us/via-github.md) that walks through this process in more detail if you're new to using Git. @@ -21,5 +21,5 @@ And of course you can always email us: [support@inn.org](mailto:support@inn.org) ### Standards - Follow all standards from the INN Labs [coding style guide](https://github.com/INN/docs/tree/master/style-guides/code). -- Use [markdown syntax](http://daringfireball.net/projects/markdown/syntax) for all text documents. +- Use [markdown syntax](https://daringfireball.net/projects/markdown/syntax) for all text documents. - Pull requests for new functionality should be accompanied by tests wherever possible. diff --git a/js/pym.js b/js/pym.js index 7aa2dda..6cbc3e2 100644 --- a/js/pym.js +++ b/js/pym.js @@ -1,596 +1,628 @@ /* -* Pym.js is library that resizes an iframe based on the width of the parent and the resulting height of the child. -* Check out the docs at http://blog.apps.npr.org/pym.js/ or the readme at README.md for usage. -*/ + * Pym.js is library that resizes an iframe based on the width of the parent and the resulting height of the child. + * Check out the docs at http://blog.apps.npr.org/pym.js/ or the readme at README.md for usage. + */ /* global module */ -(function(factory) { - if (typeof define === 'function' && define.amd) { - define(factory); - } else if (typeof module !== 'undefined' && module.exports) { - module.exports = factory(); - } else { - window.pym = factory.call(this); - } -})(function() { - var MESSAGE_DELIMITER = 'xPYMx'; - - var lib = {}; - - /** - * Generic function for parsing URL params. - * Via http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript - * - * @method _getParameterByName - * @param {String} name The name of the paramter to get from the URL. - */ - var _getParameterByName = function(name) { - var regex = new RegExp("[\\?&]" + name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]') + '=([^&#]*)'); - var results = regex.exec(location.search); - - if (results === null) { - return ''; - } - - return decodeURIComponent(results[1].replace(/\+/g, " ")); - }; - - /** - * Check the message to make sure it comes from an acceptable xdomain. - * Defaults to '*' but can be overriden in config. - * - * @method _isSafeMessage - * @param {Event} e The message event. - * @param {Object} settings Configuration. - */ - var _isSafeMessage = function(e, settings) { - if (settings.xdomain !== '*') { - // If origin doesn't match our xdomain, return. - if (!e.origin.match(new RegExp(settings.xdomain + '$'))) { return; } - } - - return true; - }; - - /** - * Construct a message to send between frames. - * - * NB: We use string-building here because JSON message passing is - * not supported in all browsers. - * - * @method _makeMessage - * @param {String} id The unique id of the message recipient. - * @param {String} messageType The type of message to send. - * @param {String} message The message to send. - */ - var _makeMessage = function(id, messageType, message) { - var bits = ['pym', id, messageType, message]; - - return bits.join(MESSAGE_DELIMITER); - }; - - /** - * Construct a regex to validate and parse messages. - * - * @method _makeMessageRegex - * @param {String} id The unique id of the message recipient. - */ - var _makeMessageRegex = function(id) { - var bits = ['pym', id, '(\\S+)', '(.+)']; - - return new RegExp('^' + bits.join(MESSAGE_DELIMITER) + '$'); - }; - - /** - * Initialize Pym for elements on page that have data-pym attributes. - * - * @method _autoInit - */ - var _autoInit = function() { - var elements = document.querySelectorAll( - '[data-pym-src]:not([data-pym-auto-initialized])' - ); - - var length = elements.length; - - for (var idx = 0; idx < length; ++idx) { - var element = elements[idx]; - - /* - * Mark automatically-initialized elements so they are not - * re-initialized if the user includes pym.js more than once in the - * same document. - */ - element.setAttribute('data-pym-auto-initialized', ''); - - // Ensure elements have an id - if (element.id === '') { - element.id = 'pym-' + idx; - } - - var src = element.getAttribute('data-pym-src'); - var xdomain = element.getAttribute('data-pym-xdomain'); - var config = {}; - - if (xdomain) { - config.xdomain = xdomain; - } - - new lib.Parent(element.id, src, config); - } - }; - - /** - * The Parent half of a response iframe. - * - * @class Parent - * @param {String} id The id of the div into which the iframe will be rendered. - * @param {String} url The url of the iframe source. - * @param {Object} config Configuration to override the default settings. - */ - lib.Parent = function(id, url, config) { - this.id = id; - this.url = url; - this.el = document.getElementById(id); - this.iframe = null; - - this.settings = { - xdomain: '*' - }; - - this.messageRegex = _makeMessageRegex(this.id); - this.messageHandlers = {}; - - // ensure a config object - config = (config || {}); - - /** - * Construct the iframe. - * - * @memberof Parent.prototype - * @method _constructIframe - */ - this._constructIframe = function() { - // Calculate the width of this element. - var width = this.el.offsetWidth.toString(); - - // Create an iframe element attached to the document. - this.iframe = document.createElement('iframe'); - - // Save fragment id - var hash = ''; - var hashIndex = this.url.indexOf('#'); - - if (hashIndex > -1) { - hash = this.url.substring(hashIndex, this.url.length); - this.url = this.url.substring(0, hashIndex); - } - - // If the URL contains querystring bits, use them. - // Otherwise, just create a set of valid params. - if (this.url.indexOf('?') < 0) { - this.url += '?'; - } else { - this.url += '&'; - } - - // Append the initial width as a querystring parameter, and the fragment id - this.iframe.src = this.url + - 'initialWidth=' + width + - '&childId=' + this.id + - '&parentUrl=' + encodeURIComponent(window.location.href) + - hash; - - // Set some attributes to this proto-iframe. - this.iframe.setAttribute('width', '100%'); - this.iframe.setAttribute('scrolling', 'no'); - this.iframe.setAttribute('marginheight', '0'); - this.iframe.setAttribute('frameborder', '0'); - - if (this.settings.title) { - this.iframe.setAttribute('title', this.settings.title); - } - - // Append the iframe to our element. - this.el.appendChild(this.iframe); - - // Add an event listener that will handle redrawing the child on resize. - window.addEventListener('resize', this._onResize); - }; - - /** - * Send width on resize. - * - * @memberof Parent.prototype - * @method _onResize - */ - this._onResize = function() { - this.sendWidth(); - }.bind(this); - - /** - * Fire all event handlers for a given message type. - * - * @memberof Parent.prototype - * @method _fire - * @param {String} messageType The type of message. - * @param {String} message The message data. - */ - this._fire = function(messageType, message) { - if (messageType in this.messageHandlers) { - for (var i = 0; i < this.messageHandlers[messageType].length; i++) { - this.messageHandlers[messageType][i].call(this, message); - } - } - }; - - /** - * Remove this parent from the page and unbind it's event handlers. - * - * @memberof Parent.prototype - * @method remove - */ - this.remove = function() { - window.removeEventListener('message', this._processMessage); - window.removeEventListener('resize', this._onResize); - - this.el.removeChild(this.iframe); - }; - - /** - * @callback Parent~onMessageCallback - * @param {String} message The message data. - */ - - /** - * Process a new message from the child. - * - * @memberof Parent.prototype - * @method _processMessage - * @param {Event} e A message event. - */ - this._processMessage = function(e) { - // First, punt if this isn't from an acceptable xdomain. - if (!_isSafeMessage(e, this.settings)) { - return; - } - - // Discard object messages, we only care about strings - if (typeof e.data !== 'string') { - return; - } - - // Grab the message from the child and parse it. - var match = e.data.match(this.messageRegex); - - // If there's no match or too many matches in the message, punt. - if (!match || match.length !== 3) { - return false; - } - - var messageType = match[1]; - var message = match[2]; - - this._fire(messageType, message); - }.bind(this); - - /** - * Resize iframe in response to new height message from child. - * - * @memberof Parent.prototype - * @method _onHeightMessage - * @param {String} message The new height. - */ - this._onHeightMessage = function(message) { - /* - * Handle parent height message from child. - */ - var height = parseInt(message); - - this.iframe.setAttribute('height', height + 'px'); - }; - - /** - * Navigate parent to a new url. - * - * @memberof Parent.prototype - * @method _onNavigateToMessage - * @param {String} message The url to navigate to. - */ - this._onNavigateToMessage = function(message) { - /* - * Handle parent scroll message from child. - */ - document.location.href = message; - }; - - /** - * Bind a callback to a given messageType from the child. - * - * Reserved message names are: "height", "scrollTo" and "navigateTo". - * - * @memberof Parent.prototype - * @method onMessage - * @param {String} messageType The type of message being listened for. - * @param {Parent~onMessageCallback} callback The callback to invoke when a message of the given type is received. - */ - this.onMessage = function(messageType, callback) { - if (!(messageType in this.messageHandlers)) { - this.messageHandlers[messageType] = []; - } - - this.messageHandlers[messageType].push(callback); - }; - - /** - * Send a message to the the child. - * - * @memberof Parent.prototype - * @method sendMessage - * @param {String} messageType The type of message to send. - * @param {String} message The message data to send. - */ - this.sendMessage = function(messageType, message) { - this.el.getElementsByTagName('iframe')[0].contentWindow.postMessage(_makeMessage(this.id, messageType, message), '*'); - }; - - /** - * Transmit the current iframe width to the child. - * - * You shouldn't need to call this directly. - * - * @memberof Parent.prototype - * @method sendWidth - */ - this.sendWidth = function() { - var width = this.el.offsetWidth.toString(); - - this.sendMessage('width', width); - }; - - // Add any overrides to settings coming from config. - for (var key in config) { - this.settings[key] = config[key]; - } - - // Bind required message handlers - this.onMessage('height', this._onHeightMessage); - this.onMessage('navigateTo', this._onNavigateToMessage); - - // Add a listener for processing messages from the child. - window.addEventListener('message', this._processMessage, false); - - // Construct the iframe in the container element. - this._constructIframe(); - - return this; - }; - - /** - * The Child half of a responsive iframe. - * - * @class Child - * @param {Object} config Configuration to override the default settings. - */ - lib.Child = function(config) { - this.parentWidth = null; - this.id = null; - this.parentUrl = null; - - this.settings = { - renderCallback: null, - xdomain: '*', - polling: 0 - }; - - this.messageRegex = null; - this.messageHandlers = {}; - - // Ensure a config object - config = (config || {}); - - /** - * Bind a callback to a given messageType from the child. - * - * Reserved message names are: "width". - * - * @memberof Child.prototype - * @method onMessage - * @param {String} messageType The type of message being listened for. - * @param {Child~onMessageCallback} callback The callback to invoke when a message of the given type is received. - */ - this.onMessage = function(messageType, callback) { - if (!(messageType in this.messageHandlers)) { - this.messageHandlers[messageType] = []; - } - - this.messageHandlers[messageType].push(callback); - }; - - /** - * @callback Child~onMessageCallback - * @param {String} message The message data. - */ - - /** - * Fire all event handlers for a given message type. - * - * @memberof Parent.prototype - * @method _fire - * @param {String} messageType The type of message. - * @param {String} message The message data. - */ - this._fire = function(messageType, message) { - /* - * Fire all event handlers for a given message type. - */ - if (messageType in this.messageHandlers) { - for (var i = 0; i < this.messageHandlers[messageType].length; i++) { - this.messageHandlers[messageType][i].call(this, message); - } - } - }; - - /** - * Process a new message from the parent. - * - * @memberof Child.prototype - * @method _processMessage - * @param {Event} e A message event. - */ - this._processMessage = function(e) { - /* - * Process a new message from parent frame. - */ - // First, punt if this isn't from an acceptable xdomain. - if (!_isSafeMessage(e, this.settings)) { - return; - } - - // Discard object messages, we only care about strings - if (typeof e.data !== 'string') { - return; - } - - // Get the message from the parent. - var match = e.data.match(this.messageRegex); - - // If there's no match or it's a bad format, punt. - if (!match || match.length !== 3) { return; } - - var messageType = match[1]; - var message = match[2]; - - this._fire(messageType, message); - }.bind(this); - - /** - * Resize iframe in response to new width message from parent. - * - * @memberof Child.prototype - * @method _onWidthMessage - * @param {String} message The new width. - */ - this._onWidthMessage = function(message) { - /* - * Handle width message from the child. - */ - var width = parseInt(message); - - // Change the width if it's different. - if (width !== this.parentWidth) { - this.parentWidth = width; - - // Call the callback function if it exists. - if (this.settings.renderCallback) { - this.settings.renderCallback(width); - } - - // Send the height back to the parent. - this.sendHeight(); - } - }; - - /** - * Send a message to the the Parent. - * - * @memberof Child.prototype - * @method sendMessage - * @param {String} messageType The type of message to send. - * @param {String} message The message data to send. - */ - this.sendMessage = function(messageType, message) { - /* - * Send a message to the parent. - */ - window.parent.postMessage(_makeMessage(this.id, messageType, message), '*'); - }; - - /** - * Transmit the current iframe height to the parent. - * - * Call this directly in cases where you manually alter the height of the iframe contents. - * - * @memberof Child.prototype - * @method sendHeight - */ - this.sendHeight = function() { - // Get the child's height. - var height = document.getElementsByTagName('body')[0].offsetHeight.toString(); - - // Send the height to the parent. - this.sendMessage('height', height); - }.bind(this); - this.sendHeightToParent = function() { - // Get the child's height. - var height = document.getElementsByTagName('body')[0].offsetHeight.toString(); - - // Send the height to the parent. - this.sendMessage('height', height); - }.bind(this); - - /** - * Scroll parent to a given element id. - * - * @memberof Child.prototype - * @method scrollParentTo - * @param {String} hash The id of the element to scroll to. - */ - this.scrollParentTo = function(hash) { - this.sendMessage('navigateTo', '#' + hash); - }; - - /** - * Navigate parent to a given url. - * - * @memberof Parent.prototype - * @method navigateParentTo - * @param {String} url The url to navigate to. - */ - this.navigateParentTo = function(url) { - this.sendMessage('navigateTo', url); - }; - - // Identify what ID the parent knows this child as. - this.id = _getParameterByName('childId') || config.id; - this.messageRegex = new RegExp('^pym' + MESSAGE_DELIMITER + this.id + MESSAGE_DELIMITER + '(\\S+)' + MESSAGE_DELIMITER + '(.+)$'); - - // Get the initial width from a URL parameter. - var width = parseInt(_getParameterByName('initialWidth')); - - // Get the url of the parent frame - this.parentUrl = _getParameterByName('parentUrl'); - - // Bind the required message handlers - this.onMessage('width', this._onWidthMessage); - - // Initialize settings with overrides. - for (var key in config) { - this.settings[key] = config[key]; - } - - // Set up a listener to handle any incoming messages. - window.addEventListener('message', this._processMessage, false); - - // If there's a callback function, call it. - if (this.settings.renderCallback) { - this.settings.renderCallback(width); - } - - // Send the initial height to the parent. - this.sendHeight(); - - // If we're configured to poll, create a setInterval to handle that. - if (this.settings.polling) { - window.setInterval(this.sendHeight, this.settings.polling); - } - - return this; - }; - - // Initialize elements with pym data attributes - _autoInit(); - - return lib; +(function (factory) { + if (typeof define === 'function' && define.amd) { + define(factory); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = factory(); + } else { + window.pym = factory.call(this); + } +})(function () { + var MESSAGE_DELIMITER = 'xPYMx'; + + var lib = {}; + + /** + * Generic function for parsing URL params. + * Via https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript + * + * @method _getParameterByName + * @param {String} name The name of the paramter to get from the URL. + */ + var _getParameterByName = function (name) { + var regex = new RegExp( + '[\\?&]' + + name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]') + + '=([^&#]*)' + ); + var results = regex.exec(location.search); + + if (results === null) { + return ''; + } + + return decodeURIComponent(results[1].replace(/\+/g, ' ')); + }; + + /** + * Check the message to make sure it comes from an acceptable xdomain. + * Defaults to '*' but can be overriden in config. + * + * @method _isSafeMessage + * @param {Event} e The message event. + * @param {Object} settings Configuration. + */ + var _isSafeMessage = function (e, settings) { + if (settings.xdomain !== '*') { + // If origin doesn't match our xdomain, return. + if (!e.origin.match(new RegExp(settings.xdomain + '$'))) { + return; + } + } + + return true; + }; + + /** + * Construct a message to send between frames. + * + * NB: We use string-building here because JSON message passing is + * not supported in all browsers. + * + * @method _makeMessage + * @param {String} id The unique id of the message recipient. + * @param {String} messageType The type of message to send. + * @param {String} message The message to send. + */ + var _makeMessage = function (id, messageType, message) { + var bits = ['pym', id, messageType, message]; + + return bits.join(MESSAGE_DELIMITER); + }; + + /** + * Construct a regex to validate and parse messages. + * + * @method _makeMessageRegex + * @param {String} id The unique id of the message recipient. + */ + var _makeMessageRegex = function (id) { + var bits = ['pym', id, '(\\S+)', '(.+)']; + + return new RegExp('^' + bits.join(MESSAGE_DELIMITER) + '$'); + }; + + /** + * Initialize Pym for elements on page that have data-pym attributes. + * + * @method _autoInit + */ + var _autoInit = function () { + var elements = document.querySelectorAll( + '[data-pym-src]:not([data-pym-auto-initialized])' + ); + + var length = elements.length; + + for (var idx = 0; idx < length; ++idx) { + var element = elements[idx]; + + /* + * Mark automatically-initialized elements so they are not + * re-initialized if the user includes pym.js more than once in the + * same document. + */ + element.setAttribute('data-pym-auto-initialized', ''); + + // Ensure elements have an id + if (element.id === '') { + element.id = 'pym-' + idx; + } + + var src = element.getAttribute('data-pym-src'); + var xdomain = element.getAttribute('data-pym-xdomain'); + var config = {}; + + if (xdomain) { + config.xdomain = xdomain; + } + + new lib.Parent(element.id, src, config); + } + }; + + /** + * The Parent half of a response iframe. + * + * @class Parent + * @param {String} id The id of the div into which the iframe will be rendered. + * @param {String} url The url of the iframe source. + * @param {Object} config Configuration to override the default settings. + */ + lib.Parent = function (id, url, config) { + this.id = id; + this.url = url; + this.el = document.getElementById(id); + this.iframe = null; + + this.settings = { + xdomain: '*', + }; + + this.messageRegex = _makeMessageRegex(this.id); + this.messageHandlers = {}; + + // ensure a config object + config = config || {}; + + /** + * Construct the iframe. + * + * @memberof Parent.prototype + * @method _constructIframe + */ + this._constructIframe = function () { + // Calculate the width of this element. + var width = this.el.offsetWidth.toString(); + + // Create an iframe element attached to the document. + this.iframe = document.createElement('iframe'); + + // Save fragment id + var hash = ''; + var hashIndex = this.url.indexOf('#'); + + if (hashIndex > -1) { + hash = this.url.substring(hashIndex, this.url.length); + this.url = this.url.substring(0, hashIndex); + } + + // If the URL contains querystring bits, use them. + // Otherwise, just create a set of valid params. + if (this.url.indexOf('?') < 0) { + this.url += '?'; + } else { + this.url += '&'; + } + + // Append the initial width as a querystring parameter, and the fragment id + this.iframe.src = + this.url + + 'initialWidth=' + + width + + '&childId=' + + this.id + + '&parentUrl=' + + encodeURIComponent(window.location.href) + + hash; + + // Set some attributes to this proto-iframe. + this.iframe.setAttribute('width', '100%'); + this.iframe.setAttribute('scrolling', 'no'); + this.iframe.setAttribute('marginheight', '0'); + this.iframe.setAttribute('frameborder', '0'); + + if (this.settings.title) { + this.iframe.setAttribute('title', this.settings.title); + } + + // Append the iframe to our element. + this.el.appendChild(this.iframe); + + // Add an event listener that will handle redrawing the child on resize. + window.addEventListener('resize', this._onResize); + }; + + /** + * Send width on resize. + * + * @memberof Parent.prototype + * @method _onResize + */ + this._onResize = function () { + this.sendWidth(); + }.bind(this); + + /** + * Fire all event handlers for a given message type. + * + * @memberof Parent.prototype + * @method _fire + * @param {String} messageType The type of message. + * @param {String} message The message data. + */ + this._fire = function (messageType, message) { + if (messageType in this.messageHandlers) { + for (var i = 0; i < this.messageHandlers[messageType].length; i++) { + this.messageHandlers[messageType][i].call(this, message); + } + } + }; + + /** + * Remove this parent from the page and unbind it's event handlers. + * + * @memberof Parent.prototype + * @method remove + */ + this.remove = function () { + window.removeEventListener('message', this._processMessage); + window.removeEventListener('resize', this._onResize); + + this.el.removeChild(this.iframe); + }; + + /** + * @callback Parent~onMessageCallback + * @param {String} message The message data. + */ + + /** + * Process a new message from the child. + * + * @memberof Parent.prototype + * @method _processMessage + * @param {Event} e A message event. + */ + this._processMessage = function (e) { + // First, punt if this isn't from an acceptable xdomain. + if (!_isSafeMessage(e, this.settings)) { + return; + } + + // Discard object messages, we only care about strings + if (typeof e.data !== 'string') { + return; + } + + // Grab the message from the child and parse it. + var match = e.data.match(this.messageRegex); + + // If there's no match or too many matches in the message, punt. + if (!match || match.length !== 3) { + return false; + } + + var messageType = match[1]; + var message = match[2]; + + this._fire(messageType, message); + }.bind(this); + + /** + * Resize iframe in response to new height message from child. + * + * @memberof Parent.prototype + * @method _onHeightMessage + * @param {String} message The new height. + */ + this._onHeightMessage = function (message) { + /* + * Handle parent height message from child. + */ + var height = parseInt(message); + + this.iframe.setAttribute('height', height + 'px'); + }; + + /** + * Navigate parent to a new url. + * + * @memberof Parent.prototype + * @method _onNavigateToMessage + * @param {String} message The url to navigate to. + */ + this._onNavigateToMessage = function (message) { + /* + * Handle parent scroll message from child. + */ + document.location.href = message; + }; + + /** + * Bind a callback to a given messageType from the child. + * + * Reserved message names are: "height", "scrollTo" and "navigateTo". + * + * @memberof Parent.prototype + * @method onMessage + * @param {String} messageType The type of message being listened for. + * @param {Parent~onMessageCallback} callback The callback to invoke when a message of the given type is received. + */ + this.onMessage = function (messageType, callback) { + if (!(messageType in this.messageHandlers)) { + this.messageHandlers[messageType] = []; + } + + this.messageHandlers[messageType].push(callback); + }; + + /** + * Send a message to the the child. + * + * @memberof Parent.prototype + * @method sendMessage + * @param {String} messageType The type of message to send. + * @param {String} message The message data to send. + */ + this.sendMessage = function (messageType, message) { + this.el + .getElementsByTagName('iframe')[0] + .contentWindow.postMessage( + _makeMessage(this.id, messageType, message), + '*' + ); + }; + + /** + * Transmit the current iframe width to the child. + * + * You shouldn't need to call this directly. + * + * @memberof Parent.prototype + * @method sendWidth + */ + this.sendWidth = function () { + var width = this.el.offsetWidth.toString(); + + this.sendMessage('width', width); + }; + + // Add any overrides to settings coming from config. + for (var key in config) { + this.settings[key] = config[key]; + } + + // Bind required message handlers + this.onMessage('height', this._onHeightMessage); + this.onMessage('navigateTo', this._onNavigateToMessage); + + // Add a listener for processing messages from the child. + window.addEventListener('message', this._processMessage, false); + + // Construct the iframe in the container element. + this._constructIframe(); + + return this; + }; + + /** + * The Child half of a responsive iframe. + * + * @class Child + * @param {Object} config Configuration to override the default settings. + */ + lib.Child = function (config) { + this.parentWidth = null; + this.id = null; + this.parentUrl = null; + + this.settings = { + renderCallback: null, + xdomain: '*', + polling: 0, + }; + + this.messageRegex = null; + this.messageHandlers = {}; + + // Ensure a config object + config = config || {}; + + /** + * Bind a callback to a given messageType from the child. + * + * Reserved message names are: "width". + * + * @memberof Child.prototype + * @method onMessage + * @param {String} messageType The type of message being listened for. + * @param {Child~onMessageCallback} callback The callback to invoke when a message of the given type is received. + */ + this.onMessage = function (messageType, callback) { + if (!(messageType in this.messageHandlers)) { + this.messageHandlers[messageType] = []; + } + + this.messageHandlers[messageType].push(callback); + }; + + /** + * @callback Child~onMessageCallback + * @param {String} message The message data. + */ + + /** + * Fire all event handlers for a given message type. + * + * @memberof Parent.prototype + * @method _fire + * @param {String} messageType The type of message. + * @param {String} message The message data. + */ + this._fire = function (messageType, message) { + /* + * Fire all event handlers for a given message type. + */ + if (messageType in this.messageHandlers) { + for (var i = 0; i < this.messageHandlers[messageType].length; i++) { + this.messageHandlers[messageType][i].call(this, message); + } + } + }; + + /** + * Process a new message from the parent. + * + * @memberof Child.prototype + * @method _processMessage + * @param {Event} e A message event. + */ + this._processMessage = function (e) { + /* + * Process a new message from parent frame. + */ + // First, punt if this isn't from an acceptable xdomain. + if (!_isSafeMessage(e, this.settings)) { + return; + } + + // Discard object messages, we only care about strings + if (typeof e.data !== 'string') { + return; + } + + // Get the message from the parent. + var match = e.data.match(this.messageRegex); + + // If there's no match or it's a bad format, punt. + if (!match || match.length !== 3) { + return; + } + + var messageType = match[1]; + var message = match[2]; + + this._fire(messageType, message); + }.bind(this); + + /** + * Resize iframe in response to new width message from parent. + * + * @memberof Child.prototype + * @method _onWidthMessage + * @param {String} message The new width. + */ + this._onWidthMessage = function (message) { + /* + * Handle width message from the child. + */ + var width = parseInt(message); + + // Change the width if it's different. + if (width !== this.parentWidth) { + this.parentWidth = width; + + // Call the callback function if it exists. + if (this.settings.renderCallback) { + this.settings.renderCallback(width); + } + + // Send the height back to the parent. + this.sendHeight(); + } + }; + + /** + * Send a message to the the Parent. + * + * @memberof Child.prototype + * @method sendMessage + * @param {String} messageType The type of message to send. + * @param {String} message The message data to send. + */ + this.sendMessage = function (messageType, message) { + /* + * Send a message to the parent. + */ + window.parent.postMessage( + _makeMessage(this.id, messageType, message), + '*' + ); + }; + + /** + * Transmit the current iframe height to the parent. + * + * Call this directly in cases where you manually alter the height of the iframe contents. + * + * @memberof Child.prototype + * @method sendHeight + */ + this.sendHeight = function () { + // Get the child's height. + var height = document + .getElementsByTagName('body')[0] + .offsetHeight.toString(); + + // Send the height to the parent. + this.sendMessage('height', height); + }.bind(this); + this.sendHeightToParent = function () { + // Get the child's height. + var height = document + .getElementsByTagName('body')[0] + .offsetHeight.toString(); + + // Send the height to the parent. + this.sendMessage('height', height); + }.bind(this); + + /** + * Scroll parent to a given element id. + * + * @memberof Child.prototype + * @method scrollParentTo + * @param {String} hash The id of the element to scroll to. + */ + this.scrollParentTo = function (hash) { + this.sendMessage('navigateTo', '#' + hash); + }; + + /** + * Navigate parent to a given url. + * + * @memberof Parent.prototype + * @method navigateParentTo + * @param {String} url The url to navigate to. + */ + this.navigateParentTo = function (url) { + this.sendMessage('navigateTo', url); + }; + + // Identify what ID the parent knows this child as. + this.id = _getParameterByName('childId') || config.id; + this.messageRegex = new RegExp( + '^pym' + + MESSAGE_DELIMITER + + this.id + + MESSAGE_DELIMITER + + '(\\S+)' + + MESSAGE_DELIMITER + + '(.+)$' + ); + + // Get the initial width from a URL parameter. + var width = parseInt(_getParameterByName('initialWidth')); + + // Get the url of the parent frame + this.parentUrl = _getParameterByName('parentUrl'); + + // Bind the required message handlers + this.onMessage('width', this._onWidthMessage); + + // Initialize settings with overrides. + for (var key in config) { + this.settings[key] = config[key]; + } + + // Set up a listener to handle any incoming messages. + window.addEventListener('message', this._processMessage, false); + + // If there's a callback function, call it. + if (this.settings.renderCallback) { + this.settings.renderCallback(width); + } + + // Send the initial height to the parent. + this.sendHeight(); + + // If we're configured to poll, create a setInterval to handle that. + if (this.settings.polling) { + window.setInterval(this.sendHeight, this.settings.polling); + } + + return this; + }; + + // Initialize elements with pym data attributes + _autoInit(); + + return lib; }); diff --git a/license.txt b/license.txt index 23cb790..c5ddbfb 100644 --- a/license.txt +++ b/license.txt @@ -1,7 +1,7 @@ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 - Copyright (C) 1989, 1991 Free Software Foundation, Inc., + Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. From 447a15697a86198d852dafd7e56d8a988b31f757 Mon Sep 17 00:00:00 2001 From: hassanelnajjar Date: Mon, 14 Jun 2021 17:50:06 +0300 Subject: [PATCH 2/6] fix whitespaces --- js/pym.js | 1006 ++++++++++++++++++++++++++--------------------------- 1 file changed, 487 insertions(+), 519 deletions(-) diff --git a/js/pym.js b/js/pym.js index 6cbc3e2..3dadae6 100644 --- a/js/pym.js +++ b/js/pym.js @@ -1,43 +1,39 @@ /* - * Pym.js is library that resizes an iframe based on the width of the parent and the resulting height of the child. - * Check out the docs at http://blog.apps.npr.org/pym.js/ or the readme at README.md for usage. - */ +* Pym.js is library that resizes an iframe based on the width of the parent and the resulting height of the child. +* Check out the docs at http://blog.apps.npr.org/pym.js/ or the readme at README.md for usage. +*/ /* global module */ -(function (factory) { +(function(factory) { if (typeof define === 'function' && define.amd) { - define(factory); + define(factory); } else if (typeof module !== 'undefined' && module.exports) { - module.exports = factory(); + module.exports = factory(); } else { - window.pym = factory.call(this); + window.pym = factory.call(this); } -})(function () { +})(function() { var MESSAGE_DELIMITER = 'xPYMx'; var lib = {}; /** - * Generic function for parsing URL params. - * Via https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript - * - * @method _getParameterByName - * @param {String} name The name of the paramter to get from the URL. - */ - var _getParameterByName = function (name) { - var regex = new RegExp( - '[\\?&]' + - name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]') + - '=([^&#]*)' - ); - var results = regex.exec(location.search); - - if (results === null) { - return ''; - } - - return decodeURIComponent(results[1].replace(/\+/g, ' ')); + * Generic function for parsing URL params. + * Via http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript + * + * @method _getParameterByName + * @param {String} name The name of the paramter to get from the URL. + */ + var _getParameterByName = function(name) { + var regex = new RegExp("[\\?&]" + name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]') + '=([^&#]*)'); + var results = regex.exec(location.search); + + if (results === null) { + return ''; + } + + return decodeURIComponent(results[1].replace(/\+/g, " ")); }; /** @@ -48,15 +44,13 @@ * @param {Event} e The message event. * @param {Object} settings Configuration. */ - var _isSafeMessage = function (e, settings) { - if (settings.xdomain !== '*') { - // If origin doesn't match our xdomain, return. - if (!e.origin.match(new RegExp(settings.xdomain + '$'))) { - return; + var _isSafeMessage = function(e, settings) { + if (settings.xdomain !== '*') { + // If origin doesn't match our xdomain, return. + if (!e.origin.match(new RegExp(settings.xdomain + '$'))) { return; } } - } - return true; + return true; }; /** @@ -70,10 +64,10 @@ * @param {String} messageType The type of message to send. * @param {String} message The message to send. */ - var _makeMessage = function (id, messageType, message) { - var bits = ['pym', id, messageType, message]; + var _makeMessage = function(id, messageType, message) { + var bits = ['pym', id, messageType, message]; - return bits.join(MESSAGE_DELIMITER); + return bits.join(MESSAGE_DELIMITER); }; /** @@ -82,10 +76,10 @@ * @method _makeMessageRegex * @param {String} id The unique id of the message recipient. */ - var _makeMessageRegex = function (id) { - var bits = ['pym', id, '(\\S+)', '(.+)']; + var _makeMessageRegex = function(id) { + var bits = ['pym', id, '(\\S+)', '(.+)']; - return new RegExp('^' + bits.join(MESSAGE_DELIMITER) + '$'); + return new RegExp('^' + bits.join(MESSAGE_DELIMITER) + '$'); }; /** @@ -93,38 +87,38 @@ * * @method _autoInit */ - var _autoInit = function () { - var elements = document.querySelectorAll( - '[data-pym-src]:not([data-pym-auto-initialized])' - ); + var _autoInit = function() { + var elements = document.querySelectorAll( + '[data-pym-src]:not([data-pym-auto-initialized])' + ); - var length = elements.length; + var length = elements.length; - for (var idx = 0; idx < length; ++idx) { - var element = elements[idx]; + for (var idx = 0; idx < length; ++idx) { + var element = elements[idx]; - /* - * Mark automatically-initialized elements so they are not - * re-initialized if the user includes pym.js more than once in the - * same document. - */ - element.setAttribute('data-pym-auto-initialized', ''); + /* + * Mark automatically-initialized elements so they are not + * re-initialized if the user includes pym.js more than once in the + * same document. + */ + element.setAttribute('data-pym-auto-initialized', ''); - // Ensure elements have an id - if (element.id === '') { - element.id = 'pym-' + idx; - } + // Ensure elements have an id + if (element.id === '') { + element.id = 'pym-' + idx; + } - var src = element.getAttribute('data-pym-src'); - var xdomain = element.getAttribute('data-pym-xdomain'); - var config = {}; + var src = element.getAttribute('data-pym-src'); + var xdomain = element.getAttribute('data-pym-xdomain'); + var config = {}; - if (xdomain) { - config.xdomain = xdomain; - } + if (xdomain) { + config.xdomain = xdomain; + } - new lib.Parent(element.id, src, config); - } + new lib.Parent(element.id, src, config); + } }; /** @@ -135,251 +129,242 @@ * @param {String} url The url of the iframe source. * @param {Object} config Configuration to override the default settings. */ - lib.Parent = function (id, url, config) { - this.id = id; - this.url = url; - this.el = document.getElementById(id); - this.iframe = null; - - this.settings = { - xdomain: '*', - }; - - this.messageRegex = _makeMessageRegex(this.id); - this.messageHandlers = {}; - - // ensure a config object - config = config || {}; - - /** - * Construct the iframe. - * - * @memberof Parent.prototype - * @method _constructIframe - */ - this._constructIframe = function () { - // Calculate the width of this element. - var width = this.el.offsetWidth.toString(); - - // Create an iframe element attached to the document. - this.iframe = document.createElement('iframe'); - - // Save fragment id - var hash = ''; - var hashIndex = this.url.indexOf('#'); - - if (hashIndex > -1) { - hash = this.url.substring(hashIndex, this.url.length); - this.url = this.url.substring(0, hashIndex); - } + lib.Parent = function(id, url, config) { + this.id = id; + this.url = url; + this.el = document.getElementById(id); + this.iframe = null; + + this.settings = { + xdomain: '*' + }; + + this.messageRegex = _makeMessageRegex(this.id); + this.messageHandlers = {}; + + // ensure a config object + config = (config || {}); + + /** + * Construct the iframe. + * + * @memberof Parent.prototype + * @method _constructIframe + */ + this._constructIframe = function() { + // Calculate the width of this element. + var width = this.el.offsetWidth.toString(); + + // Create an iframe element attached to the document. + this.iframe = document.createElement('iframe'); + + // Save fragment id + var hash = ''; + var hashIndex = this.url.indexOf('#'); + + if (hashIndex > -1) { + hash = this.url.substring(hashIndex, this.url.length); + this.url = this.url.substring(0, hashIndex); + } + + // If the URL contains querystring bits, use them. + // Otherwise, just create a set of valid params. + if (this.url.indexOf('?') < 0) { + this.url += '?'; + } else { + this.url += '&'; + } + + // Append the initial width as a querystring parameter, and the fragment id + this.iframe.src = this.url + + 'initialWidth=' + width + + '&childId=' + this.id + + '&parentUrl=' + encodeURIComponent(window.location.href) + + hash; + + // Set some attributes to this proto-iframe. + this.iframe.setAttribute('width', '100%'); + this.iframe.setAttribute('scrolling', 'no'); + this.iframe.setAttribute('marginheight', '0'); + this.iframe.setAttribute('frameborder', '0'); + + if (this.settings.title) { + this.iframe.setAttribute('title', this.settings.title); + } + + // Append the iframe to our element. + this.el.appendChild(this.iframe); + + // Add an event listener that will handle redrawing the child on resize. + window.addEventListener('resize', this._onResize); + }; + + /** + * Send width on resize. + * + * @memberof Parent.prototype + * @method _onResize + */ + this._onResize = function() { + this.sendWidth(); + }.bind(this); - // If the URL contains querystring bits, use them. - // Otherwise, just create a set of valid params. - if (this.url.indexOf('?') < 0) { - this.url += '?'; - } else { - this.url += '&'; - } + /** + * Fire all event handlers for a given message type. + * + * @memberof Parent.prototype + * @method _fire + * @param {String} messageType The type of message. + * @param {String} message The message data. + */ + this._fire = function(messageType, message) { + if (messageType in this.messageHandlers) { + for (var i = 0; i < this.messageHandlers[messageType].length; i++) { + this.messageHandlers[messageType][i].call(this, message); + } + } + }; + + /** + * Remove this parent from the page and unbind it's event handlers. + * + * @memberof Parent.prototype + * @method remove + */ + this.remove = function() { + window.removeEventListener('message', this._processMessage); + window.removeEventListener('resize', this._onResize); - // Append the initial width as a querystring parameter, and the fragment id - this.iframe.src = - this.url + - 'initialWidth=' + - width + - '&childId=' + - this.id + - '&parentUrl=' + - encodeURIComponent(window.location.href) + - hash; - - // Set some attributes to this proto-iframe. - this.iframe.setAttribute('width', '100%'); - this.iframe.setAttribute('scrolling', 'no'); - this.iframe.setAttribute('marginheight', '0'); - this.iframe.setAttribute('frameborder', '0'); - - if (this.settings.title) { - this.iframe.setAttribute('title', this.settings.title); - } + this.el.removeChild(this.iframe); + }; - // Append the iframe to our element. - this.el.appendChild(this.iframe); - - // Add an event listener that will handle redrawing the child on resize. - window.addEventListener('resize', this._onResize); - }; - - /** - * Send width on resize. - * - * @memberof Parent.prototype - * @method _onResize - */ - this._onResize = function () { - this.sendWidth(); - }.bind(this); - - /** - * Fire all event handlers for a given message type. - * - * @memberof Parent.prototype - * @method _fire - * @param {String} messageType The type of message. - * @param {String} message The message data. - */ - this._fire = function (messageType, message) { - if (messageType in this.messageHandlers) { - for (var i = 0; i < this.messageHandlers[messageType].length; i++) { - this.messageHandlers[messageType][i].call(this, message); - } - } - }; - - /** - * Remove this parent from the page and unbind it's event handlers. - * - * @memberof Parent.prototype - * @method remove - */ - this.remove = function () { - window.removeEventListener('message', this._processMessage); - window.removeEventListener('resize', this._onResize); - - this.el.removeChild(this.iframe); - }; - - /** - * @callback Parent~onMessageCallback - * @param {String} message The message data. - */ - - /** - * Process a new message from the child. - * - * @memberof Parent.prototype - * @method _processMessage - * @param {Event} e A message event. - */ - this._processMessage = function (e) { - // First, punt if this isn't from an acceptable xdomain. - if (!_isSafeMessage(e, this.settings)) { - return; - } + /** + * @callback Parent~onMessageCallback + * @param {String} message The message data. + */ - // Discard object messages, we only care about strings - if (typeof e.data !== 'string') { - return; - } + /** + * Process a new message from the child. + * + * @memberof Parent.prototype + * @method _processMessage + * @param {Event} e A message event. + */ + this._processMessage = function(e) { + // First, punt if this isn't from an acceptable xdomain. + if (!_isSafeMessage(e, this.settings)) { + return; + } + + // Discard object messages, we only care about strings + if (typeof e.data !== 'string') { + return; + } + + // Grab the message from the child and parse it. + var match = e.data.match(this.messageRegex); + + // If there's no match or too many matches in the message, punt. + if (!match || match.length !== 3) { + return false; + } + + var messageType = match[1]; + var message = match[2]; + + this._fire(messageType, message); + }.bind(this); + + /** + * Resize iframe in response to new height message from child. + * + * @memberof Parent.prototype + * @method _onHeightMessage + * @param {String} message The new height. + */ + this._onHeightMessage = function(message) { + /* + * Handle parent height message from child. + */ + var height = parseInt(message); + + this.iframe.setAttribute('height', height + 'px'); + }; + + /** + * Navigate parent to a new url. + * + * @memberof Parent.prototype + * @method _onNavigateToMessage + * @param {String} message The url to navigate to. + */ + this._onNavigateToMessage = function(message) { + /* + * Handle parent scroll message from child. + */ + document.location.href = message; + }; + + /** + * Bind a callback to a given messageType from the child. + * + * Reserved message names are: "height", "scrollTo" and "navigateTo". + * + * @memberof Parent.prototype + * @method onMessage + * @param {String} messageType The type of message being listened for. + * @param {Parent~onMessageCallback} callback The callback to invoke when a message of the given type is received. + */ + this.onMessage = function(messageType, callback) { + if (!(messageType in this.messageHandlers)) { + this.messageHandlers[messageType] = []; + } + + this.messageHandlers[messageType].push(callback); + }; + + /** + * Send a message to the the child. + * + * @memberof Parent.prototype + * @method sendMessage + * @param {String} messageType The type of message to send. + * @param {String} message The message data to send. + */ + this.sendMessage = function(messageType, message) { + this.el.getElementsByTagName('iframe')[0].contentWindow.postMessage(_makeMessage(this.id, messageType, message), '*'); + }; + + /** + * Transmit the current iframe width to the child. + * + * You shouldn't need to call this directly. + * + * @memberof Parent.prototype + * @method sendWidth + */ + this.sendWidth = function() { + var width = this.el.offsetWidth.toString(); - // Grab the message from the child and parse it. - var match = e.data.match(this.messageRegex); + this.sendMessage('width', width); + }; - // If there's no match or too many matches in the message, punt. - if (!match || match.length !== 3) { - return false; + // Add any overrides to settings coming from config. + for (var key in config) { + this.settings[key] = config[key]; } - var messageType = match[1]; - var message = match[2]; - - this._fire(messageType, message); - }.bind(this); - - /** - * Resize iframe in response to new height message from child. - * - * @memberof Parent.prototype - * @method _onHeightMessage - * @param {String} message The new height. - */ - this._onHeightMessage = function (message) { - /* - * Handle parent height message from child. - */ - var height = parseInt(message); - - this.iframe.setAttribute('height', height + 'px'); - }; - - /** - * Navigate parent to a new url. - * - * @memberof Parent.prototype - * @method _onNavigateToMessage - * @param {String} message The url to navigate to. - */ - this._onNavigateToMessage = function (message) { - /* - * Handle parent scroll message from child. - */ - document.location.href = message; - }; - - /** - * Bind a callback to a given messageType from the child. - * - * Reserved message names are: "height", "scrollTo" and "navigateTo". - * - * @memberof Parent.prototype - * @method onMessage - * @param {String} messageType The type of message being listened for. - * @param {Parent~onMessageCallback} callback The callback to invoke when a message of the given type is received. - */ - this.onMessage = function (messageType, callback) { - if (!(messageType in this.messageHandlers)) { - this.messageHandlers[messageType] = []; - } + // Bind required message handlers + this.onMessage('height', this._onHeightMessage); + this.onMessage('navigateTo', this._onNavigateToMessage); + + // Add a listener for processing messages from the child. + window.addEventListener('message', this._processMessage, false); - this.messageHandlers[messageType].push(callback); - }; - - /** - * Send a message to the the child. - * - * @memberof Parent.prototype - * @method sendMessage - * @param {String} messageType The type of message to send. - * @param {String} message The message data to send. - */ - this.sendMessage = function (messageType, message) { - this.el - .getElementsByTagName('iframe')[0] - .contentWindow.postMessage( - _makeMessage(this.id, messageType, message), - '*' - ); - }; - - /** - * Transmit the current iframe width to the child. - * - * You shouldn't need to call this directly. - * - * @memberof Parent.prototype - * @method sendWidth - */ - this.sendWidth = function () { - var width = this.el.offsetWidth.toString(); - - this.sendMessage('width', width); - }; - - // Add any overrides to settings coming from config. - for (var key in config) { - this.settings[key] = config[key]; - } - - // Bind required message handlers - this.onMessage('height', this._onHeightMessage); - this.onMessage('navigateTo', this._onNavigateToMessage); - - // Add a listener for processing messages from the child. - window.addEventListener('message', this._processMessage, false); - - // Construct the iframe in the container element. - this._constructIframe(); - - return this; + // Construct the iframe in the container element. + this._constructIframe(); + + return this; }; /** @@ -388,237 +373,220 @@ * @class Child * @param {Object} config Configuration to override the default settings. */ - lib.Child = function (config) { - this.parentWidth = null; - this.id = null; - this.parentUrl = null; - - this.settings = { - renderCallback: null, - xdomain: '*', - polling: 0, - }; - - this.messageRegex = null; - this.messageHandlers = {}; - - // Ensure a config object - config = config || {}; - - /** - * Bind a callback to a given messageType from the child. - * - * Reserved message names are: "width". - * - * @memberof Child.prototype - * @method onMessage - * @param {String} messageType The type of message being listened for. - * @param {Child~onMessageCallback} callback The callback to invoke when a message of the given type is received. - */ - this.onMessage = function (messageType, callback) { - if (!(messageType in this.messageHandlers)) { - this.messageHandlers[messageType] = []; - } + lib.Child = function(config) { + this.parentWidth = null; + this.id = null; + this.parentUrl = null; + + this.settings = { + renderCallback: null, + xdomain: '*', + polling: 0 + }; + + this.messageRegex = null; + this.messageHandlers = {}; + + // Ensure a config object + config = (config || {}); + + /** + * Bind a callback to a given messageType from the child. + * + * Reserved message names are: "width". + * + * @memberof Child.prototype + * @method onMessage + * @param {String} messageType The type of message being listened for. + * @param {Child~onMessageCallback} callback The callback to invoke when a message of the given type is received. + */ + this.onMessage = function(messageType, callback) { + if (!(messageType in this.messageHandlers)) { + this.messageHandlers[messageType] = []; + } - this.messageHandlers[messageType].push(callback); - }; - - /** - * @callback Child~onMessageCallback - * @param {String} message The message data. - */ - - /** - * Fire all event handlers for a given message type. - * - * @memberof Parent.prototype - * @method _fire - * @param {String} messageType The type of message. - * @param {String} message The message data. - */ - this._fire = function (messageType, message) { - /* + this.messageHandlers[messageType].push(callback); + }; + + /** + * @callback Child~onMessageCallback + * @param {String} message The message data. + */ + + /** * Fire all event handlers for a given message type. + * + * @memberof Parent.prototype + * @method _fire + * @param {String} messageType The type of message. + * @param {String} message The message data. */ - if (messageType in this.messageHandlers) { - for (var i = 0; i < this.messageHandlers[messageType].length; i++) { - this.messageHandlers[messageType][i].call(this, message); - } - } - }; - - /** - * Process a new message from the parent. - * - * @memberof Child.prototype - * @method _processMessage - * @param {Event} e A message event. - */ - this._processMessage = function (e) { - /* - * Process a new message from parent frame. + this._fire = function(messageType, message) { + /* + * Fire all event handlers for a given message type. + */ + if (messageType in this.messageHandlers) { + for (var i = 0; i < this.messageHandlers[messageType].length; i++) { + this.messageHandlers[messageType][i].call(this, message); + } + } + }; + + /** + * Process a new message from the parent. + * + * @memberof Child.prototype + * @method _processMessage + * @param {Event} e A message event. */ - // First, punt if this isn't from an acceptable xdomain. - if (!_isSafeMessage(e, this.settings)) { - return; - } + this._processMessage = function(e) { + /* + * Process a new message from parent frame. + */ + // First, punt if this isn't from an acceptable xdomain. + if (!_isSafeMessage(e, this.settings)) { + return; + } + + // Discard object messages, we only care about strings + if (typeof e.data !== 'string') { + return; + } + + // Get the message from the parent. + var match = e.data.match(this.messageRegex); + + // If there's no match or it's a bad format, punt. + if (!match || match.length !== 3) { return; } + + var messageType = match[1]; + var message = match[2]; + + this._fire(messageType, message); + }.bind(this); + + /** + * Resize iframe in response to new width message from parent. + * + * @memberof Child.prototype + * @method _onWidthMessage + * @param {String} message The new width. + */ + this._onWidthMessage = function(message) { + /* + * Handle width message from the child. + */ + var width = parseInt(message); + + // Change the width if it's different. + if (width !== this.parentWidth) { + this.parentWidth = width; + + // Call the callback function if it exists. + if (this.settings.renderCallback) { + this.settings.renderCallback(width); + } + + // Send the height back to the parent. + this.sendHeight(); + } + }; + + /** + * Send a message to the the Parent. + * + * @memberof Child.prototype + * @method sendMessage + * @param {String} messageType The type of message to send. + * @param {String} message The message data to send. + */ + this.sendMessage = function(messageType, message) { + /* + * Send a message to the parent. + */ + window.parent.postMessage(_makeMessage(this.id, messageType, message), '*'); + }; + + /** + * Transmit the current iframe height to the parent. + * + * Call this directly in cases where you manually alter the height of the iframe contents. + * + * @memberof Child.prototype + * @method sendHeight + */ + this.sendHeight = function() { + // Get the child's height. + var height = document.getElementsByTagName('body')[0].offsetHeight.toString(); + + // Send the height to the parent. + this.sendMessage('height', height); + }.bind(this); + this.sendHeightToParent = function() { + // Get the child's height. + var height = document.getElementsByTagName('body')[0].offsetHeight.toString(); + + // Send the height to the parent. + this.sendMessage('height', height); + }.bind(this); + + /** + * Scroll parent to a given element id. + * + * @memberof Child.prototype + * @method scrollParentTo + * @param {String} hash The id of the element to scroll to. + */ + this.scrollParentTo = function(hash) { + this.sendMessage('navigateTo', '#' + hash); + }; + + /** + * Navigate parent to a given url. + * + * @memberof Parent.prototype + * @method navigateParentTo + * @param {String} url The url to navigate to. + */ + this.navigateParentTo = function(url) { + this.sendMessage('navigateTo', url); + }; - // Discard object messages, we only care about strings - if (typeof e.data !== 'string') { - return; - } + // Identify what ID the parent knows this child as. + this.id = _getParameterByName('childId') || config.id; + this.messageRegex = new RegExp('^pym' + MESSAGE_DELIMITER + this.id + MESSAGE_DELIMITER + '(\\S+)' + MESSAGE_DELIMITER + '(.+)$'); - // Get the message from the parent. - var match = e.data.match(this.messageRegex); + // Get the initial width from a URL parameter. + var width = parseInt(_getParameterByName('initialWidth')); - // If there's no match or it's a bad format, punt. - if (!match || match.length !== 3) { - return; - } + // Get the url of the parent frame + this.parentUrl = _getParameterByName('parentUrl'); - var messageType = match[1]; - var message = match[2]; - - this._fire(messageType, message); - }.bind(this); - - /** - * Resize iframe in response to new width message from parent. - * - * @memberof Child.prototype - * @method _onWidthMessage - * @param {String} message The new width. - */ - this._onWidthMessage = function (message) { - /* - * Handle width message from the child. - */ - var width = parseInt(message); + // Bind the required message handlers + this.onMessage('width', this._onWidthMessage); - // Change the width if it's different. - if (width !== this.parentWidth) { - this.parentWidth = width; + // Initialize settings with overrides. + for (var key in config) { + this.settings[key] = config[key]; + } - // Call the callback function if it exists. - if (this.settings.renderCallback) { + // Set up a listener to handle any incoming messages. + window.addEventListener('message', this._processMessage, false); + + // If there's a callback function, call it. + if (this.settings.renderCallback) { this.settings.renderCallback(width); - } + } + + // Send the initial height to the parent. + this.sendHeight(); - // Send the height back to the parent. - this.sendHeight(); + // If we're configured to poll, create a setInterval to handle that. + if (this.settings.polling) { + window.setInterval(this.sendHeight, this.settings.polling); } - }; - - /** - * Send a message to the the Parent. - * - * @memberof Child.prototype - * @method sendMessage - * @param {String} messageType The type of message to send. - * @param {String} message The message data to send. - */ - this.sendMessage = function (messageType, message) { - /* - * Send a message to the parent. - */ - window.parent.postMessage( - _makeMessage(this.id, messageType, message), - '*' - ); - }; - - /** - * Transmit the current iframe height to the parent. - * - * Call this directly in cases where you manually alter the height of the iframe contents. - * - * @memberof Child.prototype - * @method sendHeight - */ - this.sendHeight = function () { - // Get the child's height. - var height = document - .getElementsByTagName('body')[0] - .offsetHeight.toString(); - - // Send the height to the parent. - this.sendMessage('height', height); - }.bind(this); - this.sendHeightToParent = function () { - // Get the child's height. - var height = document - .getElementsByTagName('body')[0] - .offsetHeight.toString(); - - // Send the height to the parent. - this.sendMessage('height', height); - }.bind(this); - - /** - * Scroll parent to a given element id. - * - * @memberof Child.prototype - * @method scrollParentTo - * @param {String} hash The id of the element to scroll to. - */ - this.scrollParentTo = function (hash) { - this.sendMessage('navigateTo', '#' + hash); - }; - - /** - * Navigate parent to a given url. - * - * @memberof Parent.prototype - * @method navigateParentTo - * @param {String} url The url to navigate to. - */ - this.navigateParentTo = function (url) { - this.sendMessage('navigateTo', url); - }; - - // Identify what ID the parent knows this child as. - this.id = _getParameterByName('childId') || config.id; - this.messageRegex = new RegExp( - '^pym' + - MESSAGE_DELIMITER + - this.id + - MESSAGE_DELIMITER + - '(\\S+)' + - MESSAGE_DELIMITER + - '(.+)$' - ); - - // Get the initial width from a URL parameter. - var width = parseInt(_getParameterByName('initialWidth')); - - // Get the url of the parent frame - this.parentUrl = _getParameterByName('parentUrl'); - - // Bind the required message handlers - this.onMessage('width', this._onWidthMessage); - - // Initialize settings with overrides. - for (var key in config) { - this.settings[key] = config[key]; - } - - // Set up a listener to handle any incoming messages. - window.addEventListener('message', this._processMessage, false); - - // If there's a callback function, call it. - if (this.settings.renderCallback) { - this.settings.renderCallback(width); - } - - // Send the initial height to the parent. - this.sendHeight(); - - // If we're configured to poll, create a setInterval to handle that. - if (this.settings.polling) { - window.setInterval(this.sendHeight, this.settings.polling); - } - - return this; + + return this; }; // Initialize elements with pym data attributes From 71525414a13199125449598301c2739052dc0036 Mon Sep 17 00:00:00 2001 From: hassanelnajjar Date: Mon, 14 Jun 2021 17:55:21 +0300 Subject: [PATCH 3/6] fix indentation --- js/pym.js | 350 +++++++++++++++++++++++++++--------------------------- 1 file changed, 175 insertions(+), 175 deletions(-) diff --git a/js/pym.js b/js/pym.js index 3dadae6..2c43d2d 100644 --- a/js/pym.js +++ b/js/pym.js @@ -37,13 +37,13 @@ }; /** - * Check the message to make sure it comes from an acceptable xdomain. - * Defaults to '*' but can be overriden in config. - * - * @method _isSafeMessage - * @param {Event} e The message event. - * @param {Object} settings Configuration. - */ + * Check the message to make sure it comes from an acceptable xdomain. + * Defaults to '*' but can be overriden in config. + * + * @method _isSafeMessage + * @param {Event} e The message event. + * @param {Object} settings Configuration. + */ var _isSafeMessage = function(e, settings) { if (settings.xdomain !== '*') { // If origin doesn't match our xdomain, return. @@ -54,16 +54,16 @@ }; /** - * Construct a message to send between frames. - * - * NB: We use string-building here because JSON message passing is - * not supported in all browsers. - * - * @method _makeMessage - * @param {String} id The unique id of the message recipient. - * @param {String} messageType The type of message to send. - * @param {String} message The message to send. - */ + * Construct a message to send between frames. + * + * NB: We use string-building here because JSON message passing is + * not supported in all browsers. + * + * @method _makeMessage + * @param {String} id The unique id of the message recipient. + * @param {String} messageType The type of message to send. + * @param {String} message The message to send. + */ var _makeMessage = function(id, messageType, message) { var bits = ['pym', id, messageType, message]; @@ -71,11 +71,11 @@ }; /** - * Construct a regex to validate and parse messages. - * - * @method _makeMessageRegex - * @param {String} id The unique id of the message recipient. - */ + * Construct a regex to validate and parse messages. + * + * @method _makeMessageRegex + * @param {String} id The unique id of the message recipient. + */ var _makeMessageRegex = function(id) { var bits = ['pym', id, '(\\S+)', '(.+)']; @@ -83,10 +83,10 @@ }; /** - * Initialize Pym for elements on page that have data-pym attributes. - * - * @method _autoInit - */ + * Initialize Pym for elements on page that have data-pym attributes. + * + * @method _autoInit + */ var _autoInit = function() { var elements = document.querySelectorAll( '[data-pym-src]:not([data-pym-auto-initialized])' @@ -114,7 +114,7 @@ var config = {}; if (xdomain) { - config.xdomain = xdomain; + config.xdomain = xdomain; } new lib.Parent(element.id, src, config); @@ -122,13 +122,13 @@ }; /** - * The Parent half of a response iframe. - * - * @class Parent - * @param {String} id The id of the div into which the iframe will be rendered. - * @param {String} url The url of the iframe source. - * @param {Object} config Configuration to override the default settings. - */ + * The Parent half of a response iframe. + * + * @class Parent + * @param {String} id The id of the div into which the iframe will be rendered. + * @param {String} url The url of the iframe source. + * @param {Object} config Configuration to override the default settings. + */ lib.Parent = function(id, url, config) { this.id = id; this.url = url; @@ -146,11 +146,11 @@ config = (config || {}); /** - * Construct the iframe. - * - * @memberof Parent.prototype - * @method _constructIframe - */ + * Construct the iframe. + * + * @memberof Parent.prototype + * @method _constructIframe + */ this._constructIframe = function() { // Calculate the width of this element. var width = this.el.offsetWidth.toString(); @@ -200,37 +200,37 @@ }; /** - * Send width on resize. - * - * @memberof Parent.prototype - * @method _onResize - */ + * Send width on resize. + * + * @memberof Parent.prototype + * @method _onResize + */ this._onResize = function() { this.sendWidth(); }.bind(this); /** - * Fire all event handlers for a given message type. - * - * @memberof Parent.prototype - * @method _fire - * @param {String} messageType The type of message. - * @param {String} message The message data. - */ + * Fire all event handlers for a given message type. + * + * @memberof Parent.prototype + * @method _fire + * @param {String} messageType The type of message. + * @param {String} message The message data. + */ this._fire = function(messageType, message) { if (messageType in this.messageHandlers) { for (var i = 0; i < this.messageHandlers[messageType].length; i++) { - this.messageHandlers[messageType][i].call(this, message); + this.messageHandlers[messageType][i].call(this, message); } } }; /** - * Remove this parent from the page and unbind it's event handlers. - * - * @memberof Parent.prototype - * @method remove - */ + * Remove this parent from the page and unbind it's event handlers. + * + * @memberof Parent.prototype + * @method remove + */ this.remove = function() { window.removeEventListener('message', this._processMessage); window.removeEventListener('resize', this._onResize); @@ -239,17 +239,17 @@ }; /** - * @callback Parent~onMessageCallback - * @param {String} message The message data. - */ + * @callback Parent~onMessageCallback + * @param {String} message The message data. + */ /** - * Process a new message from the child. - * - * @memberof Parent.prototype - * @method _processMessage - * @param {Event} e A message event. - */ + * Process a new message from the child. + * + * @memberof Parent.prototype + * @method _processMessage + * @param {Event} e A message event. + */ this._processMessage = function(e) { // First, punt if this isn't from an acceptable xdomain. if (!_isSafeMessage(e, this.settings)) { @@ -276,45 +276,45 @@ }.bind(this); /** - * Resize iframe in response to new height message from child. - * - * @memberof Parent.prototype - * @method _onHeightMessage - * @param {String} message The new height. - */ + * Resize iframe in response to new height message from child. + * + * @memberof Parent.prototype + * @method _onHeightMessage + * @param {String} message The new height. + */ this._onHeightMessage = function(message) { /* - * Handle parent height message from child. - */ + * Handle parent height message from child. + */ var height = parseInt(message); this.iframe.setAttribute('height', height + 'px'); }; /** - * Navigate parent to a new url. - * - * @memberof Parent.prototype - * @method _onNavigateToMessage - * @param {String} message The url to navigate to. - */ + * Navigate parent to a new url. + * + * @memberof Parent.prototype + * @method _onNavigateToMessage + * @param {String} message The url to navigate to. + */ this._onNavigateToMessage = function(message) { /* - * Handle parent scroll message from child. - */ - document.location.href = message; + * Handle parent scroll message from child. + */ + document.location.href = message; }; /** - * Bind a callback to a given messageType from the child. - * - * Reserved message names are: "height", "scrollTo" and "navigateTo". - * - * @memberof Parent.prototype - * @method onMessage - * @param {String} messageType The type of message being listened for. - * @param {Parent~onMessageCallback} callback The callback to invoke when a message of the given type is received. - */ + * Bind a callback to a given messageType from the child. + * + * Reserved message names are: "height", "scrollTo" and "navigateTo". + * + * @memberof Parent.prototype + * @method onMessage + * @param {String} messageType The type of message being listened for. + * @param {Parent~onMessageCallback} callback The callback to invoke when a message of the given type is received. + */ this.onMessage = function(messageType, callback) { if (!(messageType in this.messageHandlers)) { this.messageHandlers[messageType] = []; @@ -324,25 +324,25 @@ }; /** - * Send a message to the the child. - * - * @memberof Parent.prototype - * @method sendMessage - * @param {String} messageType The type of message to send. - * @param {String} message The message data to send. - */ + * Send a message to the the child. + * + * @memberof Parent.prototype + * @method sendMessage + * @param {String} messageType The type of message to send. + * @param {String} message The message data to send. + */ this.sendMessage = function(messageType, message) { this.el.getElementsByTagName('iframe')[0].contentWindow.postMessage(_makeMessage(this.id, messageType, message), '*'); }; /** - * Transmit the current iframe width to the child. - * - * You shouldn't need to call this directly. - * - * @memberof Parent.prototype - * @method sendWidth - */ + * Transmit the current iframe width to the child. + * + * You shouldn't need to call this directly. + * + * @memberof Parent.prototype + * @method sendWidth + */ this.sendWidth = function() { var width = this.el.offsetWidth.toString(); @@ -368,11 +368,11 @@ }; /** - * The Child half of a responsive iframe. - * - * @class Child - * @param {Object} config Configuration to override the default settings. - */ + * The Child half of a responsive iframe. + * + * @class Child + * @param {Object} config Configuration to override the default settings. + */ lib.Child = function(config) { this.parentWidth = null; this.id = null; @@ -391,15 +391,15 @@ config = (config || {}); /** - * Bind a callback to a given messageType from the child. - * - * Reserved message names are: "width". - * - * @memberof Child.prototype - * @method onMessage - * @param {String} messageType The type of message being listened for. - * @param {Child~onMessageCallback} callback The callback to invoke when a message of the given type is received. - */ + * Bind a callback to a given messageType from the child. + * + * Reserved message names are: "width". + * + * @memberof Child.prototype + * @method onMessage + * @param {String} messageType The type of message being listened for. + * @param {Child~onMessageCallback} callback The callback to invoke when a message of the given type is received. + */ this.onMessage = function(messageType, callback) { if (!(messageType in this.messageHandlers)) { this.messageHandlers[messageType] = []; @@ -409,36 +409,36 @@ }; /** - * @callback Child~onMessageCallback - * @param {String} message The message data. - */ + * @callback Child~onMessageCallback + * @param {String} message The message data. + */ /** - * Fire all event handlers for a given message type. - * - * @memberof Parent.prototype - * @method _fire - * @param {String} messageType The type of message. - * @param {String} message The message data. - */ + * Fire all event handlers for a given message type. + * + * @memberof Parent.prototype + * @method _fire + * @param {String} messageType The type of message. + * @param {String} message The message data. + */ this._fire = function(messageType, message) { /* - * Fire all event handlers for a given message type. - */ + * Fire all event handlers for a given message type. + */ if (messageType in this.messageHandlers) { for (var i = 0; i < this.messageHandlers[messageType].length; i++) { - this.messageHandlers[messageType][i].call(this, message); + this.messageHandlers[messageType][i].call(this, message); } } }; /** - * Process a new message from the parent. - * - * @memberof Child.prototype - * @method _processMessage - * @param {Event} e A message event. - */ + * Process a new message from the parent. + * + * @memberof Child.prototype + * @method _processMessage + * @param {Event} e A message event. + */ this._processMessage = function(e) { /* * Process a new message from parent frame. @@ -466,16 +466,16 @@ }.bind(this); /** - * Resize iframe in response to new width message from parent. - * - * @memberof Child.prototype - * @method _onWidthMessage - * @param {String} message The new width. - */ + * Resize iframe in response to new width message from parent. + * + * @memberof Child.prototype + * @method _onWidthMessage + * @param {String} message The new width. + */ this._onWidthMessage = function(message) { /* - * Handle width message from the child. - */ + * Handle width message from the child. + */ var width = parseInt(message); // Change the width if it's different. @@ -493,28 +493,28 @@ }; /** - * Send a message to the the Parent. - * - * @memberof Child.prototype - * @method sendMessage - * @param {String} messageType The type of message to send. - * @param {String} message The message data to send. - */ + * Send a message to the the Parent. + * + * @memberof Child.prototype + * @method sendMessage + * @param {String} messageType The type of message to send. + * @param {String} message The message data to send. + */ this.sendMessage = function(messageType, message) { /* - * Send a message to the parent. - */ + * Send a message to the parent. + */ window.parent.postMessage(_makeMessage(this.id, messageType, message), '*'); }; /** - * Transmit the current iframe height to the parent. - * - * Call this directly in cases where you manually alter the height of the iframe contents. - * - * @memberof Child.prototype - * @method sendHeight - */ + * Transmit the current iframe height to the parent. + * + * Call this directly in cases where you manually alter the height of the iframe contents. + * + * @memberof Child.prototype + * @method sendHeight + */ this.sendHeight = function() { // Get the child's height. var height = document.getElementsByTagName('body')[0].offsetHeight.toString(); @@ -531,23 +531,23 @@ }.bind(this); /** - * Scroll parent to a given element id. - * - * @memberof Child.prototype - * @method scrollParentTo - * @param {String} hash The id of the element to scroll to. - */ + * Scroll parent to a given element id. + * + * @memberof Child.prototype + * @method scrollParentTo + * @param {String} hash The id of the element to scroll to. + */ this.scrollParentTo = function(hash) { this.sendMessage('navigateTo', '#' + hash); }; /** - * Navigate parent to a given url. - * - * @memberof Parent.prototype - * @method navigateParentTo - * @param {String} url The url to navigate to. - */ + * Navigate parent to a given url. + * + * @memberof Parent.prototype + * @method navigateParentTo + * @param {String} url The url to navigate to. + */ this.navigateParentTo = function(url) { this.sendMessage('navigateTo', url); }; From db463787f924c0d0eaa5d7ed9ea939e64e74b57e Mon Sep 17 00:00:00 2001 From: hassanelnajjar Date: Mon, 14 Jun 2021 17:58:45 +0300 Subject: [PATCH 4/6] fix indentaion --- js/pym.js | 1172 ++++++++++++++++++++++++++--------------------------- 1 file changed, 586 insertions(+), 586 deletions(-) diff --git a/js/pym.js b/js/pym.js index 2c43d2d..22ef50d 100644 --- a/js/pym.js +++ b/js/pym.js @@ -6,591 +6,591 @@ /* global module */ (function(factory) { - if (typeof define === 'function' && define.amd) { - define(factory); - } else if (typeof module !== 'undefined' && module.exports) { - module.exports = factory(); - } else { - window.pym = factory.call(this); - } + if (typeof define === 'function' && define.amd) { + define(factory); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = factory(); + } else { + window.pym = factory.call(this); + } })(function() { - var MESSAGE_DELIMITER = 'xPYMx'; - - var lib = {}; - - /** - * Generic function for parsing URL params. - * Via http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript - * - * @method _getParameterByName - * @param {String} name The name of the paramter to get from the URL. - */ - var _getParameterByName = function(name) { - var regex = new RegExp("[\\?&]" + name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]') + '=([^&#]*)'); - var results = regex.exec(location.search); - - if (results === null) { - return ''; - } - - return decodeURIComponent(results[1].replace(/\+/g, " ")); - }; - - /** - * Check the message to make sure it comes from an acceptable xdomain. - * Defaults to '*' but can be overriden in config. - * - * @method _isSafeMessage - * @param {Event} e The message event. - * @param {Object} settings Configuration. - */ - var _isSafeMessage = function(e, settings) { - if (settings.xdomain !== '*') { - // If origin doesn't match our xdomain, return. - if (!e.origin.match(new RegExp(settings.xdomain + '$'))) { return; } - } - - return true; - }; - - /** - * Construct a message to send between frames. - * - * NB: We use string-building here because JSON message passing is - * not supported in all browsers. - * - * @method _makeMessage - * @param {String} id The unique id of the message recipient. - * @param {String} messageType The type of message to send. - * @param {String} message The message to send. - */ - var _makeMessage = function(id, messageType, message) { - var bits = ['pym', id, messageType, message]; - - return bits.join(MESSAGE_DELIMITER); - }; - - /** - * Construct a regex to validate and parse messages. - * - * @method _makeMessageRegex - * @param {String} id The unique id of the message recipient. - */ - var _makeMessageRegex = function(id) { - var bits = ['pym', id, '(\\S+)', '(.+)']; - - return new RegExp('^' + bits.join(MESSAGE_DELIMITER) + '$'); - }; - - /** - * Initialize Pym for elements on page that have data-pym attributes. - * - * @method _autoInit - */ - var _autoInit = function() { - var elements = document.querySelectorAll( - '[data-pym-src]:not([data-pym-auto-initialized])' - ); - - var length = elements.length; - - for (var idx = 0; idx < length; ++idx) { - var element = elements[idx]; - - /* - * Mark automatically-initialized elements so they are not - * re-initialized if the user includes pym.js more than once in the - * same document. - */ - element.setAttribute('data-pym-auto-initialized', ''); - - // Ensure elements have an id - if (element.id === '') { - element.id = 'pym-' + idx; - } - - var src = element.getAttribute('data-pym-src'); - var xdomain = element.getAttribute('data-pym-xdomain'); - var config = {}; - - if (xdomain) { - config.xdomain = xdomain; - } - - new lib.Parent(element.id, src, config); - } - }; - - /** - * The Parent half of a response iframe. - * - * @class Parent - * @param {String} id The id of the div into which the iframe will be rendered. - * @param {String} url The url of the iframe source. - * @param {Object} config Configuration to override the default settings. - */ - lib.Parent = function(id, url, config) { - this.id = id; - this.url = url; - this.el = document.getElementById(id); - this.iframe = null; - - this.settings = { - xdomain: '*' - }; - - this.messageRegex = _makeMessageRegex(this.id); - this.messageHandlers = {}; - - // ensure a config object - config = (config || {}); - - /** - * Construct the iframe. - * - * @memberof Parent.prototype - * @method _constructIframe - */ - this._constructIframe = function() { - // Calculate the width of this element. - var width = this.el.offsetWidth.toString(); - - // Create an iframe element attached to the document. - this.iframe = document.createElement('iframe'); - - // Save fragment id - var hash = ''; - var hashIndex = this.url.indexOf('#'); - - if (hashIndex > -1) { - hash = this.url.substring(hashIndex, this.url.length); - this.url = this.url.substring(0, hashIndex); - } - - // If the URL contains querystring bits, use them. - // Otherwise, just create a set of valid params. - if (this.url.indexOf('?') < 0) { - this.url += '?'; - } else { - this.url += '&'; - } - - // Append the initial width as a querystring parameter, and the fragment id - this.iframe.src = this.url + - 'initialWidth=' + width + - '&childId=' + this.id + - '&parentUrl=' + encodeURIComponent(window.location.href) + - hash; - - // Set some attributes to this proto-iframe. - this.iframe.setAttribute('width', '100%'); - this.iframe.setAttribute('scrolling', 'no'); - this.iframe.setAttribute('marginheight', '0'); - this.iframe.setAttribute('frameborder', '0'); - - if (this.settings.title) { - this.iframe.setAttribute('title', this.settings.title); - } - - // Append the iframe to our element. - this.el.appendChild(this.iframe); - - // Add an event listener that will handle redrawing the child on resize. - window.addEventListener('resize', this._onResize); - }; - - /** - * Send width on resize. - * - * @memberof Parent.prototype - * @method _onResize - */ - this._onResize = function() { - this.sendWidth(); - }.bind(this); - - /** - * Fire all event handlers for a given message type. - * - * @memberof Parent.prototype - * @method _fire - * @param {String} messageType The type of message. - * @param {String} message The message data. - */ - this._fire = function(messageType, message) { - if (messageType in this.messageHandlers) { - for (var i = 0; i < this.messageHandlers[messageType].length; i++) { - this.messageHandlers[messageType][i].call(this, message); - } - } - }; - - /** - * Remove this parent from the page and unbind it's event handlers. - * - * @memberof Parent.prototype - * @method remove - */ - this.remove = function() { - window.removeEventListener('message', this._processMessage); - window.removeEventListener('resize', this._onResize); - - this.el.removeChild(this.iframe); - }; - - /** - * @callback Parent~onMessageCallback - * @param {String} message The message data. - */ - - /** - * Process a new message from the child. - * - * @memberof Parent.prototype - * @method _processMessage - * @param {Event} e A message event. - */ - this._processMessage = function(e) { - // First, punt if this isn't from an acceptable xdomain. - if (!_isSafeMessage(e, this.settings)) { - return; - } - - // Discard object messages, we only care about strings - if (typeof e.data !== 'string') { - return; - } - - // Grab the message from the child and parse it. - var match = e.data.match(this.messageRegex); - - // If there's no match or too many matches in the message, punt. - if (!match || match.length !== 3) { - return false; - } - - var messageType = match[1]; - var message = match[2]; - - this._fire(messageType, message); - }.bind(this); - - /** - * Resize iframe in response to new height message from child. - * - * @memberof Parent.prototype - * @method _onHeightMessage - * @param {String} message The new height. - */ - this._onHeightMessage = function(message) { - /* - * Handle parent height message from child. - */ - var height = parseInt(message); - - this.iframe.setAttribute('height', height + 'px'); - }; - - /** - * Navigate parent to a new url. - * - * @memberof Parent.prototype - * @method _onNavigateToMessage - * @param {String} message The url to navigate to. - */ - this._onNavigateToMessage = function(message) { - /* - * Handle parent scroll message from child. - */ - document.location.href = message; - }; - - /** - * Bind a callback to a given messageType from the child. - * - * Reserved message names are: "height", "scrollTo" and "navigateTo". - * - * @memberof Parent.prototype - * @method onMessage - * @param {String} messageType The type of message being listened for. - * @param {Parent~onMessageCallback} callback The callback to invoke when a message of the given type is received. - */ - this.onMessage = function(messageType, callback) { - if (!(messageType in this.messageHandlers)) { - this.messageHandlers[messageType] = []; - } - - this.messageHandlers[messageType].push(callback); - }; - - /** - * Send a message to the the child. - * - * @memberof Parent.prototype - * @method sendMessage - * @param {String} messageType The type of message to send. - * @param {String} message The message data to send. - */ - this.sendMessage = function(messageType, message) { - this.el.getElementsByTagName('iframe')[0].contentWindow.postMessage(_makeMessage(this.id, messageType, message), '*'); - }; - - /** - * Transmit the current iframe width to the child. - * - * You shouldn't need to call this directly. - * - * @memberof Parent.prototype - * @method sendWidth - */ - this.sendWidth = function() { - var width = this.el.offsetWidth.toString(); - - this.sendMessage('width', width); - }; - - // Add any overrides to settings coming from config. - for (var key in config) { - this.settings[key] = config[key]; - } - - // Bind required message handlers - this.onMessage('height', this._onHeightMessage); - this.onMessage('navigateTo', this._onNavigateToMessage); - - // Add a listener for processing messages from the child. - window.addEventListener('message', this._processMessage, false); - - // Construct the iframe in the container element. - this._constructIframe(); - - return this; - }; - - /** - * The Child half of a responsive iframe. - * - * @class Child - * @param {Object} config Configuration to override the default settings. - */ - lib.Child = function(config) { - this.parentWidth = null; - this.id = null; - this.parentUrl = null; - - this.settings = { - renderCallback: null, - xdomain: '*', - polling: 0 - }; - - this.messageRegex = null; - this.messageHandlers = {}; - - // Ensure a config object - config = (config || {}); - - /** - * Bind a callback to a given messageType from the child. - * - * Reserved message names are: "width". - * - * @memberof Child.prototype - * @method onMessage - * @param {String} messageType The type of message being listened for. - * @param {Child~onMessageCallback} callback The callback to invoke when a message of the given type is received. - */ - this.onMessage = function(messageType, callback) { - if (!(messageType in this.messageHandlers)) { - this.messageHandlers[messageType] = []; - } - - this.messageHandlers[messageType].push(callback); - }; - - /** - * @callback Child~onMessageCallback - * @param {String} message The message data. - */ - - /** - * Fire all event handlers for a given message type. - * - * @memberof Parent.prototype - * @method _fire - * @param {String} messageType The type of message. - * @param {String} message The message data. - */ - this._fire = function(messageType, message) { - /* - * Fire all event handlers for a given message type. - */ - if (messageType in this.messageHandlers) { - for (var i = 0; i < this.messageHandlers[messageType].length; i++) { - this.messageHandlers[messageType][i].call(this, message); - } - } - }; - - /** - * Process a new message from the parent. - * - * @memberof Child.prototype - * @method _processMessage - * @param {Event} e A message event. - */ - this._processMessage = function(e) { - /* - * Process a new message from parent frame. - */ - // First, punt if this isn't from an acceptable xdomain. - if (!_isSafeMessage(e, this.settings)) { - return; - } - - // Discard object messages, we only care about strings - if (typeof e.data !== 'string') { - return; - } - - // Get the message from the parent. - var match = e.data.match(this.messageRegex); - - // If there's no match or it's a bad format, punt. - if (!match || match.length !== 3) { return; } - - var messageType = match[1]; - var message = match[2]; - - this._fire(messageType, message); - }.bind(this); - - /** - * Resize iframe in response to new width message from parent. - * - * @memberof Child.prototype - * @method _onWidthMessage - * @param {String} message The new width. - */ - this._onWidthMessage = function(message) { - /* - * Handle width message from the child. - */ - var width = parseInt(message); - - // Change the width if it's different. - if (width !== this.parentWidth) { - this.parentWidth = width; - - // Call the callback function if it exists. - if (this.settings.renderCallback) { - this.settings.renderCallback(width); - } - - // Send the height back to the parent. - this.sendHeight(); - } - }; - - /** - * Send a message to the the Parent. - * - * @memberof Child.prototype - * @method sendMessage - * @param {String} messageType The type of message to send. - * @param {String} message The message data to send. - */ - this.sendMessage = function(messageType, message) { - /* - * Send a message to the parent. - */ - window.parent.postMessage(_makeMessage(this.id, messageType, message), '*'); - }; - - /** - * Transmit the current iframe height to the parent. - * - * Call this directly in cases where you manually alter the height of the iframe contents. - * - * @memberof Child.prototype - * @method sendHeight - */ - this.sendHeight = function() { - // Get the child's height. - var height = document.getElementsByTagName('body')[0].offsetHeight.toString(); - - // Send the height to the parent. - this.sendMessage('height', height); - }.bind(this); - this.sendHeightToParent = function() { - // Get the child's height. - var height = document.getElementsByTagName('body')[0].offsetHeight.toString(); - - // Send the height to the parent. - this.sendMessage('height', height); - }.bind(this); - - /** - * Scroll parent to a given element id. - * - * @memberof Child.prototype - * @method scrollParentTo - * @param {String} hash The id of the element to scroll to. - */ - this.scrollParentTo = function(hash) { - this.sendMessage('navigateTo', '#' + hash); - }; - - /** - * Navigate parent to a given url. - * - * @memberof Parent.prototype - * @method navigateParentTo - * @param {String} url The url to navigate to. - */ - this.navigateParentTo = function(url) { - this.sendMessage('navigateTo', url); - }; - - // Identify what ID the parent knows this child as. - this.id = _getParameterByName('childId') || config.id; - this.messageRegex = new RegExp('^pym' + MESSAGE_DELIMITER + this.id + MESSAGE_DELIMITER + '(\\S+)' + MESSAGE_DELIMITER + '(.+)$'); - - // Get the initial width from a URL parameter. - var width = parseInt(_getParameterByName('initialWidth')); - - // Get the url of the parent frame - this.parentUrl = _getParameterByName('parentUrl'); - - // Bind the required message handlers - this.onMessage('width', this._onWidthMessage); - - // Initialize settings with overrides. - for (var key in config) { - this.settings[key] = config[key]; - } - - // Set up a listener to handle any incoming messages. - window.addEventListener('message', this._processMessage, false); - - // If there's a callback function, call it. - if (this.settings.renderCallback) { - this.settings.renderCallback(width); - } - - // Send the initial height to the parent. - this.sendHeight(); - - // If we're configured to poll, create a setInterval to handle that. - if (this.settings.polling) { - window.setInterval(this.sendHeight, this.settings.polling); - } - - return this; - }; - - // Initialize elements with pym data attributes - _autoInit(); - - return lib; + var MESSAGE_DELIMITER = 'xPYMx'; + + var lib = {}; + + /** + * Generic function for parsing URL params. + * Via http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript + * + * @method _getParameterByName + * @param {String} name The name of the paramter to get from the URL. + */ + var _getParameterByName = function(name) { + var regex = new RegExp("[\\?&]" + name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]') + '=([^&#]*)'); + var results = regex.exec(location.search); + + if (results === null) { + return ''; + } + + return decodeURIComponent(results[1].replace(/\+/g, " ")); + }; + + /** + * Check the message to make sure it comes from an acceptable xdomain. + * Defaults to '*' but can be overriden in config. + * + * @method _isSafeMessage + * @param {Event} e The message event. + * @param {Object} settings Configuration. + */ + var _isSafeMessage = function(e, settings) { + if (settings.xdomain !== '*') { + // If origin doesn't match our xdomain, return. + if (!e.origin.match(new RegExp(settings.xdomain + '$'))) { return; } + } + + return true; + }; + + /** + * Construct a message to send between frames. + * + * NB: We use string-building here because JSON message passing is + * not supported in all browsers. + * + * @method _makeMessage + * @param {String} id The unique id of the message recipient. + * @param {String} messageType The type of message to send. + * @param {String} message The message to send. + */ + var _makeMessage = function(id, messageType, message) { + var bits = ['pym', id, messageType, message]; + + return bits.join(MESSAGE_DELIMITER); + }; + + /** + * Construct a regex to validate and parse messages. + * + * @method _makeMessageRegex + * @param {String} id The unique id of the message recipient. + */ + var _makeMessageRegex = function(id) { + var bits = ['pym', id, '(\\S+)', '(.+)']; + + return new RegExp('^' + bits.join(MESSAGE_DELIMITER) + '$'); + }; + + /** + * Initialize Pym for elements on page that have data-pym attributes. + * + * @method _autoInit + */ + var _autoInit = function() { + var elements = document.querySelectorAll( + '[data-pym-src]:not([data-pym-auto-initialized])' + ); + + var length = elements.length; + + for (var idx = 0; idx < length; ++idx) { + var element = elements[idx]; + + /* + * Mark automatically-initialized elements so they are not + * re-initialized if the user includes pym.js more than once in the + * same document. + */ + element.setAttribute('data-pym-auto-initialized', ''); + + // Ensure elements have an id + if (element.id === '') { + element.id = 'pym-' + idx; + } + + var src = element.getAttribute('data-pym-src'); + var xdomain = element.getAttribute('data-pym-xdomain'); + var config = {}; + + if (xdomain) { + config.xdomain = xdomain; + } + + new lib.Parent(element.id, src, config); + } + }; + + /** + * The Parent half of a response iframe. + * + * @class Parent + * @param {String} id The id of the div into which the iframe will be rendered. + * @param {String} url The url of the iframe source. + * @param {Object} config Configuration to override the default settings. + */ + lib.Parent = function(id, url, config) { + this.id = id; + this.url = url; + this.el = document.getElementById(id); + this.iframe = null; + + this.settings = { + xdomain: '*' + }; + + this.messageRegex = _makeMessageRegex(this.id); + this.messageHandlers = {}; + + // ensure a config object + config = (config || {}); + + /** + * Construct the iframe. + * + * @memberof Parent.prototype + * @method _constructIframe + */ + this._constructIframe = function() { + // Calculate the width of this element. + var width = this.el.offsetWidth.toString(); + + // Create an iframe element attached to the document. + this.iframe = document.createElement('iframe'); + + // Save fragment id + var hash = ''; + var hashIndex = this.url.indexOf('#'); + + if (hashIndex > -1) { + hash = this.url.substring(hashIndex, this.url.length); + this.url = this.url.substring(0, hashIndex); + } + + // If the URL contains querystring bits, use them. + // Otherwise, just create a set of valid params. + if (this.url.indexOf('?') < 0) { + this.url += '?'; + } else { + this.url += '&'; + } + + // Append the initial width as a querystring parameter, and the fragment id + this.iframe.src = this.url + + 'initialWidth=' + width + + '&childId=' + this.id + + '&parentUrl=' + encodeURIComponent(window.location.href) + + hash; + + // Set some attributes to this proto-iframe. + this.iframe.setAttribute('width', '100%'); + this.iframe.setAttribute('scrolling', 'no'); + this.iframe.setAttribute('marginheight', '0'); + this.iframe.setAttribute('frameborder', '0'); + + if (this.settings.title) { + this.iframe.setAttribute('title', this.settings.title); + } + + // Append the iframe to our element. + this.el.appendChild(this.iframe); + + // Add an event listener that will handle redrawing the child on resize. + window.addEventListener('resize', this._onResize); + }; + + /** + * Send width on resize. + * + * @memberof Parent.prototype + * @method _onResize + */ + this._onResize = function() { + this.sendWidth(); + }.bind(this); + + /** + * Fire all event handlers for a given message type. + * + * @memberof Parent.prototype + * @method _fire + * @param {String} messageType The type of message. + * @param {String} message The message data. + */ + this._fire = function(messageType, message) { + if (messageType in this.messageHandlers) { + for (var i = 0; i < this.messageHandlers[messageType].length; i++) { + this.messageHandlers[messageType][i].call(this, message); + } + } + }; + + /** + * Remove this parent from the page and unbind it's event handlers. + * + * @memberof Parent.prototype + * @method remove + */ + this.remove = function() { + window.removeEventListener('message', this._processMessage); + window.removeEventListener('resize', this._onResize); + + this.el.removeChild(this.iframe); + }; + + /** + * @callback Parent~onMessageCallback + * @param {String} message The message data. + */ + + /** + * Process a new message from the child. + * + * @memberof Parent.prototype + * @method _processMessage + * @param {Event} e A message event. + */ + this._processMessage = function(e) { + // First, punt if this isn't from an acceptable xdomain. + if (!_isSafeMessage(e, this.settings)) { + return; + } + + // Discard object messages, we only care about strings + if (typeof e.data !== 'string') { + return; + } + + // Grab the message from the child and parse it. + var match = e.data.match(this.messageRegex); + + // If there's no match or too many matches in the message, punt. + if (!match || match.length !== 3) { + return false; + } + + var messageType = match[1]; + var message = match[2]; + + this._fire(messageType, message); + }.bind(this); + + /** + * Resize iframe in response to new height message from child. + * + * @memberof Parent.prototype + * @method _onHeightMessage + * @param {String} message The new height. + */ + this._onHeightMessage = function(message) { + /* + * Handle parent height message from child. + */ + var height = parseInt(message); + + this.iframe.setAttribute('height', height + 'px'); + }; + + /** + * Navigate parent to a new url. + * + * @memberof Parent.prototype + * @method _onNavigateToMessage + * @param {String} message The url to navigate to. + */ + this._onNavigateToMessage = function(message) { + /* + * Handle parent scroll message from child. + */ + document.location.href = message; + }; + + /** + * Bind a callback to a given messageType from the child. + * + * Reserved message names are: "height", "scrollTo" and "navigateTo". + * + * @memberof Parent.prototype + * @method onMessage + * @param {String} messageType The type of message being listened for. + * @param {Parent~onMessageCallback} callback The callback to invoke when a message of the given type is received. + */ + this.onMessage = function(messageType, callback) { + if (!(messageType in this.messageHandlers)) { + this.messageHandlers[messageType] = []; + } + + this.messageHandlers[messageType].push(callback); + }; + + /** + * Send a message to the the child. + * + * @memberof Parent.prototype + * @method sendMessage + * @param {String} messageType The type of message to send. + * @param {String} message The message data to send. + */ + this.sendMessage = function(messageType, message) { + this.el.getElementsByTagName('iframe')[0].contentWindow.postMessage(_makeMessage(this.id, messageType, message), '*'); + }; + + /** + * Transmit the current iframe width to the child. + * + * You shouldn't need to call this directly. + * + * @memberof Parent.prototype + * @method sendWidth + */ + this.sendWidth = function() { + var width = this.el.offsetWidth.toString(); + + this.sendMessage('width', width); + }; + + // Add any overrides to settings coming from config. + for (var key in config) { + this.settings[key] = config[key]; + } + + // Bind required message handlers + this.onMessage('height', this._onHeightMessage); + this.onMessage('navigateTo', this._onNavigateToMessage); + + // Add a listener for processing messages from the child. + window.addEventListener('message', this._processMessage, false); + + // Construct the iframe in the container element. + this._constructIframe(); + + return this; + }; + + /** + * The Child half of a responsive iframe. + * + * @class Child + * @param {Object} config Configuration to override the default settings. + */ + lib.Child = function(config) { + this.parentWidth = null; + this.id = null; + this.parentUrl = null; + + this.settings = { + renderCallback: null, + xdomain: '*', + polling: 0 + }; + + this.messageRegex = null; + this.messageHandlers = {}; + + // Ensure a config object + config = (config || {}); + + /** + * Bind a callback to a given messageType from the child. + * + * Reserved message names are: "width". + * + * @memberof Child.prototype + * @method onMessage + * @param {String} messageType The type of message being listened for. + * @param {Child~onMessageCallback} callback The callback to invoke when a message of the given type is received. + */ + this.onMessage = function(messageType, callback) { + if (!(messageType in this.messageHandlers)) { + this.messageHandlers[messageType] = []; + } + + this.messageHandlers[messageType].push(callback); + }; + + /** + * @callback Child~onMessageCallback + * @param {String} message The message data. + */ + + /** + * Fire all event handlers for a given message type. + * + * @memberof Parent.prototype + * @method _fire + * @param {String} messageType The type of message. + * @param {String} message The message data. + */ + this._fire = function(messageType, message) { + /* + * Fire all event handlers for a given message type. + */ + if (messageType in this.messageHandlers) { + for (var i = 0; i < this.messageHandlers[messageType].length; i++) { + this.messageHandlers[messageType][i].call(this, message); + } + } + }; + + /** + * Process a new message from the parent. + * + * @memberof Child.prototype + * @method _processMessage + * @param {Event} e A message event. + */ + this._processMessage = function(e) { + /* + * Process a new message from parent frame. + */ + // First, punt if this isn't from an acceptable xdomain. + if (!_isSafeMessage(e, this.settings)) { + return; + } + + // Discard object messages, we only care about strings + if (typeof e.data !== 'string') { + return; + } + + // Get the message from the parent. + var match = e.data.match(this.messageRegex); + + // If there's no match or it's a bad format, punt. + if (!match || match.length !== 3) { return; } + + var messageType = match[1]; + var message = match[2]; + + this._fire(messageType, message); + }.bind(this); + + /** + * Resize iframe in response to new width message from parent. + * + * @memberof Child.prototype + * @method _onWidthMessage + * @param {String} message The new width. + */ + this._onWidthMessage = function(message) { + /* + * Handle width message from the child. + */ + var width = parseInt(message); + + // Change the width if it's different. + if (width !== this.parentWidth) { + this.parentWidth = width; + + // Call the callback function if it exists. + if (this.settings.renderCallback) { + this.settings.renderCallback(width); + } + + // Send the height back to the parent. + this.sendHeight(); + } + }; + + /** + * Send a message to the the Parent. + * + * @memberof Child.prototype + * @method sendMessage + * @param {String} messageType The type of message to send. + * @param {String} message The message data to send. + */ + this.sendMessage = function(messageType, message) { + /* + * Send a message to the parent. + */ + window.parent.postMessage(_makeMessage(this.id, messageType, message), '*'); + }; + + /** + * Transmit the current iframe height to the parent. + * + * Call this directly in cases where you manually alter the height of the iframe contents. + * + * @memberof Child.prototype + * @method sendHeight + */ + this.sendHeight = function() { + // Get the child's height. + var height = document.getElementsByTagName('body')[0].offsetHeight.toString(); + + // Send the height to the parent. + this.sendMessage('height', height); + }.bind(this); + this.sendHeightToParent = function() { + // Get the child's height. + var height = document.getElementsByTagName('body')[0].offsetHeight.toString(); + + // Send the height to the parent. + this.sendMessage('height', height); + }.bind(this); + + /** + * Scroll parent to a given element id. + * + * @memberof Child.prototype + * @method scrollParentTo + * @param {String} hash The id of the element to scroll to. + */ + this.scrollParentTo = function(hash) { + this.sendMessage('navigateTo', '#' + hash); + }; + + /** + * Navigate parent to a given url. + * + * @memberof Parent.prototype + * @method navigateParentTo + * @param {String} url The url to navigate to. + */ + this.navigateParentTo = function(url) { + this.sendMessage('navigateTo', url); + }; + + // Identify what ID the parent knows this child as. + this.id = _getParameterByName('childId') || config.id; + this.messageRegex = new RegExp('^pym' + MESSAGE_DELIMITER + this.id + MESSAGE_DELIMITER + '(\\S+)' + MESSAGE_DELIMITER + '(.+)$'); + + // Get the initial width from a URL parameter. + var width = parseInt(_getParameterByName('initialWidth')); + + // Get the url of the parent frame + this.parentUrl = _getParameterByName('parentUrl'); + + // Bind the required message handlers + this.onMessage('width', this._onWidthMessage); + + // Initialize settings with overrides. + for (var key in config) { + this.settings[key] = config[key]; + } + + // Set up a listener to handle any incoming messages. + window.addEventListener('message', this._processMessage, false); + + // If there's a callback function, call it. + if (this.settings.renderCallback) { + this.settings.renderCallback(width); + } + + // Send the initial height to the parent. + this.sendHeight(); + + // If we're configured to poll, create a setInterval to handle that. + if (this.settings.polling) { + window.setInterval(this.sendHeight, this.settings.polling); + } + + return this; + }; + + // Initialize elements with pym data attributes + _autoInit(); + + return lib; }); From 524dc9958b5b622d4f84e7f964dc31ab5ed35ed1 Mon Sep 17 00:00:00 2001 From: hassanelnajjar Date: Mon, 14 Jun 2021 18:02:28 +0300 Subject: [PATCH 5/6] fix indentaion of pym.js --- js/pym.js | 1032 ++++++++++++++++++++++++++--------------------------- 1 file changed, 516 insertions(+), 516 deletions(-) diff --git a/js/pym.js b/js/pym.js index 22ef50d..7aa2dda 100644 --- a/js/pym.js +++ b/js/pym.js @@ -7,11 +7,11 @@ (function(factory) { if (typeof define === 'function' && define.amd) { - define(factory); + define(factory); } else if (typeof module !== 'undefined' && module.exports) { - module.exports = factory(); + module.exports = factory(); } else { - window.pym = factory.call(this); + window.pym = factory.call(this); } })(function() { var MESSAGE_DELIMITER = 'xPYMx'; @@ -26,567 +26,567 @@ * @param {String} name The name of the paramter to get from the URL. */ var _getParameterByName = function(name) { - var regex = new RegExp("[\\?&]" + name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]') + '=([^&#]*)'); - var results = regex.exec(location.search); + var regex = new RegExp("[\\?&]" + name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]') + '=([^&#]*)'); + var results = regex.exec(location.search); - if (results === null) { - return ''; - } + if (results === null) { + return ''; + } - return decodeURIComponent(results[1].replace(/\+/g, " ")); + return decodeURIComponent(results[1].replace(/\+/g, " ")); }; /** - * Check the message to make sure it comes from an acceptable xdomain. - * Defaults to '*' but can be overriden in config. - * - * @method _isSafeMessage - * @param {Event} e The message event. - * @param {Object} settings Configuration. - */ + * Check the message to make sure it comes from an acceptable xdomain. + * Defaults to '*' but can be overriden in config. + * + * @method _isSafeMessage + * @param {Event} e The message event. + * @param {Object} settings Configuration. + */ var _isSafeMessage = function(e, settings) { - if (settings.xdomain !== '*') { - // If origin doesn't match our xdomain, return. - if (!e.origin.match(new RegExp(settings.xdomain + '$'))) { return; } - } + if (settings.xdomain !== '*') { + // If origin doesn't match our xdomain, return. + if (!e.origin.match(new RegExp(settings.xdomain + '$'))) { return; } + } - return true; + return true; }; /** - * Construct a message to send between frames. - * - * NB: We use string-building here because JSON message passing is - * not supported in all browsers. - * - * @method _makeMessage - * @param {String} id The unique id of the message recipient. - * @param {String} messageType The type of message to send. - * @param {String} message The message to send. - */ + * Construct a message to send between frames. + * + * NB: We use string-building here because JSON message passing is + * not supported in all browsers. + * + * @method _makeMessage + * @param {String} id The unique id of the message recipient. + * @param {String} messageType The type of message to send. + * @param {String} message The message to send. + */ var _makeMessage = function(id, messageType, message) { - var bits = ['pym', id, messageType, message]; + var bits = ['pym', id, messageType, message]; - return bits.join(MESSAGE_DELIMITER); + return bits.join(MESSAGE_DELIMITER); }; /** - * Construct a regex to validate and parse messages. - * - * @method _makeMessageRegex - * @param {String} id The unique id of the message recipient. - */ + * Construct a regex to validate and parse messages. + * + * @method _makeMessageRegex + * @param {String} id The unique id of the message recipient. + */ var _makeMessageRegex = function(id) { - var bits = ['pym', id, '(\\S+)', '(.+)']; + var bits = ['pym', id, '(\\S+)', '(.+)']; - return new RegExp('^' + bits.join(MESSAGE_DELIMITER) + '$'); + return new RegExp('^' + bits.join(MESSAGE_DELIMITER) + '$'); }; /** - * Initialize Pym for elements on page that have data-pym attributes. - * - * @method _autoInit - */ + * Initialize Pym for elements on page that have data-pym attributes. + * + * @method _autoInit + */ var _autoInit = function() { - var elements = document.querySelectorAll( - '[data-pym-src]:not([data-pym-auto-initialized])' - ); - - var length = elements.length; + var elements = document.querySelectorAll( + '[data-pym-src]:not([data-pym-auto-initialized])' + ); - for (var idx = 0; idx < length; ++idx) { - var element = elements[idx]; + var length = elements.length; - /* - * Mark automatically-initialized elements so they are not - * re-initialized if the user includes pym.js more than once in the - * same document. - */ - element.setAttribute('data-pym-auto-initialized', ''); + for (var idx = 0; idx < length; ++idx) { + var element = elements[idx]; - // Ensure elements have an id - if (element.id === '') { - element.id = 'pym-' + idx; - } + /* + * Mark automatically-initialized elements so they are not + * re-initialized if the user includes pym.js more than once in the + * same document. + */ + element.setAttribute('data-pym-auto-initialized', ''); - var src = element.getAttribute('data-pym-src'); - var xdomain = element.getAttribute('data-pym-xdomain'); - var config = {}; + // Ensure elements have an id + if (element.id === '') { + element.id = 'pym-' + idx; + } - if (xdomain) { - config.xdomain = xdomain; - } + var src = element.getAttribute('data-pym-src'); + var xdomain = element.getAttribute('data-pym-xdomain'); + var config = {}; - new lib.Parent(element.id, src, config); + if (xdomain) { + config.xdomain = xdomain; } + + new lib.Parent(element.id, src, config); + } }; /** - * The Parent half of a response iframe. - * - * @class Parent - * @param {String} id The id of the div into which the iframe will be rendered. - * @param {String} url The url of the iframe source. - * @param {Object} config Configuration to override the default settings. - */ + * The Parent half of a response iframe. + * + * @class Parent + * @param {String} id The id of the div into which the iframe will be rendered. + * @param {String} url The url of the iframe source. + * @param {Object} config Configuration to override the default settings. + */ lib.Parent = function(id, url, config) { - this.id = id; - this.url = url; - this.el = document.getElementById(id); - this.iframe = null; - - this.settings = { - xdomain: '*' - }; - - this.messageRegex = _makeMessageRegex(this.id); - this.messageHandlers = {}; - - // ensure a config object - config = (config || {}); - - /** - * Construct the iframe. - * - * @memberof Parent.prototype - * @method _constructIframe - */ - this._constructIframe = function() { - // Calculate the width of this element. - var width = this.el.offsetWidth.toString(); - - // Create an iframe element attached to the document. - this.iframe = document.createElement('iframe'); - - // Save fragment id - var hash = ''; - var hashIndex = this.url.indexOf('#'); - - if (hashIndex > -1) { - hash = this.url.substring(hashIndex, this.url.length); - this.url = this.url.substring(0, hashIndex); - } - - // If the URL contains querystring bits, use them. - // Otherwise, just create a set of valid params. - if (this.url.indexOf('?') < 0) { - this.url += '?'; - } else { - this.url += '&'; - } - - // Append the initial width as a querystring parameter, and the fragment id - this.iframe.src = this.url + - 'initialWidth=' + width + - '&childId=' + this.id + - '&parentUrl=' + encodeURIComponent(window.location.href) + - hash; - - // Set some attributes to this proto-iframe. - this.iframe.setAttribute('width', '100%'); - this.iframe.setAttribute('scrolling', 'no'); - this.iframe.setAttribute('marginheight', '0'); - this.iframe.setAttribute('frameborder', '0'); - - if (this.settings.title) { - this.iframe.setAttribute('title', this.settings.title); - } - - // Append the iframe to our element. - this.el.appendChild(this.iframe); - - // Add an event listener that will handle redrawing the child on resize. - window.addEventListener('resize', this._onResize); - }; - - /** - * Send width on resize. - * - * @memberof Parent.prototype - * @method _onResize - */ - this._onResize = function() { - this.sendWidth(); - }.bind(this); - - /** - * Fire all event handlers for a given message type. - * - * @memberof Parent.prototype - * @method _fire - * @param {String} messageType The type of message. - * @param {String} message The message data. - */ - this._fire = function(messageType, message) { - if (messageType in this.messageHandlers) { - for (var i = 0; i < this.messageHandlers[messageType].length; i++) { - this.messageHandlers[messageType][i].call(this, message); - } - } - }; - - /** - * Remove this parent from the page and unbind it's event handlers. - * - * @memberof Parent.prototype - * @method remove - */ - this.remove = function() { - window.removeEventListener('message', this._processMessage); - window.removeEventListener('resize', this._onResize); - - this.el.removeChild(this.iframe); - }; - - /** - * @callback Parent~onMessageCallback - * @param {String} message The message data. - */ - - /** - * Process a new message from the child. - * - * @memberof Parent.prototype - * @method _processMessage - * @param {Event} e A message event. - */ - this._processMessage = function(e) { - // First, punt if this isn't from an acceptable xdomain. - if (!_isSafeMessage(e, this.settings)) { - return; - } - - // Discard object messages, we only care about strings - if (typeof e.data !== 'string') { - return; - } - - // Grab the message from the child and parse it. - var match = e.data.match(this.messageRegex); - - // If there's no match or too many matches in the message, punt. - if (!match || match.length !== 3) { - return false; - } - - var messageType = match[1]; - var message = match[2]; - - this._fire(messageType, message); - }.bind(this); - - /** - * Resize iframe in response to new height message from child. - * - * @memberof Parent.prototype - * @method _onHeightMessage - * @param {String} message The new height. - */ - this._onHeightMessage = function(message) { - /* - * Handle parent height message from child. - */ - var height = parseInt(message); - - this.iframe.setAttribute('height', height + 'px'); - }; - - /** - * Navigate parent to a new url. - * - * @memberof Parent.prototype - * @method _onNavigateToMessage - * @param {String} message The url to navigate to. - */ - this._onNavigateToMessage = function(message) { - /* - * Handle parent scroll message from child. - */ - document.location.href = message; - }; - - /** - * Bind a callback to a given messageType from the child. - * - * Reserved message names are: "height", "scrollTo" and "navigateTo". - * - * @memberof Parent.prototype - * @method onMessage - * @param {String} messageType The type of message being listened for. - * @param {Parent~onMessageCallback} callback The callback to invoke when a message of the given type is received. - */ - this.onMessage = function(messageType, callback) { - if (!(messageType in this.messageHandlers)) { - this.messageHandlers[messageType] = []; - } - - this.messageHandlers[messageType].push(callback); - }; - - /** - * Send a message to the the child. - * - * @memberof Parent.prototype - * @method sendMessage - * @param {String} messageType The type of message to send. - * @param {String} message The message data to send. - */ - this.sendMessage = function(messageType, message) { - this.el.getElementsByTagName('iframe')[0].contentWindow.postMessage(_makeMessage(this.id, messageType, message), '*'); - }; - - /** - * Transmit the current iframe width to the child. - * - * You shouldn't need to call this directly. - * - * @memberof Parent.prototype - * @method sendWidth - */ - this.sendWidth = function() { - var width = this.el.offsetWidth.toString(); - - this.sendMessage('width', width); - }; - - // Add any overrides to settings coming from config. - for (var key in config) { - this.settings[key] = config[key]; + this.id = id; + this.url = url; + this.el = document.getElementById(id); + this.iframe = null; + + this.settings = { + xdomain: '*' + }; + + this.messageRegex = _makeMessageRegex(this.id); + this.messageHandlers = {}; + + // ensure a config object + config = (config || {}); + + /** + * Construct the iframe. + * + * @memberof Parent.prototype + * @method _constructIframe + */ + this._constructIframe = function() { + // Calculate the width of this element. + var width = this.el.offsetWidth.toString(); + + // Create an iframe element attached to the document. + this.iframe = document.createElement('iframe'); + + // Save fragment id + var hash = ''; + var hashIndex = this.url.indexOf('#'); + + if (hashIndex > -1) { + hash = this.url.substring(hashIndex, this.url.length); + this.url = this.url.substring(0, hashIndex); } - // Bind required message handlers - this.onMessage('height', this._onHeightMessage); - this.onMessage('navigateTo', this._onNavigateToMessage); + // If the URL contains querystring bits, use them. + // Otherwise, just create a set of valid params. + if (this.url.indexOf('?') < 0) { + this.url += '?'; + } else { + this.url += '&'; + } - // Add a listener for processing messages from the child. - window.addEventListener('message', this._processMessage, false); + // Append the initial width as a querystring parameter, and the fragment id + this.iframe.src = this.url + + 'initialWidth=' + width + + '&childId=' + this.id + + '&parentUrl=' + encodeURIComponent(window.location.href) + + hash; + + // Set some attributes to this proto-iframe. + this.iframe.setAttribute('width', '100%'); + this.iframe.setAttribute('scrolling', 'no'); + this.iframe.setAttribute('marginheight', '0'); + this.iframe.setAttribute('frameborder', '0'); + + if (this.settings.title) { + this.iframe.setAttribute('title', this.settings.title); + } - // Construct the iframe in the container element. - this._constructIframe(); + // Append the iframe to our element. + this.el.appendChild(this.iframe); + + // Add an event listener that will handle redrawing the child on resize. + window.addEventListener('resize', this._onResize); + }; + + /** + * Send width on resize. + * + * @memberof Parent.prototype + * @method _onResize + */ + this._onResize = function() { + this.sendWidth(); + }.bind(this); + + /** + * Fire all event handlers for a given message type. + * + * @memberof Parent.prototype + * @method _fire + * @param {String} messageType The type of message. + * @param {String} message The message data. + */ + this._fire = function(messageType, message) { + if (messageType in this.messageHandlers) { + for (var i = 0; i < this.messageHandlers[messageType].length; i++) { + this.messageHandlers[messageType][i].call(this, message); + } + } + }; + + /** + * Remove this parent from the page and unbind it's event handlers. + * + * @memberof Parent.prototype + * @method remove + */ + this.remove = function() { + window.removeEventListener('message', this._processMessage); + window.removeEventListener('resize', this._onResize); + + this.el.removeChild(this.iframe); + }; + + /** + * @callback Parent~onMessageCallback + * @param {String} message The message data. + */ + + /** + * Process a new message from the child. + * + * @memberof Parent.prototype + * @method _processMessage + * @param {Event} e A message event. + */ + this._processMessage = function(e) { + // First, punt if this isn't from an acceptable xdomain. + if (!_isSafeMessage(e, this.settings)) { + return; + } + + // Discard object messages, we only care about strings + if (typeof e.data !== 'string') { + return; + } - return this; + // Grab the message from the child and parse it. + var match = e.data.match(this.messageRegex); + + // If there's no match or too many matches in the message, punt. + if (!match || match.length !== 3) { + return false; + } + + var messageType = match[1]; + var message = match[2]; + + this._fire(messageType, message); + }.bind(this); + + /** + * Resize iframe in response to new height message from child. + * + * @memberof Parent.prototype + * @method _onHeightMessage + * @param {String} message The new height. + */ + this._onHeightMessage = function(message) { + /* + * Handle parent height message from child. + */ + var height = parseInt(message); + + this.iframe.setAttribute('height', height + 'px'); + }; + + /** + * Navigate parent to a new url. + * + * @memberof Parent.prototype + * @method _onNavigateToMessage + * @param {String} message The url to navigate to. + */ + this._onNavigateToMessage = function(message) { + /* + * Handle parent scroll message from child. + */ + document.location.href = message; + }; + + /** + * Bind a callback to a given messageType from the child. + * + * Reserved message names are: "height", "scrollTo" and "navigateTo". + * + * @memberof Parent.prototype + * @method onMessage + * @param {String} messageType The type of message being listened for. + * @param {Parent~onMessageCallback} callback The callback to invoke when a message of the given type is received. + */ + this.onMessage = function(messageType, callback) { + if (!(messageType in this.messageHandlers)) { + this.messageHandlers[messageType] = []; + } + + this.messageHandlers[messageType].push(callback); + }; + + /** + * Send a message to the the child. + * + * @memberof Parent.prototype + * @method sendMessage + * @param {String} messageType The type of message to send. + * @param {String} message The message data to send. + */ + this.sendMessage = function(messageType, message) { + this.el.getElementsByTagName('iframe')[0].contentWindow.postMessage(_makeMessage(this.id, messageType, message), '*'); + }; + + /** + * Transmit the current iframe width to the child. + * + * You shouldn't need to call this directly. + * + * @memberof Parent.prototype + * @method sendWidth + */ + this.sendWidth = function() { + var width = this.el.offsetWidth.toString(); + + this.sendMessage('width', width); + }; + + // Add any overrides to settings coming from config. + for (var key in config) { + this.settings[key] = config[key]; + } + + // Bind required message handlers + this.onMessage('height', this._onHeightMessage); + this.onMessage('navigateTo', this._onNavigateToMessage); + + // Add a listener for processing messages from the child. + window.addEventListener('message', this._processMessage, false); + + // Construct the iframe in the container element. + this._constructIframe(); + + return this; }; /** - * The Child half of a responsive iframe. - * - * @class Child - * @param {Object} config Configuration to override the default settings. - */ + * The Child half of a responsive iframe. + * + * @class Child + * @param {Object} config Configuration to override the default settings. + */ lib.Child = function(config) { - this.parentWidth = null; - this.id = null; - this.parentUrl = null; - - this.settings = { - renderCallback: null, - xdomain: '*', - polling: 0 - }; - - this.messageRegex = null; - this.messageHandlers = {}; - - // Ensure a config object - config = (config || {}); - - /** - * Bind a callback to a given messageType from the child. - * - * Reserved message names are: "width". - * - * @memberof Child.prototype - * @method onMessage - * @param {String} messageType The type of message being listened for. - * @param {Child~onMessageCallback} callback The callback to invoke when a message of the given type is received. - */ - this.onMessage = function(messageType, callback) { - if (!(messageType in this.messageHandlers)) { - this.messageHandlers[messageType] = []; - } - - this.messageHandlers[messageType].push(callback); - }; - - /** - * @callback Child~onMessageCallback - * @param {String} message The message data. - */ - - /** - * Fire all event handlers for a given message type. - * - * @memberof Parent.prototype - * @method _fire - * @param {String} messageType The type of message. - * @param {String} message The message data. - */ - this._fire = function(messageType, message) { - /* - * Fire all event handlers for a given message type. - */ - if (messageType in this.messageHandlers) { - for (var i = 0; i < this.messageHandlers[messageType].length; i++) { - this.messageHandlers[messageType][i].call(this, message); - } - } - }; - - /** - * Process a new message from the parent. - * - * @memberof Child.prototype - * @method _processMessage - * @param {Event} e A message event. - */ - this._processMessage = function(e) { - /* - * Process a new message from parent frame. - */ - // First, punt if this isn't from an acceptable xdomain. - if (!_isSafeMessage(e, this.settings)) { - return; - } - - // Discard object messages, we only care about strings - if (typeof e.data !== 'string') { - return; - } - - // Get the message from the parent. - var match = e.data.match(this.messageRegex); - - // If there's no match or it's a bad format, punt. - if (!match || match.length !== 3) { return; } - - var messageType = match[1]; - var message = match[2]; - - this._fire(messageType, message); - }.bind(this); - - /** - * Resize iframe in response to new width message from parent. - * - * @memberof Child.prototype - * @method _onWidthMessage - * @param {String} message The new width. - */ - this._onWidthMessage = function(message) { - /* - * Handle width message from the child. - */ - var width = parseInt(message); - - // Change the width if it's different. - if (width !== this.parentWidth) { - this.parentWidth = width; - - // Call the callback function if it exists. - if (this.settings.renderCallback) { - this.settings.renderCallback(width); - } - - // Send the height back to the parent. - this.sendHeight(); - } - }; - - /** - * Send a message to the the Parent. - * - * @memberof Child.prototype - * @method sendMessage - * @param {String} messageType The type of message to send. - * @param {String} message The message data to send. - */ - this.sendMessage = function(messageType, message) { - /* - * Send a message to the parent. - */ - window.parent.postMessage(_makeMessage(this.id, messageType, message), '*'); - }; - - /** - * Transmit the current iframe height to the parent. - * - * Call this directly in cases where you manually alter the height of the iframe contents. - * - * @memberof Child.prototype - * @method sendHeight - */ - this.sendHeight = function() { - // Get the child's height. - var height = document.getElementsByTagName('body')[0].offsetHeight.toString(); - - // Send the height to the parent. - this.sendMessage('height', height); - }.bind(this); - this.sendHeightToParent = function() { - // Get the child's height. - var height = document.getElementsByTagName('body')[0].offsetHeight.toString(); - - // Send the height to the parent. - this.sendMessage('height', height); - }.bind(this); - - /** - * Scroll parent to a given element id. - * - * @memberof Child.prototype - * @method scrollParentTo - * @param {String} hash The id of the element to scroll to. - */ - this.scrollParentTo = function(hash) { - this.sendMessage('navigateTo', '#' + hash); - }; - - /** - * Navigate parent to a given url. - * - * @memberof Parent.prototype - * @method navigateParentTo - * @param {String} url The url to navigate to. - */ - this.navigateParentTo = function(url) { - this.sendMessage('navigateTo', url); - }; - - // Identify what ID the parent knows this child as. - this.id = _getParameterByName('childId') || config.id; - this.messageRegex = new RegExp('^pym' + MESSAGE_DELIMITER + this.id + MESSAGE_DELIMITER + '(\\S+)' + MESSAGE_DELIMITER + '(.+)$'); - - // Get the initial width from a URL parameter. - var width = parseInt(_getParameterByName('initialWidth')); - - // Get the url of the parent frame - this.parentUrl = _getParameterByName('parentUrl'); - - // Bind the required message handlers - this.onMessage('width', this._onWidthMessage); - - // Initialize settings with overrides. - for (var key in config) { - this.settings[key] = config[key]; + this.parentWidth = null; + this.id = null; + this.parentUrl = null; + + this.settings = { + renderCallback: null, + xdomain: '*', + polling: 0 + }; + + this.messageRegex = null; + this.messageHandlers = {}; + + // Ensure a config object + config = (config || {}); + + /** + * Bind a callback to a given messageType from the child. + * + * Reserved message names are: "width". + * + * @memberof Child.prototype + * @method onMessage + * @param {String} messageType The type of message being listened for. + * @param {Child~onMessageCallback} callback The callback to invoke when a message of the given type is received. + */ + this.onMessage = function(messageType, callback) { + if (!(messageType in this.messageHandlers)) { + this.messageHandlers[messageType] = []; } - // Set up a listener to handle any incoming messages. - window.addEventListener('message', this._processMessage, false); + this.messageHandlers[messageType].push(callback); + }; + + /** + * @callback Child~onMessageCallback + * @param {String} message The message data. + */ + + /** + * Fire all event handlers for a given message type. + * + * @memberof Parent.prototype + * @method _fire + * @param {String} messageType The type of message. + * @param {String} message The message data. + */ + this._fire = function(messageType, message) { + /* + * Fire all event handlers for a given message type. + */ + if (messageType in this.messageHandlers) { + for (var i = 0; i < this.messageHandlers[messageType].length; i++) { + this.messageHandlers[messageType][i].call(this, message); + } + } + }; + + /** + * Process a new message from the parent. + * + * @memberof Child.prototype + * @method _processMessage + * @param {Event} e A message event. + */ + this._processMessage = function(e) { + /* + * Process a new message from parent frame. + */ + // First, punt if this isn't from an acceptable xdomain. + if (!_isSafeMessage(e, this.settings)) { + return; + } - // If there's a callback function, call it. - if (this.settings.renderCallback) { - this.settings.renderCallback(width); + // Discard object messages, we only care about strings + if (typeof e.data !== 'string') { + return; } - // Send the initial height to the parent. - this.sendHeight(); + // Get the message from the parent. + var match = e.data.match(this.messageRegex); + + // If there's no match or it's a bad format, punt. + if (!match || match.length !== 3) { return; } + + var messageType = match[1]; + var message = match[2]; + + this._fire(messageType, message); + }.bind(this); + + /** + * Resize iframe in response to new width message from parent. + * + * @memberof Child.prototype + * @method _onWidthMessage + * @param {String} message The new width. + */ + this._onWidthMessage = function(message) { + /* + * Handle width message from the child. + */ + var width = parseInt(message); + + // Change the width if it's different. + if (width !== this.parentWidth) { + this.parentWidth = width; + + // Call the callback function if it exists. + if (this.settings.renderCallback) { + this.settings.renderCallback(width); + } - // If we're configured to poll, create a setInterval to handle that. - if (this.settings.polling) { - window.setInterval(this.sendHeight, this.settings.polling); + // Send the height back to the parent. + this.sendHeight(); } - - return this; + }; + + /** + * Send a message to the the Parent. + * + * @memberof Child.prototype + * @method sendMessage + * @param {String} messageType The type of message to send. + * @param {String} message The message data to send. + */ + this.sendMessage = function(messageType, message) { + /* + * Send a message to the parent. + */ + window.parent.postMessage(_makeMessage(this.id, messageType, message), '*'); + }; + + /** + * Transmit the current iframe height to the parent. + * + * Call this directly in cases where you manually alter the height of the iframe contents. + * + * @memberof Child.prototype + * @method sendHeight + */ + this.sendHeight = function() { + // Get the child's height. + var height = document.getElementsByTagName('body')[0].offsetHeight.toString(); + + // Send the height to the parent. + this.sendMessage('height', height); + }.bind(this); + this.sendHeightToParent = function() { + // Get the child's height. + var height = document.getElementsByTagName('body')[0].offsetHeight.toString(); + + // Send the height to the parent. + this.sendMessage('height', height); + }.bind(this); + + /** + * Scroll parent to a given element id. + * + * @memberof Child.prototype + * @method scrollParentTo + * @param {String} hash The id of the element to scroll to. + */ + this.scrollParentTo = function(hash) { + this.sendMessage('navigateTo', '#' + hash); + }; + + /** + * Navigate parent to a given url. + * + * @memberof Parent.prototype + * @method navigateParentTo + * @param {String} url The url to navigate to. + */ + this.navigateParentTo = function(url) { + this.sendMessage('navigateTo', url); + }; + + // Identify what ID the parent knows this child as. + this.id = _getParameterByName('childId') || config.id; + this.messageRegex = new RegExp('^pym' + MESSAGE_DELIMITER + this.id + MESSAGE_DELIMITER + '(\\S+)' + MESSAGE_DELIMITER + '(.+)$'); + + // Get the initial width from a URL parameter. + var width = parseInt(_getParameterByName('initialWidth')); + + // Get the url of the parent frame + this.parentUrl = _getParameterByName('parentUrl'); + + // Bind the required message handlers + this.onMessage('width', this._onWidthMessage); + + // Initialize settings with overrides. + for (var key in config) { + this.settings[key] = config[key]; + } + + // Set up a listener to handle any incoming messages. + window.addEventListener('message', this._processMessage, false); + + // If there's a callback function, call it. + if (this.settings.renderCallback) { + this.settings.renderCallback(width); + } + + // Send the initial height to the parent. + this.sendHeight(); + + // If we're configured to poll, create a setInterval to handle that. + if (this.settings.polling) { + window.setInterval(this.sendHeight, this.settings.polling); + } + + return this; }; // Initialize elements with pym data attributes From 884fd107f082abc55378505329d58f7d3a770513 Mon Sep 17 00:00:00 2001 From: hassanelnajjar Date: Mon, 14 Jun 2021 18:04:09 +0300 Subject: [PATCH 6/6] fix http to https for stackoverfolw --- js/pym.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/pym.js b/js/pym.js index 7aa2dda..df889c0 100644 --- a/js/pym.js +++ b/js/pym.js @@ -20,7 +20,7 @@ /** * Generic function for parsing URL params. - * Via http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript + * Via https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript * * @method _getParameterByName * @param {String} name The name of the paramter to get from the URL.