diff options
Diffstat (limited to 'src/components/script/dom/node.rs')
-rw-r--r-- | src/components/script/dom/node.rs | 80 |
1 files changed, 77 insertions, 3 deletions
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index 45c85ea793e..261518752cb 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -4,7 +4,8 @@ //! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements. -use dom::attr::Attr; +use cssparser::tokenize; +use dom::attr::{Attr, AttrMethods}; use dom::bindings::codegen::InheritTypes::{CommentCast, DocumentCast, DocumentTypeCast}; use dom::bindings::codegen::InheritTypes::{ElementCast, TextCast, NodeCast, ElementDerived}; use dom::bindings::codegen::InheritTypes::{CharacterDataCast, NodeBase, NodeDerived}; @@ -14,14 +15,15 @@ use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, Root, OptionalUnr use dom::bindings::js::{OptionalSettable, TemporaryPushable, OptionalRootedRootable}; use dom::bindings::js::{ResultRootable, OptionalRootable}; 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::characterdata::{CharacterData, CharacterDataMethods}; use dom::comment::Comment; use dom::document::{Document, DocumentMethods, DocumentHelpers, HTMLDocument, NonHTMLDocument}; use dom::documentfragment::DocumentFragment; use dom::documenttype::DocumentType; -use dom::element::{Element, ElementMethods, ElementTypeId, HTMLAnchorElementTypeId}; +use dom::element::{AttributeHandlers, Element, ElementMethods, ElementTypeId}; +use dom::element::{HTMLAnchorElementTypeId, ElementHelpers}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::nodelist::{NodeList}; use dom::processinginstruction::{ProcessingInstruction, ProcessingInstructionMethods}; @@ -34,6 +36,7 @@ use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery, C LayoutChan, ReapLayoutDataMsg, TrustedNodeAddress, UntrustedNodeAddress}; use servo_util::geometry::Au; 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::jsfriendapi; @@ -42,6 +45,7 @@ use libc::uintptr_t; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::iter::{Map, Filter}; use std::mem; +use style; use style::ComputedValues; use sync::Arc; @@ -384,6 +388,8 @@ pub trait NodeHelpers { fn get_bounding_content_box(&self) -> Rect<Au>; fn get_content_boxes(&self) -> Vec<Rect<Au>>; + fn query_selector(&self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>>; + fn remove_self(&self); } @@ -544,6 +550,31 @@ impl<'a> NodeHelpers for JSRef<'a, Node> { 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()); + 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) { + let elem: &JSRef<Element> = ElementCast::to_ref(&node).unwrap(); + return Ok(Some(Temporary::from_rooted(elem))); + } + } + } + } + } + Ok(None) + } + fn ancestors(&self) -> AncestorIterator { AncestorIterator { current: self.parent_node.get().map(|node| (*node.root()).clone()), @@ -1900,3 +1931,46 @@ impl<'a> VirtualMethods for JSRef<'a, Node> { Some(eventtarget as &VirtualMethods:) } } + +impl<'a> style::TNode<JSRef<'a, Element>> for JSRef<'a, Node> { + fn parent_node(&self) -> Option<JSRef<'a, Node>> { + (self as &NodeHelpers).parent_node().map(|node| *node.root()) + } + fn prev_sibling(&self) -> Option<JSRef<'a, Node>> { + (self as &NodeHelpers).prev_sibling().map(|node| *node.root()) + } + fn next_sibling(&self) -> Option<JSRef<'a, Node>> { + (self as &NodeHelpers).next_sibling().map(|node| *node.root()) + } + fn is_document(&self) -> bool { + (self as &NodeHelpers).is_document() + } + fn is_element(&self) -> bool { + (self as &NodeHelpers).is_element() + } + fn as_element(&self) -> JSRef<'a, Element> { + let elem: Option<&JSRef<'a, Element>> = ElementCast::to_ref(self); + assert!(elem.is_some()); + *elem.unwrap() + } + fn match_attr(&self, attr: &style::AttrSelector, test: |&str| -> bool) -> bool { + let name = { + let elem: Option<&JSRef<'a, Element>> = ElementCast::to_ref(self); + assert!(elem.is_some()); + let elem: &ElementHelpers = elem.unwrap() as &ElementHelpers; + if elem.html_element_in_html_document() { + attr.lower_name.as_slice() + } else { + attr.name.as_slice() + } + }; + match attr.namespace { + style::SpecificNamespace(ref ns) => { + self.as_element().get_attribute(ns.clone(), name).root() + .map_or(false, |attr| test(attr.deref().Value().as_slice())) + }, + // FIXME: https://github.com/mozilla/servo/issues/1558 + style::AnyNamespace => false, + } + } +} |