diff options
author | Xiaocheng Hu <xiaochengh.work@gmail.com> | 2025-03-14 02:03:57 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-03-13 18:03:57 +0000 |
commit | 62d6759106c987ed438d6a8e281fea28859300d3 (patch) | |
tree | e6d4e4e64311d059671fafbecd05da0fe0030964 | |
parent | ea35353e9aacb65944b8e23ae564cc771bdab33f (diff) | |
download | servo-62d6759106c987ed438d6a8e281fea28859300d3.tar.gz servo-62d6759106c987ed438d6a8e281fea28859300d3.zip |
Check whether an element is custom in the spec-compliant way (#35960)
* Check whether element is custom in spec-compliant way
Signed-off-by: Xiaocheng Hu <xiaochengh.work@gmail.com>
* Update tests
Signed-off-by: Xiaocheng Hu <xiaochengh.work@gmail.com>
---------
Signed-off-by: Xiaocheng Hu <xiaochengh.work@gmail.com>
-rw-r--r-- | components/script/dom/attr.rs | 2 | ||||
-rw-r--r-- | components/script/dom/element.rs | 17 | ||||
-rw-r--r-- | components/script/dom/node.rs | 5 | ||||
-rw-r--r-- | tests/wpt/meta/MANIFEST.json | 2 | ||||
-rw-r--r-- | tests/wpt/meta/custom-elements/custom-element-reaction-queue.html.ini | 4 | ||||
-rw-r--r-- | tests/wpt/tests/custom-elements/custom-element-reaction-queue.html | 54 |
6 files changed, 71 insertions, 13 deletions
diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs index fff594cead0..428f02cece3 100644 --- a/components/script/dom/attr.rs +++ b/components/script/dom/attr.rs @@ -166,7 +166,7 @@ impl Attr { MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation); - if owner.get_custom_element_definition().is_some() { + if owner.is_custom() { let reaction = CallbackReaction::AttributeChanged( name, Some(old_value), diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 43f09bc60cf..2b06da5b6ce 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -371,6 +371,11 @@ impl Element { CustomElementState::Uncustomized } + /// <https://dom.spec.whatwg.org/#concept-element-custom> + pub(crate) fn is_custom(&self) -> bool { + self.get_custom_element_state() == CustomElementState::Custom + } + pub(crate) fn set_custom_element_definition(&self, definition: Rc<CustomElementDefinition>) { self.ensure_rare_data().custom_element_definition = Some(definition); } @@ -1580,7 +1585,7 @@ impl Element { MutationObserver::queue_a_mutation_record(&self.node, mutation); - if self.get_custom_element_definition().is_some() { + if self.is_custom() { let value = DOMString::from(&**attr.value()); let reaction = CallbackReaction::AttributeChanged(name, None, Some(value), namespace); ScriptThread::enqueue_callback_reaction(self, reaction, None); @@ -1772,9 +1777,11 @@ impl Element { MutationObserver::queue_a_mutation_record(&self.node, mutation); - let reaction = - CallbackReaction::AttributeChanged(name, Some(old_value), None, namespace); - ScriptThread::enqueue_callback_reaction(self, reaction, None); + if self.is_custom() { + let reaction = + CallbackReaction::AttributeChanged(name, Some(old_value), None, namespace); + ScriptThread::enqueue_callback_reaction(self, reaction, None); + } self.attrs.borrow_mut().remove(idx); attr.set_owner(None); @@ -2453,7 +2460,7 @@ impl ElementMethods<crate::DomTypeHolder> for Element { } // Step 4. - if self.get_custom_element_definition().is_some() { + if self.is_custom() { let old_name = old_attr.local_name().clone(); let old_value = DOMString::from(&**old_attr.value()); let new_value = DOMString::from(&**attr.value()); diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 6ae2c5b646f..6326b59f62d 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -422,7 +422,8 @@ impl Node { pub(crate) fn as_custom_element(&self) -> Option<DomRoot<Element>> { self.downcast::<Element>().and_then(|element| { - if element.get_custom_element_definition().is_some() { + if element.is_custom() { + assert!(element.get_custom_element_definition().is_some()); Some(DomRoot::from_ref(element)) } else { None @@ -2334,7 +2335,7 @@ impl Node { .filter_map(DomRoot::downcast::<Element>) { // Step 7.7.2, whatwg/dom#833 - if descendant.get_custom_element_definition().is_some() { + if descendant.is_custom() { if descendant.is_connected() { ScriptThread::enqueue_callback_reaction( &descendant, diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json index e54ddc40d22..de9221bf3ac 100644 --- a/tests/wpt/meta/MANIFEST.json +++ b/tests/wpt/meta/MANIFEST.json @@ -612804,7 +612804,7 @@ ] ], "custom-element-reaction-queue.html": [ - "246b15a0af36cffa0b64f1d57e4208538b92bdd7", + "eb8366f2b415894f396da613987982ae41ffe0b6", [ null, {} diff --git a/tests/wpt/meta/custom-elements/custom-element-reaction-queue.html.ini b/tests/wpt/meta/custom-elements/custom-element-reaction-queue.html.ini deleted file mode 100644 index bd5d04c5256..00000000000 --- a/tests/wpt/meta/custom-elements/custom-element-reaction-queue.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[custom-element-reaction-queue.html] - [Upgrading a custom element must not invoke attributeChangedCallback for the attribute that is changed during upgrading] - expected: FAIL - diff --git a/tests/wpt/tests/custom-elements/custom-element-reaction-queue.html b/tests/wpt/tests/custom-elements/custom-element-reaction-queue.html index 246b15a0af3..eb8366f2b41 100644 --- a/tests/wpt/tests/custom-elements/custom-element-reaction-queue.html +++ b/tests/wpt/tests/custom-elements/custom-element-reaction-queue.html @@ -85,6 +85,60 @@ test_with_window(function (contentWindow) { test_with_window(function (contentWindow) { const contentDocument = contentWindow.document; + contentDocument.write('<test-element>'); + + const element = contentDocument.querySelector('test-element'); + assert_equals(Object.getPrototypeOf(element), contentWindow.HTMLElement.prototype); + + let log = []; + class TestElement extends contentWindow.HTMLElement { + constructor() { + super(); + this.remove(); + log.push(create_constructor_log(this)); + } + connectedCallback(...args) { + log.push(create_connected_callback_log(this, ...args)); + } + disconnectedCallback(...args) { + log.push(create_disconnected_callback_log(this, ...args)); + } + } + contentWindow.customElements.define('test-element', TestElement); + assert_equals(Object.getPrototypeOf(element), TestElement.prototype); + + assert_equals(log.length, 2); + assert_constructor_log_entry(log[0], element); + assert_connected_log_entry(log[1], element); +}, 'Upgrading a custom element must not invoke disconnectedCallback if the element is disconnected during upgrading'); + +test_with_window(function (contentWindow) { + const contentDocument = contentWindow.document; + const element = contentDocument.createElement('test-element'); + assert_equals(Object.getPrototypeOf(element), contentWindow.HTMLElement.prototype); + + let log = []; + class TestElement extends contentWindow.HTMLElement { + constructor() { + super(); + contentDocument.documentElement.appendChild(this); + log.push(create_constructor_log(this)); + } + connectedCallback(...args) { + log.push(create_connected_callback_log(this, ...args)); + } + } + contentWindow.customElements.define('test-element', TestElement); + contentWindow.customElements.upgrade(element); + + assert_equals(Object.getPrototypeOf(element), TestElement.prototype); + + assert_equals(log.length, 1); + assert_constructor_log_entry(log[0], element); +}, 'Upgrading a disconnected custom element must not invoke connectedCallback if the element is connected during upgrading'); + +test_with_window(function (contentWindow) { + const contentDocument = contentWindow.document; contentDocument.write('<test-element id="first-element">'); contentDocument.write('<test-element id="second-element">'); |