Skip to content
This repository has been archived by the owner on Sep 20, 2019. It is now read-only.

Commit

Permalink
Merge pull request #271 from webcomponents/importNode
Browse files Browse the repository at this point in the history
Make the CustomElements polyfill upgrade elements created by `document.importNode`
  • Loading branch information
garlicnation committed Apr 7, 2015
2 parents 1e1b111 + e260435 commit 9e5c7b5
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 34 deletions.
24 changes: 3 additions & 21 deletions src/CustomElements/boot.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,6 @@ var initializeModules = scope.initializeModules;

var isIE11OrOlder = /Trident/.test(navigator.userAgent);

// Patch document.importNode to work around IE11 bug that
// casues children of a document fragment imported while
// there is a mutation observer to not have a parentNode (!?!)
if (isIE11OrOlder) {
(function() {
var importNode = document.importNode;
document.importNode = function() {
var n = importNode.apply(document, arguments);
// Copy all children to a new document fragment since
// this one may be broken
if (n.nodeType == n.DOCUMENT_FRAGMENT_NODE) {
var f = document.createDocumentFragment();
f.appendChild(n);
return f;
} else {
return n;
}
};
})();
}

// If native, setup stub api and bail.
// NOTE: we fire `WebComponentsReady` under native for api compatibility
if (useNative) {
Expand Down Expand Up @@ -139,4 +118,7 @@ if (document.readyState === 'complete' || scope.flags.eager) {
window.addEventListener(loadEvent, bootstrap);
}

// exports
scope.isIE11OrOlder = isIE11OrOlder;

})(window.CustomElements);
49 changes: 36 additions & 13 deletions src/CustomElements/register.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
CustomElements.addModule(function(scope) {

// imports
var isIE11OrOlder = scope.isIE11OrOlder;
var upgradeDocumentTree = scope.upgradeDocumentTree;
var upgrade = scope.upgrade;
var upgradeAll = scope.upgradeAll;
var upgradeWithDefinition = scope.upgradeWithDefinition;
var implementPrototype = scope.implementPrototype;
var useNative = scope.useNative;
Expand Down Expand Up @@ -291,20 +292,9 @@ function createElement(tag, typeExtension) {
return element;
}

function cloneNode(deep) {
// call original clone
var n = domCloneNode.call(this, deep);
// upgrade the element and subtree
upgrade(n);
// return the clone
return n;
}

// capture native createElement before we override it
var domCreateElement = document.createElement.bind(document);
var domCreateElementNS = document.createElementNS.bind(document);
// capture native cloneNode before we override it
var domCloneNode = Node.prototype.cloneNode;

// Create a custom 'instanceof'. This is necessary when CustomElements
// are implemented via a mixin strategy, as for example on IE10.
Expand All @@ -329,11 +319,44 @@ if (!Object.__proto__ && !useNative) {
};
}

// wrap a dom object method that works on nodes such that it forces upgrade
function wrapDomMethodToForceUpgrade(obj, methodName) {
var orig = obj[methodName];
obj[methodName] = function() {
var n = orig.apply(this, arguments);
upgradeAll(n);
return n;
};
}

wrapDomMethodToForceUpgrade(Node.prototype, 'cloneNode');
wrapDomMethodToForceUpgrade(document, 'importNode');

// Patch document.importNode to work around IE11 bug that
// casues children of a document fragment imported while
// there is a mutation observer to not have a parentNode (!?!)
if (isIE11OrOlder) {
(function() {
var importNode = document.importNode;
document.importNode = function() {
var n = importNode.apply(document, arguments);
// Copy all children to a new document fragment since
// this one may be broken
if (n.nodeType == n.DOCUMENT_FRAGMENT_NODE) {
var f = document.createDocumentFragment();
f.appendChild(n);
return f;
} else {
return n;
}
};
})();
}

// exports
document.registerElement = register;
document.createElement = createElement; // override
document.createElementNS = createElementNS; // override
Node.prototype.cloneNode = cloneNode; // override
scope.registry = registry;
scope.instanceof = isInstance;
scope.reservedTagList = reservedTagList;
Expand Down
16 changes: 16 additions & 0 deletions tests/CustomElements/js/customElements.js
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,22 @@ suite('customElements', function() {
done();
});

test('document.importNode upgrades', function() {
var XImportPrototype = Object.create(HTMLElement.prototype);
XImportPrototype.createdCallback = function() {
this.__ready__ = true;
};
document.registerElement('x-import', {
prototype: XImportPrototype
});
var frag = document.createDocumentFragment();
frag.appendChild(document.createElement('x-import'));
assert.isTrue(frag.firstChild.__ready__, 'source element upgraded');
var imported = document.importNode(frag, true);
window.imported = imported;
assert.isTrue(imported.firstChild.__ready__, 'imported element upgraded');
});

test('entered left apply to view', function() {
var invocations = [];
var elementProto = Object.create(HTMLElement.prototype);
Expand Down

0 comments on commit 9e5c7b5

Please sign in to comment.