mirror of
https://github.com/servo/servo.git
synced 2025-06-20 15:18:58 +01:00
Implementation of pseudo class 'first-child'.
This commit is contained in:
parent
572ba98ac9
commit
6dba191efe
4 changed files with 64 additions and 25 deletions
|
@ -164,6 +164,10 @@ impl<View> TreeNodeRef<Node<View>> for AbstractNode<View> {
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_root(&self) -> bool {
|
||||||
|
self.parent_node().is_none()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<View> TreeNodeRefAsElement<Node<View>, Element> for AbstractNode<View> {
|
impl<View> TreeNodeRefAsElement<Node<View>, Element> for AbstractNode<View> {
|
||||||
|
@ -611,7 +615,7 @@ impl Node<ScriptView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetPreviousSibling(&self) -> Option<AbstractNode<ScriptView>> {
|
pub fn GetPreviousSibling(&self) -> Option<AbstractNode<ScriptView>> {
|
||||||
self.prev_sibling
|
self.prev_sibling
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetNextSibling(&self) -> Option<AbstractNode<ScriptView>> {
|
pub fn GetNextSibling(&self) -> Option<AbstractNode<ScriptView>> {
|
||||||
|
@ -621,7 +625,7 @@ impl Node<ScriptView> {
|
||||||
pub fn GetNodeValue(&self, abstract_self: AbstractNode<ScriptView>) -> DOMString {
|
pub fn GetNodeValue(&self, abstract_self: AbstractNode<ScriptView>) -> DOMString {
|
||||||
match self.type_id {
|
match self.type_id {
|
||||||
// ProcessingInstruction
|
// ProcessingInstruction
|
||||||
CommentNodeTypeId | TextNodeTypeId => {
|
CommentNodeTypeId | TextNodeTypeId => {
|
||||||
do abstract_self.with_imm_characterdata() |characterdata| {
|
do abstract_self.with_imm_characterdata() |characterdata| {
|
||||||
characterdata.Data()
|
characterdata.Data()
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,13 +150,10 @@ fn matches_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLik
|
||||||
matches_compound_selector::<N, T, E>(&selector.compound_selectors, element)
|
matches_compound_selector::<N, T, E>(&selector.compound_selectors, element)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn matches_compound_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
fn matches_compound_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
||||||
selector: &CompoundSelector, element: &T) -> bool {
|
selector: &CompoundSelector, element: &T) -> bool {
|
||||||
if do element.with_imm_element_like |element: &E| {
|
if !do selector.simple_selectors.iter().all |simple_selector| {
|
||||||
!do selector.simple_selectors.iter().all |simple_selector| {
|
|
||||||
matches_simple_selector(simple_selector, element)
|
matches_simple_selector(simple_selector, element)
|
||||||
}
|
|
||||||
} {
|
} {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -193,25 +190,37 @@ fn matches_compound_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: E
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn matches_simple_selector<E: ElementLike>(selector: &SimpleSelector, element: &E) -> bool {
|
fn matches_simple_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
||||||
|
selector: &SimpleSelector, element: &T) -> bool {
|
||||||
static WHITESPACE: &'static [char] = &'static [' ', '\t', '\n', '\r', '\x0C'];
|
static WHITESPACE: &'static [char] = &'static [' ', '\t', '\n', '\r', '\x0C'];
|
||||||
|
|
||||||
match *selector {
|
match *selector {
|
||||||
// TODO: case-sensitivity depends on the document type
|
// TODO: case-sensitivity depends on the document type
|
||||||
// TODO: intern element names
|
// TODO: intern element names
|
||||||
LocalNameSelector(ref name)
|
LocalNameSelector(ref name) => {
|
||||||
=> element.get_local_name().eq_ignore_ascii_case(name.as_slice()),
|
do element.with_imm_element_like |element: &E| {
|
||||||
|
element.get_local_name().eq_ignore_ascii_case(name.as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
NamespaceSelector(_) => false, // TODO, when the DOM supports namespaces on elements.
|
NamespaceSelector(_) => false, // TODO, when the DOM supports namespaces on elements.
|
||||||
// TODO: case-sensitivity depends on the document type and quirks mode
|
// TODO: case-sensitivity depends on the document type and quirks mode
|
||||||
// TODO: cache and intern IDs on elements.
|
// TODO: cache and intern IDs on elements.
|
||||||
IDSelector(ref id) => element.get_attr("id") == Some(id.as_slice()),
|
IDSelector(ref id) => {
|
||||||
|
do element.with_imm_element_like |element: &E| {
|
||||||
|
element.get_attr("id") == Some(id.as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
// TODO: cache and intern classe names on elements.
|
// TODO: cache and intern classe names on elements.
|
||||||
ClassSelector(ref class) => match element.get_attr("class") {
|
ClassSelector(ref class) => {
|
||||||
None => false,
|
do element.with_imm_element_like |element: &E| {
|
||||||
// TODO: case-sensitivity depends on the document type and quirks mode
|
match element.get_attr("class") {
|
||||||
Some(ref class_attr)
|
None => false,
|
||||||
=> class_attr.split_iter(WHITESPACE).any(|c| c == class.as_slice()),
|
// TODO: case-sensitivity depends on the document type and quirks mode
|
||||||
},
|
Some(ref class_attr)
|
||||||
|
=> class_attr.split_iter(WHITESPACE).any(|c| c == class.as_slice()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AttrExists(ref attr) => match_attribute(attr, element, |_| true),
|
AttrExists(ref attr) => match_attribute(attr, element, |_| true),
|
||||||
AttrEqual(ref attr, ref value) => match_attribute(attr, element, |v| v == value.as_slice()),
|
AttrEqual(ref attr, ref value) => match_attribute(attr, element, |v| v == value.as_slice()),
|
||||||
|
@ -232,20 +241,41 @@ fn matches_simple_selector<E: ElementLike>(selector: &SimpleSelector, element: &
|
||||||
attr_value.ends_with(value.as_slice())
|
attr_value.ends_with(value.as_slice())
|
||||||
},
|
},
|
||||||
|
|
||||||
|
FirstChild => matches_first_child(element),
|
||||||
|
|
||||||
Negation(ref negated) => {
|
Negation(ref negated) => {
|
||||||
!negated.iter().all(|s| matches_simple_selector(s, element))
|
!negated.iter().all(|s| matches_simple_selector(s, element))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn match_attribute<E: ElementLike>(attr: &AttrSelector, element: &E, f: &fn(&str)-> bool) -> bool {
|
fn matches_first_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
||||||
match attr.namespace {
|
element: &T) -> bool {
|
||||||
Some(_) => false, // TODO, when the DOM supports namespaces on attributes
|
let mut node = element.clone();
|
||||||
None => match element.get_attr(attr.name) {
|
loop {
|
||||||
None => false,
|
match node.node().prev_sibling() {
|
||||||
Some(ref value) => f(value.as_slice())
|
Some(prev_sibling) => {
|
||||||
|
node = prev_sibling;
|
||||||
|
if node.is_element() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => return !element.is_root(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn match_attribute<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
||||||
|
attr: &AttrSelector, element: &T, f: &fn(&str)-> bool) -> bool {
|
||||||
|
do element.with_imm_element_like |element: &E| {
|
||||||
|
match attr.namespace {
|
||||||
|
Some(_) => false, // TODO, when the DOM supports namespaces on attributes
|
||||||
|
None => match element.get_attr(attr.name) {
|
||||||
|
None => false,
|
||||||
|
Some(ref value) => f(value.as_slice())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ pub enum SimpleSelector {
|
||||||
AttrSuffixMatch(AttrSelector, ~str), // [foo$=bar]
|
AttrSuffixMatch(AttrSelector, ~str), // [foo$=bar]
|
||||||
|
|
||||||
// Pseudo-classes
|
// Pseudo-classes
|
||||||
|
FirstChild,
|
||||||
// Empty,
|
// Empty,
|
||||||
// Root,
|
// Root,
|
||||||
// Lang(~str),
|
// Lang(~str),
|
||||||
|
@ -180,6 +181,7 @@ fn compute_specificity(mut selector: &CompoundSelector,
|
||||||
&ClassSelector(*)
|
&ClassSelector(*)
|
||||||
| &AttrExists(*) | &AttrEqual(*) | &AttrIncludes(*) | &AttrDashMatch(*)
|
| &AttrExists(*) | &AttrEqual(*) | &AttrIncludes(*) | &AttrDashMatch(*)
|
||||||
| &AttrPrefixMatch(*) | &AttrSubstringMatch(*) | &AttrSuffixMatch(*)
|
| &AttrPrefixMatch(*) | &AttrSubstringMatch(*) | &AttrSuffixMatch(*)
|
||||||
|
| &FirstChild
|
||||||
// | &Empty | &Root | &Lang(*) | &NthChild(*)
|
// | &Empty | &Root | &Lang(*) | &NthChild(*)
|
||||||
=> specificity.class_like_selectors += 1,
|
=> specificity.class_like_selectors += 1,
|
||||||
&NamespaceSelector(*) => (),
|
&NamespaceSelector(*) => (),
|
||||||
|
@ -272,7 +274,7 @@ fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_
|
||||||
},
|
},
|
||||||
_ => fail!("Implementation error, this should not happen."),
|
_ => fail!("Implementation error, this should not happen."),
|
||||||
},
|
},
|
||||||
Some(&Delim(':')) => {
|
Some(&Colon) => {
|
||||||
iter.next();
|
iter.next();
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
Some(Ident(name)) => match parse_simple_pseudo_class(name) {
|
Some(Ident(name)) => match parse_simple_pseudo_class(name) {
|
||||||
|
@ -292,7 +294,7 @@ fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_
|
||||||
None => None,
|
None => None,
|
||||||
Some(simple_selector) => Some(Some(Left(simple_selector))),
|
Some(simple_selector) => Some(Some(Left(simple_selector))),
|
||||||
},
|
},
|
||||||
Some(Delim(':')) => {
|
Some(Colon) => {
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
Some(Ident(name)) => match parse_pseudo_element(name) {
|
Some(Ident(name)) => match parse_pseudo_element(name) {
|
||||||
Some(pseudo_element) => Some(Some(Right(pseudo_element))),
|
Some(pseudo_element) => Some(Some(Right(pseudo_element))),
|
||||||
|
@ -414,6 +416,7 @@ fn parse_attribute_selector(content: ~[ComponentValue], namespaces: &NamespaceMa
|
||||||
|
|
||||||
fn parse_simple_pseudo_class(name: &str) -> Option<SimpleSelector> {
|
fn parse_simple_pseudo_class(name: &str) -> Option<SimpleSelector> {
|
||||||
match name.to_ascii_lower().as_slice() {
|
match name.to_ascii_lower().as_slice() {
|
||||||
|
"first-child" => Some(FirstChild),
|
||||||
// "root" => Some(Root),
|
// "root" => Some(Root),
|
||||||
// "empty" => Some(Empty),
|
// "empty" => Some(Empty),
|
||||||
_ => None
|
_ => None
|
||||||
|
|
|
@ -239,6 +239,8 @@ pub trait TreeNodeRef<Node>: Clone {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_element(&self) -> bool;
|
fn is_element(&self) -> bool;
|
||||||
|
|
||||||
|
fn is_root(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TreeNodeRefAsElement<Node, E: ElementLike>: TreeNodeRef<Node> {
|
pub trait TreeNodeRefAsElement<Node, E: ElementLike>: TreeNodeRef<Node> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue