aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/element.rs6
-rw-r--r--components/script/dom/htmlmediaelement.rs2
-rw-r--r--components/script/dom/node.rs55
-rw-r--r--components/script/dom/shadowroot.rs25
-rw-r--r--components/script/dom/webidls/Element.webidl2
-rw-r--r--components/script/dom/webidls/ShadowRoot.webidl6
6 files changed, 81 insertions, 15 deletions
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 75f8f4d4b20..594c63bbab6 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -507,8 +507,10 @@ impl Element {
/// <https://dom.spec.whatwg.org/#dom-element-attachshadow>
pub fn attach_shadow(
&self,
+ // TODO: remove is_ua_widget argument
is_ua_widget: IsUserAgentWidget,
mode: ShadowRootMode,
+ clonable: bool,
) -> Fallible<DomRoot<ShadowRoot>> {
// Step 1.
if self.namespace != ns!(html) {
@@ -546,7 +548,7 @@ impl Element {
}
// Steps 4, 5 and 6.
- let shadow_root = ShadowRoot::new(self, &self.node.owner_doc(), mode);
+ let shadow_root = ShadowRoot::new(self, &self.node.owner_doc(), mode, clonable);
self.ensure_rare_data().shadow_root = Some(Dom::from_ref(&*shadow_root));
shadow_root
.upcast::<Node>()
@@ -3034,7 +3036,7 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
fn AttachShadow(&self, init: &ShadowRootInit) -> Fallible<DomRoot<ShadowRoot>> {
// Step 1. Run attach a shadow root with this, init["mode"], init["clonable"], init["serializable"],
// init["delegatesFocus"], and init["slotAssignment"].
- let shadow_root = self.attach_shadow(IsUserAgentWidget::No, init.mode)?;
+ let shadow_root = self.attach_shadow(IsUserAgentWidget::No, init.mode, init.clonable)?;
// Step 2. Return this’s shadow root.
Ok(shadow_root)
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index e7b2fdbb30e..18bca9decee 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -1910,7 +1910,7 @@ impl HTMLMediaElement {
return;
}
let shadow_root = element
- .attach_shadow(IsUserAgentWidget::Yes, ShadowRootMode::Closed)
+ .attach_shadow(IsUserAgentWidget::Yes, ShadowRootMode::Closed, false)
.unwrap();
let document = document_from_node(self);
let script = HTMLScriptElement::new(
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 00501ea1718..3c7df12b633 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -98,7 +98,7 @@ use crate::dom::nodelist::NodeList;
use crate::dom::processinginstruction::ProcessingInstruction;
use crate::dom::range::WeakRangeVec;
use crate::dom::raredata::NodeRareData;
-use crate::dom::shadowroot::{LayoutShadowRootHelpers, ShadowRoot};
+use crate::dom::shadowroot::{IsUserAgentWidget, LayoutShadowRootHelpers, ShadowRoot};
use crate::dom::stylesheetlist::StyleSheetListOwner;
use crate::dom::svgsvgelement::{LayoutSVGSVGElementHelpers, SVGSVGElement};
use crate::dom::text::Text;
@@ -2247,13 +2247,13 @@ impl Node {
clone_children: CloneChildrenFlag,
can_gc: CanGc,
) -> DomRoot<Node> {
- // Step 1.
+ // Step 1. If document is not given, let document be node’s node document.
let document = match maybe_doc {
Some(doc) => DomRoot::from_ref(doc),
None => node.owner_doc(),
};
- // Step 2.
+ // Step 2. / Step 3.
// XXXabinader: clone() for each node as trait?
let copy: DomRoot<Node> = match node.type_id() {
NodeTypeId::DocumentType => {
@@ -2337,14 +2337,15 @@ impl Node {
},
};
- // Step 3.
+ // Step 4. Set copy’s node document and document to copy, if copy is a document,
+ // and set copy’s node document to document otherwise.
let document = match copy.downcast::<Document>() {
Some(doc) => DomRoot::from_ref(doc),
None => DomRoot::from_ref(&*document),
};
assert!(copy.owner_doc() == document);
- // Step 4 (some data already copied in step 2).
+ // TODO: The spec tells us to do this in step 3.
match node.type_id() {
NodeTypeId::Document(_) => {
let node_doc = node.downcast::<Document>().unwrap();
@@ -2370,10 +2371,12 @@ impl Node {
_ => (),
}
- // Step 5: cloning steps.
+ // Step 5: Run any cloning steps defined for node in other applicable specifications and pass copy,
+ // node, document, and the clone children flag if set, as parameters.
vtable_for(node).cloning_steps(&copy, maybe_doc, clone_children);
- // Step 6.
+ // Step 6. If the clone children flag is set, then for each child child of node, in tree order: append the
+ // result of cloning child with document and the clone children flag set, to copy.
if clone_children == CloneChildrenFlag::CloneChildren {
for child in node.children() {
let child_copy = Node::clone(&child, Some(&document), clone_children, can_gc);
@@ -2381,7 +2384,43 @@ impl Node {
}
}
- // Step 7.
+ // Step 7. If node is a shadow host whose shadow root’s clonable is true:
+ // NOTE: Only elements can be shadow hosts
+ if matches!(node.type_id(), NodeTypeId::Element(_)) {
+ let node_elem = node.downcast::<Element>().unwrap();
+ let copy_elem = copy.downcast::<Element>().unwrap();
+
+ if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
+ // Step 7.1 Assert: copy is not a shadow host.
+ assert!(!copy_elem.is_shadow_host());
+
+ // Step 7.2 Run attach a shadow root with copy, node’s shadow root’s mode, true,
+ // node’s shadow root’s serializable, node’s shadow root’s delegates focus,
+ // and node’s shadow root’s slot assignment.
+ let copy_shadow_root =
+ copy_elem.attach_shadow(IsUserAgentWidget::No, shadow_root.Mode(), true)
+ .expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
+
+ // TODO: Step 7.3 Set copy’s shadow root’s declarative to node’s shadow root’s declarative.
+
+ // Step 7.4 For each child child of node’s shadow root, in tree order: append the result of
+ // cloning child with document and the clone children flag set, to copy’s shadow root.
+ for child in shadow_root.upcast::<Node>().children() {
+ let child_copy = Node::clone(
+ &child,
+ Some(&document),
+ CloneChildrenFlag::CloneChildren,
+ can_gc,
+ );
+
+ // TODO: Should we handle the error case here and in step 6?
+ let _inserted_node =
+ Node::pre_insert(&child_copy, copy_shadow_root.upcast::<Node>(), None);
+ }
+ }
+ }
+
+ // Step 8. Return copy.
copy
}
diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs
index da918ec0f51..77c4ba99b2a 100644
--- a/components/script/dom/shadowroot.rs
+++ b/components/script/dom/shadowroot.rs
@@ -55,11 +55,19 @@ pub struct ShadowRoot {
/// <https://dom.spec.whatwg.org/#dom-shadowroot-mode>
mode: ShadowRootMode,
+
+ /// <https://dom.spec.whatwg.org/#dom-shadowroot-clonable>
+ clonable: bool,
}
impl ShadowRoot {
#[allow(crown::unrooted_must_root)]
- fn new_inherited(host: &Element, document: &Document, mode: ShadowRootMode) -> ShadowRoot {
+ fn new_inherited(
+ host: &Element,
+ document: &Document,
+ mode: ShadowRootMode,
+ clonable: bool,
+ ) -> ShadowRoot {
let document_fragment = DocumentFragment::new_inherited(document);
let node = document_fragment.upcast::<Node>();
node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, true);
@@ -77,12 +85,18 @@ impl ShadowRoot {
stylesheet_list: MutNullableDom::new(None),
window: Dom::from_ref(document.window()),
mode,
+ clonable,
}
}
- pub fn new(host: &Element, document: &Document, mode: ShadowRootMode) -> DomRoot<ShadowRoot> {
+ pub fn new(
+ host: &Element,
+ document: &Document,
+ mode: ShadowRootMode,
+ clonable: bool,
+ ) -> DomRoot<ShadowRoot> {
reflect_dom_object(
- Box::new(ShadowRoot::new_inherited(host, document, mode)),
+ Box::new(ShadowRoot::new_inherited(host, document, mode, clonable)),
document.window(),
)
}
@@ -238,6 +252,11 @@ impl ShadowRootMethods<crate::DomTypeHolder> for ShadowRoot {
self.mode
}
+ /// <https://dom.spec.whatwg.org/#dom-shadowroot-clonable>
+ fn Clonable(&self) -> bool {
+ self.clonable
+ }
+
/// <https://dom.spec.whatwg.org/#dom-shadowroot-host>
fn Host(&self) -> DomRoot<Element> {
let host = self.host.get();
diff --git a/components/script/dom/webidls/Element.webidl b/components/script/dom/webidls/Element.webidl
index 99d17117221..1a99d5ec480 100644
--- a/components/script/dom/webidls/Element.webidl
+++ b/components/script/dom/webidls/Element.webidl
@@ -91,7 +91,7 @@ dictionary ShadowRootInit {
required ShadowRootMode mode;
// boolean delegatesFocus = false;
// SlotAssignmentMode slotAssignment = "named";
- // boolean clonable = false;
+ boolean clonable = false;
// boolean serializable = false;
};
diff --git a/components/script/dom/webidls/ShadowRoot.webidl b/components/script/dom/webidls/ShadowRoot.webidl
index a1ecdc5c10f..40301f48517 100644
--- a/components/script/dom/webidls/ShadowRoot.webidl
+++ b/components/script/dom/webidls/ShadowRoot.webidl
@@ -9,9 +9,15 @@
[Exposed=Window]
interface ShadowRoot : DocumentFragment {
readonly attribute ShadowRootMode mode;
+ // readonly attribute boolean delegatesFocus;
+ // readonly attribute SlotAssignmentMode slotAssignment;
+ readonly attribute boolean clonable;
+ // readonly attribute boolean serializable;
readonly attribute Element host;
+ // attribute EventHandler onslotchange;
};
+
enum ShadowRootMode { "open", "closed"};
// enum SlotAssignmentMode { "manual", "named" };