Bug 1430034 - Fix attributeChangedCallback isn't fired with correct newValue when the attribute value is an empty string; draft
authorEdgar Chen <echen@mozilla.com>
Mon, 15 Jan 2018 15:24:41 +0800
changeset 720329 0294f39851acc561288eb9022d269567631a3e4b
parent 720328 7f3af76f29693ec80fc24ae529f469ecb90ada03
child 720343 96143bb4f12ef12b5774bde539dae5b175a79ab8
push id95509
push userechen@mozilla.com
push dateMon, 15 Jan 2018 08:26:17 +0000
bugs1430034
milestone59.0a1
Bug 1430034 - Fix attributeChangedCallback isn't fired with correct newValue when the attribute value is an empty string; MozReview-Commit-ID: L3RvNPNDfUC
dom/base/CustomElementRegistry.cpp
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/custom-elements/attribute-changed-callback.html
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -929,17 +929,17 @@ CustomElementRegistry::Upgrade(Element* 
         nsAutoString attrValue, namespaceURI;
         info.mValue->ToString(attrValue);
         nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID,
                                                             namespaceURI);
 
         LifecycleCallbackArgs args = {
           nsDependentAtomString(attrName),
           VoidString(),
-          (attrValue.IsEmpty() ? VoidString() : attrValue),
+          attrValue,
           (namespaceURI.IsEmpty() ? VoidString() : namespaceURI)
         };
         nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eAttributeChanged,
                                                  aElement,
                                                  &args, nullptr, aDefinition);
       }
     }
   }
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -529211,17 +529211,17 @@
    "9f6553b67cad3b479d3beb678653db4e712ed227",
    "support"
   ],
   "custom-elements/adopted-callback.html": [
    "3eaf4dbfe67edd892c9a950c20a87c9b9ed565fa",
    "testharness"
   ],
   "custom-elements/attribute-changed-callback.html": [
-   "1ad26231aa638a0e0f9b76d77bdd93a3712dda98",
+   "320fb2bb26e7495d0829c39c113df3ea7ec1f4ef",
    "testharness"
   ],
   "custom-elements/connected-callbacks.html": [
    "615db12371d6f1f0ed6763abee3a84af9f87c0b2",
    "testharness"
   ],
   "custom-elements/custom-element-reaction-queue.html": [
    "68b226d776736e6044f842c440b42606b63c7175",
--- a/testing/web-platform/tests/custom-elements/attribute-changed-callback.html
+++ b/testing/web-platform/tests/custom-elements/attribute-changed-callback.html
@@ -6,16 +6,17 @@
 <meta name="assert" content="attributeChangedCallback must be enqueued whenever custom element's attribute is added, changed or removed">
 <link rel="help" href="https://w3c.github.io/webcomponents/spec/custom/#dfn-attribute-changed-callback">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="resources/custom-elements-helpers.js"></script>
 </head>
 <body>
 <div id="log"></div>
+<parser-created-element title></parser-created-element>
 <script>
 
 var customElement = define_new_custom_element(['title', 'id', 'r']);
 
 test(function () {
     const instance = document.createElement(customElement.name);
     assert_array_equals(customElement.takeLog().types(), ['constructed']);
 
@@ -213,11 +214,41 @@ test(function () {
     var instance = document.createElement('element-with-no-style-attribute-observation');
     assert_equals(calls.length, 0);
     instance.style.fontSize = '10px';
     assert_equals(calls.length, 0);
     instance.title = 'hello';
     assert_attribute_log_entry(calls[0], {name: 'title', oldValue: null, newValue: 'hello', namespace: null});
 }, 'attributedChangedCallback must not be enqueued when mutating inline style declaration if the style attribute is not observed');
 
+test(function () {
+    var calls = [];
+    class CustomElement extends HTMLElement { }
+    CustomElement.prototype.attributeChangedCallback = function (...args) {
+        calls.push(create_attribute_changed_callback_log(this, ...args));
+    }
+    CustomElement.observedAttributes = ['title'];
+    customElements.define('parser-created-element', CustomElement);
+    assert_attribute_log_entry(calls[0], {name: 'title', oldValue: null, newValue: '', namespace: null});
+}, 'Upgrading a parser created element must enqueue and invoke attributeChangedCallback for an HTML attribute');
+
+test(function () {
+    var calls = [];
+    class CustomElement extends HTMLElement { }
+    CustomElement.prototype.attributeChangedCallback = function (...args) {
+        calls.push(create_attribute_changed_callback_log(this, ...args));
+    }
+    CustomElement.observedAttributes = ['title'];
+    customElements.define('cloned-element-with-attribute', CustomElement);
+
+    var instance = document.createElement('cloned-element-with-attribute');
+    assert_equals(calls.length, 0);
+    instance.title = '';
+    assert_attribute_log_entry(calls[0], {name: 'title', oldValue: null, newValue: '', namespace: null});
+
+    calls = [];
+    var clone = instance.cloneNode(false);
+    assert_attribute_log_entry(calls[0], {name: 'title', oldValue: null, newValue: '', namespace: null});
+}, 'Upgrading a cloned element must enqueue and invoke attributeChangedCallback for an HTML attribute');
+
 </script>
 </body>
 </html>