mirror of
https://github.com/servo/servo.git
synced 2025-08-07 22:45:34 +01:00
Fix details children slotting and apply summary
Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>
This commit is contained in:
parent
a824b2781f
commit
9d469fc917
2 changed files with 74 additions and 49 deletions
|
@ -8,11 +8,11 @@ slot[id="internal-contents-slot"] {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
summary[id="internal-fallback-summary"] {
|
:host summary:first-of-type {
|
||||||
display: list-item;
|
display: list-item;
|
||||||
counter-increment: list-item 0;
|
counter-increment: list-item 0;
|
||||||
list-style: disclosure-closed inside;
|
list-style: disclosure-closed inside;
|
||||||
}
|
}
|
||||||
:host([open]) summary[id="internal-fallback-summary"] {
|
:host([open]) summary:first-of-type {
|
||||||
list-style-type: disclosure-open;
|
list-style-type: disclosure-open;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,8 +45,9 @@ const DEFAULT_SUMMARY: &str = "Details";
|
||||||
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
||||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||||
struct ShadowTree {
|
struct ShadowTree {
|
||||||
summary: Dom<HTMLSlotElement>,
|
summary_slot: Dom<HTMLSlotElement>,
|
||||||
descendants: Dom<HTMLSlotElement>,
|
descendants_slot: Dom<HTMLSlotElement>,
|
||||||
|
fallback_summary: Dom<HTMLElement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
@ -103,6 +104,7 @@ impl HTMLDetailsElement {
|
||||||
.expect("UA shadow tree was not created")
|
.expect("UA shadow tree was not created")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <https://html.spec.whatwg.org/multipage/rendering.html#the-details-and-summary-elements>
|
||||||
fn create_shadow_tree(&self, can_gc: CanGc) {
|
fn create_shadow_tree(&self, can_gc: CanGc) {
|
||||||
let document = self.owner_document();
|
let document = self.owner_document();
|
||||||
let root = self
|
let root = self
|
||||||
|
@ -118,6 +120,50 @@ impl HTMLDetailsElement {
|
||||||
)
|
)
|
||||||
.expect("Attaching UA shadow root failed");
|
.expect("Attaching UA shadow root failed");
|
||||||
|
|
||||||
|
// > The details element is expected to have an internal shadow tree with three child elements:
|
||||||
|
// > 1. The first child element is a slot that is expected to take the details element's first summary
|
||||||
|
// > element child, if any.
|
||||||
|
let summary_slot = HTMLSlotElement::new(local_name!("slot"), None, &document, None, can_gc);
|
||||||
|
summary_slot.upcast::<Element>().set_attribute(
|
||||||
|
&local_name!("id"),
|
||||||
|
AttrValue::from_atomic("internal-summary-slot".to_owned()),
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
root.upcast::<Node>()
|
||||||
|
.AppendChild(summary_slot.upcast::<Node>(), can_gc)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// > This element has a single child summary element called the default summary which has
|
||||||
|
// > text content that is implementation-defined (and probably locale-specific).
|
||||||
|
let fallback_summary =
|
||||||
|
HTMLElement::new(local_name!("summary"), None, &document, None, can_gc);
|
||||||
|
fallback_summary.upcast::<Element>().set_attribute(
|
||||||
|
&local_name!("id"),
|
||||||
|
AttrValue::from_atomic("internal-fallback-summary".to_owned()),
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
fallback_summary
|
||||||
|
.upcast::<Node>()
|
||||||
|
.SetTextContent(Some(DEFAULT_SUMMARY.into()), can_gc);
|
||||||
|
summary_slot
|
||||||
|
.upcast::<Node>()
|
||||||
|
.AppendChild(fallback_summary.upcast::<Node>(), can_gc)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// > 2. The second child element is a slot that is expected to take the details element's
|
||||||
|
// > remaining descendants, if any. This element has no contents.
|
||||||
|
let descendants_slot =
|
||||||
|
HTMLSlotElement::new(local_name!("slot"), None, &document, None, can_gc);
|
||||||
|
descendants_slot.upcast::<Element>().set_attribute(
|
||||||
|
&local_name!("id"),
|
||||||
|
AttrValue::from_atomic("internal-contents-slot".to_owned()),
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
root.upcast::<Node>()
|
||||||
|
.AppendChild(descendants_slot.upcast::<Node>(), can_gc)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// > 3. The third child element is either a link or style element with the following styles for the default summary:
|
||||||
let link_element = HTMLLinkElement::new(
|
let link_element = HTMLLinkElement::new(
|
||||||
local_name!("link"),
|
local_name!("link"),
|
||||||
None,
|
None,
|
||||||
|
@ -135,6 +181,8 @@ impl HTMLDetailsElement {
|
||||||
.AppendChild(link_element.upcast::<Node>(), can_gc)
|
.AppendChild(link_element.upcast::<Node>(), can_gc)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
// TODO(stevennovaryo): We need a mechanism for parsing and storing a stylesheet as
|
||||||
|
// we shouldn't reparse this each time we access the element.
|
||||||
let details_stylesheet = parse_details_stylesheet(
|
let details_stylesheet = parse_details_stylesheet(
|
||||||
link_element
|
link_element
|
||||||
.upcast::<Node>()
|
.upcast::<Node>()
|
||||||
|
@ -143,45 +191,11 @@ impl HTMLDetailsElement {
|
||||||
);
|
);
|
||||||
link_element.set_stylesheet(details_stylesheet.unwrap());
|
link_element.set_stylesheet(details_stylesheet.unwrap());
|
||||||
|
|
||||||
let summary_slot = HTMLSlotElement::new(local_name!("slot"), None, &document, None, can_gc);
|
|
||||||
summary_slot.upcast::<Element>().set_attribute(
|
|
||||||
&local_name!("id"),
|
|
||||||
AttrValue::from_atomic("internal-summary-slot".to_owned()),
|
|
||||||
can_gc,
|
|
||||||
);
|
|
||||||
root.upcast::<Node>()
|
|
||||||
.AppendChild(summary_slot.upcast::<Node>(), can_gc)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let fallback_summary =
|
|
||||||
HTMLElement::new(local_name!("summary"), None, &document, None, can_gc);
|
|
||||||
fallback_summary.upcast::<Element>().set_attribute(
|
|
||||||
&local_name!("id"),
|
|
||||||
AttrValue::from_atomic("internal-fallback-summary".to_owned()),
|
|
||||||
can_gc,
|
|
||||||
);
|
|
||||||
fallback_summary
|
|
||||||
.upcast::<Node>()
|
|
||||||
.SetTextContent(Some(DEFAULT_SUMMARY.into()), can_gc);
|
|
||||||
summary_slot
|
|
||||||
.upcast::<Node>()
|
|
||||||
.AppendChild(fallback_summary.upcast::<Node>(), can_gc)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let descendants_slot =
|
|
||||||
HTMLSlotElement::new(local_name!("slot"), None, &document, None, can_gc);
|
|
||||||
descendants_slot.upcast::<Element>().set_attribute(
|
|
||||||
&local_name!("id"),
|
|
||||||
AttrValue::from_atomic("internal-contents-slot".to_owned()),
|
|
||||||
can_gc,
|
|
||||||
);
|
|
||||||
root.upcast::<Node>()
|
|
||||||
.AppendChild(descendants_slot.upcast::<Node>(), can_gc)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let _ = self.shadow_tree.borrow_mut().insert(ShadowTree {
|
let _ = self.shadow_tree.borrow_mut().insert(ShadowTree {
|
||||||
summary: summary_slot.as_traced(),
|
summary_slot: summary_slot.as_traced(),
|
||||||
descendants: descendants_slot.as_traced(),
|
descendants_slot: descendants_slot.as_traced(),
|
||||||
|
fallback_summary: fallback_summary.as_traced(),
|
||||||
});
|
});
|
||||||
self.upcast::<Node>()
|
self.upcast::<Node>()
|
||||||
.dirty(crate::dom::node::NodeDamage::OtherNodeDamage);
|
.dirty(crate::dom::node::NodeDamage::OtherNodeDamage);
|
||||||
|
@ -199,16 +213,18 @@ impl HTMLDetailsElement {
|
||||||
fn update_shadow_tree_contents(&self, can_gc: CanGc) {
|
fn update_shadow_tree_contents(&self, can_gc: CanGc) {
|
||||||
let shadow_tree = self.shadow_tree(can_gc);
|
let shadow_tree = self.shadow_tree(can_gc);
|
||||||
|
|
||||||
if let Some(summary) = self.find_corresponding_summary_element() {
|
let mut discovered_first_summary_element = false;
|
||||||
shadow_tree
|
|
||||||
.summary
|
|
||||||
.Assign(vec![ElementOrText::Element(DomRoot::upcast(summary))]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut slottable_children = vec![];
|
let mut slottable_children = vec![];
|
||||||
|
|
||||||
|
// Assign all children to its corresponding slots.
|
||||||
for child in self.upcast::<Node>().children() {
|
for child in self.upcast::<Node>().children() {
|
||||||
if let Some(element) = child.downcast::<Element>() {
|
if let Some(element) = child.downcast::<Element>() {
|
||||||
if element.local_name() == &local_name!("summary") {
|
// Assign the first summary element to the summary slot.
|
||||||
|
if element.local_name() == &local_name!("summary") && !discovered_first_summary_element {
|
||||||
|
shadow_tree
|
||||||
|
.summary_slot
|
||||||
|
.Assign(vec![ElementOrText::Element(DomRoot::from_ref(element))]);
|
||||||
|
discovered_first_summary_element = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +235,16 @@ impl HTMLDetailsElement {
|
||||||
slottable_children.push(ElementOrText::Text(DomRoot::from_ref(text)));
|
slottable_children.push(ElementOrText::Text(DomRoot::from_ref(text)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shadow_tree.descendants.Assign(slottable_children);
|
shadow_tree.descendants_slot.Assign(slottable_children);
|
||||||
|
|
||||||
|
// If there are no summary element, assign fallback summary instead.
|
||||||
|
if !discovered_first_summary_element {
|
||||||
|
shadow_tree
|
||||||
|
.summary_slot
|
||||||
|
.Assign(vec![ElementOrText::Element(DomRoot::upcast(
|
||||||
|
shadow_tree.fallback_summary.as_rooted()
|
||||||
|
))]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue