├── .babelrc ├── .eslintrc ├── .gitignore ├── .npmignore ├── .scripts ├── get_gh_pages_url.js ├── mocha_runner.js ├── prepublish.sh ├── publish_storybook.sh └── user │ ├── prepublish.sh │ └── pretest.js ├── .storybook ├── config.js ├── user │ └── modify_webpack_config.js └── webpack.config.js ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── package.json └── src ├── index.js ├── stories ├── index.js ├── loremipsum.js └── loremipsumAsReact.js └── tests └── index.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2", "react"] 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "arrow-body-style": 0, 5 | "prefer-arrow-callback": 0, 6 | "func-names": 0, 7 | "react/jsx-no-bind": 0, 8 | "react/jsx-uses-react": 1, 9 | "react/prefer-stateless-function": 0 10 | }, 11 | "parserOptions": { 12 | "ecmaVersion": 6, 13 | "ecmaFeatures": { 14 | "experimentalObjectRestSpread": true 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .idea 4 | dist 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | .babelrc 3 | -------------------------------------------------------------------------------- /.scripts/get_gh_pages_url.js: -------------------------------------------------------------------------------- 1 | // IMPORTANT 2 | // --------- 3 | // This is an auto generated file with React CDK. 4 | // Do not modify this file. 5 | 6 | const parse = require('git-url-parse'); 7 | var ghUrl = process.argv[2]; 8 | const parsedUrl = parse(ghUrl); 9 | 10 | const ghPagesUrl = 'https://' + parsedUrl.owner + '.github.io/' + parsedUrl.name; 11 | console.log(ghPagesUrl); 12 | -------------------------------------------------------------------------------- /.scripts/mocha_runner.js: -------------------------------------------------------------------------------- 1 | // IMPORTANT 2 | // --------- 3 | // This is an auto generated file with React CDK. 4 | // Do not modify this file. 5 | // Use `.scripts/user/pretest.js instead`. 6 | 7 | require('babel-core/register'); 8 | require('babel-polyfill'); 9 | 10 | // Add jsdom support, which is required for enzyme. 11 | var jsdom = require('jsdom').jsdom; 12 | 13 | var exposedProperties = ['window', 'navigator', 'document']; 14 | 15 | global.document = jsdom(''); 16 | global.window = document.defaultView; 17 | Object.keys(document.defaultView).forEach((property) => { 18 | if (typeof global[property] === 'undefined') { 19 | exposedProperties.push(property); 20 | global[property] = document.defaultView[property]; 21 | } 22 | }); 23 | 24 | global.navigator = { 25 | userAgent: 'node.js' 26 | }; 27 | 28 | process.on('unhandledRejection', function (error) { 29 | console.error('Unhandled Promise Rejection:'); 30 | console.error(error && error.stack || error); 31 | }); 32 | 33 | require('./user/pretest.js'); 34 | -------------------------------------------------------------------------------- /.scripts/prepublish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # IMPORTANT 4 | # --------- 5 | # This is an auto generated file with React CDK. 6 | # Do not modify this file. 7 | # Use `.scripts/user/prepublish.sh instead`. 8 | 9 | echo "=> Transpiling 'src' into ES5 ..." 10 | echo "" 11 | rm -rf ./dist 12 | ./node_modules/.bin/babel --ignore tests,stories --plugins "transform-runtime" ./src --out-dir ./dist 13 | echo "" 14 | echo "=> Transpiling completed." 15 | 16 | . .scripts/user/prepublish.sh 17 | -------------------------------------------------------------------------------- /.scripts/publish_storybook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # IMPORTANT 4 | # --------- 5 | # This is an auto generated file with React CDK. 6 | # Do not modify this file. 7 | 8 | set -e # exit with nonzero exit code if anything fails 9 | 10 | # get GIT url 11 | 12 | GIT_URL=`git config --get remote.origin.url` 13 | if [[ $GIT_URL == "" ]]; then 14 | echo "This project is not configured with a remote git repo". 15 | exit 1 16 | fi 17 | 18 | # clear and re-create the out directory 19 | rm -rf .out || exit 0; 20 | mkdir .out; 21 | 22 | # run our compile script, discussed above 23 | build-storybook -o .out 24 | 25 | # go to the out directory and create a *new* Git repo 26 | cd .out 27 | git init 28 | 29 | # inside this git repo we'll pretend to be a new user 30 | git config user.name "GH Pages Bot" 31 | git config user.email "hello@ghbot.com" 32 | 33 | # The first and only commit to this new Git repo contains all the 34 | # files present with the commit message "Deploy to GitHub Pages". 35 | git add . 36 | git commit -m "Deploy Storybook to GitHub Pages" 37 | 38 | # Force push from the current repo's master branch to the remote 39 | # repo's gh-pages branch. (All previous history on the gh-pages branch 40 | # will be lost, since we are overwriting it.) We redirect any output to 41 | # /dev/null to hide any sensitive credential data that might otherwise be exposed. 42 | git push --force --quiet $GIT_URL master:gh-pages > /dev/null 2>&1 43 | cd .. 44 | rm -rf .out 45 | 46 | echo "" 47 | echo "=> Storybook deployed to: `node .scripts/get_gh_pages_url.js $GIT_URL`" 48 | -------------------------------------------------------------------------------- /.scripts/user/prepublish.sh: -------------------------------------------------------------------------------- 1 | # Use this file to your own code to run at NPM `prepublish` event. 2 | -------------------------------------------------------------------------------- /.scripts/user/pretest.js: -------------------------------------------------------------------------------- 1 | // Use this file to setup any test utilities. 2 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | // IMPORTANT 2 | // --------- 3 | // This is an auto generated file with React CDK. 4 | // Do not modify this file. 5 | 6 | import { configure } from '@kadira/storybook'; 7 | 8 | function loadStories() { 9 | require('../src/stories'); 10 | } 11 | 12 | configure(loadStories, module); 13 | -------------------------------------------------------------------------------- /.storybook/user/modify_webpack_config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (config) { 2 | // This is the default webpack config defined in the `../webpack.config.js` 3 | // modify as you need. 4 | }; 5 | -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | // IMPORTANT 2 | // --------- 3 | // This is an auto generated file with React CDK. 4 | // Do not modify this file. 5 | // Use `.storybook/user/modify_webpack_config.js instead`. 6 | 7 | const path = require('path'); 8 | const updateConfig = require('./user/modify_webpack_config'); 9 | 10 | const config = { 11 | module: { 12 | loaders: [ 13 | { 14 | test: /\.css?$/, 15 | loaders: ['style', 'raw'], 16 | include: path.resolve(__dirname, '../'), 17 | }, 18 | ], 19 | }, 20 | }; 21 | 22 | updateConfig(config); 23 | module.exports = config; 24 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to React Iframe Resizer Component 2 | 3 | We welcome your help to make this component better. This document will help to streamline the contributing process and save everyone's precious time. 4 | 5 | ## Development Setup 6 | 7 | This component has been setup with [React CDK](https://github.com/kadirahq/react-cdk). Refer [React CDK documentation](https://github.com/kadirahq/react-cdk)) to get started with the development. 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Your Name. 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Iframe Resizer With Super-Powers (cross domain, resize, etc) 2 | 3 | This is a versatile [React](https://facebook.github.io/react/) Component 4 | which renders an iframe and wires in the excellent 5 | [Iframe Resizer](http://davidjbradshaw.github.io/iframe-resizer/) library. 6 | 7 | 8 | This Component was created with the 9 | [React CDK](https://github.com/kadirahq/react-cdk) 10 | by the great folks at [Kadira](https://github.com/kadirahq). 11 | 12 | NOTE: Renamed to `react-iframe-resizer-super` because there is already a `react-iframe-resier` npm package. 13 | 14 | ## Installation 15 | ```sh 16 | npm install --save react-iframe-resizer-super iframe-resizer 17 | ``` 18 | 19 | ## Usage 20 | 21 | ```jsx 22 | import ReactIframeResizer from 'react-iframe-resizer-super'; 23 | 24 | 25 | const iframeResizerOptions = { checkOrigin: false }; 26 | 27 | const MyComponent = props => ( 28 |
29 |

Content Before Iframe (style unaffected by iframe)

30 | 31 | 32 |

Here is some green text, inside an iframe

33 |
34 |

Content After Iframe (style unaffected by iframe)

35 |
36 | ); 37 | ``` 38 | 39 | ### Props supported 40 | 41 | - `content` (string) iframe document option 1. - content of HTML to load in the iframe 42 | - `src` (string) iframe document option 2. - src to a URL to load in the iframe 43 | - `iframeResizerEnable` (bool) [true] 44 | - `iframeResizerOptions` (object) see all supported 45 | [iframe-resizer](http://davidjbradshaw.github.io/iframe-resizer/) options. 46 | - `iframeResizerUrl` (string || bool) URL to the client JS for injecting into the 47 | iframe. This only works for `content` type, at the moment. The default URL 48 | is `https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/3.5.8/iframeResizer.contentWindow.min.js`. If you wanted to disable this, you could set it to {false} 49 | - `frameBorder` (number) [0] optionally set a frameBorder 50 | - `id` (string) optionally set an id property 51 | - `className` (string) optionally set a className property 52 | - `style` (object) optionally set a style property 53 | default `{ width: '100%', minHeight: 20 }` 54 | 55 | ## Examples 56 | 57 | See our stories/demos at 58 | [zeroasterisk.github.io/react-iframe-resizer-super](https://zeroasterisk.github.io/react-iframe-resizer-super) 59 | and the 60 | [source of the stories/demo](https://github.com/zeroasterisk/react-iframe-resizer-super/blob/master/src/stories/index.js). 61 | and of course, more about 62 | [iframe-resizer](http://davidjbradshaw.github.io/iframe-resizer/) 63 | which is where most of the iframe magic happens. 64 | 65 | ## Acknowledgements 66 | 67 | * [Iframe Resizer](http://davidjbradshaw.com/iframe-resizer/) library is 68 | excellent and deals well with crappy browsers. 69 | _(caution: do not try to roll your own)_ 70 | * [React CDK](https://github.com/kadirahq/react-cdk) makes react Components 71 | easy to create, document, test, and share. 72 | 73 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-iframe-resizer-super", 3 | "version": "0.2.0", 4 | "description": "React Iframe Resizer With Super-Powers (cross domain, resize, etc)", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/zeroasterisk/react-iframe-resizer-super.git" 8 | }, 9 | "license": "MIT", 10 | "scripts": { 11 | "prepublish": ". ./.scripts/prepublish.sh", 12 | "lint": "eslint src", 13 | "lintfix": "eslint src --fix", 14 | "testonly": "mocha --require .scripts/mocha_runner src/**/tests/**/*.js", 15 | "test": "npm run lint && npm run testonly", 16 | "test-watch": "npm run testonly -- --watch --watch-extensions js", 17 | "storybook": "start-storybook -p 9010", 18 | "publish-storybook": "bash .scripts/publish_storybook.sh" 19 | }, 20 | "devDependencies": { 21 | "@kadira/storybook": "^1.19.0", 22 | "babel-cli": "^6.5.0", 23 | "babel-core": "^6.5.0", 24 | "babel-eslint": "^6.0.2", 25 | "babel-loader": "^6.2.4", 26 | "babel-plugin-transform-runtime": "^6.5.0", 27 | "babel-polyfill": "^6.5.0", 28 | "babel-preset-es2015": "^6.5.0", 29 | "babel-preset-react": "^6.5.0", 30 | "babel-preset-stage-2": "^6.5.0", 31 | "chai": "^3.5.0", 32 | "enzyme": "^2.2.0", 33 | "eslint": "^2.7.0", 34 | "eslint-config-airbnb": "^7.0.0", 35 | "eslint-plugin-babel": "^3.2.0", 36 | "eslint-plugin-jsx-a11y": "^0.6.2", 37 | "eslint-plugin-react": "^4.3.0", 38 | "git-url-parse": "^6.0.1", 39 | "jsdom": "^8.3.1", 40 | "mocha": "^2.4.5", 41 | "prop-types": "^15.0.0", 42 | "raw-loader": "^0.5.1", 43 | "react": "^15.0.0", 44 | "react-addons-test-utils": "^15.0.0", 45 | "react-dom": "^15.0.0", 46 | "sinon": "^1.17.3", 47 | "style-loader": "^0.13.1" 48 | }, 49 | "peerDependencies": { 50 | "iframe-resizer": "^3.6.2", 51 | "react": "^0.14.7 || ^15.0.0 || ^16.0" 52 | }, 53 | "dependencies": { 54 | "babel-runtime": "^6.5.0" 55 | }, 56 | "main": "dist/index.js", 57 | "engines": { 58 | "npm": "^3.0.0" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * inject script to facilitate iframe resizing 4 | * https://github.com/davidjbradshaw/iframe-resizer 5 | * 6 | */ 7 | import React from 'react'; 8 | import PropTypes from 'prop-types'; 9 | import ReactDOM from 'react-dom'; 10 | import { iframeResizer as iframeResizerLib } from 'iframe-resizer'; 11 | 12 | class IframeResizer extends React.Component { 13 | componentDidMount() { 14 | // can't update until we have a mounted iframe 15 | this.updateIframe(this.props); 16 | this.resizeIframe(this.props); 17 | } 18 | componentWillUnmount() { 19 | // React will remove the iframe, however we need to manually 20 | // call iframe-resizer to stop its listeners 21 | const iframeResizer = this.refs.frame.iFrameResizer 22 | iframeResizer && iframeResizer.removeListeners(); 23 | } 24 | componentWillReceiveProps(nextProps) { 25 | // can replace content if we got new props 26 | this.updateIframe(nextProps); 27 | this.resizeIframe(nextProps); 28 | } 29 | updateIframe = (props) => { 30 | // has src - no injected content 31 | if (props.src) return; 32 | // do we have content to inject (content or children) 33 | const content = props.content || props.children; 34 | if (!content) return; 35 | // get frame to inject into 36 | const frame = this.refs.frame; 37 | if (!frame) return; 38 | // verify frame document access 39 | // Due to browser security, this will fail with the following error 40 | // Uncaught DOMException: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': 41 | // Blocked a frame with origin "http://" from accessing a cross-origin frame. 42 | // resolve this by loading documents from the same domain name, 43 | // or injecting HTML `content` vs. loading via `src` 44 | const doc = frame.contentDocument; 45 | if (!doc) return; 46 | // replace iframe document content 47 | if (typeof content === 'string') { 48 | // assume this is a HTML block 49 | // we could send this in via REACT dangerously set HTML 50 | // but we are in an iframe anyway, already a red-headed step-child. 51 | doc.open(); 52 | doc.write(content); 53 | doc.close(); 54 | } else { 55 | // assume this is a REACT component 56 | doc.open(); 57 | doc.write('
'); 58 | doc.close(); 59 | ReactDOM.render(content, doc.getElementById('iframe-root')) 60 | } 61 | } 62 | // inject the iframe resizer "content window" script 63 | injectIframeResizerUrl = () => { 64 | if (!this.props.iframeResizerUrl) return; 65 | const frame = this.refs.frame; 66 | if (!frame) return; 67 | // verify frame document access 68 | // Due to browser security, this will fail with the following error 69 | // Uncaught DOMException: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': 70 | // Blocked a frame with origin "http://" from accessing a cross-origin frame. 71 | // resolve this by loading documents from the same domain name, 72 | // or injecting HTML `content` vs. loading via `src` 73 | const doc = frame.contentDocument; 74 | if (!doc) return; 75 | // where can we insert into? (fail into whatever we can find) 76 | let injectTarget = null; 77 | ['head', 'HEAD', 'body', 'BODY', 'div', 'DIV'].forEach(tagName => { 78 | if (injectTarget) return; 79 | const found = doc.getElementsByTagName(tagName); 80 | if (!(found && found.length)) return; 81 | injectTarget = found[0]; 82 | }); 83 | if (!injectTarget) { 84 | console.error('Unable to inject iframe resizer script'); 85 | return; 86 | } 87 | const resizerScriptElement = document.createElement('script'); 88 | resizerScriptElement.type = 'text/javascript'; 89 | resizerScriptElement.src = this.props.iframeResizerUrl; 90 | injectTarget.appendChild(resizerScriptElement); 91 | } 92 | onLoad = () => { 93 | this.injectIframeResizerUrl(); 94 | // DISABLED because it's causing a loading loop :( 95 | // if (this.props.onIframeLoaded) this.props.onIframeLoaded(); 96 | } 97 | resizeIframe = (props) => { 98 | const frame = this.refs.frame; 99 | if (!frame) return; 100 | if (props.iframeResizerEnable) { 101 | iframeResizerLib(props.iframeResizerOptions, frame); 102 | } 103 | } 104 | render() { 105 | const { src, id, frameBorder, className, style } = this.props; 106 | return ( 107 |