bors-servo 2014-12-26 13:18:45 -07:00
commit 3af73e9962
9 changed files with 106 additions and 112 deletions

View file

@ -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)
}

View file

@ -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)
}
}
}
}
}

View file

@ -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),
}
}

View file

@ -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),
}
}

View file

@ -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),
}
}

View file

@ -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),
}
}

View file

@ -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;
};

View file

@ -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

View file

@ -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