auto merge of #2632 : brunoabinader/servo/document-queryselectorall, r=Ms2ger

Spec:
http://dom.spec.whatwg.org/#dom-parentnode-queryselectorall

Closes #851.
This commit is contained in:
bors-servo 2014-06-11 16:05:04 -04:00
commit baa97fe6e5
6 changed files with 116 additions and 3 deletions

View file

@ -330,6 +330,7 @@ pub trait DocumentMethods {
fn Location(&self) -> Temporary<Location>;
fn Children(&self) -> Temporary<HTMLCollection>;
fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>>;
fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<Temporary<NodeList>>;
fn GetOnclick(&self) -> Option<EventHandlerNonNull>;
fn SetOnclick(&self, listener: Option<EventHandlerNonNull>);
fn GetOnload(&self) -> Option<EventHandlerNonNull>;
@ -821,6 +822,12 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
root.query_selector(selectors)
}
// http://dom.spec.whatwg.org/#dom-parentnode-queryselectorall
fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<Temporary<NodeList>> {
let root: &JSRef<Node> = NodeCast::from_ref(self);
root.query_selector_all(selectors)
}
fn GetOnclick(&self) -> Option<EventHandlerNonNull> {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("click")

View file

@ -11,6 +11,7 @@ use dom::element::Element;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlcollection::HTMLCollection;
use dom::node::{DocumentFragmentNodeTypeId, Node, NodeHelpers, window_from_node};
use dom::nodelist::NodeList;
use dom::window::{Window, WindowMethods};
use servo_util::str::DOMString;
@ -49,6 +50,7 @@ impl DocumentFragment {
pub trait DocumentFragmentMethods {
fn Children(&self) -> Temporary<HTMLCollection>;
fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>>;
fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<Temporary<NodeList>>;
}
impl<'a> DocumentFragmentMethods for JSRef<'a, DocumentFragment> {
@ -63,4 +65,11 @@ impl<'a> DocumentFragmentMethods for JSRef<'a, DocumentFragment> {
let root: &JSRef<Node> = NodeCast::from_ref(self);
root.query_selector(selectors)
}
// http://dom.spec.whatwg.org/#dom-parentnode-queryselectorall
fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<Temporary<NodeList>> {
let root: &JSRef<Node> = NodeCast::from_ref(self);
root.query_selector_all(selectors)
}
}

View file

@ -22,6 +22,7 @@ use dom::htmlcollection::HTMLCollection;
use dom::htmlserializer::serialize;
use dom::node::{ElementNodeTypeId, Node, NodeHelpers, NodeIterator, document_from_node};
use dom::node::{window_from_node, LayoutNodeHelpers};
use dom::nodelist::NodeList;
use dom::virtualmethods::{VirtualMethods, vtable_for};
use layout_interface::ContentChangedDocumentDamage;
use layout_interface::MatchSelectorsDocumentDamage;
@ -430,6 +431,7 @@ pub trait ElementMethods {
fn GetOuterHTML(&self) -> Fallible<DOMString>;
fn Children(&self) -> Temporary<HTMLCollection>;
fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>>;
fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<Temporary<NodeList>>;
fn Remove(&self);
}
@ -712,6 +714,12 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
root.query_selector(selectors)
}
// http://dom.spec.whatwg.org/#dom-parentnode-queryselectorall
fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<Temporary<NodeList>> {
let root: &JSRef<Node> = NodeCast::from_ref(self);
root.query_selector_all(selectors)
}
// http://dom.spec.whatwg.org/#dom-childnode-remove
fn Remove(&self) {
let node: &JSRef<Node> = NodeCast::from_ref(self);

View file

@ -399,6 +399,7 @@ pub trait NodeHelpers {
fn get_content_boxes(&self) -> Vec<Rect<Au>>;
fn query_selector(&self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>>;
fn query_selector_all(&self, selectors: DOMString) -> Fallible<Temporary<NodeList>>;
fn remove_self(&self);
}
@ -569,9 +570,9 @@ impl<'a> NodeHelpers for JSRef<'a, Node> {
None => return Err(Syntax),
// Step 3.
Some(ref selectors) => {
let root = self.ancestors().last().unwrap_or(self.clone());
for selector in selectors.iter() {
assert!(selector.pseudo_element.is_none());
let root = self.ancestors().last().unwrap_or(self.clone());
for node in root.traverse_preorder().filter(|node| node.is_element()) {
let mut _shareable: bool = false;
if matches_compound_selector(selector.compound_selectors.deref(), &node, &mut _shareable) {
@ -585,6 +586,32 @@ impl<'a> NodeHelpers for JSRef<'a, Node> {
Ok(None)
}
// http://dom.spec.whatwg.org/#dom-parentnode-queryselectorall
fn query_selector_all(&self, selectors: DOMString) -> Fallible<Temporary<NodeList>> {
// Step 1.
let mut nodes = vec!();
let root = self.ancestors().last().unwrap_or(self.clone());
let namespace = NamespaceMap::new();
match parse_selector_list(tokenize(selectors.as_slice()).map(|(token, _)| token).collect(), &namespace) {
// Step 2.
None => return Err(Syntax),
// Step 3.
Some(ref selectors) => {
for selector in selectors.iter() {
assert!(selector.pseudo_element.is_none());
for node in root.traverse_preorder().filter(|node| node.is_element()) {
let mut _shareable: bool = false;
if matches_compound_selector(selector.compound_selectors.deref(), &node, &mut _shareable) {
nodes.push(node.clone())
}
}
}
}
}
let window = window_from_node(self).root();
Ok(NodeList::new_simple_list(&window.root_ref(), nodes))
}
fn ancestors(&self) -> AncestorIterator {
AncestorIterator {
current: self.parent_node.get().map(|node| (*node.root()).clone()),

View file

@ -24,8 +24,11 @@ interface ParentNode {
// void append((Node or DOMString)... nodes);
//Element? query(DOMString relativeSelectors);
//[NewObject] Elements queryAll(DOMString relativeSelectors);
//[NewObject]
//Elements queryAll(DOMString relativeSelectors);
[Throws]
Element? querySelector(DOMString selectors);
//[NewObject] NodeList querySelectorAll(DOMString selectors);
//[NewObject]
[Throws]
NodeList querySelectorAll(DOMString selectors);
};

View file

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html>
<head>
<script src="harness.js"></script>
<script>
let foo = document.getElementById("foo");
let bar = document.getElementById("bar");
let baz = document.getElementById("baz");
{ // document.querySelector
let nodelist = document.querySelectorAll(".test");
is_a(nodelist, NodeList);
is(nodelist.length, 3);
is(nodelist.item(0), foo);
is(nodelist.item(1), bar);
is(nodelist.item(2), baz);
nodelist = document.querySelectorAll("div > .test");
is(nodelist.length, 3);
}
{ // element.querySelector
let div = document.getElementById("parent");
let nodelist = div.querySelectorAll(".test");
is(nodelist.length, 3);
nodelist = div.querySelectorAll("div:nth-of-type(1)");
is(nodelist.item(0), div);
}
{ // docfrag.querySelector
let docfrag = document.createDocumentFragment();
let div = document.createElement("div");
div.id = "foo";
div.className = "myClass";
let child = document.createElement("div");
div.appendChild(child);
docfrag.appendChild(div);
let nodelist = docfrag.querySelectorAll("#foo");
is(nodelist.item(0), div);
nodelist = docfrag.querySelectorAll("#foo:nth-child(1)");
is(nodelist.item(0), div);
}
finish();
</script>
</head>
<body>
<div id="parent">
<div id="foo" class="test"></div>
<div id="bar" class="test"></div>
<div id="baz" class="test"></div>
</div>
</body>
</html>