Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make Document.getElementsByName a live collection #25428

Merged
merged 1 commit into from Feb 28, 2020
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

make Document.getElementsByName a live collection

  • Loading branch information
pshaughn committed Feb 15, 2020
commit 007a6cd05083c16abb0d0b129fe0dc7544530cda
@@ -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
@@ -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)))
}
}

This file was deleted.

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.