Commit 5361078a authored by Rakina Zata Amni's avatar Rakina Zata Amni Committed by Commit Bot

Implement Element.toggleAttribute

Add a new method Element.toggleAttribute(string qualifiedName,
optional bool force) that allow toggling the existence of an element’s
attribute, similar to Element.classList.toggle.

Spec
https://dom.spec.whatwg.org/#dom-element-toggleattribute

Intent to Implement and Ship
https://groups.google.com/a/chromium.org/d/msg/blink-dev/mAWBTaANvmE/OgaCRH04BAAJ

Bug: 854960
Change-Id: Iab8a1a97dd4e2f8b377bcf590401699f9013aa8a
Reviewed-on: https://chromium-review.googlesource.com/1111761
Commit-Queue: Rakina Zata Amni <rakina@chromium.org>
Reviewed-by: default avatarKent Tamura <tkent@chromium.org>
Reviewed-by: default avatarHayato Ito <hayato@chromium.org>
Cr-Commit-Position: refs/heads/master@{#570348}
parent b0178447
This is a testharness.js-based test.
Found 67 tests; 58 PASS, 9 FAIL, 0 TIMEOUT, 0 NOTRUN.
FAIL When qualifiedName does not match the Name production, an INVALID_CHARACTER_ERR exception is to be thrown. (toggleAttribute) assert_throws: function "function() { el.toggleAttribute(invalid_names[i], true) }" threw object "TypeError: el.toggleAttribute is not a function" that is not a DOMException INVALID_CHARACTER_ERR: property "code" is equal to undefined, expected 5
FAIL When qualifiedName does not match the Name production, an INVALID_CHARACTER_ERR exception is to be thrown, even if the attribute is already present. (toggleAttribute) assert_throws: function "function() {
el.children[i].toggleAttribute("~", false)
}" threw object "TypeError: el.children[i].toggleAttribute is not a function" that is not a DOMException INVALID_CHARACTER_ERR: property "code" is equal to undefined, expected 5
FAIL toggleAttribute should lowercase its name argument (upper case attribute) el.toggleAttribute is not a function
FAIL toggleAttribute should lowercase its name argument (mixed case attribute) el.toggleAttribute is not a function
FAIL toggleAttribute should not throw even when qualifiedName starts with 'xmlns' el.toggleAttribute is not a function
FAIL Basic functionality should be intact. (toggleAttribute) el.toggleAttribute is not a function
FAIL toggleAttribute should not change the order of previously set attributes. el.toggleAttribute is not a function
FAIL toggleAttribute should set the first attribute with the given name el.toggleAttribute is not a function
FAIL toggleAttribute should set the attribute with the given qualified name el.toggleAttribute is not a function
PASS When qualifiedName does not match the Name production, an INVALID_CHARACTER_ERR exception is to be thrown. (setAttribute)
PASS When qualifiedName does not match the Name production, an INVALID_CHARACTER_ERR exception is to be thrown, even if the attribute is already present. (setAttribute)
PASS setAttribute should lowercase its name argument (upper case attribute)
PASS setAttribute should lowercase its name argument (mixed case attribute)
PASS setAttribute should not throw even when qualifiedName starts with 'xmlns'
PASS Basic functionality should be intact.
PASS setAttribute should not change the order of previously set attributes.
PASS setAttribute should set the first attribute with the given name
PASS setAttribute should set the attribute with the given qualified name
PASS When qualifiedName does not match the Name production, an INVALID_CHARACTER_ERR exception is to be thrown. (setAttributeNS)
PASS When qualifiedName does not match the Name production, an INVALID_CHARACTER_ERR exception is to be thrown, even if the attribute is already present. (setAttributeNS)
PASS When qualifiedName does not match the QName production, an INVALID_CHARACTER_ERR exception is to be thrown.
PASS null and the empty string should result in a null namespace.
PASS A namespace is required to use a prefix.
PASS The xml prefix should not be allowed for arbitrary namespaces
PASS XML-namespaced attributes don't need an xml prefix
PASS The xmlns prefix should not be allowed for arbitrary namespaces
PASS The xmlns qualified name should not be allowed for arbitrary namespaces
PASS xmlns should be allowed as local name
PASS The XMLNS namespace should require xmlns as prefix or qualified name
PASS xmlns should be allowed as prefix in the XMLNS namespace
PASS xmlns should be allowed as qualified name in the XMLNS namespace
PASS Setting the same attribute with another prefix should not change the prefix
PASS setAttribute should not throw even if a load is not allowed
PASS Attributes should work in document fragments.
PASS Attribute values should not be parsed.
PASS Specified attributes should be accessible.
PASS Entities in attributes should have been expanded while parsing.
PASS Unset attributes return null
PASS First set attribute is returned by getAttribute
PASS Style attributes are not normalized
PASS Only lowercase attributes are returned on HTML elements (upper case attribute)
PASS Only lowercase attributes are returned on HTML elements (mixed case attribute)
PASS First set attribute is returned with mapped attribute set first
PASS First set attribute is returned with mapped attribute set later
PASS Non-HTML element with upper-case attribute
PASS Attribute with prefix in local name
PASS Attribute loses its owner when removed
PASS Basic functionality of getAttributeNode/getAttributeNodeNS
PASS Basic functionality of setAttributeNode
PASS setAttributeNode should distinguish attributes with same local name and different namespaces
PASS setAttributeNode doesn't have case-insensitivity even with an HTMLElement
PASS Basic functionality of setAttributeNodeNS
PASS If attr’s element is neither null nor element, throw an InUseAttributeError.
PASS Replacing an attr by itself
PASS Basic functionality of removeAttributeNode
PASS setAttributeNode on bound attribute should throw InUseAttributeError
PASS setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute
PASS setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute (outer shell)
PASS setAttributeNode called with an Attr that has the same name as an existing one should not change attribute order
PASS getAttributeNames tests
PASS Own property correctness with basic attributes
PASS Own property correctness with non-namespaced attribute before same-name namespaced one
PASS Own property correctness with namespaced attribute before same-name non-namespaced one
PASS Own property correctness with two namespaced attributes with the same name-with-prefix
PASS Own property names should only include all-lowercase qualified names for an HTML element in an HTML document
PASS Own property names should include all qualified names for a non-HTML element in an HTML document
PASS Own property names should include all qualified names for an HTML element in a non-HTML document
Harness: the test ran to completion.
......@@ -136,6 +136,12 @@ test(function() {
attr_is(el.attributes[0], "2", "bat", "foo", "foo", "foo:bat")
}, "toggleAttribute should set the attribute with the given qualified name")
test(function() {
var el = document.createElement("foo")
el.style = "color: red; background-color: green"
assert_equals(el.toggleAttribute("style"), false)
}, "Toggling element with inline style should make inline style disappear")
// setAttribute exhaustive tests
// Step 1
test(function() {
......
......@@ -241,6 +241,7 @@ namespace http://www.w3.org/1999/xhtml
property textContent
property title
property toString
property toggleAttribute
property translate
property webkitMatchesSelector
property webkitRequestFullScreen
......@@ -1323,6 +1324,7 @@ namespace http://www.w3.org/2000/svg
property tabIndex
property tagName
property textContent
property toggleAttribute
property viewportElement
property webkitMatchesSelector
property webkitRequestFullScreen
......
......@@ -292,6 +292,7 @@ namespace http://www.w3.org/1999/xhtml
property textContent
property title
property toString
property toggleAttribute
property translate
property webkitMatchesSelector
property webkitRequestFullScreen
......@@ -1435,6 +1436,7 @@ namespace http://www.w3.org/2000/svg
property tabIndex
property tagName
property textContent
property toggleAttribute
property viewportElement
property webkitMatchesSelector
property webkitRequestFullScreen
......
......@@ -1964,6 +1964,7 @@ interface Element : Node
method setAttributeNode
method setAttributeNodeNS
method setPointerCapture
method toggleAttribute
method webkitMatchesSelector
method webkitRequestFullScreen
method webkitRequestFullscreen
......
......@@ -1413,6 +1413,79 @@ AccessibleNode* Element::accessibleNode() {
return rare_data.EnsureAccessibleNode(this);
}
bool Element::toggleAttribute(const AtomicString& qualified_name,
ExceptionState& exception_state) {
// https://dom.spec.whatwg.org/#dom-element-toggleattribute
// 1. If qualifiedName does not match the Name production in XML, then throw
// an "InvalidCharacterError" DOMException.
if (!Document::IsValidName(qualified_name)) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidCharacterError,
"'" + qualified_name + "' is not a valid attribute name.");
return false;
}
// 2. If the context object is in the HTML namespace and its node document is
// an HTML document, then set qualifiedName to qualifiedName in ASCII
// lowercase.
AtomicString lower_case_name = LowercaseIfNecessary(qualified_name);
// 3. Let attribute be the first attribute in the context object’s attribute
// list whose qualified name is qualifiedName, and null otherwise.
// 4. If attribute is null, then
if (!getAttribute(lower_case_name)) {
// 4. 1. If force is not given or is true, create an attribute whose local
// name is qualifiedName, value is the empty string, and node document is
// the context object’s node document, then append this attribute to the
// context object, and then return true.
setAttribute(lower_case_name, g_empty_atom);
return true;
}
// 5. Otherwise, if force is not given or is false, remove an attribute given
// qualifiedName and the context object, and then return false.
removeAttribute(lower_case_name);
return false;
}
bool Element::toggleAttribute(const AtomicString& qualified_name,
bool force,
ExceptionState& exception_state) {
// https://dom.spec.whatwg.org/#dom-element-toggleattribute
// 1. If qualifiedName does not match the Name production in XML, then throw
// an "InvalidCharacterError" DOMException.
if (!Document::IsValidName(qualified_name)) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidCharacterError,
"'" + qualified_name + "' is not a valid attribute name.");
return false;
}
// 2. If the context object is in the HTML namespace and its node document is
// an HTML document, then set qualifiedName to qualifiedName in ASCII
// lowercase.
AtomicString lower_case_name = LowercaseIfNecessary(qualified_name);
// 3. Let attribute be the first attribute in the context object’s attribute
// list whose qualified name is qualifiedName, and null otherwise.
// 4. If attribute is null, then
if (!getAttribute(lower_case_name)) {
// 4. 1. If force is not given or is true, create an attribute whose local
// name is qualifiedName, value is the empty string, and node document is
// the context object’s node document, then append this attribute to the
// context object, and then return true.
if (force) {
setAttribute(lower_case_name, g_empty_atom);
return true;
}
// 4. 2. Return false.
return false;
}
// 5. Otherwise, if force is not given or is false, remove an attribute given
// qualifiedName and the context object, and then return false.
if (!force) {
removeAttribute(lower_case_name);
return false;
}
// 6. Return true.
return true;
}
const AtomicString& Element::getAttribute(
const AtomicString& local_name) const {
if (!GetElementData())
......
......@@ -220,6 +220,9 @@ class CORE_EXPORT Element : public ContainerNode {
const AtomicString& value,
ExceptionState&);
bool toggleAttribute(const AtomicString&, ExceptionState&);
bool toggleAttribute(const AtomicString&, bool force, ExceptionState&);
const AtomicString& GetIdAttribute() const;
void SetIdAttribute(const AtomicString&);
......
......@@ -54,6 +54,7 @@ interface Element : Node {
[CEReactions, CustomElementCallbacks] void removeAttributeNS(DOMString? namespaceURI, DOMString localName);
[Affects=Nothing] boolean hasAttribute(DOMString name);
[Affects=Nothing] boolean hasAttributeNS(DOMString? namespaceURI, DOMString localName);
[RaisesException] boolean toggleAttribute(DOMString qualifiedName, optional boolean force);
Attr? getAttributeNode(DOMString name);
Attr? getAttributeNodeNS(DOMString? namespaceURI, DOMString localName);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment