Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/iframe-resizer/js/iframeResizer.contentWindow.js')
-rw-r--r--node_modules/iframe-resizer/js/iframeResizer.contentWindow.js1288
1 files changed, 1288 insertions, 0 deletions
diff --git a/node_modules/iframe-resizer/js/iframeResizer.contentWindow.js b/node_modules/iframe-resizer/js/iframeResizer.contentWindow.js
new file mode 100644
index 0000000000..07f918490d
--- /dev/null
+++ b/node_modules/iframe-resizer/js/iframeResizer.contentWindow.js
@@ -0,0 +1,1288 @@
+/*
+ * File: iframeResizer.contentWindow.js
+ * Desc: Include this file in any page being loaded into an iframe
+ * to force the iframe to resize to the content size.
+ * Requires: iframeResizer.js on host page.
+ * Doc: https://github.com/davidjbradshaw/iframe-resizer
+ * Author: David J. Bradshaw - dave@bradshaw.net
+ *
+ */
+
+// eslint-disable-next-line sonarjs/cognitive-complexity, no-shadow-restricted-names
+;(function (undefined) {
+ if (typeof window === 'undefined') return // don't run for server side render
+
+ var autoResize = true,
+ base = 10,
+ bodyBackground = '',
+ bodyMargin = 0,
+ bodyMarginStr = '',
+ bodyObserver = null,
+ bodyPadding = '',
+ calculateWidth = false,
+ doubleEventList = { resize: 1, click: 1 },
+ eventCancelTimer = 128,
+ firstRun = true,
+ height = 1,
+ heightCalcModeDefault = 'bodyOffset',
+ heightCalcMode = heightCalcModeDefault,
+ initLock = true,
+ initMsg = '',
+ inPageLinks = {},
+ interval = 32,
+ intervalTimer = null,
+ logging = false,
+ msgID = '[iFrameSizer]', // Must match host page msg ID
+ msgIdLen = msgID.length,
+ myID = '',
+ resetRequiredMethods = {
+ max: 1,
+ min: 1,
+ bodyScroll: 1,
+ documentElementScroll: 1
+ },
+ resizeFrom = 'child',
+ sendPermit = true,
+ target = window.parent,
+ targetOriginDefault = '*',
+ tolerance = 0,
+ triggerLocked = false,
+ triggerLockedTimer = null,
+ throttledTimer = 16,
+ width = 1,
+ widthCalcModeDefault = 'scroll',
+ widthCalcMode = widthCalcModeDefault,
+ win = window,
+ onMessage = function () {
+ warn('onMessage function not defined')
+ },
+ onReady = function () {},
+ onPageInfo = function () {},
+ customCalcMethods = {
+ height: function () {
+ warn('Custom height calculation function not defined')
+ return document.documentElement.offsetHeight
+ },
+ width: function () {
+ warn('Custom width calculation function not defined')
+ return document.body.scrollWidth
+ }
+ },
+ eventHandlersByName = {},
+ passiveSupported = false
+
+ function noop() {}
+
+ try {
+ var options = Object.create(
+ {},
+ {
+ passive: {
+ get: function () {
+ passiveSupported = true
+ }
+ }
+ }
+ )
+ window.addEventListener('test', noop, options)
+ window.removeEventListener('test', noop, options)
+ } catch (error) {
+ /* */
+ }
+
+ function addEventListener(el, evt, func, options) {
+ el.addEventListener(evt, func, passiveSupported ? options || {} : false)
+ }
+
+ function removeEventListener(el, evt, func) {
+ el.removeEventListener(evt, func, false)
+ }
+
+ function capitalizeFirstLetter(string) {
+ return string.charAt(0).toUpperCase() + string.slice(1)
+ }
+
+ // Based on underscore.js
+ function throttle(func) {
+ var context,
+ args,
+ result,
+ timeout = null,
+ previous = 0,
+ later = function () {
+ previous = getNow()
+ timeout = null
+ result = func.apply(context, args)
+ if (!timeout) {
+ // eslint-disable-next-line no-multi-assign
+ context = args = null
+ }
+ }
+
+ return function () {
+ var now = getNow()
+
+ if (!previous) {
+ previous = now
+ }
+
+ var remaining = throttledTimer - (now - previous)
+
+ context = this
+ args = arguments
+
+ if (remaining <= 0 || remaining > throttledTimer) {
+ if (timeout) {
+ clearTimeout(timeout)
+ timeout = null
+ }
+
+ previous = now
+ result = func.apply(context, args)
+
+ if (!timeout) {
+ // eslint-disable-next-line no-multi-assign
+ context = args = null
+ }
+ } else if (!timeout) {
+ timeout = setTimeout(later, remaining)
+ }
+
+ return result
+ }
+ }
+
+ var getNow =
+ Date.now ||
+ function () {
+ /* istanbul ignore next */ // Not testable in PhantonJS
+ return new Date().getTime()
+ }
+
+ function formatLogMsg(msg) {
+ return msgID + '[' + myID + '] ' + msg
+ }
+
+ function log(msg) {
+ if (logging && 'object' === typeof window.console) {
+ // eslint-disable-next-line no-console
+ console.log(formatLogMsg(msg))
+ }
+ }
+
+ function warn(msg) {
+ if ('object' === typeof window.console) {
+ // eslint-disable-next-line no-console
+ console.warn(formatLogMsg(msg))
+ }
+ }
+
+ function init() {
+ readDataFromParent()
+ log('Initialising iFrame (' + location.href + ')')
+ readDataFromPage()
+ setMargin()
+ setBodyStyle('background', bodyBackground)
+ setBodyStyle('padding', bodyPadding)
+ injectClearFixIntoBodyElement()
+ checkHeightMode()
+ checkWidthMode()
+ stopInfiniteResizingOfIFrame()
+ setupPublicMethods()
+ startEventListeners()
+ inPageLinks = setupInPageLinks()
+ sendSize('init', 'Init message from host page')
+ onReady()
+ }
+
+ function readDataFromParent() {
+ function strBool(str) {
+ return 'true' === str
+ }
+
+ var data = initMsg.substr(msgIdLen).split(':')
+
+ myID = data[0]
+ bodyMargin = undefined !== data[1] ? Number(data[1]) : bodyMargin // For V1 compatibility
+ calculateWidth = undefined !== data[2] ? strBool(data[2]) : calculateWidth
+ logging = undefined !== data[3] ? strBool(data[3]) : logging
+ interval = undefined !== data[4] ? Number(data[4]) : interval
+ autoResize = undefined !== data[6] ? strBool(data[6]) : autoResize
+ bodyMarginStr = data[7]
+ heightCalcMode = undefined !== data[8] ? data[8] : heightCalcMode
+ bodyBackground = data[9]
+ bodyPadding = data[10]
+ tolerance = undefined !== data[11] ? Number(data[11]) : tolerance
+ inPageLinks.enable = undefined !== data[12] ? strBool(data[12]) : false
+ resizeFrom = undefined !== data[13] ? data[13] : resizeFrom
+ widthCalcMode = undefined !== data[14] ? data[14] : widthCalcMode
+ }
+
+ function depricate(key) {
+ var splitName = key.split('Callback')
+
+ if (splitName.length === 2) {
+ var name =
+ 'on' + splitName[0].charAt(0).toUpperCase() + splitName[0].slice(1)
+ this[name] = this[key]
+ delete this[key]
+ warn(
+ "Deprecated: '" +
+ key +
+ "' has been renamed '" +
+ name +
+ "'. The old method will be removed in the next major version."
+ )
+ }
+ }
+
+ function readDataFromPage() {
+ function readData() {
+ var data = window.iFrameResizer
+
+ log('Reading data from page: ' + JSON.stringify(data))
+ Object.keys(data).forEach(depricate, data)
+
+ onMessage = 'onMessage' in data ? data.onMessage : onMessage
+ onReady = 'onReady' in data ? data.onReady : onReady
+ targetOriginDefault =
+ 'targetOrigin' in data ? data.targetOrigin : targetOriginDefault
+ heightCalcMode =
+ 'heightCalculationMethod' in data
+ ? data.heightCalculationMethod
+ : heightCalcMode
+ widthCalcMode =
+ 'widthCalculationMethod' in data
+ ? data.widthCalculationMethod
+ : widthCalcMode
+ }
+
+ function setupCustomCalcMethods(calcMode, calcFunc) {
+ if ('function' === typeof calcMode) {
+ log('Setup custom ' + calcFunc + 'CalcMethod')
+ customCalcMethods[calcFunc] = calcMode
+ calcMode = 'custom'
+ }
+
+ return calcMode
+ }
+
+ if (
+ 'iFrameResizer' in window &&
+ Object === window.iFrameResizer.constructor
+ ) {
+ readData()
+ heightCalcMode = setupCustomCalcMethods(heightCalcMode, 'height')
+ widthCalcMode = setupCustomCalcMethods(widthCalcMode, 'width')
+ }
+
+ log('TargetOrigin for parent set to: ' + targetOriginDefault)
+ }
+
+ function chkCSS(attr, value) {
+ if (-1 !== value.indexOf('-')) {
+ warn('Negative CSS value ignored for ' + attr)
+ value = ''
+ }
+ return value
+ }
+
+ function setBodyStyle(attr, value) {
+ if (undefined !== value && '' !== value && 'null' !== value) {
+ document.body.style[attr] = value
+ log('Body ' + attr + ' set to "' + value + '"')
+ }
+ }
+
+ function setMargin() {
+ // If called via V1 script, convert bodyMargin from int to str
+ if (undefined === bodyMarginStr) {
+ bodyMarginStr = bodyMargin + 'px'
+ }
+
+ setBodyStyle('margin', chkCSS('margin', bodyMarginStr))
+ }
+
+ function stopInfiniteResizingOfIFrame() {
+ document.documentElement.style.height = ''
+ document.body.style.height = ''
+ log('HTML & body height set to "auto"')
+ }
+
+ function manageTriggerEvent(options) {
+ var listener = {
+ add: function (eventName) {
+ function handleEvent() {
+ sendSize(options.eventName, options.eventType)
+ }
+
+ eventHandlersByName[eventName] = handleEvent
+
+ addEventListener(window, eventName, handleEvent, { passive: true })
+ },
+ remove: function (eventName) {
+ var handleEvent = eventHandlersByName[eventName]
+ delete eventHandlersByName[eventName]
+
+ removeEventListener(window, eventName, handleEvent)
+ }
+ }
+
+ if (options.eventNames && Array.prototype.map) {
+ options.eventName = options.eventNames[0]
+ options.eventNames.map(listener[options.method])
+ } else {
+ listener[options.method](options.eventName)
+ }
+
+ log(
+ capitalizeFirstLetter(options.method) +
+ ' event listener: ' +
+ options.eventType
+ )
+ }
+
+ function manageEventListeners(method) {
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Animation Start',
+ eventNames: ['animationstart', 'webkitAnimationStart']
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Animation Iteration',
+ eventNames: ['animationiteration', 'webkitAnimationIteration']
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Animation End',
+ eventNames: ['animationend', 'webkitAnimationEnd']
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Input',
+ eventName: 'input'
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Mouse Up',
+ eventName: 'mouseup'
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Mouse Down',
+ eventName: 'mousedown'
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Orientation Change',
+ eventName: 'orientationchange'
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Print',
+ eventName: ['afterprint', 'beforeprint']
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Ready State Change',
+ eventName: 'readystatechange'
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Touch Start',
+ eventName: 'touchstart'
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Touch End',
+ eventName: 'touchend'
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Touch Cancel',
+ eventName: 'touchcancel'
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Transition Start',
+ eventNames: [
+ 'transitionstart',
+ 'webkitTransitionStart',
+ 'MSTransitionStart',
+ 'oTransitionStart',
+ 'otransitionstart'
+ ]
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Transition Iteration',
+ eventNames: [
+ 'transitioniteration',
+ 'webkitTransitionIteration',
+ 'MSTransitionIteration',
+ 'oTransitionIteration',
+ 'otransitioniteration'
+ ]
+ })
+ manageTriggerEvent({
+ method: method,
+ eventType: 'Transition End',
+ eventNames: [
+ 'transitionend',
+ 'webkitTransitionEnd',
+ 'MSTransitionEnd',
+ 'oTransitionEnd',
+ 'otransitionend'
+ ]
+ })
+ if ('child' === resizeFrom) {
+ manageTriggerEvent({
+ method: method,
+ eventType: 'IFrame Resized',
+ eventName: 'resize'
+ })
+ }
+ }
+
+ function checkCalcMode(calcMode, calcModeDefault, modes, type) {
+ if (calcModeDefault !== calcMode) {
+ if (!(calcMode in modes)) {
+ warn(
+ calcMode + ' is not a valid option for ' + type + 'CalculationMethod.'
+ )
+ calcMode = calcModeDefault
+ }
+ log(type + ' calculation method set to "' + calcMode + '"')
+ }
+
+ return calcMode
+ }
+
+ function checkHeightMode() {
+ heightCalcMode = checkCalcMode(
+ heightCalcMode,
+ heightCalcModeDefault,
+ getHeight,
+ 'height'
+ )
+ }
+
+ function checkWidthMode() {
+ widthCalcMode = checkCalcMode(
+ widthCalcMode,
+ widthCalcModeDefault,
+ getWidth,
+ 'width'
+ )
+ }
+
+ function startEventListeners() {
+ if (true === autoResize) {
+ manageEventListeners('add')
+ setupMutationObserver()
+ } else {
+ log('Auto Resize disabled')
+ }
+ }
+
+ // function stopMsgsToParent() {
+ // log('Disable outgoing messages')
+ // sendPermit = false
+ // }
+
+ // function removeMsgListener() {
+ // log('Remove event listener: Message')
+ // removeEventListener(window, 'message', receiver)
+ // }
+
+ function disconnectMutationObserver() {
+ if (null !== bodyObserver) {
+ /* istanbul ignore next */ // Not testable in PhantonJS
+ bodyObserver.disconnect()
+ }
+ }
+
+ function stopEventListeners() {
+ manageEventListeners('remove')
+ disconnectMutationObserver()
+ clearInterval(intervalTimer)
+ }
+
+ // function teardown() {
+ // stopMsgsToParent()
+ // removeMsgListener()
+ // if (true === autoResize) stopEventListeners()
+ // }
+
+ function injectClearFixIntoBodyElement() {
+ var clearFix = document.createElement('div')
+ clearFix.style.clear = 'both'
+ // Guard against the following having been globally redefined in CSS.
+ clearFix.style.display = 'block'
+ clearFix.style.height = '0'
+ document.body.appendChild(clearFix)
+ }
+
+ function setupInPageLinks() {
+ function getPagePosition() {
+ return {
+ x:
+ window.pageXOffset !== undefined
+ ? window.pageXOffset
+ : document.documentElement.scrollLeft,
+ y:
+ window.pageYOffset !== undefined
+ ? window.pageYOffset
+ : document.documentElement.scrollTop
+ }
+ }
+
+ function getElementPosition(el) {
+ var elPosition = el.getBoundingClientRect(),
+ pagePosition = getPagePosition()
+
+ return {
+ x: parseInt(elPosition.left, 10) + parseInt(pagePosition.x, 10),
+ y: parseInt(elPosition.top, 10) + parseInt(pagePosition.y, 10)
+ }
+ }
+
+ function findTarget(location) {
+ function jumpToTarget(target) {
+ var jumpPosition = getElementPosition(target)
+
+ log(
+ 'Moving to in page link (#' +
+ hash +
+ ') at x: ' +
+ jumpPosition.x +
+ ' y: ' +
+ jumpPosition.y
+ )
+ sendMsg(jumpPosition.y, jumpPosition.x, 'scrollToOffset') // X&Y reversed at sendMsg uses height/width
+ }
+
+ var hash = location.split('#')[1] || location, // Remove # if present
+ hashData = decodeURIComponent(hash),
+ target =
+ document.getElementById(hashData) ||
+ document.getElementsByName(hashData)[0]
+
+ if (undefined !== target) {
+ jumpToTarget(target)
+ } else {
+ log(
+ 'In page link (#' +
+ hash +
+ ') not found in iFrame, so sending to parent'
+ )
+ sendMsg(0, 0, 'inPageLink', '#' + hash)
+ }
+ }
+
+ function checkLocationHash() {
+ if ('' !== location.hash && '#' !== location.hash) {
+ findTarget(location.href)
+ }
+ }
+
+ function bindAnchors() {
+ function setupLink(el) {
+ function linkClicked(e) {
+ e.preventDefault()
+
+ /* jshint validthis:true */
+ findTarget(this.getAttribute('href'))
+ }
+
+ if ('#' !== el.getAttribute('href')) {
+ addEventListener(el, 'click', linkClicked)
+ }
+ }
+
+ Array.prototype.forEach.call(
+ document.querySelectorAll('a[href^="#"]'),
+ setupLink
+ )
+ }
+
+ function bindLocationHash() {
+ addEventListener(window, 'hashchange', checkLocationHash)
+ }
+
+ function initCheck() {
+ // Check if page loaded with location hash after init resize
+ setTimeout(checkLocationHash, eventCancelTimer)
+ }
+
+ function enableInPageLinks() {
+ /* istanbul ignore else */ // Not testable in phantonJS
+ if (Array.prototype.forEach && document.querySelectorAll) {
+ log('Setting up location.hash handlers')
+ bindAnchors()
+ bindLocationHash()
+ initCheck()
+ } else {
+ warn(
+ 'In page linking not fully supported in this browser! (See README.md for IE8 workaround)'
+ )
+ }
+ }
+
+ if (inPageLinks.enable) {
+ enableInPageLinks()
+ } else {
+ log('In page linking not enabled')
+ }
+
+ return {
+ findTarget: findTarget
+ }
+ }
+
+ function setupPublicMethods() {
+ log('Enable public methods')
+
+ win.parentIFrame = {
+ autoResize: function autoResizeF(resize) {
+ if (true === resize && false === autoResize) {
+ autoResize = true
+ startEventListeners()
+ } else if (false === resize && true === autoResize) {
+ autoResize = false
+ stopEventListeners()
+ }
+ sendMsg(0, 0, 'autoResize', JSON.stringify(autoResize))
+ return autoResize
+ },
+
+ close: function closeF() {
+ sendMsg(0, 0, 'close')
+ // teardown()
+ },
+
+ getId: function getIdF() {
+ return myID
+ },
+
+ getPageInfo: function getPageInfoF(callback) {
+ if ('function' === typeof callback) {
+ onPageInfo = callback
+ sendMsg(0, 0, 'pageInfo')
+ } else {
+ onPageInfo = function () {}
+ sendMsg(0, 0, 'pageInfoStop')
+ }
+ },
+
+ moveToAnchor: function moveToAnchorF(hash) {
+ inPageLinks.findTarget(hash)
+ },
+
+ reset: function resetF() {
+ resetIFrame('parentIFrame.reset')
+ },
+
+ scrollTo: function scrollToF(x, y) {
+ sendMsg(y, x, 'scrollTo') // X&Y reversed at sendMsg uses height/width
+ },
+
+ scrollToOffset: function scrollToF(x, y) {
+ sendMsg(y, x, 'scrollToOffset') // X&Y reversed at sendMsg uses height/width
+ },
+
+ sendMessage: function sendMessageF(msg, targetOrigin) {
+ sendMsg(0, 0, 'message', JSON.stringify(msg), targetOrigin)
+ },
+
+ setHeightCalculationMethod: function setHeightCalculationMethodF(
+ heightCalculationMethod
+ ) {
+ heightCalcMode = heightCalculationMethod
+ checkHeightMode()
+ },
+
+ setWidthCalculationMethod: function setWidthCalculationMethodF(
+ widthCalculationMethod
+ ) {
+ widthCalcMode = widthCalculationMethod
+ checkWidthMode()
+ },
+
+ setTargetOrigin: function setTargetOriginF(targetOrigin) {
+ log('Set targetOrigin: ' + targetOrigin)
+ targetOriginDefault = targetOrigin
+ },
+
+ size: function sizeF(customHeight, customWidth) {
+ var valString =
+ '' + (customHeight || '') + (customWidth ? ',' + customWidth : '')
+ sendSize(
+ 'size',
+ 'parentIFrame.size(' + valString + ')',
+ customHeight,
+ customWidth
+ )
+ }
+ }
+ }
+
+ function initInterval() {
+ if (0 !== interval) {
+ log('setInterval: ' + interval + 'ms')
+ intervalTimer = setInterval(function () {
+ sendSize('interval', 'setInterval: ' + interval)
+ }, Math.abs(interval))
+ }
+ }
+
+ // Not testable in PhantomJS
+ /* istanbul ignore next */
+ function setupBodyMutationObserver() {
+ function addImageLoadListners(mutation) {
+ function addImageLoadListener(element) {
+ if (false === element.complete) {
+ log('Attach listeners to ' + element.src)
+ element.addEventListener('load', imageLoaded, false)
+ element.addEventListener('error', imageError, false)
+ elements.push(element)
+ }
+ }
+
+ if (mutation.type === 'attributes' && mutation.attributeName === 'src') {
+ addImageLoadListener(mutation.target)
+ } else if (mutation.type === 'childList') {
+ Array.prototype.forEach.call(
+ mutation.target.querySelectorAll('img'),
+ addImageLoadListener
+ )
+ }
+ }
+
+ function removeFromArray(element) {
+ elements.splice(elements.indexOf(element), 1)
+ }
+
+ function removeImageLoadListener(element) {
+ log('Remove listeners from ' + element.src)
+ element.removeEventListener('load', imageLoaded, false)
+ element.removeEventListener('error', imageError, false)
+ removeFromArray(element)
+ }
+
+ function imageEventTriggered(event, type, typeDesc) {
+ removeImageLoadListener(event.target)
+ sendSize(type, typeDesc + ': ' + event.target.src, undefined, undefined)
+ }
+
+ function imageLoaded(event) {
+ imageEventTriggered(event, 'imageLoad', 'Image loaded')
+ }
+
+ function imageError(event) {
+ imageEventTriggered(event, 'imageLoadFailed', 'Image load failed')
+ }
+
+ function mutationObserved(mutations) {
+ sendSize(
+ 'mutationObserver',
+ 'mutationObserver: ' + mutations[0].target + ' ' + mutations[0].type
+ )
+
+ // Deal with WebKit / Blink asyncing image loading when tags are injected into the page
+ mutations.forEach(addImageLoadListners)
+ }
+
+ function createMutationObserver() {
+ var target = document.querySelector('body'),
+ config = {
+ attributes: true,
+ attributeOldValue: false,
+ characterData: true,
+ characterDataOldValue: false,
+ childList: true,
+ subtree: true
+ }
+
+ observer = new MutationObserver(mutationObserved)
+
+ log('Create body MutationObserver')
+ observer.observe(target, config)
+
+ return observer
+ }
+
+ var elements = [],
+ MutationObserver =
+ window.MutationObserver || window.WebKitMutationObserver,
+ observer = createMutationObserver()
+
+ return {
+ disconnect: function () {
+ if ('disconnect' in observer) {
+ log('Disconnect body MutationObserver')
+ observer.disconnect()
+ elements.forEach(removeImageLoadListener)
+ }
+ }
+ }
+ }
+
+ function setupMutationObserver() {
+ var forceIntervalTimer = 0 > interval
+
+ // Not testable in PhantomJS
+ /* istanbul ignore if */ if (
+ window.MutationObserver ||
+ window.WebKitMutationObserver
+ ) {
+ if (forceIntervalTimer) {
+ initInterval()
+ } else {
+ bodyObserver = setupBodyMutationObserver()
+ }
+ } else {
+ log('MutationObserver not supported in this browser!')
+ initInterval()
+ }
+ }
+
+ // document.documentElement.offsetHeight is not reliable, so
+ // we have to jump through hoops to get a better value.
+ function getComputedStyle(prop, el) {
+ var retVal = 0
+ el = el || document.body // Not testable in phantonJS
+
+ retVal = document.defaultView.getComputedStyle(el, null)
+ retVal = null !== retVal ? retVal[prop] : 0
+
+ return parseInt(retVal, base)
+ }
+
+ function chkEventThottle(timer) {
+ if (timer > throttledTimer / 2) {
+ throttledTimer = 2 * timer
+ log('Event throttle increased to ' + throttledTimer + 'ms')
+ }
+ }
+
+ // Idea from https://github.com/guardian/iframe-messenger
+ function getMaxElement(side, elements) {
+ var elementsLength = elements.length,
+ elVal = 0,
+ maxVal = 0,
+ Side = capitalizeFirstLetter(side),
+ timer = getNow()
+
+ for (var i = 0; i < elementsLength; i++) {
+ elVal =
+ elements[i].getBoundingClientRect()[side] +
+ getComputedStyle('margin' + Side, elements[i])
+ if (elVal > maxVal) {
+ maxVal = elVal
+ }
+ }
+
+ timer = getNow() - timer
+
+ log('Parsed ' + elementsLength + ' HTML elements')
+ log('Element position calculated in ' + timer + 'ms')
+
+ chkEventThottle(timer)
+
+ return maxVal
+ }
+
+ function getAllMeasurements(dimention) {
+ return [
+ dimention.bodyOffset(),
+ dimention.bodyScroll(),
+ dimention.documentElementOffset(),
+ dimention.documentElementScroll()
+ ]
+ }
+
+ function getTaggedElements(side, tag) {
+ function noTaggedElementsFound() {
+ warn('No tagged elements (' + tag + ') found on page')
+ return document.querySelectorAll('body *')
+ }
+
+ var elements = document.querySelectorAll('[' + tag + ']')
+
+ if (0 === elements.length) noTaggedElementsFound()
+
+ return getMaxElement(side, elements)
+ }
+
+ function getAllElements() {
+ return document.querySelectorAll('body *')
+ }
+
+ var getHeight = {
+ bodyOffset: function getBodyOffsetHeight() {
+ return (
+ document.body.offsetHeight +
+ getComputedStyle('marginTop') +
+ getComputedStyle('marginBottom')
+ )
+ },
+
+ offset: function () {
+ return getHeight.bodyOffset() // Backwards compatability
+ },
+
+ bodyScroll: function getBodyScrollHeight() {
+ return document.body.scrollHeight
+ },
+
+ custom: function getCustomWidth() {
+ return customCalcMethods.height()
+ },
+
+ documentElementOffset: function getDEOffsetHeight() {
+ return document.documentElement.offsetHeight
+ },
+
+ documentElementScroll: function getDEScrollHeight() {
+ return document.documentElement.scrollHeight
+ },
+
+ max: function getMaxHeight() {
+ return Math.max.apply(null, getAllMeasurements(getHeight))
+ },
+
+ min: function getMinHeight() {
+ return Math.min.apply(null, getAllMeasurements(getHeight))
+ },
+
+ grow: function growHeight() {
+ return getHeight.max() // Run max without the forced downsizing
+ },
+
+ lowestElement: function getBestHeight() {
+ return Math.max(
+ getHeight.bodyOffset() || getHeight.documentElementOffset(),
+ getMaxElement('bottom', getAllElements())
+ )
+ },
+
+ taggedElement: function getTaggedElementsHeight() {
+ return getTaggedElements('bottom', 'data-iframe-height')
+ }
+ },
+ getWidth = {
+ bodyScroll: function getBodyScrollWidth() {
+ return document.body.scrollWidth
+ },
+
+ bodyOffset: function getBodyOffsetWidth() {
+ return document.body.offsetWidth
+ },
+
+ custom: function getCustomWidth() {
+ return customCalcMethods.width()
+ },
+
+ documentElementScroll: function getDEScrollWidth() {
+ return document.documentElement.scrollWidth
+ },
+
+ documentElementOffset: function getDEOffsetWidth() {
+ return document.documentElement.offsetWidth
+ },
+
+ scroll: function getMaxWidth() {
+ return Math.max(getWidth.bodyScroll(), getWidth.documentElementScroll())
+ },
+
+ max: function getMaxWidth() {
+ return Math.max.apply(null, getAllMeasurements(getWidth))
+ },
+
+ min: function getMinWidth() {
+ return Math.min.apply(null, getAllMeasurements(getWidth))
+ },
+
+ rightMostElement: function rightMostElement() {
+ return getMaxElement('right', getAllElements())
+ },
+
+ taggedElement: function getTaggedElementsWidth() {
+ return getTaggedElements('right', 'data-iframe-width')
+ }
+ }
+
+ function sizeIFrame(
+ triggerEvent,
+ triggerEventDesc,
+ customHeight,
+ customWidth
+ ) {
+ function resizeIFrame() {
+ height = currentHeight
+ width = currentWidth
+
+ sendMsg(height, width, triggerEvent)
+ }
+
+ function isSizeChangeDetected() {
+ function checkTolarance(a, b) {
+ var retVal = Math.abs(a - b) <= tolerance
+ return !retVal
+ }
+
+ currentHeight =
+ undefined !== customHeight ? customHeight : getHeight[heightCalcMode]()
+ currentWidth =
+ undefined !== customWidth ? customWidth : getWidth[widthCalcMode]()
+
+ return (
+ checkTolarance(height, currentHeight) ||
+ (calculateWidth && checkTolarance(width, currentWidth))
+ )
+ }
+
+ function isForceResizableEvent() {
+ return !(triggerEvent in { init: 1, interval: 1, size: 1 })
+ }
+
+ function isForceResizableCalcMode() {
+ return (
+ heightCalcMode in resetRequiredMethods ||
+ (calculateWidth && widthCalcMode in resetRequiredMethods)
+ )
+ }
+
+ function logIgnored() {
+ log('No change in size detected')
+ }
+
+ function checkDownSizing() {
+ if (isForceResizableEvent() && isForceResizableCalcMode()) {
+ resetIFrame(triggerEventDesc)
+ } else if (!(triggerEvent in { interval: 1 })) {
+ logIgnored()
+ }
+ }
+
+ var currentHeight, currentWidth
+
+ if (isSizeChangeDetected() || 'init' === triggerEvent) {
+ lockTrigger()
+ resizeIFrame()
+ } else {
+ checkDownSizing()
+ }
+ }
+
+ var sizeIFrameThrottled = throttle(sizeIFrame)
+
+ function sendSize(triggerEvent, triggerEventDesc, customHeight, customWidth) {
+ function recordTrigger() {
+ if (!(triggerEvent in { reset: 1, resetPage: 1, init: 1 })) {
+ log('Trigger event: ' + triggerEventDesc)
+ }
+ }
+
+ function isDoubleFiredEvent() {
+ return triggerLocked && triggerEvent in doubleEventList
+ }
+
+ if (!isDoubleFiredEvent()) {
+ recordTrigger()
+ if (triggerEvent === 'init') {
+ sizeIFrame(triggerEvent, triggerEventDesc, customHeight, customWidth)
+ } else {
+ sizeIFrameThrottled(
+ triggerEvent,
+ triggerEventDesc,
+ customHeight,
+ customWidth
+ )
+ }
+ } else {
+ log('Trigger event cancelled: ' + triggerEvent)
+ }
+ }
+
+ function lockTrigger() {
+ if (!triggerLocked) {
+ triggerLocked = true
+ log('Trigger event lock on')
+ }
+ clearTimeout(triggerLockedTimer)
+ triggerLockedTimer = setTimeout(function () {
+ triggerLocked = false
+ log('Trigger event lock off')
+ log('--')
+ }, eventCancelTimer)
+ }
+
+ function triggerReset(triggerEvent) {
+ height = getHeight[heightCalcMode]()
+ width = getWidth[widthCalcMode]()
+
+ sendMsg(height, width, triggerEvent)
+ }
+
+ function resetIFrame(triggerEventDesc) {
+ var hcm = heightCalcMode
+ heightCalcMode = heightCalcModeDefault
+
+ log('Reset trigger event: ' + triggerEventDesc)
+ lockTrigger()
+ triggerReset('reset')
+
+ heightCalcMode = hcm
+ }
+
+ function sendMsg(height, width, triggerEvent, msg, targetOrigin) {
+ function setTargetOrigin() {
+ if (undefined === targetOrigin) {
+ targetOrigin = targetOriginDefault
+ } else {
+ log('Message targetOrigin: ' + targetOrigin)
+ }
+ }
+
+ function sendToParent() {
+ var size = height + ':' + width,
+ message =
+ myID +
+ ':' +
+ size +
+ ':' +
+ triggerEvent +
+ (undefined !== msg ? ':' + msg : '')
+
+ log('Sending message to host page (' + message + ')')
+ target.postMessage(msgID + message, targetOrigin)
+ }
+
+ if (true === sendPermit) {
+ setTargetOrigin()
+ sendToParent()
+ }
+ }
+
+ function receiver(event) {
+ var processRequestFromParent = {
+ init: function initFromParent() {
+ initMsg = event.data
+ target = event.source
+
+ init()
+ firstRun = false
+ setTimeout(function () {
+ initLock = false
+ }, eventCancelTimer)
+ },
+
+ reset: function resetFromParent() {
+ if (!initLock) {
+ log('Page size reset by host page')
+ triggerReset('resetPage')
+ } else {
+ log('Page reset ignored by init')
+ }
+ },
+
+ resize: function resizeFromParent() {
+ sendSize('resizeParent', 'Parent window requested size check')
+ },
+
+ moveToAnchor: function moveToAnchorF() {
+ inPageLinks.findTarget(getData())
+ },
+ inPageLink: function inPageLinkF() {
+ this.moveToAnchor()
+ }, // Backward compatability
+
+ pageInfo: function pageInfoFromParent() {
+ var msgBody = getData()
+ log('PageInfoFromParent called from parent: ' + msgBody)
+ onPageInfo(JSON.parse(msgBody))
+ log(' --')
+ },
+
+ message: function messageFromParent() {
+ var msgBody = getData()
+
+ log('onMessage called from parent: ' + msgBody)
+ // eslint-disable-next-line sonarjs/no-extra-arguments
+ onMessage(JSON.parse(msgBody))
+ log(' --')
+ }
+ }
+
+ function isMessageForUs() {
+ return msgID === ('' + event.data).substr(0, msgIdLen) // ''+ Protects against non-string messages
+ }
+
+ function getMessageType() {
+ return event.data.split(']')[1].split(':')[0]
+ }
+
+ function getData() {
+ return event.data.substr(event.data.indexOf(':') + 1)
+ }
+
+ function isMiddleTier() {
+ return (
+ (!(typeof module !== 'undefined' && module.exports) &&
+ 'iFrameResize' in window) ||
+ ('jQuery' in window && 'iFrameResize' in window.jQuery.prototype)
+ )
+ }
+
+ function isInitMsg() {
+ // Test if this message is from a child below us. This is an ugly test, however, updating
+ // the message format would break backwards compatibity.
+ return event.data.split(':')[2] in { true: 1, false: 1 }
+ }
+
+ function callFromParent() {
+ var messageType = getMessageType()
+
+ if (messageType in processRequestFromParent) {
+ processRequestFromParent[messageType]()
+ } else if (!isMiddleTier() && !isInitMsg()) {
+ warn('Unexpected message (' + event.data + ')')
+ }
+ }
+
+ function processMessage() {
+ if (false === firstRun) {
+ callFromParent()
+ } else if (isInitMsg()) {
+ processRequestFromParent.init()
+ } else {
+ log(
+ 'Ignored message of type "' +
+ getMessageType() +
+ '". Received before initialization.'
+ )
+ }
+ }
+
+ if (isMessageForUs()) {
+ processMessage()
+ }
+ }
+
+ // Normally the parent kicks things off when it detects the iFrame has loaded.
+ // If this script is async-loaded, then tell parent page to retry init.
+ function chkLateLoaded() {
+ if ('loading' !== document.readyState) {
+ window.parent.postMessage('[iFrameResizerChild]Ready', '*')
+ }
+ }
+
+ addEventListener(window, 'message', receiver)
+ addEventListener(window, 'readystatechange', chkLateLoaded)
+ chkLateLoaded()
+
+
+})()