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

Commit

Permalink
Re-enable dynamic parsing for scripts and styles.
Browse files Browse the repository at this point in the history
  • Loading branch information
sorvell committed Sep 29, 2014
1 parent af95b49 commit caea5ff
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 30 deletions.
32 changes: 20 additions & 12 deletions src/Observer.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,40 @@ function handler(mutations) {
}

// find loadable elements and add them to the importer
// IFF the owning document has already parsed, then parsable elements
// need to be marked for dynamic parsing.
function addedNodes(nodes) {
var owner;
for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) {
owner = owner || n.ownerDocument;
if (shouldLoadNode(n)) {
var owner, parsed;
for (var i=0, l=nodes.length, n, loading; (i<l) && (n=nodes[i]); i++) {
if (!owner) {
owner = n.ownerDocument;
parsed = parser.isParsed(owner);
}
// note: the act of loading kicks the parser, so we use parseDynamic's
// 2nd argument to control if this added node needs to kick the parser.
loading = shouldLoadNode(n);
if (loading) {
importer.loadNode(n);
}
if (shouldParseNode(n) && parsed) {
parser.parseDynamic(n, loading);
}
if (n.children && n.children.length) {
addedNodes(n.children);
}
}
// TODO(sorvell): This is not the right approach here. We shouldn't need to
// invalidate parsing when an element is added. Disabling this code
// until a better approach is found.
/*
if (owner) {
parser.invalidateParse(owner);
}
*/
}

function shouldLoadNode(node) {
return (node.nodeType === 1) && matches.call(node,
importer.loadSelectorsForNode(node));
}

function shouldParseNode(node) {
return (node.nodeType === 1) && matches.call(node,
parser.parseSelectorsForNode(node));
}

// x-plat matches
var matches = HTMLElement.prototype.matches ||
HTMLElement.prototype.matchesSelector ||
Expand Down
35 changes: 21 additions & 14 deletions src/Parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var importParser = {
script: 'parseScript',
style: 'parseStyle'
},
dynamicElements: [],
// try to parse the next import in the tree
parseNext: function() {
var next = this.nextToParse();
Expand All @@ -57,6 +58,12 @@ var importParser = {
fn.call(this, elt);
}
},
parseDynamic: function(elt, quiet) {
this.dynamicElements.push(elt);
if (!quiet) {
this.parseNext();
}
},
// only 1 element may be parsed at a time; parsing is async so each
// parsing implementation must inform the system that parsing is complete
// via markParsingComplete.
Expand All @@ -71,27 +78,20 @@ var importParser = {
},
markParsingComplete: function(elt) {
elt.__importParsed = true;
this.markDynamicParsingComplete(elt);
if (elt.__importElement) {
elt.__importElement.__importParsed = true;
this.markDynamicParsingComplete(elt.__importElement);
}
this.parsingElement = null;
flags.parse && console.log('completed', elt);
},
invalidateParse: function(doc) {
if (doc && doc.__importLink) {
doc.__importParsed = doc.__importLink.__importParsed = false;
this.parseSoon();
markDynamicParsingComplete: function(elt) {
var i = this.dynamicElements.indexOf(elt);
if (i >= 0) {
this.dynamicElements.splice(i, 1);
}
},
parseSoon: function() {
if (this._parseSoon) {
cancelAnimationFrame(this._parseDelay);
}
var parser = this;
this._parseSoon = requestAnimationFrame(function() {
parser.parseNext();
});
},
parseImport: function(elt) {
// TODO(sorvell): consider if there's a better way to do this;
// expose an imports parsing hook; this is needed, for example, by the
Expand Down Expand Up @@ -218,7 +218,8 @@ var importParser = {
// determine the next element in the tree which should be parsed
nextToParse: function() {
this._mayParse = [];
return !this.parsingElement && this.nextToParseInDoc(mainDoc);
return !this.parsingElement && (this.nextToParseInDoc(mainDoc) ||
this.nextToParseDynamic());
},
nextToParseInDoc: function(doc, link) {
// use `marParse` list to avoid looping into the same document again
Expand All @@ -239,6 +240,9 @@ var importParser = {
// all nodes have been parsed, ready to parse import, if any
return link;
},
nextToParseDynamic: function() {
return this.dynamicElements[0];
},
// return the set of parse selectors relevant for this node.
parseSelectorsForNode: function(node) {
var doc = node.ownerDocument || node;
Expand All @@ -247,6 +251,9 @@ var importParser = {
isParsed: function(node) {
return node.__importParsed;
},
needsDynamicParsing: function(elt) {
return (this.dynamicElements.indexOf(elt) >= 0);
},
hasResource: function(node) {
if (nodeIsImport(node) && (node.import === undefined)) {
return false;
Expand Down
4 changes: 2 additions & 2 deletions test/html/dynamic-elements.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@

<script>
document.addEventListener('asyncElementsAdded', function() {
HTMLImports.whenReady(function() {
setTimeout(function() {
chai.assert.isTrue(window.asyncScript, 'async added script ran');
var computed = getComputedStyle(document.querySelector('#asyncStyled'));
chai.assert.equal(computed.backgroundColor, 'rgb(255, 0, 0)', 'async added style applied');
done();
});
}, 1);
});
</script>
</body>
Expand Down
3 changes: 1 addition & 2 deletions test/js/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ htmlSuite('HTMLImports', function() {
htmlTest('html/currentScript.html');
htmlTest('html/dedupe.html');
htmlTest('html/dynamic.html');
// TODO(sjmiles): feature not implemented currently
//htmlTest('html/dynamic-elements.html');
htmlTest('html/dynamic-elements.html');
htmlTest('html/csp.html');
htmlTest('html/encoding.html');
htmlTest('html/HTMLImportsLoaded-native.html');
Expand Down

0 comments on commit caea5ff

Please sign in to comment.