зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #3061 - Implement DOMTokenList.contains; r=Ms2ger (from brunoabinader:domtokenlist)
Source-Repo: https://github.com/servo/servo Source-Revision: ce452801109d0d828b36aa08ed9242b921dc4bc3
This commit is contained in:
Родитель
adc3335def
Коммит
977edc8d5c
|
@ -16,9 +16,10 @@ use dom::virtualmethods::vtable_for;
|
|||
use servo_util::atom::Atom;
|
||||
use servo_util::namespace;
|
||||
use servo_util::namespace::Namespace;
|
||||
use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS};
|
||||
use servo_util::str::{DOMString, split_html_space_chars};
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::mem;
|
||||
use std::slice::Items;
|
||||
|
||||
pub enum AttrSettingType {
|
||||
FirstSetAttr,
|
||||
|
@ -28,22 +29,16 @@ pub enum AttrSettingType {
|
|||
#[deriving(PartialEq, Clone, Encodable)]
|
||||
pub enum AttrValue {
|
||||
StringAttrValue(DOMString),
|
||||
TokenListAttrValue(DOMString, Vec<(uint, uint)>),
|
||||
TokenListAttrValue(DOMString, Vec<Atom>),
|
||||
UIntAttrValue(DOMString, u32),
|
||||
AtomAttrValue(Atom),
|
||||
}
|
||||
|
||||
impl AttrValue {
|
||||
pub fn from_tokenlist(list: DOMString) -> AttrValue {
|
||||
let mut indexes = vec![];
|
||||
let mut last_index: uint = 0;
|
||||
for (index, ch) in list.as_slice().char_indices() {
|
||||
if HTML_SPACE_CHARACTERS.iter().any(|&space| space == ch) {
|
||||
indexes.push((last_index, index));
|
||||
last_index = index + 1;
|
||||
}
|
||||
}
|
||||
return TokenListAttrValue(list, indexes);
|
||||
pub fn from_tokenlist(tokens: DOMString) -> AttrValue {
|
||||
let atoms = split_html_space_chars(tokens.as_slice())
|
||||
.map(|token| Atom::from_slice(token)).collect();
|
||||
TokenListAttrValue(tokens, atoms)
|
||||
}
|
||||
|
||||
pub fn from_u32(string: DOMString, default: u32) -> AttrValue {
|
||||
|
@ -56,6 +51,12 @@ impl AttrValue {
|
|||
AtomAttrValue(value)
|
||||
}
|
||||
|
||||
pub fn tokens<'a>(&'a self) -> Option<Items<'a, Atom>> {
|
||||
match *self {
|
||||
TokenListAttrValue(_, ref tokens) => Some(tokens.iter()),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Str for AttrValue {
|
||||
|
|
|
@ -2,17 +2,19 @@
|
|||
* 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 dom::attr::{Attr, TokenListAttrValue};
|
||||
use dom::attr::Attr;
|
||||
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,37 +57,30 @@ 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
|
||||
impl<'a> DOMTokenListMethods for JSRef<'a, DOMTokenList> {
|
||||
// http://dom.spec.whatwg.org/#dom-domtokenlist-length
|
||||
fn Length(&self) -> u32 {
|
||||
let attribute = self.attribute().root();
|
||||
match attribute {
|
||||
Some(attribute) => {
|
||||
match *attribute.deref().value() {
|
||||
TokenListAttrValue(_, ref indexes) => indexes.len() as u32,
|
||||
_ => fail!("Expected a TokenListAttrValue"),
|
||||
}
|
||||
}
|
||||
None => 0,
|
||||
}
|
||||
self.attribute().root().map(|attr| {
|
||||
attr.value().tokens().map(|tokens| tokens.len()).unwrap_or(0)
|
||||
}).unwrap_or(0) as u32
|
||||
}
|
||||
|
||||
// http://dom.spec.whatwg.org/#dom-domtokenlist-item
|
||||
fn Item(&self, index: u32) -> Option<DOMString> {
|
||||
let attribute = self.attribute().root();
|
||||
attribute.and_then(|attribute| {
|
||||
match *attribute.deref().value() {
|
||||
TokenListAttrValue(ref value, ref indexes) => {
|
||||
indexes.as_slice().get(index as uint).map(|&(start, end)| {
|
||||
value.as_slice().slice(start, end).to_string()
|
||||
})
|
||||
},
|
||||
_ => fail!("Expected a TokenListAttrValue"),
|
||||
}
|
||||
})
|
||||
self.attribute().root().and_then(|attr| attr.value().tokens().and_then(|mut tokens| {
|
||||
tokens.idx(index as uint).map(|token| token.as_slice().to_string())
|
||||
}))
|
||||
}
|
||||
|
||||
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<DOMString> {
|
||||
|
@ -92,4 +88,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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ use style;
|
|||
use servo_util::atom::Atom;
|
||||
use servo_util::namespace;
|
||||
use servo_util::namespace::{Namespace, Null};
|
||||
use servo_util::str::{DOMString, null_str_as_empty_ref, split_html_space_chars};
|
||||
use servo_util::str::{DOMString, null_str_as_empty_ref};
|
||||
|
||||
use std::ascii::StrAsciiExt;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
@ -377,9 +377,11 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> {
|
|||
}
|
||||
|
||||
fn has_class(&self, name: &str) -> bool {
|
||||
let class_names = self.get_string_attribute("class");
|
||||
let mut classes = split_html_space_chars(class_names.as_slice());
|
||||
classes.any(|class| name == class)
|
||||
self.get_attribute(Null, "class").root().map(|attr| {
|
||||
attr.deref().value().tokens().map(|mut tokens| {
|
||||
tokens.any(|atom| atom.as_slice() == name)
|
||||
}).unwrap_or(false)
|
||||
}).unwrap_or(false)
|
||||
}
|
||||
|
||||
fn set_atomic_attribute(&self, name: &str, value: DOMString) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
|
@ -0,0 +1,21 @@
|
|||
<!-- Remove this and update WPT metadata once DOMTokenList.toggle (#3138) is implemented. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="harness.js"></script>
|
||||
<script>
|
||||
let div = document.createElement("div");
|
||||
div.className = "foo bar";
|
||||
|
||||
let classList = div.classList;
|
||||
div.className = "";
|
||||
|
||||
is(classList.item(0), null, "classList.item(0) must return null when all classes have been removed");
|
||||
is(classList[0], undefined, "classList[0] must be undefined when all classes have been removed");
|
||||
|
||||
finish();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче