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 331132 0eb8cf4e5b9283b3be5a5a6b3c5aab1ec927718a
parent 331131 6500ef91810315bd2a4103b0b9ada0207c2b3686
child 331133 f81406821d565c0d9d5d5d9120f0b4b4347a3c5b
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku, Ms2ger
bugs1224186
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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>