From eb3678fa286fc2480624c977b1de5b60a971b3f7 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Mon, 15 Dec 2014 12:33:49 -0400 Subject: [PATCH 1/9] AttrValue's s/from_tokenlist/from_serialized_tokenlist/ --- components/script/dom/attr.rs | 2 +- components/script/dom/element.rs | 4 ++-- components/script/dom/htmlanchorelement.rs | 2 +- components/script/dom/htmlareaelement.rs | 2 +- components/script/dom/htmllinkelement.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs index d1b288bd7ad..2b821371819 100644 --- a/components/script/dom/attr.rs +++ b/components/script/dom/attr.rs @@ -37,7 +37,7 @@ pub enum AttrValue { } impl AttrValue { - pub fn from_tokenlist(tokens: DOMString) -> AttrValue { + pub fn from_serialized_tokenlist(tokens: DOMString) -> AttrValue { let atoms = split_html_space_chars(tokens.as_slice()) .map(|token| Atom::from_slice(token)).collect(); AttrValue::TokenList(tokens, atoms) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 52a16fc6ea4..ba6e94445a6 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -848,7 +848,7 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { 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 get_uint_attribute(self, name: &Atom) -> u32 { @@ -1290,7 +1290,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), } } diff --git a/components/script/dom/htmlanchorelement.rs b/components/script/dom/htmlanchorelement.rs index 10d574672a3..c4e9558c359 100644 --- a/components/script/dom/htmlanchorelement.rs +++ b/components/script/dom/htmlanchorelement.rs @@ -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), } } diff --git a/components/script/dom/htmlareaelement.rs b/components/script/dom/htmlareaelement.rs index 1ede87d380d..4871f35dc2d 100644 --- a/components/script/dom/htmlareaelement.rs +++ b/components/script/dom/htmlareaelement.rs @@ -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), } } diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index f84314b7008..1105d60c6c6 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -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), } } From c5f7e553e43d865194d3251e584b166f4aa1095d Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 16 Dec 2014 11:02:04 -0400 Subject: [PATCH 2/9] Avoid duplicated tokens in AttrValue::from_serialized_tokenlist --- components/script/dom/attr.rs | 8 ++++++-- tests/wpt/metadata/dom/nodes/Element-classlist.html.ini | 6 ------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs index 2b821371819..a848ca85e0c 100644 --- a/components/script/dom/attr.rs +++ b/components/script/dom/attr.rs @@ -38,8 +38,12 @@ pub enum AttrValue { impl AttrValue { pub fn from_serialized_tokenlist(tokens: DOMString) -> AttrValue { - let atoms = split_html_space_chars(tokens.as_slice()) - .map(|token| Atom::from_slice(token)).collect(); + let mut atoms: Vec = 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) } diff --git a/tests/wpt/metadata/dom/nodes/Element-classlist.html.ini b/tests/wpt/metadata/dom/nodes/Element-classlist.html.ini index c072735d502..3ec7b9070e1 100644 --- a/tests/wpt/metadata/dom/nodes/Element-classlist.html.ini +++ b/tests/wpt/metadata/dom/nodes/Element-classlist.html.ini @@ -3,9 +3,6 @@ [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 @@ -63,9 +60,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 From 8859286a99f31ca25e516eb23db79a5fedbef980 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Sat, 20 Dec 2014 16:56:19 -0400 Subject: [PATCH 3/9] Added AttrValue::from_atomic_tokens & Element::set_atomic_tokenlist_attribute --- components/script/dom/attr.rs | 8 ++++++++ components/script/dom/element.rs | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs index a848ca85e0c..014fa5f5357 100644 --- a/components/script/dom/attr.rs +++ b/components/script/dom/attr.rs @@ -47,6 +47,14 @@ impl AttrValue { AttrValue::TokenList(tokens, atoms) } + pub fn from_atomic_tokens(atoms: Vec) -> AttrValue { + let tokens = { + let slices: Vec<&str> = atoms.iter().map(|atom| atom.as_slice()).collect(); + slices.connect("\x20") + }; + AttrValue::TokenList(tokens, atoms) + } + pub fn from_u32(string: DOMString, default: u32) -> AttrValue { let result: u32 = from_str(string.as_slice()).unwrap_or(default); AttrValue::UInt(string, result) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index ba6e94445a6..8c858c2d3b6 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -656,6 +656,7 @@ pub trait AttributeHandlers { fn get_string_attribute(self, name: &Atom) -> DOMString; fn set_string_attribute(self, name: &Atom, value: DOMString); fn set_tokenlist_attribute(self, name: &Atom, value: DOMString); + fn set_atomic_tokenlist_attribute(self, name: &Atom, tokens: Vec); fn get_uint_attribute(self, name: &Atom) -> u32; fn set_uint_attribute(self, name: &Atom, value: u32); } @@ -851,6 +852,11 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { self.set_attribute(name, AttrValue::from_serialized_tokenlist(value)); } + fn set_atomic_tokenlist_attribute(self, name: &Atom, tokens: Vec) { + 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 { assert!(name.as_slice().chars().all(|ch| { !ch.is_ascii() || ch.to_ascii().to_lowercase() == ch.to_ascii() From 51fac3d2cc69c6d4c47ed4ad3f0ee2b1248f8b30 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Sat, 20 Dec 2014 16:56:45 -0400 Subject: [PATCH 4/9] Added Element::get_tokenlist_attribute --- components/script/dom/element.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 8c858c2d3b6..60c12399160 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -655,6 +655,7 @@ 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; fn set_tokenlist_attribute(self, name: &Atom, value: DOMString); fn set_atomic_tokenlist_attribute(self, name: &Atom, tokens: Vec); fn get_uint_attribute(self, name: &Atom) -> u32; @@ -847,6 +848,15 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { self.set_attribute(name, AttrValue::String(value)); } + fn get_tokenlist_attribute(self, name: &Atom) -> Vec { + 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_serialized_tokenlist(value)); From 08e7cf24cd0cdb2f1c0d95718e388b7ab0f4e8ed Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Fri, 12 Dec 2014 12:54:02 -0400 Subject: [PATCH 5/9] DOMTokenList::check_token_exceptions now returns an Atom --- components/script/dom/domtokenlist.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/components/script/dom/domtokenlist.rs b/components/script/dom/domtokenlist.rs index 6ba0307b14e..4169e87487f 100644 --- a/components/script/dom/domtokenlist.rs +++ b/components/script/dom/domtokenlist.rs @@ -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>; - fn check_token_exceptions<'a>(self, token: &'a str) -> Fallible<&'a str>; + fn check_token_exceptions<'a>(self, token: &'a str) -> Fallible; } 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 { 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,13 +90,13 @@ impl<'a> DOMTokenListMethods for JSRef<'a, DOMTokenList> { // http://dom.spec.whatwg.org/#dom-domtokenlist-contains fn Contains(self, token: DOMString) -> Fallible { - 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) }) } From aa29dc195d04f7d586a6eee5db80bfc575924c86 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Fri, 12 Dec 2014 12:55:55 -0400 Subject: [PATCH 6/9] Implement DOMTokenList.add --- components/script/dom/domtokenlist.rs | 14 ++++++++++++++ components/script/dom/webidls/DOMTokenList.webidl | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/components/script/dom/domtokenlist.rs b/components/script/dom/domtokenlist.rs index 4169e87487f..6f7fbf369ca 100644 --- a/components/script/dom/domtokenlist.rs +++ b/components/script/dom/domtokenlist.rs @@ -100,4 +100,18 @@ impl<'a> DOMTokenListMethods for JSRef<'a, DOMTokenList> { }).unwrap_or(false) }) } + + // https://dom.spec.whatwg.org/#dom-domtokenlist-add + fn Add(self, tokens: Vec) -> 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(()) + } } diff --git a/components/script/dom/webidls/DOMTokenList.webidl b/components/script/dom/webidls/DOMTokenList.webidl index bc32f4bf256..67faa24b587 100644 --- a/components/script/dom/webidls/DOMTokenList.webidl +++ b/components/script/dom/webidls/DOMTokenList.webidl @@ -10,8 +10,9 @@ interface DOMTokenList { [Throws] boolean contains(DOMString token); + [Throws] + void add(DOMString... tokens); - //void add(DOMString... tokens); //void remove(DOMString... tokens); //boolean toggle(DOMString token, optional boolean force); //stringifier; From 2cfb4648ceea2da3865d619cd4a480bf69901e5f Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Fri, 12 Dec 2014 12:56:35 -0400 Subject: [PATCH 7/9] Implement DOMTokenList.remove --- components/script/dom/domtokenlist.rs | 14 ++++++++++++++ components/script/dom/webidls/DOMTokenList.webidl | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/components/script/dom/domtokenlist.rs b/components/script/dom/domtokenlist.rs index 6f7fbf369ca..8d91540ca2f 100644 --- a/components/script/dom/domtokenlist.rs +++ b/components/script/dom/domtokenlist.rs @@ -114,4 +114,18 @@ impl<'a> DOMTokenListMethods for JSRef<'a, DOMTokenList> { element.set_atomic_tokenlist_attribute(&self.local_name, atoms); Ok(()) } + + // https://dom.spec.whatwg.org/#dom-domtokenlist-remove + fn Remove(self, tokens: Vec) -> 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(()) + } } diff --git a/components/script/dom/webidls/DOMTokenList.webidl b/components/script/dom/webidls/DOMTokenList.webidl index 67faa24b587..9a10a188310 100644 --- a/components/script/dom/webidls/DOMTokenList.webidl +++ b/components/script/dom/webidls/DOMTokenList.webidl @@ -12,8 +12,9 @@ interface DOMTokenList { boolean contains(DOMString token); [Throws] void add(DOMString... tokens); + [Throws] + void remove(DOMString... tokens); - //void remove(DOMString... tokens); //boolean toggle(DOMString token, optional boolean force); //stringifier; }; From 5afcf3ef652b71e340363d52cbd28db7c1dc70a4 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Fri, 12 Dec 2014 12:56:48 -0400 Subject: [PATCH 8/9] Implement DOMTokenList.toggle --- components/script/dom/domtokenlist.rs | 25 +++++++++++++++++++ .../script/dom/webidls/DOMTokenList.webidl | 3 ++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/components/script/dom/domtokenlist.rs b/components/script/dom/domtokenlist.rs index 8d91540ca2f..fc1ed509568 100644 --- a/components/script/dom/domtokenlist.rs +++ b/components/script/dom/domtokenlist.rs @@ -128,4 +128,29 @@ impl<'a> DOMTokenListMethods for JSRef<'a, DOMTokenList> { 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) -> Fallible { + 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) + } + } + } + } } diff --git a/components/script/dom/webidls/DOMTokenList.webidl b/components/script/dom/webidls/DOMTokenList.webidl index 9a10a188310..4cdcea84255 100644 --- a/components/script/dom/webidls/DOMTokenList.webidl +++ b/components/script/dom/webidls/DOMTokenList.webidl @@ -14,7 +14,8 @@ interface DOMTokenList { void add(DOMString... tokens); [Throws] void remove(DOMString... tokens); + [Throws] + boolean toggle(DOMString token, optional boolean force); - //boolean toggle(DOMString token, optional boolean force); //stringifier; }; From 3624673d2faf7a36face3321af70fc55117a24a7 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Fri, 12 Dec 2014 12:57:01 -0400 Subject: [PATCH 9/9] Updated web-platform-tests results --- tests/wpt/metadata/dom/interfaces.html.ini | 18 ----- .../dom/nodes/Element-classlist.html.ini | 66 ------------------- 2 files changed, 84 deletions(-) diff --git a/tests/wpt/metadata/dom/interfaces.html.ini b/tests/wpt/metadata/dom/interfaces.html.ini index 941b80264b2..3a11f7df0d6 100644 --- a/tests/wpt/metadata/dom/interfaces.html.ini +++ b/tests/wpt/metadata/dom/interfaces.html.ini @@ -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 diff --git a/tests/wpt/metadata/dom/nodes/Element-classlist.html.ini b/tests/wpt/metadata/dom/nodes/Element-classlist.html.ini index 3ec7b9070e1..9a6f69132ab 100644 --- a/tests/wpt/metadata/dom/nodes/Element-classlist.html.ini +++ b/tests/wpt/metadata/dom/nodes/Element-classlist.html.ini @@ -6,45 +6,12 @@ [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 @@ -75,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 -