├── index.js ├── .ncurc.json ├── spec ├── resources │ ├── djb.jpg │ ├── frame.lateload.html │ ├── frame.nested.html │ └── frame.content.html ├── javascripts │ └── fixtures │ │ ├── iframe.html │ │ ├── iframe600.html │ │ ├── iframe600WithId.html │ │ └── twoIFrame600WithId.html ├── support │ └── jasmine.json ├── initJQuerySpec.js ├── initUndefinedDomSpec.js ├── initDomSpec.js ├── initDoubleCallSpec.js ├── initCssSpec.js ├── closeSpecSpec.js ├── scrollSpec.js ├── anchorSpec.js ├── lib │ └── common.js ├── sendMessageSpec.js ├── initErrorSpec.js ├── _initSpec.js ├── getPageInfoSpec.js └── parentSpec.js ├── test ├── resources │ ├── djb.jpg │ ├── testLib.js │ ├── frame.lateload.html │ ├── frame.nested.html │ ├── qunit.css │ └── frame.content.html ├── close.html ├── _init.html ├── nested.html ├── jqueryNoConflict.html ├── background.html ├── setHeightCalculationMethod.html ├── getId.html ├── resize.contentWidth.html ├── changePage.html ├── _init_once.html ├── interval.html ├── margin.html ├── sendMessage.html ├── mutationObserver.html ├── noMessageForBlackListedOrigins.html ├── _init_once_async.html ├── size.html ├── resize.width.html ├── lateImageLoad.html ├── removeIFrame.html ├── scrolling.html └── v1.html ├── .travis.yml ├── docs ├── use_with │ ├── jquery.md │ └── vue.md ├── upgrade.md ├── iframed_page │ ├── events.md │ ├── options.md │ └── methods.md ├── parent_page │ ├── methods.md │ ├── events.md │ └── options.md ├── readme.md ├── getting_started.md └── troubleshooting.md ├── .gitignore ├── README.md ├── js ├── index.js ├── iframeResizer.min.js └── iframeResizer.contentWindow.min.js ├── .npmignore ├── .prettierrc ├── FUNDING.md ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── FUNDING.yml ├── bower.json ├── LICENSE ├── .eslintrc ├── test-main.js ├── example ├── frame.textarea.html ├── frame.hover.html ├── index.html ├── two.html ├── frame.nested.html ├── frame.tolerance.html ├── frame.absolute.html └── frame.content.html ├── karma.conf.js ├── CONTRIBUTING.md ├── package.json └── gruntfile.js /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./js') 2 | -------------------------------------------------------------------------------- /.ncurc.json: -------------------------------------------------------------------------------- 1 | { 2 | "reject": ["grunt-contrib-qunit"] 3 | } 4 | -------------------------------------------------------------------------------- /spec/resources/djb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vote/clean-iframe-resizer/clean/spec/resources/djb.jpg -------------------------------------------------------------------------------- /test/resources/djb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vote/clean-iframe-resizer/clean/test/resources/djb.jpg -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "11.0" 4 | before_script: 5 | - npm install -g grunt-cli 6 | sudo: false 7 | -------------------------------------------------------------------------------- /spec/javascripts/fixtures/iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /spec/support/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "spec", 3 | "spec_files": ["**/*[sS]pec.js"], 4 | "helpers": ["helpers/**/*.js"] 5 | } 6 | -------------------------------------------------------------------------------- /docs/use_with/jquery.md: -------------------------------------------------------------------------------- 1 | ## jQuery 2 | 3 | This library also provides a simple jQuery interface 4 | 5 | ```js 6 | $('iframe').iFrameResize([{ options }]) 7 | ``` 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .coveralls.yml 3 | node_modules 4 | bin 5 | example/test.html 6 | test/*.off 7 | npm-debug.log 8 | bower_components 9 | coverage* 10 | .idea 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clean iFrame resizer 2 | 3 | Clean iFrame Resizer is a fork of [iFrame Resizer](https://github.com/davidjbradshaw/iframe-resizer) that does not pollute `window` or try to add a plugin to `jquery` 4 | -------------------------------------------------------------------------------- /spec/javascripts/fixtures/iframe600.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 | -------------------------------------------------------------------------------- /js/index.js: -------------------------------------------------------------------------------- 1 | var iframeResize = require('./iframeResizer') 2 | 3 | exports.iframeResize = iframeResize 4 | exports.iframeResizer = iframeResize // Backwards compatability 5 | exports.iframeResizerContentWindow = require('./iframeResizer.contentWindow') 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .coveralls.yml 3 | .idea 4 | node_modules 5 | bin 6 | docs 7 | example 8 | test 9 | spec 10 | src 11 | npm-debug.log 12 | bower_components 13 | bower.json 14 | gruntfile.js 15 | karma.conf.js 16 | test-main.js 17 | coverage* 18 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": false, 6 | "singleQuote": true, 7 | "trailingComma": "none", 8 | "bracketSpacing": true, 9 | "jsxBracketSameLine": false 10 | } 11 | -------------------------------------------------------------------------------- /spec/javascripts/fixtures/iframe600WithId.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 | -------------------------------------------------------------------------------- /test/resources/testLib.js: -------------------------------------------------------------------------------- 1 | function sendMessage(msg) { 2 | 'use strict'; 3 | //var msgId = '[iFrameSizerTest]:'; 4 | 5 | //document.getElementsByTagName('iframe')[0].contentWindow.postMessage( msgId + msg, '*' ); 6 | 7 | //console.log('Sending '+msg); 8 | document.getElementsByTagName('iframe')[0].iFrameResizer.sendMessage(msg); 9 | } 10 | -------------------------------------------------------------------------------- /spec/javascripts/fixtures/twoIFrame600WithId.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |
7 | 8 |
-------------------------------------------------------------------------------- /docs/upgrade.md: -------------------------------------------------------------------------------- 1 | ## Upgrading to version 4 2 | 3 | In version 4 support for IE 8-10 and Andriod 4.4 has been removed, if you still need this then please use [version 3](https://github.com/davidjbradshaw/iframe-resizer/tree/V3) of this library. 4 | 5 | The callback methods have been renamed to onEvents, so for example `scrollCallback` is now called `onScroll`. This is to enable better integration with modern libraries such as React. 6 | -------------------------------------------------------------------------------- /FUNDING.md: -------------------------------------------------------------------------------- 1 | # Donate to Iframe-Resizer 2 | 3 | Iframe-resizer is the result of many 100s of hours of work, if you would like to join others in showing support for the development of this project, then please feel free to buy me a coffee. 4 | 5 | Buy Me A Coffee 6 | -------------------------------------------------------------------------------- /docs/iframed_page/events.md: -------------------------------------------------------------------------------- 1 | ## IFrame Page Events 2 | 3 | The following events can be included in the [options](options.md) object attached to the iframed page. 4 | 5 | ### onMessage 6 | 7 | type: function (message) 8 | 9 | Receive message posted from the parent page with the `iframe.iFrameResizer.sendMessage()` method. 10 | 11 | ### onReady 12 | 13 | type: function() 14 | 15 | This function is called once iFrame-Resizer has been initialized after receiving a call from the parent page. If you need to call any of the parentIFrame methods (See below) during page load, then they should be called from this event handler. 16 | -------------------------------------------------------------------------------- /spec/initJQuerySpec.js: -------------------------------------------------------------------------------- 1 | /* jshint undef: false, unused: true */ 2 | 3 | 'use strict' 4 | 5 | define(['iframeResizer', 'jquery'], function(iFrameResize, $) { 6 | describe('iFrame init(jQuery)', function() { 7 | var iframe 8 | 9 | beforeAll(function() { 10 | loadIFrame('iframe600.html') 11 | 12 | var $iframes = $('iframe').iFrameResize() 13 | 14 | iframe = $iframes.get(0) 15 | }) 16 | 17 | afterAll(function() { 18 | tearDown(iframe) 19 | }) 20 | 21 | it('should create iFrameResizer object', function() { 22 | expect(iframe.iFrameResizer).toBeDefined() 23 | }) 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /spec/initUndefinedDomSpec.js: -------------------------------------------------------------------------------- 1 | /* jshint undef: false, unused: true */ 2 | 3 | 'use strict' 4 | 5 | define(['iframeResizer'], function(iFrameResize) { 6 | describe('iFrame init(DOM Object)', function() { 7 | var iframe 8 | 9 | beforeAll(function() { 10 | loadIFrame('iframe600.html') 11 | 12 | iframe = iFrameResize( 13 | undefined, 14 | document.getElementsByTagName('iframe')[0] 15 | )[0] 16 | }) 17 | 18 | afterAll(function() { 19 | tearDown(iframe) 20 | }) 21 | 22 | it('should create iFrameResizer object', function() { 23 | expect(iframe.iFrameResizer).toBeDefined() 24 | }) 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /spec/initDomSpec.js: -------------------------------------------------------------------------------- 1 | /* jshint undef: false, unused: true */ 2 | 3 | 'use strict' 4 | 5 | define(['iframeResizer'], function(iFrameResize) { 6 | describe('iFrame init(DOM Object)', function() { 7 | var iframe 8 | 9 | beforeAll(function() { 10 | loadIFrame('iframe600.html') 11 | 12 | iframe = iFrameResize( 13 | { 14 | log: LOG 15 | }, 16 | document.getElementsByTagName('iframe')[0] 17 | )[0] 18 | }) 19 | 20 | afterAll(function() { 21 | tearDown(iframe) 22 | }) 23 | 24 | it('should create iFrameResizer object', function() { 25 | expect(iframe.iFrameResizer).toBeDefined() 26 | }) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /docs/use_with/vue.md: -------------------------------------------------------------------------------- 1 | ## Vue 2 | 3 | Create the following Vue directive 4 | 5 | ```js 6 | import Vue from 'vue' 7 | import iFrameResize from 'iframe-resizer/js/iframeResizer' 8 | 9 | Vue.directive('resize', { 10 | bind: function(el, { value = {} }) { 11 | el.addEventListener('load', () => iFrameResize(value, el)) 12 | } 13 | }) 14 | ``` 15 | 16 | and then include it on you page as follows. 17 | 18 | ```html 19 | 25 | ``` 26 | 27 | - Thanks to [Aldebaran Desombergh](https://github.com/davidjbradshaw/iframe-resizer/issues/513#issuecomment-538333854) for this example 28 | -------------------------------------------------------------------------------- /docs/parent_page/methods.md: -------------------------------------------------------------------------------- 1 | ## IFrame Object Methods 2 | 3 | Once the iFrame has been initialized, an `iFrameResizer` object is bound to it. This has the following methods available. 4 | 5 | ### close() 6 | 7 | Remove the iFrame from the page. 8 | 9 | ### moveToAnchor(anchor) 10 | 11 | Move to anchor in iFrame. 12 | 13 | ### removeListeners() 14 | 15 | Detach event listeners from iFrame. This is option allows Virtual DOMs to remove an iFrame tag. It should not normally be required. 16 | 17 | ### resize() 18 | 19 | Tell the iFrame to resize itself. 20 | 21 | ### sendMessage(message, [targetOrigin]) 22 | 23 | Send data to the containing page, `message` can be any data type that can be serialized into JSON. The `targetOrigin` option is used to restrict where the message is sent to, in case your iFrame navigates away to another domain. 24 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | # iFrame-Resizer Documentation 2 | 3 | - [Getting Started](getting_started.md) 4 | - **Parent Page API** 5 | - [Options](parent_page/options.md) 6 | - [Events](parent_page/events.md) 7 | - [Methods](parent_page/methods.md) 8 | - **IFramed Page API** 9 | - [Options](iframed_page/options.md) 10 | - [Events](iframed_page/events.md) 11 | - [Methods](iframed_page/methods.md) 12 | - **Use with Libraries and Frameworks** 13 | - [React](https://github.com/zeroasterisk/react-iframe-resizer-super) 14 | - [Vue](https://github.com/davidjbradshaw/iframe-resizer/blob/master/docs/use_with/vue.md) 15 | - [Angular](https://github.com/davidjbradshaw/iframe-resizer/issues/478#issuecomment-347958630) 16 | - [jQuery](use_with/jquery.md) 17 | - [Troubleshooting](troubleshooting.md) 18 | - [Upgrade from version 3](upgrade.md) 19 | - [Version history](../CHANGELOG.md) 20 | -------------------------------------------------------------------------------- /spec/initDoubleCallSpec.js: -------------------------------------------------------------------------------- 1 | /* jshint undef: false, unused: true */ 2 | 3 | 'use strict' 4 | 5 | define(['iframeResizer'], function(iFrameResize) { 6 | describe('iFrame init(Double)', function() { 7 | var iframe 8 | 9 | beforeAll(function() { 10 | loadIFrame('iframe600WithId.html') 11 | //spyOn(console,'warn'); 12 | }) 13 | 14 | afterAll(function() { 15 | tearDown(iframe) 16 | }) 17 | 18 | it('should create iFrameResizer object', function() { 19 | window.parentIFrame = { 20 | getId: function() { 21 | return 'getIdTest' 22 | } 23 | } 24 | iframe = iFrameResize({ log: LOG }, '#doubleTest')[0] 25 | iFrameResize({ log: LOG }, '#doubleTest') 26 | expect(iframe.iFrameResizer).toBeDefined() 27 | expect(console.warn).toHaveBeenCalled() 28 | delete window.parentIFrame 29 | }) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /spec/initCssSpec.js: -------------------------------------------------------------------------------- 1 | /* jshint undef: false, unused: true */ 2 | 3 | 'use strict' 4 | 5 | define(['iframeResizer'], function(iFrameResize) { 6 | describe('iFrame init(CSS Selector)', function() { 7 | var iframe 8 | 9 | beforeAll(function(done) { 10 | loadIFrame('iframe600.html') 11 | 12 | iframe = iFrameResize( 13 | { 14 | log: LOG, 15 | minHeight: 99999, 16 | onResized: done, 17 | checkOrigin: [ 18 | 'http://localhost', 19 | 'https://localhost', 20 | location.href 21 | .split('/') 22 | .slice(0, 3) 23 | .join('/') 24 | ] 25 | }, 26 | 'iframe' 27 | )[0] 28 | }) 29 | 30 | afterAll(function() { 31 | tearDown(iframe) 32 | }) 33 | 34 | it('should create iFrameResizer object', function() { 35 | expect(iframe.iFrameResizer).toBeDefined() 36 | }) 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /spec/closeSpecSpec.js: -------------------------------------------------------------------------------- 1 | define(['iframeResizer'], function(iFrameResize) { 2 | describe('Close iFrame', function() { 3 | var iframe 4 | 5 | beforeEach(function() { 6 | loadIFrame('iframe600.html') 7 | }) 8 | 9 | it('closes from parent', function(done) { 10 | var evtCounter = 0 11 | 12 | iframe = iFrameResize({ 13 | log: LOG, 14 | id: 'close1', 15 | onClosed: function() { 16 | setTimeout(done, 0) 17 | } 18 | })[0] 19 | 20 | setTimeout(iframe.iFrameResizer.close, 1) 21 | }) 22 | 23 | it('closes from iframe', function(done) { 24 | var evtCounter = 0 25 | 26 | iframe = iFrameResize({ 27 | log: LOG, 28 | id: 'close2', 29 | onClosed: function() { 30 | setTimeout(done, 0) 31 | }, 32 | onInit: function(iframe) { 33 | iframe.iFrameResizer.sendMessage('close') 34 | } 35 | })[0] 36 | 37 | mockMsgFromIFrame(iframe, 'close') 38 | }) 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /test/resources/frame.lateload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | iFrame message passing test 7 | 8 | 9 | 10 | 26 | 27 | 28 | 29 |

Late load JS test

30 |

Load JS with require after load event has fired.

31 |
32 |
33 | 34 | 35 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /spec/resources/frame.lateload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | iFrame message passing test 8 | 9 | 10 | 11 | 27 | 28 | 29 | 30 |

Late load JS test

31 |

Load JS with require after load event has fired.

32 |
33 |
34 | 35 | 36 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | # github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | # patreon: # Replace with a single Patreon username 5 | # open_collective: # Replace with a single Open Collective username 6 | # ko_fi: # Replace with a single Ko-fi username 7 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | # liberapay: # Replace with a single Liberapay username 10 | # issuehunt: # Replace with a single IssueHunt username 11 | # otechie: # Replace with a single Otechie username 12 | # custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | 14 | # github: davidjbradshaw 15 | custom: https://www.buymeacoffee.com/davidjbradshaw 16 | custom: https://www.paypal.me/davidjbradshaw 17 | # issuehunt: davidjbradshaw 18 | # liberapay: davidjbradshaw 19 | # ko_fi: davidjbradshaw 20 | # tidelift: npm/iframe-resizer 21 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iframe-resizer", 3 | "version": "4.2.10", 4 | "homepage": "https://github.com/davidjbradshaw/iframe-resizer", 5 | "authors": ["David J. Bradshaw "], 6 | "description": "Responsively keep same and cross domain iFrames sized to their content with support for window/content resizing, multiple and nested iFrames. (Dependacy free and works with IE8+)", 7 | "main": ["js/iframeResizer.js", "js/iframeResizer.contentWindow.js"], 8 | "keywords": [ 9 | "CrossDomain", 10 | "Cross-Domain", 11 | "iFrame", 12 | "Resizing", 13 | "Resizer", 14 | "postMessage", 15 | "content", 16 | "resize", 17 | "height", 18 | "autoheight", 19 | "auto-height", 20 | "iframe-auto-height", 21 | "height-iframe", 22 | "heightiframe", 23 | "width", 24 | "mutationObserver", 25 | "RWD", 26 | "responsive", 27 | "responsiveiframes", 28 | "responsive-iframes" 29 | ], 30 | "license": "MIT", 31 | "ignore": ["example", "test", "gruntfile.js", "*.md", "*.json"], 32 | "dependencies": {}, 33 | "devDependencies": {} 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2019 David J. Bradshaw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /spec/scrollSpec.js: -------------------------------------------------------------------------------- 1 | define(['iframeResizer'], function(iFrameResize) { 2 | describe('Scroll Page', function() { 3 | var iframe 4 | var log = LOG 5 | 6 | beforeEach(function() { 7 | loadIFrame('iframe600.html') 8 | }) 9 | 10 | afterEach(function() { 11 | tearDown(iframe) 12 | }) 13 | 14 | it('mock incoming message', function(done) { 15 | iframe = iFrameResize({ 16 | log: log, 17 | id: 'scroll1' 18 | })[0] 19 | 20 | window.parentIFrame = { 21 | scrollTo: function(x, y) { 22 | expect(x).toBe(0) 23 | expect(y).toBe(0) 24 | done() 25 | } 26 | } 27 | 28 | mockMsgFromIFrame(iframe, 'scrollTo') 29 | }) 30 | 31 | it('mock incoming message', function(done) { 32 | iframe = iFrameResize({ 33 | log: log, 34 | id: 'scroll2' 35 | })[0] 36 | 37 | window.parentIFrame = { 38 | scrollToOffset: function(x, y) { 39 | expect(x).toBe(8) 40 | expect(y).toBe(8) 41 | done() 42 | } 43 | } 44 | 45 | mockMsgFromIFrame(iframe, 'scrollToOffset') 46 | }) 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["airbnb-base", "adjunct", "prettier"], 3 | "plugins": ["prettier", "ie11"], 4 | "env": { 5 | "amd": true, 6 | "browser": true, 7 | "jasmine": true 8 | }, 9 | "parserOptions": { "ecmaVersion": 2015 }, 10 | "rules": { 11 | "func-names": 0, 12 | "global-require": 0, 13 | "no-param-reassign": 0, 14 | "no-plusplus": 0, 15 | "no-restricted-globals": 0, 16 | "no-use-before-define": 0, 17 | "no-shadow": 0, 18 | "no-var": 0, 19 | "object-shorthand": 0, 20 | "one-var": 0, 21 | "prefer-destructuring": 0, 22 | "prefer-rest-params": 0, 23 | "prefer-template": 0, 24 | "vars-on-top": 0, 25 | "yoda": 0, 26 | "ie11/no-collection-args": ["error"], 27 | "ie11/no-for-in-const": ["error"], 28 | "ie11/no-loop-func": ["warn"], 29 | "ie11/no-weak-collections": ["error"], 30 | "import/no-amd": 0, 31 | "unicorn/consistent-function-scoping": 0, 32 | "unicorn/filename-case": 0, 33 | "unicorn/prefer-node-append": 0, 34 | "unicorn/prefer-node-remove": 0, 35 | "unicorn/prefer-query-selector": 0, 36 | "unicorn/prevent-abbreviations": 0, 37 | "unicorn/prefer-string-slice": 0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /docs/iframed_page/options.md: -------------------------------------------------------------------------------- 1 | ## IFrame Page Options 2 | 3 | The following options can be set from within the iFrame page by creating a `window.iFrameResizer` object before the JavaScript file is loaded into the page. 4 | 5 | ```html 6 | 11 | 12 | ``` 13 | 14 | ### targetOrigin 15 | 16 | default: '*' 17 | type: string 18 | 19 | This option allows you to restrict the domain of the parent page, to prevent other sites mimicing your parent page. 20 | 21 | ### heightCalculationMethod / widthCalculationMethod 22 | 23 | default: null 24 | type: string | function() { return integer } 25 | 26 | These options can be used to override the option set in the parent page (See above for details on available values). This can be useful when moving between pages in the iFrame that require different values for these options. 27 | 28 | Altenatively you can pass a custom function that returns the size as an integer. This can be useful when none of the standard ways of working out the size are suitable. However, normally problems with sizing are due to CSS issues and this should be looked at first. 29 | -------------------------------------------------------------------------------- /test-main.js: -------------------------------------------------------------------------------- 1 | var allTestFiles = [] 2 | 3 | var TEST_REGEXP = /(spec|test)\.js$/i 4 | 5 | // Get a list of all the test files to include 6 | // eslint-disable-next-line no-underscore-dangle 7 | Object.keys(window.__karma__.files).forEach(function (file) { 8 | if (TEST_REGEXP.test(file)) { 9 | // Normalize paths to RequireJS module names. 10 | // If you require sub-dependencies of test files to be loaded as-is (requiring file extension) 11 | // then do not normalize the paths 12 | var normalizedTestModule = file.replace(/^\/base\/|\.js$/g, '') 13 | allTestFiles.push(normalizedTestModule) 14 | } 15 | }) 16 | 17 | require.config({ 18 | // Karma serves files under /base, which is the basePath from your config file 19 | baseUrl: '/base', 20 | 21 | paths: { 22 | jquery: 'node_modules/jquery/dist/jquery', 23 | iframeResizerMin: 'js/iframeResizer.min', 24 | iframeResizer: 'src/iframeResizer', 25 | iframeResizerContentMin: 'js/iframeResizer.contentWindow.min', 26 | iframeResizerContent: 'src/iframeResizer.contentWindow' 27 | }, 28 | 29 | // dynamically load all test files 30 | deps: allTestFiles, 31 | 32 | // we have to kickoff jasmine, as it is asynchronous 33 | callback: window.__karma__.start // eslint-disable-line no-underscore-dangle 34 | }) 35 | -------------------------------------------------------------------------------- /test/close.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 25 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /example/frame.textarea.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | iFrame message passing test 6 | 7 | 8 | 14 | 15 | 16 | 17 | iFrame TextArea Example 18 | Back to page 1 19 | 20 |

21 | Resize the textarea below. 22 |

23 | 24 | 25 | 26 | 27 | 28 | 29 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /test/_init.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /test/nested.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 19 |
20 |
21 | 22 | 23 | 24 | 25 | 26 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /test/jqueryNoConflict.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 25 | 26 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /spec/resources/frame.nested.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | iFrame message passing test 7 | 8 | 9 | 10 | 15 | 16 | 17 | 18 |

Nested iFrame

19 |

Resize window or click one of the links in the nested iFrame to watch it resize.

20 |
21 | 22 |
23 |

24 |

25 | 26 | 27 | 28 | 29 | 30 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /test/background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 25 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /test/setHeightCalculationMethod.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 |
10 |
11 |
12 | 17 |
18 |
19 | 20 | 21 | 22 | 23 | 24 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /test/getId.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 19 |
20 |
21 | 22 | 23 | 24 | 25 | 26 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /test/resources/frame.nested.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | iFrame message passing test 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |

Nested iFrame

21 |

Resize window or click one of the links in the nested iFrame to watch it resize.

22 |
23 | 24 |
25 |

26 |

27 | 28 | 29 | 30 | 31 | 32 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /test/resize.contentWidth.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 25 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /test/changePage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 25 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /spec/anchorSpec.js: -------------------------------------------------------------------------------- 1 | define(['iframeResizer'], function(iFrameResize) { 2 | describe('jump to anchor', function() { 3 | var iframe 4 | var log = LOG 5 | var testId = 'anchor' 6 | 7 | beforeEach(function() { 8 | loadIFrame('iframe600.html') 9 | }) 10 | 11 | afterEach(function() { 12 | tearDown(iframe) 13 | }) 14 | 15 | it('requested from host page', function(done) { 16 | var iframe1 = iFrameResize({ 17 | log: log, 18 | id: 'anchor1' 19 | })[0] 20 | 21 | spyOnIFramePostMessage(iframe1) 22 | setTimeout(function() { 23 | iframe1.iFrameResizer.moveToAnchor('testAnchor') 24 | expect(iframe1.contentWindow.postMessage).toHaveBeenCalledWith( 25 | '[iFrameSizer]moveToAnchor:testAnchor', 26 | getTarget(iframe1) 27 | ) 28 | tearDown(iframe1) 29 | done() 30 | }, 100) 31 | }) 32 | 33 | it('mock incoming message', function(done) { 34 | iframe2 = iFrameResize({ 35 | log: log, 36 | id: 'anchor2', 37 | onScroll: function(position) { 38 | expect(position.x).toBe(8) 39 | expect(position.y).toBeGreaterThan(8) 40 | done() 41 | } 42 | })[0] 43 | 44 | mockMsgFromIFrame(iframe2, 'inPageLink:#anchorParentTest') 45 | }) 46 | 47 | it('mock incoming message to parent', function(done) { 48 | iframe3 = iFrameResize({ 49 | log: log, 50 | id: 'anchor3' 51 | })[0] 52 | 53 | window.parentIFrame = { 54 | moveToAnchor: function() { 55 | done() 56 | } 57 | } 58 | 59 | mockMsgFromIFrame(iframe3, 'inPageLink:#anchorParentTest2') 60 | }) 61 | }) 62 | }) 63 | -------------------------------------------------------------------------------- /docs/parent_page/events.md: -------------------------------------------------------------------------------- 1 | ## Events 2 | 3 | The following callback events can be passed to iframe-resizer on the parent page, as part of the [options](options.md) object. 4 | 5 | ### onClose 6 | 7 | ```js 8 | onClosed: (iframeID) => boolean 9 | ``` 10 | 11 | Called before iFrame is closed via `parentIFrame.close()` or `iframe.iFrameResizer.close()` methods. Returning `false` will prevent the iFrame from closing. 12 | 13 | ### onClosed 14 | 15 | ```js 16 | onClosed: (iframeID) => undefined 17 | ``` 18 | 19 | Called after iFrame is closed via `parentIFrame.close()` or `iframe.iFrameResizer.close()` methods. 20 | 21 | ### onInit 22 | 23 | ```js 24 | onInit: (iframe) => undefined 25 | ``` 26 | 27 | Called after initial setup. 28 | 29 | ### onMessage 30 | 31 | ```js 32 | onMessage: ({iframe,message}) => undefined 33 | ``` 34 | 35 | Receive message posted from iFrame with the `parentIFrame.sendMessage()` method. 36 | 37 | ### onResized 38 | 39 | ```js 40 | onResized: ({iframe,height,width,type}) => undefined 41 | ``` 42 | 43 | Function called after iFrame resized. Passes in messageData object containing the **iFrame**, **height**, **width** and the **type** of event that triggered the iFrame to resize. 44 | 45 | ### onScroll 46 | 47 | ```js 48 | onScroll: ({x,y}) => [true|false] 49 | ``` 50 | 51 | Called before the page is repositioned after a request from the iFrame, due to either an in page link, or a direct request from either [parentIFrame.scrollTo()](../iframed_page/methods.md#scrolltoxy) or [parentIFrame.scrollToOffset()](../iframed_page/methods.md#scrolltooffsetxy). If this function returns **false**, it will stop the library from repositioning the page, so that you can implement your own animated page scrolling instead. 52 | -------------------------------------------------------------------------------- /test/_init_once.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /spec/lib/common.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var LOG = true; 4 | 5 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 4000; 6 | jasmine.getFixtures().fixturesPath = 'base/spec/javascripts/fixtures'; 7 | 8 | function tearDown(iframe) { 9 | if (iframe) setTimeout(iframe.iFrameResizer.close, 1); 10 | window.parentIFrame = undefined; 11 | } 12 | 13 | function loadIFrame(filename) { 14 | loadFixtures(filename); 15 | } 16 | 17 | function getTarget(iframe) { 18 | return iframe.src 19 | .split('/') 20 | .slice(0, 3) 21 | .join('/'); 22 | } 23 | 24 | function mockPostMsgViaHook(testIFrame, id, msg, callback) { 25 | return testIFrame('[iFrameSizer]' + id + ':' + msg, callback); 26 | } 27 | 28 | function mockPostMsg(id, msg) { 29 | var message = '[iFrameSizer]' + id + ':' + msg; 30 | console.log('Mock postMessage: ', message); 31 | window.postMessage(message, '*'); 32 | } 33 | 34 | function mockMsgFromIFrame(iframe, msg) { 35 | mockPostMsg(iframe.id, '0:0:' + msg); 36 | } 37 | 38 | function mockInitFromParent(testIFrame, id, log, callback) { 39 | return mockPostMsgViaHook( 40 | testIFrame, 41 | id, 42 | '8:false:' + log + ':0:true:false:null:max:wheat:null:0:true:child:scroll', 43 | callback 44 | ); 45 | } 46 | 47 | function spyOnPostMessage(target) { 48 | spyOn(target, 'postMessage'); 49 | } 50 | 51 | function spyOnWindowPostMessage() { 52 | spyOnPostMessage(window.parent); 53 | return window.parent.postMessage; 54 | } 55 | 56 | function spyOnIFramePostMessage(iframe) { 57 | spyOnPostMessage(iframe.contentWindow); 58 | } 59 | 60 | function closeChild(window, done) { 61 | window.parentIFrame.close(); 62 | done(); 63 | } 64 | 65 | function strEnd(str, num) { 66 | return str.substr(str.length - num); 67 | } 68 | -------------------------------------------------------------------------------- /spec/sendMessageSpec.js: -------------------------------------------------------------------------------- 1 | define(['iframeResizer'], function(iFrameResize) { 2 | describe('Send Message from Host Page', function() { 3 | var iframe 4 | var log = LOG 5 | 6 | beforeEach(function() { 7 | loadIFrame('iframe600.html') 8 | }) 9 | 10 | afterEach(function() { 11 | tearDown(iframe) 12 | }) 13 | 14 | it('send message to iframe', function(done) { 15 | var iframe1 = iFrameResize({ 16 | log: log, 17 | id: 'sendMessage1' 18 | })[0] 19 | 20 | spyOnIFramePostMessage(iframe1) 21 | setTimeout(function() { 22 | iframe1.iFrameResizer.sendMessage('chkSendMsg:test') 23 | expect(iframe1.contentWindow.postMessage).toHaveBeenCalledWith( 24 | '[iFrameSizer]message:"chkSendMsg:test"', 25 | getTarget(iframe1) 26 | ) 27 | tearDown(iframe1) 28 | done() 29 | }, 100) 30 | }) 31 | 32 | it('mock incoming message', function(done) { 33 | iframe = iFrameResize({ 34 | log: log, 35 | id: 'sendMessage2', 36 | onMessage: function(messageData) { 37 | expect(messageData.message).toBe('test:test') 38 | done() 39 | } 40 | })[0] 41 | 42 | mockMsgFromIFrame(iframe, 'message:"test:test"') 43 | }) 44 | 45 | it('send message and get response', function(done) { 46 | iframe = iFrameResize({ 47 | log: log, 48 | id: 'sendMessage3', 49 | onInit: function(iframe) { 50 | iframe.iFrameResizer.sendMessage('chkSendMsg') 51 | }, 52 | onMessage: function(messageData) { 53 | expect(messageData.message).toBe('message: test string') 54 | done() 55 | } 56 | })[0] 57 | }) 58 | }) 59 | }) 60 | -------------------------------------------------------------------------------- /spec/initErrorSpec.js: -------------------------------------------------------------------------------- 1 | define(['iframeResizer'], function(iFrameResize) { 2 | describe('Setup error', function() { 3 | var iframe 4 | var log = LOG 5 | 6 | beforeEach(function() { 7 | loadIFrame('iframe600.html') 8 | }) 9 | 10 | it('min > max', function() { 11 | expect(function() { 12 | iFrameResize({ 13 | log: log, 14 | id: 'error1', 15 | maxHeight: 100, 16 | minHeight: 999 17 | }) 18 | }).toThrow( 19 | new Error('Value for minHeight can not be greater than maxHeight') 20 | ) 21 | }) 22 | 23 | it('Unexpected data type', function() { 24 | expect(function() { 25 | iFrameResize( 26 | { 27 | log: log, 28 | id: 'error2' 29 | }, 30 | 1 31 | ) 32 | }).toThrow(new TypeError('Unexpected data type (number)')) 33 | }) 34 | 35 | it('Expected 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/getting_started.md: -------------------------------------------------------------------------------- 1 | ## Getting Started 2 | 3 | ### Install 4 | 5 | This package can be installed via NPM (`npm install iframe-resizer --save`). 6 | 7 | ### Usage 8 | 9 | The package contains two minified JavaScript files in the [js](../js) folder. The first ([iframeResizer.min.js](https://raw.githubusercontent.com/davidjbradshaw/iframe-resizer/master/js/iframeResizer.min.js)) is for the page hosting the iFrames. It can be called with **native** JavaScript; 10 | 11 | ```js 12 | const iframes = iFrameResize( [{options}], [css selector] || [iframe] ); 13 | ``` 14 | 15 | The second file ([iframeResizer.contentWindow.min.js](https://raw.github.com/davidjbradshaw/iframe-resizer/master/js/iframeResizer.contentWindow.min.js)) needs placing in the page(s) contained within your iFrame. This file is designed to be a guest on someone else's system, so has no dependencies and won't do anything until it's activated by a message from the containing page. 16 | 17 | ### Typical setup 18 | 19 | The normal configuration is to have the iFrame resize when the browser window changes size or the content of the iFrame changes. To set this up you need to configure one of the dimensions of the iFrame to a percentage and tell the library to only update the other dimension. Normally you would set the width to 100% and have the height scale to fit the content. 20 | 21 | ```html 22 | 28 | 29 | 32 | ``` 33 | 34 | **Note:** Using _min-width_ to set the width of the iFrame, works around an issue in iOS that can prevent the iFrame from sizing correctly. 35 | 36 | If you have problems, check the [troubleshooting](troubleshooting.md) section. 37 | 38 | ### Example 39 | 40 | To see this working take a look at this [example](http://davidjbradshaw.com/iframe-resizer/example/) and watch the [console](https://developer.mozilla.org/en-US/docs/Tools/Web_Console). 41 | -------------------------------------------------------------------------------- /test/margin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 25 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /test/sendMessage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 25 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /test/mutationObserver.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /test/noMessageForBlackListedOrigins.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 | 24 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /spec/getPageInfoSpec.js: -------------------------------------------------------------------------------- 1 | define(['iframeResizer'], function(iFrameResize) { 2 | describe('Get Page info', function() { 3 | var log = LOG 4 | var testId = 'anchor' 5 | 6 | beforeEach(function() { 7 | loadIFrame('iframe600.html') 8 | }) 9 | 10 | it('requested from iFrame', function(done) { 11 | var iframe1 = iFrameResize({ 12 | log: log, 13 | id: 'getPageInfo' 14 | })[0] 15 | 16 | spyOn(iframe1.contentWindow, 'postMessage').and.callFake(function(msg) { 17 | if (0 !== msg.indexOf('pageInfo')) { 18 | expect( 19 | msg.indexOf( 20 | '"offsetTop":0,"offsetLeft":0,"scrollTop":0,"scrollLeft":0' 21 | ) 22 | ).not.toEqual(0) 23 | } 24 | if (0 !== msg.indexOf('pageInfoStop')) { 25 | tearDown(iframe1) 26 | done() 27 | } 28 | }) 29 | 30 | mockMsgFromIFrame(iframe1, 'pageInfo') 31 | mockMsgFromIFrame(iframe1, 'pageInfoStop') 32 | }) 33 | }) 34 | 35 | describe('Get Page info with multiple frames', function() { 36 | var log = LOG 37 | 38 | beforeEach(function() { 39 | loadIFrame('twoIFrame600WithId.html') 40 | }) 41 | 42 | xit('must send pageInfo to second frame', function(done) { 43 | var iframes = iFrameResize({ 44 | log: log, 45 | id: '#frame1,#frame2', 46 | onInit: function(iframe) { 47 | iframe.iFrameResizer.sendMessage('getPageInfo') 48 | } 49 | }) 50 | 51 | var iframe1 = iframes[0], 52 | iframe2 = iframes[1] 53 | 54 | setTimeout(function() { 55 | var counter = 0, 56 | frame1Called = false, 57 | frame2Called = false 58 | 59 | function checkCounter() { 60 | if (counter === 2) { 61 | expect(frame1Called && frame2Called).toBeTruthy() 62 | tearDown(iframe1) 63 | tearDown(iframe2) 64 | done() 65 | } 66 | } 67 | iframe1.contentWindow.postMessage = function(msg) { 68 | if (0 < msg.indexOf('pageInfo')) { 69 | frame1Called = true 70 | counter++ 71 | checkCounter() 72 | } 73 | } 74 | iframe2.contentWindow.postMessage = function(msg) { 75 | if (0 < msg.indexOf('pageInfo')) { 76 | frame2Called = true 77 | counter++ 78 | checkCounter() 79 | } 80 | } 81 | 82 | window.dispatchEvent(new Event('resize')) 83 | }, 200) 84 | }) 85 | }) 86 | }) 87 | -------------------------------------------------------------------------------- /test/_init_once_async.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /test/size.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 |
10 |
11 |
12 | 17 |
18 |
19 | 20 | 21 | 22 | 23 | 24 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /test/resize.width.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 23 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Tue Aug 25 2015 12:11:48 GMT+0100 (BST) 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | // base path that will be used to resolve all patterns (eg. files, exclude) 7 | basePath: '', 8 | 9 | // frameworks to use 10 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 11 | frameworks: ['jasmine-jquery', 'jasmine', 'requirejs'], 12 | 13 | // Karma will require() these plugins 14 | /* 15 | plugins: [ 16 | 'logcapture', 17 | 'karma-verbose-summary-reporter', 18 | 'karma-jasmine', 19 | 'karma-chrome-launcher' 20 | ], 21 | */ 22 | 23 | // list of files / patterns to load in the browser 24 | files: [ 25 | 'test-main.js', 26 | 'spec/lib/*.js', 27 | 'js/ie8.polyfils.min.js', 28 | { pattern: 'js/*.js', included: false }, 29 | { pattern: 'src/*.js', included: false }, 30 | { pattern: 'example/*.html', included: false }, 31 | { pattern: 'spec/*Spec.js', included: false }, 32 | { pattern: 'spec/resources/*', included: false }, 33 | { pattern: 'spec/javascripts/fixtures/*.html', included: false } 34 | ], 35 | 36 | // list of files to exclude 37 | exclude: [], 38 | 39 | // preprocess matching files before serving them to the browser 40 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 41 | preprocessors: { 42 | 'src/*.js': ['coverage'] 43 | }, 44 | 45 | coverageReporter: { 46 | type: 'html', 47 | dir: 'coverage/' 48 | }, 49 | 50 | client: { 51 | captureConsole: true 52 | }, 53 | 54 | // test results reporter to use 55 | // possible values: 'dots', 'progress' 56 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 57 | reporters: ['logcapture', 'progress', 'verbose-summary', 'coverage'], 58 | 59 | // web server port 60 | port: 9876, 61 | 62 | // enable / disable colors in the output (reporters and logs) 63 | colors: true, 64 | 65 | // level of logging 66 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 67 | logLevel: config.LOG_INFO, 68 | 69 | // enable / disable watching file and executing tests whenever any file changes 70 | autoWatch: true, 71 | 72 | // start these browsers 73 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 74 | browsers: ['PhantomJS'], // 'Chrome', 'Firefox', 'Safari', 'PhantomJS' 75 | 76 | // Continuous Integration mode 77 | // if true, Karma captures browsers, runs the tests and exits 78 | singleRun: true 79 | }) 80 | } 81 | -------------------------------------------------------------------------------- /test/lateImageLoad.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 25 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | iFrame message passing test 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Automagically resizing iFrame

13 |

14 | Resize window or click one of the links in the iFrame to watch it resize. 15 | Or try with two iFrames. 16 |

17 |
18 | 19 |
20 |

21 |
22 | For details on how this works, see 23 | http://davidjbradshaw.github.io/iframe-resizer/. 26 |
27 | 28 | 29 | 32 | 33 | 34 | 35 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /example/two.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | iFrame message passing test 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Automagically resizing iFrame

13 |

14 | Resize window or click one of the links in the iFrame to watch it resize. 15 | Or go back to a 16 | single iFrame. 17 |

18 |
19 | 25 | 26 |
27 |

28 |
29 | For details on how this works, see 30 | http://davidjbradshaw.github.io/iframe-resizer/. 33 |
34 | 35 | 36 | 39 | 40 | 41 | 42 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /example/frame.nested.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | iFrame message passing test 6 | 7 | 8 | 9 | 27 | 28 | 29 | 30 | Back to page 1 31 |

Nested iFrame

32 |

33 | Resize window or click one of the links in the nested iFrame to watch it 34 | resize. 35 |

36 |
37 | 43 |
44 |

45 | 46 | 47 | 48 | 49 | 95 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /test/removeIFrame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 |
14 | 20 |
21 |
22 | 23 | 24 | 25 | 26 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to iframe-resizer 2 | 3 | Looking to contribute something? **Here's how you can help.** 4 | 5 | Please take a moment to review this document in order to make the contribution 6 | process easy and effective for everyone involved. 7 | 8 | ## Using the issue tracker 9 | 10 | The [issue tracker](https://github.com/davidjbradshaw/iframe-resizer/issues) is 11 | the preferred channel for [bug reports](#bug-reports), [features requests](#feature-requests) 12 | and [submitting pull requests](#pull-requests). 13 | 14 | **Please do not use the issue tracker for personal support requests. These should be raised on 15 | Stack Overflow ([`iframe-resizer`](http://stackoverflow.com/questions/tagged/iframe-resizer) tag).** 16 | 17 | ## Bug reports 18 | 19 | A bug is a _demonstrable problem_ that is caused by the code in the repository. 20 | Good bug reports are extremely helpful, so thanks! 21 | 22 | Guidelines for bug reports: 23 | 24 | 0. **Lint your code** — Use [jshint](http://jshint.com/) 25 | to ensure your problem isn't caused by a simple error in your own code. 26 | 27 | 1. **Use the GitHub issue search** — check if the issue has already been 28 | reported. 29 | 30 | 1. **Check if the issue has been fixed** — try to reproduce it using the 31 | latest `master` or development branch in the repository. 32 | 33 | 1. **Isolate the problem** — ideally create a [reduced test 34 | case](https://css-tricks.com/reduced-test-cases/) and a live example. 35 | 36 | A good bug report shouldn't leave others needing to chase you up for more 37 | information. Please try to be as detailed as possible in your report. What is 38 | your environment? What steps will reproduce the issue? What browser(s) and OS 39 | experience the problem? Do other browsers show the bug differently? What 40 | would you expect to be the outcome? All these details will help people to fix 41 | any potential bugs. 42 | 43 | Example: 44 | 45 | > Short and descriptive example bug report title 46 | > 47 | > A summary of the issue and the browser/OS environment in which it occurs. If 48 | > suitable, include the steps required to reproduce the bug. 49 | > 50 | > 1. This is the first step 51 | > 2. This is the second step 52 | > 3. Further steps, etc. 53 | > 54 | > `` - a link to the reduced test case 55 | > 56 | > Any other information you want to share that is relevant to the issue being 57 | > reported. This might include the lines of code that you have identified as 58 | > causing the bug, and potential solutions (and your opinions on their 59 | > merits). 60 | 61 | ## Feature requests 62 | 63 | Feature requests are welcome. But take a moment to find out whether your idea 64 | fits with the scope and aims of the project. 65 | 66 | ## Pull requests 67 | 68 | Good pull requests—patches, improvements, new features—are a fantastic 69 | help. They should remain focused in scope and avoid containing unrelated 70 | commits. 71 | 72 | **Please ask first** before embarking on any significant pull request (e.g. 73 | implementing features or refactoring code), 74 | otherwise you risk spending a lot of time working on something that the 75 | project's developers might not want to merge into the project. 76 | 77 | In lieu of a formal style-guide, take care to maintain the existing coding 78 | style. Add unit tests for any new or changed functionality. Lint and test 79 | your code using [Grunt](http://gruntjs.com/). 80 | 81 | ## License 82 | 83 | By contributing your code, you agree to license your contribution under the [MIT License](LICENSE). 84 | -------------------------------------------------------------------------------- /docs/iframed_page/methods.md: -------------------------------------------------------------------------------- 1 | ## IFrame Page Methods 2 | 3 | These methods are available in the iFrame via the `window.parentIFrame` object. These method should be contained by a test for the `window.parentIFrame` object, in case the page is not loaded inside an iFrame. For example: 4 | 5 | ```js 6 | if ('parentIFrame' in window) { 7 | parentIFrame.close(); 8 | } 9 | ``` 10 | 11 | ### autoResize([bool]) 12 | 13 | Turn autoResizing of the iFrame on and off. Returns bool of current state. 14 | 15 | ### close() 16 | 17 | Remove the iFrame from the parent page. 18 | 19 | ### getId() 20 | 21 | Returns the ID of the iFrame that the page is contained in. 22 | 23 | ### getPageInfo(callback || false) 24 | 25 | Ask the containing page for its positioning coordinates. You need to provide a callback which receives an object with the following properties: 26 | 27 | * **iframeHeight** The height of the iframe in pixels 28 | * **iframeWidth** The width of the iframe in pixels 29 | * **offsetLeft** The number of pixels between the left edge of the containing page and the left edge of the iframe 30 | * **offsetTop** The number of pixels between the top edge of the containing page and the top edge of the iframe 31 | * **scrollLeft** The number of pixels between the left edge of the iframe and the left edge of the iframe viewport 32 | * **scrollTop** The number of pixels between the top edge of the iframe and the top edge of the iframe viewport 33 | * **documentHeight** The containing document's height in pixels (the equivalent of `document.documentElement.clientHeight` in the container) 34 | * **documentWidth** The containing document's width in pixels (the equivalent of `document.documentElement.clientWidth` in the container) 35 | * **windowHeight** The containing window's height in pixels (the equivalent of `window.innerHeight` in the container) 36 | * **windowWidth** The containing window's width in pixels (the equivalent of `window.innerWidth` in the container) 37 | * **clientHeight** (deprecated) The height of the containing document, considering the viewport, in pixels (`max(documentHeight, windowHeight)`). 38 | * **clientWidth** (deprecated) The width of the containing document, considering the viewport, in pixels (`max(documentWidth, windowWidth)`). 39 | 40 | 41 | Your callback function will be recalled when the parent page is scrolled or resized. 42 | 43 | Pass `false` to disable the callback. 44 | 45 | ### scrollTo(x,y) 46 | 47 | Scroll the parent page to the coordinates x and y. 48 | 49 | ### scrollToOffset(x,y) 50 | 51 | Scroll the parent page to the coordinates x and y relative to the position of the iFrame. 52 | 53 | ### sendMessage(message,[targetOrigin]) 54 | 55 | Send data to the containing page, `message` can be any data type that can be serialized into JSON. The `targetOrigin` option is used to restrict where the message is sent to; to stop an attacker mimicking your parent page. See the MDN documentation on [postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage) for more details. 56 | 57 | ### setHeightCalculationMethod(heightCalculationMethod) 58 | 59 | Change the method use to workout the height of the iFrame. 60 | 61 | ### size ([customHeight],[ customWidth]) 62 | 63 | Manually force iFrame to resize. This method optionally accepts two arguments: **customHeight** & **customWidth**. To use them you need first to disable the `autoResize` option to prevent auto resizing and enable the `sizeWidth` option if you wish to set the width. 64 | 65 | ```js 66 | iFrameResize({ 67 | autoResize: false, 68 | sizeWidth: true 69 | }); 70 | ``` 71 | 72 | Then you can call the `size` method with dimensions: 73 | 74 | ```js 75 | if ('parentIFrame' in window) { 76 | parentIFrame.size(100); // Set height to 100px 77 | } 78 | ``` 79 | -------------------------------------------------------------------------------- /example/frame.tolerance.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | iFrame message passing test 6 | 7 | 35 | 36 | 37 | 38 |

39 | iFrame 40 | 41 | Back to page 1 42 |   43 | Bottom 49 |

50 |

51 | This page has an absolute position elemnt that take it out side the normal 52 | document body, which is marked with a red border on this page. This 53 | prevents the normal height calculation, which is based on the body tag 54 | from returning the correct height. To work around this you can set the 55 | heightCalculationMethod option to use one of the other page height 56 | propeties. 57 |

58 |

59 | Use the dropdown to change the sizing method of the page, select the 60 | different sizing options to see how the effect the page. Note that they 61 | can have different effects in different browsers, so you are normally best 62 | off selecting max if you need to change away from the default 63 | bodyOffset option. 64 |

65 |

66 | Height Calculation Method 67 | 77 |

78 |

79 | This option should be used sparingly, as the alternate methods can be 81 | less acurate at working out the correct page size, can cause screen 82 | flicker and can sometimes fail to reduce in size when the frame content 83 | changes in browsers that do not support mutationObservers (See 84 | caniuse.com for 85 | details). 87 |

88 | 89 |
90 | Absolute positioned element 91 | Top 97 |
98 | 99 | 100 | 104 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iframe-resizer", 3 | "version": "4.2.10", 4 | "homepage": "https://github.com/davidjbradshaw/iframe-resizer", 5 | "authors": [ 6 | "David J. Bradshaw " 7 | ], 8 | "maintainers": [ 9 | { 10 | "name": "David J. Bradshaw", 11 | "email": "dave@bradshaw.net" 12 | } 13 | ], 14 | "scripts": { 15 | "build": "npm install && grunt", 16 | "eslint": "eslint *.js src/* --color", 17 | "eslint:fix": "npm run eslint -- --fix", 18 | "test-watch": "grunt test-watch", 19 | "test": "grunt travis" 20 | }, 21 | "description": "Keep same and cross domain iFrames sized to their content with support for window/content resizing, and multiple iFrames.", 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/davidjbradshaw/iframe-resizer.git" 25 | }, 26 | "github": "https://github.com/davidjbradshaw/iframe-resizer", 27 | "funding": { 28 | "type": "individual", 29 | "url": "https://github.com/davidjbradshaw/iframe-resizer/blob/master/FUNDING.md" 30 | }, 31 | "dependencies": {}, 32 | "devDependencies": { 33 | "cosmiconfig": "^6.0.0", 34 | "cryptiles": "^4.1.3", 35 | "deep-extend": "^0.6.0", 36 | "eslint": "^6.8.0", 37 | "eslint-config-adjunct": "4.0.2", 38 | "eslint-config-airbnb-base": "^14.1.0", 39 | "eslint-config-prettier": "^6.10.1", 40 | "eslint-plugin-array-func": "^3.1.4", 41 | "eslint-plugin-eslint-comments": "^3.1.2", 42 | "eslint-plugin-html": "^6.0.0", 43 | "eslint-plugin-ie11": "^1.0.0", 44 | "eslint-plugin-import": "^2.20.2", 45 | "eslint-plugin-jasmine": "^4.1.0", 46 | "eslint-plugin-json": "^2.1.1", 47 | "eslint-plugin-json-format": "^2.0.1", 48 | "eslint-plugin-lodash": "^6.0.0", 49 | "eslint-plugin-markdown": "^1.0.2", 50 | "eslint-plugin-no-constructor-bind": "^1.2.8", 51 | "eslint-plugin-no-secrets": "^0.6.5", 52 | "eslint-plugin-no-use-extend-native": "^0.4.1", 53 | "eslint-plugin-only-error": "^1.0.2", 54 | "eslint-plugin-optimize-regex": "^1.1.7", 55 | "eslint-plugin-prettier": "^3.1.2", 56 | "eslint-plugin-promise": "^4.2.1", 57 | "eslint-plugin-simple-import-sort": "^5.0.2", 58 | "eslint-plugin-sonarjs": "^0.5.0", 59 | "eslint-plugin-switch-case": "^1.1.2", 60 | "eslint-plugin-unicorn": "^18.0.1", 61 | "grunt": "^1.1.0", 62 | "grunt-bump": "^0.8.0", 63 | "grunt-cli": "^1.3.2", 64 | "grunt-contrib-clean": "^2.0.0", 65 | "grunt-contrib-compress": "~1.6.0", 66 | "grunt-contrib-copy": "^1.0.0", 67 | "grunt-contrib-jshint": "~2.1.0", 68 | "grunt-contrib-qunit": "^2.0.0", 69 | "grunt-contrib-uglify": "^4.0.1", 70 | "grunt-contrib-watch": "~1.1.0", 71 | "grunt-eslint": "^22.0.0", 72 | "grunt-jsonlint": "~2.1.2", 73 | "grunt-karma": "^3.0.2", 74 | "grunt-karma-coveralls": "^2.5.4", 75 | "grunt-shell": "~3.0.1", 76 | "hoek": "^6.1.3", 77 | "jasmine": "^3.5.0", 78 | "jasmine-core": "^3.5.0", 79 | "jasmine-jquery": "^2.1.1", 80 | "jit-grunt": "~0.10.0", 81 | "jquery": "^3.4.1", 82 | "karma": "^4.4.1", 83 | "karma-chrome-launcher": "^3.1.0", 84 | "karma-coverage": "^2.0.1", 85 | "karma-firefox-launcher": "^1.3.0", 86 | "karma-jasmine": "^3.1.1", 87 | "karma-jasmine-jquery": "^0.1.1", 88 | "karma-logcapture-reporter": "0.0.1", 89 | "karma-phantomjs-launcher": "^1.0.4", 90 | "karma-requirejs": "^1.1.0", 91 | "karma-safari-launcher": "^1.0.0", 92 | "karma-verbose-summary-reporter": "0.0.1", 93 | "load-grunt-tasks": "~5.1.0", 94 | "lodash": "^4.17.15", 95 | "minimatch": "^3.0.4", 96 | "phantomjs": "^2.1.7", 97 | "prettier": "^2.0.2", 98 | "requirejs": "^2.3.6", 99 | "time-grunt": "^2.0.0" 100 | }, 101 | "main": "index.js", 102 | "engines": { 103 | "node": ">=0.8.0" 104 | }, 105 | "license": "MIT", 106 | "keywords": [ 107 | "CrossDomain", 108 | "Cross-Domain", 109 | "iFrame", 110 | "Resizing", 111 | "Resizer", 112 | "postMessage", 113 | "autoheight", 114 | "auto-height", 115 | "iframe-auto-height", 116 | "height-iframe", 117 | "heightiframe", 118 | "width", 119 | "mutationObserver", 120 | "RWD", 121 | "responsiveiframes", 122 | "responsive-iframes", 123 | "jquery-plugin" 124 | ] 125 | } 126 | -------------------------------------------------------------------------------- /example/frame.absolute.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | iFrame message passing test 6 | 7 | 8 | 9 | 36 | 37 | 38 | 39 |

40 | iFrame 41 | 42 | Back to page 1 43 |   44 | Bottom 50 |   51 | Scroll to iFrame 57 |   58 | Jump to iFrame anchor 59 | Jump to parent anchor 60 |

61 |

62 | This page has an absolute position element that take it out side the 63 | normal document body, which is marked with a red border on this page. This 64 | prevents the normal height calculation, which is based on the body tag 65 | from returning the correct height. To work around this you can set the 66 | heightCalculationMethod option to use one of the other page height 67 | propeties. 68 |

69 |

70 | Use the dropdown to change the sizing method of the page, select the 71 | different sizing options to see how the effect the page. Note that they 72 | can have different effects in different browsers, so you are normally best 73 | off selecting max if you need to change away from the default 74 | bodyOffset option. 75 |

76 |

77 | Height Calculation Method 78 | 89 |

90 |

91 | This option should be used sparingly, as the alternate methods can be 93 | less acurate at working out the correct page size, can cause screen 94 | flicker and can sometimes fail to reduce in size when the frame content 95 | changes in browsers that do not support mutationObservers (See 96 | caniuse.com for 97 | details). 99 |

100 | Test in page anchor 101 | 102 |
103 | Absolute positioned element 104 | Top 110 |
111 | 112 | 113 | 114 | 118 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /test/scrolling.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 | 23 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /example/frame.content.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | iFrame message passing test 6 | 7 | 8 | 9 | 20 | 21 | 22 | 23 | iFrame 24 | Toggle content 25 |   26 | Size(250) 31 |   32 | autoResize(true) 37 | 38 | autoResize(false) 43 | 44 | Nested 45 |   46 | :Hover 47 |   48 | TextArea 49 |   50 | Absolute Position 51 |   52 | Send Message 57 |   58 | Close 63 | 64 |

65 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 66 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim 67 | veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea 68 | commodo consequat. Duis aute irure dolor in reprehenderit in voluptate 69 | velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat 70 | cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id 71 | est laborum. 72 |

73 |

74 | But I must explain to you how all this mistaken idea of denouncing 75 | pleasure and praising pain was born and I will give you a complete account 76 | of the system, and expound the actual teachings of the great explorer of 77 | the truth, the master-builder of human happiness. No one rejects, 78 | dislikes, or avoids pleasure itself, because it is pleasure, but because 79 | those who do not know how to pursue pleasure rationally encounter 80 | consequences that are extremely painful. Nor again is there anyone who 81 | loves or pursues or desires to obtain pain of itself, because it is pain, 82 | but because occasionally circumstances occur in which toil and pain can 83 | procure him some great pleasure. To take a trivial example, which of us 84 | ever undertakes laborious physical exercise, except to obtain some 85 | advantage from it? But who has any right to find fault with a man who 86 | chooses to enjoy a pleasure that has no annoying consequences, or one who 87 | avoids a pain that produces no resultant pleasure? 88 |

89 |

90 | On the other hand, we denounce with righteous indignation and dislike men 91 | who are so beguiled and demoralized by the charms of pleasure of the 92 | moment, so blinded by desire, that they cannot foresee the pain and 93 | trouble that are bound to ensue; and equal blame belongs to those who fail 94 | in their duty through weakness of will, which is the same as saying 95 | through shrinking from toil and pain. These cases are perfectly simple and 96 | easy to distinguish. In a free hour, when our power of choice is 97 | untrammelled and when nothing prevents our being able to do what we like 98 | best, every pleasure is to be welcomed and every pain avoided. But in 99 | certain circumstances and owing to the claims of duty or the obligations 100 | of business it will frequently occur that pleasures have to be repudiated 101 | and annoyances accepted. The wise man therefore always holds in these 102 | matters to this principle of selection: he rejects pleasures to secure 103 | other greater pleasures, or else he endures pains to avoid worse pains. 104 |

105 | 106 | 110 | 111 | 118 | 119 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /spec/parentSpec.js: -------------------------------------------------------------------------------- 1 | define(['iframeResizer'], function(iFrameResize) { 2 | describe('Parent Page', function() { 3 | describe('default resize', function() { 4 | var iframe 5 | var log = LOG 6 | var testId = 'defaultResize3' 7 | var ready 8 | 9 | beforeEach(function(done) { 10 | loadIFrame('iframe600.html') 11 | iframe = iFrameResize({ 12 | log: log, 13 | id: testId, 14 | onResized: function() { 15 | ready = true 16 | done() 17 | } 18 | })[0] 19 | 20 | mockMsgFromIFrame(iframe, 'foo') 21 | }) 22 | 23 | afterEach(function() { 24 | tearDown(iframe) 25 | }) 26 | 27 | it('receive message', function() { 28 | expect(ready).toBe(true) 29 | }) 30 | }) 31 | 32 | 33 | describe('reset Page', function() { 34 | var iframe 35 | var log = LOG 36 | var testId = 'parentPage1' 37 | 38 | beforeEach(function(done) { 39 | loadIFrame('iframe600.html') 40 | iframe = iFrameResize({ 41 | log: log, 42 | id: testId 43 | })[0] 44 | 45 | spyOn(iframe.contentWindow, 'postMessage').and.callFake(done) 46 | mockMsgFromIFrame(iframe, 'reset') 47 | }) 48 | 49 | afterEach(function() { 50 | tearDown(iframe) 51 | }) 52 | 53 | it('receive message', function() { 54 | expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith( 55 | '[iFrameSizer]reset', 56 | 'http://localhost:9876' 57 | ) 58 | }) 59 | }) 60 | 61 | describe('late load msg received', function() { 62 | var iframe 63 | var log = LOG 64 | var testId = 'parentPage2' 65 | 66 | beforeEach(function(done) { 67 | loadIFrame('iframe600.html') 68 | iframe = iFrameResize({ 69 | log: log, 70 | id: testId 71 | })[0] 72 | 73 | spyOn(iframe.contentWindow, 'postMessage').and.callFake(done) 74 | window.postMessage('[iFrameResizerChild]Ready', '*') 75 | }) 76 | 77 | afterEach(function() { 78 | tearDown(iframe) 79 | }) 80 | 81 | it('receive message', function() { 82 | expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith( 83 | '[iFrameSizer]parentPage2:8:false:true:32:true:true:null:bodyOffset:null:null:0:false:parent:scroll', 84 | 'http://localhost:9876' 85 | ) 86 | }) 87 | }) 88 | 89 | describe('resize height', function() { 90 | var iframe 91 | var log = LOG 92 | var testId = 'parentPage3' 93 | var HEIGHT = 90 94 | var extraHeights = [1,2,3,4] 95 | 96 | var setUp = (boxSizing, units) => { 97 | loadIFrame('iframe.html') 98 | 99 | iframe = iFrameResize({ 100 | log: log, 101 | id: testId 102 | })[0] 103 | 104 | iframe.style.boxSizing = boxSizing 105 | iframe.style.paddingTop = extraHeights[0] + units 106 | iframe.style.paddingBottom = extraHeights[1] + units 107 | iframe.style.borderTop = `${extraHeights[2]}${units} solid` 108 | iframe.style.borderBottom = `${extraHeights[3]}${units} solid` 109 | 110 | spyPostMsg = spyOn(iframe.contentWindow, 'postMessage') 111 | 112 | // needs timeout so postMessage always comes after 'ready' postMessage 113 | setTimeout(() => { 114 | window.postMessage(`[iFrameSizer]${testId}:${HEIGHT}:600:mutationObserver`, '*') 115 | }, 0) 116 | } 117 | 118 | afterEach(function() { 119 | tearDown(iframe) 120 | }) 121 | 122 | it('includes padding and borders from "px" units in height when CSS "box-sizing" is set to "border-box"', done => { 123 | 124 | setUp('border-box', 'px') 125 | 126 | // timeout needed because of requestAnimationFrame and must be more than window.postMessage in setUp 127 | setTimeout(() => { 128 | expect(iframe.offsetHeight).toBe(HEIGHT + extraHeights.reduce((a, b) => a+b, 0)) 129 | done() 130 | }, 100) 131 | }) 132 | 133 | it('includes padding and borders from "rem" units in height when CSS "box-sizing" is set to "border-box"', done => { 134 | const REM = 14 135 | 136 | // changes the rem units of the doc so we can test accurately 137 | document.querySelector('html').style.fontSize = `${REM}px` 138 | 139 | setUp('border-box', 'rem') 140 | 141 | // timeout needed because of requestAnimationFrame and must be more than window.postMessage in setUp 142 | setTimeout(() => { 143 | expect(iframe.offsetHeight).toBe(HEIGHT + extraHeights.reduce((a, b) => a+(b*REM), 0)) 144 | done() 145 | }, 100) 146 | }) 147 | 148 | it('includes padding and borders from "px" units in height when CSS "box-sizing" is set to "content-box"', done => { 149 | 150 | setUp('content-box', 'px') 151 | 152 | // timeout needed because of requestAnimationFrame and must be more than window.postMessage in setUp 153 | setTimeout(() => { 154 | expect(iframe.offsetHeight).toBe(HEIGHT + extraHeights.reduce((a, b) => a+b, 0)) 155 | done() 156 | }, 100) 157 | }) 158 | 159 | }) 160 | }) 161 | }) 162 | -------------------------------------------------------------------------------- /gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | // show elapsed time at the end 3 | require('time-grunt')(grunt) // eslint-disable-line import/no-extraneous-dependencies 4 | 5 | // load all grunt tasks 6 | // require('load-grunt-tasks')(grunt); 7 | 8 | // eslint-disable-next-line import/no-extraneous-dependencies 9 | require('jit-grunt')(grunt, { 10 | 'bump-only': 'grunt-bump', 11 | 'bump-commit': 'grunt-bump', 12 | coveralls: 'grunt-karma-coveralls' 13 | }) 14 | 15 | // Project configuration. 16 | grunt.initConfig({ 17 | pkg: grunt.file.readJSON('package.json'), 18 | 19 | meta: { 20 | bannerLocal: 21 | '/*! iFrame Resizer (iframeSizer.min.js ) - v<%= pkg.version %> - ' + 22 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' + 23 | ' * Desc: Force cross domain iframes to size to content.\n' + 24 | ' * Requires: iframeResizer.contentWindow.min.js to be loaded into the target frame.\n' + 25 | ' * Copyright: (c) <%= grunt.template.today("yyyy") %> David J. Bradshaw - dave@bradshaw.net\n' + 26 | ' * License: MIT\n */\n', 27 | bannerRemote: 28 | '/*! iFrame Resizer (iframeSizer.contentWindow.min.js) - v<%= pkg.version %> - ' + 29 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' + 30 | ' * Desc: Include this file in any page being loaded into an iframe\n' + 31 | ' * to force the iframe to resize to the content size.\n' + 32 | ' * Requires: iframeResizer.min.js on host page.\n' + 33 | ' * Copyright: (c) <%= grunt.template.today("yyyy") %> David J. Bradshaw - dave@bradshaw.net\n' + 34 | ' * License: MIT\n */\n' 35 | }, 36 | 37 | clean: ['coverage', 'coverageLcov'], 38 | 39 | coveralls: { 40 | options: { 41 | debug: true, 42 | coverageDir: 'coverageLcov', 43 | dryRun: false, 44 | force: true, 45 | recursive: true 46 | } 47 | }, 48 | 49 | uglify: { 50 | options: { 51 | sourceMap: true, 52 | sourceMapIncludeSources: true, 53 | report: 'gzip' 54 | }, 55 | local: { 56 | options: { 57 | banner: '<%= meta.bannerLocal %>', 58 | sourceMapName: 'js/iframeResizer.map' 59 | }, 60 | src: ['js/iframeResizer.js'], 61 | dest: 'js/iframeResizer.min.js' 62 | }, 63 | remote: { 64 | options: { 65 | banner: '<%= meta.bannerRemote %>', 66 | sourceMapName: 'js/iframeResizer.contentWindow.map' 67 | }, 68 | src: ['js/iframeResizer.contentWindow.js'], 69 | dest: 'js/iframeResizer.contentWindow.min.js' 70 | } 71 | }, 72 | 73 | watch: { 74 | files: ['src/**/*'], 75 | tasks: 'default' 76 | }, 77 | 78 | bump: { 79 | options: { 80 | files: [ 81 | 'package.json', 82 | 'package-lock.json', 83 | 'bower.json', 84 | 'iframeResizer.jquery.json' 85 | ], 86 | updateConfigs: ['pkg'], 87 | commit: true, 88 | commitMessage: 'Release v%VERSION%', 89 | commitFiles: ['-a'], // '-a' for all files 90 | createTag: true, 91 | tagName: 'v%VERSION%', 92 | tagMessage: 'Version %VERSION%', 93 | push: true, 94 | pushTo: 'origin', 95 | gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d' // options to use with '$ git describe' 96 | } 97 | }, 98 | 99 | shell: { 100 | options: { 101 | stdout: true, 102 | stderr: true, 103 | failOnError: true 104 | }, 105 | npm: { 106 | command: 'npm publish' 107 | }, 108 | deployExample: { 109 | command: function () { 110 | var retStr = '', 111 | fs = require('fs') 112 | 113 | if (fs.existsSync('bin')) { 114 | retStr = 'bin/deploy.sh' 115 | } 116 | 117 | return retStr 118 | } 119 | } 120 | }, 121 | 122 | jsonlint: { 123 | json: { 124 | src: ['*.json'] 125 | } 126 | }, 127 | 128 | removeBlock: { 129 | options: ['TEST CODE START', 'TEST CODE END'], 130 | files: [ 131 | { 132 | src: 'src/iframeResizer.contentWindow.js', 133 | dest: 'js/iframeResizer.contentWindow.js' 134 | } 135 | ] 136 | }, 137 | 138 | copy: { 139 | main: { 140 | nonull: true, 141 | src: 'src/iframeResizer.js', 142 | dest: 'js/iframeResizer.js' 143 | } 144 | }, 145 | 146 | eslint: { 147 | target: ['src/**', '*.js'] 148 | } 149 | }) 150 | 151 | grunt.registerTask('default', ['notest']) 152 | grunt.registerTask('build', ['removeBlock', 'copy', 'uglify']) 153 | grunt.registerTask('notest', ['eslint', 'jsonlint', 'build']) 154 | grunt.registerTask('test', ['clean', 'eslint']) 155 | grunt.registerTask('test-watch', ['clean']) 156 | grunt.registerTask('travis', ['clean', 'notest', 'coveralls']) 157 | 158 | grunt.registerTask('postBump', ['build', 'bump-commit', 'shell']) 159 | grunt.registerTask('preBump', ['clean', 'notest']) 160 | grunt.registerTask('patch', ['preBump', 'bump-only:patch', 'postBump']) 161 | grunt.registerTask('minor', ['preBump', 'bump-only:minor', 'postBump']) 162 | grunt.registerTask('major', ['preBump', 'bump-only:major', 'postBump']) 163 | 164 | grunt.registerMultiTask('removeBlock', function () { 165 | // set up a removal regular expression 166 | var removalRegEx = new RegExp( 167 | '(// ' + 168 | this.options()[0] + 169 | ' //)(?:[^])*?(// ' + 170 | this.options()[1] + 171 | ' //)', 172 | 'g' 173 | ) 174 | 175 | this.data.forEach(function (fileObj) { 176 | var sourceFile = grunt.file.read(fileObj.src) 177 | var removedFile = sourceFile.replace(removalRegEx, '') 178 | 179 | grunt.file.write(fileObj.dest, removedFile) 180 | }) // for each loop end 181 | }) 182 | } 183 | -------------------------------------------------------------------------------- /test/resources/qunit.css: -------------------------------------------------------------------------------- 1 | /** 2 | * QUnit v1.12.0 - A JavaScript Unit Testing Framework 3 | * 4 | * http://qunitjs.com 5 | * 6 | * Copyright 2012 jQuery Foundation and other contributors 7 | * Released under the MIT license. 8 | * http://jquery.org/license 9 | */ 10 | 11 | /** Font Family and Sizes */ 12 | 13 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { 14 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; 15 | } 16 | 17 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } 18 | #qunit-tests { font-size: smaller; } 19 | 20 | 21 | /** Resets */ 22 | 23 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { 24 | margin: 0; 25 | padding: 0; 26 | } 27 | 28 | 29 | /** Header */ 30 | 31 | #qunit-header { 32 | padding: 0.5em 0 0.5em 1em; 33 | 34 | color: #8699a4; 35 | background-color: #0d3349; 36 | 37 | font-size: 1.5em; 38 | line-height: 1em; 39 | font-weight: normal; 40 | 41 | border-radius: 5px 5px 0 0; 42 | -moz-border-radius: 5px 5px 0 0; 43 | -webkit-border-top-right-radius: 5px; 44 | -webkit-border-top-left-radius: 5px; 45 | } 46 | 47 | #qunit-header a { 48 | text-decoration: none; 49 | color: #c2ccd1; 50 | } 51 | 52 | #qunit-header a:hover, 53 | #qunit-header a:focus { 54 | color: #fff; 55 | } 56 | 57 | #qunit-testrunner-toolbar label { 58 | display: inline-block; 59 | padding: 0 .5em 0 .1em; 60 | } 61 | 62 | #qunit-banner { 63 | height: 5px; 64 | } 65 | 66 | #qunit-testrunner-toolbar { 67 | padding: 0.5em 0 0.5em 2em; 68 | color: #5E740B; 69 | background-color: #eee; 70 | overflow: hidden; 71 | } 72 | 73 | #qunit-userAgent { 74 | padding: 0.5em 0 0.5em 2.5em; 75 | background-color: #2b81af; 76 | color: #fff; 77 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 78 | } 79 | 80 | #qunit-modulefilter-container { 81 | float: right; 82 | } 83 | 84 | /** Tests: Pass/Fail */ 85 | 86 | #qunit-tests { 87 | list-style-position: inside; 88 | } 89 | 90 | #qunit-tests li { 91 | padding: 0.4em 0.5em 0.4em 2.5em; 92 | border-bottom: 1px solid #fff; 93 | list-style-position: inside; 94 | } 95 | 96 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { 97 | display: none; 98 | } 99 | 100 | #qunit-tests li strong { 101 | cursor: pointer; 102 | } 103 | 104 | #qunit-tests li a { 105 | padding: 0.5em; 106 | color: #c2ccd1; 107 | text-decoration: none; 108 | } 109 | #qunit-tests li a:hover, 110 | #qunit-tests li a:focus { 111 | color: #000; 112 | } 113 | 114 | #qunit-tests li .runtime { 115 | float: right; 116 | font-size: smaller; 117 | } 118 | 119 | .qunit-assert-list { 120 | margin-top: 0.5em; 121 | padding: 0.5em; 122 | 123 | background-color: #fff; 124 | 125 | border-radius: 5px; 126 | -moz-border-radius: 5px; 127 | -webkit-border-radius: 5px; 128 | } 129 | 130 | .qunit-collapsed { 131 | display: none; 132 | } 133 | 134 | #qunit-tests table { 135 | border-collapse: collapse; 136 | margin-top: .2em; 137 | } 138 | 139 | #qunit-tests th { 140 | text-align: right; 141 | vertical-align: top; 142 | padding: 0 .5em 0 0; 143 | } 144 | 145 | #qunit-tests td { 146 | vertical-align: top; 147 | } 148 | 149 | #qunit-tests pre { 150 | margin: 0; 151 | white-space: pre-wrap; 152 | word-wrap: break-word; 153 | } 154 | 155 | #qunit-tests del { 156 | background-color: #e0f2be; 157 | color: #374e0c; 158 | text-decoration: none; 159 | } 160 | 161 | #qunit-tests ins { 162 | background-color: #ffcaca; 163 | color: #500; 164 | text-decoration: none; 165 | } 166 | 167 | /*** Test Counts */ 168 | 169 | #qunit-tests b.counts { color: black; } 170 | #qunit-tests b.passed { color: #5E740B; } 171 | #qunit-tests b.failed { color: #710909; } 172 | 173 | #qunit-tests li li { 174 | padding: 5px; 175 | background-color: #fff; 176 | border-bottom: none; 177 | list-style-position: inside; 178 | } 179 | 180 | /*** Passing Styles */ 181 | 182 | #qunit-tests li li.pass { 183 | color: #3c510c; 184 | background-color: #fff; 185 | border-left: 10px solid #C6E746; 186 | } 187 | 188 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } 189 | #qunit-tests .pass .test-name { color: #366097; } 190 | 191 | #qunit-tests .pass .test-actual, 192 | #qunit-tests .pass .test-expected { color: #999999; } 193 | 194 | #qunit-banner.qunit-pass { background-color: #C6E746; } 195 | 196 | /*** Failing Styles */ 197 | 198 | #qunit-tests li li.fail { 199 | color: #710909; 200 | background-color: #fff; 201 | border-left: 10px solid #EE5757; 202 | white-space: pre; 203 | } 204 | 205 | #qunit-tests > li:last-child { 206 | border-radius: 0 0 5px 5px; 207 | -moz-border-radius: 0 0 5px 5px; 208 | -webkit-border-bottom-right-radius: 5px; 209 | -webkit-border-bottom-left-radius: 5px; 210 | } 211 | 212 | #qunit-tests .fail { color: #000000; background-color: #EE5757; } 213 | #qunit-tests .fail .test-name, 214 | #qunit-tests .fail .module-name { color: #000000; } 215 | 216 | #qunit-tests .fail .test-actual { color: #EE5757; } 217 | #qunit-tests .fail .test-expected { color: green; } 218 | 219 | #qunit-banner.qunit-fail { background-color: #EE5757; } 220 | 221 | 222 | /** Result */ 223 | 224 | #qunit-testresult { 225 | padding: 0.5em 0.5em 0.5em 2.5em; 226 | 227 | color: #2b81af; 228 | background-color: #D2E0E6; 229 | 230 | border-bottom: 1px solid white; 231 | } 232 | #qunit-testresult .module-name { 233 | font-weight: bold; 234 | } 235 | 236 | /** Fixture */ 237 | 238 | #qunit-fixture { 239 | position: absolute; 240 | top: -10000px; 241 | left: -10000px; 242 | width: 1000px; 243 | height: 1000px; 244 | } 245 | -------------------------------------------------------------------------------- /test/v1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit LoadHide 6 | 7 | 8 | 9 |
10 |
11 |
12 | 17 |
18 |
19 | 20 | 21 | 187 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /docs/troubleshooting.md: -------------------------------------------------------------------------------- 1 | ## Troubleshooting 2 | 3 | The first steps to investigate a problem is to make sure you are using the latest version and then enable the [log](#log) option, which outputs everything that happens to the [JavaScript Console](https://developers.google.com/chrome-developer-tools/docs/console#opening_the_console). This will enable you to see what both the iFrame and host page are up to and also see any JavaScript error messages. 4 | 5 | Solutions for the most common problems are outlined in this section. If you need futher help, then please ask questions on [StackOverflow](http://stackoverflow.com/questions/tagged/iframe-resizer) with the `iframe-resizer` tag. 6 | 7 | Bug reports and pull requests are welcome on the [issue tracker](https://github.com/davidjbradshaw/iframe-resizer/issues). Please read the [contributing guidelines](https://github.com/davidjbradshaw/iframe-resizer/blob/master/CONTRIBUTING.md) before openning a ticket, as this will ensure a faster resolution. 8 | 9 | ### Multiple IFrames on one page 10 | 11 | When the resizer does not work using multiple IFrames on one page, make sure that each frame has an unique id or no ids at all. 12 | 13 | ### IFrame not sizing correctly 14 | 15 | If a larger element of content is removed from the normal document flow, through the use of absolute positioning, it can prevent the browser working out the correct size of the page. In such cases you can change the [heightCalculationMethod](./parent_page/options.md#heightcalculationmethod) to uses one of the other sizing methods. 16 | 17 | ### IFrame not downsizing 18 | 19 | The most likely cause of this problem is having set the height of an element to be 100% of the page somewhere in your CSS. This is normally on the `html` or `body` elements, but it could be on any element in the page. This can sometimes be got around by using the `taggedElement` height calculation method and added a `data-iframe-height` attribute to the element that you want to define the bottom position of the page. You may find it useful to use `position: relative` on this element to define a bottom margin or allow space for a floating footer. 20 | 21 | Not having a valid [HTML document type](http://en.wikipedia.org/wiki/Document_type_declaration) in the iFrame can also sometimes prevent downsizing. At it's most simplest this can be the following. 22 | 23 | ```html 24 | 25 | ``` 26 | 27 | ### IFrame not resizing 28 | 29 | The most common cause of this is not placing the [iframeResizer.contentWindow.min.js](https://raw.github.com/davidjbradshaw/iframe-resizer/master/js/iframeResizer.contentWindow.min.js) script inside the iFramed page. If the other page is on a domain outside your control and you can not add JavaScript to that page, then now is the time to give up all hope of ever getting the iFrame to size to the content. As it is impossible to work out the size of the contained page, without using JavaScript on both the parent and child pages. 30 | 31 | ### IFrame not detecting CSS :hover events 32 | 33 | If your page resizes via CSS `:hover` events, these won't be detected by default. It is however possible to create `mouseover` and `mouseout` event listeners on the elements that are resized via CSS and have these events call the [parentIFrame.size()](##parentiframesize-customheight-customwidth) method. With jQuery this can be done as follows 34 | 35 | ```js 36 | function resize(){ 37 | if ('parentIFrame' in window) { 38 | // Fix race condition in FireFox with setTimeout 39 | setTimeout(parentIFrame.size.bind(parentIFrame),0); 40 | } 41 | } 42 | 43 | $(*Element with hover style*).hover(resize); 44 | ``` 45 | 46 | ### IFrame not detecting textarea resizes 47 | 48 | Both FireFox and the WebKit based browsers allow the user to resize `textarea` input boxes. Unfortunately the WebKit browsers don't trigger the mutation event when this happens. This can be worked around to some extent with the following code. 49 | 50 | ```js 51 | function store() { 52 | this.x = this.offsetWidth 53 | this.y = this.offsetHeight 54 | } 55 | 56 | $('textarea') 57 | .each(store) 58 | .on('mouseover mouseout', function() { 59 | if (this.offsetWidth !== this.x || this.offsetHeight !== this.y) { 60 | store.call(this) 61 | if ('parentIFrame' in window) { 62 | parentIFrame.size() 63 | } 64 | } 65 | }) 66 | ``` 67 | 68 | ### IFrame flickers 69 | 70 | Some of the alternate [height calculation methods](./parent_page/options.md#heightcalculationmethod), such as **max** can cause the iFrame to flicker. This is due to the fact that to check for downsizing, the iFrame first has to be downsized before the new height can be worked out. This effect can be reduced by setting a [minSize](./docs/parent_page/options.md#minheight--minwidth) value, so that the iFrame is not reset to zero height before regrowing. 71 | 72 | In modern browsers, if the default [height calculation method](./parent_page/options.md#heightcalculationmethod) does not work, then it is normally best to use **taggedElement** or **lowestElement**, which are both flicker free. 73 | 74 | Please see the notes section under [heightCalculationMethod](./parent_page/options.md#heightcalculationmethod) to understand the limitations of the different options. 75 | 76 | ### Failed to execute 'postMessage' on 'DOMWindow' 77 | 78 | This error occurs when the parent window tries to send a message to the iframe before it has loaded. IFrameResize makes multiple attempts to talk to the iFrame, so if everything is working then you can safely ignore this error message. 79 | 80 | If you're still having problems, or you really want to not ignore the error, then you can try delaying the call to `iframeResize()` until after the `onLoad` event of the iframe has fired. 81 | 82 | If this does not fix the problem then check `x-Frame-Options` http header on the server that is sending the iframe content, as this can also block calls to `postMessage` if set incorrectly. 83 | 84 | 85 | ### ParentIFrame not found errors 86 | 87 | The `parentIFrame` object is created once the iFrame has been initially resized. If you wish to use it during page load you will need call it from the onReady. 88 | 89 | ```html 90 | 98 | 99 | ``` 100 | 101 | ### PDF and OpenDocument files 102 | 103 | It is not possible to add the required JavaScript to PDF and ODF files. However, you can get around this limitation by using [ViewerJS](http://viewerjs.org/) to render these files inside a HTML page, that also contains the iFrame JavaScript file ([iframeResizer.contentWindow.min.js](https://raw.github.com/davidjbradshaw/iframe-resizer/master/js/iframeResizer.contentWindow.min.js)). 104 | 105 | ### Unexpected message received error 106 | 107 | By default the origin of incoming messages is checked against the `src` attribute of the iFrame. If they don't match an error is thrown. This behaviour can be disabled by setting the [checkOrigin](./docs/parent_page/options.md#checkorigin) option to **false**. 108 | 109 | ### Width not resizing 110 | 111 | By default only changes in height are detected, if you want to calculate the width you need to set the `sizeWidth` opion to true and the `sizeHeight` option to false. 112 | -------------------------------------------------------------------------------- /docs/parent_page/options.md: -------------------------------------------------------------------------------- 1 | 2 | ## Options 3 | 4 | The following options can be passed to iframe-resizer on the parent page. 5 | 6 | ### log 7 | 8 | default: false 9 | type: boolean 10 | 11 | Setting the `log` option to true will make the scripts in both the host page and the iFrame output everything they do to the JavaScript console so you can see the communication between the two scripts. 12 | 13 | ### autoResize 14 | 15 | default: true 16 | type: boolean 17 | 18 | When enabled changes to the Window size or the DOM will cause the iFrame to resize to the new content size. Disable if using size method with custom dimensions. 19 | 20 | Note: When set to false the iFrame will still inititally size to the contained content, only additional resizing events are disabled. 21 | 22 | ### bodyBackground 23 | 24 | default: null 25 | type: string 26 | 27 | Override the body background style in the iFrame. 28 | 29 | ### bodyMargin 30 | 31 | default: null 32 | type: string || number 33 | 34 | Override the default body margin style in the iFrame. A string can be any valid value for the CSS margin attribute, for example '8px 3em'. A number value is converted into px. 35 | 36 | ### bodyPadding 37 | 38 | default: null 39 | type: string || number 40 | 41 | Override the default body padding style in the iFrame. A string can be any valid value for the CSS margin attribute, for example '8px 3em'. A number value is converted into px. 42 | 43 | ### checkOrigin 44 | 45 | default: true 46 | type: boolean || array 47 | 48 | When set to true, only allow incoming messages from the domain listed in the `src` property of the iFrame tag. If your iFrame navigates between different domains, ports or protocols; then you will need to provide an array of URLs or disable this option. 49 | 50 | ### inPageLinks 51 | 52 | default: false 53 | type: boolean 54 | 55 | When enabled in page linking inside the iFrame and from the iFrame to the parent page will be enabled. 56 | 57 | ### heightCalculationMethod 58 | 59 | default: 'bodyOffset' 60 | values: 'bodyOffset' | 'bodyScroll' | 'documentElementOffset' | 'documentElementScroll' | 61 | 'max' | 'min' | 'grow' | 'lowestElement' | 'taggedElement' 62 | 63 | By default the height of the iFrame is calculated by converting the margin of the `body` to px and then adding the top and bottom figures to the offsetHeight of the `body` tag. 64 | 65 | In cases where CSS styles causes the content to flow outside the `body` you may need to change this setting to one of the following options. Each can give different values depending on how CSS is used in the page and each has varying side-effects. You will need to experiment to see which is best for any particular circumstance. 66 | 67 | * **bodyOffset** uses `document.body.offsetHeight` 68 | * **bodyScroll** uses `document.body.scrollHeight` * 69 | * **documentElementOffset** uses `document.documentElement.offsetHeight` 70 | * **documentElementScroll** uses `document.documentElement.scrollHeight` * 71 | * **max** takes the largest value of the main four options * 72 | * **min** takes the smallest value of the main four options * 73 | * **lowestElement** Loops though every element in the the DOM and finds the lowest bottom point 74 | * **taggedElement** Finds the bottom of the lowest element with a `data-iframe-height` attribute 75 | 76 | Notes: 77 | 78 | **If the default option doesn't work then the best solutions is to use either** taggedElement, **or** lowestElement**.** Alternatively it is possible to add your own custom sizing method directly inside the iFrame, see the [iFrame Page Options](../iframed_page/options.md) section for more details. 79 | 80 | The **lowestElement** option is the most reliable way of determining the page height. However, it does have a performance impact, as it requires checking the position of every element on the page. The **taggedElement** option provides much greater performance by limiting the number of elements that need their position checked. 81 | 82 | * These methods can cause screen flicker in some browsers. 83 | 84 | ### maxHeight / maxWidth 85 | 86 | default: infinity 87 | type: integer 88 | 89 | Set maximum height/width of iFrame. 90 | 91 | ### minHeight / minWidth 92 | 93 | default: 0 94 | type: integer 95 | 96 | Set minimum height/width of iFrame. 97 | 98 | ### resizeFrom 99 | 100 | default: 'parent' 101 | values: 'parent', 'child' 102 | 103 | Listen for resize events from the parent page, or the iFrame. Select the 'child' value if the iFrame can be resized independently of the browser window. Selecting this value can cause issues with some height calculation methods on mobile devices. 104 | 105 | ### scrolling 106 | 107 | default: false 108 | type: boolean | 'omit' 109 | 110 | Enable scroll bars in iFrame. 111 | 112 | * **true** applies `scrolling="yes"` 113 | * **false** applies `scrolling="no"` 114 | * **'omit'** applies no `scrolling` attribute to the iFrame 115 | 116 | ### sizeHeight 117 | 118 | default: true 119 | type: boolean 120 | 121 | Resize iFrame to content height. 122 | 123 | ### sizeWidth 124 | 125 | default: false 126 | type: boolean 127 | 128 | Resize iFrame to content width. 129 | 130 | 131 | ### tolerance 132 | 133 | default: 0 134 | type: integer 135 | 136 | Set the number of pixels the iFrame content size has to change by, before triggering a resize of the iFrame. 137 | 138 | ### widthCalculationMethod 139 | 140 | default: 'scroll' 141 | values: 'bodyOffset' | 'bodyScroll' | 'documentElementOffset' | 'documentElementScroll' | 142 | 'max' | 'min' | 'scroll' | 'rightMostElement' | 'taggedElement' 143 | 144 | By default the width of the page is worked out by taking the greater of the **documentElement** and **body** scrollWidth values. 145 | 146 | Some CSS techniques may require you to change this setting to one of the following options. Each can give different values depending on how CSS is used in the page and each has varying side-effects. You will need to experiment to see which is best for any particular circumstance. 147 | 148 | * **bodyOffset** uses `document.body.offsetWidth` 149 | * **bodyScroll** uses `document.body.scrollWidth` * 150 | * **documentElementOffset** uses `document.documentElement.offsetWidth` 151 | * **documentElementScroll** uses `document.documentElement.scrollWidth` * 152 | * **scroll** takes the largest value of the two scroll options * 153 | * **max** takes the largest value of the main four options * 154 | * **min** takes the smallest value of the main four options * 155 | * **rightMostElement** Loops though every element in the the DOM and finds the right most point 156 | * **taggedElement** Finds the left most element with a `data-iframe-width` attribute 157 | 158 | Alternatively it is possible to add your own custom sizing method directly inside the iFrame, see the [iFrame Page Options](../iframed_page/options.md) section for more details 159 | 160 | The **rightMostElement** option is the most reliable way of determining the page width. However, it does have a performance impact as it requires calculating the position of every element on the page. The **taggedElement** option provides much greater performance by limiting the number of elements that need their position checked. 161 | 162 | * These methods can cause screen flicker in some browsers. 163 | -------------------------------------------------------------------------------- /js/iframeResizer.min.js: -------------------------------------------------------------------------------- 1 | /*! iFrame Resizer (iframeSizer.min.js ) - v4.2.10 - 2020-04-20 2 | * Desc: Force cross domain iframes to size to content. 3 | * Requires: iframeResizer.contentWindow.min.js to be loaded into the target frame. 4 | * Copyright: (c) 2020 David J. Bradshaw - dave@bradshaw.net 5 | * License: MIT 6 | */ 7 | 8 | !function(l){if("undefined"!=typeof window){var m=0,g=!1,o=!1,v="message".length,I="[iFrameSizer]",x=I.length,M=null,r=window.requestAnimationFrame,h={max:1,scroll:1,bodyScroll:1,documentElementScroll:1},k={},t=null,p={autoResize:!0,bodyBackground:null,bodyMargin:null,bodyMarginV1:8,bodyPadding:null,checkOrigin:!0,inPageLinks:!1,enablePublicMethods:!0,heightCalculationMethod:"bodyOffset",id:"iFrameResizer",interval:32,log:!1,maxHeight:1/0,maxWidth:1/0,minHeight:0,minWidth:0,resizeFrom:"parent",scrolling:!1,sizeHeight:!0,sizeWidth:!1,warningTimeout:5e3,tolerance:0,widthCalculationMethod:"scroll",onClose:function(){return!0},onClosed:function(){},onInit:function(){},onMessage:function(){R("onMessage function not defined")},onResized:function(){},onScroll:function(){return!0}},F={};"function"==typeof define&&define.amd?define([],u):"object"==typeof module&&"object"==typeof module.exports&&(module.exports=u())}function w(){return window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver}function z(e,n,t){e.addEventListener(n,t,!1)}function O(e,n,t){e.removeEventListener(n,t,!1)}function a(e){return I+"["+function(e){var n="Host page: "+e;return window.top!==window.self&&(n=window.parentIFrame&&window.parentIFrame.getId?window.parentIFrame.getId()+": "+e:"Nested host page: "+e),n}(e)+"]"}function T(e){return k[e]?k[e].log:g}function N(e,n){E("log",e,n,T(e))}function R(e,n){E("warn",e,n,!0)}function E(e,n,t,i){!0===i&&"object"==typeof window.console&&console[e](a(n),t)}function e(n){function e(){t("Height"),t("Width"),B(function(){A(b),H(y),d("onResized",b)},b,"init")}function t(e){var n=Number(k[y]["max"+e]),t=Number(k[y]["min"+e]),i=e.toLowerCase(),o=Number(b[i]);N(y,"Checking "+i+" is in range "+t+"-"+n),ok[c]["max"+e])throw new Error("Value for min"+e+" can not be greater than max"+e)}c in k&&"iFrameResizer"in t?R(c,"Ignored iFrame, already setup."):(d=(d=e)||{},k[c]={firstRun:!0,iframe:t,remoteHost:t.src&&t.src.split("/").slice(0,3).join("/")},function(e){if("object"!=typeof e)throw new TypeError("Options is not an object")}(d),Object.keys(d).forEach(n,d),function(e){for(var n in p)Object.prototype.hasOwnProperty.call(p,n)&&(k[c][n]=Object.prototype.hasOwnProperty.call(e,n)?e[n]:p[n])}(d),k[c]&&(k[c].targetOrigin=!0===k[c].checkOrigin?function(e){return""===e||null!==e.match(/^(about:blank|javascript:|file:\/\/)/)?"*":e}(k[c].remoteHost):"*"),function(){switch(N(c,"IFrame scrolling "+(k[c]&&k[c].scrolling?"enabled":"disabled")+" for "+c),t.style.overflow=!1===(k[c]&&k[c].scrolling)?"hidden":"auto",k[c]&&k[c].scrolling){case"omit":break;case!0:t.scrolling="yes";break;case!1:t.scrolling="no";break;default:t.scrolling=k[c]?k[c].scrolling:"no"}}(),f("Height"),f("Width"),u("maxHeight"),u("minHeight"),u("maxWidth"),u("minWidth"),"number"!=typeof(k[c]&&k[c].bodyMargin)&&"0"!==(k[c]&&k[c].bodyMargin)||(k[c].bodyMarginV1=k[c].bodyMargin,k[c].bodyMargin=k[c].bodyMargin+"px"),r=q(c),(s=w())&&(a=s,t.parentNode&&new a(function(e){e.forEach(function(e){Array.prototype.slice.call(e.removedNodes).forEach(function(e){e===t&&C(t)})})}).observe(t.parentNode,{childList:!0})),z(t,"load",function(){L("iFrame.onload",r,t,l,!0),function(){var e=k[c]&&k[c].firstRun,n=k[c]&&k[c].heightCalculationMethod in h;!e&&n&&j({iframe:t,height:0,width:0,type:"init"})}()}),L("init",r,t,l,!0),k[c]&&(k[c].iframe.iFrameResizer={close:C.bind(null,k[c].iframe),removeListeners:b.bind(null,k[c].iframe),resize:L.bind(null,"Window resize","resize",k[c].iframe),moveToAnchor:function(e){L("Move to anchor","moveToAnchor:"+e,k[c].iframe,c)},sendMessage:function(e){L("Send Message","message:"+(e=JSON.stringify(e)),k[c].iframe,c)}}))}function d(e,n){null===t&&(t=setTimeout(function(){t=null,e()},n))}function n(){"hidden"!==document.visibilityState&&(N("document","Trigger event: Visiblity change"),d(function(){i("Tab Visable","resize")},16))}function i(n,t){Object.keys(k).forEach(function(e){!function(e){return k[e]&&"parent"===k[e].resizeFrom&&k[e].autoResize&&!k[e].firstRun}(e)||L(n,t,k[e].iframe,e)})}function c(){z(window,"message",e),z(window,"resize",function(){!function(e){N("window","Trigger event: "+e),d(function(){i("Window "+e,"resize")},16)}("resize")}),z(document,"visibilitychange",n),z(document,"-webkit-visibilitychange",n)}function u(){function t(e,n){n&&(function(){if(!n.tagName)throw new TypeError("Object is not a valid DOM element");if("IFRAME"!==n.tagName.toUpperCase())throw new TypeError("Expected