mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Simplify rust-selectors API for attribute selectors
This commit is contained in:
parent
2ca2c2d2be
commit
83c7824fda
15 changed files with 447 additions and 480 deletions
|
@ -5,122 +5,13 @@
|
|||
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and
|
||||
//! style.
|
||||
|
||||
use attr::AttrSelectorOperation;
|
||||
use matching::{ElementSelectorFlags, MatchingContext};
|
||||
use parser::{AttrSelector, SelectorImpl};
|
||||
use std::ascii::AsciiExt;
|
||||
use parser::{NamespaceConstraint, SelectorImpl};
|
||||
|
||||
/// The definition of whitespace per CSS Selectors Level 3 § 4.
|
||||
pub static SELECTOR_WHITESPACE: &'static [char] = &[' ', '\t', '\n', '\r', '\x0C'];
|
||||
|
||||
// Attribute matching routines. Consumers with simple implementations can implement
|
||||
// MatchAttrGeneric instead.
|
||||
pub trait MatchAttr {
|
||||
pub trait Element: Sized {
|
||||
type Impl: SelectorImpl;
|
||||
|
||||
fn match_attr_has(
|
||||
&self,
|
||||
attr: &AttrSelector<Self::Impl>) -> bool;
|
||||
|
||||
fn match_attr_equals(
|
||||
&self,
|
||||
attr: &AttrSelector<Self::Impl>,
|
||||
value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
|
||||
|
||||
fn match_attr_equals_ignore_ascii_case(
|
||||
&self,
|
||||
attr: &AttrSelector<Self::Impl>,
|
||||
value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
|
||||
|
||||
fn match_attr_includes(
|
||||
&self,
|
||||
attr: &AttrSelector<Self::Impl>,
|
||||
value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
|
||||
|
||||
fn match_attr_dash(
|
||||
&self,
|
||||
attr: &AttrSelector<Self::Impl>,
|
||||
value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
|
||||
|
||||
fn match_attr_prefix(
|
||||
&self,
|
||||
attr: &AttrSelector<Self::Impl>,
|
||||
value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
|
||||
|
||||
fn match_attr_substring(
|
||||
&self,
|
||||
attr: &AttrSelector<Self::Impl>,
|
||||
value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
|
||||
|
||||
fn match_attr_suffix(
|
||||
&self,
|
||||
attr: &AttrSelector<Self::Impl>,
|
||||
value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
|
||||
}
|
||||
|
||||
pub trait MatchAttrGeneric {
|
||||
type Impl: SelectorImpl;
|
||||
fn match_attr<F>(&self, attr: &AttrSelector<Self::Impl>, test: F) -> bool where F: Fn(&str) -> bool;
|
||||
}
|
||||
|
||||
impl<T> MatchAttr for T where T: MatchAttrGeneric, T::Impl: SelectorImpl<AttrValue = String> {
|
||||
type Impl = T::Impl;
|
||||
|
||||
fn match_attr_has(&self, attr: &AttrSelector<Self::Impl>) -> bool {
|
||||
self.match_attr(attr, |_| true)
|
||||
}
|
||||
|
||||
fn match_attr_equals(&self, attr: &AttrSelector<Self::Impl>, value: &String) -> bool {
|
||||
self.match_attr(attr, |v| v == value)
|
||||
}
|
||||
|
||||
fn match_attr_equals_ignore_ascii_case(&self, attr: &AttrSelector<Self::Impl>,
|
||||
value: &String) -> bool {
|
||||
self.match_attr(attr, |v| v.eq_ignore_ascii_case(value))
|
||||
}
|
||||
|
||||
fn match_attr_includes(&self, attr: &AttrSelector<Self::Impl>, value: &String) -> bool {
|
||||
self.match_attr(attr, |attr_value| {
|
||||
attr_value.split(SELECTOR_WHITESPACE).any(|v| v == value)
|
||||
})
|
||||
}
|
||||
|
||||
fn match_attr_dash(&self, attr: &AttrSelector<Self::Impl>, value: &String) -> bool {
|
||||
self.match_attr(attr, |attr_value| {
|
||||
// The attribute must start with the pattern.
|
||||
if !attr_value.starts_with(value) {
|
||||
return false
|
||||
}
|
||||
|
||||
// If the strings are the same, we're done.
|
||||
if attr_value.len() == value.len() {
|
||||
return true
|
||||
}
|
||||
|
||||
// The attribute is long than the pattern, so the next character must be '-'.
|
||||
attr_value.as_bytes()[value.len()] == '-' as u8
|
||||
})
|
||||
}
|
||||
|
||||
fn match_attr_prefix(&self, attr: &AttrSelector<Self::Impl>, value: &String) -> bool {
|
||||
self.match_attr(attr, |attr_value| {
|
||||
attr_value.starts_with(value)
|
||||
})
|
||||
}
|
||||
|
||||
fn match_attr_substring(&self, attr: &AttrSelector<Self::Impl>, value: &String) -> bool {
|
||||
self.match_attr(attr, |attr_value| {
|
||||
attr_value.contains(value)
|
||||
})
|
||||
}
|
||||
|
||||
fn match_attr_suffix(&self, attr: &AttrSelector<Self::Impl>, value: &String) -> bool {
|
||||
self.match_attr(attr, |attr_value| {
|
||||
attr_value.ends_with(value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Element: MatchAttr + Sized {
|
||||
fn parent_element(&self) -> Option<Self>;
|
||||
|
||||
/// The parent of a given pseudo-element, after matching a pseudo-element
|
||||
|
@ -147,6 +38,12 @@ pub trait Element: MatchAttr + Sized {
|
|||
fn get_local_name(&self) -> &<Self::Impl as SelectorImpl>::BorrowedLocalName;
|
||||
fn get_namespace(&self) -> &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl;
|
||||
|
||||
fn attr_matches(&self,
|
||||
ns: &NamespaceConstraint<Self::Impl>,
|
||||
local_name: &<Self::Impl as SelectorImpl>::LocalName,
|
||||
operation: &AttrSelectorOperation<Self::Impl>)
|
||||
-> bool;
|
||||
|
||||
fn match_non_ts_pseudo_class<F>(&self,
|
||||
pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
|
||||
context: &mut MatchingContext,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue