aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/components/script/dom/domtokenlist.rs23
-rw-r--r--src/components/script/dom/webidls/DOMTokenList.webidl5
-rw-r--r--src/test/content/test_domtokenlist.html45
-rw-r--r--src/test/wpt/metadata/dom/interfaces.html.ini9
-rw-r--r--src/test/wpt/metadata/dom/nodes/Element-classlist.html.ini39
5 files changed, 71 insertions, 50 deletions
diff --git a/src/components/script/dom/domtokenlist.rs b/src/components/script/dom/domtokenlist.rs
index cf44d5f7abc..3d252d36731 100644
--- a/src/components/script/dom/domtokenlist.rs
+++ b/src/components/script/dom/domtokenlist.rs
@@ -5,14 +5,16 @@
use dom::attr::{Attr, TokenListAttrValue};
use dom::bindings::codegen::Bindings::DOMTokenListBinding;
use dom::bindings::codegen::Bindings::DOMTokenListBinding::DOMTokenListMethods;
+use dom::bindings::error::{Fallible, InvalidCharacter, Syntax};
use dom::bindings::global::Window;
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable};
use dom::bindings::utils::{Reflector, Reflectable, reflect_dom_object};
use dom::element::{Element, AttributeHandlers};
use dom::node::window_from_node;
+use servo_util::atom::Atom;
use servo_util::namespace::Null;
-use servo_util::str::DOMString;
+use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS};
#[deriving(Encodable)]
pub struct DOMTokenList {
@@ -47,6 +49,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>;
}
impl<'a> PrivateDOMTokenListHelpers for JSRef<'a, DOMTokenList> {
@@ -54,6 +57,14 @@ impl<'a> PrivateDOMTokenListHelpers for JSRef<'a, DOMTokenList> {
let element = self.element.root();
element.deref().get_attribute(Null, self.local_name)
}
+
+ fn check_token_exceptions<'a>(&self, token: &'a str) -> Fallible<&'a str> {
+ match token {
+ "" => Err(Syntax),
+ token if token.find(HTML_SPACE_CHARACTERS).is_some() => Err(InvalidCharacter),
+ token => Ok(token)
+ }
+ }
}
// http://dom.spec.whatwg.org/#domtokenlist
@@ -92,4 +103,14 @@ impl<'a> DOMTokenListMethods for JSRef<'a, DOMTokenList> {
*found = item.is_some();
item
}
+
+ // 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.attribute().root().and_then(|attr| attr.value().tokens().map(|mut tokens| {
+ let atom = Atom::from_slice(slice);
+ tokens.any(|token| *token == atom)
+ })).unwrap_or(false)
+ })
+ }
}
diff --git a/src/components/script/dom/webidls/DOMTokenList.webidl b/src/components/script/dom/webidls/DOMTokenList.webidl
index 650d8abf6c6..bc32f4bf256 100644
--- a/src/components/script/dom/webidls/DOMTokenList.webidl
+++ b/src/components/script/dom/webidls/DOMTokenList.webidl
@@ -7,7 +7,10 @@
interface DOMTokenList {
readonly attribute unsigned long length;
getter DOMString? item(unsigned long index);
- //boolean contains(DOMString token);
+
+ [Throws]
+ boolean contains(DOMString token);
+
//void add(DOMString... tokens);
//void remove(DOMString... tokens);
//boolean toggle(DOMString token, optional boolean force);
diff --git a/src/test/content/test_domtokenlist.html b/src/test/content/test_domtokenlist.html
new file mode 100644
index 00000000000..bc32777ec0e
--- /dev/null
+++ b/src/test/content/test_domtokenlist.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script src="harness.js"></script>
+ <script>
+ var div = document.createElement("div");
+ var classList = div.classList;
+
+ is(classList.length, 0);
+ is(classList.item(0), null);
+ should_throw(function () {
+ classList.contains("");
+ });
+ should_throw(function () {
+ classList.contains(" ");
+ });
+
+ var list = ["foo", " foo", "foo ", " foo ", " foo "];
+ for(var i = 0; i < list.length; i++) {
+ div.className = list[i];
+ is(div.className, list[i]);
+ is(classList.length, 1);
+ is(classList.item(0), "foo");
+ is(classList.item(1), null);
+ is(classList.contains("foo"), true);
+ is(classList.contains("bar"), false);
+ }
+
+ list = ["foo bar", " foo bar", " foo bar ", " foo bar "];
+ for(var i = 0; i < list.length; i++) {
+ div.className = list[i];
+ is(div.className, list[i]);
+ is(classList.length, 2);
+ is(classList.item(0), "foo");
+ is(classList.item(1), "bar");
+ is(classList.item(2), null);
+ is(classList.contains("foo"), true);
+ is(classList.contains("bar"), true);
+ is(classList.contains("baz"), false);
+ }
+
+ finish();
+ </script>
+ </head>
+</html>
diff --git a/src/test/wpt/metadata/dom/interfaces.html.ini b/src/test/wpt/metadata/dom/interfaces.html.ini
index f534ec23922..53d11f5d15f 100644
--- a/src/test/wpt/metadata/dom/interfaces.html.ini
+++ b/src/test/wpt/metadata/dom/interfaces.html.ini
@@ -1017,9 +1017,6 @@
[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 contains(DOMString)]
- expected: FAIL
-
[DOMTokenList interface: operation add(DOMString)]
expected: FAIL
@@ -1029,12 +1026,6 @@
[DOMTokenList interface: operation toggle(DOMString,boolean)]
expected: FAIL
- [DOMTokenList interface: document.body.classList must inherit property "contains" with the proper type (2)]
- expected: FAIL
-
- [DOMTokenList interface: calling contains(DOMString) on document.body.classList with too few arguments must throw TypeError]
- expected: FAIL
-
[DOMTokenList interface: document.body.classList must inherit property "add" with the proper type (3)]
expected: FAIL
diff --git a/src/test/wpt/metadata/dom/nodes/Element-classlist.html.ini b/src/test/wpt/metadata/dom/nodes/Element-classlist.html.ini
index 61f7cd11fbf..b1c1947cac2 100644
--- a/src/test/wpt/metadata/dom/nodes/Element-classlist.html.ini
+++ b/src/test/wpt/metadata/dom/nodes/Element-classlist.html.ini
@@ -6,24 +6,9 @@
[classList must be correct for an element that has classes]
expected: FAIL
- [classList.length must be 0 for an element that has no classes]
- expected: FAIL
-
- [classList must not contain an undefined class]
- expected: FAIL
-
- [classList.item() must return null for out-of-range index]
- expected: FAIL
-
- [classList[index\] must be undefined for out-of-range index]
- expected: FAIL
-
[empty classList should return the empty string since the ordered set parser skip the whitespaces]
expected: FAIL
- [.contains(empty_string) must throw a SYNTAX_ERR]
- expected: FAIL
-
[.add(empty_string) must throw a SYNTAX_ERR]
expected: FAIL
@@ -33,9 +18,6 @@
[.toggle(empty_string) must throw a SYNTAX_ERR]
expected: FAIL
- [.contains(string_with_spaces) must throw an INVALID_CHARACTER_ERR]
- expected: FAIL
-
[.add(string_with_spaces) must throw an INVALID_CHARACTER_ERR]
expected: FAIL
@@ -48,36 +30,18 @@
[computed style must update when setting .className]
expected: FAIL
- [classList.contains must update when .className is changed]
- expected: FAIL
-
- [classList.contains must be case sensitive]
- expected: FAIL
-
- [classList.contains must not match when punctuation characters are added]
- expected: FAIL
-
[classList.add must not cause the CSS selector to stop matching]
expected: FAIL
- [classList.add must not remove existing classes]
- 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(0) must return the first token]
- expected: FAIL
-
[classList.item must return case-sensitive strings and preserve token order]
expected: FAIL
- [classList[0\] must return the first token]
- expected: FAIL
-
[classList[index\] must return case-sensitive strings and preserve token order]
expected: FAIL
@@ -153,6 +117,3 @@
[classList.add should treat \\f as a space]
expected: FAIL
- [classList.length must be read-only]
- expected: FAIL
-