Web Inspector: Debugger: sidebar should always reveal active call frame when hitting...
authormattbaker@apple.com <mattbaker@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 3 Jun 2019 00:05:10 +0000 (00:05 +0000)
committermattbaker@apple.com <mattbaker@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 3 Jun 2019 00:05:10 +0000 (00:05 +0000)
https://bugs.webkit.org/show_bug.cgi?id=198228
<rdar://problem/46719447>

Reviewed by Devin Rousso.

Reveal the active call frame TreeElement when call frames change. Refreshing
the current target's ThreadTreeElement children is insufficient, since
the sidebar panel content may have been scrolled.

This patch also introduces a workaround to prevent the DetailsSection header
element, which has sticky positioning, from covering a revealed TreeElement.
This can be the case when the TreeElement being revealed is at the topmost edge
of the scrolled content element.

* UserInterface/Base/Utilities.js:

* UserInterface/Views/DebuggerSidebarPanel.js:
(WI.DebuggerSidebarPanel.prototype.createContentTreeOutline):
(WI.DebuggerSidebarPanel.prototype._debuggerCallFramesDidChange):

* UserInterface/Views/DetailsSection.js:
(WI.DetailsSection.prototype.get element):
(WI.DetailsSection.prototype.get headerElement):
(WI.DetailsSection.prototype.get identifier):

* UserInterface/Views/SourcesNavigationSidebarPanel.js:
(WI.SourcesNavigationSidebarPanel.prototype.createContentTreeOutline):
(WI.SourcesNavigationSidebarPanel.prototype._handleDebuggerCallFramesDidChange):

* UserInterface/Views/TreeElement.js:
(WI.TreeElement.prototype.reveal):
* UserInterface/Views/TreeOutline.js:

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

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Base/Utilities.js
Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js
Source/WebInspectorUI/UserInterface/Views/DetailsSection.js
Source/WebInspectorUI/UserInterface/Views/SourcesNavigationSidebarPanel.js
Source/WebInspectorUI/UserInterface/Views/TreeElement.js
Source/WebInspectorUI/UserInterface/Views/TreeOutline.js

index 16f2cbe..358159b 100644 (file)
@@ -1,3 +1,39 @@
+2019-06-02  Matt Baker  <mattbaker@apple.com>
+
+        Web Inspector: Debugger: sidebar should always reveal active call frame when hitting a breakpoint
+        https://bugs.webkit.org/show_bug.cgi?id=198228
+        <rdar://problem/46719447>
+
+        Reviewed by Devin Rousso.
+
+        Reveal the active call frame TreeElement when call frames change. Refreshing
+        the current target's ThreadTreeElement children is insufficient, since
+        the sidebar panel content may have been scrolled.
+
+        This patch also introduces a workaround to prevent the DetailsSection header
+        element, which has sticky positioning, from covering a revealed TreeElement.
+        This can be the case when the TreeElement being revealed is at the topmost edge
+        of the scrolled content element.
+
+        * UserInterface/Base/Utilities.js:
+
+        * UserInterface/Views/DebuggerSidebarPanel.js:
+        (WI.DebuggerSidebarPanel.prototype.createContentTreeOutline):
+        (WI.DebuggerSidebarPanel.prototype._debuggerCallFramesDidChange):
+
+        * UserInterface/Views/DetailsSection.js:
+        (WI.DetailsSection.prototype.get element):
+        (WI.DetailsSection.prototype.get headerElement):
+        (WI.DetailsSection.prototype.get identifier):
+
+        * UserInterface/Views/SourcesNavigationSidebarPanel.js:
+        (WI.SourcesNavigationSidebarPanel.prototype.createContentTreeOutline):
+        (WI.SourcesNavigationSidebarPanel.prototype._handleDebuggerCallFramesDidChange):
+
+        * UserInterface/Views/TreeElement.js:
+        (WI.TreeElement.prototype.reveal):
+        * UserInterface/Views/TreeOutline.js:
+
 2019-06-02  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: propagate whether to show prototype information to subobject views
index ebd71e0..b0b2446 100644 (file)
@@ -388,6 +388,14 @@ Object.defineProperty(Element.prototype, "totalOffsetTop",
     }
 });
 
+Object.defineProperty(Element.prototype, "totalOffsetBottom",
+{
+    get()
+    {
+        return this.getBoundingClientRect().bottom;
+    }
+});
+
 Object.defineProperty(Element.prototype, "removeChildren",
 {
     value()
index 8dc2175..9bb6a68 100644 (file)
@@ -161,8 +161,8 @@ WI.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSideba
         breakpointNavigationBar.addNavigationItem(this._createBreakpointButton);
 
         let breakpointsGroup = new WI.DetailsSectionGroup([breakpointsRow]);
-        let breakpointsSection = new WI.DetailsSection("breakpoints", WI.UIString("Breakpoints"), [breakpointsGroup], breakpointNavigationBarWrapper);
-        this.contentView.element.appendChild(breakpointsSection.element);
+        this._breakpointsSection = new WI.DetailsSection("breakpoints", WI.UIString("Breakpoints"), [breakpointsGroup], breakpointNavigationBarWrapper);
+        this.contentView.element.appendChild(this._breakpointsSection.element);
 
         this._breakpointsContentTreeOutline.addEventListener(WI.TreeOutline.Event.ElementAdded, this._handleBreakpointElementAddedOrRemoved, this);
         this._breakpointsContentTreeOutline.addEventListener(WI.TreeOutline.Event.ElementRemoved, this._handleBreakpointElementAddedOrRemoved, this);
@@ -329,6 +329,29 @@ WI.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSideba
         return this._addScript(representedObject);
     }
 
+    createContentTreeOutline(options = {})
+    {
+        let treeOutline = super.createContentTreeOutline(options)
+
+        treeOutline.addEventListener(WI.TreeOutline.Event.ElementRevealed, (event) => {
+            let treeElement = event.data.element;
+            let detailsSections = [this._pauseReasonSection, this._callStackSection, this._breakpointsSection, this._scriptsSection];
+            let detailsSection = detailsSections.find((detailsSection) => detailsSection.element.contains(treeElement.listItemElement));
+            if (!detailsSection)
+                return;
+
+            // Revealing a TreeElement at the scroll container's topmost edge with
+            // scrollIntoViewIfNeeded may result in the element being covered by the
+            // DetailsSection header, which uses sticky positioning. Detect this case,
+            // and adjust the sidebar content's scroll position to compensate.
+            let offset = detailsSection.headerElement.totalOffsetBottom - treeElement.listItemElement.totalOffsetTop;
+            if (offset > 0)
+                this.scrollElement.scrollBy(0, -offset);
+        });
+
+        return treeOutline;
+    }
+
     // Protected
 
     saveStateToCookie(cookie)
@@ -862,6 +885,10 @@ WI.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSideba
         let target = event.data.target;
         let treeElement = this._findThreadTreeElementForTarget(target);
         treeElement.refresh();
+
+        let activeCallFrameTreeElement = this._callStackTreeOutline.findTreeElement(WI.debuggerManager.activeCallFrame);
+        if (activeCallFrameTreeElement)
+            activeCallFrameTreeElement.reveal();
     }
 
     _debuggerActiveCallFrameDidChange()
index aa3b18f..0a9022a 100644 (file)
@@ -65,15 +65,9 @@ WI.DetailsSection = class DetailsSection extends WI.Object
 
     // Public
 
-    get element()
-    {
-        return this._element;
-    }
-
-    get identifier()
-    {
-        return this._identifier;
-    }
+    get element() { return this._element; }
+    get headerElement() { return this._headerElement; }
+    get identifier() { return this._identifier; }
 
     get title()
     {
index c5a1bfe..8e9dd14 100644 (file)
@@ -474,6 +474,29 @@ WI.SourcesNavigationSidebarPanel = class SourcesNavigationSidebarPanel extends W
 
     // Protected
 
+    createContentTreeOutline(options = {})
+    {
+        let treeOutline = super.createContentTreeOutline(options)
+
+        treeOutline.addEventListener(WI.TreeOutline.Event.ElementRevealed, (event) => {
+            let treeElement = event.data.element;
+            let detailsSections = [this._pauseReasonSection, this._callStackSection, this._breakpointsSection];
+            let detailsSection = detailsSections.find((detailsSection) => detailsSection.element.contains(treeElement.listItemElement));
+            if (!detailsSection)
+                return;
+
+            // Revealing a TreeElement at the scroll container's topmost edge with
+            // scrollIntoViewIfNeeded may result in the element being covered by the
+            // DetailsSection header, which uses sticky positioning. Detect this case,
+            // and adjust the sidebar content's scroll position to compensate.
+            let offset = detailsSection.headerElement.totalOffsetBottom - treeElement.listItemElement.totalOffsetTop;
+            if (offset > 0)
+                this.scrollElement.scrollBy(0, -offset);
+        });
+
+        return treeOutline;
+    }
+
     resetFilter()
     {
         this._resourceTypeScopeBar.resetToDefault();
@@ -1728,6 +1751,10 @@ WI.SourcesNavigationSidebarPanel = class SourcesNavigationSidebarPanel extends W
         console.assert(treeElement);
         if (treeElement)
             treeElement.refresh();
+
+        let activeCallFrameTreeElement = this._callStackTreeOutline.findTreeElement(WI.debuggerManager.activeCallFrame);
+        if (activeCallFrameTreeElement)
+            activeCallFrameTreeElement.reveal();
     }
 
     _handleDebuggerActiveCallFrameDidChange(event)
index 63c27b8..f6ae046 100644 (file)
@@ -488,6 +488,9 @@ WI.TreeElement = class TreeElement extends WI.Object
 
         if (this.onreveal)
             this.onreveal(this);
+
+        if (this.treeOutline)
+            this.treeOutline.dispatchEventToListeners(WI.TreeOutline.Event.ElementRevealed, {element: this});
     }
 
     revealed(ignoreHidden)
index 66ecd52..970982d 100644 (file)
@@ -1159,6 +1159,7 @@ WI.TreeOutline.Event = {
     ElementAdded: Symbol("element-added"),
     ElementDidChange: Symbol("element-did-change"),
     ElementRemoved: Symbol("element-removed"),
+    ElementRevealed: Symbol("element-revealed"),
     ElementClicked: Symbol("element-clicked"),
     ElementDisclosureDidChanged: Symbol("element-disclosure-did-change"),
     ElementVisibilityDidChange: Symbol("element-visbility-did-change"),