diff options
author | Patrick Shaughnessy <pshaughn@comcast.net> | 2020-01-03 16:45:29 -0500 |
---|---|---|
committer | Patrick Shaughnessy <pshaughn@comcast.net> | 2020-02-15 10:16:29 -0500 |
commit | 007a6cd05083c16abb0d0b129fe0dc7544530cda (patch) | |
tree | ba61f3fdbe6ad3b96870a25eb374870710ec75f7 /components | |
parent | 3475790fc23f939560f546901bf3082ebf20508a (diff) | |
download | servo-007a6cd05083c16abb0d0b129fe0dc7544530cda.tar.gz servo-007a6cd05083c16abb0d0b129fe0dc7544530cda.zip |
make Document.getElementsByName a live collection
Diffstat (limited to 'components')
-rw-r--r-- | components/script/dom/document.rs | 61 | ||||
-rw-r--r-- | components/script/dom/nodelist.rs | 42 |
2 files changed, 89 insertions, 14 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 3049d4f0bd6..7c6fb00ae9a 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -3056,14 +3056,56 @@ impl Document { self.redirect_count.set(count) } - fn create_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> DomRoot<NodeList> { + pub fn elements_by_name_count(&self, name: &DOMString) -> u32 { + if name.is_empty() { + return 0; + } + self.count_node_list(|n| Document::is_element_in_get_by_name(n, name)) + } + + pub fn nth_element_by_name(&self, index: u32, name: &DOMString) -> Option<DomRoot<Node>> { + if name.is_empty() { + return None; + } + self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name)) + } + + // Note that document.getByName does not match on the same conditions + // as the document named getter. + fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool { + let element = match node.downcast::<Element>() { + Some(element) => element, + None => return false, + }; + if element.namespace() != &ns!(html) { + return false; + } + element.get_name().map_or(false, |n| *n == **name) + } + + fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 { let doc = self.GetDocumentElement(); let maybe_node = doc.as_deref().map(Castable::upcast::<Node>); - let iter = maybe_node + maybe_node .iter() .flat_map(|node| node.traverse_preorder(ShadowIncluding::No)) - .filter(|node| callback(&node)); - NodeList::new_simple_list(&self.window, iter) + .filter(|node| callback(&node)) + .count() as u32 + } + + fn nth_in_node_list<F: Fn(&Node) -> bool>( + &self, + index: u32, + callback: F, + ) -> Option<DomRoot<Node>> { + let doc = self.GetDocumentElement(); + let maybe_node = doc.as_deref().map(Castable::upcast::<Node>); + maybe_node + .iter() + .flat_map(|node| node.traverse_preorder(ShadowIncluding::No)) + .filter(|node| callback(&node)) + .nth(index as usize) + .map(|n| DomRoot::from_ref(&*n)) } fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> { @@ -4244,16 +4286,7 @@ impl DocumentMethods for Document { // https://html.spec.whatwg.org/multipage/#dom-document-getelementsbyname fn GetElementsByName(&self, name: DOMString) -> DomRoot<NodeList> { - self.create_node_list(|node| { - let element = match node.downcast::<Element>() { - Some(element) => element, - None => return false, - }; - if element.namespace() != &ns!(html) { - return false; - } - element.get_name().map_or(false, |atom| *atom == *name) - }) + NodeList::new_elements_by_name_list(self.window(), self, name) } // https://html.spec.whatwg.org/multipage/#dom-document-images diff --git a/components/script/dom/nodelist.rs b/components/script/dom/nodelist.rs index 8c4f6d39358..5218d1b3026 100644 --- a/components/script/dom/nodelist.rs +++ b/components/script/dom/nodelist.rs @@ -7,6 +7,8 @@ use crate::dom::bindings::codegen::Bindings::NodeListBinding; use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; +use crate::dom::bindings::str::DOMString; +use crate::dom::document::Document; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlformelement::HTMLFormElement; use crate::dom::node::{ChildrenMutation, Node}; @@ -22,6 +24,7 @@ pub enum NodeListType { Children(ChildrenList), Labels(LabelsList), Radio(RadioList), + ElementsByName(ElementsByNameList), } // https://dom.spec.whatwg.org/#interface-nodelist @@ -74,6 +77,17 @@ impl NodeList { NodeList::new(window, NodeListType::Labels(LabelsList::new(element))) } + pub fn new_elements_by_name_list( + window: &Window, + document: &Document, + name: DOMString, + ) -> DomRoot<NodeList> { + NodeList::new( + window, + NodeListType::ElementsByName(ElementsByNameList::new(document, name)), + ) + } + pub fn empty(window: &Window) -> DomRoot<NodeList> { NodeList::new(window, NodeListType::Simple(vec![])) } @@ -87,6 +101,7 @@ impl NodeListMethods for NodeList { NodeListType::Children(ref list) => list.len(), NodeListType::Labels(ref list) => list.len(), NodeListType::Radio(ref list) => list.len(), + NodeListType::ElementsByName(ref list) => list.len(), } } @@ -99,6 +114,7 @@ impl NodeListMethods for NodeList { NodeListType::Children(ref list) => list.item(index), NodeListType::Labels(ref list) => list.item(index), NodeListType::Radio(ref list) => list.item(index), + NodeListType::ElementsByName(ref list) => list.item(index), } } @@ -401,3 +417,29 @@ impl RadioList { self.form.nth_for_radio_list(index, self.mode, &self.name) } } + +#[derive(JSTraceable, MallocSizeOf)] +#[unrooted_must_root_lint::must_root] +pub struct ElementsByNameList { + document: Dom<Document>, + name: DOMString, +} + +impl ElementsByNameList { + pub fn new(document: &Document, name: DOMString) -> ElementsByNameList { + ElementsByNameList { + document: Dom::from_ref(document), + name: name, + } + } + + pub fn len(&self) -> u32 { + self.document.elements_by_name_count(&self.name) + } + + pub fn item(&self, index: u32) -> Option<DomRoot<Node>> { + self.document + .nth_element_by_name(index, &self.name) + .and_then(|n| Some(DomRoot::from_ref(&*n))) + } +} |