Skip to content

Commit 40e520d

Browse files
committed
Implement revamped scoped custom element registry
https://bugs.webkit.org/show_bug.cgi?id=286870 Reviewed by Chris Dumez. This PR implements a number of API changes we proposed in whatwg/html#10854. Since the new API's behavior is sufficiently different from the old proposal, this PR opts to write a new set of tests instead of retrofitting the old tests to match the new behavior. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Construct.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Construct.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/CustomElementRegistry-define.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/CustomElementRegistry-define.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/CustomElementRegistry-initialize.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/CustomElementRegistry-initialize.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/CustomElementRegistry-upgrade.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/CustomElementRegistry-upgrade.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Document-createElement.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Document-createElement.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Document-importNode.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Document-importNode.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Element-customElements-exceptions.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Element-customElements-exceptions.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Element-customElements.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Element-customElements.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Element-innerHTML.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Element-innerHTML.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/ShadowRoot-init-customElements.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/ShadowRoot-init-customElements.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/ShadowRoot-innerHTML.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/ShadowRoot-innerHTML.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/ShadowRoot-createElement.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/ShadowRoot-importNode.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/ShadowRoot-init-registry.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/ShadowRoot-innerHTML-upgrade.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/ShadowRoot-innerHTML.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/constructor-reentry-with-different-definition.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/scoped-registry-define-upgrade-criteria.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/scoped-registry-define-upgrade-order.tentative-expected.txt: * Source/WebCore/CMakeLists.txt: * Source/WebCore/DerivedSources-input.xcfilelist: * Source/WebCore/DerivedSources-output.xcfilelist: * Source/WebCore/DerivedSources.make: * Source/WebCore/Headers.cmake: * Source/WebCore/Sources.txt: * Source/WebCore/WebCore.xcodeproj/project.pbxproj: * Source/WebCore/dom/Attr.cpp: (WebCore::Attr::cloneNodeInternal): * Source/WebCore/dom/Attr.h: * Source/WebCore/dom/CDATASection.cpp: (WebCore::CDATASection::cloneNodeInternal): * Source/WebCore/dom/CDATASection.h: * Source/WebCore/dom/Comment.cpp: (WebCore::Comment::cloneNodeInternal): * Source/WebCore/dom/Comment.h: * Source/WebCore/dom/ContainerNode.cpp: (WebCore::ContainerNode::cloneChildNodes): * Source/WebCore/dom/ContainerNode.h: * Source/WebCore/dom/CustomElementReactionQueue.cpp: (WebCore::CustomElementReactionQueue::tryToUpgradeElement): * Source/WebCore/dom/CustomElementRegistry.cpp: (WebCore::upgradeElementsInShadowIncludingDescendants): (WebCore::CustomElementRegistry::upgrade): (WebCore::CustomElementRegistry::initialize): (WebCore::CustomElementRegistry::addToScopedCustomElementRegistryMap): * Source/WebCore/dom/CustomElementRegistry.h: (WebCore::CustomElementRegistry::registryForElement): (WebCore::CustomElementRegistry::registryForNodeOrTreeScope): * Source/WebCore/dom/CustomElementRegistry.idl: * Source/WebCore/dom/Document.cpp: (WebCore::createUpgradeCandidateElement): (WebCore::createHTMLElementWithNameValidation): (WebCore::Document::createElementForBindings): (WebCore::Document::importNode): (WebCore::createFallbackHTMLElement): (WebCore::Document::createElement): (WebCore::Document::createElementNS): (WebCore::Document::cloneNodeInternal): (WebCore::TreeScope::createElementForBindings): Deleted. (WebCore::TreeScope::createElement): Deleted. (WebCore::TreeScope::createElementNS): Deleted. * Source/WebCore/dom/Document.h: (WebCore::Document::setSawElementsInKnownNamespaces): Deleted. * Source/WebCore/dom/Document.idl: * Source/WebCore/dom/DocumentFragment.cpp: (WebCore::DocumentFragment::cloneNodeInternal): * Source/WebCore/dom/DocumentFragment.h: * Source/WebCore/dom/DocumentType.cpp: (WebCore::DocumentType::cloneNodeInternal): * Source/WebCore/dom/DocumentType.h: * Source/WebCore/dom/Element.cpp: (WebCore::Element::cloneNodeInternal): (WebCore::Element::cloneShadowTreeIfPossible): (WebCore::Element::cloneElementWithChildren): (WebCore::Element::cloneElementWithoutChildren): (WebCore::Element::cloneElementWithoutAttributesAndChildren): (WebCore::Element::insertedIntoAncestor): (WebCore::Element::removedFromAncestor): (WebCore::Element::customElementRegistry const): * Source/WebCore/dom/Element.h: * Source/WebCore/dom/Element.idl: * Source/WebCore/dom/ElementCreationOptions.h: Copied from Source/WebCore/dom/ShadowRootInit.h. * Source/WebCore/dom/ElementCreationOptions.idl: Copied from Source/WebCore/dom/ShadowRootInit.idl. * Source/WebCore/dom/ImportNodeOptions.h: Copied from Source/WebCore/dom/ShadowRootInit.h. * Source/WebCore/dom/ImportNodeOptions.idl: Copied from Source/WebCore/dom/ShadowRootInit.idl. * Source/WebCore/dom/Node.cpp: (WebCore::Node::cloneNode): * Source/WebCore/dom/Node.h: (WebCore::Node::usesNullCustomElementRegistry const): (WebCore::Node::setUsesNullCustomElementRegistry const): (WebCore::Node::clearUsesNullCustomElementRegistry const): * Source/WebCore/dom/ProcessingInstruction.cpp: (WebCore::ProcessingInstruction::cloneNodeInternal): * Source/WebCore/dom/ProcessingInstruction.h: * Source/WebCore/dom/ShadowRoot.cpp: (WebCore::ShadowRoot::insertedIntoAncestor): (WebCore::ShadowRoot::removedFromAncestor): (WebCore::ShadowRoot::registryForBindings const): (WebCore::ShadowRoot::cloneNodeInternal): * Source/WebCore/dom/ShadowRoot.h: * Source/WebCore/dom/ShadowRoot.idl: * Source/WebCore/dom/ShadowRootInit.h: * Source/WebCore/dom/ShadowRootInit.idl: * Source/WebCore/dom/Text.cpp: (WebCore::Text::cloneNodeInternal): * Source/WebCore/dom/Text.h: * Source/WebCore/dom/TreeScope.cpp: (WebCore::TreeScope::setCustomElementRegistry): (WebCore::TreeScope::importNode): Deleted. * Source/WebCore/dom/TreeScope.h: (WebCore::TreeScope::customElementRegistry const): * Source/WebCore/editing/ApplyStyleCommand.cpp: (WebCore::ApplyStyleCommand::pushDownInlineStyleAroundNode): (WebCore::ApplyStyleCommand::applyInlineStyleChange): * Source/WebCore/editing/BreakBlockquoteCommand.cpp: (WebCore::BreakBlockquoteCommand::doApply): * Source/WebCore/editing/InsertParagraphSeparatorCommand.cpp: (WebCore::InsertParagraphSeparatorCommand::cloneHierarchyUnderNewBlock): (WebCore::InsertParagraphSeparatorCommand::doApply): * Source/WebCore/editing/MarkupAccumulator.cpp: (WebCore::MarkupAccumulator::startAppendingNode): * Source/WebCore/editing/ModifySelectionListLevel.cpp: (WebCore::IncreaseSelectionListLevelCommand::doApply): * Source/WebCore/editing/SplitElementCommand.cpp: (WebCore::SplitElementCommand::doApply): * Source/WebCore/editing/TextManipulationController.cpp: (WebCore::TextManipulationController::updateInsertions): * Source/WebCore/editing/markup.cpp: (WebCore::createFragmentFromText): * Source/WebCore/html/AttachmentAssociatedElement.cpp: (WebCore::AttachmentAssociatedElement::cloneAttachmentAssociatedElementWithoutAttributesAndChildren): * Source/WebCore/html/AttachmentAssociatedElement.h: * Source/WebCore/html/HTMLAttributeNames.in: * Source/WebCore/html/HTMLImageElement.cpp: (WebCore::HTMLImageElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/html/HTMLImageElement.h: * Source/WebCore/html/HTMLInputElement.cpp: (WebCore::HTMLInputElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/html/HTMLInputElement.h: * Source/WebCore/html/HTMLScriptElement.cpp: (WebCore::HTMLScriptElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/html/HTMLScriptElement.h: * Source/WebCore/html/HTMLSourceElement.cpp: (WebCore::HTMLSourceElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/html/HTMLSourceElement.h: * Source/WebCore/html/HTMLTemplateElement.cpp: (WebCore::HTMLTemplateElement::cloneNodeInternal): (WebCore::HTMLTemplateElement::attachAsDeclarativeShadowRootIfNeeded): Deleted used code. * Source/WebCore/html/HTMLTemplateElement.h: * Source/WebCore/html/HTMLTemplateElement.idl: * Source/WebCore/html/parser/HTMLConstructionSite.cpp: (WebCore::HTMLConstructionSite::insertHTMLTemplateElement): (WebCore::HTMLConstructionSite::createElement): (WebCore::HTMLConstructionSite::createHTMLElementOrFindCustomElementInterface): * Source/WebCore/html/shadow/SliderThumbElement.cpp: (WebCore::SliderThumbElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/html/shadow/SliderThumbElement.h: * Source/WebCore/html/track/TextTrackCue.cpp: (WebCore::TextTrackCue::create): (WebCore::TextTrackCue::getCueAsHTML): (WebCore::TextTrackCue::rebuildDisplayTree): * Source/WebCore/html/track/VTTCue.cpp: (WebCore::VTTCue::createCueRenderingTree): * Source/WebCore/html/track/WebVTTElement.cpp: (WebCore::WebVTTElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/html/track/WebVTTElement.h: * Source/WebCore/inspector/agents/InspectorDOMAgent.cpp: * Source/WebCore/page/LocalDOMWindow.cpp: (WebCore::LocalDOMWindow::ensureCustomElementRegistry): * Source/WebCore/svg/SVGScriptElement.cpp: (WebCore::SVGScriptElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/svg/SVGScriptElement.h: * Source/WebCore/svg/SVGUseElement.cpp: (WebCore::SVGUseElement::cloneTarget const): (WebCore::cloneDataAndChildren): * Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::XMLDocumentParser::startElementNs): * Source/WebKitLegacy/mac/DOM/DOMDocument.mm: Canonical link: https://commits.webkit.org/290096@main
1 parent 3bd23d6 commit 40e520d

File tree

112 files changed

+1506
-296
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+1506
-296
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
PASS A constructor with only a scoped custom element registry definition should fail upon construction
3+
PASS A constructor uses the global registry to create an element
4+
PASS A constructor creating an element from another registry before or after super call should work
5+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta name="author" title="Ryosuke Niwa" href="mailto:[email protected]">
5+
<link rel="help" href="https://github.com/whatwg/html/issues/10854">
6+
<script src="../../resources/testharness.js"></script>
7+
<script src="../../resources/testharnessreport.js"></script>
8+
</head>
9+
<body>
10+
<script>
11+
12+
test(() => {
13+
class ABElement extends HTMLElement { };
14+
const scopedRegistry = new CustomElementRegistry;
15+
scopedRegistry.define('a-b', ABElement);
16+
assert_throws_js(TypeError, () => new ABElement);
17+
}, 'A constructor with only a scoped custom element registry definition should fail upon construction');
18+
19+
test(() => {
20+
class CElement extends HTMLElement { };
21+
const scopedRegistry = new CustomElementRegistry;
22+
scopedRegistry.define('scoped-c', CElement);
23+
customElements.define('global-c', CElement);
24+
const cElement = new CElement;
25+
assert_equals(cElement.localName, 'global-c');
26+
}, 'A constructor uses the global registry to create an element');
27+
28+
test(() => {
29+
let fgElement;
30+
let hiElement;
31+
class DEElement extends HTMLElement {
32+
constructor() {
33+
fgElement = document.createElement('f-g', {customElements: scopedRegistry2});
34+
super();
35+
hiElement = document.createElement('h-i', {customElements: scopedRegistry2});
36+
}
37+
};
38+
class FGElement extends HTMLElement { }
39+
class HIElement extends HTMLElement { }
40+
const scopedRegistry1 = new CustomElementRegistry;
41+
scopedRegistry1.define('d-e', DEElement);
42+
const scopedRegistry2 = new CustomElementRegistry;
43+
scopedRegistry2.define('f-g', FGElement);
44+
scopedRegistry2.define('h-i', HIElement);
45+
46+
const deElement = document.createElement('d-e', {customElements: scopedRegistry1});
47+
assert_true(deElement instanceof DEElement);
48+
assert_equals(deElement.customElements, scopedRegistry1);
49+
assert_true(fgElement instanceof FGElement);
50+
assert_equals(fgElement.customElements, scopedRegistry2);
51+
assert_true(hiElement instanceof HIElement);
52+
assert_equals(hiElement.customElements, scopedRegistry2);
53+
}, 'A constructor creating an element from another registry before or after super call should work');
54+
55+
</script>
56+
</body>
57+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
PASS Create a CustomElementRegistry not identically equal to window.customElements
3+
PASS Defining an element in the global registry does not add a definition to a scoped CustomElementRegistry
4+
PASS Defining an element in a scoped global registry does not add a definition to the global registry
5+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta name="author" title="Ryosuke Niwa" href="mailto:[email protected]">
5+
<link rel="help" href="https://github.com/whatwg/html/issues/10854">
6+
<script src="../../resources/testharness.js"></script>
7+
<script src="../../resources/testharnessreport.js"></script>
8+
</head>
9+
<body>
10+
<script>
11+
test(() => {
12+
let registry = new CustomElementRegistry();
13+
assert_not_equals(registry, window.customElements);
14+
}, 'Create a CustomElementRegistry not identically equal to window.customElements');
15+
16+
test(() => {
17+
let registry = new CustomElementRegistry();
18+
window.customElements.define('a-b', class extends HTMLElement {});
19+
assert_equals(registry.get('a-b'), undefined);
20+
}, 'Defining an element in the global registry does not add a definition to a scoped CustomElementRegistry');
21+
22+
test(() => {
23+
let registry = new CustomElementRegistry();
24+
registry.define('b-c', class extends HTMLElement {});
25+
assert_equals(window.customElements.get('b-c'), undefined);
26+
}, 'Defining an element in a scoped global registry does not add a definition to the global registry');
27+
28+
</script>
29+
</body>
30+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
PASS initialize is a function on both global and scoped CustomElementRegistry
3+
PASS initialize sets element.customElements to the global registry
4+
PASS initialize does not set the registry of nested shadow tree to the global registry
5+
PASS initialize sets element.customElements to a scoped registry
6+
PASS initialize does not set the registry of nested shadow tree to a scoped registry
7+
PASS initialize sets element.customElements permantently
8+
PASS initialize is no-op on a subtree with a non-null registry
9+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta name="author" title="Ryosuke Niwa" href="mailto:[email protected]">
5+
<link rel="help" href="https://github.com/whatwg/html/issues/10854">
6+
<script src="../../resources/testharness.js"></script>
7+
<script src="../../resources/testharnessreport.js"></script>
8+
</head>
9+
<body>
10+
<div id="host">
11+
<template shadowrootmode="open" shadowrootclonable="true" shadowrootcustomelements>
12+
<a-b>
13+
<template shadowrootmode="open" shadowrootclonable="true" shadowrootcustomelements>
14+
<c-d/><c-d>
15+
</template>
16+
</a-b>
17+
<ef></ef>
18+
</template>
19+
</div>
20+
<div id="host-with-registry">
21+
<template shadowrootmode="open" shadowrootclonable="true">
22+
<a-b></a-b>
23+
<ef></ef>
24+
</template>
25+
</div>
26+
<script>
27+
28+
test(() => {
29+
assert_equals(typeof(window.customElements.initialize), 'function');
30+
assert_equals(typeof((new CustomElementRegistry).initialize), 'function');
31+
}, 'initialize is a function on both global and scoped CustomElementRegistry');
32+
33+
test(() => {
34+
const clone = host.cloneNode(true);
35+
const shadowRoot = clone.shadowRoot;
36+
assert_equals(shadowRoot.customElements, null);
37+
assert_equals(shadowRoot.querySelector('a-b').customElements, null);
38+
assert_equals(shadowRoot.querySelector('ef').customElements, null);
39+
window.customElements.initialize(shadowRoot);
40+
assert_equals(shadowRoot.customElements, window.customElements);
41+
assert_equals(shadowRoot.querySelector('a-b').customElements, window.customElements);
42+
assert_equals(shadowRoot.querySelector('ef').customElements, window.customElements);
43+
}, 'initialize sets element.customElements to the global registry');
44+
45+
test(() => {
46+
const clone = host.cloneNode(true);
47+
const shadowRoot = clone.shadowRoot;
48+
assert_equals(shadowRoot.customElements, null);
49+
assert_equals(shadowRoot.querySelector('a-b').customElements, null);
50+
assert_equals(shadowRoot.querySelector('ef').customElements, null);
51+
window.customElements.initialize(shadowRoot);
52+
assert_equals(shadowRoot.customElements, window.customElements);
53+
assert_equals(shadowRoot.querySelector('a-b').customElements, window.customElements);
54+
assert_equals(shadowRoot.querySelector('ef').customElements, window.customElements);
55+
assert_equals(shadowRoot.querySelector('a-b').shadowRoot.customElements, null);
56+
assert_equals(shadowRoot.querySelector('a-b').shadowRoot.querySelector('c-d').customElements, null);
57+
}, 'initialize does not set the registry of nested shadow tree to the global registry');
58+
59+
60+
test(() => {
61+
const clone = host.cloneNode(true);
62+
const shadowRoot = clone.shadowRoot;
63+
assert_equals(shadowRoot.customElements, null);
64+
assert_equals(shadowRoot.querySelector('a-b').customElements, null);
65+
assert_equals(shadowRoot.querySelector('ef').customElements, null);
66+
const registry = new CustomElementRegistry;
67+
registry.initialize(shadowRoot);
68+
assert_equals(shadowRoot.customElements, registry);
69+
assert_equals(shadowRoot.querySelector('a-b').customElements, registry);
70+
assert_equals(shadowRoot.querySelector('ef').customElements, registry);
71+
}, 'initialize sets element.customElements to a scoped registry');
72+
73+
test(() => {
74+
const clone = host.cloneNode(true);
75+
const shadowRoot = clone.shadowRoot;
76+
assert_equals(shadowRoot.customElements, null);
77+
assert_equals(shadowRoot.querySelector('a-b').customElements, null);
78+
assert_equals(shadowRoot.querySelector('ef').customElements, null);
79+
const registry = new CustomElementRegistry;
80+
registry.initialize(shadowRoot);
81+
assert_equals(shadowRoot.customElements, registry);
82+
assert_equals(shadowRoot.querySelector('a-b').customElements, registry);
83+
assert_equals(shadowRoot.querySelector('ef').customElements, registry);
84+
assert_equals(shadowRoot.querySelector('a-b').shadowRoot.customElements, null);
85+
assert_equals(shadowRoot.querySelector('a-b').shadowRoot.querySelector('c-d').customElements, null);
86+
}, 'initialize does not set the registry of nested shadow tree to a scoped registry');
87+
88+
test(() => {
89+
const clone = host.cloneNode(true);
90+
const shadowRoot = clone.shadowRoot;
91+
assert_equals(shadowRoot.customElements, null);
92+
assert_equals(shadowRoot.querySelector('a-b').customElements, null);
93+
assert_equals(shadowRoot.querySelector('ef').customElements, null);
94+
const registry = new CustomElementRegistry;
95+
registry.initialize(shadowRoot);
96+
assert_equals(shadowRoot.customElements, registry);
97+
assert_equals(shadowRoot.querySelector('a-b').customElements, registry);
98+
assert_equals(shadowRoot.querySelector('ef').customElements, registry);
99+
document.body.appendChild(clone);
100+
assert_equals(shadowRoot.customElements, registry);
101+
assert_equals(shadowRoot.querySelector('a-b').customElements, registry);
102+
assert_equals(shadowRoot.querySelector('ef').customElements, registry);
103+
}, 'initialize sets element.customElements permantently');
104+
105+
test(() => {
106+
const clone = document.getElementById('host-with-registry').cloneNode(true);
107+
const shadowRoot = clone.shadowRoot;
108+
assert_equals(shadowRoot.customElements, window.customElements);
109+
assert_equals(shadowRoot.querySelector('a-b').customElements, window.customElements);
110+
assert_equals(shadowRoot.querySelector('ef').customElements, window.customElements);
111+
const registry = new CustomElementRegistry;
112+
registry.initialize(shadowRoot);
113+
assert_equals(shadowRoot.customElements, window.customElements);
114+
assert_equals(shadowRoot.querySelector('a-b').customElements, window.customElements);
115+
assert_equals(shadowRoot.querySelector('ef').customElements, window.customElements);
116+
}, 'initialize is no-op on a subtree with a non-null registry');
117+
118+
</script>
119+
</body>
120+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
PASS upgrade is a function on both global and scoped CustomElementRegistry
3+
PASS upgrade is a no-op when called on a shadow root with no association
4+
PASS upgrade should upgrade a candidate element when called on a shadow root with an association
5+
PASS upgrade should not upgrade a candidate element not associated with the registry
6+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta name="author" title="Ryosuke Niwa" href="mailto:[email protected]">
5+
<link rel="help" href="https://github.com/whatwg/html/issues/10854">
6+
<script src="../../resources/testharness.js"></script>
7+
<script src="../../resources/testharnessreport.js"></script>
8+
</head>
9+
<body>
10+
<some-host id="host">
11+
<template shadowrootmode="closed" shadowrootclonable="true" shadowrootcustomelements>
12+
<a-b>
13+
<template shadowrootmode="closed" shadowrootclonable="true" shadowrootcustomelements>
14+
<c-d/>
15+
<template shadowrootmode="closed" shadowrootclonable="true">
16+
<a-b></a-b>
17+
</template>
18+
<c-d>
19+
</template>
20+
</a-b>
21+
</template>
22+
</some-host>
23+
<script>
24+
25+
customElements.define('some-host', class SomeHost extends HTMLElement {
26+
internals;
27+
28+
constructor() {
29+
super();
30+
this.internals = this.attachInternals();
31+
}
32+
});
33+
customElements.define('a-b', class GlobalABElement extends HTMLElement { });
34+
customElements.define('c-d', class GlobalCDElement extends HTMLElement { });
35+
36+
test(() => {
37+
assert_equals(typeof(window.customElements.upgrade), 'function');
38+
assert_equals(typeof((new CustomElementRegistry).upgrade), 'function');
39+
}, 'upgrade is a function on both global and scoped CustomElementRegistry');
40+
41+
test(() => {
42+
const registry = new CustomElementRegistry;
43+
registry.define('a-b', class ABElement extends HTMLElement { });
44+
45+
const clone = host.cloneNode(true);
46+
registry.upgrade(clone.internals.shadowRoot);
47+
assert_equals(clone.internals.shadowRoot.querySelector('a-b').__proto__.constructor.name, 'HTMLElement');
48+
}, 'upgrade is a no-op when called on a shadow root with no association');
49+
50+
test(() => {
51+
const registry = new CustomElementRegistry;
52+
registry.define('a-b', class ABElement extends HTMLElement {
53+
internals;
54+
55+
constructor() {
56+
super();
57+
this.internals = this.attachInternals();
58+
}
59+
});
60+
61+
const clone = host.cloneNode(true);
62+
registry.initialize(clone.internals.shadowRoot);
63+
registry.upgrade(clone.internals.shadowRoot);
64+
const abElement = clone.internals.shadowRoot.querySelector('a-b');
65+
assert_equals(abElement.__proto__.constructor.name, 'ABElement');
66+
assert_equals(abElement.internals.shadowRoot.customElements, null);
67+
const cdElement = abElement.internals.shadowRoot.querySelector('c-d');
68+
assert_equals(cdElement.__proto__.constructor.name, 'HTMLElement');
69+
assert_equals(cdElement.customElements, null);
70+
}, 'upgrade should upgrade a candidate element when called on a shadow root with an association');
71+
72+
test(() => {
73+
const registry = new CustomElementRegistry;
74+
registry.define('a-b', class ScopedABElement extends HTMLElement {
75+
internals;
76+
77+
constructor() {
78+
super();
79+
this.internals = this.attachInternals();
80+
}
81+
});
82+
83+
const clone = host.cloneNode(true);
84+
registry.initialize(clone.internals.shadowRoot);
85+
registry.upgrade(clone.internals.shadowRoot);
86+
const abElement = clone.internals.shadowRoot.querySelector('a-b');
87+
assert_equals(abElement.__proto__.constructor.name, 'ScopedABElement');
88+
registry.initialize(abElement.internals.shadowRoot);
89+
assert_equals(abElement.internals.shadowRoot.customElements, registry);
90+
const cdElement = abElement.internals.shadowRoot.querySelector('c-d');
91+
assert_equals(cdElement.customElements, registry);
92+
93+
registry.define('c-d', class ScopedCDElement extends HTMLElement {
94+
internals;
95+
96+
constructor() {
97+
super();
98+
this.internals = this.attachInternals();
99+
}
100+
});
101+
assert_equals(cdElement.__proto__.constructor.name, 'HTMLElement');
102+
registry.upgrade(abElement.internals.shadowRoot);
103+
assert_equals(cdElement.__proto__.constructor.name, 'ScopedCDElement');
104+
assert_equals(cdElement.customElements, registry);
105+
106+
assert_equals(cdElement.internals.shadowRoot.customElements, window.customElements);
107+
const innerAB = cdElement.internals.shadowRoot.querySelector('a-b');
108+
assert_equals(innerAB.customElements, window.customElements);
109+
assert_equals(innerAB.__proto__.constructor.name, 'HTMLElement');
110+
}, 'upgrade should not upgrade a candidate element not associated with the registry');
111+
112+
</script>
113+
</body>
114+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
PASS createElement should use the global registry by default
3+
PASS createElement should use the specified scoped registry
4+
PASS createElement should create a builtin element regardles of a custom element registry specified
5+
PASS createElement should use the specified global registry
6+
PASS createElement should create an upgrade candidate when there is no matching definition in the specified registry
7+
PASS createElement should create an upgrade candidate and the candidate should be upgraded when the element is defined
8+

0 commit comments

Comments
 (0)