balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

iframeResizer.js (32229B)


      1 "use strict";
      2 
      3 function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
      4 
      5 /*
      6  * File: iframeResizer.js
      7  * Desc: Force iframes to size to content.
      8  * Requires: iframeResizer.contentWindow.js to be loaded into the target frame.
      9  * Doc: https://github.com/davidjbradshaw/iframe-resizer
     10  * Author: David J. Bradshaw - dave@bradshaw.net
     11  * Contributor: Jure Mav - jure.mav@gmail.com
     12  * Contributor: Reed Dadoune - reed@dadoune.com
     13  */
     14 (function (undefined) {
     15   'use strict';
     16 
     17   if (typeof window === 'undefined') return; // don't run for server side render
     18 
     19   var count = 0,
     20       logEnabled = false,
     21       hiddenCheckEnabled = false,
     22       msgHeader = 'message',
     23       msgHeaderLen = msgHeader.length,
     24       msgId = '[iFrameSizer]',
     25       //Must match iframe msg ID
     26   msgIdLen = msgId.length,
     27       pagePosition = null,
     28       requestAnimationFrame = window.requestAnimationFrame,
     29       resetRequiredMethods = {
     30     max: 1,
     31     scroll: 1,
     32     bodyScroll: 1,
     33     documentElementScroll: 1
     34   },
     35       settings = {},
     36       timer = null,
     37       logId = 'Host Page',
     38       defaults = {
     39     autoResize: true,
     40     bodyBackground: null,
     41     bodyMargin: null,
     42     bodyMarginV1: 8,
     43     bodyPadding: null,
     44     checkOrigin: true,
     45     inPageLinks: false,
     46     enablePublicMethods: true,
     47     heightCalculationMethod: 'bodyOffset',
     48     id: 'iFrameResizer',
     49     interval: 32,
     50     log: false,
     51     maxHeight: Infinity,
     52     maxWidth: Infinity,
     53     minHeight: 0,
     54     minWidth: 0,
     55     resizeFrom: 'parent',
     56     scrolling: false,
     57     sizeHeight: true,
     58     sizeWidth: false,
     59     warningTimeout: 5000,
     60     tolerance: 0,
     61     widthCalculationMethod: 'scroll',
     62     closedCallback: function closedCallback() {},
     63     initCallback: function initCallback() {},
     64     messageCallback: function messageCallback() {
     65       warn('MessageCallback function not defined');
     66     },
     67     resizedCallback: function resizedCallback() {},
     68     scrollCallback: function scrollCallback() {
     69       return true;
     70     }
     71   };
     72 
     73   function addEventListener(obj, evt, func) {
     74     /* istanbul ignore else */
     75     // Not testable in PhantonJS
     76     if ('addEventListener' in window) {
     77       obj.addEventListener(evt, func, false);
     78     } else if ('attachEvent' in window) {
     79       //IE
     80       obj.attachEvent('on' + evt, func);
     81     }
     82   }
     83 
     84   function removeEventListener(el, evt, func) {
     85     /* istanbul ignore else */
     86     // Not testable in phantonJS
     87     if ('removeEventListener' in window) {
     88       el.removeEventListener(evt, func, false);
     89     } else if ('detachEvent' in window) {
     90       //IE
     91       el.detachEvent('on' + evt, func);
     92     }
     93   }
     94 
     95   function setupRequestAnimationFrame() {
     96     var vendors = ['moz', 'webkit', 'o', 'ms'],
     97         x; // Remove vendor prefixing if prefixed and break early if not
     98 
     99     for (x = 0; x < vendors.length && !requestAnimationFrame; x += 1) {
    100       requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
    101     }
    102 
    103     if (!requestAnimationFrame) {
    104       log('setup', 'RequestAnimationFrame not supported');
    105     }
    106   }
    107 
    108   function getMyID(iframeId) {
    109     var retStr = 'Host page: ' + iframeId;
    110 
    111     if (window.top !== window.self) {
    112       if (window.parentIFrame && window.parentIFrame.getId) {
    113         retStr = window.parentIFrame.getId() + ': ' + iframeId;
    114       } else {
    115         retStr = 'Nested host page: ' + iframeId;
    116       }
    117     }
    118 
    119     return retStr;
    120   }
    121 
    122   function formatLogHeader(iframeId) {
    123     return msgId + '[' + getMyID(iframeId) + ']';
    124   }
    125 
    126   function isLogEnabled(iframeId) {
    127     return settings[iframeId] ? settings[iframeId].log : logEnabled;
    128   }
    129 
    130   function log(iframeId, msg) {
    131     output('log', iframeId, msg, isLogEnabled(iframeId));
    132   }
    133 
    134   function info(iframeId, msg) {
    135     output('info', iframeId, msg, isLogEnabled(iframeId));
    136   }
    137 
    138   function warn(iframeId, msg) {
    139     output('warn', iframeId, msg, true);
    140   }
    141 
    142   function output(type, iframeId, msg, enabled) {
    143     if (true === enabled && 'object' === _typeof(window.console)) {
    144       console[type](formatLogHeader(iframeId), msg);
    145     }
    146   }
    147 
    148   function iFrameListener(event) {
    149     function resizeIFrame() {
    150       function resize() {
    151         setSize(messageData);
    152         setPagePosition(iframeId);
    153         callback('resizedCallback', messageData);
    154       }
    155 
    156       ensureInRange('Height');
    157       ensureInRange('Width');
    158       syncResize(resize, messageData, 'init');
    159     }
    160 
    161     function processMsg() {
    162       var data = msg.substr(msgIdLen).split(':');
    163       return {
    164         iframe: settings[data[0]] && settings[data[0]].iframe,
    165         id: data[0],
    166         height: data[1],
    167         width: data[2],
    168         type: data[3]
    169       };
    170     }
    171 
    172     function ensureInRange(Dimension) {
    173       var max = Number(settings[iframeId]['max' + Dimension]),
    174           min = Number(settings[iframeId]['min' + Dimension]),
    175           dimension = Dimension.toLowerCase(),
    176           size = Number(messageData[dimension]);
    177       log(iframeId, 'Checking ' + dimension + ' is in range ' + min + '-' + max);
    178 
    179       if (size < min) {
    180         size = min;
    181         log(iframeId, 'Set ' + dimension + ' to min value');
    182       }
    183 
    184       if (size > max) {
    185         size = max;
    186         log(iframeId, 'Set ' + dimension + ' to max value');
    187       }
    188 
    189       messageData[dimension] = '' + size;
    190     }
    191 
    192     function isMessageFromIFrame() {
    193       function checkAllowedOrigin() {
    194         function checkList() {
    195           var i = 0,
    196               retCode = false;
    197           log(iframeId, 'Checking connection is from allowed list of origins: ' + checkOrigin);
    198 
    199           for (; i < checkOrigin.length; i++) {
    200             if (checkOrigin[i] === origin) {
    201               retCode = true;
    202               break;
    203             }
    204           }
    205 
    206           return retCode;
    207         }
    208 
    209         function checkSingle() {
    210           var remoteHost = settings[iframeId] && settings[iframeId].remoteHost;
    211           log(iframeId, 'Checking connection is from: ' + remoteHost);
    212           return origin === remoteHost;
    213         }
    214 
    215         return checkOrigin.constructor === Array ? checkList() : checkSingle();
    216       }
    217 
    218       var origin = event.origin,
    219           checkOrigin = settings[iframeId] && settings[iframeId].checkOrigin;
    220 
    221       if (checkOrigin && '' + origin !== 'null' && !checkAllowedOrigin()) {
    222         throw new Error('Unexpected message received from: ' + origin + ' for ' + messageData.iframe.id + '. Message was: ' + event.data + '. This error can be disabled by setting the checkOrigin: false option or by providing of array of trusted domains.');
    223       }
    224 
    225       return true;
    226     }
    227 
    228     function isMessageForUs() {
    229       return msgId === ('' + msg).substr(0, msgIdLen) && msg.substr(msgIdLen).split(':')[0] in settings; //''+Protects against non-string msg
    230     }
    231 
    232     function isMessageFromMetaParent() {
    233       //Test if this message is from a parent above us. This is an ugly test, however, updating
    234       //the message format would break backwards compatibity.
    235       var retCode = messageData.type in {
    236         true: 1,
    237         false: 1,
    238         undefined: 1
    239       };
    240 
    241       if (retCode) {
    242         log(iframeId, 'Ignoring init message from meta parent page');
    243       }
    244 
    245       return retCode;
    246     }
    247 
    248     function getMsgBody(offset) {
    249       return msg.substr(msg.indexOf(':') + msgHeaderLen + offset);
    250     }
    251 
    252     function forwardMsgFromIFrame(msgBody) {
    253       log(iframeId, 'MessageCallback passed: {iframe: ' + messageData.iframe.id + ', message: ' + msgBody + '}');
    254       callback('messageCallback', {
    255         iframe: messageData.iframe,
    256         message: JSON.parse(msgBody)
    257       });
    258       log(iframeId, '--');
    259     }
    260 
    261     function getPageInfo() {
    262       var bodyPosition = document.body.getBoundingClientRect(),
    263           iFramePosition = messageData.iframe.getBoundingClientRect();
    264       return JSON.stringify({
    265         iframeHeight: iFramePosition.height,
    266         iframeWidth: iFramePosition.width,
    267         clientHeight: Math.max(document.documentElement.clientHeight, window.innerHeight || 0),
    268         clientWidth: Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
    269         offsetTop: parseInt(iFramePosition.top - bodyPosition.top, 10),
    270         offsetLeft: parseInt(iFramePosition.left - bodyPosition.left, 10),
    271         scrollTop: window.pageYOffset,
    272         scrollLeft: window.pageXOffset
    273       });
    274     }
    275 
    276     function sendPageInfoToIframe(iframe, iframeId) {
    277       function debouncedTrigger() {
    278         trigger('Send Page Info', 'pageInfo:' + getPageInfo(), iframe, iframeId);
    279       }
    280 
    281       debounceFrameEvents(debouncedTrigger, 32, iframeId);
    282     }
    283 
    284     function startPageInfoMonitor() {
    285       function setListener(type, func) {
    286         function sendPageInfo() {
    287           if (settings[id]) {
    288             sendPageInfoToIframe(settings[id].iframe, id);
    289           } else {
    290             stop();
    291           }
    292         }
    293 
    294         ['scroll', 'resize'].forEach(function (evt) {
    295           log(id, type + evt + ' listener for sendPageInfo');
    296           func(window, evt, sendPageInfo);
    297         });
    298       }
    299 
    300       function stop() {
    301         setListener('Remove ', removeEventListener);
    302       }
    303 
    304       function start() {
    305         setListener('Add ', addEventListener);
    306       }
    307 
    308       var id = iframeId; //Create locally scoped copy of iFrame ID
    309 
    310       start();
    311 
    312       if (settings[id]) {
    313         settings[id].stopPageInfo = stop;
    314       }
    315     }
    316 
    317     function stopPageInfoMonitor() {
    318       if (settings[iframeId] && settings[iframeId].stopPageInfo) {
    319         settings[iframeId].stopPageInfo();
    320         delete settings[iframeId].stopPageInfo;
    321       }
    322     }
    323 
    324     function checkIFrameExists() {
    325       var retBool = true;
    326 
    327       if (null === messageData.iframe) {
    328         warn(iframeId, 'IFrame (' + messageData.id + ') not found');
    329         retBool = false;
    330       }
    331 
    332       return retBool;
    333     }
    334 
    335     function getElementPosition(target) {
    336       var iFramePosition = target.getBoundingClientRect();
    337       getPagePosition(iframeId);
    338       return {
    339         x: Math.floor(Number(iFramePosition.left) + Number(pagePosition.x)),
    340         y: Math.floor(Number(iFramePosition.top) + Number(pagePosition.y))
    341       };
    342     }
    343 
    344     function scrollRequestFromChild(addOffset) {
    345       /* istanbul ignore next */
    346       //Not testable in Karma
    347       function reposition() {
    348         pagePosition = newPosition;
    349         scrollTo();
    350         log(iframeId, '--');
    351       }
    352 
    353       function calcOffset() {
    354         return {
    355           x: Number(messageData.width) + offset.x,
    356           y: Number(messageData.height) + offset.y
    357         };
    358       }
    359 
    360       function scrollParent() {
    361         if (window.parentIFrame) {
    362           window.parentIFrame['scrollTo' + (addOffset ? 'Offset' : '')](newPosition.x, newPosition.y);
    363         } else {
    364           warn(iframeId, 'Unable to scroll to requested position, window.parentIFrame not found');
    365         }
    366       }
    367 
    368       var offset = addOffset ? getElementPosition(messageData.iframe) : {
    369         x: 0,
    370         y: 0
    371       },
    372           newPosition = calcOffset();
    373       log(iframeId, 'Reposition requested from iFrame (offset x:' + offset.x + ' y:' + offset.y + ')');
    374 
    375       if (window.top !== window.self) {
    376         scrollParent();
    377       } else {
    378         reposition();
    379       }
    380     }
    381 
    382     function scrollTo() {
    383       if (false !== callback('scrollCallback', pagePosition)) {
    384         setPagePosition(iframeId);
    385       } else {
    386         unsetPagePosition();
    387       }
    388     }
    389 
    390     function findTarget(location) {
    391       function jumpToTarget() {
    392         var jumpPosition = getElementPosition(target);
    393         log(iframeId, 'Moving to in page link (#' + hash + ') at x: ' + jumpPosition.x + ' y: ' + jumpPosition.y);
    394         pagePosition = {
    395           x: jumpPosition.x,
    396           y: jumpPosition.y
    397         };
    398         scrollTo();
    399         log(iframeId, '--');
    400       }
    401 
    402       function jumpToParent() {
    403         if (window.parentIFrame) {
    404           window.parentIFrame.moveToAnchor(hash);
    405         } else {
    406           log(iframeId, 'In page link #' + hash + ' not found and window.parentIFrame not found');
    407         }
    408       }
    409 
    410       var hash = location.split('#')[1] || '',
    411           hashData = decodeURIComponent(hash),
    412           target = document.getElementById(hashData) || document.getElementsByName(hashData)[0];
    413 
    414       if (target) {
    415         jumpToTarget();
    416       } else if (window.top !== window.self) {
    417         jumpToParent();
    418       } else {
    419         log(iframeId, 'In page link #' + hash + ' not found');
    420       }
    421     }
    422 
    423     function callback(funcName, val) {
    424       return chkCallback(iframeId, funcName, val);
    425     }
    426 
    427     function actionMsg() {
    428       if (settings[iframeId] && settings[iframeId].firstRun) firstRun();
    429 
    430       switch (messageData.type) {
    431         case 'close':
    432           if (settings[iframeId].closeRequestCallback) chkCallback(iframeId, 'closeRequestCallback', settings[iframeId].iframe);else closeIFrame(messageData.iframe);
    433           break;
    434 
    435         case 'message':
    436           forwardMsgFromIFrame(getMsgBody(6));
    437           break;
    438 
    439         case 'scrollTo':
    440           scrollRequestFromChild(false);
    441           break;
    442 
    443         case 'scrollToOffset':
    444           scrollRequestFromChild(true);
    445           break;
    446 
    447         case 'pageInfo':
    448           sendPageInfoToIframe(settings[iframeId] && settings[iframeId].iframe, iframeId);
    449           startPageInfoMonitor();
    450           break;
    451 
    452         case 'pageInfoStop':
    453           stopPageInfoMonitor();
    454           break;
    455 
    456         case 'inPageLink':
    457           findTarget(getMsgBody(9));
    458           break;
    459 
    460         case 'reset':
    461           resetIFrame(messageData);
    462           break;
    463 
    464         case 'init':
    465           resizeIFrame();
    466           callback('initCallback', messageData.iframe);
    467           break;
    468 
    469         default:
    470           resizeIFrame();
    471       }
    472     }
    473 
    474     function hasSettings(iframeId) {
    475       var retBool = true;
    476 
    477       if (!settings[iframeId]) {
    478         retBool = false;
    479         warn(messageData.type + ' No settings for ' + iframeId + '. Message was: ' + msg);
    480       }
    481 
    482       return retBool;
    483     }
    484 
    485     function iFrameReadyMsgReceived() {
    486       for (var iframeId in settings) {
    487         trigger('iFrame requested init', createOutgoingMsg(iframeId), document.getElementById(iframeId), iframeId);
    488       }
    489     }
    490 
    491     function firstRun() {
    492       if (settings[iframeId]) {
    493         settings[iframeId].firstRun = false;
    494       }
    495     }
    496 
    497     function clearWarningTimeout() {
    498       if (settings[iframeId]) {
    499         clearTimeout(settings[iframeId].msgTimeout);
    500         settings[iframeId].warningTimeout = 0;
    501       }
    502     }
    503 
    504     var msg = event.data,
    505         messageData = {},
    506         iframeId = null;
    507 
    508     if ('[iFrameResizerChild]Ready' === msg) {
    509       iFrameReadyMsgReceived();
    510     } else if (isMessageForUs()) {
    511       messageData = processMsg();
    512       iframeId = logId = messageData.id;
    513 
    514       if (settings[iframeId]) {
    515         settings[iframeId].loaded = true;
    516       }
    517 
    518       if (!isMessageFromMetaParent() && hasSettings(iframeId)) {
    519         log(iframeId, 'Received: ' + msg);
    520 
    521         if (checkIFrameExists() && isMessageFromIFrame()) {
    522           actionMsg();
    523         }
    524       }
    525     } else {
    526       info(iframeId, 'Ignored: ' + msg);
    527     }
    528   }
    529 
    530   function chkCallback(iframeId, funcName, val) {
    531     var func = null,
    532         retVal = null;
    533 
    534     if (settings[iframeId]) {
    535       func = settings[iframeId][funcName];
    536 
    537       if ('function' === typeof func) {
    538         retVal = func(val);
    539       } else {
    540         throw new TypeError(funcName + ' on iFrame[' + iframeId + '] is not a function');
    541       }
    542     }
    543 
    544     return retVal;
    545   }
    546 
    547   function removeIframeListeners(iframe) {
    548     var iframeId = iframe.id;
    549     delete settings[iframeId];
    550   }
    551 
    552   function closeIFrame(iframe) {
    553     var iframeId = iframe.id;
    554     log(iframeId, 'Removing iFrame: ' + iframeId);
    555 
    556     try {
    557       // Catch race condition error with React
    558       if (iframe.parentNode) {
    559         iframe.parentNode.removeChild(iframe);
    560       }
    561     } catch (e) {}
    562 
    563     chkCallback(iframeId, 'closedCallback', iframeId);
    564     log(iframeId, '--');
    565     removeIframeListeners(iframe);
    566   }
    567 
    568   function getPagePosition(iframeId) {
    569     if (null === pagePosition) {
    570       pagePosition = {
    571         x: window.pageXOffset !== undefined ? window.pageXOffset : document.documentElement.scrollLeft,
    572         y: window.pageYOffset !== undefined ? window.pageYOffset : document.documentElement.scrollTop
    573       };
    574       log(iframeId, 'Get page position: ' + pagePosition.x + ',' + pagePosition.y);
    575     }
    576   }
    577 
    578   function setPagePosition(iframeId) {
    579     if (null !== pagePosition) {
    580       window.scrollTo(pagePosition.x, pagePosition.y);
    581       log(iframeId, 'Set page position: ' + pagePosition.x + ',' + pagePosition.y);
    582       unsetPagePosition();
    583     }
    584   }
    585 
    586   function unsetPagePosition() {
    587     pagePosition = null;
    588   }
    589 
    590   function resetIFrame(messageData) {
    591     function reset() {
    592       setSize(messageData);
    593       trigger('reset', 'reset', messageData.iframe, messageData.id);
    594     }
    595 
    596     log(messageData.id, 'Size reset requested by ' + ('init' === messageData.type ? 'host page' : 'iFrame'));
    597     getPagePosition(messageData.id);
    598     syncResize(reset, messageData, 'reset');
    599   }
    600 
    601   function setSize(messageData) {
    602     function setDimension(dimension) {
    603       if (!messageData.id) {
    604         log('undefined', 'messageData id not set');
    605         return;
    606       }
    607 
    608       messageData.iframe.style[dimension] = messageData[dimension] + 'px';
    609       log(messageData.id, 'IFrame (' + iframeId + ') ' + dimension + ' set to ' + messageData[dimension] + 'px');
    610     }
    611 
    612     function chkZero(dimension) {
    613       //FireFox sets dimension of hidden iFrames to zero.
    614       //So if we detect that set up an event to check for
    615       //when iFrame becomes visible.
    616 
    617       /* istanbul ignore next */
    618       //Not testable in PhantomJS
    619       if (!hiddenCheckEnabled && '0' === messageData[dimension]) {
    620         hiddenCheckEnabled = true;
    621         log(iframeId, 'Hidden iFrame detected, creating visibility listener');
    622         fixHiddenIFrames();
    623       }
    624     }
    625 
    626     function processDimension(dimension) {
    627       setDimension(dimension);
    628       chkZero(dimension);
    629     }
    630 
    631     var iframeId = messageData.iframe.id;
    632 
    633     if (settings[iframeId]) {
    634       if (settings[iframeId].sizeHeight) {
    635         processDimension('height');
    636       }
    637 
    638       if (settings[iframeId].sizeWidth) {
    639         processDimension('width');
    640       }
    641     }
    642   }
    643 
    644   function syncResize(func, messageData, doNotSync) {
    645     /* istanbul ignore if */
    646     //Not testable in PhantomJS
    647     if (doNotSync !== messageData.type && requestAnimationFrame) {
    648       log(messageData.id, 'Requesting animation frame');
    649       requestAnimationFrame(func);
    650     } else {
    651       func();
    652     }
    653   }
    654 
    655   function trigger(calleeMsg, msg, iframe, id, noResponseWarning) {
    656     function postMessageToIFrame() {
    657       var target = settings[id] && settings[id].targetOrigin;
    658       log(id, '[' + calleeMsg + '] Sending msg to iframe[' + id + '] (' + msg + ') targetOrigin: ' + target);
    659       iframe.contentWindow.postMessage(msgId + msg, target);
    660     }
    661 
    662     function iFrameNotFound() {
    663       warn(id, '[' + calleeMsg + '] IFrame(' + id + ') not found');
    664     }
    665 
    666     function chkAndSend() {
    667       if (iframe && 'contentWindow' in iframe && null !== iframe.contentWindow) {
    668         //Null test for PhantomJS
    669         postMessageToIFrame();
    670       } else {
    671         iFrameNotFound();
    672       }
    673     }
    674 
    675     function warnOnNoResponse() {
    676       function warning() {
    677         if (settings[id] && !settings[id].loaded && !errorShown) {
    678           errorShown = true;
    679           warn(id, 'IFrame has not responded within ' + settings[id].warningTimeout / 1000 + ' seconds. Check iFrameResizer.contentWindow.js has been loaded in iFrame. This message can be ignored if everything is working, or you can set the warningTimeout option to a higher value or zero to suppress this warning.');
    680         }
    681       }
    682 
    683       if (!!noResponseWarning && settings[id] && !!settings[id].warningTimeout) {
    684         settings[id].msgTimeout = setTimeout(warning, settings[id].warningTimeout);
    685       }
    686     }
    687 
    688     var errorShown = false;
    689     id = id || iframe.id;
    690 
    691     if (settings[id]) {
    692       chkAndSend();
    693       warnOnNoResponse();
    694     }
    695   }
    696 
    697   function createOutgoingMsg(iframeId) {
    698     return iframeId + ':' + settings[iframeId].bodyMarginV1 + ':' + settings[iframeId].sizeWidth + ':' + settings[iframeId].log + ':' + settings[iframeId].interval + ':' + settings[iframeId].enablePublicMethods + ':' + settings[iframeId].autoResize + ':' + settings[iframeId].bodyMargin + ':' + settings[iframeId].heightCalculationMethod + ':' + settings[iframeId].bodyBackground + ':' + settings[iframeId].bodyPadding + ':' + settings[iframeId].tolerance + ':' + settings[iframeId].inPageLinks + ':' + settings[iframeId].resizeFrom + ':' + settings[iframeId].widthCalculationMethod;
    699   }
    700 
    701   function setupIFrame(iframe, options) {
    702     function setLimits() {
    703       function addStyle(style) {
    704         if (Infinity !== settings[iframeId][style] && 0 !== settings[iframeId][style]) {
    705           iframe.style[style] = settings[iframeId][style] + 'px';
    706           log(iframeId, 'Set ' + style + ' = ' + settings[iframeId][style] + 'px');
    707         }
    708       }
    709 
    710       function chkMinMax(dimension) {
    711         if (settings[iframeId]['min' + dimension] > settings[iframeId]['max' + dimension]) {
    712           throw new Error('Value for min' + dimension + ' can not be greater than max' + dimension);
    713         }
    714       }
    715 
    716       chkMinMax('Height');
    717       chkMinMax('Width');
    718       addStyle('maxHeight');
    719       addStyle('minHeight');
    720       addStyle('maxWidth');
    721       addStyle('minWidth');
    722     }
    723 
    724     function newId() {
    725       var id = options && options.id || defaults.id + count++;
    726 
    727       if (null !== document.getElementById(id)) {
    728         id = id + count++;
    729       }
    730 
    731       return id;
    732     }
    733 
    734     function ensureHasId(iframeId) {
    735       logId = iframeId;
    736 
    737       if ('' === iframeId) {
    738         iframe.id = iframeId = newId();
    739         logEnabled = (options || {}).log;
    740         logId = iframeId;
    741         log(iframeId, 'Added missing iframe ID: ' + iframeId + ' (' + iframe.src + ')');
    742       }
    743 
    744       return iframeId;
    745     }
    746 
    747     function setScrolling() {
    748       log(iframeId, 'IFrame scrolling ' + (settings[iframeId] && settings[iframeId].scrolling ? 'enabled' : 'disabled') + ' for ' + iframeId);
    749       iframe.style.overflow = false === (settings[iframeId] && settings[iframeId].scrolling) ? 'hidden' : 'auto';
    750 
    751       switch (settings[iframeId] && settings[iframeId].scrolling) {
    752         case 'omit':
    753           break;
    754 
    755         case true:
    756           iframe.scrolling = 'yes';
    757           break;
    758 
    759         case false:
    760           iframe.scrolling = 'no';
    761           break;
    762 
    763         default:
    764           iframe.scrolling = settings[iframeId] ? settings[iframeId].scrolling : 'no';
    765       }
    766     } //The V1 iFrame script expects an int, where as in V2 expects a CSS
    767     //string value such as '1px 3em', so if we have an int for V2, set V1=V2
    768     //and then convert V2 to a string PX value.
    769 
    770 
    771     function setupBodyMarginValues() {
    772       if ('number' === typeof (settings[iframeId] && settings[iframeId].bodyMargin) || '0' === (settings[iframeId] && settings[iframeId].bodyMargin)) {
    773         settings[iframeId].bodyMarginV1 = settings[iframeId].bodyMargin;
    774         settings[iframeId].bodyMargin = '' + settings[iframeId].bodyMargin + 'px';
    775       }
    776     }
    777 
    778     function checkReset() {
    779       // Reduce scope of firstRun to function, because IE8's JS execution
    780       // context stack is borked and this value gets externally
    781       // changed midway through running this function!!!
    782       var firstRun = settings[iframeId] && settings[iframeId].firstRun,
    783           resetRequertMethod = settings[iframeId] && settings[iframeId].heightCalculationMethod in resetRequiredMethods;
    784 
    785       if (!firstRun && resetRequertMethod) {
    786         resetIFrame({
    787           iframe: iframe,
    788           height: 0,
    789           width: 0,
    790           type: 'init'
    791         });
    792       }
    793     }
    794 
    795     function setupIFrameObject() {
    796       if (Function.prototype.bind && settings[iframeId]) {
    797         //Ignore unpolyfilled IE8.
    798         settings[iframeId].iframe.iFrameResizer = {
    799           close: closeIFrame.bind(null, settings[iframeId].iframe),
    800           removeListeners: removeIframeListeners.bind(null, settings[iframeId].iframe),
    801           resize: trigger.bind(null, 'Window resize', 'resize', settings[iframeId].iframe),
    802           moveToAnchor: function moveToAnchor(anchor) {
    803             trigger('Move to anchor', 'moveToAnchor:' + anchor, settings[iframeId].iframe, iframeId);
    804           },
    805           sendMessage: function sendMessage(message) {
    806             message = JSON.stringify(message);
    807             trigger('Send Message', 'message:' + message, settings[iframeId].iframe, iframeId);
    808           }
    809         };
    810       }
    811     } //We have to call trigger twice, as we can not be sure if all
    812     //iframes have completed loading when this code runs. The
    813     //event listener also catches the page changing in the iFrame.
    814 
    815 
    816     function init(msg) {
    817       function iFrameLoaded() {
    818         trigger('iFrame.onload', msg, iframe, undefined, true);
    819         checkReset();
    820       }
    821 
    822       addEventListener(iframe, 'load', iFrameLoaded);
    823       trigger('init', msg, iframe, undefined, true);
    824     }
    825 
    826     function checkOptions(options) {
    827       if ('object' !== _typeof(options)) {
    828         throw new TypeError('Options is not an object');
    829       }
    830     }
    831 
    832     function copyOptions(options) {
    833       for (var option in defaults) {
    834         if (defaults.hasOwnProperty(option)) {
    835           settings[iframeId][option] = options.hasOwnProperty(option) ? options[option] : defaults[option];
    836         }
    837       }
    838     }
    839 
    840     function getTargetOrigin(remoteHost) {
    841       return '' === remoteHost || 'file://' === remoteHost ? '*' : remoteHost;
    842     }
    843 
    844     function processOptions(options) {
    845       options = options || {};
    846       settings[iframeId] = {
    847         firstRun: true,
    848         iframe: iframe,
    849         remoteHost: iframe.src.split('/').slice(0, 3).join('/')
    850       };
    851       checkOptions(options);
    852       copyOptions(options);
    853 
    854       if (settings[iframeId]) {
    855         settings[iframeId].targetOrigin = true === settings[iframeId].checkOrigin ? getTargetOrigin(settings[iframeId].remoteHost) : '*';
    856       }
    857     }
    858 
    859     function beenHere() {
    860       return iframeId in settings && 'iFrameResizer' in iframe;
    861     }
    862 
    863     var iframeId = ensureHasId(iframe.id);
    864 
    865     if (!beenHere()) {
    866       processOptions(options);
    867       setScrolling();
    868       setLimits();
    869       setupBodyMarginValues();
    870       init(createOutgoingMsg(iframeId));
    871       setupIFrameObject();
    872     } else {
    873       warn(iframeId, 'Ignored iFrame, already setup.');
    874     }
    875   }
    876 
    877   function debouce(fn, time) {
    878     if (null === timer) {
    879       timer = setTimeout(function () {
    880         timer = null;
    881         fn();
    882       }, time);
    883     }
    884   }
    885 
    886   var frameTimer = {};
    887 
    888   function debounceFrameEvents(fn, time, frameId) {
    889     if (!frameTimer[frameId]) {
    890       frameTimer[frameId] = setTimeout(function () {
    891         frameTimer[frameId] = null;
    892         fn();
    893       }, time);
    894     }
    895   } //Not testable in PhantomJS
    896 
    897   /* istanbul ignore next */
    898 
    899 
    900   function fixHiddenIFrames() {
    901     function checkIFrames() {
    902       function checkIFrame(settingId) {
    903         function chkDimension(dimension) {
    904           return '0px' === (settings[settingId] && settings[settingId].iframe.style[dimension]);
    905         }
    906 
    907         function isVisible(el) {
    908           return null !== el.offsetParent;
    909         }
    910 
    911         if (settings[settingId] && isVisible(settings[settingId].iframe) && (chkDimension('height') || chkDimension('width'))) {
    912           trigger('Visibility change', 'resize', settings[settingId].iframe, settingId);
    913         }
    914       }
    915 
    916       for (var settingId in settings) {
    917         checkIFrame(settingId);
    918       }
    919     }
    920 
    921     function mutationObserved(mutations) {
    922       log('window', 'Mutation observed: ' + mutations[0].target + ' ' + mutations[0].type);
    923       debouce(checkIFrames, 16);
    924     }
    925 
    926     function createMutationObserver() {
    927       var target = document.querySelector('body'),
    928           config = {
    929         attributes: true,
    930         attributeOldValue: false,
    931         characterData: true,
    932         characterDataOldValue: false,
    933         childList: true,
    934         subtree: true
    935       },
    936           observer = new MutationObserver(mutationObserved);
    937       observer.observe(target, config);
    938     }
    939 
    940     var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    941     if (MutationObserver) createMutationObserver();
    942   }
    943 
    944   function resizeIFrames(event) {
    945     function resize() {
    946       sendTriggerMsg('Window ' + event, 'resize');
    947     }
    948 
    949     log('window', 'Trigger event: ' + event);
    950     debouce(resize, 16);
    951   } //Not testable in PhantomJS
    952 
    953   /* istanbul ignore next */
    954 
    955 
    956   function tabVisible() {
    957     function resize() {
    958       sendTriggerMsg('Tab Visable', 'resize');
    959     }
    960 
    961     if ('hidden' !== document.visibilityState) {
    962       log('document', 'Trigger event: Visiblity change');
    963       debouce(resize, 16);
    964     }
    965   }
    966 
    967   function sendTriggerMsg(eventName, event) {
    968     function isIFrameResizeEnabled(iframeId) {
    969       return settings[iframeId] && 'parent' === settings[iframeId].resizeFrom && settings[iframeId].autoResize && !settings[iframeId].firstRun;
    970     }
    971 
    972     for (var iframeId in settings) {
    973       if (isIFrameResizeEnabled(iframeId)) {
    974         trigger(eventName, event, document.getElementById(iframeId), iframeId);
    975       }
    976     }
    977   }
    978 
    979   function setupEventListeners() {
    980     addEventListener(window, 'message', iFrameListener);
    981     addEventListener(window, 'resize', function () {
    982       resizeIFrames('resize');
    983     });
    984     addEventListener(document, 'visibilitychange', tabVisible);
    985     addEventListener(document, '-webkit-visibilitychange', tabVisible); //Andriod 4.4
    986 
    987     addEventListener(window, 'focusin', function () {
    988       resizeIFrames('focus');
    989     }); //IE8-9
    990 
    991     addEventListener(window, 'focus', function () {
    992       resizeIFrames('focus');
    993     });
    994   }
    995 
    996   function factory() {
    997     function init(options, element) {
    998       function chkType() {
    999         if (!element.tagName) {
   1000           throw new TypeError('Object is not a valid DOM element');
   1001         } else if ('IFRAME' !== element.tagName.toUpperCase()) {
   1002           throw new TypeError('Expected <IFRAME> tag, found <' + element.tagName + '>');
   1003         }
   1004       }
   1005 
   1006       if (element) {
   1007         chkType();
   1008         setupIFrame(element, options);
   1009         iFrames.push(element);
   1010       }
   1011     }
   1012 
   1013     function warnDeprecatedOptions(options) {
   1014       if (options && options.enablePublicMethods) {
   1015         warn('enablePublicMethods option has been removed, public methods are now always available in the iFrame');
   1016       }
   1017     }
   1018 
   1019     var iFrames;
   1020     setupRequestAnimationFrame();
   1021     setupEventListeners();
   1022     return function iFrameResizeF(options, target) {
   1023       iFrames = []; //Only return iFrames past in on this call
   1024 
   1025       warnDeprecatedOptions(options);
   1026 
   1027       switch (_typeof(target)) {
   1028         case 'undefined':
   1029         case 'string':
   1030           Array.prototype.forEach.call(document.querySelectorAll(target || 'iframe'), init.bind(undefined, options));
   1031           break;
   1032 
   1033         case 'object':
   1034           init(options, target);
   1035           break;
   1036 
   1037         default:
   1038           throw new TypeError('Unexpected data type (' + _typeof(target) + ')');
   1039       }
   1040 
   1041       return iFrames;
   1042     };
   1043   }
   1044 
   1045   function createJQueryPublicMethod($) {
   1046     if (!$.fn) {
   1047       info('', 'Unable to bind to jQuery, it is not fully loaded.');
   1048     } else if (!$.fn.iFrameResize) {
   1049       $.fn.iFrameResize = function $iFrameResizeF(options) {
   1050         function init(index, element) {
   1051           setupIFrame(element, options);
   1052         }
   1053 
   1054         return this.filter('iframe').each(init).end();
   1055       };
   1056     }
   1057   }
   1058 
   1059   if (window.jQuery) {
   1060     createJQueryPublicMethod(window.jQuery);
   1061   }
   1062 
   1063   if (typeof define === 'function' && define.amd) {
   1064     define([], factory);
   1065   } else if ((typeof module === "undefined" ? "undefined" : _typeof(module)) === 'object' && _typeof(module.exports) === 'object') {
   1066     //Node for browserfy
   1067     module.exports = factory();
   1068   } else {
   1069     window.iFrameResize = window.iFrameResize || factory();
   1070   }
   1071 })();