mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Add [foo=bar i] case-insensitive attribute selectors.
This commit is contained in:
parent
2f9808e130
commit
1117d86b63
5 changed files with 81 additions and 17 deletions
|
@ -2,6 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::ascii::AsciiExt;
|
||||
use std::collections::hashmap::HashMap;
|
||||
use std::hash::Hash;
|
||||
use std::num::div_rem;
|
||||
|
@ -723,14 +724,17 @@ pub fn matches_simple_selector<'a, E:TElement<'a>,
|
|||
*shareable = false;
|
||||
element.match_attr(attr, |_| true)
|
||||
}
|
||||
AttrEqual(ref attr, ref value) => {
|
||||
AttrEqual(ref attr, ref value, case_sensitivity) => {
|
||||
if value.as_slice() != "DIR" {
|
||||
// FIXME(pcwalton): Remove once we start actually supporting RTL text. This is in
|
||||
// here because the UA style otherwise disables all style sharing completely.
|
||||
*shareable = false
|
||||
}
|
||||
element.match_attr(attr, |attr_value| {
|
||||
attr_value == value.as_slice()
|
||||
match case_sensitivity {
|
||||
CaseSensitive => attr_value == value.as_slice(),
|
||||
CaseInsensitive => attr_value.eq_ignore_ascii_case(value.as_slice()),
|
||||
}
|
||||
})
|
||||
}
|
||||
AttrIncludes(ref attr, ref value) => {
|
||||
|
|
|
@ -61,9 +61,9 @@ pub enum SimpleSelector {
|
|||
|
||||
// Attribute selectors
|
||||
AttrExists(AttrSelector), // [foo]
|
||||
AttrEqual(AttrSelector, String), // [foo=bar]
|
||||
AttrEqual(AttrSelector, String, CaseSensitivity), // [foo=bar]
|
||||
AttrIncludes(AttrSelector, String), // [foo~=bar]
|
||||
AttrDashMatch(AttrSelector, String, String), // [foo|=bar] Second string is the first + "-"
|
||||
AttrDashMatch(AttrSelector, String, String), // [foo|=bar] Second string is the first + "-"
|
||||
AttrPrefixMatch(AttrSelector, String), // [foo^=bar]
|
||||
AttrSubstringMatch(AttrSelector, String), // [foo*=bar]
|
||||
AttrSuffixMatch(AttrSelector, String), // [foo$=bar]
|
||||
|
@ -90,6 +90,14 @@ pub enum SimpleSelector {
|
|||
// ...
|
||||
}
|
||||
|
||||
|
||||
#[deriving(Eq, PartialEq, Clone, Hash)]
|
||||
pub enum CaseSensitivity {
|
||||
CaseSensitive, // Selectors spec says language-defined, but HTML says sensitive.
|
||||
CaseInsensitive,
|
||||
}
|
||||
|
||||
|
||||
#[deriving(Eq, PartialEq, Clone, Hash)]
|
||||
pub struct LocalName {
|
||||
pub name: Atom,
|
||||
|
@ -446,25 +454,21 @@ fn parse_attribute_selector(content: Vec<ComponentValue>, namespaces: &Namespace
|
|||
};
|
||||
skip_whitespace(iter);
|
||||
// TODO: deal with empty value or value containing whitespace (see spec)
|
||||
macro_rules! get_value( () => {{
|
||||
skip_whitespace(iter);
|
||||
match iter.next() {
|
||||
Some(Ident(value)) | Some(QuotedString(value)) => value,
|
||||
_ => return Err(())
|
||||
}
|
||||
}};)
|
||||
let result = match iter.next() {
|
||||
None => AttrExists(attr), // [foo]
|
||||
Some(Delim('=')) => AttrEqual(attr, (get_value!())), // [foo=bar]
|
||||
Some(IncludeMatch) => AttrIncludes(attr, (get_value!())), // [foo~=bar]
|
||||
Some(Delim('=')) => AttrEqual(
|
||||
attr, try!(parse_attribute_value(iter)),
|
||||
try!(parse_attribute_flags(iter))), // [foo=bar]
|
||||
Some(IncludeMatch) => AttrIncludes(attr, try!(parse_attribute_value(iter))), // [foo~=bar]
|
||||
Some(DashMatch) => {
|
||||
let value = get_value!();
|
||||
let value = try!(parse_attribute_value(iter));
|
||||
let dashing_value = format!("{}-", value);
|
||||
AttrDashMatch(attr, value, dashing_value) // [foo|=bar]
|
||||
},
|
||||
Some(PrefixMatch) => AttrPrefixMatch(attr, (get_value!())), // [foo^=bar]
|
||||
Some(SubstringMatch) => AttrSubstringMatch(attr, (get_value!())), // [foo*=bar]
|
||||
Some(SuffixMatch) => AttrSuffixMatch(attr, (get_value!())), // [foo$=bar]
|
||||
Some(PrefixMatch) => AttrPrefixMatch(attr, try!(parse_attribute_value(iter))), // [foo^=bar]
|
||||
// [foo*=bar]
|
||||
Some(SubstringMatch) => AttrSubstringMatch(attr, try!(parse_attribute_value(iter))),
|
||||
Some(SuffixMatch) => AttrSuffixMatch(attr, try!(parse_attribute_value(iter))), // [foo$=bar]
|
||||
_ => return Err(())
|
||||
};
|
||||
skip_whitespace(iter);
|
||||
|
@ -472,6 +476,27 @@ fn parse_attribute_selector(content: Vec<ComponentValue>, namespaces: &Namespace
|
|||
}
|
||||
|
||||
|
||||
fn parse_attribute_value<I: Iterator<ComponentValue>>(iter: &mut Iter<I>) -> Result<String, ()> {
|
||||
skip_whitespace(iter);
|
||||
match iter.next() {
|
||||
Some(Ident(value)) | Some(QuotedString(value)) => Ok(value),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn parse_attribute_flags<I: Iterator<ComponentValue>>(iter: &mut Iter<I>)
|
||||
-> Result<CaseSensitivity, ()> {
|
||||
skip_whitespace(iter);
|
||||
match iter.next() {
|
||||
None => Ok(CaseSensitive),
|
||||
Some(Ident(ref value)) if value.as_slice().eq_ignore_ascii_case("i")
|
||||
=> Ok(CaseInsensitive),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn parse_simple_pseudo_class(name: &str) -> Result<SimpleSelector, ()> {
|
||||
match name.to_ascii_lower().as_slice() {
|
||||
"any-link" => Ok(AnyLink),
|
||||
|
|
17
tests/ref/attr_selector_case_sensitivity.html
Normal file
17
tests/ref/attr_selector_case_sensitivity.html
Normal file
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Attribute selector case-sensitivity: [foo=bar] and [foo=bar i]</title>
|
||||
<style>
|
||||
p[data-foo=Bar] { color: green }
|
||||
p[data-foo=bar] { color: red }
|
||||
p[data-foo=baz i] { color: green }
|
||||
p[data-foo=baz] { color: red }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p data-foo="Bar">This text should be green.</p>
|
||||
<p data-foo="Baz">This text should be green.</p>
|
||||
<p>This text should be black.</p>
|
||||
</body>
|
||||
</html>
|
17
tests/ref/attr_selector_case_sensitivity_ref.html
Normal file
17
tests/ref/attr_selector_case_sensitivity_ref.html
Normal file
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Attribute selector case-sensitivity: [foo=bar] and [foo=bar i]</title>
|
||||
<style>
|
||||
p[data-foo=Bar] { color: green }
|
||||
p[data-foo=bar] { color: red }
|
||||
p[data-foo=baz i] { color: green }
|
||||
p[data-foo=baz] { color: red }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p style="color: green">This text should be green.</p>
|
||||
<p style="color: green">This text should be green.</p>
|
||||
<p>This text should be black.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -30,6 +30,7 @@
|
|||
# inline_border_a.html inline_border_b.html
|
||||
== anon_block_inherit_a.html anon_block_inherit_b.html
|
||||
== attr_exists_selector.html attr_exists_selector_ref.html
|
||||
== attr_selector_case_sensitivity.html attr_selector_case_sensitivity_ref.html
|
||||
!= noteq_attr_exists_selector.html attr_exists_selector_ref.html
|
||||
== data_img_a.html data_img_b.html
|
||||
== background_style_attr.html background_ref.html
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue