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

Commit 9e5c7b5

Browse files
committed
Merge pull request #271 from webcomponents/importNode
Make the CustomElements polyfill upgrade elements created by `document.importNode`
2 parents 1e1b111 + e260435 commit 9e5c7b5

File tree

3 files changed

+55
-34
lines changed

3 files changed

+55
-34
lines changed

src/CustomElements/boot.js

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,6 @@ var initializeModules = scope.initializeModules;
1515

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

18-
// Patch document.importNode to work around IE11 bug that
19-
// casues children of a document fragment imported while
20-
// there is a mutation observer to not have a parentNode (!?!)
21-
if (isIE11OrOlder) {
22-
(function() {
23-
var importNode = document.importNode;
24-
document.importNode = function() {
25-
var n = importNode.apply(document, arguments);
26-
// Copy all children to a new document fragment since
27-
// this one may be broken
28-
if (n.nodeType == n.DOCUMENT_FRAGMENT_NODE) {
29-
var f = document.createDocumentFragment();
30-
f.appendChild(n);
31-
return f;
32-
} else {
33-
return n;
34-
}
35-
};
36-
})();
37-
}
38-
3918
// If native, setup stub api and bail.
4019
// NOTE: we fire `WebComponentsReady` under native for api compatibility
4120
if (useNative) {
@@ -139,4 +118,7 @@ if (document.readyState === 'complete' || scope.flags.eager) {
139118
window.addEventListener(loadEvent, bootstrap);
140119
}
141120

121+
// exports
122+
scope.isIE11OrOlder = isIE11OrOlder;
123+
142124
})(window.CustomElements);

src/CustomElements/register.js

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@
2121
CustomElements.addModule(function(scope) {
2222

2323
// imports
24+
var isIE11OrOlder = scope.isIE11OrOlder;
2425
var upgradeDocumentTree = scope.upgradeDocumentTree;
25-
var upgrade = scope.upgrade;
26+
var upgradeAll = scope.upgradeAll;
2627
var upgradeWithDefinition = scope.upgradeWithDefinition;
2728
var implementPrototype = scope.implementPrototype;
2829
var useNative = scope.useNative;
@@ -291,20 +292,9 @@ function createElement(tag, typeExtension) {
291292
return element;
292293
}
293294

294-
function cloneNode(deep) {
295-
// call original clone
296-
var n = domCloneNode.call(this, deep);
297-
// upgrade the element and subtree
298-
upgrade(n);
299-
// return the clone
300-
return n;
301-
}
302-
303295
// capture native createElement before we override it
304296
var domCreateElement = document.createElement.bind(document);
305297
var domCreateElementNS = document.createElementNS.bind(document);
306-
// capture native cloneNode before we override it
307-
var domCloneNode = Node.prototype.cloneNode;
308298

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

322+
// wrap a dom object method that works on nodes such that it forces upgrade
323+
function wrapDomMethodToForceUpgrade(obj, methodName) {
324+
var orig = obj[methodName];
325+
obj[methodName] = function() {
326+
var n = orig.apply(this, arguments);
327+
upgradeAll(n);
328+
return n;
329+
};
330+
}
331+
332+
wrapDomMethodToForceUpgrade(Node.prototype, 'cloneNode');
333+
wrapDomMethodToForceUpgrade(document, 'importNode');
334+
335+
// Patch document.importNode to work around IE11 bug that
336+
// casues children of a document fragment imported while
337+
// there is a mutation observer to not have a parentNode (!?!)
338+
if (isIE11OrOlder) {
339+
(function() {
340+
var importNode = document.importNode;
341+
document.importNode = function() {
342+
var n = importNode.apply(document, arguments);
343+
// Copy all children to a new document fragment since
344+
// this one may be broken
345+
if (n.nodeType == n.DOCUMENT_FRAGMENT_NODE) {
346+
var f = document.createDocumentFragment();
347+
f.appendChild(n);
348+
return f;
349+
} else {
350+
return n;
351+
}
352+
};
353+
})();
354+
}
355+
332356
// exports
333357
document.registerElement = register;
334358
document.createElement = createElement; // override
335359
document.createElementNS = createElementNS; // override
336-
Node.prototype.cloneNode = cloneNode; // override
337360
scope.registry = registry;
338361
scope.instanceof = isInstance;
339362
scope.reservedTagList = reservedTagList;

tests/CustomElements/js/customElements.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,22 @@ suite('customElements', function() {
364364
done();
365365
});
366366

367+
test('document.importNode upgrades', function() {
368+
var XImportPrototype = Object.create(HTMLElement.prototype);
369+
XImportPrototype.createdCallback = function() {
370+
this.__ready__ = true;
371+
};
372+
document.registerElement('x-import', {
373+
prototype: XImportPrototype
374+
});
375+
var frag = document.createDocumentFragment();
376+
frag.appendChild(document.createElement('x-import'));
377+
assert.isTrue(frag.firstChild.__ready__, 'source element upgraded');
378+
var imported = document.importNode(frag, true);
379+
window.imported = imported;
380+
assert.isTrue(imported.firstChild.__ready__, 'imported element upgraded');
381+
});
382+
367383
test('entered left apply to view', function() {
368384
var invocations = [];
369385
var elementProto = Object.create(HTMLElement.prototype);

0 commit comments

Comments
 (0)