Skip to content
This repository has been archived by the owner on Mar 13, 2018. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
sorvell committed Aug 28, 2014
1 parent e1bb8e8 commit 0d443fe
Show file tree
Hide file tree
Showing 3 changed files with 232 additions and 173 deletions.
367 changes: 194 additions & 173 deletions src/base.js
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,173 +1,194 @@
/*
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/(function(scope) {

var hasNative = ('import' in document.createElement('link'));
var useNative = hasNative;

isIE = /Trident/.test(navigator.userAgent);

// TODO(sorvell): SD polyfill intrusion
var hasShadowDOMPolyfill = Boolean(window.ShadowDOMPolyfill);
var wrap = function(node) {
return hasShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node) : node;
};
var mainDoc = wrap(document);

// NOTE: We cannot polyfill document.currentScript because it's not possible
// both to override and maintain the ability to capture the native value;
// therefore we choose to expose _currentScript both when native imports
// and the polyfill are in use.
var currentScriptDescriptor = {
get: function() {
var script = HTMLImports.currentScript || document.currentScript ||
// NOTE: only works when called in synchronously executing code.
// readyState should check if `loading` but IE10 is
// interactive when scripts run so we cheat.
(document.readyState !== 'complete' ?
document.scripts[document.scripts.length - 1] : null);
return wrap(script);
},
configurable: true
};

Object.defineProperty(document, '_currentScript', currentScriptDescriptor);
Object.defineProperty(mainDoc, '_currentScript', currentScriptDescriptor);

// call a callback when all HTMLImports in the document at call (or at least
// document ready) time have loaded.
// 1. ensure the document is in a ready state (has dom), then
// 2. watch for loading of imports and call callback when done
function whenImportsReady(callback, doc) {
doc = doc || mainDoc;
// if document is loading, wait and try again
whenDocumentReady(function() {
watchImportsLoad(callback, doc);
}, doc);
}

// call the callback when the document is in a ready state (has dom)
var requiredReadyState = isIE ? 'complete' : 'interactive';
var READY_EVENT = 'readystatechange';
function isDocumentReady(doc) {
return (doc.readyState === 'complete' ||
doc.readyState === requiredReadyState);
}

// call <callback> when we ensure the document is in a ready state
function whenDocumentReady(callback, doc) {
if (!isDocumentReady(doc)) {
var checkReady = function() {
if (doc.readyState === 'complete' ||
doc.readyState === requiredReadyState) {
doc.removeEventListener(READY_EVENT, checkReady);
whenDocumentReady(callback, doc);
}
};
doc.addEventListener(READY_EVENT, checkReady);
} else if (callback) {
callback();
}
}

function markTargetLoaded(event) {
event.target.__loaded = true;
}

// call <callback> when we ensure all imports have loaded
function watchImportsLoad(callback, doc) {
var imports = doc.querySelectorAll('link[rel=import]');
var loaded = 0, l = imports.length;
function checkDone(d) {
if (loaded == l) {
callback && callback();
}
}
function loadedImport(e) {
markTargetLoaded(e);
loaded++;
checkDone();
}
if (l) {
for (var i=0, imp; (i<l) && (imp=imports[i]); i++) {
if (isImportLoaded(imp)) {
loadedImport.call(imp, {target: imp});
} else {
imp.addEventListener('load', loadedImport);
imp.addEventListener('error', loadedImport);
}
}
} else {
checkDone();
}
}

// NOTE: test for native imports loading is based on explicitly watching
// all imports (see below).
function isImportLoaded(link) {
return useNative ? link.__loaded : link.__importParsed;
}

// TODO(sorvell): install a mutation observer to see if HTMLImports have loaded
// this is a workaround for https://www.w3.org/Bugs/Public/show_bug.cgi?id=25007
// and should be removed when this bug is addressed.
if (useNative) {
new MutationObserver(function(mxns) {
for (var i=0, l=mxns.length, m; (i < l) && (m=mxns[i]); i++) {
if (m.addedNodes) {
handleImports(m.addedNodes);
}
}
}).observe(document.head, {childList: true});

function handleImports(nodes) {
for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) {
if (isImport(n)) {
handleImport(n);
}
}
}

function isImport(element) {
return element.localName === 'link' && element.rel === 'import';
}

function handleImport(element) {
var loaded = element.import;
if (loaded) {
markTargetLoaded({target: element});
} else {
element.addEventListener('load', markTargetLoaded);
element.addEventListener('error', markTargetLoaded);
}
}

}

// Fire the 'HTMLImportsLoaded' event when imports in document at load time
// have loaded. This event is required to simulate the script blocking
// behavior of native imports. A main document script that needs to be sure
// imports have loaded should wait for this event.
whenImportsReady(function() {
HTMLImports.ready = true;
HTMLImports.readyTime = new Date().getTime();
mainDoc.dispatchEvent(
new CustomEvent('HTMLImportsLoaded', {bubbles: true})
);
});

// exports
scope.useNative = useNative;
scope.isImportLoaded = isImportLoaded;
scope.whenReady = whenImportsReady;
scope.isIE = isIE;

// deprecated
scope.whenImportsReady = whenImportsReady;

})(window.HTMLImports);
/*
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

(function(scope) {

var hasNative = ('import' in document.createElement('link'));
var useNative = hasNative;

isIE = /Trident/.test(navigator.userAgent);

// TODO(sorvell): SD polyfill intrusion
var hasShadowDOMPolyfill = Boolean(window.ShadowDOMPolyfill);
var wrap = function(node) {
return hasShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node) : node;
};
var mainDoc = wrap(document);

// NOTE: We cannot polyfill document.currentScript because it's not possible
// both to override and maintain the ability to capture the native value;
// therefore we choose to expose _currentScript both when native imports
// and the polyfill are in use.
var currentScriptDescriptor = {
get: function() {
var script = HTMLImports.currentScript || document.currentScript ||
// NOTE: only works when called in synchronously executing code.
// readyState should check if `loading` but IE10 is
// interactive when scripts run so we cheat.
(document.readyState !== 'complete' ?
document.scripts[document.scripts.length - 1] : null);
return wrap(script);
},
configurable: true
};

Object.defineProperty(document, '_currentScript', currentScriptDescriptor);
Object.defineProperty(mainDoc, '_currentScript', currentScriptDescriptor);

// call a callback when all HTMLImports in the document at call (or at least
// document ready) time have loaded.
// 1. ensure the document is in a ready state (has dom), then
// 2. watch for loading of imports and call callback when done
function whenImportsReady(callback, doc) {
doc = doc || mainDoc;
// if document is loading, wait and try again
whenDocumentReady(function() {
watchImportsLoad(callback, doc);
}, doc);
}

// call the callback when the document is in a ready state (has dom)
var requiredReadyState = isIE ? 'complete' : 'interactive';
var READY_EVENT = 'readystatechange';
function isDocumentReady(doc) {
return (doc.readyState === 'complete' ||
doc.readyState === requiredReadyState);
}

// call <callback> when we ensure the document is in a ready state
function whenDocumentReady(callback, doc) {
if (!isDocumentReady(doc)) {
var checkReady = function() {
if (doc.readyState === 'complete' ||
doc.readyState === requiredReadyState) {
doc.removeEventListener(READY_EVENT, checkReady);
whenDocumentReady(callback, doc);
}
};
doc.addEventListener(READY_EVENT, checkReady);
} else if (callback) {
callback();
}
}

function markTargetLoaded(event) {
event.target.__loaded = true;
}

// call <callback> when we ensure all imports have loaded
function watchImportsLoad(callback, doc) {
var imports = doc.querySelectorAll('link[rel=import]');
var loaded = 0, l = imports.length;
function checkDone(d) {
if (loaded == l) {
callback && callback();
}
}
function loadedImport(e) {
markTargetLoaded(e);
loaded++;
checkDone();
}
if (l) {
for (var i=0, imp; (i<l) && (imp=imports[i]); i++) {
if (isImportLoaded(imp)) {
loadedImport.call(imp, {target: imp});
} else {
imp.addEventListener('load', loadedImport);
imp.addEventListener('error', loadedImport);
}
}
} else {
checkDone();
}
}

// NOTE: test for native imports loading is based on explicitly watching
// all imports (see below).
function isImportLoaded(link) {
return useNative ? link.__loaded : link.__importParsed;
}

// TODO(sorvell): Workaround for
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=25007, should be removed when
// this bug is addressed.
// (1) Install a mutation observer to see when HTMLImports have loaded
// (2) if this script is run during document load it will watch any existing
// imports for loading.
//
// NOTE: The workaround has restricted functionality: (1) it's only compatible
// with imports that are added to document.head since the mutation observer
// watches only head for perf reasons, (2) it requires this script
// to run before any imports have completed loading.
if (useNative) {
new MutationObserver(function(mxns) {
for (var i=0, l=mxns.length, m; (i < l) && (m=mxns[i]); i++) {
if (m.addedNodes) {
handleImports(m.addedNodes);
}
}
}).observe(document.head, {childList: true});

function handleImports(nodes) {
for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) {
if (isImport(n)) {
handleImport(n);
}
}
}

function isImport(element) {
return element.localName === 'link' && element.rel === 'import';
}

function handleImport(element) {
var loaded = element.import;
if (loaded) {
markTargetLoaded({target: element});
} else {
element.addEventListener('load', markTargetLoaded);
element.addEventListener('error', markTargetLoaded);
}
}

// make sure to catch any imports that are in the process of loading
// when this script is run.
(function() {
if (document.readyState === 'loading') {
var imports = document.querySelectorAll('link[rel=import]');
for (var i=0, l=imports.length, imp; (i<l) && (imp=imports[i]); i++) {
handleImport(imp);
}
}
})();

}

// Fire the 'HTMLImportsLoaded' event when imports in document at load time
// have loaded. This event is required to simulate the script blocking
// behavior of native imports. A main document script that needs to be sure
// imports have loaded should wait for this event.
whenImportsReady(function() {
HTMLImports.ready = true;
HTMLImports.readyTime = new Date().getTime();
mainDoc.dispatchEvent(
new CustomEvent('HTMLImportsLoaded', {bubbles: true})
);
});

// exports
scope.useNative = useNative;
scope.isImportLoaded = isImportLoaded;
scope.whenReady = whenImportsReady;
scope.isIE = isIE;

// deprecated
scope.whenImportsReady = whenImportsReady;

})(window.HTMLImports);
Loading

0 comments on commit 0d443fe

Please sign in to comment.