Title: [233475] trunk
Revision
233475
Author
[email protected]
Date
2018-07-03 13:46:38 -0700 (Tue, 03 Jul 2018)

Log Message

Implement support for Element.toggleAttribute
https://bugs.webkit.org/show_bug.cgi?id=186883

Reviewed by Sam Weinig.

LayoutTests/imported/w3c:

Import WPT test coverage from:
https://github.com/web-platform-tests/wpt/commit/c3db018b96681af3c73ec331ecc01d38e48b8b10

* web-platform-tests/dom/nodes/attributes-expected.txt:
* web-platform-tests/dom/nodes/attributes.html:

Source/WebCore:

Implement support for Element.toggleAttribute as per:
- https://github.com/whatwg/dom/issues/461
- https://dom.spec.whatwg.org/#dom-element-toggleattribute

This was already implemented in Blink:
- https://bugs.chromium.org/p/chromium/issues/detail?id=854960

Edge expressed public support:
- https://github.com/whatwg/dom/issues/461#issuecomment-398206390

Gecko is working on it:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1469592

* dom/Element.cpp:
(WebCore::Element::toggleAttribute):
* dom/Element.h:
* dom/Element.idl:

Modified Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (233474 => 233475)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2018-07-03 20:44:59 UTC (rev 233474)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2018-07-03 20:46:38 UTC (rev 233475)
@@ -1,3 +1,16 @@
+2018-07-03  Chris Dumez  <[email protected]>
+
+        Implement support for Element.toggleAttribute
+        https://bugs.webkit.org/show_bug.cgi?id=186883
+
+        Reviewed by Sam Weinig.
+
+        Import WPT test coverage from:
+        https://github.com/web-platform-tests/wpt/commit/c3db018b96681af3c73ec331ecc01d38e48b8b10
+
+        * web-platform-tests/dom/nodes/attributes-expected.txt:
+        * web-platform-tests/dom/nodes/attributes.html:
+
 2018-07-03  Frederic Wang  <[email protected]>
 
         Import WPT infrastructure tests

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/dom/nodes/attributes-expected.txt (233474 => 233475)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/dom/nodes/attributes-expected.txt	2018-07-03 20:44:59 UTC (rev 233474)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/dom/nodes/attributes-expected.txt	2018-07-03 20:46:38 UTC (rev 233475)
@@ -1,4 +1,14 @@
 
+PASS When qualifiedName does not match the Name production, an INVALID_CHARACTER_ERR exception is to be thrown. (toggleAttribute) 
+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. (toggleAttribute) 
+PASS toggleAttribute should lowercase its name argument (upper case attribute) 
+PASS toggleAttribute should lowercase its name argument (mixed case attribute) 
+PASS toggleAttribute should not throw even when qualifiedName starts with 'xmlns' 
+PASS Basic functionality should be intact. (toggleAttribute) 
+PASS toggleAttribute should not change the order of previously set attributes. 
+PASS toggleAttribute should set the first attribute with the given name 
+PASS toggleAttribute should set the attribute with the given qualified name 
+PASS Toggling element with inline style should make inline style disappear 
 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) 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/dom/nodes/attributes.html (233474 => 233475)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/dom/nodes/attributes.html	2018-07-03 20:44:59 UTC (rev 233474)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/dom/nodes/attributes.html	2018-07-03 20:46:38 UTC (rev 233475)
@@ -20,6 +20,128 @@
 var XML = "http://www.w3.org/XML/1998/namespace"
 var XMLNS = "http://www.w3.org/2000/xmlns/"
 
+// toggleAttribute exhaustive tests
+// Step 1
+test(function() {
+  var el = document.createElement("foo")
+  for (var i = 0; i < invalid_names.length; i++) {
+    assert_throws("INVALID_CHARACTER_ERR", function() { el.toggleAttribute(invalid_names[i], true) })
+  }
+  for (var i = 0; i < invalid_names.length; i++) {
+    assert_throws("INVALID_CHARACTER_ERR", function() { el.toggleAttribute(invalid_names[i]) })
+  }
+  for (var i = 0; i < invalid_names.length; i++) {
+    assert_throws("INVALID_CHARACTER_ERR", function() { el.toggleAttribute(invalid_names[i], false) })
+  }
+}, "When qualifiedName does not match the Name production, an " +
+   "INVALID_CHARACTER_ERR exception is to be thrown. (toggleAttribute)")
+test(function() {
+  var el = document.getElementById("test2")
+  for (var i = 0; i < el.children.length; i++) {
+    assert_throws("INVALID_CHARACTER_ERR", function() {
+      el.children[i].toggleAttribute("~", false)
+    })
+  }
+  for (var i = 0; i < el.children.length; i++) {
+    assert_throws("INVALID_CHARACTER_ERR", function() {
+      el.children[i].toggleAttribute("~")
+    })
+  }
+  for (var i = 0; i < el.children.length; i++) {
+    assert_throws("INVALID_CHARACTER_ERR", function() {
+      el.children[i].toggleAttribute("~", true)
+    })
+  }
+}, "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)")
+
+// Step 2
+test(function() {
+  var el = document.createElement("div")
+  assert_true(el.toggleAttribute("ALIGN"))
+  assert_true(!el.hasAttributeNS("", "ALIGN"))
+  assert_true(el.hasAttributeNS("", "align"))
+  assert_true(el.hasAttribute("align"))
+  assert_true(!el.toggleAttribute("ALIGN"))
+  assert_true(!el.hasAttributeNS("", "ALIGN"))
+  assert_true(!el.hasAttributeNS("", "align"))
+  assert_true(!el.hasAttribute("align"))
+}, "toggleAttribute should lowercase its name argument (upper case attribute)")
+test(function() {
+  var el = document.createElement("div")
+  assert_true(el.toggleAttribute("CHEEseCaKe"))
+  assert_true(!el.hasAttributeNS("", "CHEEseCaKe"))
+  assert_true(el.hasAttributeNS("", "cheesecake"))
+  assert_true(el.hasAttribute("cheesecake"))
+}, "toggleAttribute should lowercase its name argument (mixed case attribute)")
+
+// Step 3
+test(function() {
+  var el = document.createElement("foo")
+  var tests = ["xmlns", "xmlns:a", "xmlnsx", "xmlns0"]
+  for (var i = 0; i < tests.length; i++) {
+    assert_true(el.toggleAttribute(tests[i]));
+    assert_true(el.hasAttribute(tests[i]));
+  }
+}, "toggleAttribute should not throw even when qualifiedName starts with 'xmlns'")
+
+// Step 4
+test(function() {
+  var el = document.createElement("foo")
+  for (var i = 0; i < valid_names.length; i++) {
+    assert_true(el.toggleAttribute(valid_names[i]))
+    assert_true(el.hasAttribute(valid_names[i]))
+    assert_true(!el.toggleAttribute(valid_names[i]))
+    assert_true(!el.hasAttribute(valid_names[i]))
+    // Check using force attr
+    assert_true(el.toggleAttribute(valid_names[i], true))
+    assert_true(el.hasAttribute(valid_names[i]))
+    assert_true(el.toggleAttribute(valid_names[i], true))
+    assert_true(el.hasAttribute(valid_names[i]))
+    assert_true(!el.toggleAttribute(valid_names[i], false))
+    assert_true(!el.hasAttribute(valid_names[i]))
+  }
+}, "Basic functionality should be intact. (toggleAttribute)")
+
+// Step 5
+test(function() {
+  var el = document.createElement("foo")
+  el.toggleAttribute("a")
+  el.toggleAttribute("b")
+  el.setAttribute("a", "thing")
+  el.toggleAttribute("c")
+  attributes_are(el, [["a", "thing"],
+                      ["b", ""],
+                      ["c", ""]])
+}, "toggleAttribute should not change the order of previously set attributes.")
+test(function() {
+  var el = document.createElement("baz")
+  el.setAttributeNS("ab", "attr", "fail")
+  el.setAttributeNS("kl", "attr", "pass")
+  el.toggleAttribute("attr")
+  attributes_are(el, [["attr", "pass", "kl"]])
+}, "toggleAttribute should set the first attribute with the given name")
+test(function() {
+  // Based on a test by David Flanagan.
+  var el = document.createElement("baz")
+  el.setAttributeNS("foo", "foo:bar", "1");
+  el.setAttributeNS("foo", "foo:bat", "2");
+  assert_equals(el.getAttribute("foo:bar"), "1")
+  assert_equals(el.getAttribute("foo:bat"), "2")
+  attr_is(el.attributes[0], "1", "bar", "foo", "foo", "foo:bar")
+  attr_is(el.attributes[1], "2", "bat", "foo", "foo", "foo:bat")
+  el.toggleAttribute("foo:bar");
+  assert_true(!el.hasAttribute("foo:bar"))
+  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() {

Modified: trunk/Source/WebCore/ChangeLog (233474 => 233475)


--- trunk/Source/WebCore/ChangeLog	2018-07-03 20:44:59 UTC (rev 233474)
+++ trunk/Source/WebCore/ChangeLog	2018-07-03 20:46:38 UTC (rev 233475)
@@ -1,3 +1,28 @@
+2018-07-03  Chris Dumez  <[email protected]>
+
+        Implement support for Element.toggleAttribute
+        https://bugs.webkit.org/show_bug.cgi?id=186883
+
+        Reviewed by Sam Weinig.
+
+        Implement support for Element.toggleAttribute as per:
+        - https://github.com/whatwg/dom/issues/461
+        - https://dom.spec.whatwg.org/#dom-element-toggleattribute
+
+        This was already implemented in Blink:
+        - https://bugs.chromium.org/p/chromium/issues/detail?id=854960
+
+        Edge expressed public support:
+        - https://github.com/whatwg/dom/issues/461#issuecomment-398206390
+
+        Gecko is working on it:
+        - https://bugzilla.mozilla.org/show_bug.cgi?id=1469592
+
+        * dom/Element.cpp:
+        (WebCore::Element::toggleAttribute):
+        * dom/Element.h:
+        * dom/Element.idl:
+
 2018-07-03  Zalan Bujtas  <[email protected]>
 
         [LFC] Implement minimum/maximum content width logic.

Modified: trunk/Source/WebCore/dom/Element.cpp (233474 => 233475)


--- trunk/Source/WebCore/dom/Element.cpp	2018-07-03 20:44:59 UTC (rev 233474)
+++ trunk/Source/WebCore/dom/Element.cpp	2018-07-03 20:46:38 UTC (rev 233475)
@@ -1272,6 +1272,31 @@
     return getAttribute(QualifiedName(nullAtom(), localName, namespaceURI));
 }
 
+// https://dom.spec.whatwg.org/#dom-element-toggleattribute
+ExceptionOr<bool> Element::toggleAttribute(const AtomicString& localName, std::optional<bool> force)
+{
+    if (!Document::isValidName(localName))
+        return Exception { InvalidCharacterError };
+
+    synchronizeAttribute(localName);
+
+    auto caseAdjustedLocalName = shouldIgnoreAttributeCase(*this) ? localName.convertToASCIILowercase() : localName;
+    unsigned index = elementData() ? elementData()->findAttributeIndexByName(caseAdjustedLocalName, false) : ElementData::attributeNotFound;
+    if (index == ElementData::attributeNotFound) {
+        if (!force || *force) {
+            setAttributeInternal(index, QualifiedName { nullAtom(), caseAdjustedLocalName, nullAtom() }, emptyString(), NotInSynchronizationOfLazyAttribute);
+            return true;
+        }
+        return false;
+    }
+
+    if (!force || !*force) {
+        removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
+        return false;
+    }
+    return true;
+}
+
 ExceptionOr<void> Element::setAttribute(const AtomicString& localName, const AtomicString& value)
 {
     if (!Document::isValidName(localName))

Modified: trunk/Source/WebCore/dom/Element.h (233474 => 233475)


--- trunk/Source/WebCore/dom/Element.h	2018-07-03 20:44:59 UTC (rev 233474)
+++ trunk/Source/WebCore/dom/Element.h	2018-07-03 20:46:38 UTC (rev 233475)
@@ -114,6 +114,8 @@
     static ExceptionOr<QualifiedName> parseAttributeName(const AtomicString& namespaceURI, const AtomicString& qualifiedName);
     WEBCORE_EXPORT ExceptionOr<void> setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value);
 
+    ExceptionOr<bool> toggleAttribute(const AtomicString& name, std::optional<bool> force);
+
     const AtomicString& getIdAttribute() const;
     void setIdAttribute(const AtomicString&);
 

Modified: trunk/Source/WebCore/dom/Element.idl (233474 => 233475)


--- trunk/Source/WebCore/dom/Element.idl	2018-07-03 20:44:59 UTC (rev 233474)
+++ trunk/Source/WebCore/dom/Element.idl	2018-07-03 20:46:38 UTC (rev 233475)
@@ -44,6 +44,7 @@
     [CEReactions, MayThrowException] void setAttributeNS(DOMString? namespaceURI, DOMString qualifiedName, DOMString value);
     [CEReactions] void removeAttribute(DOMString qualifiedName);
     [CEReactions] void removeAttributeNS(DOMString? namespaceURI, DOMString localName);
+    [CEReactions, MayThrowException] boolean toggleAttribute(DOMString qualifiedName, optional boolean force);
     boolean hasAttribute(DOMString qualifiedName);
     boolean hasAttributeNS(DOMString? namespaceURI, DOMString localName);
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to