diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 17e1549c64d..2f27b11bc87 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -2241,6 +2241,12 @@ impl ElementMethods for Element { .or_init(|| DOMTokenList::new(self, &local_name!("class"), None)) } + // https://dom.spec.whatwg.org/#dom-element-slot + make_getter!(Slot, "slot"); + + // https://dom.spec.whatwg.org/#dom-element-slot + make_setter!(SetSlot, "slot"); + // https://dom.spec.whatwg.org/#dom-element-attributes fn Attributes(&self) -> DomRoot { self.attr_list @@ -3666,7 +3672,12 @@ impl VirtualMethods for Element { // Update slottable data let cx = GlobalScope::get_cx(); rooted!(in(*cx) let slottable = Slottable::Element(Dom::from_ref(self))); - slottable.update_slot_name(attr, mutation, CanGc::note()) + + // Slottable name change steps from https://dom.spec.whatwg.org/#light-tree-slotables + if let Some(assigned_slot) = slottable.assigned_slot() { + assigned_slot.assign_slottables(); + } + slottable.assign_a_slot(); }, _ => { // FIXME(emilio): This is pretty dubious, and should be done in diff --git a/components/script/dom/htmlslotelement.rs b/components/script/dom/htmlslotelement.rs index f60d5f3b5b1..2e28aeec9c8 100644 --- a/components/script/dom/htmlslotelement.rs +++ b/components/script/dom/htmlslotelement.rs @@ -8,8 +8,6 @@ use dom_struct::dom_struct; use html5ever::{local_name, namespace_url, ns, LocalName, Prefix}; use js::gc::{RootedGuard, RootedVec}; use js::rust::HandleObject; -use servo_atoms::Atom; -use style::attr::AttrValue; use crate::dom::attr::Attr; use crate::dom::bindings::codegen::Bindings::HTMLSlotElementBinding::{ @@ -382,58 +380,6 @@ impl Slottable { None } - /// Slottable name change steps from - pub(crate) fn update_slot_name(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) { - debug_assert!(matches!(self, Self::Element(_))); - - // Step 1. If localName is slot and namespace is null: - // NOTE: This is done by the caller - let old_value = if let AttributeMutation::Set(old_name) = mutation { - old_name.and_then(|attr| match attr { - AttrValue::String(s) => Some(s.clone()), - _ => None, - }) - } else { - None - }; - let value = mutation.new_value(attr).and_then(|attr| match &*attr { - AttrValue::String(s) => Some(s.clone()), - _ => None, - }); - - // Step 1.1 If value is oldValue, then return. - if value == old_value { - return; - } - - // Step 1.2 If value is null and oldValue is the empty string, then return. - if value.is_none() && old_value.as_ref().is_some_and(|s| s.is_empty()) { - return; - } - - // Step 1.3 If value is the empty string and oldValue is null, then return. - if old_value.is_none() && value.as_ref().is_some_and(|s| s.is_empty()) { - return; - } - - // Step 1.4 If value is null or the empty string, then set element’s name to the empty string. - if value.as_ref().is_none_or(|s| s.is_empty()) { - self.set_name(DOMString::new(), can_gc); - } - // Step 1.5 Otherwise, set element’s name to value. - else { - self.set_name(DOMString::from(value.unwrap_or_default()), can_gc); - } - - // Step 1.6 If element is assigned, then run assign slottables for element’s assigned slot. - if let Some(assigned_slot) = self.assigned_slot() { - assigned_slot.assign_slottables(); - } - - // Step 1.7 Run assign a slot for element. - self.assign_a_slot(); - } - /// pub(crate) fn assign_a_slot(&self) { // Step 1. Let slot be the result of finding a slot with slottable. @@ -452,7 +398,7 @@ impl Slottable { } } - fn assigned_slot(&self) -> Option> { + pub(crate) fn assigned_slot(&self) -> Option> { match self { Self::Element(element) => element.assigned_slot(), Self::Text(text) => { @@ -501,30 +447,13 @@ impl Slottable { } } - fn set_name(&self, name: DOMString, can_gc: CanGc) { - // NOTE: Only elements have non-empty names - let Self::Element(element) = self else { - return; - }; - let element = element.as_rooted(); - element.set_attribute( - &local_name!("name"), - AttrValue::Atom(Atom::from(name)), - can_gc, - ); - } - fn name(&self) -> DOMString { // NOTE: Only elements have non-empty names let Self::Element(element) = self else { return DOMString::new(); }; - element - .name_attribute() - .map(|a| DOMString::from(a.as_ref())) - .unwrap_or_default() - .clone() + element.get_string_attribute(&local_name!("slot")) } } diff --git a/components/script_bindings/webidls/Element.webidl b/components/script_bindings/webidls/Element.webidl index 60a6db4e4e1..845728b110d 100644 --- a/components/script_bindings/webidls/Element.webidl +++ b/components/script_bindings/webidls/Element.webidl @@ -30,6 +30,7 @@ interface Element : Node { attribute DOMString className; [SameObject, PutForwards=value] readonly attribute DOMTokenList classList; + [CEReactions, Unscopable] attribute DOMString slot; [Pure] boolean hasAttributes(); diff --git a/tests/wpt/meta/custom-elements/reactions/Element.html.ini b/tests/wpt/meta/custom-elements/reactions/Element.html.ini deleted file mode 100644 index bacc3729edc..00000000000 --- a/tests/wpt/meta/custom-elements/reactions/Element.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[Element.html] - [slot on Element must enqueue an attributeChanged reaction when adding slot content attribute] - expected: FAIL - - [slot on Element must enqueue an attributeChanged reaction when replacing an existing attribute] - expected: FAIL diff --git a/tests/wpt/meta/dom/idlharness.window.js.ini b/tests/wpt/meta/dom/idlharness.window.js.ini index d08fa6382fc..f98cee42af9 100644 --- a/tests/wpt/meta/dom/idlharness.window.js.ini +++ b/tests/wpt/meta/dom/idlharness.window.js.ini @@ -56,9 +56,6 @@ [CharacterData interface: operation remove()] expected: FAIL - [Element interface: element must inherit property "slot" with the proper type] - expected: FAIL - [AbortController interface: new AbortController() must inherit property "signal" with the proper type] expected: FAIL diff --git a/tests/wpt/meta/shadow-dom/HTMLSlotElement-interface.html.ini b/tests/wpt/meta/shadow-dom/HTMLSlotElement-interface.html.ini index edb9c4274b9..23a181aca59 100644 --- a/tests/wpt/meta/shadow-dom/HTMLSlotElement-interface.html.ini +++ b/tests/wpt/meta/shadow-dom/HTMLSlotElement-interface.html.ini @@ -8,15 +8,6 @@ [assignedNodes({"flattened":true}) must return the list of assigned nodes when none of the assigned nodes themselves are slots] expected: FAIL - [assignedNodes() must update when slot and name attributes are modified] - expected: FAIL - - [assignedNodes({"flattened":false}) must update when slot and name attributes are modified] - expected: FAIL - - [assignedNodes({"flattened":true}) must update when slot and name attributes are modified] - expected: FAIL - [assignedNodes() must update when slot elements are inserted or removed] expected: FAIL diff --git a/tests/wpt/meta/shadow-dom/Slottable-mixin.html.ini b/tests/wpt/meta/shadow-dom/Slottable-mixin.html.ini deleted file mode 100644 index b76c3d007b9..00000000000 --- a/tests/wpt/meta/shadow-dom/Slottable-mixin.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[Slottable-mixin.html] - [assignedSlot must return the assigned slot] - expected: FAIL diff --git a/tests/wpt/meta/shadow-dom/slotchange.html.ini b/tests/wpt/meta/shadow-dom/slotchange.html.ini index 8ba59d0d187..6ebeaa0a8b2 100644 --- a/tests/wpt/meta/shadow-dom/slotchange.html.ini +++ b/tests/wpt/meta/shadow-dom/slotchange.html.ini @@ -3,8 +3,5 @@ [slotchange event: Append a child to a host.] expected: TIMEOUT - [slotchange event: A slot is assigned to another slot.] - expected: TIMEOUT - [slotchange event: Child content is added to nested slots.] expected: TIMEOUT diff --git a/tests/wpt/meta/shadow-dom/slots.html.ini b/tests/wpt/meta/shadow-dom/slots.html.ini index 65c0eaf8030..e460db55d88 100644 --- a/tests/wpt/meta/shadow-dom/slots.html.ini +++ b/tests/wpt/meta/shadow-dom/slots.html.ini @@ -31,3 +31,6 @@ [Slots: Mutation: Change slot slot= attribute.] expected: FAIL + + [Slots: Mutation: Remove a slot.] + expected: FAIL