Bug 1224186 - Implement DOMTokenlist.replace r=baku r=Ms2ger
☠☠ backed out by a9cfac4ce926 ☠ ☠
authorEmilio Cobos Álvarez <ecoal95@gmail.com>
Wed, 13 Apr 2016 08:49:00 +0200
changeset 317035 0eb8cf4e5b9283b3be5a5a6b3c5aab1ec927718a
parent 317034 6500ef91810315bd2a4103b0b9ada0207c2b3686
child 317036 f81406821d565c0d9d5d5d9120f0b4b4347a3c5b
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku, Ms2ger
bugs1224186
milestone48.0a1
Bug 1224186 - Implement DOMTokenlist.replace r=baku r=Ms2ger
dom/base/nsDOMTokenList.cpp
dom/base/nsDOMTokenList.h
dom/webidl/DOMTokenList.webidl
testing/web-platform/meta/dom/interfaces.html.ini
testing/web-platform/meta/dom/nodes/Element-classlist.html.ini
testing/web-platform/tests/dom/nodes/Element-classlist.html
--- a/dom/base/nsDOMTokenList.cpp
+++ b/dom/base/nsDOMTokenList.cpp
@@ -69,17 +69,17 @@ nsDOMTokenList::IndexedGetter(uint32_t a
     aFound = true;
     attr->AtomAt(aIndex)->ToString(aResult);
   } else {
     aFound = false;
   }
 }
 
 void
-nsDOMTokenList::SetValue(const nsAString& aValue, mozilla::ErrorResult& rv)
+nsDOMTokenList::SetValue(const nsAString& aValue, ErrorResult& rv)
 {
   if (!mElement) {
     return;
   }
 
   rv = mElement->SetAttr(kNameSpaceID_None, mAttrAtom, aValue, true);
 }
 
@@ -177,17 +177,17 @@ nsDOMTokenList::Add(const nsTArray<nsStr
     return;
   }
 
   const nsAttrValue* attr = GetParsedAttr();
   AddInternal(attr, aTokens);
 }
 
 void
-nsDOMTokenList::Add(const nsAString& aToken, mozilla::ErrorResult& aError)
+nsDOMTokenList::Add(const nsAString& aToken, ErrorResult& aError)
 {
   AutoTArray<nsString, 1> tokens;
   tokens.AppendElement(aToken);
   Add(tokens, aError);
 }
 
 void
 nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
@@ -263,17 +263,17 @@ nsDOMTokenList::Remove(const nsTArray<ns
   if (!attr) {
     return;
   }
 
   RemoveInternal(attr, aTokens);
 }
 
 void
-nsDOMTokenList::Remove(const nsAString& aToken, mozilla::ErrorResult& aError)
+nsDOMTokenList::Remove(const nsAString& aToken, ErrorResult& aError)
 {
   AutoTArray<nsString, 1> tokens;
   tokens.AppendElement(aToken);
   Remove(tokens, aError);
 }
 
 bool
 nsDOMTokenList::Toggle(const nsAString& aToken,
@@ -304,16 +304,53 @@ nsDOMTokenList::Toggle(const nsAString& 
       isPresent = true;
     }
   }
 
   return isPresent;
 }
 
 void
+nsDOMTokenList::Replace(const nsAString& aToken,
+                        const nsAString& aNewToken,
+                        ErrorResult& aError)
+{
+  // Doing this here instead of using `CheckToken` because if aToken had invalid
+  // characters, and aNewToken is empty, the returned error should be a
+  // SyntaxError, not an InvalidCharacterError.
+  if (aNewToken.IsEmpty()) {
+    aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
+  }
+
+  aError = CheckToken(aToken);
+  if (aError.Failed()) {
+    return;
+  }
+
+  aError = CheckToken(aNewToken);
+  if (aError.Failed()) {
+    return;
+  }
+
+  const nsAttrValue* attr = GetParsedAttr();
+  if (!attr || !attr->Contains(aToken)) {
+    return;
+  }
+
+  AutoTArray<nsString, 1> tokens;
+
+  tokens.AppendElement(aToken);
+  RemoveInternal(attr, tokens);
+
+  tokens[0] = aNewToken;
+  AddInternal(attr, tokens);
+}
+
+void
 nsDOMTokenList::Stringify(nsAString& aResult)
 {
   if (!mElement) {
     aResult.Truncate();
     return;
   }
 
   mElement->GetAttr(kNameSpaceID_None, mAttrAtom, aResult);
--- a/dom/base/nsDOMTokenList.h
+++ b/dom/base/nsDOMTokenList.h
@@ -58,20 +58,23 @@ public:
   void IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aResult);
   bool Contains(const nsAString& aToken, mozilla::ErrorResult& aError);
   void Add(const nsAString& aToken, mozilla::ErrorResult& aError);
   void Add(const nsTArray<nsString>& aTokens,
            mozilla::ErrorResult& aError);
   void Remove(const nsAString& aToken, mozilla::ErrorResult& aError);
   void Remove(const nsTArray<nsString>& aTokens,
               mozilla::ErrorResult& aError);
+  void Replace(const nsAString& aToken,
+               const nsAString& aNewToken,
+               mozilla::ErrorResult& aError);
   bool Toggle(const nsAString& aToken,
               const mozilla::dom::Optional<bool>& force,
               mozilla::ErrorResult& aError);
-  
+
   void GetValue(nsAString& aResult) { Stringify(aResult); }
   void SetValue(const nsAString& aValue, mozilla::ErrorResult& rv);
   void Stringify(nsAString& aResult);
 
 protected:
   virtual ~nsDOMTokenList();
 
   nsresult CheckToken(const nsAString& aStr);
--- a/dom/webidl/DOMTokenList.webidl
+++ b/dom/webidl/DOMTokenList.webidl
@@ -15,13 +15,15 @@ interface DOMTokenList {
   getter DOMString? item(unsigned long index);
   [Throws]
   boolean contains(DOMString token);
   [Throws]
   void add(DOMString... tokens);
   [Throws]
   void remove(DOMString... tokens);
   [Throws]
+  void replace(DOMString token, DOMString newToken);
+  [Throws]
   boolean toggle(DOMString token, optional boolean force);
   [SetterThrows]
   attribute DOMString value;
   stringifier DOMString ();
 };
--- a/testing/web-platform/meta/dom/interfaces.html.ini
+++ b/testing/web-platform/meta/dom/interfaces.html.ini
@@ -259,28 +259,22 @@
     expected: FAIL
 
   [Document interface: xmlDoc must inherit property "query" with the proper type (35)]
     expected: FAIL
 
   [Document interface: xmlDoc must inherit property "queryAll" with the proper type (36)]
     expected: FAIL
 
-  [DOMTokenList interface: operation replace(DOMString,DOMString)]
-    expected: FAIL
-
   [DOMTokenList interface: operation supports(DOMString)]
     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)]
     expected: FAIL
 
   [DOMTokenList interface: calling supports(DOMString) on document.body.classList with too few arguments must throw TypeError]
     expected: FAIL
 
   [Element interface: element must inherit property "prepend" with the proper type (34)]
     expected: FAIL
--- a/testing/web-platform/meta/dom/nodes/Element-classlist.html.ini
+++ b/testing/web-platform/meta/dom/nodes/Element-classlist.html.ini
@@ -22,37 +22,19 @@
     expected: FAIL
 
   [classList.add should treat \\n as a space]
     expected: FAIL
 
   [classList.add should treat \\f as a space]
     expected: FAIL
 
-  [.replace with empty_string must throw a SYNTAX_ERR]
-    expected: FAIL
-
-  [.replace with string_with_spaces must throw a INVALID_CHARACTER_ERR]
-    expected: FAIL
-
-  [.replace with an already existing token]
-    expected: FAIL
-
-  [classList.replace replaces arguments passed, if they are present.]
-    expected: FAIL
-
   [classList.replace must replace existing tokens]
     expected: FAIL
 
-  [classList.replace must not break case-sensitive CSS selector matching]
-    expected: FAIL
-
-  [classList.replace must replace duplicated tokens]
-    expected: FAIL
-
   [classList.replace must collapse whitespace around replaced tokens]
     expected: FAIL
 
   [classList.replace must collapse whitespaces around each token]
     expected: FAIL
 
   [classList.replace must collapse whitespaces around each token and remove duplicates]
     expected: FAIL
--- a/testing/web-platform/tests/dom/nodes/Element-classlist.html
+++ b/testing/web-platform/tests/dom/nodes/Element-classlist.html
@@ -372,16 +372,30 @@ test(function () {
 test(function () {
   var realList = secondelem.classList;
   secondelem.classList = 'foo bar';
   assert_equals(secondelem.classList,realList);
   assert_equals(secondelem.classList.length,2);
   assert_equals(secondelem.classList[0],'foo');
   assert_equals(secondelem.classList[1],'bar');
 }, 'classList must have [PutForwards=value]');
+test(function () {
+  var foo = document.createElement('div');
+  foo.className = 'a';
+  foo.classList.replace('token1', 'token2');
+
+  assert_equals(foo.className, 'a');
+
+  foo.classList.replace('a', 'b');
+  assert_equals(foo.className, 'b');
+
+  assert_throws('SYNTAX_ERR', function () { foo.classList.replace('t with space', '') });
+  assert_throws('INVALID_CHARACTER_ERR', function () { foo.classList.replace('t with space', 'foo') });
+  assert_throws('SYNTAX_ERR', function () { foo.classList.replace('', 'foo') });
+}, 'classList.replace should work');
     </script>
   </head>
   <body>
 
     <div id="log"></div>
 
   </body>
 </html>