mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Implement declarative shadow dom (#34964)
* Implement declarative shadow dom Signed-off-by: batu_hoang <longvatrong111@gmail.com> * Set allowDeclarativeShadowRoots false for innerHTML Signed-off-by: batu_hoang <longvatrong111@gmail.com> * Enable allowDeclarativeShadowRoots for Document Signed-off-by: batu_hoang <longvatrong111@gmail.com> * Expose HTMLTemplateElement to js Signed-off-by: batu_hoang <longvatrong111@gmail.com> * Implemenet setHTMLUnsafe and add more test cases Signed-off-by: batu_hoang <longvatrong111@gmail.com> * Declarative shadow dom: minor updates and expected test result update Signed-off-by: batu_hoang <longvatrong111@gmail.com> * Shadow-dom: add more test cases Signed-off-by: batu_hoang <longvatrong111@gmail.com> * Update comments according to the spec Signed-off-by: batu_hoang <longvatrong111@gmail.com> * Bump html5ever version Signed-off-by: batu_hoang <longvatrong111@gmail.com> --------- Signed-off-by: batu_hoang <longvatrong111@gmail.com>
This commit is contained in:
parent
f483a3d34b
commit
28c8c1df0c
44 changed files with 360 additions and 1965 deletions
|
@ -44,6 +44,9 @@ use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
|
|||
use crate::dom::bindings::codegen::Bindings::HTMLImageElementBinding::HTMLImageElementMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
|
||||
ShadowRootMode, SlotAssignmentMode,
|
||||
};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
|
@ -53,6 +56,7 @@ use crate::dom::bindings::str::{DOMString, USVString};
|
|||
use crate::dom::characterdata::CharacterData;
|
||||
use crate::dom::comment::Comment;
|
||||
use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
|
||||
use crate::dom::documentfragment::DocumentFragment;
|
||||
use crate::dom::documenttype::DocumentType;
|
||||
use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
|
||||
use crate::dom::htmlformelement::{FormControlElementHelpers, HTMLFormElement};
|
||||
|
@ -64,6 +68,7 @@ use crate::dom::node::{Node, ShadowIncluding};
|
|||
use crate::dom::performanceentry::PerformanceEntry;
|
||||
use crate::dom::performancenavigationtiming::PerformanceNavigationTiming;
|
||||
use crate::dom::processinginstruction::ProcessingInstruction;
|
||||
use crate::dom::shadowroot::IsUserAgentWidget;
|
||||
use crate::dom::text::Text;
|
||||
use crate::dom::virtualmethods::vtable_for;
|
||||
use crate::network_listener::PreInvoke;
|
||||
|
@ -191,6 +196,7 @@ impl ServoParser {
|
|||
pub(crate) fn parse_html_fragment(
|
||||
context: &Element,
|
||||
input: DOMString,
|
||||
allow_declarative_shadow_roots: bool,
|
||||
can_gc: CanGc,
|
||||
) -> impl Iterator<Item = DomRoot<Node>> + use<'_> {
|
||||
let context_node = context.upcast::<Node>();
|
||||
|
@ -218,6 +224,7 @@ impl ServoParser {
|
|||
None,
|
||||
Default::default(),
|
||||
false,
|
||||
allow_declarative_shadow_roots,
|
||||
Some(context_document.insecure_requests_policy()),
|
||||
can_gc,
|
||||
);
|
||||
|
@ -1184,18 +1191,23 @@ impl TreeSink for Sink {
|
|||
&self,
|
||||
name: QualName,
|
||||
attrs: Vec<Attribute>,
|
||||
_flags: ElementFlags,
|
||||
flags: ElementFlags,
|
||||
) -> Dom<Node> {
|
||||
let attrs = attrs
|
||||
.into_iter()
|
||||
.map(|attr| ElementAttribute::new(attr.name, DOMString::from(String::from(attr.value))))
|
||||
.collect();
|
||||
let parsing_algorithm = if flags.template {
|
||||
ParsingAlgorithm::Fragment
|
||||
} else {
|
||||
self.parsing_algorithm
|
||||
};
|
||||
let element = create_element_for_token(
|
||||
name,
|
||||
attrs,
|
||||
&self.document,
|
||||
ElementCreator::ParserCreated(self.current_line.get()),
|
||||
self.parsing_algorithm,
|
||||
parsing_algorithm,
|
||||
CanGc::note(),
|
||||
);
|
||||
Dom::from_ref(element.upcast())
|
||||
|
@ -1381,6 +1393,91 @@ impl TreeSink for Sink {
|
|||
let node = DomRoot::from_ref(&**node);
|
||||
vtable_for(&node).pop();
|
||||
}
|
||||
|
||||
fn allow_declarative_shadow_roots(&self, intended_parent: &Dom<Node>) -> bool {
|
||||
intended_parent.owner_doc().allow_declarative_shadow_roots()
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#parsing-main-inhead>
|
||||
/// A start tag whose tag name is "template"
|
||||
/// Attach shadow path
|
||||
fn attach_declarative_shadow(
|
||||
&self,
|
||||
host: &Dom<Node>,
|
||||
template: &Dom<Node>,
|
||||
attrs: Vec<Attribute>,
|
||||
) -> Result<(), String> {
|
||||
let host_element = host.downcast::<Element>().unwrap();
|
||||
|
||||
if host_element.shadow_root().is_some() {
|
||||
return Err(String::from("Already in a shadow host"));
|
||||
}
|
||||
|
||||
let template_element = template.downcast::<HTMLTemplateElement>().unwrap();
|
||||
|
||||
// Step 3. Let mode be template start tag's shadowrootmode attribute's value.
|
||||
// Step 4. Let clonable be true if template start tag has a shadowrootclonable attribute; otherwise false.
|
||||
// Step 5. Let delegatesfocus be true if template start tag
|
||||
// has a shadowrootdelegatesfocus attribute; otherwise false.
|
||||
// Step 6. Let serializable be true if template start tag
|
||||
// has a shadowrootserializable attribute; otherwise false.
|
||||
let mut shadow_root_mode = ShadowRootMode::Open;
|
||||
let mut clonable = false;
|
||||
let mut _delegatesfocus = false;
|
||||
let mut _serializable = false;
|
||||
|
||||
let attrs: Vec<ElementAttribute> = attrs
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|attr| ElementAttribute::new(attr.name, DOMString::from(String::from(attr.value))))
|
||||
.collect();
|
||||
|
||||
attrs
|
||||
.iter()
|
||||
.for_each(|attr: &ElementAttribute| match attr.name.local {
|
||||
local_name!("shadowrootmode") => {
|
||||
if attr.value.str().eq_ignore_ascii_case("open") {
|
||||
shadow_root_mode = ShadowRootMode::Open;
|
||||
} else if attr.value.str().eq_ignore_ascii_case("closed") {
|
||||
shadow_root_mode = ShadowRootMode::Closed;
|
||||
} else {
|
||||
unreachable!("shadowrootmode value is not open nor closed");
|
||||
}
|
||||
},
|
||||
local_name!("shadowrootclonable") => {
|
||||
clonable = true;
|
||||
},
|
||||
local_name!("shadowrootdelegatesfocus") => {
|
||||
_delegatesfocus = true;
|
||||
},
|
||||
local_name!("shadowrootserializable") => {
|
||||
_serializable = true;
|
||||
},
|
||||
_ => {},
|
||||
});
|
||||
|
||||
// Step 8.1. Attach a shadow root with declarative shadow host element,
|
||||
// mode, clonable, serializable, delegatesFocus, and "named".
|
||||
match host_element.attach_shadow(
|
||||
IsUserAgentWidget::No,
|
||||
shadow_root_mode,
|
||||
clonable,
|
||||
SlotAssignmentMode::Manual,
|
||||
CanGc::note(),
|
||||
) {
|
||||
Ok(shadow_root) => {
|
||||
// Step 8.3. Set shadow's declarative to true.
|
||||
shadow_root.set_declarative(true);
|
||||
|
||||
// Set 8.4. Set template's template contents property to shadow.
|
||||
let shadow = shadow_root.upcast::<DocumentFragment>();
|
||||
template_element.set_contents(Some(shadow));
|
||||
|
||||
Ok(())
|
||||
},
|
||||
Err(_) => Err(String::from("Attaching shadow fails")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#create-an-element-for-the-token>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue