mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Implement QuerySelectorIterator (fixes #4082)
This commit is contained in:
parent
a2f7e0fbd6
commit
3ba4bba28b
1 changed files with 45 additions and 11 deletions
|
@ -50,7 +50,7 @@ use devtools_traits::NodeInfo;
|
|||
use script_traits::UntrustedNodeAddress;
|
||||
use servo_util::geometry::Au;
|
||||
use servo_util::str::{DOMString, null_str_as_empty};
|
||||
use style::{parse_selector_list_from_str, matches};
|
||||
use style::{parse_selector_list_from_str, matches, SelectorList};
|
||||
|
||||
use js::jsapi::{JSContext, JSObject, JSTracer, JSRuntime};
|
||||
use js::jsfriendapi;
|
||||
|
@ -377,6 +377,29 @@ impl<'a> PrivateNodeHelpers for JSRef<'a, Node> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct QuerySelectorIterator<'a> {
|
||||
selectors: SelectorList,
|
||||
iterator: TreeIterator<'a>,
|
||||
}
|
||||
|
||||
impl<'a> QuerySelectorIterator<'a> {
|
||||
unsafe fn new(iter: TreeIterator<'a>, selectors: SelectorList) -> QuerySelectorIterator<'a> {
|
||||
QuerySelectorIterator {
|
||||
selectors: selectors,
|
||||
iterator: iter,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator<JSRef<'a, Node>> for QuerySelectorIterator<'a> {
|
||||
fn next(&mut self) -> Option<JSRef<'a, Node>> {
|
||||
let selectors = &self.selectors;
|
||||
// TODO(cgaebel): Is it worth it to build a bloom filter here
|
||||
// (instead of passing `None`)? Probably.
|
||||
self.iterator.find(|node| node.is_element() && matches(selectors, node, &mut None))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NodeHelpers<'a> {
|
||||
fn ancestors(self) -> AncestorIterator<'a>;
|
||||
fn children(self) -> NodeChildrenIterator<'a>;
|
||||
|
@ -449,6 +472,7 @@ pub trait NodeHelpers<'a> {
|
|||
fn get_content_boxes(self) -> Vec<Rect<Au>>;
|
||||
|
||||
fn query_selector(self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>>;
|
||||
unsafe fn query_selector_iter(self, selectors: DOMString) -> Fallible<QuerySelectorIterator<'a>>;
|
||||
fn query_selector_all(self, selectors: DOMString) -> Fallible<Temporary<NodeList>>;
|
||||
|
||||
fn remove_self(self);
|
||||
|
@ -719,8 +743,10 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> {
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
// http://dom.spec.whatwg.org/#dom-parentnode-queryselectorall
|
||||
fn query_selector_all(self, selectors: DOMString) -> Fallible<Temporary<NodeList>> {
|
||||
/// Get an iterator over all nodes which match a set of selectors
|
||||
/// Be careful not to do anything which may manipulate the DOM tree whilst iterating, otherwise
|
||||
/// the iterator may be invalidated
|
||||
unsafe fn query_selector_iter(self, selectors: DOMString) -> Fallible<QuerySelectorIterator<'a>> {
|
||||
// Step 1.
|
||||
let nodes;
|
||||
let root = self.ancestors().last().unwrap_or(self.clone());
|
||||
|
@ -728,17 +754,25 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> {
|
|||
// Step 2.
|
||||
Err(()) => return Err(Syntax),
|
||||
// Step 3.
|
||||
Ok(ref selectors) => {
|
||||
nodes = root.traverse_preorder().filter(
|
||||
// TODO(cgaebel): Is it worth it to build a bloom filter here
|
||||
// (instead of passing `None`)? Probably.
|
||||
|node| node.is_element() && matches(selectors, node, &mut None)).collect()
|
||||
Ok(selectors) => {
|
||||
nodes = QuerySelectorIterator::new(root.traverse_preorder(), selectors);
|
||||
}
|
||||
}
|
||||
let window = window_from_node(self).root();
|
||||
Ok(NodeList::new_simple_list(*window, nodes))
|
||||
};
|
||||
Ok(nodes)
|
||||
}
|
||||
|
||||
// http://dom.spec.whatwg.org/#dom-parentnode-queryselectorall
|
||||
fn query_selector_all(self, selectors: DOMString) -> Fallible<Temporary<NodeList>> {
|
||||
// Step 1.
|
||||
unsafe {
|
||||
self.query_selector_iter(selectors).map(|mut iter| {
|
||||
let window = window_from_node(self).root();
|
||||
NodeList::new_simple_list(*window, iter.collect())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn ancestors(self) -> AncestorIterator<'a> {
|
||||
AncestorIterator {
|
||||
current: self.parent_node.get().map(|node| (*node.root()).clone()),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue