Skip to content

Commit

Permalink
Fix root node type in customElements.upgrade polyfill
Browse files Browse the repository at this point in the history
  • Loading branch information
edoardocavazza committed Mar 29, 2024
1 parent 197d483 commit 9ec10fe
Show file tree
Hide file tree
Showing 3 changed files with 1,398 additions and 1,425 deletions.
5 changes: 5 additions & 0 deletions .changeset/clever-terms-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@chialab/dna": patch
---

Fix root node type in `customElements.upgrade` polyfill.
82 changes: 44 additions & 38 deletions src/polyfill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,55 +138,61 @@ function polyfillBuiltin() {
CurrentConstructor.__shim = true;
};

customElements.upgrade = function polyfillUpgrade(root: HTMLElement, nested = false) {
const isElement = (node: Node): node is Element => node.nodeType === Node.ELEMENT_NODE;
const isParent = (node: Node): node is ParentNode => 'children' in node;

customElements.upgrade = function polyfillUpgrade(root: Node, nested = false) {
if (!nested) {
upgrade(root);
}

Array.from(root.children).forEach((node) => {
polyfillUpgrade(node as HTMLElement, true);
});

if (CE_SYMBOL in root) {
// already upgraded
return;
}

const is = root.getAttribute('is');
if (!is) {
upgrade(root);
return;
}
upgradeBlock: if (isElement(root)) {
if (CE_SYMBOL in root) {
// already upgraded
break upgradeBlock;
}

const constructor = customElements.get(is) as CustomElementConstructor;
if (!constructor) {
return;
}
const is = root.getAttribute('is');
if (!is) {
upgrade(root);
break upgradeBlock;
}

const attributes: { name: string; value: string }[] = [];
const observed = (constructor as CustomElementConstructor).observedAttributes || [];
for (let i = 0, len = root.attributes.length; i < len; i++) {
const attr = root.attributes[i];
if (observed.includes(attr.name)) {
attributes.push({
name: attr.name,
value: attr.value,
});
const constructor = customElements.get(is) as CustomElementConstructor;
if (!constructor) {
break upgradeBlock;
}
}

root = Reflect.construct(constructor, [root], constructor);
const attributes: { name: string; value: string }[] = [];
const observed = (constructor as CustomElementConstructor).observedAttributes || [];
for (let i = 0, len = root.attributes.length; i < len; i++) {
const attr = root.attributes[i];
if (observed.includes(attr.name)) {
attributes.push({
name: attr.name,
value: attr.value,
});
}
}

for (let i = 0, len = attributes.length; i < len; i++) {
const { name, value } = attributes[i];
if (root.getAttribute(name) === value) {
(root as CustomElement).attributeChangedCallback(name, null, value);
} else {
root.setAttribute(name, value);
const upgradedNode = Reflect.construct(constructor, [root], constructor) as CustomElement;
for (let i = 0, len = attributes.length; i < len; i++) {
const { name, value } = attributes[i];
if (upgradedNode.getAttribute(name) === value) {
upgradedNode.attributeChangedCallback(name, null, value);
} else {
upgradedNode.setAttribute(name, value);
}
}
if (upgradedNode.isConnected) {
upgradedNode.connectedCallback();
}
}
if (root.isConnected) {
(root as CustomElement).connectedCallback();

if (isParent(root)) {
Array.from(root.children).forEach((node) => {
polyfillUpgrade(node as HTMLElement, true);
});
}
};

Expand Down
Loading

0 comments on commit 9ec10fe

Please sign in to comment.