Web Inspector: Unexpectedly frequent flashing of DOM node attributes
authordrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 3 Mar 2019 00:18:55 +0000 (00:18 +0000)
committerdrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 3 Mar 2019 00:18:55 +0000 (00:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=148049
<rdar://problem/22296830>

Reviewed by Joseph Pecoraro.

Save a timestamp of when the CSS animation began, so that if the attribute's node is replaced,
we can "resume" the CSS animation at the same point with the attribute's new node.

* UserInterface/Views/DOMTreeElement.js:
(WI.DOMTreeElement):
(WI.DOMTreeElement.prototype.attributeDidChange):
(WI.DOMTreeElement.prototype._buildAttributeDOM):
(WI.DOMTreeElement.prototype._createModifiedAnimation):
(WI.DOMTreeElement.prototype._markNodeChanged): Deleted.
(WI.DOMTreeElement.prototype._nodeChangedAnimationEnd): Deleted.
(WI.DOMTreeElement.prototype._fireDidChange): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@242322 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js

index 94c5feb..c16522c 100644 (file)
@@ -1,5 +1,25 @@
 2019-03-02  Devin Rousso  <drousso@apple.com>
 
+        Web Inspector: Unexpectedly frequent flashing of DOM node attributes
+        https://bugs.webkit.org/show_bug.cgi?id=148049
+        <rdar://problem/22296830>
+
+        Reviewed by Joseph Pecoraro.
+
+        Save a timestamp of when the CSS animation began, so that if the attribute's node is replaced,
+        we can "resume" the CSS animation at the same point with the attribute's new node.
+
+        * UserInterface/Views/DOMTreeElement.js:
+        (WI.DOMTreeElement):
+        (WI.DOMTreeElement.prototype.attributeDidChange):
+        (WI.DOMTreeElement.prototype._buildAttributeDOM):
+        (WI.DOMTreeElement.prototype._createModifiedAnimation):
+        (WI.DOMTreeElement.prototype._markNodeChanged): Deleted.
+        (WI.DOMTreeElement.prototype._nodeChangedAnimationEnd): Deleted.
+        (WI.DOMTreeElement.prototype._fireDidChange): Deleted.
+
+2019-03-02  Devin Rousso  <drousso@apple.com>
+
         Web Inspector: Debugger: DOM, URL, and Event breakpoints don't grey out when all breakpoints are disabled
         https://bugs.webkit.org/show_bug.cgi?id=195170
         <rdar://problem/48478193>
index 0a1f825..3947dc9 100644 (file)
@@ -48,8 +48,7 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
         this._subtreeBreakpointCount = 0;
 
         this._highlightedAttributes = new Set;
-        this._recentlyModifiedAttributes = [];
-        this._boundNodeChangedAnimationEnd = this._nodeChangedAnimationEnd.bind(this);
+        this._recentlyModifiedAttributes = new Map;
 
         node.addEventListener(WI.DOMNode.Event.EnabledPseudoClassesChanged, this._nodePseudoClassesDidChange, this);
 
@@ -266,7 +265,15 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
 
     attributeDidChange(name)
     {
-        this._recentlyModifiedAttributes.push({name});
+        if (this._recentlyModifiedAttributes.has(name))
+            return;
+
+        this._recentlyModifiedAttributes.set(name, {
+            value: null,
+            timestamp: NaN,
+            element: null,
+            listener: null,
+        });
     }
 
     highlightAttribute(name)
@@ -1312,10 +1319,7 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
         if (hasText)
             attrSpanElement.append("\"");
 
-        for (let attribute of this._recentlyModifiedAttributes) {
-            if (attribute.name === name)
-                attribute.element = hasText ? attrValueElement : attrNameElement;
-        }
+        this._createModifiedAnimation(name, value, hasText ? attrValueElement : attrNameElement);
 
         if (this._highlightedAttributes.has(name))
             attrSpanElement.classList.add("highlight");
@@ -1724,29 +1728,40 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
         WI.highlightRangesWithStyleClass(this.title, matchRanges, WI.DOMTreeElement.SearchHighlightStyleClassName, this._highlightResult);
     }
 
-    _markNodeChanged()
+    _createModifiedAnimation(key, value, element)
     {
-        for (let attribute of this._recentlyModifiedAttributes) {
-            let element = attribute.element;
-            if (!element)
-                continue;
+        let existing = this._recentlyModifiedAttributes.get(key);
+        if (!existing)
+            return;
 
-            element.classList.remove("node-state-changed");
-            element.addEventListener("animationend", this._boundNodeChangedAnimationEnd);
-            element.classList.add("node-state-changed");
+        if (existing.element) {
+            if (existing.listener)
+                existing.element.removeEventListener("animationend", existing.listener);
+
+            existing.element.classList.remove("node-state-changed");
+            existing.element.style.removeProperty("animation-delay");
         }
-    }
 
-    _nodeChangedAnimationEnd(event)
-    {
-        let element = event.target;
+        existing.listener = (event) => {
+            element.classList.remove("node-state-changed");
+            element.style.removeProperty("animation-delay");
+
+            this._recentlyModifiedAttributes.delete(key);
+        };
+
         element.classList.remove("node-state-changed");
-        element.removeEventListener("animationend", this._boundNodeChangedAnimationEnd);
+        element.style.removeProperty("animation-delay");
 
-        for (let i = this._recentlyModifiedAttributes.length - 1; i >= 0; --i) {
-            if (this._recentlyModifiedAttributes[i].element === element)
-                this._recentlyModifiedAttributes.splice(i, 1);
-        }
+        if (existing.value === value)
+            element.style.setProperty("animation-delay", "-" + (performance.now() - existing.timestamp) + "ms");
+        else
+            existing.timestamp = performance.now();
+
+        existing.value = value;
+        existing.element = element;
+
+        element.addEventListener("animationend", existing.listener, {once: true});
+        element.classList.add("node-state-changed");
     }
 
     get pseudoClassesEnabled()
@@ -1769,13 +1784,6 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
         this.listItemElement.classList.toggle("pseudo-class-enabled", !!this.representedObject.enabledPseudoClasses.length);
     }
 
-    _fireDidChange()
-    {
-        super._fireDidChange();
-
-        this._markNodeChanged();
-    }
-
     handleEvent(event)
     {
         if (event.type === "dragstart" && this._editing)