diff --git a/html-imports.js b/html-imports.js index 2477ffb..9c97b9c 100644 --- a/html-imports.js +++ b/html-imports.js @@ -11,6 +11,7 @@ var scopeName = 'HTMLImports'; var modules = [ 'src/scope.js', 'src/path.js', + 'src/Loader.js', 'src/HTMLImports.js', 'src/Parser.js', 'src/boot.js' diff --git a/src/HTMLImports.js b/src/HTMLImports.js index ff086ca..d093a90 100644 --- a/src/HTMLImports.js +++ b/src/HTMLImports.js @@ -13,6 +13,7 @@ if (!useNative) { // imports var path = scope.path; + var Loader = scope.Loader; var xhr = scope.xhr; // importer @@ -33,7 +34,7 @@ if (!useNative) { // linked style sheets in an are loaded, and the content gets path fixups // inline style sheets get path fixups when their containing import modifies paths - var loader; + var importLoader; var IMPORT_LINK_TYPE = 'import'; var STYLE_LINK_TYPE = 'stylesheet'; @@ -47,30 +48,30 @@ if (!useNative) { 'script[src][type="text/javascript"]' ].join(','), loader: function(next) { - if (loader && loader.inflight) { - var currentComplete = loader.oncomplete; - loader.oncomplete = function() { + if (importLoader && importLoader.inflight) { + var currentComplete = importLoader.oncomplete; + importLoader.oncomplete = function() { currentComplete(); next(); } - return loader; + return importLoader; } // construct a loader instance - loader = new Loader(importer.loaded, next); + importLoader = new Loader(importer.loaded, next); // alias the importer cache (for debugging) - loader.cache = importer.cache; - return loader; + importLoader.cache = importer.cache; + return importLoader; }, load: function(doc, next) { // get a loader instance from the factory - loader = importer.loader(next); + importLoader = importer.loader(next); // add nodes from document into loader queue importer.preload(doc); }, preload: function(doc) { var nodes = this.marshalNodes(doc); // add these nodes to loader's queue - loader.addNodes(nodes); + importLoader.addNodes(nodes); }, marshalNodes: function(doc) { // all preloadable nodes in inDocument @@ -188,178 +189,13 @@ if (!useNative) { return doc; } - var Loader = function(onLoad, onComplete) { - this.onload = onLoad; - this.oncomplete = onComplete; - this.inflight = 0; - this.pending = {}; - this.cache = {}; - }; - - Loader.prototype = { - addNodes: function(nodes) { - // number of transactions to complete - this.inflight += nodes.length; - // commence transactions - forEach(nodes, this.require, this); - // anything to do? - this.checkDone(); - }, - require: function(elt) { - var url = path.nodeUrl(elt); - // ensure we have a standard url that can be used - // reliably for deduping. - url = path.makeAbsUrl(url); - // TODO(sjmiles): ad-hoc - elt.__nodeUrl = url; - // deduplication - if (!this.dedupe(url, elt)) { - // fetch this resource - this.fetch(url, elt); - } - }, - dedupe: function(url, elt) { - if (this.pending[url]) { - // add to list of nodes waiting for inUrl - this.pending[url].push(elt); - // don't need fetch - return true; - } - if (this.cache[url]) { - // complete load using cache data - this.onload(url, elt, loader.cache[url]); - // finished this transaction - this.tail(); - // don't need fetch - return true; - } - // first node waiting for inUrl - this.pending[url] = [elt]; - // need fetch (not a dupe) - return false; - }, - fetch: function(url, elt) { - var receiveXhr = function(err, resource) { - 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(url, elt, err, resource) { - if (!err) { - loader.cache[url] = resource; - } - loader.pending[url].forEach(function(e) { - if (!err) { - this.onload(url, e, resource); - } - this.tail(); - }, this); - loader.pending[url] = null; - }, - tail: function() { - --this.inflight; - this.checkDone(); - }, - checkDone: function() { - if (!this.inflight) { - this.oncomplete(); - } - } - }; - - xhr = xhr || { - async: true, - ok: function(request) { - return (request.status >= 200 && request.status < 300) - || (request.status === 304) - || (request.status === 0); - }, - load: function(url, next, nextContext) { - var request = new XMLHttpRequest(); - if (scope.flags.debug || scope.flags.bust) { - url += '?' + Math.random(); - } - request.open('GET', url, xhr.async); - request.addEventListener('readystatechange', function(e) { - if (request.readyState === 4) { - next.call(nextContext, !xhr.ok(request) && request, - request.response || request.responseText, url); - } - }); - request.send(); - return request; - }, - loadDocument: function(url, next, nextContext) { - this.load(url, next, nextContext).responseType = 'document'; - } - }; - var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); // exports - scope.xhr = xhr; scope.importer = importer; scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE; } else { // do nothing if using native imports - /* - // TODO(sorvell): this exists as a load extension point. - importer.preloadSelectors = [ - 'template' - ].join(','); - - function forEachImport(imp, cb) { - if (cb) { - cb(imp); - } - var n$ = imp.querySelectorAll('link[rel=' + IMPORT_LINK_TYPE + ']'); - for (var i=0, l=n$.length, n; (i= 200 && request.status < 300) + || (request.status === 304) + || (request.status === 0); + }, + load: function(url, next, nextContext) { + var request = new XMLHttpRequest(); + if (scope.flags.debug || scope.flags.bust) { + url += '?' + Math.random(); + } + request.open('GET', url, xhr.async); + request.addEventListener('readystatechange', function(e) { + if (request.readyState === 4) { + next.call(nextContext, !xhr.ok(request) && request, + request.response || request.responseText, url); + } + }); + request.send(); + return request; + }, + loadDocument: function(url, next, nextContext) { + this.load(url, next, nextContext).responseType = 'document'; + } + }; + + var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); + + // exports + scope.xhr = xhr; + scope.Loader = Loader; + +})(window.HTMLImports); diff --git a/src/boot.js b/src/boot.js index 7d12744..c2dbd15 100644 --- a/src/boot.js +++ b/src/boot.js @@ -35,7 +35,7 @@ function notifyReady() { } if (HTMLImports.useNative) { - notifyReady(); + //notifyReady(); } else { function bootstrap() { // preload document resource trees @@ -56,6 +56,10 @@ if (HTMLImports.useNative) { } else { window.addEventListener('DOMContentLoaded', bootstrap); } + + HTMLImports.whenImportsReady(function() { + notifyReady(); + }); } })();