mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
auto merge of #4353 : brunoabinader/servo/domtokenlist, r=Ms2ger
Specs: https://dom.spec.whatwg.org/#dom-domtokenlist-add https://dom.spec.whatwg.org/#dom-domtokenlist-remove https://dom.spec.whatwg.org/#dom-domtokenlist-toggle https://dom.spec.whatwg.org/#concept-dtl-update https://dom.spec.whatwg.org/#concept-ordered-set-serializer Closes #3138.
This commit is contained in:
commit
3af73e9962
9 changed files with 106 additions and 112 deletions
|
@ -37,9 +37,21 @@ pub enum AttrValue {
|
|||
}
|
||||
|
||||
impl AttrValue {
|
||||
pub fn from_tokenlist(tokens: DOMString) -> AttrValue {
|
||||
let atoms = split_html_space_chars(tokens.as_slice())
|
||||
.map(|token| Atom::from_slice(token)).collect();
|
||||
pub fn from_serialized_tokenlist(tokens: DOMString) -> AttrValue {
|
||||
let mut atoms: Vec<Atom> = vec!();
|
||||
for token in split_html_space_chars(tokens.as_slice()).map(|slice| Atom::from_slice(slice)) {
|
||||
if !atoms.iter().any(|atom| *atom == token) {
|
||||
atoms.push(token);
|
||||
}
|
||||
}
|
||||
AttrValue::TokenList(tokens, atoms)
|
||||
}
|
||||
|
||||
pub fn from_atomic_tokens(atoms: Vec<Atom>) -> AttrValue {
|
||||
let tokens = {
|
||||
let slices: Vec<&str> = atoms.iter().map(|atom| atom.as_slice()).collect();
|
||||
slices.connect("\x20")
|
||||
};
|
||||
AttrValue::TokenList(tokens, atoms)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
use dom::attr::{Attr, AttrHelpers};
|
||||
use dom::bindings::codegen::Bindings::DOMTokenListBinding;
|
||||
use dom::bindings::codegen::Bindings::DOMTokenListBinding::DOMTokenListMethods;
|
||||
use dom::bindings::error::Fallible;
|
||||
use dom::bindings::error::{ErrorResult, Fallible};
|
||||
use dom::bindings::error::Error::{InvalidCharacter, Syntax};
|
||||
use dom::bindings::global::GlobalRef;
|
||||
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable};
|
||||
|
@ -48,7 +48,7 @@ impl Reflectable for DOMTokenList {
|
|||
|
||||
trait PrivateDOMTokenListHelpers {
|
||||
fn attribute(self) -> Option<Temporary<Attr>>;
|
||||
fn check_token_exceptions<'a>(self, token: &'a str) -> Fallible<&'a str>;
|
||||
fn check_token_exceptions<'a>(self, token: &'a str) -> Fallible<Atom>;
|
||||
}
|
||||
|
||||
impl<'a> PrivateDOMTokenListHelpers for JSRef<'a, DOMTokenList> {
|
||||
|
@ -57,11 +57,11 @@ impl<'a> PrivateDOMTokenListHelpers for JSRef<'a, DOMTokenList> {
|
|||
element.get_attribute(ns!(""), &self.local_name)
|
||||
}
|
||||
|
||||
fn check_token_exceptions<'a>(self, token: &'a str) -> Fallible<&'a str> {
|
||||
fn check_token_exceptions<'a>(self, token: &'a str) -> Fallible<Atom> {
|
||||
match token {
|
||||
"" => Err(Syntax),
|
||||
token if token.find(HTML_SPACE_CHARACTERS).is_some() => Err(InvalidCharacter),
|
||||
token => Ok(token)
|
||||
slice if slice.find(HTML_SPACE_CHARACTERS).is_some() => Err(InvalidCharacter),
|
||||
slice => Ok(Atom::from_slice(slice))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,14 +90,67 @@ impl<'a> DOMTokenListMethods for JSRef<'a, DOMTokenList> {
|
|||
|
||||
// http://dom.spec.whatwg.org/#dom-domtokenlist-contains
|
||||
fn Contains(self, token: DOMString) -> Fallible<bool> {
|
||||
self.check_token_exceptions(token.as_slice()).map(|slice| {
|
||||
self.check_token_exceptions(token.as_slice()).map(|token| {
|
||||
self.attribute().root().map(|attr| {
|
||||
let value = attr.value();
|
||||
let tokens = value.tokens()
|
||||
.expect("Should have parsed this attribute");
|
||||
let atom = Atom::from_slice(slice);
|
||||
tokens.iter().any(|token| *token == atom)
|
||||
attr.value()
|
||||
.tokens()
|
||||
.expect("Should have parsed this attribute")
|
||||
.iter()
|
||||
.any(|atom| *atom == token)
|
||||
}).unwrap_or(false)
|
||||
})
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-domtokenlist-add
|
||||
fn Add(self, tokens: Vec<DOMString>) -> ErrorResult {
|
||||
let element = self.element.root();
|
||||
let mut atoms = element.get_tokenlist_attribute(&self.local_name);
|
||||
for token in tokens.iter() {
|
||||
let token = try!(self.check_token_exceptions(token.as_slice()));
|
||||
if !atoms.iter().any(|atom| *atom == token) {
|
||||
atoms.push(token);
|
||||
}
|
||||
}
|
||||
element.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-domtokenlist-remove
|
||||
fn Remove(self, tokens: Vec<DOMString>) -> ErrorResult {
|
||||
let element = self.element.root();
|
||||
let mut atoms = element.get_tokenlist_attribute(&self.local_name);
|
||||
for token in tokens.iter() {
|
||||
let token = try!(self.check_token_exceptions(token.as_slice()));
|
||||
atoms.iter().position(|atom| *atom == token).and_then(|index| {
|
||||
atoms.remove(index)
|
||||
});
|
||||
}
|
||||
element.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-domtokenlist-toggle
|
||||
fn Toggle(self, token: DOMString, force: Option<bool>) -> Fallible<bool> {
|
||||
let element = self.element.root();
|
||||
let mut atoms = element.get_tokenlist_attribute(&self.local_name);
|
||||
let token = try!(self.check_token_exceptions(token.as_slice()));
|
||||
match atoms.iter().position(|atom| *atom == token) {
|
||||
Some(index) => match force {
|
||||
Some(true) => Ok(true),
|
||||
_ => {
|
||||
atoms.remove(index);
|
||||
element.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||
Ok(false)
|
||||
}
|
||||
},
|
||||
None => match force {
|
||||
Some(false) => Ok(false),
|
||||
_ => {
|
||||
atoms.push(token);
|
||||
element.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -655,7 +655,9 @@ pub trait AttributeHandlers {
|
|||
fn set_url_attribute(self, name: &Atom, value: DOMString);
|
||||
fn get_string_attribute(self, name: &Atom) -> DOMString;
|
||||
fn set_string_attribute(self, name: &Atom, value: DOMString);
|
||||
fn get_tokenlist_attribute(self, name: &Atom) -> Vec<Atom>;
|
||||
fn set_tokenlist_attribute(self, name: &Atom, value: DOMString);
|
||||
fn set_atomic_tokenlist_attribute(self, name: &Atom, tokens: Vec<Atom>);
|
||||
fn get_uint_attribute(self, name: &Atom) -> u32;
|
||||
fn set_uint_attribute(self, name: &Atom, value: u32);
|
||||
}
|
||||
|
@ -846,9 +848,23 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> {
|
|||
self.set_attribute(name, AttrValue::String(value));
|
||||
}
|
||||
|
||||
fn get_tokenlist_attribute(self, name: &Atom) -> Vec<Atom> {
|
||||
self.get_attribute(ns!(""), name).root().map(|attr| {
|
||||
attr.value()
|
||||
.tokens()
|
||||
.expect("Expected a TokenListAttrValue")
|
||||
.to_vec()
|
||||
}).unwrap_or(vec!())
|
||||
}
|
||||
|
||||
fn set_tokenlist_attribute(self, name: &Atom, value: DOMString) {
|
||||
assert!(name.as_slice() == name.as_slice().to_ascii_lower().as_slice());
|
||||
self.set_attribute(name, AttrValue::from_tokenlist(value));
|
||||
self.set_attribute(name, AttrValue::from_serialized_tokenlist(value));
|
||||
}
|
||||
|
||||
fn set_atomic_tokenlist_attribute(self, name: &Atom, tokens: Vec<Atom>) {
|
||||
assert!(name.as_slice() == name.as_slice().to_ascii_lower().as_slice());
|
||||
self.set_attribute(name, AttrValue::from_atomic_tokens(tokens));
|
||||
}
|
||||
|
||||
fn get_uint_attribute(self, name: &Atom) -> u32 {
|
||||
|
@ -1290,7 +1306,7 @@ impl<'a> VirtualMethods for JSRef<'a, Element> {
|
|||
fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue {
|
||||
match name {
|
||||
&atom!("id") => AttrValue::from_atomic(value),
|
||||
&atom!("class") => AttrValue::from_tokenlist(value),
|
||||
&atom!("class") => AttrValue::from_serialized_tokenlist(value),
|
||||
_ => self.super_type().unwrap().parse_plain_attribute(name, value),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLAnchorElement> {
|
|||
|
||||
fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue {
|
||||
match name {
|
||||
&atom!("rel") => AttrValue::from_tokenlist(value),
|
||||
&atom!("rel") => AttrValue::from_serialized_tokenlist(value),
|
||||
_ => self.super_type().unwrap().parse_plain_attribute(name, value),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLAreaElement> {
|
|||
|
||||
fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue {
|
||||
match name {
|
||||
&atom!("rel") => AttrValue::from_tokenlist(value),
|
||||
&atom!("rel") => AttrValue::from_serialized_tokenlist(value),
|
||||
_ => self.super_type().unwrap().parse_plain_attribute(name, value),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLLinkElement> {
|
|||
|
||||
fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue {
|
||||
match name {
|
||||
&atom!("rel") => AttrValue::from_tokenlist(value),
|
||||
&atom!("rel") => AttrValue::from_serialized_tokenlist(value),
|
||||
_ => self.super_type().unwrap().parse_plain_attribute(name, value),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,12 @@ interface DOMTokenList {
|
|||
|
||||
[Throws]
|
||||
boolean contains(DOMString token);
|
||||
[Throws]
|
||||
void add(DOMString... tokens);
|
||||
[Throws]
|
||||
void remove(DOMString... tokens);
|
||||
[Throws]
|
||||
boolean toggle(DOMString token, optional boolean force);
|
||||
|
||||
//void add(DOMString... tokens);
|
||||
//void remove(DOMString... tokens);
|
||||
//boolean toggle(DOMString token, optional boolean force);
|
||||
//stringifier;
|
||||
};
|
||||
|
|
|
@ -1032,36 +1032,18 @@
|
|||
[TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "nextNode" with the proper type (10)]
|
||||
expected: FAIL
|
||||
|
||||
[DOMTokenList interface: operation add(DOMString)]
|
||||
expected: FAIL
|
||||
|
||||
[DOMTokenList interface: operation remove(DOMString)]
|
||||
expected: FAIL
|
||||
|
||||
[DOMTokenList interface: operation toggle(DOMString,boolean)]
|
||||
expected: FAIL
|
||||
|
||||
[DOMTokenList interface: stringifier]
|
||||
expected: FAIL
|
||||
|
||||
[DOMTokenList interface: document.body.classList must inherit property "add" with the proper type (3)]
|
||||
expected: FAIL
|
||||
|
||||
[DOMTokenList interface: calling add(DOMString) on document.body.classList with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[DOMTokenList interface: document.body.classList must inherit property "remove" with the proper type (4)]
|
||||
expected: FAIL
|
||||
|
||||
[DOMTokenList interface: calling remove(DOMString) on document.body.classList with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[DOMTokenList interface: document.body.classList must inherit property "toggle" with the proper type (5)]
|
||||
expected: FAIL
|
||||
|
||||
[DOMTokenList interface: calling toggle(DOMString,boolean) on document.body.classList with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[DOMSettableTokenList interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -3,51 +3,15 @@
|
|||
[CSS .foo selectors must not match elements without any class]
|
||||
expected: FAIL
|
||||
|
||||
[classList must be correct for an element that has classes]
|
||||
expected: FAIL
|
||||
|
||||
[empty classList should return the empty string since the ordered set parser skip the whitespaces]
|
||||
expected: FAIL
|
||||
|
||||
[.add(empty_string) must throw a SYNTAX_ERR]
|
||||
expected: FAIL
|
||||
|
||||
[.remove(empty_string) must throw a SYNTAX_ERR]
|
||||
expected: FAIL
|
||||
|
||||
[.toggle(empty_string) must throw a SYNTAX_ERR]
|
||||
expected: FAIL
|
||||
|
||||
[.add(string_with_spaces) must throw an INVALID_CHARACTER_ERR]
|
||||
expected: FAIL
|
||||
|
||||
[.remove(string_with_spaces) must throw an INVALID_CHARACTER_ERR]
|
||||
expected: FAIL
|
||||
|
||||
[.toggle(string_with_spaces) must throw an INVALID_CHARACTER_ERR]
|
||||
expected: FAIL
|
||||
|
||||
[computed style must update when setting .className]
|
||||
expected: FAIL
|
||||
|
||||
[classList.add must not cause the CSS selector to stop matching]
|
||||
expected: FAIL
|
||||
|
||||
[classList.contains case sensitivity must match a case-specific string]
|
||||
expected: FAIL
|
||||
|
||||
[classList.length must correctly reflect the number of tokens]
|
||||
expected: FAIL
|
||||
|
||||
[classList.item must return case-sensitive strings and preserve token order]
|
||||
expected: FAIL
|
||||
|
||||
[classList[index\] must return case-sensitive strings and preserve token order]
|
||||
expected: FAIL
|
||||
|
||||
[className must update correctly when items have been added through classList]
|
||||
expected: FAIL
|
||||
|
||||
[classList must stringify correctly when items have been added]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -63,9 +27,6 @@
|
|||
[classList.remove must not break case-sensitive CSS selector matching]
|
||||
expected: FAIL
|
||||
|
||||
[classList.remove must remove duplicated tokens]
|
||||
expected: FAIL
|
||||
|
||||
[classList.remove must collapse whitespace around removed tokens]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -81,45 +42,12 @@
|
|||
[classList.add must collapse whitespaces and remove duplicates when adding a token that already exists]
|
||||
expected: FAIL
|
||||
|
||||
[classList.toggle must toggle tokens case-sensitively when adding]
|
||||
expected: FAIL
|
||||
|
||||
[classList.toggle must not break case-sensitive CSS selector matching]
|
||||
expected: FAIL
|
||||
|
||||
[classList.toggle must be able to remove tokens]
|
||||
expected: FAIL
|
||||
|
||||
[classList.toggle must be case-sensitive when removing tokens]
|
||||
expected: FAIL
|
||||
|
||||
[CSS class selectors must stop matching when all classes have been removed]
|
||||
expected: FAIL
|
||||
|
||||
[className must be empty when all classes have been removed]
|
||||
expected: FAIL
|
||||
|
||||
[classList must stringify to an empty string when all classes have been removed]
|
||||
expected: FAIL
|
||||
|
||||
[classList.item(0) must return null when all classes have been removed]
|
||||
expected: FAIL
|
||||
|
||||
[classList[0\] must be undefined when all classes have been removed]
|
||||
expected: FAIL
|
||||
|
||||
[classList.add should treat " " as a space]
|
||||
expected: FAIL
|
||||
|
||||
[classList.add should treat \\t as a space]
|
||||
expected: FAIL
|
||||
|
||||
[classList.add should treat \\r as a space]
|
||||
expected: FAIL
|
||||
|
||||
[classList.add should treat \\n as a space]
|
||||
expected: FAIL
|
||||
|
||||
[classList.add should treat \\f as a space]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue