Implement querySelector for Document

This commit is contained in:
Bruno de Oliveira Abinader 2014-06-04 13:28:36 -07:00
parent f0aadb790d
commit 249c484c24
5 changed files with 38 additions and 5 deletions

View file

@ -12,7 +12,8 @@ use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable, TemporaryPushabl
use dom::bindings::js::OptionalRootable; use dom::bindings::js::OptionalRootable;
use dom::bindings::trace::Untraceable; use dom::bindings::trace::Untraceable;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::error::{ErrorResult, Fallible, NotSupported, InvalidCharacter, HierarchyRequest, NamespaceError}; use dom::bindings::error::{ErrorResult, Fallible, NotSupported, InvalidCharacter};
use dom::bindings::error::{HierarchyRequest, NamespaceError};
use dom::bindings::utils::{xml_name_type, InvalidXMLName, Name, QName}; use dom::bindings::utils::{xml_name_type, InvalidXMLName, Name, QName};
use dom::comment::Comment; use dom::comment::Comment;
use dom::customevent::CustomEvent; use dom::customevent::CustomEvent;
@ -806,13 +807,16 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
window.Location() window.Location()
} }
// http://dom.spec.whatwg.org/#dom-parentnode-children
fn Children(&self) -> Temporary<HTMLCollection> { fn Children(&self) -> Temporary<HTMLCollection> {
let window = self.window.root(); let window = self.window.root();
HTMLCollection::children(&*window, NodeCast::from_ref(self)) HTMLCollection::children(&*window, NodeCast::from_ref(self))
} }
// http://dom.spec.whatwg.org/#dom-parentnode-queryselector
fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>> { fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>> {
Ok(None) let root: &JSRef<Node> = NodeCast::from_ref(self);
root.query_selector(selectors)
} }
fn GetOnload(&self) -> Option<EventHandlerNonNull> { fn GetOnload(&self) -> Option<EventHandlerNonNull> {

View file

@ -15,7 +15,7 @@ use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, Root, OptionalUnr
use dom::bindings::js::{OptionalSettable, TemporaryPushable, OptionalRootedRootable}; use dom::bindings::js::{OptionalSettable, TemporaryPushable, OptionalRootedRootable};
use dom::bindings::js::{ResultRootable, OptionalRootable}; use dom::bindings::js::{ResultRootable, OptionalRootable};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::error::{ErrorResult, Fallible, NotFound, HierarchyRequest}; use dom::bindings::error::{ErrorResult, Fallible, NotFound, HierarchyRequest, Syntax};
use dom::bindings::utils; use dom::bindings::utils;
use dom::characterdata::{CharacterData, CharacterDataMethods}; use dom::characterdata::{CharacterData, CharacterDataMethods};
use dom::comment::Comment; use dom::comment::Comment;
@ -36,6 +36,7 @@ use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery, C
LayoutChan, ReapLayoutDataMsg, TrustedNodeAddress, UntrustedNodeAddress}; LayoutChan, ReapLayoutDataMsg, TrustedNodeAddress, UntrustedNodeAddress};
use servo_util::geometry::Au; use servo_util::geometry::Au;
use servo_util::str::{DOMString, null_str_as_empty}; use servo_util::str::{DOMString, null_str_as_empty};
use style::{parse_selector_list, matches_compound_selector, NamespaceMap};
use js::jsapi::{JSContext, JSObject, JSRuntime}; use js::jsapi::{JSContext, JSObject, JSRuntime};
use js::jsfriendapi; use js::jsfriendapi;
@ -396,6 +397,8 @@ pub trait NodeHelpers {
fn get_bounding_content_box(&self) -> Rect<Au>; fn get_bounding_content_box(&self) -> Rect<Au>;
fn get_content_boxes(&self) -> Vec<Rect<Au>>; fn get_content_boxes(&self) -> Vec<Rect<Au>>;
fn query_selector(&self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>>;
fn remove_self(&self); fn remove_self(&self);
} }
@ -552,6 +555,30 @@ impl<'a> NodeHelpers for JSRef<'a, Node> {
rects rects
} }
// http://dom.spec.whatwg.org/#dom-parentnode-queryselector
fn query_selector(&self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>> {
// Step 1.
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 elem in self.child_elements() {
let node: &JSRef<Node> = NodeCast::from_ref(&elem);
let mut _shareable: bool = false;
if matches_compound_selector(selector.compound_selectors.deref(), node, &mut _shareable) {
return Ok(Some(Temporary::from_rooted(&elem)));
}
}
}
}
}
Ok(None)
}
fn ancestors(&self) -> AncestorIterator { fn ancestors(&self) -> AncestorIterator {
AncestorIterator { AncestorIterator {
current: self.parent_node.get().map(|node| (*node.root()).clone()), current: self.parent_node.get().map(|node| (*node.root()).clone()),

View file

@ -17,6 +17,7 @@
extern crate log; extern crate log;
extern crate debug; extern crate debug;
extern crate cssparser;
extern crate collections; extern crate collections;
extern crate geom; extern crate geom;
extern crate hubbub; extern crate hubbub;

View file

@ -521,7 +521,7 @@ impl Ord for MatchedProperty {
/// `shareable` to false unless you are willing to update the style sharing logic. Otherwise things /// `shareable` to false unless you are willing to update the style sharing logic. Otherwise things
/// will almost certainly break as nodes will start mistakenly sharing styles. (See the code in /// will almost certainly break as nodes will start mistakenly sharing styles. (See the code in
/// `main/css/matching.rs`.) /// `main/css/matching.rs`.)
fn matches_compound_selector<E:TElement, pub fn matches_compound_selector<E:TElement,
N:TNode<E>>( N:TNode<E>>(
selector: &CompoundSelector, selector: &CompoundSelector,
element: &N, element: &N,

View file

@ -33,7 +33,7 @@ extern crate servo_util = "util";
// Public API // Public API
pub use stylesheets::{Stylesheet, CSSRule, StyleRule}; pub use stylesheets::{Stylesheet, CSSRule, StyleRule};
pub use selector_matching::{Stylist, StylesheetOrigin, UserAgentOrigin, AuthorOrigin, UserOrigin}; pub use selector_matching::{Stylist, StylesheetOrigin, UserAgentOrigin, AuthorOrigin, UserOrigin};
pub use selector_matching::{MatchedProperty}; pub use selector_matching::{MatchedProperty, matches_compound_selector};
pub use properties::{cascade, cascade_anonymous}; pub use properties::{cascade, cascade_anonymous};
pub use properties::{PropertyDeclaration, ComputedValues, computed_values, style_structs}; pub use properties::{PropertyDeclaration, ComputedValues, computed_values, style_structs};
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
@ -43,6 +43,7 @@ pub use errors::with_errors_silenced;
pub use node::{TElement, TNode}; pub use node::{TElement, TNode};
pub use selectors::{PseudoElement, Before, After, AttrSelector, SpecificNamespace, AnyNamespace}; pub use selectors::{PseudoElement, Before, After, AttrSelector, SpecificNamespace, AnyNamespace};
pub use selectors::{NamespaceConstraint, Selector, CompoundSelector, SimpleSelector, Combinator}; pub use selectors::{NamespaceConstraint, Selector, CompoundSelector, SimpleSelector, Combinator};
pub use selectors::{parse_selector_list};
pub use namespaces::NamespaceMap; pub use namespaces::NamespaceMap;
pub use media_queries::{MediaRule, MediaQueryList, MediaQuery, Device, MediaType, MediaQueryType}; pub use media_queries::{MediaRule, MediaQueryList, MediaQuery, Device, MediaType, MediaQueryType};