mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Implement and test DOMTokenList.replace (fixes #8511)
This commit is contained in:
parent
feddb52e59
commit
d010df92cf
4 changed files with 101 additions and 9 deletions
|
@ -139,6 +139,32 @@ impl DOMTokenListMethods for DOMTokenList {
|
||||||
self.element.set_tokenlist_attribute(&self.local_name, value);
|
self.element.set_tokenlist_attribute(&self.local_name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://dom.spec.whatwg.org/#dom-domtokenlist-replace
|
||||||
|
fn Replace(&self, token: DOMString, new_token: DOMString) -> ErrorResult {
|
||||||
|
if token.is_empty() || new_token.is_empty() {
|
||||||
|
// Step 1.
|
||||||
|
return Err(Error::Syntax);
|
||||||
|
}
|
||||||
|
if token.contains(HTML_SPACE_CHARACTERS) || new_token.contains(HTML_SPACE_CHARACTERS) {
|
||||||
|
// Step 2.
|
||||||
|
return Err(Error::InvalidCharacter);
|
||||||
|
}
|
||||||
|
// Steps 3-4.
|
||||||
|
let token = Atom::from(token);
|
||||||
|
let new_token = Atom::from(new_token);
|
||||||
|
let mut atoms = self.element.get_tokenlist_attribute(&self.local_name);
|
||||||
|
if let Some(pos) = atoms.iter().position(|atom| *atom == token) {
|
||||||
|
if !atoms.contains(&new_token) {
|
||||||
|
atoms[pos] = new_token;
|
||||||
|
} else {
|
||||||
|
atoms.remove(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Step 5.
|
||||||
|
self.element.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#concept-dtl-serialize
|
// https://dom.spec.whatwg.org/#concept-dtl-serialize
|
||||||
fn Stringifier(&self) -> DOMString {
|
fn Stringifier(&self) -> DOMString {
|
||||||
self.element.get_string_attribute(&self.local_name)
|
self.element.get_string_attribute(&self.local_name)
|
||||||
|
|
|
@ -18,6 +18,8 @@ interface DOMTokenList {
|
||||||
void remove(DOMString... tokens);
|
void remove(DOMString... tokens);
|
||||||
[Throws]
|
[Throws]
|
||||||
boolean toggle(DOMString token, optional boolean force);
|
boolean toggle(DOMString token, optional boolean force);
|
||||||
|
[Throws]
|
||||||
|
void replace(DOMString token, DOMString newToken);
|
||||||
|
|
||||||
[Pure]
|
[Pure]
|
||||||
attribute DOMString value;
|
attribute DOMString value;
|
||||||
|
|
|
@ -156,18 +156,9 @@
|
||||||
[DOMSettableTokenList interface object name]
|
[DOMSettableTokenList interface object name]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[DOMTokenList interface: operation replace(DOMString,DOMString)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[DOMTokenList interface: operation supports(DOMString)]
|
[DOMTokenList interface: operation supports(DOMString)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[DOMTokenList interface: document.body.classList must inherit property "replace" with the proper type (6)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[DOMTokenList interface: calling replace(DOMString,DOMString) on document.body.classList with too few arguments must throw TypeError]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[DOMTokenList interface: document.body.classList must inherit property "supports" with the proper type (7)]
|
[DOMTokenList interface: document.body.classList must inherit property "supports" with the proper type (7)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,13 @@ test(function () {
|
||||||
test(function () {
|
test(function () {
|
||||||
assert_throws( 'SYNTAX_ERR', function () { elem.classList.toggle(''); } );
|
assert_throws( 'SYNTAX_ERR', function () { elem.classList.toggle(''); } );
|
||||||
}, '.toggle(empty_string) must throw a SYNTAX_ERR');
|
}, '.toggle(empty_string) must throw a SYNTAX_ERR');
|
||||||
|
test(function () {
|
||||||
|
assert_throws( 'SYNTAX_ERR', function () { elem.classList.replace('', 'foo'); } );
|
||||||
|
assert_throws( 'SYNTAX_ERR', function () { elem.classList.replace('foo', ''); } );
|
||||||
|
assert_throws( 'SYNTAX_ERR', function () { elem.classList.replace('', 'foo bar'); } );
|
||||||
|
assert_throws( 'SYNTAX_ERR', function () { elem.classList.replace('foo bar', ''); } );
|
||||||
|
assert_throws( 'SYNTAX_ERR', function () { elem.classList.replace('', ''); } );
|
||||||
|
}, '.replace with empty_string must throw a SYNTAX_ERR');
|
||||||
test(function () {
|
test(function () {
|
||||||
assert_throws( 'INVALID_CHARACTER_ERR', function () { elem.classList.contains('a b'); } );
|
assert_throws( 'INVALID_CHARACTER_ERR', function () { elem.classList.contains('a b'); } );
|
||||||
}, '.contains(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
|
}, '.contains(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
|
||||||
|
@ -89,6 +96,20 @@ test(function () {
|
||||||
test(function () {
|
test(function () {
|
||||||
assert_throws( 'INVALID_CHARACTER_ERR', function () { elem.classList.toggle('a b'); } );
|
assert_throws( 'INVALID_CHARACTER_ERR', function () { elem.classList.toggle('a b'); } );
|
||||||
}, '.toggle(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
|
}, '.toggle(string_with_spaces) must throw an INVALID_CHARACTER_ERR');
|
||||||
|
test(function () {
|
||||||
|
assert_throws( 'INVALID_CHARACTER_ERR', function () { elem.classList.replace('z', 'a b'); } );
|
||||||
|
assert_throws( 'INVALID_CHARACTER_ERR', function () { elem.classList.replace('a b', 'z'); } );
|
||||||
|
assert_throws( 'INVALID_CHARACTER_ERR', function () { elem.classList.replace('a b', 'b c'); } );
|
||||||
|
}, '.replace with string_with_spaces must throw a INVALID_CHARACTER_ERR');
|
||||||
|
test(function () {
|
||||||
|
var foo = document.createElement('div');
|
||||||
|
foo.className = 'token1 token2 token3'
|
||||||
|
foo.classList.replace('token1', 'token3');
|
||||||
|
assert_equals( foo.classList.length, 2 );
|
||||||
|
assert_false( foo.classList.contains('token1') );
|
||||||
|
assert_true( foo.classList.contains('token2') );
|
||||||
|
assert_true( foo.classList.contains('token3') );
|
||||||
|
}, '.replace with an already existing token')
|
||||||
elem.className = 'foo';
|
elem.className = 'foo';
|
||||||
test(function () {
|
test(function () {
|
||||||
assert_equals( getComputedStyle(elem,null).fontStyle, 'italic', 'critical test; required by the testsuite' );
|
assert_equals( getComputedStyle(elem,null).fontStyle, 'italic', 'critical test; required by the testsuite' );
|
||||||
|
@ -224,6 +245,58 @@ test(function () {
|
||||||
assert_false( elem.classList.contains('foo') );
|
assert_false( elem.classList.contains('foo') );
|
||||||
assert_false( elem.classList.contains('FOO') );
|
assert_false( elem.classList.contains('FOO') );
|
||||||
}, 'classList.toggle must be case-sensitive when removing tokens');
|
}, 'classList.toggle must be case-sensitive when removing tokens');
|
||||||
|
test(function () {
|
||||||
|
secondelem.className = 'foo FOO'
|
||||||
|
secondelem.classList.replace('bar', 'baz');
|
||||||
|
assert_equals( secondelem.classList.length, 2 );
|
||||||
|
assert_equals( secondelem.classList + '', 'foo FOO', 'implicit' );
|
||||||
|
assert_equals( secondelem.classList.toString(), 'foo FOO', 'explicit' );
|
||||||
|
}, 'classList.replace replaces arguments passed, if they are present.');
|
||||||
|
test(function () {
|
||||||
|
secondelem.classList.replace('foo', 'bar');
|
||||||
|
assert_equals( secondelem.classList.length, 2 );
|
||||||
|
assert_equals( secondelem.classList + '', 'bar FOO', 'implicit' );
|
||||||
|
assert_equals( secondelem.classList.toString(), 'bar FOO', 'explicit' );
|
||||||
|
assert_false( secondelem.classList.contains('foo') );
|
||||||
|
assert_true( secondelem.classList.contains('bar') );
|
||||||
|
assert_true( secondelem.classList.contains('FOO') );
|
||||||
|
}, 'classList.replace must replace existing tokens');
|
||||||
|
test(function () {
|
||||||
|
assert_not_equals( getComputedStyle(secondelem,null).fontStyle, 'italic' );
|
||||||
|
}, 'classList.replace must not break case-sensitive CSS selector matching');
|
||||||
|
test(function () {
|
||||||
|
secondelem.className = 'token1 token2 token1'
|
||||||
|
secondelem.classList.replace('token1', 'token3');
|
||||||
|
assert_equals( secondelem.classList.length, 2 );
|
||||||
|
assert_false( secondelem.classList.contains('token1') );
|
||||||
|
assert_true( secondelem.classList.contains('token2') );
|
||||||
|
assert_true( secondelem.classList.contains('token3') );
|
||||||
|
}, 'classList.replace must replace duplicated tokens');
|
||||||
|
test(function () {
|
||||||
|
secondelem.className = 'token1 token2 token3';
|
||||||
|
secondelem.classList.replace('token2', 'token4');
|
||||||
|
assert_equals( secondelem.classList + '', 'token1 token4 token3', 'implicit' );
|
||||||
|
assert_equals( secondelem.classList.toString(), 'token1 token4 token3', 'explicit' );
|
||||||
|
}, 'classList.replace must collapse whitespace around replaced tokens');
|
||||||
|
test(function () {
|
||||||
|
secondelem.className = ' token1 token2 ';
|
||||||
|
secondelem.classList.replace('token2', 'token3');
|
||||||
|
assert_equals( secondelem.classList.length, 2 );
|
||||||
|
assert_equals( secondelem.classList + '', 'token1 token3', 'implicit' );
|
||||||
|
assert_equals( secondelem.classList.toString(), 'token1 token3', 'explicit' );
|
||||||
|
}, 'classList.replace must collapse whitespaces around each token');
|
||||||
|
test(function () {
|
||||||
|
secondelem.className = ' token1 token2 token1 ';
|
||||||
|
secondelem.classList.replace('token2', 'token3');
|
||||||
|
assert_equals( secondelem.classList + '', 'token1 token3', 'implicit' );
|
||||||
|
assert_equals( secondelem.classList.toString(), 'token1 token3', 'explicit' );
|
||||||
|
}, 'classList.replace must collapse whitespaces around each token and remove duplicates');
|
||||||
|
test(function () {
|
||||||
|
secondelem.className = ' token1 token2 token1 ';
|
||||||
|
secondelem.classList.replace('token1', 'token3');
|
||||||
|
assert_equals( secondelem.classList + '', 'token3 token2', 'implicit' );
|
||||||
|
assert_equals( secondelem.classList.toString(), 'token3 token2', 'explicit' );
|
||||||
|
}, 'classList.replace must collapse whitespace when replacing duplicate tokens');
|
||||||
test(function () {
|
test(function () {
|
||||||
assert_not_equals( getComputedStyle(elem,null).fontStyle, 'italic' );
|
assert_not_equals( getComputedStyle(elem,null).fontStyle, 'italic' );
|
||||||
}, 'CSS class selectors must stop matching when all classes have been removed');
|
}, 'CSS class selectors must stop matching when all classes have been removed');
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue