diff --git a/build.json b/build.json new file mode 100644 index 0000000..d957ebb --- /dev/null +++ b/build.json @@ -0,0 +1,5 @@ +[ + "src/Parser.js", + "src/HTMLImports.js", + "src/boot.js" +] diff --git a/conf/karma.conf.js b/conf/karma.conf.js index a204c98..8cdb5af 100644 --- a/conf/karma.conf.js +++ b/conf/karma.conf.js @@ -1,88 +1,84 @@ -// Sample Karma configuration file, that contain pretty much all the available options -// It's used for running client tests on Travis (http://travis-ci.org/#!/karma-runner/karma) -// Most of the options can be overriden by cli arguments (see karma --help) -// -// For all available config options and default values, see: -// https://github.com/karma-runner/karma/blob/stable/lib/config.js#L54 - - -// base path, that will be used to resolve files and exclude -basePath = '../'; - -// list of files / patterns to load in the browser -files = [ - 'tools/test/mocha-htmltest.js', - 'conf/mocha.conf.js', - 'node_modules/chai/chai.js', - 'test/js/*.js', - 'html-imports.js', - {pattern: 'tools/**/*.js', included: false}, - {pattern: 'src/*', included: false}, - {pattern: 'test/**/*', included: false} -]; - -// list of files to exclude -exclude = []; - -frameworks = ['mocha']; - -// use dots reporter, as travis terminal does not support escaping sequences -// possible values: 'dots', 'progress', 'junit', 'teamcity' -// CLI --reporters progress -reporters = ['progress']; - -// web server port -// CLI --port 9876 -port = 9876; - -// cli runner port -// CLI --runner-port 9100 -runnerPort = 9100; - -// enable / disable colors in the output (reporters and logs) -// CLI --colors --no-colors -colors = true; - -// level of logging -// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG -// CLI --log-level debug -logLevel = LOG_INFO; - -// enable / disable watching file and executing tests whenever any file changes -// CLI --auto-watch --no-auto-watch -autoWatch = true; - -// Start these browsers, currently available: -// - Chrome -// - ChromeCanary -// - Firefox -// - Opera -// - Safari (only Mac) -// - PhantomJS -// - IE (only Windows) -// CLI --browsers Chrome,Firefox,Safari -browsers = ['ChromeCanary']; - -// If browser does not capture in given timeout [ms], kill it -// CLI --capture-timeout 5000 -captureTimeout = 50000; - -// Auto run tests on start (when browsers are captured) and exit -// CLI --single-run --no-single-run -singleRun = true; - -// report which specs are slower than 500ms -// CLI --report-slower-than 500 -reportSlowerThan = 500; - -// compile coffee scripts -preprocessors = { +module.exports = function(karma) { + karma.configure({ + // base path, that will be used to resolve files and exclude + basePath: '../', + + // list of files / patterns to load in the browser + files: [ + 'tools/test/mocha-htmltest.js', + 'conf/mocha.conf.js', + 'node_modules/chai/chai.js', + 'test/js/*.js', + 'html-imports.js', + {pattern: 'tools/**/*.js', included: false}, + {pattern: 'src/*', included: false}, + {pattern: 'test/**/*', included: false} + ], + + // list of files to exclude + exclude: [], + + frameworks: ['mocha'], + + // use dots reporter, as travis terminal does not support escaping sequences + // possible values: 'dots', 'progress', 'junit', 'teamcity' + // CLI --reporters progress + reporters: ['progress'], + + // web server port + // CLI --port 9876 + port: 9876, + + // cli runner port + // CLI --runner-port 9100 + runnerPort: 9100, + + // enable / disable colors in the output (reporters and logs) + // CLI --colors --no-colors + colors: true, + + // level of logging + // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG + // CLI --log-level debug + logLevel: LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + // CLI --auto-watch --no-auto-watch + autoWatch: true, + + // Start these browsers, currently available: + // - Chrome + // - ChromeCanary + // - Firefox + // - Opera + // - Safari (only Mac) + // - PhantomJS + // - IE (only Windows) + // CLI --browsers Chrome,Firefox,Safari + browsers: ['ChromeCanary'], + + // If browser does not capture in given timeout [ms], kill it + // CLI --capture-timeout 5000 + captureTimeout: 50000, + + // Auto run tests on start (when browsers are captured) and exit + // CLI --single-run --no-single-run + singleRun: true, + + // report which specs are slower than 500ms + // CLI --report-slower-than 500 + reportSlowerThan: 500, + + // compile coffee scripts + preprocessors: { + }, + + plugins: [ + 'karma-mocha', + 'karma-chrome-launcher', + 'karma-firefox-launcher', + 'karma-script-launcher', + 'karma-crbot-reporter' + ] + }); }; - -plugins = [ - 'karma-mocha', - 'karma-chrome-launcher', - 'karma-firefox-launcher', - 'karma-script-launcher', - 'karma-crbot-reporter' -] diff --git a/gruntfile.js b/gruntfile.js index 45668fa..f1e9236 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -4,9 +4,7 @@ * license that can be found in the LICENSE file. */ module.exports = function(grunt) { - HTMLComponents = [ - 'src/HTMLImports.js' - ]; + HTMLComponents = grunt.file.readJSON('build.json'); // karma setup var browsers; (function() { @@ -44,11 +42,10 @@ module.exports = function(grunt) { }, uglify: { HTMLComponents: { - /* options: { - sourceMap: 'html-components.min.source-map.js' + sourceMap: 'html-components.min.source-map.js', + banner: grunt.file.read('LICENSE') }, - */ files: { 'html-imports.min.js': HTMLComponents } @@ -76,7 +73,7 @@ module.exports = function(grunt) { // plugins grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-yuidoc'); - grunt.loadNpmTasks('grunt-karma-0.9.1'); + grunt.loadNpmTasks('grunt-karma'); // tasks grunt.registerTask('default', ['uglify']); diff --git a/package.json b/package.json index 6a523d4..6240e88 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "grunt": "*", "grunt-contrib-uglify": "*", "grunt-contrib-yuidoc": "~0.4.0", - "grunt-karma-0.9.1": "~0.4.3", + "grunt-karma": "~0.5.0", "karma-mocha": "*", "karma-script-launcher": "*", "karma-crbot-reporter": "*" diff --git a/src/HTMLImports.js b/src/HTMLImports.js index 5c9c418..db0239d 100644 --- a/src/HTMLImports.js +++ b/src/HTMLImports.js @@ -43,7 +43,8 @@ var importer = { 'link[rel=' + IMPORT_LINK_TYPE + ']', 'element link[rel=' + STYLE_LINK_TYPE + ']', 'template', - 'script[src]' + 'script[src]:not([type])', + 'script[src][type="text/javascript"]' ].join(','), loader: function(inNext) { // construct a loader instance @@ -82,10 +83,10 @@ var importer = { nodes = Array.prototype.filter.call(nodes, function(n) { if (n.localName === 'template') { if (n.content) { - var l$ = n.content.querySelectorAll('link[rel=' + STYLE_LINK_TYPE + + var l$ = n.content.querySelectorAll('link[rel=' + STYLE_LINK_TYPE + ']'); if (l$.length) { - extra = extra.concat(Array.prototype.slice.call(l$, 0)); + extra = extra.concat(Array.prototype.slice.call(l$, 0)); } } return false; @@ -105,7 +106,7 @@ var importer = { // generate an HTMLDocument from data document = makeDocument(resource, url); // resolve resource paths relative to host document - path.resolvePathsInHTML(document.body); + path.resolvePathsInHTML(document); // cache document importer.documents[url] = document; // add nodes from this document to the loader queue @@ -147,17 +148,20 @@ function isScript(elt) { return elt.localName === 'script'; } -function makeDocument(inHTML, inUrl) { +function makeDocument(resource, url) { // create a new HTML document - var doc = document.implementation.createHTMLDocument(IMPORT_LINK_TYPE); + var doc = resource; + if (!(doc instanceof Document)) { + doc = document.implementation.createHTMLDocument(IMPORT_LINK_TYPE); + // install html + doc.body.innerHTML = resource; + } // cache the new document's source url - doc._URL = inUrl; + doc._URL = url; // establish a relative path via var base = doc.createElement('base'); base.setAttribute('href', document.baseURI); doc.head.appendChild(base); - // install html - doc.body.innerHTML = inHTML; // TODO(sorvell): MDV Polyfill intrusion: boostrap template polyfill if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) { HTMLTemplateElement.bootstrap(doc); @@ -219,6 +223,19 @@ Loader.prototype = { this.receive(url, elt, err, resource); }.bind(this); xhr.load(url, receiveXhr); + // TODO(sorvell): blocked on + // https://code.google.com/p/chromium/issues/detail?id=257221 + // xhr'ing for a document makes scripts in imports runnable; otherwise + // they are not; however, it requires that we have doctype=html in + // the import which is unacceptable. This is only needed on Chrome + // to avoid the bug above. + /* + if (isDocumentLink(elt)) { + xhr.loadDocument(url, receiveXhr); + } else { + xhr.load(url, receiveXhr); + } + */ }, receive: function(inUrl, inElt, inErr, inResource) { if (!inErr) { @@ -255,7 +272,7 @@ var path = { return inNode.getAttribute("href") || inNode.getAttribute("src"); }, documentUrlFromNode: function(inNode) { - return path.getDocumentUrl(inNode.ownerDocument); + return path.getDocumentUrl(inNode.ownerDocument || inNode); }, getDocumentUrl: function(inDocument) { var url = inDocument && @@ -386,6 +403,10 @@ xhr = xhr || { } }); request.send(); + return request; + }, + loadDocument: function(url, next, nextContext) { + this.load(url, next, nextContext).responseType = 'document'; } }; @@ -393,6 +414,7 @@ var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); // exports +scope.path = path; scope.xhr = xhr; scope.importer = importer; scope.getDocumentUrl = path.getDocumentUrl; diff --git a/src/Parser.js b/src/Parser.js index 07700df..2f00e05 100644 --- a/src/Parser.js +++ b/src/Parser.js @@ -15,7 +15,8 @@ var importParser = { 'link[rel=' + IMPORT_LINK_TYPE + ']', 'link[rel=stylesheet]', 'style', - 'script' + 'script:not([type])', + 'script[type="text/javascript"]' ], map: { link: 'parseLink', @@ -50,10 +51,25 @@ var importParser = { }, parseScript: function(scriptElt) { if (needsMainDocumentContext(scriptElt)) { - // evaluate now - var code = scriptElt.__resource || scriptElt.textContent; + // acquire code to execute + var code = (scriptElt.__resource || scriptElt.textContent).trim(); if (code) { - code += "\n//# sourceURL=" + (scriptElt.__nodeUrl || ('inline' + '[' + Math.floor((Math.random()+1)*1000) + ']')) + "\n"; + // calculate source map hint + var moniker = scriptElt.__nodeUrl; + if (!moniker) { + var moniker = scope.path.documentUrlFromNode(scriptElt); + // there could be more than one script this url + var tag = '[' + Math.floor((Math.random()+1)*1000) + ']'; + // TODO(sjmiles): Polymer hack, should be pluggable if we need to allow + // this sort of thing + var matches = code.match(/Polymer\(['"]([^'"]*)/); + tag = matches && matches[1] || tag; + // tag the moniker + moniker += '/' + tag + '.js'; + } + // source map hint + code += "\n//# sourceURL=" + moniker + "\n"; + // evaluate the code eval.call(window, code); } } @@ -62,9 +78,9 @@ var importParser = { var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); -function isDocumentLink(inElt) { - return inElt.localName === 'link' - && inElt.getAttribute('rel') === IMPORT_LINK_TYPE; +function isDocumentLink(elt) { + return elt.localName === 'link' + && elt.getAttribute('rel') === IMPORT_LINK_TYPE; } function needsMainDocumentContext(node) { @@ -74,14 +90,14 @@ function needsMainDocumentContext(node) { && !isElementElementChild(node); } -function inMainDocument(inElt) { - return inElt.ownerDocument === document || +function inMainDocument(elt) { + return elt.ownerDocument === document || // TODO(sjmiles): ShadowDOMPolyfill intrusion - inElt.ownerDocument.impl === document; + elt.ownerDocument.impl === document; } -function isElementElementChild(inElt) { - return inElt.parentNode && inElt.parentNode.localName === 'element'; +function isElementElementChild(elt) { + return elt.parentNode && elt.parentNode.localName === 'element'; } // exports diff --git a/src/boot.js b/src/boot.js index 4468524..3ec4897 100644 --- a/src/boot.js +++ b/src/boot.js @@ -28,7 +28,7 @@ function bootstrap() { }); }; -if (document.readyState === 'complete' || document.readyState === 'interactive') { +if (document.readyState === 'complete') { bootstrap(); } else { window.addEventListener('DOMContentLoaded', bootstrap); diff --git a/test/html/imports/template-import.html b/test/html/imports/template-import.html new file mode 100644 index 0000000..9f34e4e --- /dev/null +++ b/test/html/imports/template-import.html @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/test/html/template-script.html b/test/html/template-script.html new file mode 100644 index 0000000..cbb7954 --- /dev/null +++ b/test/html/template-script.html @@ -0,0 +1,23 @@ + + + + template script test + + + + + + + + +