vendor: 35,048 bytes, lines 1-1311
1/* 2 * File: iframeResizer.contentWindow.js 3 * Desc: Include this file in any page being loaded into an iframe 4 * to force the iframe to resize to the content size. 5 * Requires: iframeResizer.js on host page. 6 * Doc: https://iframe-resizer.com 7 * Author: David J. Bradshaw - [email protected] 8 * 9 */ 10 11// eslint-disable-next-line sonarjs/cognitive-complexity, no-shadow-restricted-names 12;(function (undefined) { 13 if (typeof window === 'undefined') return // don't run for server side render 14 15 var autoResize = true, 16 base = 10, 17 bodyBackground = '', 18 bodyMargin = 0, 19 bodyMarginStr = '', 20 bodyObserver = null, 21 bodyPadding = '', 22 calculateWidth = false, 23 doubleEventList = { resize: 1, click: 1 }, 24 eventCancelTimer = 128, 25 firstRun = true, 26 height = 1, 27 heightCalcModeDefault = 'bodyOffset', 28 heightCalcMode = heightCalcModeDefault, 29 initLock = true, 30 initMsg = '', 31 inPageLinks = {}, 32 interval = 32, 33 intervalTimer = null, 34 logging = false, 35 mouseEvents = false, 36 msgID = '[iFrameSizer]', // Must match host page msg ID 37 msgIdLen = msgID.length, 38 myID = '', 39 resetRequiredMethods = { 40 max: 1, 41 min: 1, 42 bodyScroll: 1, 43 documentElementScroll: 1 44 }, 45 resizeFrom = 'child', 46 sendPermit = true, 47 target = window.parent, 48 targetOriginDefault = '*', 49 tolerance = 0, 50 triggerLocked = false, 51 triggerLockedTimer = null, 52 throttledTimer = 16, 53 width = 1, 54 widthCalcModeDefault = 'scroll', 55 widthCalcMode = widthCalcModeDefault, 56 win = window, 57 onMessage = function () { 58 warn('onMessage function not defined') 59 }, 60 onReady = function () {}, 61 onPageInfo = function () {}, 62 customCalcMethods = { 63 height: function () { 64 warn('Custom height calculation function not defined') 65 return document.documentElement.offsetHeight 66 }, 67 width: function () { 68 warn('Custom width calculation function not defined') 69 return document.body.scrollWidth 70 } 71 }, 72 eventHandlersByName = {}, 73 passiveSupported = false 74 75 function noop() {} 76 77 try { 78 var options = Object.create( 79 {}, 80 { 81 passive: { 82 // eslint-disable-next-line getter-return 83 get: function () { 84 passiveSupported = true 85 } 86 } 87 } 88 ) 89 window.addEventListener('test', noop, options) 90 window.removeEventListener('test', noop, options) 91 } catch (error) { 92 /* */ 93 } 94 95 function addEventListener(el, evt, func, options) { 96 el.addEventListener(evt, func, passiveSupported ? options || {} : false) 97 } 98 99 function removeEventListener(el, evt, func) { 100 el.removeEventListener(evt, func, false) 101 } 102 103 function capitalizeFirstLetter(string) { 104 return string.charAt(0).toUpperCase() + string.slice(1) 105 } 106 107 // Based on underscore.js 108 function throttle(func) { 109 var context, 110 args, 111 result, 112 timeout = null, 113 previous = 0, 114 later = function () { 115 previous = Date.now() 116 timeout = null 117 result = func.apply(context, args) 118 if (!timeout) { 119 // eslint-disable-next-line no-multi-assign 120 context = args = null 121 } 122 } 123 124 return function () { 125 var now = Date.now() 126 127 if (!previous) { 128 previous = now 129 } 130 131 var remaining = throttledTimer - (now - previous) 132 133 context = this 134 args = arguments 135 136 if (remaining <= 0 || remaining > throttledTimer) { 137 if (timeout) { 138 clearTimeout(timeout) 139 timeout = null 140 } 141 142 previous = now 143 result = func.apply(context, args) 144 145 if (!timeout) { 146 // eslint-disable-next-line no-multi-assign 147 context = args = null 148 } 149 } else if (!timeout) { 150 timeout = setTimeout(later, remaining) 151 } 152 153 return result 154 } 155 } 156 157 function formatLogMsg(msg) { 158 return msgID + '[' + myID + '] ' + msg 159 } 160 161 function log(msg) { 162 if (logging && 'object' === typeof window.console) { 163 // eslint-disable-next-line no-console 164 console.log(formatLogMsg(msg)) 165 } 166 } 167 168 function warn(msg) { 169 if ('object' === typeof window.console) { 170 // eslint-disable-next-line no-console 171 console.warn(formatLogMsg(msg)) 172 } 173 } 174 175 function init() { 176 readDataFromParent() 177 log('Initialising iFrame (' + window.location.href + ')') 178 readDataFromPage() 179 setMargin() 180 setBodyStyle('background', bodyBackground) 181 setBodyStyle('padding', bodyPadding) 182 injectClearFixIntoBodyElement() 183 checkHeightMode() 184 checkWidthMode() 185 stopInfiniteResizingOfIFrame() 186 setupPublicMethods() 187 setupMouseEvents() 188 startEventListeners() 189 inPageLinks = setupInPageLinks() 190 sendSize('init', 'Init message from host page') 191 onReady() 192 } 193 194 function readDataFromParent() { 195 function strBool(str) { 196 return 'true' === str 197 } 198 199 var data = initMsg.slice(msgIdLen).split(':') 200 201 myID = data[0] 202 bodyMargin = undefined === data[1] ? bodyMargin : Number(data[1]) // For V1 compatibility 203 calculateWidth = undefined === data[2] ? calculateWidth : strBool(data[2]) 204 logging = undefined === data[3] ? logging : strBool(data[3]) 205 interval = undefined === data[4] ? interval : Number(data[4]) 206 autoResize = undefined === data[6] ? autoResize : strBool(data[6]) 207 bodyMarginStr = data[7] 208 heightCalcMode = undefined === data[8] ? heightCalcMode : data[8] 209 bodyBackground = data[9] 210 bodyPadding = data[10] 211 tolerance = undefined === data[11] ? tolerance : Number(data[11]) 212 inPageLinks.enable = undefined === data[12] ? false : strBool(data[12]) 213 resizeFrom = undefined === data[13] ? resizeFrom : data[13] 214 widthCalcMode = undefined === data[14] ? widthCalcMode : data[14] 215 mouseEvents = undefined === data[15] ? mouseEvents : strBool(data[15]) 216 } 217 218 function depricate(key) { 219 var splitName = key.split('Callback') 220 221 if (splitName.length === 2) { 222 var name = 223 'on' + splitName[0].charAt(0).toUpperCase() + splitName[0].slice(1) 224 this[name] = this[key] 225 delete this[key] 226 warn( 227 "Deprecated: '" + 228 key + 229 "' has been renamed '" + 230 name + 231 "'. The old method will be removed in the next major version." 232 ) 233 } 234 } 235 236 function readDataFromPage() { 237 function readData() { 238 var data = window.iFrameResizer 239 240 log('Reading data from page: ' + JSON.stringify(data)) 241 Object.keys(data).forEach(depricate, data) 242 243 onMessage = 'onMessage' in data ? data.onMessage : onMessage 244 onReady = 'onReady' in data ? data.onReady : onReady 245 targetOriginDefault = 246 'targetOrigin' in data ? data.targetOrigin : targetOriginDefault 247 heightCalcMode = 248 'heightCalculationMethod' in data 249 ? data.heightCalculationMethod 250 : heightCalcMode 251 widthCalcMode = 252 'widthCalculationMethod' in data 253 ? data.widthCalculationMethod 254 : widthCalcMode 255 } 256 257 function setupCustomCalcMethods(calcMode, calcFunc) { 258 if ('function' === typeof calcMode) { 259 log('Setup custom ' + calcFunc + 'CalcMethod') 260 customCalcMethods[calcFunc] = calcMode 261 calcMode = 'custom' 262 } 263 264 return calcMode 265 } 266 267 if ( 268 'iFrameResizer' in window && 269 Object === window.iFrameResizer.constructor 270 ) { 271 readData() 272 heightCalcMode = setupCustomCalcMethods(heightCalcMode, 'height') 273 widthCalcMode = setupCustomCalcMethods(widthCalcMode, 'width') 274 } 275 276 log('TargetOrigin for parent set to: ' + targetOriginDefault) 277 } 278 279 function chkCSS(attr, value) { 280 if (-1 !== value.indexOf('-')) { 281 warn('Negative CSS value ignored for ' + attr) 282 value = '' 283 } 284 return value 285 } 286 287 function setBodyStyle(attr, value) { 288 if (undefined !== value && '' !== value && 'null' !== value) { 289 document.body.style[attr] = value 290 log('Body ' + attr + ' set to "' + value + '"') 291 } 292 } 293 294 function setMargin() { 295 // If called via V1 script, convert bodyMargin from int to str 296 if (undefined === bodyMarginStr) { 297 bodyMarginStr = bodyMargin + 'px' 298 } 299 300 setBodyStyle('margin', chkCSS('margin', bodyMarginStr)) 301 } 302 303 function stopInfiniteResizingOfIFrame() { 304 document.documentElement.style.height = '' 305 document.body.style.height = '' 306 log('HTML & body height set to "auto"') 307 } 308 309 function manageTriggerEvent(options) { 310 var listener = { 311 add: function (eventName) { 312 function handleEvent() { 313 sendSize(options.eventName, options.eventType) 314 } 315 316 eventHandlersByName[eventName] = handleEvent 317 318 addEventListener(window, eventName, handleEvent, { passive: true }) 319 }, 320 remove: function (eventName) { 321 var handleEvent = eventHandlersByName[eventName] 322 delete eventHandlersByName[eventName] 323 324 removeEventListener(window, eventName, handleEvent) 325 } 326 } 327 328 if (options.eventNames && Array.prototype.map) { 329 options.eventName = options.eventNames[0] 330 options.eventNames.map(listener[options.method]) 331 } else { 332 listener[options.method](options.eventName) 333 } 334 335 log( 336 capitalizeFirstLetter(options.method) + 337 ' event listener: ' + 338 options.eventType 339 ) 340 } 341 342 function manageEventListeners(method) { 343 manageTriggerEvent({ 344 method: method, 345 eventType: 'Animation Start', 346 eventNames: ['animationstart', 'webkitAnimationStart'] 347 }) 348 manageTriggerEvent({ 349 method: method, 350 eventType: 'Animation Iteration', 351 eventNames: ['animationiteration', 'webkitAnimationIteration'] 352 }) 353 manageTriggerEvent({ 354 method: method, 355 eventType: 'Animation End', 356 eventNames: ['animationend', 'webkitAnimationEnd'] 357 }) 358 manageTriggerEvent({ 359 method: method, 360 eventType: 'Input', 361 eventName: 'input' 362 }) 363 manageTriggerEvent({ 364 method: method, 365 eventType: 'Mouse Up', 366 eventName: 'mouseup' 367 }) 368 manageTriggerEvent({ 369 method: method, 370 eventType: 'Mouse Down', 371 eventName: 'mousedown' 372 }) 373 manageTriggerEvent({ 374 method: method, 375 eventType: 'Orientation Change', 376 eventName: 'orientationchange' 377 }) 378 manageTriggerEvent({ 379 method: method, 380 eventType: 'Print', 381 eventNames: ['afterprint', 'beforeprint'] 382 }) 383 manageTriggerEvent({ 384 method: method, 385 eventType: 'Ready State Change', 386 eventName: 'readystatechange' 387 }) 388 manageTriggerEvent({ 389 method: method, 390 eventType: 'Touch Start', 391 eventName: 'touchstart' 392 }) 393 manageTriggerEvent({ 394 method: method, 395 eventType: 'Touch End', 396 eventName: 'touchend' 397 }) 398 manageTriggerEvent({ 399 method: method, 400 eventType: 'Touch Cancel', 401 eventName: 'touchcancel' 402 }) 403 manageTriggerEvent({ 404 method: method, 405 eventType: 'Transition Start', 406 eventNames: [ 407 'transitionstart', 408 'webkitTransitionStart', 409 'MSTransitionStart', 410 'oTransitionStart', 411 'otransitionstart' 412 ] 413 }) 414 manageTriggerEvent({ 415 method: method, 416 eventType: 'Transition Iteration', 417 eventNames: [ 418 'transitioniteration', 419 'webkitTransitionIteration', 420 'MSTransitionIteration', 421 'oTransitionIteration', 422 'otransitioniteration' 423 ] 424 }) 425 manageTriggerEvent({ 426 method: method, 427 eventType: 'Transition End', 428 eventNames: [ 429 'transitionend', 430 'webkitTransitionEnd', 431 'MSTransitionEnd', 432 'oTransitionEnd', 433 'otransitionend' 434 ] 435 }) 436 if ('child' === resizeFrom) { 437 manageTriggerEvent({ 438 method: method, 439 eventType: 'IFrame Resized', 440 eventName: 'resize' 441 }) 442 } 443 } 444 445 function checkCalcMode(calcMode, calcModeDefault, modes, type) { 446 if (calcModeDefault !== calcMode) { 447 if (!(calcMode in modes)) { 448 warn( 449 calcMode + ' is not a valid option for ' + type + 'CalculationMethod.' 450 ) 451 calcMode = calcModeDefault 452 } 453 log(type + ' calculation method set to "' + calcMode + '"') 454 } 455 456 return calcMode 457 } 458 459 function checkHeightMode() { 460 heightCalcMode = checkCalcMode( 461 heightCalcMode, 462 heightCalcModeDefault, 463 getHeight, 464 'height' 465 ) 466 } 467 468 function checkWidthMode() { 469 widthCalcMode = checkCalcMode( 470 widthCalcMode, 471 widthCalcModeDefault, 472 getWidth, 473 'width' 474 ) 475 } 476 477 function startEventListeners() { 478 if (true === autoResize) { 479 manageEventListeners('add') 480 setupMutationObserver() 481 } else { 482 log('Auto Resize disabled') 483 } 484 } 485 486 // function stopMsgsToParent() { 487 // log('Disable outgoing messages') 488 // sendPermit = false 489 // } 490 491 // function removeMsgListener() { 492 // log('Remove event listener: Message') 493 // removeEventListener(window, 'message', receiver) 494 // } 495 496 function disconnectMutationObserver() { 497 if (null !== bodyObserver) { 498 /* istanbul ignore next */ // Not testable in PhantonJS 499 bodyObserver.disconnect() 500 } 501 } 502 503 function stopEventListeners() { 504 manageEventListeners('remove') 505 disconnectMutationObserver() 506 clearInterval(intervalTimer) 507 } 508 509 // function teardown() { 510 // stopMsgsToParent() 511 // removeMsgListener() 512 // if (true === autoResize) stopEventListeners() 513 // } 514 515 function injectClearFixIntoBodyElement() { 516 var clearFix = document.createElement('div') 517 clearFix.style.clear = 'both' 518 // Guard against the following having been globally redefined in CSS. 519 clearFix.style.display = 'block' 520 clearFix.style.height = '0' 521 document.body.appendChild(clearFix) 522 } 523 524 function setupInPageLinks() { 525 function getPagePosition() { 526 return { 527 x: 528 window.pageXOffset === undefined 529 ? document.documentElement.scrollLeft 530 : window.pageXOffset, 531 y: 532 window.pageYOffset === undefined 533 ? document.documentElement.scrollTop 534 : window.pageYOffset 535 } 536 } 537 538 function getElementPosition(el) { 539 var elPosition = el.getBoundingClientRect(), 540 pagePosition = getPagePosition() 541 542 return { 543 x: parseInt(elPosition.left, 10) + parseInt(pagePosition.x, 10), 544 y: parseInt(elPosition.top, 10) + parseInt(pagePosition.y, 10) 545 } 546 } 547 548 function findTarget(location) { 549 function jumpToTarget(target) { 550 var jumpPosition = getElementPosition(target) 551 552 log( 553 'Moving to in page link (#' + 554 hash + 555 ') at x: ' + 556 jumpPosition.x + 557 ' y: ' + 558 jumpPosition.y 559 ) 560 sendMsg(jumpPosition.y, jumpPosition.x, 'scrollToOffset') // X&Y reversed at sendMsg uses height/width 561 } 562 563 var hash = location.split('#')[1] || location, // Remove # if present 564 hashData = decodeURIComponent(hash), 565 target = 566 document.getElementById(hashData) || 567 document.getElementsByName(hashData)[0] 568 569 if (undefined === target) { 570 log( 571 'In page link (#' + 572 hash + 573 ') not found in iFrame, so sending to parent' 574 ) 575 sendMsg(0, 0, 'inPageLink', '#' + hash) 576 } else { 577 jumpToTarget(target) 578 } 579 } 580 581 function checkLocationHash() { 582 var hash = window.location.hash 583 var href = window.location.href 584 585 if ('' !== hash && '#' !== hash) { 586 findTarget(href) 587 } 588 } 589 590 function bindAnchors() { 591 function setupLink(el) { 592 function linkClicked(e) { 593 e.preventDefault() 594 595 /* jshint validthis:true */ 596 findTarget(this.getAttribute('href')) 597 } 598 599 if ('#' !== el.getAttribute('href')) { 600 addEventListener(el, 'click', linkClicked) 601 } 602 } 603 604 Array.prototype.forEach.call( 605 document.querySelectorAll('a[href^="#"]'), 606 setupLink 607 ) 608 } 609 610 function bindLocationHash() { 611 addEventListener(window, 'hashchange', checkLocationHash) 612 } 613 614 function initCheck() { 615 // Check if page loaded with location hash after init resize 616 setTimeout(checkLocationHash, eventCancelTimer) 617 } 618 619 function enableInPageLinks() { 620 /* istanbul ignore else */ // Not testable in phantonJS 621 if (Array.prototype.forEach && document.querySelectorAll) { 622 log('Setting up location.hash handlers') 623 bindAnchors() 624 bindLocationHash() 625 initCheck() 626 } else { 627 warn( 628 'In page linking not fully supported in this browser! (See README.md for IE8 workaround)' 629 ) 630 } 631 } 632 633 if (inPageLinks.enable) { 634 enableInPageLinks() 635 } else { 636 log('In page linking not enabled') 637 } 638 639 return { 640 findTarget: findTarget 641 } 642 } 643 644 function setupMouseEvents() { 645 if (mouseEvents !== true) return 646 647 function sendMouse(e) { 648 sendMsg(0, 0, e.type, e.screenY + ':' + e.screenX) 649 } 650 651 function addMouseListener(evt, name) { 652 log('Add event listener: ' + name) 653 addEventListener(window.document, evt, sendMouse) 654 } 655 656 addMouseListener('mouseenter', 'Mouse Enter') 657 addMouseListener('mouseleave', 'Mouse Leave') 658 } 659 660 function setupPublicMethods() { 661 log('Enable public methods') 662 663 win.parentIFrame = { 664 autoResize: function autoResizeF(resize) { 665 if (true === resize && false === autoResize) { 666 autoResize = true 667 startEventListeners() 668 } else if (false === resize && true === autoResize) { 669 autoResize = false 670 stopEventListeners() 671 } 672 sendMsg(0, 0, 'autoResize', JSON.stringify(autoResize)) 673 return autoResize 674 }, 675 676 close: function closeF() { 677 sendMsg(0, 0, 'close') 678 // teardown() 679 }, 680 681 getId: function getIdF() { 682 return myID 683 }, 684 685 getPageInfo: function getPageInfoF(callback) { 686 if ('function' === typeof callback) { 687 onPageInfo = callback 688 sendMsg(0, 0, 'pageInfo') 689 } else { 690 onPageInfo = function () {} 691 sendMsg(0, 0, 'pageInfoStop') 692 } 693 }, 694 695 moveToAnchor: function moveToAnchorF(hash) { 696 inPageLinks.findTarget(hash) 697 }, 698 699 reset: function resetF() { 700 resetIFrame('parentIFrame.reset') 701 }, 702 703 scrollTo: function scrollToF(x, y) { 704 sendMsg(y, x, 'scrollTo') // X&Y reversed at sendMsg uses height/width 705 }, 706 707 scrollToOffset: function scrollToF(x, y) { 708 sendMsg(y, x, 'scrollToOffset') // X&Y reversed at sendMsg uses height/width 709 }, 710 711 sendMessage: function sendMessageF(msg, targetOrigin) { 712 sendMsg(0, 0, 'message', JSON.stringify(msg), targetOrigin) 713 }, 714 715 setHeightCalculationMethod: function setHeightCalculationMethodF( 716 heightCalculationMethod 717 ) { 718 heightCalcMode = heightCalculationMethod 719 checkHeightMode() 720 }, 721 722 setWidthCalculationMethod: function setWidthCalculationMethodF( 723 widthCalculationMethod 724 ) { 725 widthCalcMode = widthCalculationMethod 726 checkWidthMode() 727 }, 728 729 setTargetOrigin: function setTargetOriginF(targetOrigin) { 730 log('Set targetOrigin: ' + targetOrigin) 731 targetOriginDefault = targetOrigin 732 }, 733 734 size: function sizeF(customHeight, customWidth) { 735 var valString = 736 '' + (customHeight || '') + (customWidth ? ',' + customWidth : '') 737 sendSize( 738 'size', 739 'parentIFrame.size(' + valString + ')', 740 customHeight, 741 customWidth 742 ) 743 } 744 } 745 } 746 747 function initInterval() { 748 if (0 !== interval) { 749 log('setInterval: ' + interval + 'ms') 750 intervalTimer = setInterval(function () { 751 sendSize('interval', 'setInterval: ' + interval) 752 }, Math.abs(interval)) 753 } 754 } 755 756 // Not testable in PhantomJS 757 /* istanbul ignore next */ 758 function setupBodyMutationObserver() { 759 function addImageLoadListners(mutation) { 760 function addImageLoadListener(element) { 761 if (false === element.complete) { 762 log('Attach listeners to ' + element.src) 763 element.addEventListener('load', imageLoaded, false) 764 element.addEventListener('error', imageError, false) 765 elements.push(element) 766 } 767 } 768 769 if (mutation.type === 'attributes' && mutation.attributeName === 'src') { 770 addImageLoadListener(mutation.target) 771 } else if (mutation.type === 'childList') { 772 Array.prototype.forEach.call( 773 mutation.target.querySelectorAll('img'), 774 addImageLoadListener 775 ) 776 } 777 } 778 779 function removeFromArray(element) { 780 elements.splice(elements.indexOf(element), 1) 781 } 782 783 function removeImageLoadListener(element) { 784 log('Remove listeners from ' + element.src) 785 element.removeEventListener('load', imageLoaded, false) 786 element.removeEventListener('error', imageError, false) 787 removeFromArray(element) 788 } 789 790 function imageEventTriggered(event, type, typeDesc) { 791 removeImageLoadListener(event.target) 792 sendSize(type, typeDesc + ': ' + event.target.src) 793 } 794 795 function imageLoaded(event) { 796 imageEventTriggered(event, 'imageLoad', 'Image loaded') 797 } 798 799 function imageError(event) { 800 imageEventTriggered(event, 'imageLoadFailed', 'Image load failed') 801 } 802 803 function mutationObserved(mutations) { 804 sendSize( 805 'mutationObserver', 806 'mutationObserver: ' + mutations[0].target + ' ' + mutations[0].type 807 ) 808 809 // Deal with WebKit / Blink asyncing image loading when tags are injected into the page 810 mutations.forEach(addImageLoadListners) 811 } 812 813 function createMutationObserver() { 814 var target = document.querySelector('body'), 815 config = { 816 attributes: true, 817 attributeOldValue: false, 818 characterData: true, 819 characterDataOldValue: false, 820 childList: true, 821 subtree: true 822 } 823 824 observer = new MutationObserver(mutationObserved) 825 826 log('Create body MutationObserver') 827 observer.observe(target, config) 828 829 return observer 830 } 831 832 var elements = [], 833 MutationObserver = 834 window.MutationObserver || window.WebKitMutationObserver, 835 observer = createMutationObserver() 836 837 return { 838 disconnect: function () { 839 if ('disconnect' in observer) { 840 log('Disconnect body MutationObserver') 841 observer.disconnect() 842 elements.forEach(removeImageLoadListener) 843 } 844 } 845 } 846 } 847 848 function setupMutationObserver() { 849 var forceIntervalTimer = 0 > interval 850 851 // Not testable in PhantomJS 852 /* istanbul ignore if */ if ( 853 window.MutationObserver || 854 window.WebKitMutationObserver 855 ) { 856 if (forceIntervalTimer) { 857 initInterval() 858 } else { 859 bodyObserver = setupBodyMutationObserver() 860 } 861 } else { 862 log('MutationObserver not supported in this browser!') 863 initInterval() 864 } 865 } 866 867 // document.documentElement.offsetHeight is not reliable, so 868 // we have to jump through hoops to get a better value. 869 function getComputedStyle(prop, el) { 870 var retVal = 0 871 el = el || document.body // Not testable in phantonJS 872 873 retVal = document.defaultView.getComputedStyle(el, null) 874 retVal = null === retVal ? 0 : retVal[prop] 875 876 return parseInt(retVal, base) 877 } 878 879 function chkEventThottle(timer) { 880 if (timer > throttledTimer / 2) { 881 throttledTimer = 2 * timer 882 log('Event throttle increased to ' + throttledTimer + 'ms') 883 } 884 } 885 886 // Idea from https://github.com/guardian/iframe-messenger 887 function getMaxElement(side, elements) { 888 var elementsLength = elements.length, 889 elVal = 0, 890 maxVal = 0, 891 Side = capitalizeFirstLetter(side), 892 timer = Date.now() 893 894 for (var i = 0; i < elementsLength; i++) { 895 elVal = 896 elements[i].getBoundingClientRect()[side] + 897 getComputedStyle('margin' + Side, elements[i]) 898 if (elVal > maxVal) { 899 maxVal = elVal 900 } 901 } 902 903 timer = Date.now() - timer 904 905 log('Parsed ' + elementsLength + ' HTML elements') 906 log('Element position calculated in ' + timer + 'ms') 907 908 chkEventThottle(timer) 909 910 return maxVal 911 } 912 913 function getAllMeasurements(dimensions) { 914 return [ 915 dimensions.bodyOffset(), 916 dimensions.bodyScroll(), 917 dimensions.documentElementOffset(), 918 dimensions.documentElementScroll() 919 ] 920 } 921 922 function getTaggedElements(side, tag) { 923 function noTaggedElementsFound() { 924 warn('No tagged elements (' + tag + ') found on page') 925 return document.querySelectorAll('body *') 926 } 927 928 var elements = document.querySelectorAll('[' + tag + ']') 929 930 if (elements.length === 0) noTaggedElementsFound() 931 932 return getMaxElement(side, elements) 933 } 934 935 function getAllElements() { 936 return document.querySelectorAll('body *') 937 } 938 939 var getHeight = { 940 bodyOffset: function getBodyOffsetHeight() { 941 return ( 942 document.body.offsetHeight + 943 getComputedStyle('marginTop') + 944 getComputedStyle('marginBottom') 945 ) 946 }, 947 948 offset: function () { 949 return getHeight.bodyOffset() // Backwards compatibility 950 }, 951 952 bodyScroll: function getBodyScrollHeight() { 953 return document.body.scrollHeight 954 }, 955 956 custom: function getCustomWidth() { 957 return customCalcMethods.height() 958 }, 959 960 documentElementOffset: function getDEOffsetHeight() { 961 return document.documentElement.offsetHeight 962 }, 963 964 documentElementScroll: function getDEScrollHeight() { 965 return document.documentElement.scrollHeight 966 }, 967 968 max: function getMaxHeight() { 969 return Math.max.apply(null, getAllMeasurements(getHeight)) 970 }, 971 972 min: function getMinHeight() { 973 return Math.min.apply(null, getAllMeasurements(getHeight)) 974 }, 975 976 grow: function growHeight() { 977 return getHeight.max() // Run max without the forced downsizing 978 }, 979 980 lowestElement: function getBestHeight() { 981 return Math.max( 982 getHeight.bodyOffset() || getHeight.documentElementOffset(), 983 getMaxElement('bottom', getAllElements()) 984 ) 985 }, 986 987 taggedElement: function getTaggedElementsHeight() { 988 return getTaggedElements('bottom', 'data-iframe-height') 989 } 990 }, 991 getWidth = { 992 bodyScroll: function getBodyScrollWidth() { 993 return document.body.scrollWidth 994 }, 995 996 bodyOffset: function getBodyOffsetWidth() { 997 return document.body.offsetWidth 998 }, 999 1000 custom: function getCustomWidth() { 1001 return customCalcMethods.width() 1002 }, 1003 1004 documentElementScroll: function getDEScrollWidth() { 1005 return document.documentElement.scrollWidth 1006 }, 1007 1008 documentElementOffset: function getDEOffsetWidth() { 1009 return document.documentElement.offsetWidth 1010 }, 1011 1012 scroll: function getMaxWidth() { 1013 return Math.max(getWidth.bodyScroll(), getWidth.documentElementScroll()) 1014 }, 1015 1016 max: function getMaxWidth() { 1017 return Math.max.apply(null, getAllMeasurements(getWidth)) 1018 }, 1019 1020 min: function getMinWidth() { 1021 return Math.min.apply(null, getAllMeasurements(getWidth)) 1022 }, 1023 1024 rightMostElement: function rightMostElement() { 1025 return getMaxElement('right', getAllElements()) 1026 }, 1027 1028 taggedElement: function getTaggedElementsWidth() { 1029 return getTaggedElements('right', 'data-iframe-width') 1030 } 1031 } 1032 1033 function sizeIFrame( 1034 triggerEvent, 1035 triggerEventDesc, 1036 customHeight, 1037 customWidth 1038 ) { 1039 function resizeIFrame() { 1040 height = currentHeight 1041 width = currentWidth 1042 1043 sendMsg(height, width, triggerEvent) 1044 } 1045 1046 function isSizeChangeDetected() { 1047 function checkTolarance(a, b) { 1048 var retVal = Math.abs(a - b) <= tolerance 1049 return !retVal 1050 } 1051 1052 currentHeight = 1053 undefined === customHeight ? getHeight[heightCalcMode]() : customHeight 1054 currentWidth = 1055 undefined === customWidth ? getWidth[widthCalcMode]() : customWidth 1056 1057 return ( 1058 checkTolarance(height, currentHeight) || 1059 (calculateWidth && checkTolarance(width, currentWidth)) 1060 ) 1061 } 1062 1063 function isForceResizableEvent() { 1064 return !(triggerEvent in { init: 1, interval: 1, size: 1 }) 1065 } 1066 1067 function isForceResizableCalcMode() { 1068 return ( 1069 heightCalcMode in resetRequiredMethods || 1070 (calculateWidth && widthCalcMode in resetRequiredMethods) 1071 ) 1072 } 1073 1074 function logIgnored() { 1075 log('No change in size detected') 1076 } 1077 1078 function checkDownSizing() { 1079 if (isForceResizableEvent() && isForceResizableCalcMode()) { 1080 resetIFrame(triggerEventDesc) 1081 } else if (!(triggerEvent in { interval: 1 })) { 1082 logIgnored() 1083 } 1084 } 1085 1086 var currentHeight, currentWidth 1087 1088 if (isSizeChangeDetected() || 'init' === triggerEvent) { 1089 lockTrigger() 1090 resizeIFrame() 1091 } else { 1092 checkDownSizing() 1093 } 1094 } 1095 1096 var sizeIFrameThrottled = throttle(sizeIFrame) 1097 1098 function sendSize(triggerEvent, triggerEventDesc, customHeight, customWidth) { 1099 function recordTrigger() { 1100 if (!(triggerEvent in { reset: 1, resetPage: 1, init: 1 })) { 1101 log('Trigger event: ' + triggerEventDesc) 1102 } 1103 } 1104 1105 function isDoubleFiredEvent() { 1106 return triggerLocked && triggerEvent in doubleEventList 1107 } 1108 1109 if (isDoubleFiredEvent()) { 1110 log('Trigger event cancelled: ' + triggerEvent) 1111 } else { 1112 recordTrigger() 1113 if (triggerEvent === 'init') { 1114 sizeIFrame(triggerEvent, triggerEventDesc, customHeight, customWidth) 1115 } else { 1116 sizeIFrameThrottled( 1117 triggerEvent, 1118 triggerEventDesc, 1119 customHeight, 1120 customWidth 1121 ) 1122 } 1123 } 1124 } 1125 1126 function lockTrigger() { 1127 if (!triggerLocked) { 1128 triggerLocked = true 1129 log('Trigger event lock on') 1130 } 1131 clearTimeout(triggerLockedTimer) 1132 triggerLockedTimer = setTimeout(function () { 1133 triggerLocked = false 1134 log('Trigger event lock off') 1135 log('--') 1136 }, eventCancelTimer) 1137 } 1138 1139 function triggerReset(triggerEvent) { 1140 height = getHeight[heightCalcMode]() 1141 width = getWidth[widthCalcMode]() 1142 1143 sendMsg(height, width, triggerEvent) 1144 } 1145 1146 function resetIFrame(triggerEventDesc) { 1147 var hcm = heightCalcMode 1148 heightCalcMode = heightCalcModeDefault 1149 1150 log('Reset trigger event: ' + triggerEventDesc) 1151 lockTrigger() 1152 triggerReset('reset') 1153 1154 heightCalcMode = hcm 1155 } 1156 1157 function sendMsg(height, width, triggerEvent, msg, targetOrigin) { 1158 function setTargetOrigin() { 1159 if (undefined === targetOrigin) { 1160 targetOrigin = targetOriginDefault 1161 } else { 1162 log('Message targetOrigin: ' + targetOrigin) 1163 } 1164 } 1165 1166 function sendToParent() { 1167 var size = height + ':' + width, 1168 message = 1169 myID + 1170 ':' + 1171 size + 1172 ':' + 1173 triggerEvent + 1174 (undefined === msg ? '' : ':' + msg) 1175 1176 log('Sending message to host page (' + message + ')') 1177 target.postMessage(msgID + message, targetOrigin) 1178 } 1179 1180 if (true === sendPermit) { 1181 setTargetOrigin() 1182 sendToParent() 1183 } 1184 } 1185 1186 function receiver(event) { 1187 var processRequestFromParent = { 1188 init: function initFromParent() { 1189 initMsg = event.data 1190 target = event.source 1191 1192 init() 1193 firstRun = false 1194 setTimeout(function () { 1195 initLock = false 1196 }, eventCancelTimer) 1197 }, 1198 1199 reset: function resetFromParent() { 1200 if (initLock) { 1201 log('Page reset ignored by init') 1202 } else { 1203 log('Page size reset by host page') 1204 triggerReset('resetPage') 1205 } 1206 }, 1207 1208 resize: function resizeFromParent() { 1209 sendSize('resizeParent', 'Parent window requested size check') 1210 }, 1211 1212 moveToAnchor: function moveToAnchorF() { 1213 inPageLinks.findTarget(getData()) 1214 }, 1215 inPageLink: function inPageLinkF() { 1216 this.moveToAnchor() 1217 }, // Backward compatibility 1218 1219 pageInfo: function pageInfoFromParent() { 1220 var msgBody = getData() 1221 log('PageInfoFromParent called from parent: ' + msgBody) 1222 onPageInfo(JSON.parse(msgBody)) 1223 log(' --') 1224 }, 1225 1226 message: function messageFromParent() { 1227 var msgBody = getData() 1228 1229 log('onMessage called from parent: ' + msgBody) 1230 // eslint-disable-next-line sonarjs/no-extra-arguments 1231 onMessage(JSON.parse(msgBody)) 1232 log(' --') 1233 } 1234 } 1235 1236 function isMessageForUs() { 1237 return msgID === ('' + event.data).slice(0, msgIdLen) // ''+ Protects against non-string messages 1238 } 1239 1240 function getMessageType() { 1241 return event.data.split(']')[1].split(':')[0] 1242 } 1243 1244 function getData() { 1245 return event.data.slice(event.data.indexOf(':') + 1) 1246 } 1247 1248 function isMiddleTier() { 1249 return ( 1250 (!(typeof module !== 'undefined' && module.exports) && 1251 'iFrameResize' in window) || 1252 (window.jQuery !== undefined && 1253 'iFrameResize' in window.jQuery.prototype) 1254 ) 1255 } 1256 1257 function isInitMsg() { 1258 // Test if this message is from a child below us. This is an ugly test, however, updating 1259 // the message format would break backwards compatibility. 1260 return event.data.split(':')[2] in { true: 1, false: 1 } 1261 } 1262 1263 function callFromParent() { 1264 var messageType = getMessageType() 1265 1266 if (messageType in processRequestFromParent) { 1267 processRequestFromParent[messageType]() 1268 } else if (!isMiddleTier() && !isInitMsg()) { 1269 warn('Unexpected message (' + event.data + ')') 1270 } 1271 } 1272 1273 function processMessage() { 1274 if (false === firstRun) { 1275 callFromParent() 1276 } else if (isInitMsg()) { 1277 processRequestFromParent.init() 1278 } else { 1279 log( 1280 'Ignored message of type "' + 1281 getMessageType() + 1282 '". Received before initialization.' 1283 ) 1284 } 1285 } 1286 1287 if (isMessageForUs()) { 1288 processMessage() 1289 } 1290 } 1291 1292 // Normally the parent kicks things off when it detects the iFrame has loaded. 1293 // If this script is async-loaded, then tell parent page to retry init. 1294 function chkLateLoaded() { 1295 if ('loading' !== document.readyState) { 1296 window.parent.postMessage('[iFrameResizerChild]Ready', '*') 1297 } 1298 } 1299 1300 // Setup if not already running 1301 if (!('iframeResizer' in window)) { 1302 window.iframeChildListener = function (data) { 1303 receiver({ data, sameDomian: true }) 1304 } 1305 addEventListener(window, 'message', receiver) 1306 addEventListener(window, 'readystatechange', chkLateLoaded) 1307 chkLateLoaded() 1308 } 1309 1310 1311})()
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.