├── .gitignore ├── .jshintrc ├── .travis.yml ├── Gruntfile.js ├── LICENSE-MIT ├── bower.json ├── package.json ├── readme.md ├── srcdoc-polyfill.js ├── srcdoc-polyfill.min.js └── test ├── .jshintrc ├── cjs-src.js ├── index.html ├── lib └── jquery-1.7.2.js ├── load-source.js └── tests.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | test/cjs-built.js 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": true, 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "boss": true, 11 | "eqnull": true, 12 | "browser": true, 13 | "scripturl": true, 14 | "globals": { 15 | "define": false, 16 | "exports": false 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.12" 4 | before_install: 5 | - npm install -g grunt-cli 6 | sudo: false 7 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global module:false*/ 2 | module.exports = function(grunt) { 3 | 4 | // Project configuration. 5 | grunt.initConfig({ 6 | meta: { 7 | pkg: grunt.file.readJSON("package.json") 8 | }, 9 | jshint: { 10 | build: { 11 | src: ["Gruntfile.js"], 12 | options: { 13 | jshintrc: ".jshintrc" 14 | } 15 | }, 16 | source: { 17 | src: ["srcdoc-polyfill.js"], 18 | options: { 19 | jshintrc: ".jshintrc" 20 | } 21 | }, 22 | test: { 23 | src: ["test/*.js", "!test/cjs-built.js"], 24 | options: { 25 | jshintrc: "test/.jshintrc" 26 | } 27 | } 28 | }, 29 | browserify: { 30 | test: { 31 | files: { 32 | "test/cjs-built.js": ["test/cjs-src.js"] 33 | } 34 | } 35 | }, 36 | connect: { 37 | server: { 38 | options: { 39 | port: 8023, 40 | base: "." 41 | } 42 | } 43 | }, 44 | qunit: { 45 | options: { 46 | console: false 47 | }, 48 | moduleFmtGlobal: { 49 | options: { 50 | urls: [ 51 | "http://localhost:8023/test/index.html?moduleFmt=global" 52 | ] 53 | } 54 | }, 55 | moduleFmtAmd: { 56 | options: { 57 | urls: [ 58 | "http://localhost:8023/test/index.html?moduleFmt=amdModule", 59 | "http://localhost:8023/test/index.html?moduleFmt=amdGlobal" 60 | ] 61 | } 62 | }, 63 | moduleFmtCjs: { 64 | options: { 65 | urls: [ 66 | "http://localhost:8023/test/index.html?moduleFmt=cjs" 67 | ] 68 | } 69 | } 70 | }, 71 | uglify: { 72 | options: { 73 | banner: "/*! srcdoc-polyfill - v<%= meta.pkg.version %> - " + 74 | "<%= grunt.template.today('yyyy-mm-dd') %>\n" + 75 | "* http://github.com/jugglinmike/srcdoc-polyfill/\n" + 76 | "* Copyright (c) <%= grunt.template.today('yyyy') %> " + 77 | "<%= meta.pkg.author %>; Licensed <%= meta.pkg.license %> */\n" 78 | }, 79 | dist: { 80 | files: { 81 | "srcdoc-polyfill.min.js": "srcdoc-polyfill.js" 82 | } 83 | } 84 | }, 85 | watch: { 86 | files: "", 87 | tasks: "lint qunit" 88 | } 89 | }); 90 | 91 | grunt.loadNpmTasks("grunt-browserify"); 92 | grunt.loadNpmTasks("grunt-contrib-jshint"); 93 | grunt.loadNpmTasks("grunt-contrib-connect"); 94 | grunt.loadNpmTasks("grunt-contrib-qunit"); 95 | grunt.loadNpmTasks("grunt-contrib-uglify"); 96 | 97 | grunt.registerTask("test", ["jshint", "browserify", "connect", "qunit"]); 98 | // Default task. 99 | grunt.registerTask("default", ["test", "uglify"]); 100 | 101 | }; 102 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Mike Pennisi 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "srcdoc-polyfill", 3 | "main": "srcdoc-polyfill.js", 4 | "version": "1.0.0", 5 | "homepage": "https://github.com/jugglinmike/srcdoc-polyfill", 6 | "authors": [ 7 | "Mike Pennisi " 8 | ], 9 | "description": "A shim for the iFrame \"srcdoc\" attribute", 10 | "keywords": [ 11 | "srcdoc", 12 | "html5", 13 | "polyfill" 14 | ], 15 | "license": "MIT", 16 | "ignore": [ 17 | "**/.*", 18 | "node_modules", 19 | "bower_components", 20 | "test" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "srcdoc-polyfill", 3 | "version": "1.0.0", 4 | "description": "A shim for the iFrame \"srcdoc\" attribute", 5 | "main": "srcdoc-polyfill.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "grunt test" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/jugglinmike/srcdoc-polyfill.git" 15 | }, 16 | "keywords": [ 17 | "html5", 18 | "polyfill", 19 | "iframe" 20 | ], 21 | "author": "Mike Pennisi", 22 | "license": "MIT", 23 | "devDependencies": { 24 | "grunt": "~0.4.0", 25 | "grunt-browserify": "~4.0.1", 26 | "grunt-contrib-connect": "~0.11.2", 27 | "grunt-contrib-jshint": "~0.11.3", 28 | "grunt-contrib-qunit": "~1.2.0", 29 | "grunt-contrib-uglify": "~0.9.2", 30 | "qunitjs": "~1.19.0", 31 | "requirejs": "~2.1.20" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # `srcdoc` polyfill [![Build Status](https://travis-ci.org/jugglinmike/srcdoc-polyfill.svg)](https://travis-ci.org/jugglinmike/srcdoc-polyfill) 2 | 3 | HTML5 defines a new attribute for iFrames named `srcdoc`. This attribute allows 4 | developers to specify an iFrame's content in-line with the iFrame itself. For 5 | instance: 6 | 7 | 8 | 9 | This feature only began to see adoption in major browsers in early 2013. 10 | Fortunately, most older browsers support similar functionality through 11 | script-targeted URLs, i.e. 12 | 13 | 14 | 15 | (Because of limitations on URL length, the actual mechanism that the polyfill 16 | implements not quite this direct.) 17 | 18 | For more on `srcdoc`, see [the WhatWG specification](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#attr-iframe-srcdoc) and [this post on 19 | Bocoup.com](http://weblog.bocoup.com/third-party-javascript-development-future/). 20 | 21 | ## Usage 22 | 23 | By including the script at the bottom of the document ``, any available 24 | iFrames which declare a `srcdoc` attribute attribute) will receive this 25 | "shimmed" behavior. (In browsers that already implement this functionality, no 26 | change will take place.) 27 | 28 | **Note on [the HTML5 `sandbox` 29 | attribute](https://html.spec.whatwg.org/multipage/embedded-content.html#attr-iframe-sandbox):** 30 | Because the shim operates using a script-targeted URL in legacy environments, 31 | some configurations of the `sandbox` attribute may interfere with its behavior. 32 | This issue will only surface in environments that implement `sandbox` but that 33 | do *not* implement `srcdoc`. Because of this, this polyfill's default behavior 34 | is to issue a warning for potentially-hazardous configurations but to proceed 35 | optimistically. The API supports an `force` option that enables modification of 36 | this behavior. 37 | 38 | ## Executing 39 | 40 | This script may be consumed as a AMD module, a CommonJS module, or standalone 41 | via direct inclusion with a ` 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |

Module Formats

20 | 26 |
27 | 28 |
29 | 30 | 31 | 32 | 33 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/load-source.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file - Test utility to facilitate loading different builds of the source 3 | * code depending on the URL used to access the document. 4 | */ 5 | (function(window) { 6 | "use strict"; 7 | var sources = { 8 | global: { 9 | prereqs: ["../srcdoc-polyfill.js"], 10 | setup: function(done) { 11 | done(); 12 | } 13 | }, 14 | // Ensure that the global variable is defined even in AMD-supporting 15 | // environments. 16 | amdGlobal: { 17 | prereqs: ["../node_modules/requirejs/require.js"], 18 | setup: function(done) { 19 | require(["../srcdoc-polyfill"], function(srcDoc) { 20 | done(); 21 | }); 22 | } 23 | }, 24 | amdModule: { 25 | prereqs: ["../node_modules/requirejs/require.js"], 26 | setup: function(done) { 27 | require(["../srcdoc-polyfill"], function(srcDoc) { 28 | window.srcDoc = srcDoc; 29 | done(); 30 | }); 31 | } 32 | }, 33 | cjs: { 34 | prereqs: ["cjs-built.js"], 35 | setup: function(done) { 36 | done(); 37 | } 38 | } 39 | }; 40 | 41 | function loadScript(script, done) { 42 | var el = document.createElement("script"); 43 | el.src = script; 44 | 45 | if (el.addEventListener) { 46 | el.addEventListener("load", done); 47 | } else { 48 | el.onreadystatechange = function() { 49 | if ( done && (!this.readyState || 50 | this.readyState === "loaded" || this.readyState === "complete") ) { 51 | done(); 52 | done = null; 53 | } 54 | }; 55 | } 56 | 57 | document.getElementsByTagName('head')[0].appendChild(el); 58 | } 59 | 60 | function loadScripts(scripts, done) { 61 | if (scripts.length === 0) { 62 | setTimeout(done, 0); 63 | return; 64 | } 65 | loadScript(scripts.shift(), function() { 66 | loadScripts(scripts, done); 67 | }); 68 | } 69 | 70 | function getSource(search) { 71 | var params = search.slice(1).split("&"); 72 | var sourceName = "global"; 73 | var idx, length, parts; 74 | 75 | for (idx = 0, length = params.length; idx < length; ++idx) { 76 | parts = params[idx].split("="); 77 | if (parts[0] === "moduleFmt") { 78 | sourceName = parts[1]; 79 | } 80 | } 81 | return sourceName; 82 | } 83 | 84 | window.loadSource = function(location, done) { 85 | var source = sources[getSource(location.search)]; 86 | loadScripts(source.prereqs, function() { 87 | source.setup(done); 88 | }); 89 | }; 90 | }(this)); 91 | -------------------------------------------------------------------------------- /test/tests.js: -------------------------------------------------------------------------------- 1 | // createDocument 2 | // Create a new document within an iFrame that contains: 3 | // 1) an iFrame declaring some combination of `src` and `srcdoc` 4 | // 2) the polyfill itself 5 | // Used to test automatic shimming functionality 6 | function createDocument( iframe, insertions ) { 7 | var doc = iframe.contentWindow.document; 8 | var html = "" + 9 | ""; 10 | 11 | if (insertions.srcdoc) { 12 | html = html.replace(/iframe/, "iframe srcdoc=\"" + insertions.srcdoc + "\""); 13 | } 14 | 15 | if (insertions.src) { 16 | html = html.replace(/iframe/, "iframe src=\"" + insertions.src + "\""); 17 | } 18 | 19 | doc.open(); 20 | 21 | doc.write(html); 22 | 23 | doc.close(); 24 | } 25 | 26 | QUnit.module("srcDoc.noConflict()", { 27 | teardown: function() { 28 | // Restore srcDoc to the global 29 | window.srcDoc = this._srcDoc; 30 | 31 | // Remove the global reference 32 | delete this._srcDoc; 33 | } 34 | }); 35 | 36 | QUnit.test("will restore original value", 3, function(assert) { 37 | 38 | var preNoConflict = srcDoc; 39 | 40 | assert.equal(typeof window.srcDoc, "object", 41 | "srcDoc has been overwritten to an object"); 42 | 43 | // Restore to old srcDoc, and keep a copy of srcDoc in window._srcDoc 44 | this._srcDoc = window.srcDoc.noConflict(); 45 | 46 | assert.equal(window.srcDoc, "old", "srcDoc has been restored to the old value"); 47 | assert.equal(this._srcDoc, preNoConflict, "Returns a reference to the API"); 48 | }); 49 | 50 | QUnit.module("srcDoc.set()", { 51 | setup: function() { 52 | this.$harness = $("