Web Inspector: Critical content browser toolbar buttons are hidden at narrow widths
authormattbaker@apple.com <mattbaker@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Aug 2017 04:04:02 +0000 (04:04 +0000)
committermattbaker@apple.com <mattbaker@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Aug 2017 04:04:02 +0000 (04:04 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175999

Reviewed by Devin Rousso.

This patch adds a VisibilityPriority concept to NavigationItems. If a
NavigationBar cannot fit all of its items in the available space, items
are hidden to make room, starting with the lowest priority item. Consecutive
dividers are then collapsed, as well as leading and trailing dividers.

* UserInterface/Main.html:
New file.

* UserInterface/Views/CanvasContentView.js:
(WI.CanvasContentView):
* UserInterface/Views/ConsoleDrawer.js:
(WI.ConsoleDrawer):
* UserInterface/Views/ContentBrowser.js:
(WI.ContentBrowser):
* UserInterface/Views/ContentBrowserTabContentView.js:
(WI.ContentBrowserTabContentView):
* UserInterface/Views/DOMTreeContentView.js:
(WI.DOMTreeContentView):
Set `High` and `Low` priorities, and group the back/forward buttons.

* UserInterface/Views/GroupNavigationItem.js: Added.
(WI.GroupNavigationItem):
(WI.GroupNavigationItem.prototype.get navigationItems):
(WI.GroupNavigationItem.prototype.get minimumWidth):
(WI.GroupNavigationItem.prototype.updateLayout):
(WI.GroupNavigationItem.prototype.didAttach):
(WI.GroupNavigationItem.prototype.didDetach):
NavigationItem groups. Grouped items are shown/hidden together.

* UserInterface/Views/HierarchicalPathNavigationItem.js:
(WI.HierarchicalPathNavigationItem.prototype.updateLayout):
* UserInterface/Views/ImageResourceContentView.js:
(WI.ImageResourceContentView):
* UserInterface/Views/IndexedDatabaseObjectStoreContentView.js:
(WI.IndexedDatabaseObjectStoreContentView):
* UserInterface/Views/LogContentView.js:
(WI.LogContentView):
Set `High` and `Low` priorities.

* UserInterface/Views/NavigationBar.css:
(.navigation-bar .item.force-hidden):
New hidden class, which must be tracked separately from ".hidden".
The former is an implementation detail of NavigationBar, while the
latter is set by the client.

* UserInterface/Views/NavigationBar.js:
(WI.NavigationBar.prototype.insertNavigationItem):
(WI.NavigationBar.prototype.removeNavigationItem):
(WI.NavigationBar.prototype.findNavigationItem.matchingSelfOrChild):
(WI.NavigationBar.prototype.findNavigationItem):
(WI.NavigationBar.prototype.layout.forceItemHidden):
(WI.NavigationBar.prototype.layout.isDivider):
(WI.NavigationBar.prototype.layout.calculateVisibleItemWidth):
(WI.NavigationBar.prototype.layout):
(WI.NavigationBar.prototype._calculateMinimumWidth):
(WI.NavigationBar.prototype.get _visibleNavigationItems):
(WI.NavigationBar):

* UserInterface/Views/NavigationItem.js:
Add support for visibility priority, an integer value that determines the
order in which items are hidden when the NavigationBar becomes too narrow
to fit all of items child items. NavigationIte3m defines constants for
Low, Normal (the default), and High priority.

(WI.NavigationItem):
(WI.NavigationItem.prototype.get minimumWidth):
(WI.NavigationItem.prototype.get width):
(WI.NavigationItem.prototype.get visibilityPriority):
(WI.NavigationItem.prototype.set visibilityPriority):
(WI.NavigationItem.prototype.updateLayout):
(WI.NavigationItem.prototype.didAttach):
(WI.NavigationItem.prototype.didDetach):
Encapsulate the setting of the parent NavigationBar. Needed so that
GroupNavigationItem can forward this action to its children.

* UserInterface/Views/NetworkGridContentView.js:
(WI.NetworkGridContentView):
* UserInterface/Views/RadioButtonNavigationItem.js:
(WI.RadioButtonNavigationItem.prototype.updateLayout):
* UserInterface/Views/RecordingContentView.js:
(WI.RecordingContentView):
* UserInterface/Views/ScriptContentView.js:
(WI.ScriptContentView):
* UserInterface/Views/TextContentView.js:
(WI.TextContentView):
* UserInterface/Views/TextResourceContentView.js:
(WI.TextResourceContentView):
* UserInterface/Views/TimelineRecordingContentView.js:
(WI.TimelineRecordingContentView):
* UserInterface/Views/TimelineTabContentView.js:
(WI.TimelineTabContentView):
Set `High` and `Low` priorities, and group Timeline view mode buttons.

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

23 files changed:
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Views/CanvasContentView.js
Source/WebInspectorUI/UserInterface/Views/ConsoleDrawer.js
Source/WebInspectorUI/UserInterface/Views/ContentBrowser.js
Source/WebInspectorUI/UserInterface/Views/ContentBrowserTabContentView.js
Source/WebInspectorUI/UserInterface/Views/DOMTreeContentView.js
Source/WebInspectorUI/UserInterface/Views/GroupNavigationItem.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/HierarchicalPathNavigationItem.js
Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js
Source/WebInspectorUI/UserInterface/Views/IndexedDatabaseObjectStoreContentView.js
Source/WebInspectorUI/UserInterface/Views/LogContentView.js
Source/WebInspectorUI/UserInterface/Views/NavigationBar.css
Source/WebInspectorUI/UserInterface/Views/NavigationBar.js
Source/WebInspectorUI/UserInterface/Views/NavigationItem.js
Source/WebInspectorUI/UserInterface/Views/NetworkGridContentView.js
Source/WebInspectorUI/UserInterface/Views/RadioButtonNavigationItem.js
Source/WebInspectorUI/UserInterface/Views/RecordingContentView.js
Source/WebInspectorUI/UserInterface/Views/ScriptContentView.js
Source/WebInspectorUI/UserInterface/Views/TextContentView.js
Source/WebInspectorUI/UserInterface/Views/TextResourceContentView.js
Source/WebInspectorUI/UserInterface/Views/TimelineRecordingContentView.js
Source/WebInspectorUI/UserInterface/Views/TimelineTabContentView.js

index 8119a0a..9a398cd 100644 (file)
@@ -1,3 +1,103 @@
+2017-08-29  Matt Baker  <mattbaker@apple.com>
+
+        Web Inspector: Critical content browser toolbar buttons are hidden at narrow widths
+        https://bugs.webkit.org/show_bug.cgi?id=175999
+
+        Reviewed by Devin Rousso.
+
+        This patch adds a VisibilityPriority concept to NavigationItems. If a
+        NavigationBar cannot fit all of its items in the available space, items
+        are hidden to make room, starting with the lowest priority item. Consecutive
+        dividers are then collapsed, as well as leading and trailing dividers.
+
+        * UserInterface/Main.html:
+        New file.
+
+        * UserInterface/Views/CanvasContentView.js:
+        (WI.CanvasContentView):
+        * UserInterface/Views/ConsoleDrawer.js:
+        (WI.ConsoleDrawer):
+        * UserInterface/Views/ContentBrowser.js:
+        (WI.ContentBrowser):
+        * UserInterface/Views/ContentBrowserTabContentView.js:
+        (WI.ContentBrowserTabContentView):
+        * UserInterface/Views/DOMTreeContentView.js:
+        (WI.DOMTreeContentView):
+        Set `High` and `Low` priorities, and group the back/forward buttons.
+
+        * UserInterface/Views/GroupNavigationItem.js: Added.
+        (WI.GroupNavigationItem):
+        (WI.GroupNavigationItem.prototype.get navigationItems):
+        (WI.GroupNavigationItem.prototype.get minimumWidth):
+        (WI.GroupNavigationItem.prototype.updateLayout):
+        (WI.GroupNavigationItem.prototype.didAttach):
+        (WI.GroupNavigationItem.prototype.didDetach):
+        NavigationItem groups. Grouped items are shown/hidden together.
+
+        * UserInterface/Views/HierarchicalPathNavigationItem.js:
+        (WI.HierarchicalPathNavigationItem.prototype.updateLayout):
+        * UserInterface/Views/ImageResourceContentView.js:
+        (WI.ImageResourceContentView):
+        * UserInterface/Views/IndexedDatabaseObjectStoreContentView.js:
+        (WI.IndexedDatabaseObjectStoreContentView):
+        * UserInterface/Views/LogContentView.js:
+        (WI.LogContentView):
+        Set `High` and `Low` priorities.
+
+        * UserInterface/Views/NavigationBar.css:
+        (.navigation-bar .item.force-hidden):
+        New hidden class, which must be tracked separately from ".hidden".
+        The former is an implementation detail of NavigationBar, while the
+        latter is set by the client.
+
+        * UserInterface/Views/NavigationBar.js:
+        (WI.NavigationBar.prototype.insertNavigationItem):
+        (WI.NavigationBar.prototype.removeNavigationItem):
+        (WI.NavigationBar.prototype.findNavigationItem.matchingSelfOrChild):
+        (WI.NavigationBar.prototype.findNavigationItem):
+        (WI.NavigationBar.prototype.layout.forceItemHidden):
+        (WI.NavigationBar.prototype.layout.isDivider):
+        (WI.NavigationBar.prototype.layout.calculateVisibleItemWidth):
+        (WI.NavigationBar.prototype.layout):
+        (WI.NavigationBar.prototype._calculateMinimumWidth):
+        (WI.NavigationBar.prototype.get _visibleNavigationItems):
+        (WI.NavigationBar):
+
+        * UserInterface/Views/NavigationItem.js:
+        Add support for visibility priority, an integer value that determines the
+        order in which items are hidden when the NavigationBar becomes too narrow
+        to fit all of items child items. NavigationIte3m defines constants for
+        Low, Normal (the default), and High priority.
+
+        (WI.NavigationItem):
+        (WI.NavigationItem.prototype.get minimumWidth):
+        (WI.NavigationItem.prototype.get width):
+        (WI.NavigationItem.prototype.get visibilityPriority):
+        (WI.NavigationItem.prototype.set visibilityPriority):
+        (WI.NavigationItem.prototype.updateLayout):
+        (WI.NavigationItem.prototype.didAttach):
+        (WI.NavigationItem.prototype.didDetach):
+        Encapsulate the setting of the parent NavigationBar. Needed so that
+        GroupNavigationItem can forward this action to its children.
+
+        * UserInterface/Views/NetworkGridContentView.js:
+        (WI.NetworkGridContentView):
+        * UserInterface/Views/RadioButtonNavigationItem.js:
+        (WI.RadioButtonNavigationItem.prototype.updateLayout):
+        * UserInterface/Views/RecordingContentView.js:
+        (WI.RecordingContentView):
+        * UserInterface/Views/ScriptContentView.js:
+        (WI.ScriptContentView):
+        * UserInterface/Views/TextContentView.js:
+        (WI.TextContentView):
+        * UserInterface/Views/TextResourceContentView.js:
+        (WI.TextResourceContentView):
+        * UserInterface/Views/TimelineRecordingContentView.js:
+        (WI.TimelineRecordingContentView):
+        * UserInterface/Views/TimelineTabContentView.js:
+        (WI.TimelineTabContentView):
+        Set `High` and `Low` priorities, and group Timeline view mode buttons.
+
 2017-08-29  Joseph Pecoraro  <pecoraro@apple.com>
 
         REGRESSION(r220235): Web Inspector: Global search should not happen incrementally
index 9537d46..5970e7a 100644 (file)
     <script src="Views/DetailsSidebarPanel.js"></script>
     <script src="Views/GeneralTabBarItem.js"></script>
     <script src="Views/GeneralTreeElement.js"></script>
+    <script src="Views/GroupNavigationItem.js"></script>
     <script src="Views/NavigationSidebarPanel.js"></script>
     <script src="Views/PinnedTabBarItem.js"></script>
     <script src="Views/ResourceContentView.js"></script>
index 83de876..985ec45 100644 (file)
@@ -41,14 +41,17 @@ WI.CanvasContentView = class CanvasContentView extends WI.ContentView
             const toolTip = WI.UIString("Request recording of actions. Shift-click to record a single frame.");
             const altToolTip = WI.UIString("Cancel recording");
             this._recordButtonNavigationItem = new WI.ToggleButtonNavigationItem("canvas-record", toolTip, altToolTip, "Images/Record.svg", "Images/Stop.svg", 13, 13);
+            this._recordButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.High;
             this._recordButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._toggleRecording, this);
         }
 
         this._refreshButtonNavigationItem = new WI.ButtonNavigationItem("canvas-refresh", WI.UIString("Refresh"), "Images/ReloadFull.svg", 13, 13);
+        this._refreshButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
         this._refreshButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._showPreview, this);
 
         this._showGridButtonNavigationItem = new WI.ActivateButtonNavigationItem("show-grid", WI.UIString("Show Grid"), WI.UIString("Hide Grid"), "Images/NavigationItemCheckers.svg", 13, 13);
         this._showGridButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._showGridButtonClicked, this);
+        this._showGridButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
         this._showGridButtonNavigationItem.activated = !!WI.settings.showImageGrid.value;
     }
 
index 00bb781..e9e1c26 100644 (file)
@@ -39,6 +39,7 @@ WI.ConsoleDrawer = class ConsoleDrawer extends WI.ContentBrowser
         this.navigationBar.element.addEventListener("mousedown", this._consoleResizerMouseDown.bind(this));
 
         this._toggleDrawerButton = new WI.ToggleButtonNavigationItem("toggle-drawer", WI.UIString("Hide Console"), WI.UIString("Show Console"), "Images/HideConsoleDrawer.svg", "Images/ShowConsoleDrawer.svg");
+        this._toggleDrawerButton.visibilityPriority = WI.NavigationItem.VisibilityPriority.High;
         this._toggleDrawerButton.addEventListener(WI.ButtonNavigationItem.Event.Clicked, () => { WI.toggleSplitConsole(); });
         this.navigationBar.insertNavigationItem(this._toggleDrawerButton, 0);
 
index fea3f5b..a2ab85b 100644 (file)
@@ -57,12 +57,13 @@ WI.ContentBrowser = class ContentBrowser extends WI.View
             this._backNavigationItem = new WI.ButtonNavigationItem("back", WI.UIString("Back (%s)").format(this._backKeyboardShortcut.displayName), backButtonImage, 8, 13);
             this._backNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, goBack);
             this._backNavigationItem.enabled = false;
-            this._navigationBar.addNavigationItem(this._backNavigationItem);
 
             this._forwardNavigationItem = new WI.ButtonNavigationItem("forward", WI.UIString("Forward (%s)").format(this._forwardKeyboardShortcut.displayName), forwardButtonImage, 8, 13);
             this._forwardNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, goForward);
             this._forwardNavigationItem.enabled = false;
-            this._navigationBar.addNavigationItem(this._forwardNavigationItem);
+
+            let navigationButtonsGroup = new WI.GroupNavigationItem([this._backNavigationItem, this._forwardNavigationItem]);
+            this._navigationBar.addNavigationItem(navigationButtonsGroup);
 
             this._navigationBar.addNavigationItem(new WI.DividerNavigationItem);
         }
index 662999c..d3f24ee 100644 (file)
@@ -56,6 +56,7 @@ WI.ContentBrowserTabContentView = class ContentBrowserTabContentView extends WI.
             this._showNavigationSidebarItem = new WI.ActivateButtonNavigationItem("toggle-navigation-sidebar", showToolTip, hideToolTip, image, 16, 16);
             this._showNavigationSidebarItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, WI.toggleNavigationSidebar, WI);
             this._showNavigationSidebarItem.activated = !WI.navigationSidebar.collapsed;
+            this._showNavigationSidebarItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.High;
 
             this._contentBrowser.navigationBar.insertNavigationItem(this._showNavigationSidebarItem, 0);
             this._contentBrowser.navigationBar.insertNavigationItem(new WI.DividerNavigationItem, 1);
@@ -72,6 +73,7 @@ WI.ContentBrowserTabContentView = class ContentBrowserTabContentView extends WI.
             this._showDetailsSidebarItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, WI.toggleDetailsSidebar, WI);
             this._showDetailsSidebarItem.activated = !WI.detailsSidebar.collapsed;
             this._showDetailsSidebarItem.enabled = false;
+            this._showDetailsSidebarItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.High;
 
             this._contentBrowser.navigationBar.addNavigationItem(new WI.DividerNavigationItem);
             this._contentBrowser.navigationBar.addNavigationItem(this._showDetailsSidebarItem);
index 6b1bc36..c1bf92c 100644 (file)
@@ -34,21 +34,25 @@ WI.DOMTreeContentView = class DOMTreeContentView extends WI.ContentView
         this._compositingBordersButtonNavigationItem = new WI.ActivateButtonNavigationItem("layer-borders", WI.UIString("Show compositing borders"), WI.UIString("Hide compositing borders"), "Images/LayerBorders.svg", 13, 13);
         this._compositingBordersButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._toggleCompositingBorders, this);
         this._compositingBordersButtonNavigationItem.enabled = !!PageAgent.getCompositingBordersVisible;
+        this._compositingBordersButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
 
         WI.showPaintRectsSetting.addEventListener(WI.Setting.Event.Changed, this._showPaintRectsSettingChanged, this);
         this._paintFlashingButtonNavigationItem = new WI.ActivateButtonNavigationItem("paint-flashing", WI.UIString("Enable paint flashing"), WI.UIString("Disable paint flashing"), "Images/Paint.svg", 16, 16);
         this._paintFlashingButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._togglePaintFlashing, this);
         this._paintFlashingButtonNavigationItem.enabled = !!PageAgent.setShowPaintRects;
         this._paintFlashingButtonNavigationItem.activated = PageAgent.setShowPaintRects && WI.showPaintRectsSetting.value;
+        this._paintFlashingButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
 
         WI.showShadowDOMSetting.addEventListener(WI.Setting.Event.Changed, this._showShadowDOMSettingChanged, this);
         this._showsShadowDOMButtonNavigationItem = new WI.ActivateButtonNavigationItem("shows-shadow-DOM", WI.UIString("Show shadow DOM nodes"), WI.UIString("Hide shadow DOM nodes"), "Images/ShadowDOM.svg", 13, 13);
         this._showsShadowDOMButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._toggleShowsShadowDOMSetting, this);
+        this._showsShadowDOMButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
         this._showShadowDOMSettingChanged();
 
         WI.showPrintStylesSetting.addEventListener(WI.Setting.Event.Changed, this._showPrintStylesSettingChanged, this);
         this._showPrintStylesButtonNavigationItem = new WI.ActivateButtonNavigationItem("print-styles", WI.UIString("Force Print Media Styles"), WI.UIString("Use Default Media Styles"), "Images/Printer.svg", 16, 16);
         this._showPrintStylesButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._togglePrintStylesSetting, this);
+        this._showPrintStylesButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
         this._showPrintStylesSettingChanged();
 
         this.element.classList.add("dom-tree");
diff --git a/Source/WebInspectorUI/UserInterface/Views/GroupNavigationItem.js b/Source/WebInspectorUI/UserInterface/Views/GroupNavigationItem.js
new file mode 100644 (file)
index 0000000..a55e5ca
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.GroupNavigationItem = class GroupNavigationItem extends WI.NavigationItem
+{
+    constructor(navigationItems)
+    {
+        console.assert(Array.isArray(navigationItems));
+
+        super();
+
+        this._navigationItems = navigationItems;
+
+        for (let item of this._navigationItems) {
+            console.assert(item instanceof WI.NavigationItem);
+            this.element.appendChild(item.element);
+        }
+    }
+
+    // Public
+
+    get navigationItems() { return this._navigationItems; }
+
+    get minimumWidth()
+    {
+        return this._navigationItems.reduce((total, item) => total + item.minimumWidth, 0);
+    }
+
+    // Protected
+
+    updateLayout(expandOnly)
+    {
+        super.updateLayout(expandOnly);
+
+        for (let item of this._navigationItems)
+            item.updateLayout(expandOnly);
+    }
+
+    didAttach(navigationBar)
+    {
+        super.didAttach(navigationBar);
+
+        for (let item of this._navigationItems)
+            item.didAttach(navigationBar);
+    }
+
+    didDetach()
+    {
+        for (let item of this._navigationItems)
+            item.didDetach();
+
+        super.didDetach();
+    }
+}
index f0f1363..6c2b6b8 100644 (file)
@@ -100,6 +100,8 @@ WI.HierarchicalPathNavigationItem = class HierarchicalPathNavigationItem extends
 
     updateLayout(expandOnly)
     {
+        super.updateLayout(expandOnly);
+
         var navigationBar = this.parentNavigationBar;
         if (!navigationBar)
             return;
index 9ec59f0..3f31a5f 100644 (file)
@@ -34,6 +34,7 @@ WI.ImageResourceContentView = class ImageResourceContentView extends WI.Resource
         const toolTip = WI.UIString("Show Grid");
         const activatedToolTip = WI.UIString("Hide Grid");
         this._showGridButtonNavigationItem = new WI.ActivateButtonNavigationItem("show-grid", toolTip, activatedToolTip, "Images/NavigationItemCheckers.svg", 13, 13);
+        this._showGridButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
         this._showGridButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._showGridButtonClicked, this);
         this._showGridButtonNavigationItem.activated = !!WI.settings.showImageGrid.value;
     }
index 9a6eea0..f7b9342 100644 (file)
@@ -81,6 +81,7 @@ WI.IndexedDatabaseObjectStoreContentView = class IndexedDatabaseObjectStoreConte
         this._refreshButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._refreshButtonClicked, this);
 
         this._clearButtonNavigationItem = new WI.ButtonNavigationItem("indexed-database-object-store-clear", WI.UIString("Clear object store"), "Images/NavigationItemTrash.svg", 15, 15);
+        this._clearButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
         this._clearButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._clearButtonClicked, this);
     }
 
index 4afc197..12b41c2 100644 (file)
@@ -77,12 +77,15 @@ WI.LogContentView = class LogContentView extends WI.ContentView
         this._scopeBar.addEventListener(WI.ScopeBar.Event.SelectionChanged, this._scopeBarSelectionDidChange, this);
 
         this._garbageCollectNavigationItem = new WI.ButtonNavigationItem("clear-log", WI.UIString("Collect garbage"), "Images/NavigationItemGarbageCollect.svg", 16, 16);
+        this._garbageCollectNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
         this._garbageCollectNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._garbageCollect, this);
 
         this._clearLogNavigationItem = new WI.ButtonNavigationItem("clear-log", WI.UIString("Clear log (%s or %s)").format(WI.clearKeyboardShortcut.displayName, this._logViewController.messagesAlternateClearKeyboardShortcut.displayName), "Images/NavigationItemClear.svg", 16, 16);
+        this._clearLogNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
         this._clearLogNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._clearLog, this);
 
         this._showConsoleTabNavigationItem = new WI.ButtonNavigationItem("show-tab", WI.UIString("Show Console tab"), "Images/SplitToggleUp.svg", 16, 16);
+        this._showConsoleTabNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.High;
         this._showConsoleTabNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._showConsoleTab, this);
 
         this.messagesElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false);
index 19ed5de..5e0767a 100644 (file)
@@ -47,3 +47,7 @@
     height: auto;
     outline: none;
 }
+
+.navigation-bar .item.force-hidden {
+    display: none;
+}
index f54f20b..6eac2ea 100644 (file)
@@ -69,7 +69,7 @@ WI.NavigationBar = class NavigationBar extends WI.View
         if (navigationItem.parentNavigationBar)
             navigationItem.parentNavigationBar.removeNavigationItem(navigationItem);
 
-        navigationItem._parentNavigationBar = this;
+        navigationItem.didAttach(this);
 
         console.assert(index >= 0 && index <= this._navigationItems.length);
         index = Math.max(0, Math.min(index, this._navigationItems.length));
@@ -106,7 +106,7 @@ WI.NavigationBar = class NavigationBar extends WI.View
         if (navigationItem._parentNavigationBar !== this)
             return null;
 
-        navigationItem._parentNavigationBar = null;
+        navigationItem.didDetach();
 
         if (this._selectedNavigationItem === navigationItem)
             this.selectedNavigationItem = null;
@@ -174,7 +174,28 @@ WI.NavigationBar = class NavigationBar extends WI.View
 
     findNavigationItem(identifier)
     {
-        return this._navigationItems.find((item) => item.identifier === identifier) || null;
+        function matchingSelfOrChild(item) {
+            if (item.identifier === identifier)
+                return item;
+
+            if (item instanceof WI.GroupNavigationItem) {
+                for (let childItem of item.navigationItems) {
+                    let result = matchingSelfOrChild(childItem);
+                    if (result)
+                        return result;
+                }
+            }
+
+            return null;
+        }
+
+        for (let item of this._navigationItems) {
+            let result = matchingSelfOrChild(item);
+            if (result)
+                return result;
+        }
+
+        return null;
     }
 
     needsLayout()
@@ -194,19 +215,29 @@ WI.NavigationBar = class NavigationBar extends WI.View
         // Remove the collapsed style class to test if the items can fit at full width.
         this.element.classList.remove(WI.NavigationBar.CollapsedStyleClassName);
 
+        function forceItemHidden(item, hidden) {
+            item[WI.NavigationBar.ForceHiddenSymbol] = hidden;
+            item.element.classList.toggle("force-hidden", hidden);
+        }
+
+        function isDivider(item) {
+            return item instanceof WI.DividerNavigationItem;
+        }
+
         // Tell each navigation item to update to full width if needed.
-        for (let navigationItem of this._navigationItems)
-            navigationItem.updateLayout(true);
+        for (let item of this._navigationItems) {
+            forceItemHidden(item, false);
+            item.updateLayout(true);
+        }
 
-        let totalItemWidth = 0;
-        for (let navigationItem of this._navigationItems) {
-            // Skip flexible space items since they can take up no space at the minimum width.
-            if (navigationItem instanceof WI.FlexibleSpaceNavigationItem)
-                continue;
+        let visibleNavigationItems = this._visibleNavigationItems;
 
-            totalItemWidth += navigationItem.element.realOffsetWidth;
+        function calculateVisibleItemWidth() {
+            return visibleNavigationItems.reduce((total, item) => total + item.width, 0);
         }
 
+        let totalItemWidth = calculateVisibleItemWidth();
+
         const barWidth = this.element.realOffsetWidth;
 
         // Add the collapsed class back if the items are wider than the bar.
@@ -214,8 +245,38 @@ WI.NavigationBar = class NavigationBar extends WI.View
             this.element.classList.add(WI.NavigationBar.CollapsedStyleClassName);
 
         // Give each navigation item the opportunity to collapse further.
-        for (let navigationItem of this._navigationItems)
-            navigationItem.updateLayout(false);
+        for (let item of visibleNavigationItems)
+            item.updateLayout(false);
+
+        totalItemWidth = calculateVisibleItemWidth();
+        if (totalItemWidth <= barWidth)
+            return;
+
+        // Hide visible items, starting with the lowest priority item, until the
+        // bar fits the available width.
+        visibleNavigationItems.sort((a, b) => a.visibilityPriority - b.visibilityPriority);
+
+        while (totalItemWidth > barWidth && visibleNavigationItems.length) {
+            let navigationItem = visibleNavigationItems.shift();
+            totalItemWidth -= navigationItem.width;
+            forceItemHidden(navigationItem, true);
+        }
+
+        visibleNavigationItems = this._visibleNavigationItems;
+
+        // Hide leading, trailing, and consecutive dividers.
+        let previousItem = null;
+        for (let item of visibleNavigationItems) {
+            if (isDivider(item) && (!previousItem || isDivider(previousItem))) {
+                forceItemHidden(item);
+                continue;
+            }
+
+            previousItem = item;
+        }
+
+        if (isDivider(previousItem))
+            forceItemHidden(previousItem);
     }
 
     // Private
@@ -369,14 +430,7 @@ WI.NavigationBar = class NavigationBar extends WI.View
         if (!wasCollapsed)
             this.element.classList.add(WI.NavigationBar.CollapsedStyleClassName);
 
-        let totalItemWidth = 0;
-        for (let item of this._navigationItems) {
-            // Skip flexible space items since they can take up no space at the minimum width.
-            if (item instanceof WI.FlexibleSpaceNavigationItem)
-                continue;
-
-            totalItemWidth += item.minimumWidth;
-        }
+        let totalItemWidth = this._visibleNavigationItems.reduce((total, item) => item.minimumWidth, 0);
 
         // Remove the collapsed style class if we were not collapsed before.
         if (!wasCollapsed)
@@ -384,8 +438,22 @@ WI.NavigationBar = class NavigationBar extends WI.View
 
         return totalItemWidth;
     }
+
+    get _visibleNavigationItems()
+    {
+        return this._navigationItems.filter((item) => {
+            if (item instanceof WI.FlexibleSpaceNavigationItem)
+                return false;
+            if (item.hidden || item[WI.NavigationBar.ForceHiddenSymbol])
+                return false;
+            return true;
+        });
+    }
 };
 
+WI.NavigationBar.CachedWidthSymbol = Symbol("cached-width");
+WI.NavigationBar.ForceHiddenSymbol = Symbol("force-hidden");
+
 WI.NavigationBar.CollapsedStyleClassName = "collapsed";
 
 WI.NavigationBar.Event = {
index 3f875ba..e0ca1ac 100644 (file)
@@ -34,6 +34,8 @@ WI.NavigationItem = class NavigationItem extends WI.Object
         this._element = document.createElement("div");
         this._hidden = false;
         this._parentNavigationBar = null;
+        this._visibilityPriority = WI.NavigationItem.VisibilityPriority.Normal;
+        this._cachedWidth = NaN;
 
         if (role)
             this._element.setAttribute("role", role);
@@ -48,12 +50,24 @@ WI.NavigationItem = class NavigationItem extends WI.Object
 
     get identifier() { return this._identifier; }
     get element() { return this._element; }
-    get minimumWidth() { return this._element.realOffsetWidth; }
+    get minimumWidth() { return this.width; }
     get parentNavigationBar() { return this._parentNavigationBar; }
 
+    get width()
+    {
+        if (isNaN(this._cachedWidth))
+            this._cachedWidth = this._element.realOffsetWidth;
+        return this._cachedWidth;
+    }
+
+    get visibilityPriority() { return this._visibilityPriority; }
+    set visibilityPriority(priority) { this._visibilityPriority = priority; }
+
     updateLayout(expandOnly)
     {
         // Implemented by subclasses.
+
+        this._cachedWidth = NaN;
     }
 
     get hidden()
@@ -74,6 +88,20 @@ WI.NavigationItem = class NavigationItem extends WI.Object
             this._parentNavigationBar.needsLayout();
     }
 
+    // Protected
+
+    didAttach(navigationBar)
+    {
+        console.assert(navigationBar instanceof WI.NavigationBar);
+        this._parentNavigationBar = navigationBar;
+    }
+
+    didDetach()
+    {
+        this._cachedWidth = NaN;
+        this._parentNavigationBar = null;
+    }
+
     // Private
 
     get _classNames()
@@ -86,3 +114,9 @@ WI.NavigationItem = class NavigationItem extends WI.Object
         return classNames;
     }
 };
+
+WI.NavigationItem.VisibilityPriority = {
+    Low: -100,
+    Normal: 0,
+    High: 100,
+};
index 2827ec4..47c1eba 100644 (file)
@@ -141,6 +141,7 @@ WI.NetworkGridContentView = class NetworkGridContentView extends WI.ContentView
         }
 
         this._clearNetworkItemsNavigationItem = new WI.ButtonNavigationItem("clear-network-items", WI.UIString("Clear Network Items (%s)").format(WI.clearKeyboardShortcut.displayName), "Images/NavigationItemClear.svg", 16, 16);
+        this._clearNetworkItemsNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
         this._clearNetworkItemsNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, () => this.reset());
 
         this._pendingRecords = [];
index 643ee93..419c719 100644 (file)
@@ -62,6 +62,8 @@ WI.RadioButtonNavigationItem = class RadioButtonNavigationItem extends WI.Button
 
     updateLayout(expandOnly)
     {
+        super.updateLayout(expandOnly);
+
         if (expandOnly)
             return;
 
index 2993fed..919aa53 100644 (file)
@@ -49,6 +49,7 @@ WI.RecordingContentView = class RecordingContentView extends WI.ContentView
             }
 
             this._showGridButtonNavigationItem = new WI.ActivateButtonNavigationItem("show-grid", WI.UIString("Show Grid"), WI.UIString("Hide Grid"), "Images/NavigationItemCheckers.svg", 13, 13);
+            this._showGridButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
             this._showGridButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._showGridButtonClicked, this);
             this._showGridButtonNavigationItem.activated = !!WI.settings.showImageGrid.value;
         }
index 633f648..df6622b 100644 (file)
@@ -57,12 +57,15 @@ WI.ScriptContentView = class ScriptContentView extends WI.ContentView
         this._prettyPrintButtonNavigationItem = new WI.ActivateButtonNavigationItem("pretty-print", toolTip, activatedToolTip, "Images/NavigationItemCurleyBraces.svg", 13, 13);
         this._prettyPrintButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._togglePrettyPrint, this);
         this._prettyPrintButtonNavigationItem.enabled = false; // Enabled when the text editor is populated with content.
+        this._prettyPrintButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
 
         var toolTipTypes = WI.UIString("Show type information");
         var activatedToolTipTypes = WI.UIString("Hide type information");
         this._showTypesButtonNavigationItem = new WI.ActivateButtonNavigationItem("show-types", toolTipTypes, activatedToolTipTypes, "Images/NavigationItemTypes.svg", 13, 14);
         this._showTypesButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._toggleTypeAnnotations, this);
         this._showTypesButtonNavigationItem.enabled = false;
+        this._showTypesButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
+
         WI.showJavaScriptTypeInformationSetting.addEventListener(WI.Setting.Event.Changed, this._showJavaScriptTypeInformationSettingChanged, this);
 
         let toolTipCodeCoverage = WI.UIString("Fade unexecuted code");
@@ -70,6 +73,8 @@ WI.ScriptContentView = class ScriptContentView extends WI.ContentView
         this._codeCoverageButtonNavigationItem = new WI.ActivateButtonNavigationItem("code-coverage", toolTipCodeCoverage, activatedToolTipCodeCoverage, "Images/NavigationItemCodeCoverage.svg", 13, 14);
         this._codeCoverageButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._toggleUnexecutedCodeHighlights, this);
         this._codeCoverageButtonNavigationItem.enabled = false;
+        this._codeCoverageButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
+
         WI.enableControlFlowProfilerSetting.addEventListener(WI.Setting.Event.Changed, this._enableControlFlowProfilerSettingChanged, this);
     }
 
index 9cff075..272bd9f 100644 (file)
@@ -46,16 +46,19 @@ WI.TextContentView = class TextContentView extends WI.ContentView
         this._prettyPrintButtonNavigationItem = new WI.ActivateButtonNavigationItem("pretty-print", toolTip, activatedToolTip, "Images/NavigationItemCurleyBraces.svg", 13, 13);
         this._prettyPrintButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._togglePrettyPrint, this);
         this._prettyPrintButtonNavigationItem.enabled = this._textEditor.canBeFormatted();
+        this._prettyPrintButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
 
         var toolTipTypes = WI.UIString("Show type information");
         var activatedToolTipTypes = WI.UIString("Hide type information");
         this._showTypesButtonNavigationItem = new WI.ActivateButtonNavigationItem("show-types", toolTipTypes, activatedToolTipTypes, "Images/NavigationItemTypes.svg", 13, 14);
         this._showTypesButtonNavigationItem.enabled = false;
+        this._showTypesButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
 
         let toolTipCodeCoverage = WI.UIString("Fade unexecuted code");
         let activatedToolTipCodeCoverage = WI.UIString("Do not fade unexecuted code");
         this._codeCoverageButtonNavigationItem = new WI.ActivateButtonNavigationItem("code-coverage", toolTipCodeCoverage, activatedToolTipCodeCoverage, "Images/NavigationItemCodeCoverage.svg", 13, 14);
         this._codeCoverageButtonNavigationItem.enabled = false;
+        this._codeCoverageButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
     }
 
     // Public
index a6d3768..4de1f27 100644 (file)
@@ -48,12 +48,14 @@ WI.TextResourceContentView = class TextResourceContentView extends WI.ResourceCo
         this._prettyPrintButtonNavigationItem = new WI.ActivateButtonNavigationItem("pretty-print", toolTip, activatedToolTip, "Images/NavigationItemCurleyBraces.svg", 13, 13);
         this._prettyPrintButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._togglePrettyPrint, this);
         this._prettyPrintButtonNavigationItem.enabled = false; // Enabled when the text editor is populated with content.
+        this._prettyPrintButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
 
         var toolTipTypes = WI.UIString("Show type information");
         var activatedToolTipTypes = WI.UIString("Hide type information");
         this._showTypesButtonNavigationItem = new WI.ActivateButtonNavigationItem("show-types", toolTipTypes, activatedToolTipTypes, "Images/NavigationItemTypes.svg", 13, 14);
         this._showTypesButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._toggleTypeAnnotations, this);
         this._showTypesButtonNavigationItem.enabled = false;
+        this._showTypesButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
         WI.showJavaScriptTypeInformationSetting.addEventListener(WI.Setting.Event.Changed, this._showJavaScriptTypeInformationSettingChanged, this);
 
         let toolTipCodeCoverage = WI.UIString("Fade unexecuted code");
@@ -61,6 +63,7 @@ WI.TextResourceContentView = class TextResourceContentView extends WI.ResourceCo
         this._codeCoverageButtonNavigationItem = new WI.ActivateButtonNavigationItem("code-coverage", toolTipCodeCoverage, activatedToolTipCodeCoverage, "Images/NavigationItemCodeCoverage.svg", 13, 14);
         this._codeCoverageButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._toggleUnexecutedCodeHighlights, this);
         this._codeCoverageButtonNavigationItem.enabled = false;
+        this._codeCoverageButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
         WI.enableControlFlowProfilerSetting.addEventListener(WI.Setting.Event.Changed, this._enableControlFlowProfilerSettingChanged, this);
     }
 
index 8bd1868..bbdedc2 100644 (file)
@@ -57,6 +57,7 @@ WI.TimelineRecordingContentView = class TimelineRecordingContentView extends WI.
         this.addSubview(this._timelineContentBrowser);
 
         this._clearTimelineNavigationItem = new WI.ButtonNavigationItem("clear-timeline", WI.UIString("Clear Timeline (%s)").format(WI.clearKeyboardShortcut.displayName), "Images/NavigationItemClear.svg", 16, 16);
+        this._clearTimelineNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
         this._clearTimelineNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._clearTimeline, this);
 
         this._overviewTimelineView = new WI.OverviewTimelineView(recording);
index 2bbc120..b7fe99b 100644 (file)
@@ -50,6 +50,7 @@ WI.TimelineTabContentView = class TimelineTabContentView extends WI.ContentBrows
         let toolTip = WI.UIString("Start recording (%s)\nCreate new recording (%s)").format(this._toggleRecordingShortcut.displayName, this._toggleNewRecordingShortcut.displayName);
         let altToolTip = WI.UIString("Stop recording (%s)").format(this._toggleRecordingShortcut.displayName);
         this._recordButton = new WI.ToggleButtonNavigationItem("record-start-stop", toolTip, altToolTip, "Images/Record.svg", "Images/Stop.svg", 13, 13);
+        this._recordButton.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
         this._recordButton.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._recordButtonClicked, this);
 
         this.contentBrowser.navigationBar.insertNavigationItem(this._recordButton, 0);
@@ -58,9 +59,10 @@ WI.TimelineTabContentView = class TimelineTabContentView extends WI.ContentBrows
             let timelinesNavigationItem = new WI.RadioButtonNavigationItem(WI.TimelineOverview.ViewMode.Timelines, WI.UIString("Events"));
             let renderingFramesNavigationItem = new WI.RadioButtonNavigationItem(WI.TimelineOverview.ViewMode.RenderingFrames, WI.UIString("Frames"));
 
-            this.contentBrowser.navigationBar.insertNavigationItem(timelinesNavigationItem, 1);
-            this.contentBrowser.navigationBar.insertNavigationItem(renderingFramesNavigationItem, 2);
+            let viewModeGroup = new WI.GroupNavigationItem([timelinesNavigationItem, renderingFramesNavigationItem]);
+            viewModeGroup.visibilityPriority = WI.NavigationItem.VisibilityPriority.High;
 
+            this.contentBrowser.navigationBar.insertNavigationItem(viewModeGroup, 1);
             this.contentBrowser.navigationBar.addEventListener(WI.NavigationBar.Event.NavigationItemSelected, this._viewModeSelected, this);
         }