Web Inspector: Create View base class, refactor some core view classes
authormattbaker@apple.com <mattbaker@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Nov 2015 21:56:35 +0000 (21:56 +0000)
committermattbaker@apple.com <mattbaker@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Nov 2015 21:56:35 +0000 (21:56 +0000)
https://bugs.webkit.org/show_bug.cgi?id=149186

Reviewed by Brian Burg and Timothy Hatcher.

This patch introduces a new View base class, which encapsulates DOM element creation,
layout scheduling, and subview management. The View class constructor accepts an optional
element parameter, allowing an existing DOM element to be associated with the View object,
rather than dynamically creating a new element. View also adds a `__view` property to its
associated DOM element to facilitate debugging the Inspector UI.

For the view classes refactored in this patch, the changes are largely mechanical. Dynamically
created DOM elements and redundant element getters have been removed. needsLayout has replaced
updateLayoutIfNeeded where appropriate. updateLayout has been removed entirely for views that
performed no layout other than to cascade layouts to their children.

* UserInterface/Base/Main.js:
Moved TabBar layout updates out of TabBrowser and into Main.js.

* UserInterface/Main.html:
* UserInterface/Views/ConsolePrompt.js:
(WebInspector.ConsolePrompt):
(WebInspector.ConsolePrompt.prototype.layout):
(WebInspector.ConsolePrompt.prototype.get element): Deleted.
(WebInspector.ConsolePrompt.prototype.updateLayout): Deleted.
* UserInterface/Views/ContentBrowser.js:
(WebInspector.ContentBrowser):
(WebInspector.ContentBrowser.prototype.get element): Deleted.
(WebInspector.ContentBrowser.prototype.updateLayout): Deleted.
* UserInterface/Views/ContentBrowserTabContentView.js:
(WebInspector.ContentBrowserTabContentView):
(WebInspector.ContentBrowserTabContentView.prototype.updateLayout): Deleted.
* UserInterface/Views/ContentView.js:
(WebInspector.ContentView):
(WebInspector.ContentView.prototype.get element): Deleted.
(WebInspector.ContentView.prototype.updateLayout): Deleted.
* UserInterface/Views/ContentViewContainer.js:
(WebInspector.ContentViewContainer):
(WebInspector.ContentViewContainer.prototype._showEntry):
(WebInspector.ContentViewContainer.prototype._hideEntry):
(WebInspector.ContentViewContainer.prototype.get element): Deleted.
(WebInspector.ContentViewContainer.prototype.updateLayout): Deleted.
(WebInspector.ContentViewContainer.prototype._addContentViewElement): Deleted.
(WebInspector.ContentViewContainer.prototype._removeContentViewElement): Deleted.
* UserInterface/Views/DataGrid.js:
(WebInspector.DataGrid.prototype.autoSizeColumns):
(WebInspector.DataGrid.prototype.layout):
(WebInspector.DataGrid.prototype.applyColumnWidthsMap):
(WebInspector.DataGrid): Deleted.
(WebInspector.DataGrid.prototype.updateLayout): Deleted.
(WebInspector.DataGrid.prototype.resizerDragging): Deleted.
(WebInspector.DataGrid.prototype.resizerDragEnded): Deleted.
* UserInterface/Views/HierarchicalPathNavigationItem.js:
(WebInspector.HierarchicalPathNavigationItem.prototype.set components):
* UserInterface/Views/LayoutTimelineView.js:
(WebInspector.LayoutTimelineView):
(WebInspector.LayoutTimelineView.prototype.layout):
(WebInspector.LayoutTimelineView.prototype.updateLayout): Deleted.
* UserInterface/Views/NavigationBar.js:
(WebInspector.NavigationBar):
(WebInspector.NavigationBar.prototype.insertNavigationItem):
(WebInspector.NavigationBar.prototype.removeNavigationItem):
(WebInspector.NavigationBar.prototype.get minimumWidth):
(WebInspector.NavigationBar.prototype.layout):
(WebInspector.NavigationBar.prototype._mouseDown):
(WebInspector.NavigationBar.prototype._mouseMoved):
(WebInspector.NavigationBar.prototype._mouseUp):
(WebInspector.NavigationBar.prototype._calculateMinimumWidth):
(WebInspector.NavigationBar.prototype.updateLayoutSoon.update): Deleted.
(WebInspector.NavigationBar.prototype.updateLayoutSoon): Deleted.
(WebInspector.NavigationBar.prototype.updateLayout): Deleted.
(WebInspector.NavigationBar.prototype.get element): Deleted.
* UserInterface/Views/NavigationItem.js:
(WebInspector.NavigationItem.prototype.set hidden):
* UserInterface/Views/NetworkTimelineView.js:
(WebInspector.NetworkTimelineView):
(WebInspector.NetworkTimelineView.prototype.layout):
(WebInspector.NetworkTimelineView.prototype.updateLayout): Deleted.
* UserInterface/Views/OverviewTimelineView.js:
(WebInspector.OverviewTimelineView):
(WebInspector.OverviewTimelineView.prototype.layout):
(WebInspector.OverviewTimelineView.prototype.updateLayout): Deleted.
* UserInterface/Views/QuickConsole.js:
(WebInspector.QuickConsole):
(WebInspector.QuickConsole.prototype.layout):
(WebInspector.QuickConsole.prototype.get element): Deleted.
(WebInspector.QuickConsole.prototype.updateLayout): Deleted.
* UserInterface/Views/RenderingFrameTimelineView.js:
(WebInspector.RenderingFrameTimelineView):
(WebInspector.RenderingFrameTimelineView.prototype.layout):
(WebInspector.RenderingFrameTimelineView.prototype.updateLayout): Deleted.
* UserInterface/Views/ScriptTimelineView.js:
(WebInspector.ScriptTimelineView):
(WebInspector.ScriptTimelineView.prototype.layout):
(WebInspector.ScriptTimelineView.prototype.updateLayout): Deleted.
* UserInterface/Views/TabBar.js:
(WebInspector.TabBar):
(WebInspector.TabBar.prototype.insertTabBarItem.animateTabs):
(WebInspector.TabBar.prototype.insertTabBarItem.removeStyles):
(WebInspector.TabBar.prototype.insertTabBarItem):
(WebInspector.TabBar.prototype.removeTabBarItem.animateTabs):
(WebInspector.TabBar.prototype.removeTabBarItem.removeStyles):
(WebInspector.TabBar.prototype.removeTabBarItem):
(WebInspector.TabBar.prototype.hasNormalTab):
(WebInspector.TabBar.prototype.layout):
(WebInspector.TabBar.prototype._recordTabBarItemSizesAndPositions):
(WebInspector.TabBar.prototype._finishExpandingTabsAfterClose.):
(WebInspector.TabBar.prototype._finishExpandingTabsAfterClose):
(WebInspector.TabBar.prototype._handleClick):
(WebInspector.TabBar.prototype._handleMouseMoved):
(WebInspector.TabBar.prototype._handleMouseUp):
(WebInspector.TabBar.prototype._handleMouseLeave):
(WebInspector.TabBar.prototype._handleNewTabMouseEnter):
(WebInspector.TabBar.prototype.updateLayoutSoon.update): Deleted.
(WebInspector.TabBar.prototype.updateLayoutSoon): Deleted.
(WebInspector.TabBar.prototype.updateLayout): Deleted.
(WebInspector.TabBar.prototype.get element): Deleted.
* UserInterface/Views/TabBrowser.js:
(WebInspector.TabBrowser):
(WebInspector.TabBrowser.prototype.get element): Deleted.
(WebInspector.TabBrowser.prototype.updateLayout): Deleted.
* UserInterface/Views/TimelineView.js:
(WebInspector.TimelineView.prototype.filterUpdated):
(WebInspector.TimelineView.prototype.needsLayout):
(WebInspector.TimelineView.prototype.updateLayout): Deleted.
(WebInspector.TimelineView.prototype.updateLayoutIfNeeded): Deleted.
(WebInspector.TimelineView): Deleted.

* UserInterface/Views/Toolbar.js:
(WebInspector.Toolbar):
(WebInspector.Toolbar.prototype.set displayMode):
(WebInspector.Toolbar.prototype.set sizeMode):
(WebInspector.Toolbar.prototype.addToolbarItem):
(WebInspector.Toolbar.prototype.layout):
(WebInspector.Toolbar.prototype.customUpdateLayout): Deleted.
Renamed to layout. This eliminated a layering violation in NavigationBar,
where the function previously known as updateLayout checked for a
a `customUpdateLayout` function property, and would call it instead of its
own layout logic if found.

* UserInterface/Views/View.js: Added.
(WebInspector.View):
(WebInspector.View.prototype.get element):
(WebInspector.View.prototype.get subviews):
(WebInspector.View.prototype.addSubview):
Appends a view to the end of the subview list.
(WebInspector.View.prototype.insertSubviewBefore):
Inserts a view into subview list before another subview.
(WebInspector.View.prototype.removeSubview):
(WebInspector.View.prototype.replaceSubview):
(WebInspector.View.prototype.updateLayout):
No longer overridden by subclasses.
(WebInspector.View.prototype.updateLayoutIfNeeded):
Forces a layout if one has been scheduled, otherwise does nothing.
(WebInspector.View.prototype.needsLayout):
Schedules a layout for the view.
(WebInspector.View.prototype.layout):
Overridden by views that require special layout logic. Layouts
cascade to child views automatically.
(WebInspector.View.prototype._layoutSubtree):
Main layout entry point. Called by requestAnimationFrame via needsLayut, by
updateLayout when forcing a synchronous layout, and called recursively during
subview traversal.

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

23 files changed:
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Base/Main.js
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Views/ConsolePrompt.js
Source/WebInspectorUI/UserInterface/Views/ContentBrowser.js
Source/WebInspectorUI/UserInterface/Views/ContentBrowserTabContentView.js
Source/WebInspectorUI/UserInterface/Views/ContentView.js
Source/WebInspectorUI/UserInterface/Views/ContentViewContainer.js
Source/WebInspectorUI/UserInterface/Views/DataGrid.js
Source/WebInspectorUI/UserInterface/Views/HierarchicalPathNavigationItem.js
Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js
Source/WebInspectorUI/UserInterface/Views/NavigationBar.js
Source/WebInspectorUI/UserInterface/Views/NavigationItem.js
Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js
Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js
Source/WebInspectorUI/UserInterface/Views/QuickConsole.js
Source/WebInspectorUI/UserInterface/Views/RenderingFrameTimelineView.js
Source/WebInspectorUI/UserInterface/Views/ScriptTimelineView.js
Source/WebInspectorUI/UserInterface/Views/TabBar.js
Source/WebInspectorUI/UserInterface/Views/TabBrowser.js
Source/WebInspectorUI/UserInterface/Views/TimelineView.js
Source/WebInspectorUI/UserInterface/Views/Toolbar.js
Source/WebInspectorUI/UserInterface/Views/View.js [new file with mode: 0644]

index 60d61a7..6a8cf94 100644 (file)
@@ -1,3 +1,169 @@
+2015-11-03  Matt Baker  <mattbaker@apple.com>
+
+        Web Inspector: Create View base class, refactor some core view classes
+        https://bugs.webkit.org/show_bug.cgi?id=149186
+
+        Reviewed by Brian Burg and Timothy Hatcher.
+
+        This patch introduces a new View base class, which encapsulates DOM element creation,
+        layout scheduling, and subview management. The View class constructor accepts an optional
+        element parameter, allowing an existing DOM element to be associated with the View object,
+        rather than dynamically creating a new element. View also adds a `__view` property to its
+        associated DOM element to facilitate debugging the Inspector UI.
+
+        For the view classes refactored in this patch, the changes are largely mechanical. Dynamically
+        created DOM elements and redundant element getters have been removed. needsLayout has replaced
+        updateLayoutIfNeeded where appropriate. updateLayout has been removed entirely for views that
+        performed no layout other than to cascade layouts to their children.
+
+        * UserInterface/Base/Main.js:
+        Moved TabBar layout updates out of TabBrowser and into Main.js.
+
+        * UserInterface/Main.html:
+        * UserInterface/Views/ConsolePrompt.js:
+        (WebInspector.ConsolePrompt):
+        (WebInspector.ConsolePrompt.prototype.layout):
+        (WebInspector.ConsolePrompt.prototype.get element): Deleted.
+        (WebInspector.ConsolePrompt.prototype.updateLayout): Deleted.
+        * UserInterface/Views/ContentBrowser.js:
+        (WebInspector.ContentBrowser):
+        (WebInspector.ContentBrowser.prototype.get element): Deleted.
+        (WebInspector.ContentBrowser.prototype.updateLayout): Deleted.
+        * UserInterface/Views/ContentBrowserTabContentView.js:
+        (WebInspector.ContentBrowserTabContentView):
+        (WebInspector.ContentBrowserTabContentView.prototype.updateLayout): Deleted.
+        * UserInterface/Views/ContentView.js:
+        (WebInspector.ContentView):
+        (WebInspector.ContentView.prototype.get element): Deleted.
+        (WebInspector.ContentView.prototype.updateLayout): Deleted.
+        * UserInterface/Views/ContentViewContainer.js:
+        (WebInspector.ContentViewContainer):
+        (WebInspector.ContentViewContainer.prototype._showEntry):
+        (WebInspector.ContentViewContainer.prototype._hideEntry):
+        (WebInspector.ContentViewContainer.prototype.get element): Deleted.
+        (WebInspector.ContentViewContainer.prototype.updateLayout): Deleted.
+        (WebInspector.ContentViewContainer.prototype._addContentViewElement): Deleted.
+        (WebInspector.ContentViewContainer.prototype._removeContentViewElement): Deleted.
+        * UserInterface/Views/DataGrid.js:
+        (WebInspector.DataGrid.prototype.autoSizeColumns):
+        (WebInspector.DataGrid.prototype.layout):
+        (WebInspector.DataGrid.prototype.applyColumnWidthsMap):
+        (WebInspector.DataGrid): Deleted.
+        (WebInspector.DataGrid.prototype.updateLayout): Deleted.
+        (WebInspector.DataGrid.prototype.resizerDragging): Deleted.
+        (WebInspector.DataGrid.prototype.resizerDragEnded): Deleted.
+        * UserInterface/Views/HierarchicalPathNavigationItem.js:
+        (WebInspector.HierarchicalPathNavigationItem.prototype.set components):
+        * UserInterface/Views/LayoutTimelineView.js:
+        (WebInspector.LayoutTimelineView):
+        (WebInspector.LayoutTimelineView.prototype.layout):
+        (WebInspector.LayoutTimelineView.prototype.updateLayout): Deleted.
+        * UserInterface/Views/NavigationBar.js:
+        (WebInspector.NavigationBar):
+        (WebInspector.NavigationBar.prototype.insertNavigationItem):
+        (WebInspector.NavigationBar.prototype.removeNavigationItem):
+        (WebInspector.NavigationBar.prototype.get minimumWidth):
+        (WebInspector.NavigationBar.prototype.layout):
+        (WebInspector.NavigationBar.prototype._mouseDown):
+        (WebInspector.NavigationBar.prototype._mouseMoved):
+        (WebInspector.NavigationBar.prototype._mouseUp):
+        (WebInspector.NavigationBar.prototype._calculateMinimumWidth):
+        (WebInspector.NavigationBar.prototype.updateLayoutSoon.update): Deleted.
+        (WebInspector.NavigationBar.prototype.updateLayoutSoon): Deleted.
+        (WebInspector.NavigationBar.prototype.updateLayout): Deleted.
+        (WebInspector.NavigationBar.prototype.get element): Deleted.
+        * UserInterface/Views/NavigationItem.js:
+        (WebInspector.NavigationItem.prototype.set hidden):
+        * UserInterface/Views/NetworkTimelineView.js:
+        (WebInspector.NetworkTimelineView):
+        (WebInspector.NetworkTimelineView.prototype.layout):
+        (WebInspector.NetworkTimelineView.prototype.updateLayout): Deleted.
+        * UserInterface/Views/OverviewTimelineView.js:
+        (WebInspector.OverviewTimelineView):
+        (WebInspector.OverviewTimelineView.prototype.layout):
+        (WebInspector.OverviewTimelineView.prototype.updateLayout): Deleted.
+        * UserInterface/Views/QuickConsole.js:
+        (WebInspector.QuickConsole):
+        (WebInspector.QuickConsole.prototype.layout):
+        (WebInspector.QuickConsole.prototype.get element): Deleted.
+        (WebInspector.QuickConsole.prototype.updateLayout): Deleted.
+        * UserInterface/Views/RenderingFrameTimelineView.js:
+        (WebInspector.RenderingFrameTimelineView):
+        (WebInspector.RenderingFrameTimelineView.prototype.layout):
+        (WebInspector.RenderingFrameTimelineView.prototype.updateLayout): Deleted.
+        * UserInterface/Views/ScriptTimelineView.js:
+        (WebInspector.ScriptTimelineView):
+        (WebInspector.ScriptTimelineView.prototype.layout):
+        (WebInspector.ScriptTimelineView.prototype.updateLayout): Deleted.
+        * UserInterface/Views/TabBar.js:
+        (WebInspector.TabBar):
+        (WebInspector.TabBar.prototype.insertTabBarItem.animateTabs):
+        (WebInspector.TabBar.prototype.insertTabBarItem.removeStyles):
+        (WebInspector.TabBar.prototype.insertTabBarItem):
+        (WebInspector.TabBar.prototype.removeTabBarItem.animateTabs):
+        (WebInspector.TabBar.prototype.removeTabBarItem.removeStyles):
+        (WebInspector.TabBar.prototype.removeTabBarItem):
+        (WebInspector.TabBar.prototype.hasNormalTab):
+        (WebInspector.TabBar.prototype.layout):
+        (WebInspector.TabBar.prototype._recordTabBarItemSizesAndPositions):
+        (WebInspector.TabBar.prototype._finishExpandingTabsAfterClose.):
+        (WebInspector.TabBar.prototype._finishExpandingTabsAfterClose):
+        (WebInspector.TabBar.prototype._handleClick):
+        (WebInspector.TabBar.prototype._handleMouseMoved):
+        (WebInspector.TabBar.prototype._handleMouseUp):
+        (WebInspector.TabBar.prototype._handleMouseLeave):
+        (WebInspector.TabBar.prototype._handleNewTabMouseEnter):
+        (WebInspector.TabBar.prototype.updateLayoutSoon.update): Deleted.
+        (WebInspector.TabBar.prototype.updateLayoutSoon): Deleted.
+        (WebInspector.TabBar.prototype.updateLayout): Deleted.
+        (WebInspector.TabBar.prototype.get element): Deleted.
+        * UserInterface/Views/TabBrowser.js:
+        (WebInspector.TabBrowser):
+        (WebInspector.TabBrowser.prototype.get element): Deleted.
+        (WebInspector.TabBrowser.prototype.updateLayout): Deleted.
+        * UserInterface/Views/TimelineView.js:
+        (WebInspector.TimelineView.prototype.filterUpdated):
+        (WebInspector.TimelineView.prototype.needsLayout):
+        (WebInspector.TimelineView.prototype.updateLayout): Deleted.
+        (WebInspector.TimelineView.prototype.updateLayoutIfNeeded): Deleted.
+        (WebInspector.TimelineView): Deleted.
+
+        * UserInterface/Views/Toolbar.js:
+        (WebInspector.Toolbar):
+        (WebInspector.Toolbar.prototype.set displayMode):
+        (WebInspector.Toolbar.prototype.set sizeMode):
+        (WebInspector.Toolbar.prototype.addToolbarItem):
+        (WebInspector.Toolbar.prototype.layout):
+        (WebInspector.Toolbar.prototype.customUpdateLayout): Deleted.
+        Renamed to layout. This eliminated a layering violation in NavigationBar,
+        where the function previously known as updateLayout checked for a
+        a `customUpdateLayout` function property, and would call it instead of its
+        own layout logic if found.
+
+        * UserInterface/Views/View.js: Added.
+        (WebInspector.View):
+        (WebInspector.View.prototype.get element):
+        (WebInspector.View.prototype.get subviews):
+        (WebInspector.View.prototype.addSubview):
+        Appends a view to the end of the subview list.
+        (WebInspector.View.prototype.insertSubviewBefore):
+        Inserts a view into subview list before another subview.
+        (WebInspector.View.prototype.removeSubview):
+        (WebInspector.View.prototype.replaceSubview):
+        (WebInspector.View.prototype.updateLayout):
+        No longer overridden by subclasses.
+        (WebInspector.View.prototype.updateLayoutIfNeeded):
+        Forces a layout if one has been scheduled, otherwise does nothing.
+        (WebInspector.View.prototype.needsLayout):
+        Schedules a layout for the view.
+        (WebInspector.View.prototype.layout):
+        Overridden by views that require special layout logic. Layouts
+        cascade to child views automatically.
+        (WebInspector.View.prototype._layoutSubtree):
+        Main layout entry point. Called by requestAnimationFrame via needsLayut, by
+        updateLayout when forcing a synchronous layout, and called recursively during
+        subview traversal.
+
 2015-11-03  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Handle or Remove ParseHTML Timeline Event Records
index 2997d0b..7fc6e8c 100644 (file)
@@ -1282,6 +1282,7 @@ WebInspector._windowBlurred = function(event)
 WebInspector._windowResized = function(event)
 {
     this.toolbar.updateLayout();
+    this.tabBar.updateLayout();
     this._tabBrowserSizeDidChange();
 };
 
index ace375b..12f5599 100644 (file)
     <script src="Models/TypeSet.js"></script>
     <script src="Models/WrappedPromise.js"></script>
 
+    <script src="Views/View.js"></script>
+
     <script src="Views/ConsoleCommandView.js"></script>
     <script src="Views/ConsoleMessageView.js"></script>
     <script src="Views/ContentView.js"></script>
index 80f494b..d657236 100644 (file)
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.ConsolePrompt = class ConsolePrompt extends WebInspector.Object
+WebInspector.ConsolePrompt = class ConsolePrompt extends WebInspector.View
 {
     constructor(delegate, mimeType, element)
     {
-        super();
+        super(element);
 
         mimeType = parseMIMEType(mimeType).type;
 
-        this._element = element || document.createElement("div");
-        this._element.classList.add("console-prompt", WebInspector.SyntaxHighlightedStyleClassName);
+        this.element.classList.add("console-prompt", WebInspector.SyntaxHighlightedStyleClassName);
 
         this._delegate = delegate || null;
 
@@ -66,11 +65,6 @@ WebInspector.ConsolePrompt = class ConsolePrompt extends WebInspector.Object
 
     // Public
 
-    get element()
-    {
-        return this._element;
-    }
-
     get delegate()
     {
         return this._delegate;
@@ -126,11 +120,6 @@ WebInspector.ConsolePrompt = class ConsolePrompt extends WebInspector.Object
         this._codeMirror.refresh();
     }
 
-    updateLayout()
-    {
-        this._codeMirror.refresh();
-    }
-
     updateCompletions(completions, implicitSuffix)
     {
         this._completionController.updateCompletions(completions, implicitSuffix);
@@ -158,6 +147,11 @@ WebInspector.ConsolePrompt = class ConsolePrompt extends WebInspector.Object
         return !!this.text;
     }
 
+    layout()
+    {
+        this._codeMirror.refresh();
+    }
+
     // Private
 
     _handleTabKey(codeMirror)
index be7be02..71134ab 100644 (file)
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.ContentBrowser = class ContentBrowser extends WebInspector.Object
+WebInspector.ContentBrowser = class ContentBrowser extends WebInspector.View
 {
     constructor(element, delegate, disableBackForward)
     {
-        super();
+        super(element);
 
-        this._element = element || document.createElement("div");
-        this._element.classList.add("content-browser");
+        this.element.classList.add("content-browser");
 
         this._navigationBar = new WebInspector.NavigationBar;
-        this._element.appendChild(this._navigationBar.element);
+        this.addSubview(this._navigationBar);
 
         this._contentViewContainer = new WebInspector.ContentViewContainer;
         this._contentViewContainer.addEventListener(WebInspector.ContentViewContainer.Event.CurrentContentViewDidChange, this._currentContentViewDidChange, this);
-        this._element.appendChild(this._contentViewContainer.element);
+        this.addSubview(this._contentViewContainer);
 
         this._findBanner = new WebInspector.FindBanner(this);
         this._findBanner.addEventListener(WebInspector.FindBanner.Event.DidShow, this._findBannerDidShow, this);
         this._findBanner.addEventListener(WebInspector.FindBanner.Event.DidHide, this._findBannerDidHide, this);
 
         if (!disableBackForward) {
-            this._backKeyboardShortcut = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.CommandOrControl | WebInspector.KeyboardShortcut.Modifier.Control, WebInspector.KeyboardShortcut.Key.Left, this._backButtonClicked.bind(this), this._element);
-            this._forwardKeyboardShortcut = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.CommandOrControl | WebInspector.KeyboardShortcut.Modifier.Control, WebInspector.KeyboardShortcut.Key.Right, this._forwardButtonClicked.bind(this), this._element);
+            this._backKeyboardShortcut = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.CommandOrControl | WebInspector.KeyboardShortcut.Modifier.Control, WebInspector.KeyboardShortcut.Key.Left, this._backButtonClicked.bind(this), this.element);
+            this._forwardKeyboardShortcut = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.CommandOrControl | WebInspector.KeyboardShortcut.Modifier.Control, WebInspector.KeyboardShortcut.Key.Right, this._forwardButtonClicked.bind(this), this.element);
 
             this._backButtonNavigationItem = new WebInspector.ButtonNavigationItem("back", WebInspector.UIString("Back (%s)").format(this._backKeyboardShortcut.displayName), "Images/BackForwardArrows.svg#back-arrow-mask", 8, 13);
             this._backButtonNavigationItem.addEventListener(WebInspector.ButtonNavigationItem.Event.Clicked, this._backButtonClicked, this);
@@ -81,11 +80,6 @@ WebInspector.ContentBrowser = class ContentBrowser extends WebInspector.Object
 
     // Public
 
-    get element()
-    {
-        return this._element;
-    }
-
     get navigationBar()
     {
         return this._navigationBar;
@@ -133,12 +127,6 @@ WebInspector.ContentBrowser = class ContentBrowser extends WebInspector.Object
         return representedObjects;
     }
 
-    updateLayout()
-    {
-        this._navigationBar.updateLayout();
-        this._contentViewContainer.updateLayout();
-    }
-
     showContentViewForRepresentedObject(representedObject, cookie, extraArguments)
     {
         var contentView = this.contentViewForRepresentedObject(representedObject, false, extraArguments);
index 4ee2ad3..5997cb0 100644 (file)
@@ -42,7 +42,6 @@ WebInspector.ContentBrowserTabContentView = class ContentBrowserTabContentView e
 
         this._lastSelectedDetailsSidebarPanelSetting = new WebInspector.Setting(identifier + "-last-selected-details-sidebar-panel", null);
 
-        this._contentBrowser = this._contentBrowser;
         this._contentBrowser.addEventListener(WebInspector.ContentBrowser.Event.CurrentRepresentedObjectsDidChange, this.showDetailsSidebarPanels, this);
         this._contentBrowser.addEventListener(WebInspector.ContentBrowser.Event.CurrentContentViewDidChange, this._contentBrowserCurrentContentViewDidChange, this);
 
@@ -82,7 +81,7 @@ WebInspector.ContentBrowserTabContentView = class ContentBrowserTabContentView e
             WebInspector.detailsSidebar.addEventListener(WebInspector.Sidebar.Event.SidebarPanelSelected, this._detailsSidebarPanelSelected, this);
         }
 
-        this.element.appendChild(this._contentBrowser.element);
+        this.addSubview(this._contentBrowser);
     }
 
     // Public
@@ -122,13 +121,6 @@ WebInspector.ContentBrowserTabContentView = class ContentBrowserTabContentView e
         this._contentBrowser.contentViewContainer.closeAllContentViews();
     }
 
-    updateLayout()
-    {
-        super.updateLayout();
-
-        this._contentBrowser.updateLayout();
-    }
-
     get managesDetailsSidebarPanels()
     {
         return true;
index a7cb8d3..18022d3 100644 (file)
@@ -23,7 +23,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.ContentView = class ContentView extends WebInspector.Object
+WebInspector.ContentView = class ContentView extends WebInspector.View
 {
     constructor(representedObject, extraArguments)
     {
@@ -34,8 +34,7 @@ WebInspector.ContentView = class ContentView extends WebInspector.Object
 
         this._representedObject = representedObject;
 
-        this._element = document.createElement("div");
-        this._element.classList.add("content-view");
+        this.element.classList.add("content-view");
 
         this._parentContainer = null;
     }
@@ -195,11 +194,6 @@ WebInspector.ContentView = class ContentView extends WebInspector.Object
         return [];
     }
 
-    get element()
-    {
-        return this._element;
-    }
-
     get parentContainer()
     {
         return this._parentContainer;
@@ -245,11 +239,6 @@ WebInspector.ContentView = class ContentView extends WebInspector.Object
         return true;
     }
 
-    updateLayout()
-    {
-        // Implemented by subclasses.
-    }
-
     shown()
     {
         // Implemented by subclasses.
index 368588d..a6da1da 100644 (file)
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.ContentViewContainer = class ContentViewContainer extends WebInspector.Object
+WebInspector.ContentViewContainer = class ContentViewContainer extends WebInspector.View
 {
-    constructor(element)
+    constructor()
     {
         super();
 
-        this._element = element || document.createElement("div");
-        this._element.classList.add("content-view-container");
+        this.element.classList.add("content-view-container");
 
         this._backForwardList = [];
         this._currentIndex = -1;
@@ -38,11 +37,6 @@ WebInspector.ContentViewContainer = class ContentViewContainer extends WebInspec
 
     // Public
 
-    get element()
-    {
-        return this._element;
-    }
-
     get currentIndex()
     {
         return this._currentIndex;
@@ -67,13 +61,6 @@ WebInspector.ContentViewContainer = class ContentViewContainer extends WebInspec
         return this._backForwardList[this._currentIndex];
     }
 
-    updateLayout()
-    {
-        var currentContentView = this.currentContentView;
-        if (currentContentView)
-            currentContentView.updateLayout();
-    }
-
     contentViewForRepresentedObject(representedObject, onlyExisting, extraArguments)
     {
         console.assert(representedObject);
@@ -428,18 +415,6 @@ WebInspector.ContentViewContainer = class ContentViewContainer extends WebInspec
 
     // Private
 
-    _addContentViewElement(contentView)
-    {
-        if (contentView.element.parentNode !== this._element)
-            this._element.appendChild(contentView.element);
-    }
-
-    _removeContentViewElement(contentView)
-    {
-        if (contentView.element.parentNode)
-            contentView.element.parentNode.removeChild(contentView.element);
-    }
-
     _disassociateFromContentView(contentView)
     {
         console.assert(!contentView.visible);
@@ -460,7 +435,9 @@ WebInspector.ContentViewContainer = class ContentViewContainer extends WebInspec
     {
         console.assert(entry instanceof WebInspector.BackForwardEntry);
 
-        this._addContentViewElement(entry.contentView);
+        if (!this.subviews.includes(entry.contentView))
+            this.addSubview(entry.contentView)
+
         entry.prepareToShow(shouldCallShown);
     }
 
@@ -469,7 +446,8 @@ WebInspector.ContentViewContainer = class ContentViewContainer extends WebInspec
         console.assert(entry instanceof WebInspector.BackForwardEntry);
 
         entry.prepareToHide();
-        this._removeContentViewElement(entry.contentView);
+        if (this.subviews.includes(entry.contentView))
+            this.removeSubview(entry.contentView)
     }
 };
 
index 19fc45f..b78a0b6 100644 (file)
@@ -23,7 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.DataGrid = class DataGrid extends WebInspector.Object
+WebInspector.DataGrid = class DataGrid extends WebInspector.View
 {
     constructor(columnsData, editCallback, deleteCallback, preferredColumnOrder)
     {
@@ -48,7 +48,6 @@ WebInspector.DataGrid = class DataGrid extends WebInspector.Object
         this.resizers = [];
         this._columnWidthsInitialized = false;
 
-        this.element = document.createElement("div");
         this.element.className = "data-grid";
         this.element.tabIndex = 0;
         this.element.addEventListener("keydown", this._keyDown.bind(this), false);
@@ -400,7 +399,7 @@ WebInspector.DataGrid = class DataGrid extends WebInspector.Object
         for (var [identifier, column] of this.columns)
             column["element"].style.width = widths[identifier] + "%";
         this._columnWidthsInitialized = false;
-        this.updateLayout();
+        this.needsLayout();
     }
 
     insertColumn(columnIdentifier, columnData, insertionIndex)
@@ -552,9 +551,9 @@ WebInspector.DataGrid = class DataGrid extends WebInspector.Object
     //
     // If this function is not called after the DataGrid is attached to its
     // parent element, then the DataGrid's columns will not be resizable.
-    updateLayout()
+    layout()
     {
-        // Do not attempt to use offsetes if we're not attached to the document tree yet.
+        // Do not attempt to use offsets if we're not attached to the document tree yet.
         if (!this._columnWidthsInitialized && this.element.offsetWidth) {
             // Give all the columns initial widths now so that during a resize,
             // when the two columns that get resized get a percent value for
@@ -580,7 +579,6 @@ WebInspector.DataGrid = class DataGrid extends WebInspector.Object
         }
 
         this._positionResizerElements();
-        this.dispatchEventToListeners(WebInspector.DataGrid.Event.DidLayout);
     }
 
     columnWidthsMap()
@@ -602,7 +600,7 @@ WebInspector.DataGrid = class DataGrid extends WebInspector.Object
             this._dataTableColumnGroupElement.children[ordinal].style.width = width;
         }
 
-        this.updateLayout();
+        this.needsLayout();
     }
 
     _isColumnVisible(columnIdentifier)
@@ -1260,7 +1258,6 @@ WebInspector.DataGrid = class DataGrid extends WebInspector.Object
 
         this._positionResizerElements();
         event.preventDefault();
-        this.dispatchEventToListeners(WebInspector.DataGrid.Event.DidLayout);
     }
 
     resizerDragEnded(resizer)
@@ -1270,12 +1267,10 @@ WebInspector.DataGrid = class DataGrid extends WebInspector.Object
             return;
 
         this._currentResizer = null;
-        this.dispatchEventToListeners(WebInspector.DataGrid.Event.DidLayout);
     }
 };
 
 WebInspector.DataGrid.Event = {
-    DidLayout: "datagrid-did-layout",
     SortChanged: "datagrid-sort-changed",
     SelectedNodeChanged: "datagrid-selected-node-changed",
     ExpandedNode: "datagrid-expanded-node",
index 2dba20b..8ab21e4 100644 (file)
@@ -61,7 +61,7 @@ WebInspector.HierarchicalPathNavigationItem = class HierarchicalPathNavigationIt
 
         // Update layout for the so other items can adjust to the extra space (or lack thereof) too.
         if (this.parentNavigationBar)
-            this.parentNavigationBar.updateLayoutSoon();
+            this.parentNavigationBar.needsLayout();
     }
 
     get lastComponent()
index d46f13d..ca45ad9 100644 (file)
@@ -86,7 +86,7 @@ WebInspector.LayoutTimelineView = class LayoutTimelineView extends WebInspector.
         this.navigationSidebarTreeOutline.element.addEventListener("mouseleave", this._mouseLeaveTreeOutline.bind(this));
 
         this.element.classList.add("layout");
-        this.element.appendChild(this._dataGrid.element);
+        this.addSubview(this._dataGrid);
 
         timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._layoutTimelineRecordAdded, this);
 
@@ -133,15 +133,6 @@ WebInspector.LayoutTimelineView = class LayoutTimelineView extends WebInspector.
         this._updateHighlight();
     }
 
-    updateLayout()
-    {
-        super.updateLayout();
-
-        this._dataGrid.updateLayout();
-
-        this._processPendingRecords();
-    }
-
     matchTreeElementAgainstCustomFilters(treeElement)
     {
         return this._dataGrid.treeElementMatchesActiveScopeFilters(treeElement);
@@ -185,6 +176,11 @@ WebInspector.LayoutTimelineView = class LayoutTimelineView extends WebInspector.
         this._updateHighlight();
     }
 
+    layout()
+    {
+        this._processPendingRecords();
+    }
+
     // Private
 
     _processPendingRecords()
index de85695..8facf3b 100644 (file)
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.NavigationBar = class NavigationBar extends WebInspector.Object
+WebInspector.NavigationBar = class NavigationBar extends WebInspector.View
 {
     constructor(element, navigationItems, role, label)
     {
-        super();
+        super(element);
 
-        this._element = element || document.createElement("div");
-        this._element.classList.add(this.constructor.StyleClassName || "navigation-bar");
-        this._element.tabIndex = 0;
+        this.element.classList.add(this.constructor.StyleClassName || "navigation-bar");
+        this.element.tabIndex = 0;
 
         if (role)
-            this._element.setAttribute("role", role);
+            this.element.setAttribute("role", role);
         if (label)
-            this._element.setAttribute("aria-label", label);
+            this.element.setAttribute("aria-label", label);
 
-        this._element.addEventListener("focus", this._focus.bind(this), false);
-        this._element.addEventListener("blur", this._blur.bind(this), false);
-        this._element.addEventListener("keydown", this._keyDown.bind(this), false);
-        this._element.addEventListener("mousedown", this._mouseDown.bind(this), false);
+        this.element.addEventListener("focus", this._focus.bind(this), false);
+        this.element.addEventListener("blur", this._blur.bind(this), false);
+        this.element.addEventListener("keydown", this._keyDown.bind(this), false);
+        this.element.addEventListener("mousedown", this._mouseDown.bind(this), false);
 
+        this._minimumWidth = NaN;
         this._navigationItems = [];
 
         if (navigationItems) {
@@ -75,7 +75,7 @@ WebInspector.NavigationBar = class NavigationBar extends WebInspector.Object
         this._navigationItems.splice(index, 0, navigationItem);
 
         if (!parentElement)
-            parentElement = this._element;
+            parentElement = this.element;
 
         var nextSibling = this._navigationItems[index + 1];
         var nextSiblingElement = nextSibling ? nextSibling.element : null;
@@ -84,9 +84,9 @@ WebInspector.NavigationBar = class NavigationBar extends WebInspector.Object
 
         parentElement.insertBefore(navigationItem.element, nextSiblingElement);
 
-        this._minimumWidthNeedsRecalculation = true;
+        this._minimumWidth = NaN;
 
-        this.updateLayoutSoon();
+        this.needsLayout();
 
         return navigationItem;
     }
@@ -105,72 +105,13 @@ WebInspector.NavigationBar = class NavigationBar extends WebInspector.Object
         this._navigationItems.remove(navigationItem);
         navigationItem.element.remove();
 
-        this._minimumWidthNeedsRecalculation = true;
+        this._minimumWidth = NaN;
 
-        this.updateLayoutSoon();
+        this.needsLayout();
 
         return navigationItem;
     }
 
-    updateLayoutSoon()
-    {
-        if (this._updateLayoutIdentifier)
-            return;
-
-        this._needsLayout = true;
-
-        function update()
-        {
-            this._updateLayoutIdentifier = undefined;
-
-            if (this._needsLayout)
-                this.updateLayout();
-        }
-
-        this._updateLayoutIdentifier = requestAnimationFrame(update.bind(this));
-    }
-
-    updateLayout()
-    {
-        if (this._updateLayoutIdentifier) {
-            cancelAnimationFrame(this._updateLayoutIdentifier);
-            this._updateLayoutIdentifier = undefined;
-        }
-
-        this._needsLayout = false;
-
-        if (typeof this.customUpdateLayout === "function") {
-            this.customUpdateLayout();
-            return;
-        }
-
-        // Remove the collapsed style class to test if the items can fit at full width.
-        this._element.classList.remove(WebInspector.NavigationBar.CollapsedStyleClassName);
-
-        // Tell each navigation item to update to full width if needed.
-        for (var i = 0; i < this._navigationItems.length; ++i)
-            this._navigationItems[i].updateLayout(true);
-
-        var totalItemWidth = 0;
-        for (var i = 0; i < this._navigationItems.length; ++i) {
-            // Skip flexible space items since they can take up no space at the minimum width.
-            if (this._navigationItems[i] instanceof WebInspector.FlexibleSpaceNavigationItem)
-                continue;
-
-            totalItemWidth += this._navigationItems[i].element.realOffsetWidth;
-        }
-
-        var barWidth = this._element.realOffsetWidth;
-
-        // Add the collapsed class back if the items are wider than the bar.
-        if (totalItemWidth > barWidth)
-            this._element.classList.add(WebInspector.NavigationBar.CollapsedStyleClassName);
-
-        // Give each navigation item the opportunity to collapse further.
-        for (var i = 0; i < this._navigationItems.length; ++i)
-            this._navigationItems[i].updateLayout();
-    }
-
     get selectedNavigationItem()
     {
         return this._selectedNavigationItem || null;
@@ -206,18 +147,10 @@ WebInspector.NavigationBar = class NavigationBar extends WebInspector.Object
         return this._navigationItems;
     }
 
-    get element()
-    {
-        return this._element;
-    }
-
     get minimumWidth()
     {
-        if (this._minimumWidth === undefined || this._minimumWidthNeedsRecalculation) {
+        if (isNaN(this._minimumWidth))
             this._minimumWidth = this._calculateMinimumWidth();
-            delete this._minimumWidthNeedsRecalculation;
-        }
-
         return this._minimumWidth;
     }
 
@@ -227,6 +160,35 @@ WebInspector.NavigationBar = class NavigationBar extends WebInspector.Object
         return false;
     }
 
+    layout()
+    {
+        // Remove the collapsed style class to test if the items can fit at full width.
+        this.element.classList.remove(WebInspector.NavigationBar.CollapsedStyleClassName);
+
+        // Tell each navigation item to update to full width if needed.
+        for (let navigationItem of this._navigationItems)
+            navigationItem.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 WebInspector.FlexibleSpaceNavigationItem)
+                continue;
+
+            totalItemWidth += navigationItem.element.realOffsetWidth;
+        }
+
+        const barWidth = this.element.realOffsetWidth;
+
+        // Add the collapsed class back if the items are wider than the bar.
+        if (totalItemWidth > barWidth)
+            this.element.classList.add(WebInspector.NavigationBar.CollapsedStyleClassName);
+
+        // Give each navigation item the opportunity to collapse further.
+        for (let navigationItem of this._navigationItems)
+            navigationItem.updateLayout(false);
+    }
+
     // Private
 
     _findNavigationItem(navigationItemOrIdentifierOrIndex)
@@ -259,7 +221,7 @@ WebInspector.NavigationBar = class NavigationBar extends WebInspector.Object
         // Remove the tabIndex so clicking the navigation bar does not give it focus.
         // Only keep the tabIndex if already focused from keyboard navigation. This matches Xcode.
         if (!this._focused)
-            this._element.removeAttribute("tabindex");
+            this.element.removeAttribute("tabindex");
 
         var itemElement = event.target.enclosingNodeOrSelfWithClass(WebInspector.RadioButtonNavigationItem.StyleClassName);
         if (!itemElement || !itemElement.navigationItem)
@@ -297,15 +259,15 @@ WebInspector.NavigationBar = class NavigationBar extends WebInspector.Object
         event.stopPropagation();
 
         var itemElement = event.target.enclosingNodeOrSelfWithClass(WebInspector.RadioButtonNavigationItem.StyleClassName);
-        if (!itemElement || !itemElement.navigationItem || !this._element.contains(itemElement)) {
+        if (!itemElement || !itemElement.navigationItem || !this.element.contains(itemElement)) {
             // Find the element that is at the X position of the mouse, even when the mouse is no longer
             // vertically in the navigation bar.
-            var element = document.elementFromPoint(event.pageX, this._element.totalOffsetTop + (this._element.offsetHeight / 2));
+            var element = document.elementFromPoint(event.pageX, this.element.totalOffsetTop + (this.element.offsetHeight / 2));
             if (!element)
                 return;
 
             itemElement = element.enclosingNodeOrSelfWithClass(WebInspector.RadioButtonNavigationItem.StyleClassName);
-            if (!itemElement || !itemElement.navigationItem || !this._element.contains(itemElement))
+            if (!itemElement || !itemElement.navigationItem || !this.element.contains(itemElement))
                 return;
         }
 
@@ -336,7 +298,7 @@ WebInspector.NavigationBar = class NavigationBar extends WebInspector.Object
         delete this._mouseUpEventListener;
 
         // Restore the tabIndex so the navigation bar can be in the keyboard tab loop.
-        this._element.tabIndex = 0;
+        this.element.tabIndex = 0;
 
         // Dispatch the selected event here since the selectedNavigationItem setter surpresses it
         // while the mouse is down to prevent sending it while scrubbing the bar.
@@ -393,11 +355,11 @@ WebInspector.NavigationBar = class NavigationBar extends WebInspector.Object
 
     _calculateMinimumWidth()
     {
-        var wasCollapsed = this._element.classList.contains(WebInspector.NavigationBar.CollapsedStyleClassName);
+        const wasCollapsed = this.element.classList.contains(WebInspector.NavigationBar.CollapsedStyleClassName);
 
         // Add the collapsed style class to calculate the width of the items when they are collapsed.
         if (!wasCollapsed)
-            this._element.classList.add(WebInspector.NavigationBar.CollapsedStyleClassName);
+            this.element.classList.add(WebInspector.NavigationBar.CollapsedStyleClassName);
 
         var totalItemWidth = 0;
         for (var i = 0; i < this._navigationItems.length; ++i) {
@@ -409,7 +371,7 @@ WebInspector.NavigationBar = class NavigationBar extends WebInspector.Object
 
         // Remove the collapsed style class if we were not collapsed before.
         if (!wasCollapsed)
-            this._element.classList.remove(WebInspector.NavigationBar.CollapsedStyleClassName);
+            this.element.classList.remove(WebInspector.NavigationBar.CollapsedStyleClassName);
 
         return totalItemWidth;
     }
index cb75543..1d76115 100644 (file)
@@ -80,7 +80,7 @@ WebInspector.NavigationItem = class NavigationItem extends WebInspector.Object
         this._element.classList.toggle("hidden", flag);
 
         if (this._parentNavigationBar)
-            this._parentNavigationBar.updateLayoutSoon();
+            this._parentNavigationBar.needsLayout();
     }
 
     // Private
index 2bb4036..a0187ea 100644 (file)
@@ -93,7 +93,7 @@ WebInspector.NetworkTimelineView = class NetworkTimelineView extends WebInspecto
         this._dataGrid.sortOrder = WebInspector.DataGrid.SortOrder.Ascending;
 
         this.element.classList.add("network");
-        this.element.appendChild(this._dataGrid.element);
+        this.addSubview(this._dataGrid);
 
         timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._networkTimelineRecordAdded, this);
 
@@ -129,15 +129,6 @@ WebInspector.NetworkTimelineView = class NetworkTimelineView extends WebInspecto
         this._dataGrid.closed();
     }
 
-    updateLayout()
-    {
-        super.updateLayout();
-
-        this._dataGrid.updateLayout();
-
-        this._processPendingRecords();
-    }
-
     matchTreeElementAgainstCustomFilters(treeElement)
     {
         return this._dataGrid.treeElementMatchesActiveScopeFilters(treeElement);
@@ -187,6 +178,11 @@ WebInspector.NetworkTimelineView = class NetworkTimelineView extends WebInspecto
         super.treeElementSelected(treeElement, selectedByUser);
     }
 
+    layout()
+    {
+        this._processPendingRecords();
+    }
+
     // Private
 
     _processPendingRecords()
index ebe1ad5..8c8a3d5 100644 (file)
@@ -41,13 +41,14 @@ WebInspector.OverviewTimelineView = class OverviewTimelineView extends WebInspec
 
         this._timelineRuler = new WebInspector.TimelineRuler;
         this._timelineRuler.allowsClippedLabels = true;
+        // FIXME: change to `this.addSubview(this._timelineRuler)` once <https://webkit.org/b/150703> is fixed.
         this.element.appendChild(this._timelineRuler.element);
 
         this._currentTimeMarker = new WebInspector.TimelineMarker(0, WebInspector.TimelineMarker.Type.CurrentTime);
         this._timelineRuler.addMarker(this._currentTimeMarker);
 
         this.element.classList.add("overview");
-        this.element.appendChild(this._dataGrid.element);
+        this.addSubview(this._dataGrid);
 
         this._networkTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Network);
         this._networkTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._networkTimelineRecordAdded, this);
@@ -88,35 +89,6 @@ WebInspector.OverviewTimelineView = class OverviewTimelineView extends WebInspec
         this._recording.removeEventListener(null, null, this);
     }
 
-    updateLayout()
-    {
-        super.updateLayout();
-
-        var oldZeroTime = this._timelineRuler.zeroTime;
-        var oldStartTime = this._timelineRuler.startTime;
-        var oldEndTime = this._timelineRuler.endTime;
-        var oldCurrentTime = this._currentTimeMarker.time;
-
-        this._timelineRuler.zeroTime = this.zeroTime;
-        this._timelineRuler.startTime = this.startTime;
-        this._timelineRuler.endTime = this.endTime;
-        this._currentTimeMarker.time = this.currentTime;
-
-        // The TimelineDataGridNode graphs are positioned with percentages, so they auto resize with the view.
-        // We only need to refresh the graphs when the any of the times change.
-        if (this.zeroTime !== oldZeroTime || this.startTime !== oldStartTime || this.endTime !== oldEndTime || this.currentTime !== oldCurrentTime) {
-            var dataGridNode = this._dataGrid.children[0];
-            while (dataGridNode) {
-                dataGridNode.refreshGraph();
-                dataGridNode = dataGridNode.traverseNextNode(true, null, true);
-            }
-        }
-
-        this._timelineRuler.updateLayout();
-
-        this._processPendingRepresentedObjects();
-    }
-
     get selectionPathComponents()
     {
         var dataGridNode = this._dataGrid.selectedNode;
@@ -187,6 +159,34 @@ WebInspector.OverviewTimelineView = class OverviewTimelineView extends WebInspec
         WebInspector.showOriginalOrFormattedSourceCodeLocation(treeElement.sourceCodeTimeline.sourceCodeLocation);
     }
 
+    layout()
+    {
+        let oldZeroTime = this._timelineRuler.zeroTime;
+        let oldStartTime = this._timelineRuler.startTime;
+        let oldEndTime = this._timelineRuler.endTime;
+        let oldCurrentTime = this._currentTimeMarker.time;
+
+        this._timelineRuler.zeroTime = this.zeroTime;
+        this._timelineRuler.startTime = this.startTime;
+        this._timelineRuler.endTime = this.endTime;
+        this._currentTimeMarker.time = this.currentTime;
+
+        // The TimelineDataGridNode graphs are positioned with percentages, so they auto resize with the view.
+        // We only need to refresh the graphs when the any of the times change.
+        if (this.zeroTime !== oldZeroTime || this.startTime !== oldStartTime || this.endTime !== oldEndTime || this.currentTime !== oldCurrentTime) {
+            let dataGridNode = this._dataGrid.children[0];
+            while (dataGridNode) {
+                dataGridNode.refreshGraph();
+                dataGridNode = dataGridNode.traverseNextNode(true, null, true);
+            }
+        }
+
+        // FIXME: remove once <https://webkit.org/b/150703> is fixed.
+        this._timelineRuler.updateLayout();
+
+        this._processPendingRepresentedObjects();
+    }
+
     // Private
 
     _compareTreeElementsByDetails(a, b)
index c4ad520..856dd9e 100644 (file)
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.QuickConsole = class QuickConsole extends WebInspector.Object
+WebInspector.QuickConsole = class QuickConsole extends WebInspector.View
 {
     constructor(element)
     {
-        super();
+        super(element);
 
         this._toggleOrFocusKeyboardShortcut = new WebInspector.KeyboardShortcut(null, WebInspector.KeyboardShortcut.Key.Escape, this._toggleOrFocus.bind(this));
 
@@ -38,12 +38,11 @@ WebInspector.QuickConsole = class QuickConsole extends WebInspector.Object
         this._otherExecutionContextPathComponents = [];
         this._frameIdentifierToExecutionContextPathComponentMap = {};
 
-        this._element = element || document.createElement("div");
-        this._element.classList.add("quick-console");
+        this.element.classList.add("quick-console");
 
         this.prompt = new WebInspector.ConsolePrompt(null, "text/javascript");
         this.prompt.element.classList.add("text-prompt");
-        this._element.appendChild(this.prompt.element);
+        this.addSubview(this.prompt);
 
         // FIXME: CodeMirror 4 has a default "Esc" key handler that always prevents default.
         // Our keyboard shortcut above will respect the default prevented and ignore the event
@@ -55,7 +54,7 @@ WebInspector.QuickConsole = class QuickConsole extends WebInspector.Object
         this.prompt.shown();
 
         this._navigationBar = new WebInspector.QuickConsoleNavigationBar;
-        this._element.appendChild(this._navigationBar.element);
+        this.addSubview(this._navigationBar);
 
         this._executionContextSelectorItem = new WebInspector.HierarchicalPathNavigationItem;
         this._executionContextSelectorItem.showSelectorArrows = true;
@@ -74,11 +73,6 @@ WebInspector.QuickConsole = class QuickConsole extends WebInspector.Object
 
     // Public
 
-    get element()
-    {
-        return this._element;
-    }
-
     get navigationBar()
     {
         return this._navigationBar;
@@ -89,13 +83,6 @@ WebInspector.QuickConsole = class QuickConsole extends WebInspector.Object
         return this._selectedExecutionContextPathComponent._executionContextIdentifier;
     }
 
-    updateLayout()
-    {
-        // A hard maximum size of 33% of the window.
-        var maximumAllowedHeight = Math.round(window.innerHeight * 0.33);
-        this.prompt.element.style.maxHeight = maximumAllowedHeight + "px";
-    }
-
     consoleLogVisibilityChanged(visible)
     {
         if (visible === this.element.classList.contains(WebInspector.QuickConsole.ShowingLogClassName))
@@ -106,6 +93,15 @@ WebInspector.QuickConsole = class QuickConsole extends WebInspector.Object
         this.dispatchEventToListeners(WebInspector.QuickConsole.Event.DidResize);
     }
 
+    // Protected
+
+    layout()
+    {
+        // A hard maximum size of 33% of the window.
+        let maximumAllowedHeight = Math.round(window.innerHeight * 0.33);
+        this.prompt.element.style.maxHeight = maximumAllowedHeight + "px";
+    }
+
     // Private
 
     _executionContextPathComponentsToDisplay()
index c9f97eb..617c59d 100644 (file)
@@ -79,7 +79,7 @@ WebInspector.RenderingFrameTimelineView = class RenderingFrameTimelineView exten
         this._dataGrid.sortOrder = WebInspector.DataGrid.SortOrder.Ascending;
 
         this.element.classList.add("rendering-frame");
-        this.element.appendChild(this._dataGrid.element);
+        this.addSubview(this._dataGrid);
 
         timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._renderingFrameTimelineRecordAdded, this);
 
@@ -131,15 +131,6 @@ WebInspector.RenderingFrameTimelineView = class RenderingFrameTimelineView exten
         this._dataGrid.closed();
     }
 
-    updateLayout()
-    {
-        super.updateLayout();
-
-        this._dataGrid.updateLayout();
-
-        this._processPendingRecords();
-    }
-
     get selectionPathComponents()
     {
         var dataGridNode = this._dataGrid.selectedNode;
@@ -245,6 +236,11 @@ WebInspector.RenderingFrameTimelineView = class RenderingFrameTimelineView exten
         return null;
     }
 
+    layout()
+    {
+        this._processPendingRecords();
+    }
+
     // Private
 
     _processPendingRecords()
index 48e5052..126a49d 100644 (file)
@@ -68,7 +68,7 @@ WebInspector.ScriptTimelineView = class ScriptTimelineView extends WebInspector.
         this._dataGrid.sortOrder = WebInspector.DataGrid.SortOrder.Ascending;
 
         this.element.classList.add("script");
-        this.element.appendChild(this._dataGrid.element);
+        this.addSubview(this._dataGrid);
 
         timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._scriptTimelineRecordAdded, this);
 
@@ -104,28 +104,6 @@ WebInspector.ScriptTimelineView = class ScriptTimelineView extends WebInspector.
         this._dataGrid.closed();
     }
 
-    updateLayout()
-    {
-        super.updateLayout();
-
-        this._dataGrid.updateLayout();
-
-        if (this.startTime !== this._oldStartTime || this.endTime !== this._oldEndTime) {
-            var dataGridNode = this._dataGrid.children[0];
-            while (dataGridNode) {
-                dataGridNode.updateRangeTimes(this.startTime, this.endTime);
-                if (dataGridNode.revealed)
-                    dataGridNode.refreshIfNeeded();
-                dataGridNode = dataGridNode.traverseNextNode(false, null, true);
-            }
-
-            this._oldStartTime = this.startTime;
-            this._oldEndTime = this.endTime;
-        }
-
-        this._processPendingRecords();
-    }
-
     get selectionPathComponents()
     {
         var dataGridNode = this._dataGrid.selectedNode;
@@ -217,6 +195,24 @@ WebInspector.ScriptTimelineView = class ScriptTimelineView extends WebInspector.
         }
     }
 
+    layout()
+    {
+        if (this.startTime !== this._oldStartTime || this.endTime !== this._oldEndTime) {
+            let dataGridNode = this._dataGrid.children[0];
+            while (dataGridNode) {
+                dataGridNode.updateRangeTimes(this.startTime, this.endTime);
+                if (dataGridNode.revealed)
+                    dataGridNode.refreshIfNeeded();
+                dataGridNode = dataGridNode.traverseNextNode(false, null, true);
+            }
+
+            this._oldStartTime = this.startTime;
+            this._oldEndTime = this.endTime;
+        }
+
+        this._processPendingRecords();
+    }
+
     // Private
 
     _processPendingRecords()
index 6d7f433..dc5d923 100644 (file)
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.TabBar = class TabBar extends WebInspector.Object
+WebInspector.TabBar = class TabBar extends WebInspector.View
 {
     constructor(element, tabBarItems)
     {
-        super();
+        super(element);
 
-        this._element = element || document.createElement("div");
-        this._element.classList.add("tab-bar");
-        this._element.setAttribute("role", "tablist");
+        this.element.classList.add("tab-bar");
+        this.element.setAttribute("role", "tablist");
 
         var topBorderElement = document.createElement("div");
         topBorderElement.classList.add("top-border");
-        this._element.appendChild(topBorderElement);
+        this.element.appendChild(topBorderElement);
 
-        this._element.addEventListener("mousedown", this._handleMouseDown.bind(this));
-        this._element.addEventListener("click", this._handleClick.bind(this));
-        this._element.addEventListener("mouseleave", this._handleMouseLeave.bind(this));
+        this.element.addEventListener("mousedown", this._handleMouseDown.bind(this));
+        this.element.addEventListener("click", this._handleClick.bind(this));
+        this.element.addEventListener("mouseleave", this._handleMouseLeave.bind(this));
 
         this._tabBarItems = [];
 
@@ -111,7 +110,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
         var lastIndex = this._newTabItem ? this._tabBarItems.length - 1 : this._tabBarItems.length;
         index = Math.max(0, Math.min(index, lastIndex));
 
-        if (this._element.classList.contains("animating")) {
+        if (this.element.classList.contains("animating")) {
             requestAnimationFrame(removeStyles.bind(this));
             doNotAnimate = true;
         }
@@ -125,34 +124,34 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
         var nextSibling = this._tabBarItems[index + 1];
         var nextSiblingElement = nextSibling ? nextSibling.element : (this._newTabItem ? this._newTabItem.element : null);
 
-        this._element.insertBefore(tabBarItem.element, nextSiblingElement);
+        this.element.insertBefore(tabBarItem.element, nextSiblingElement);
 
-        this._element.classList.toggle("single-tab", !this._hasMoreThanOneNormalTab());
+        this.element.classList.toggle("single-tab", !this._hasMoreThanOneNormalTab());
 
         tabBarItem.element.style.left = null;
         tabBarItem.element.style.width = null;
 
         function animateTabs()
         {
-            this._element.classList.add("animating");
-            this._element.classList.add("inserting-tab");
+            this.element.classList.add("animating");
+            this.element.classList.add("inserting-tab");
 
             this._applyTabBarItemSizesAndPositions(afterTabSizesAndPositions);
 
-            this._element.addEventListener("webkitTransitionEnd", removeStylesListener);
+            this.element.addEventListener("webkitTransitionEnd", removeStylesListener);
         }
 
         function removeStyles()
         {
-            this._element.classList.remove("static-layout");
-            this._element.classList.remove("animating");
-            this._element.classList.remove("inserting-tab");
+            this.element.classList.remove("static-layout");
+            this.element.classList.remove("animating");
+            this.element.classList.remove("inserting-tab");
 
             tabBarItem.element.classList.remove("being-inserted");
 
             this._clearTabBarItemSizesAndPositions();
 
-            this._element.removeEventListener("webkitTransitionEnd", removeStylesListener);
+            this.element.removeEventListener("webkitTransitionEnd", removeStylesListener);
         }
 
         if (!doNotAnimate) {
@@ -168,7 +167,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
             else
                 beforeTabSizesAndPositions.set(tabBarItem, {left: 0, width: 0});
 
-            this._element.classList.add("static-layout");
+            this.element.classList.add("static-layout");
             tabBarItem.element.classList.add("being-inserted");
 
             this._applyTabBarItemSizesAndPositions(beforeTabSizesAndPositions);
@@ -177,7 +176,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
 
             requestAnimationFrame(animateTabs.bind(this));
         } else
-            this.updateLayoutSoon();
+            this.needsLayout();
 
         this.dispatchEventToListeners(WebInspector.TabBar.Event.TabBarItemAdded, {tabBarItem});
 
@@ -204,7 +203,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
             this.selectedTabBarItem = nextTabBarItem;
         }
 
-        if (this._element.classList.contains("animating")) {
+        if (this.element.classList.contains("animating")) {
             requestAnimationFrame(removeStyles.bind(this));
             doNotAnimate = true;
         }
@@ -219,7 +218,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
         tabBarItem.element.remove();
 
         var hasMoreThanOneNormalTab = this._hasMoreThanOneNormalTab();
-        this._element.classList.toggle("single-tab", !hasMoreThanOneNormalTab);
+        this.element.classList.toggle("single-tab", !hasMoreThanOneNormalTab);
 
         const shouldOpenDefaultTab = !tabBarItem.isDefaultTab && !this.hasNormalTab();
         if (shouldOpenDefaultTab)
@@ -230,7 +229,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
                 this._tabAnimatedClosedSinceMouseEnter = true;
                 this._finishExpandingTabsAfterClose(beforeTabSizesAndPositions);
             } else
-                this.updateLayoutSoon();
+                this.needsLayout();
 
             this.dispatchEventToListeners(WebInspector.TabBar.Event.TabBarItemRemoved, {tabBarItem});
 
@@ -244,8 +243,8 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
 
         function animateTabs()
         {
-            this._element.classList.add("animating");
-            this._element.classList.add("closing-tab");
+            this.element.classList.add("animating");
+            this.element.classList.add("closing-tab");
 
             var left = 0;
             for (var currentTabBarItem of this._tabBarItems) {
@@ -266,7 +265,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
             if (lastNormalTabBarItem !== this._selectedTabBarItem)
                 lastNormalTabBarItem.element.style.width = (parseFloat(lastNormalTabBarItem.element.style.width) + 1) + "px";
 
-            this._element.addEventListener("webkitTransitionEnd", removeStylesListener);
+            this.element.addEventListener("webkitTransitionEnd", removeStylesListener);
         }
 
         function removeStyles()
@@ -275,16 +274,16 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
             if (this._selectedTabBarItem && this._selectedTabBarItem !== lastNormalTabBarItem)
                 this._selectedTabBarItem.element.style.width = (parseFloat(this._selectedTabBarItem.element.style.width) - 1) + "px";
 
-            this._element.classList.remove("animating");
-            this._element.classList.remove("closing-tab");
+            this.element.classList.remove("animating");
+            this.element.classList.remove("closing-tab");
 
             this.updateLayout();
 
-            this._element.removeEventListener("webkitTransitionEnd", removeStylesListener);
+            this.element.removeEventListener("webkitTransitionEnd", removeStylesListener);
         }
 
         if (!doNotAnimate) {
-            this._element.classList.add("static-layout");
+            this.element.classList.add("static-layout");
 
             this._tabAnimatedClosedSinceMouseEnter = true;
 
@@ -294,7 +293,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
 
             requestAnimationFrame(animateTabs.bind(this));
         } else
-            this.updateLayoutSoon();
+            this.needsLayout();
 
         this.dispatchEventToListeners(WebInspector.TabBar.Event.TabBarItemRemoved, {tabBarItem});
 
@@ -350,61 +349,6 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
         this.selectedTabBarItem = this._tabBarItems[newIndex];
     }
 
-    updateLayoutSoon()
-    {
-        if (this._updateLayoutIdentifier)
-            return;
-
-        this._needsLayout = true;
-
-        function update()
-        {
-            this._updateLayoutIdentifier = undefined;
-
-            if (this._needsLayout)
-                this.updateLayout();
-        }
-
-        this._updateLayoutIdentifier = requestAnimationFrame(update.bind(this));
-    }
-
-    updateLayout()
-    {
-        if (this._updateLayoutIdentifier) {
-            cancelAnimationFrame(this._updateLayoutIdentifier);
-            this._updateLayoutIdentifier = undefined;
-        }
-
-        if (this._element.classList.contains("static-layout"))
-            return;
-
-        this._needsLayout = false;
-
-        this._element.classList.remove("hide-titles");
-        this._element.classList.remove("collapsed");
-
-        var firstNormalTabItem = null;
-        for (var tabItem of this._tabBarItems) {
-            if (tabItem.pinned)
-                continue;
-            firstNormalTabItem = tabItem;
-            break;
-        }
-
-        if (!firstNormalTabItem)
-            return;
-
-        if (firstNormalTabItem.element.offsetWidth >= 120)
-            return;
-
-        this._element.classList.add("collapsed");
-
-        if (firstNormalTabItem.element.offsetWidth >= 60)
-            return;
-
-        this._element.classList.add("hide-titles");
-    }
-
     get selectedTabBarItem()
     {
         return this._selectedTabBarItem;
@@ -435,14 +379,41 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
         return this._tabBarItems;
     }
 
-    get element()
+    hasNormalTab()
     {
-        return this._element;
+        return this._tabBarItems.some((tab) => !tab.pinned);
     }
 
-    hasNormalTab()
+    // Protected
+
+    layout()
     {
-        return this._tabBarItems.some((tab) => !tab.pinned);
+        if (this.element.classList.contains("static-layout"))
+            return;
+
+        this.element.classList.remove("hide-titles");
+        this.element.classList.remove("collapsed");
+
+        let firstNormalTabItem = null;
+        for (let tabItem of this._tabBarItems) {
+            if (tabItem.pinned)
+                continue;
+            firstNormalTabItem = tabItem;
+            break;
+        }
+
+        if (!firstNormalTabItem)
+            return;
+
+        if (firstNormalTabItem.element.offsetWidth >= 120)
+            return;
+
+        this.element.classList.add("collapsed");
+
+        if (firstNormalTabItem.element.offsetWidth >= 60)
+            return;
+
+        this.element.classList.add("hide-titles");
     }
 
     // Private
@@ -483,7 +454,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
     {
         var tabBarItemSizesAndPositions = new Map;
 
-        var barRect = this._element.getBoundingClientRect();
+        const barRect = this.element.getBoundingClientRect();
 
         for (var tabBarItem of this._tabBarItems) {
             var boundingRect = tabBarItem.element.getBoundingClientRect();
@@ -522,7 +493,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
             if (!beforeTabSizesAndPositions)
                 beforeTabSizesAndPositions = this._recordTabBarItemSizesAndPositions();
 
-            this._element.classList.remove("static-layout");
+            this.element.classList.remove("static-layout");
             this._clearTabBarItemSizesAndPositions();
 
             var afterTabSizesAndPositions = this._recordTabBarItemSizesAndPositions();
@@ -532,26 +503,26 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
 
             function animateTabs()
             {
-                this._element.classList.add("static-layout");
-                this._element.classList.add("animating");
-                this._element.classList.add("expanding-tabs");
+                this.element.classList.add("static-layout");
+                this.element.classList.add("animating");
+                this.element.classList.add("expanding-tabs");
 
                 this._applyTabBarItemSizesAndPositions(afterTabSizesAndPositions);
 
-                this._element.addEventListener("webkitTransitionEnd", removeStylesListener);
+                this.element.addEventListener("webkitTransitionEnd", removeStylesListener);
             }
 
             function removeStyles()
             {
-                this._element.classList.remove("static-layout");
-                this._element.classList.remove("animating");
-                this._element.classList.remove("expanding-tabs");
+                this.element.classList.remove("static-layout");
+                this.element.classList.remove("animating");
+                this.element.classList.remove("expanding-tabs");
 
                 this._clearTabBarItemSizesAndPositions();
 
                 this.updateLayout();
 
-                this._element.removeEventListener("webkitTransitionEnd", removeStylesListener);
+                this.element.removeEventListener("webkitTransitionEnd", removeStylesListener);
 
                 resolve();
             }
@@ -630,7 +601,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
         var closeButtonElement = event.target.enclosingNodeOrSelfWithClass(WebInspector.TabBarItem.CloseButtonStyleClassName);
         if (closeButtonElement || clickedMiddleButton) {
             // Disallow closing the default tab if it is the only tab.
-            if (tabBarItem.isDefaultTab && this._element.classList.contains("single-tab"))
+            if (tabBarItem.isDefaultTab && this.element.classList.contains("single-tab"))
                 return;
 
             this.removeTabBarItem(tabBarItem, false, true);
@@ -651,10 +622,10 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
         event.preventDefault();
         event.stopPropagation();
 
-        if (!this._element.classList.contains("static-layout")) {
+        if (!this.element.classList.contains("static-layout")) {
             this._applyTabBarItemSizesAndPositions(this._recordTabBarItemSizesAndPositions());
-            this._element.classList.add("static-layout");
-            this._element.classList.add("dragging-tab");
+            this.element.classList.add("static-layout");
+            this.element.classList.add("dragging-tab");
         }
 
         if (this._mouseOffset === undefined)
@@ -695,7 +666,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
         var nextSibling = this._tabBarItems[newIndex + 1];
         var nextSiblingElement = nextSibling ? nextSibling.element : (this._newTabItem ? this._newTabItem.element : null);
 
-        this._element.insertBefore(this._selectedTabBarItem.element, nextSiblingElement);
+        this.element.insertBefore(this._selectedTabBarItem.element, nextSiblingElement);
 
         // FIXME: Animate the tabs that move to make room for the selected tab. This was causing me trouble when I tried.
 
@@ -714,10 +685,10 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
         if (!this._mouseIsDown)
             return;
 
-        this._element.classList.remove("dragging-tab");
+        this.element.classList.remove("dragging-tab");
 
         if (!this._tabAnimatedClosedSinceMouseEnter) {
-            this._element.classList.remove("static-layout");
+            this.element.classList.remove("static-layout");
             this._clearTabBarItemSizesAndPositions();
         } else {
             var left = 0;
@@ -745,14 +716,14 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
 
     _handleMouseLeave(event)
     {
-        if (this._mouseIsDown || !this._tabAnimatedClosedSinceMouseEnter || !this._element.classList.contains("static-layout") || this._element.classList.contains("animating"))
+        if (this._mouseIsDown || !this._tabAnimatedClosedSinceMouseEnter || !this.element.classList.contains("static-layout") || this.element.classList.contains("animating"))
             return;
 
         // This event can still fire when the mouse is inside the element if DOM nodes are added, removed or generally change inside.
         // Check if the mouse really did leave the element by checking the bounds.
         // FIXME: Is this a WebKit bug or correct behavior?
-        var barRect = this._element.getBoundingClientRect();
-        var newTabItemRect = this._newTabItem ? this._newTabItem.element.getBoundingClientRect() : null;
+        const barRect = this.element.getBoundingClientRect();
+        const newTabItemRect = this._newTabItem ? this._newTabItem.element.getBoundingClientRect() : null;
         if (event.pageY > barRect.top && event.pageY < barRect.bottom && event.pageX > barRect.left && event.pageX < (newTabItemRect ? newTabItemRect.right : barRect.right))
             return;
 
@@ -768,7 +739,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.Object
 
     _handleNewTabMouseEnter(event)
     {
-        if (!this._tabAnimatedClosedSinceMouseEnter || !this._element.classList.contains("static-layout") || this._element.classList.contains("animating"))
+        if (!this._tabAnimatedClosedSinceMouseEnter || !this.element.classList.contains("static-layout") || this.element.classList.contains("animating"))
             return;
 
         this._finishExpandingTabsAfterClose();
index 28ba939..6e0602b 100644 (file)
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.TabBrowser = class TabBrowser extends WebInspector.Object
+WebInspector.TabBrowser = class TabBrowser extends WebInspector.View
 {
     constructor(element, tabBar, navigationSidebar, detailsSidebar)
     {
-        super();
+        console.assert(tabBar, "Must provide a TabBar.");
 
-        this._element = element || document.createElement("div");
-        this._element.classList.add("tab-browser");
+        super(element);
 
-        this._tabBar = tabBar || new WebInspector.TabBar;
-        if (!tabBar)
-            this._element.appendChild(this._tabBar.element);
+        this.element.classList.add("tab-browser");
 
+        this._tabBar = tabBar;
         this._navigationSidebar = navigationSidebar || null;
         this._detailsSidebar = detailsSidebar || null;
 
@@ -48,7 +46,7 @@ WebInspector.TabBrowser = class TabBrowser extends WebInspector.Object
         }
 
         this._contentViewContainer = new WebInspector.ContentViewContainer;
-        this._element.appendChild(this._contentViewContainer.element);
+        this.addSubview(this._contentViewContainer);
 
         var showNextTab = this._showNextTab.bind(this);
         var showPreviousTab = this._showPreviousTab.bind(this);
@@ -73,11 +71,6 @@ WebInspector.TabBrowser = class TabBrowser extends WebInspector.Object
 
     // Public
 
-    get element()
-    {
-        return this._element;
-    }
-
     get tabBar()
     {
         return this._tabBar;
@@ -98,12 +91,6 @@ WebInspector.TabBrowser = class TabBrowser extends WebInspector.Object
         return this._contentViewContainer.currentContentView;
     }
 
-    updateLayout()
-    {
-        this._tabBar.updateLayout();
-        this._contentViewContainer.updateLayout();
-    }
-
     bestTabContentViewForClass(constructor)
     {
         console.assert(!this.selectedTabContentView || this.selectedTabContentView === this._recentTabContentViews[0]);
index 7a00dca..f556622 100644 (file)
@@ -172,26 +172,18 @@ WebInspector.TimelineView = class TimelineView extends WebInspector.ContentView
         return true;
     }
 
-    updateLayout()
+    filterUpdated()
     {
-        if (this._scheduledLayoutUpdateIdentifier) {
-            cancelAnimationFrame(this._scheduledLayoutUpdateIdentifier);
-            this._scheduledLayoutUpdateIdentifier = undefined;
-        }
-
-        // Implemented by sub-classes if needed.
+        this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
     }
 
-    updateLayoutIfNeeded()
+    needsLayout()
     {
-        if (!this._scheduledLayoutUpdateIdentifier)
+        // FIXME: needsLayout can be removed once <https://webkit.org/b/150741> is fixed.
+        if (!this.visible)
             return;
-        this.updateLayout();
-    }
 
-    filterUpdated()
-    {
-        this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
+        super.needsLayout();
     }
 
     // Protected
@@ -247,15 +239,4 @@ WebInspector.TimelineView = class TimelineView extends WebInspector.ContentView
 
         this.showContentViewForTreeElement(treeElement);
     }
-
-    needsLayout()
-    {
-        if (!this.visible)
-            return;
-
-        if (this._scheduledLayoutUpdateIdentifier)
-            return;
-
-        this._scheduledLayoutUpdateIdentifier = requestAnimationFrame(this.updateLayout.bind(this));
-    }
 };
index 213e320..4a5f76f 100644 (file)
@@ -34,30 +34,30 @@ WebInspector.Toolbar = class Toolbar extends WebInspector.NavigationBar
 
         this._controlSectionElement = document.createElement("div");
         this._controlSectionElement.className = WebInspector.Toolbar.ControlSectionStyleClassName;
-        this._element.appendChild(this._controlSectionElement);
+        this.element.appendChild(this._controlSectionElement);
 
         this._leftSectionElement = document.createElement("div");
         this._leftSectionElement.className = WebInspector.Toolbar.ItemSectionStyleClassName + " " + WebInspector.Toolbar.LeftItemSectionStyleClassName;
-        this._element.appendChild(this._leftSectionElement);
+        this.element.appendChild(this._leftSectionElement);
 
         this._centerLeftSectionElement = document.createElement("div");
         this._centerLeftSectionElement.className = WebInspector.Toolbar.ItemSectionStyleClassName + " " + WebInspector.Toolbar.CenterLeftItemSectionStyleClassName;
-        this._element.appendChild(this._centerLeftSectionElement);
+        this.element.appendChild(this._centerLeftSectionElement);
 
         this._centerSectionElement = document.createElement("div");
         this._centerSectionElement.className = WebInspector.Toolbar.ItemSectionStyleClassName + " " + WebInspector.Toolbar.CenterItemSectionStyleClassName;
-        this._element.appendChild(this._centerSectionElement);
+        this.element.appendChild(this._centerSectionElement);
 
         this._centerRightSectionElement = document.createElement("div");
         this._centerRightSectionElement.className = WebInspector.Toolbar.ItemSectionStyleClassName + " " + WebInspector.Toolbar.CenterRightItemSectionStyleClassName;
-        this._element.appendChild(this._centerRightSectionElement);
+        this.element.appendChild(this._centerRightSectionElement);
 
         this._rightSectionElement = document.createElement("div");
         this._rightSectionElement.className = WebInspector.Toolbar.ItemSectionStyleClassName + " " + WebInspector.Toolbar.RightItemSectionStyleClassName;
-        this._element.appendChild(this._rightSectionElement);
+        this.element.appendChild(this._rightSectionElement);
 
         if (!dontAllowModeChanges)
-            this._element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false);
+            this.element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false);
     }
 
     // Public
@@ -73,15 +73,15 @@ WebInspector.Toolbar = class Toolbar extends WebInspector.NavigationBar
             return;
 
         if (this._displayMode)
-            this._element.classList.remove(this._displayMode);
+            this.element.classList.remove(this._displayMode);
 
         // Revert the forced icon-only mode if it was applied.
         if (this._displayMode === WebInspector.Toolbar.DisplayMode.IconAndLabelHorizontal)
-            this._element.classList.remove(WebInspector.Toolbar.DisplayMode.IconOnly);
+            this.element.classList.remove(WebInspector.Toolbar.DisplayMode.IconOnly);
 
         this._displayMode = mode;
 
-        this._element.classList.add(mode);
+        this.element.classList.add(mode);
 
         this.updateLayout();
 
@@ -99,18 +99,56 @@ WebInspector.Toolbar = class Toolbar extends WebInspector.NavigationBar
             return;
 
         if (this._sizeMode)
-            this._element.classList.remove(this._sizeMode);
+            this.element.classList.remove(this._sizeMode);
 
         this._sizeMode = mode;
 
-        this._element.classList.add(mode);
+        this.element.classList.add(mode);
 
         this.updateLayout();
 
         this.dispatchEventToListeners(WebInspector.Toolbar.Event.SizeModeDidChange);
     }
 
-    customUpdateLayout()
+    addToolbarItem(toolbarItem, sectionIdentifier)
+    {
+        var sectionElement;
+
+        switch (sectionIdentifier) {
+        case WebInspector.Toolbar.Section.Control:
+            sectionElement = this._controlSectionElement;
+            break;
+
+        case WebInspector.Toolbar.Section.Left:
+            sectionElement = this._leftSectionElement;
+            break;
+
+        case WebInspector.Toolbar.Section.CenterLeft:
+            sectionElement = this._centerLeftSectionElement;
+            break;
+
+        default:
+        case WebInspector.Toolbar.Section.Center:
+            sectionElement = this._centerSectionElement;
+            break;
+
+        case WebInspector.Toolbar.Section.CenterRight:
+            sectionElement = this._centerRightSectionElement;
+            break;
+
+        case WebInspector.Toolbar.Section.Right:
+            sectionElement = this._rightSectionElement;
+            break;
+        }
+
+        console.assert(sectionElement);
+
+        this.addNavigationItem(toolbarItem, sectionElement);
+    }
+
+    // Protected
+
+    layout()
     {
         // Bail early if our sections are not created yet. This means we are being called during construction.
         if (!this._leftSectionElement || !this._centerSectionElement || !this._rightSectionElement)
@@ -118,17 +156,17 @@ WebInspector.Toolbar = class Toolbar extends WebInspector.NavigationBar
 
         // Force collapsed style for JavaScript debuggables.
         if (WebInspector.debuggableType === WebInspector.DebuggableType.JavaScript) {
-            this._element.classList.add(WebInspector.NavigationBar.CollapsedStyleClassName);
+            this.element.classList.add(WebInspector.NavigationBar.CollapsedStyleClassName);
             return;
         }
 
         // Remove the collapsed style class to test if the items can fit at full width.
-        this._element.classList.remove(WebInspector.NavigationBar.CollapsedStyleClassName);
+        this.element.classList.remove(WebInspector.NavigationBar.CollapsedStyleClassName);
 
         // Revert the forced icon-only mode if it was applied.
         if (this._displayMode === WebInspector.Toolbar.DisplayMode.IconAndLabelHorizontal) {
-            this._element.classList.remove(WebInspector.Toolbar.DisplayMode.IconOnly);
-            this._element.classList.add(WebInspector.Toolbar.DisplayMode.IconAndLabelHorizontal);
+            this.element.classList.remove(WebInspector.Toolbar.DisplayMode.IconOnly);
+            this.element.classList.add(WebInspector.Toolbar.DisplayMode.IconAndLabelHorizontal);
         }
 
         function isOverflowingToolbar()
@@ -147,50 +185,14 @@ WebInspector.Toolbar = class Toolbar extends WebInspector.NavigationBar
         // Only the horizontal display mode supports collapsing labels.
         // If any sections are overflowing the toolbar then force the display mode to be icon only.
         if (this._displayMode === WebInspector.Toolbar.DisplayMode.IconAndLabelHorizontal && isOverflowingToolbar.call(this)) {
-            this._element.classList.remove(WebInspector.Toolbar.DisplayMode.IconAndLabelHorizontal);
-            this._element.classList.add(WebInspector.Toolbar.DisplayMode.IconOnly);
+            this.element.classList.remove(WebInspector.Toolbar.DisplayMode.IconAndLabelHorizontal);
+            this.element.classList.add(WebInspector.Toolbar.DisplayMode.IconOnly);
         }
 
         if (!isOverflowingToolbar.call(this))
             return;
 
-        this._element.classList.add(WebInspector.NavigationBar.CollapsedStyleClassName);
-    }
-
-    addToolbarItem(toolbarItem, sectionIdentifier)
-    {
-        var sectionElement;
-
-        switch (sectionIdentifier) {
-        case WebInspector.Toolbar.Section.Control:
-            sectionElement = this._controlSectionElement;
-            break;
-
-        case WebInspector.Toolbar.Section.Left:
-            sectionElement = this._leftSectionElement;
-            break;
-
-        case WebInspector.Toolbar.Section.CenterLeft:
-            sectionElement = this._centerLeftSectionElement;
-            break;
-
-        default:
-        case WebInspector.Toolbar.Section.Center:
-            sectionElement = this._centerSectionElement;
-            break;
-
-        case WebInspector.Toolbar.Section.CenterRight:
-            sectionElement = this._centerRightSectionElement;
-            break;
-
-        case WebInspector.Toolbar.Section.Right:
-            sectionElement = this._rightSectionElement;
-            break;
-        }
-
-        console.assert(sectionElement);
-
-        this.addNavigationItem(toolbarItem, sectionElement);
+        this.element.classList.add(WebInspector.NavigationBar.CollapsedStyleClassName);
     }
 
     // Private
diff --git a/Source/WebInspectorUI/UserInterface/Views/View.js b/Source/WebInspectorUI/UserInterface/Views/View.js
new file mode 100644 (file)
index 0000000..87ff93e
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+WebInspector.View = class View extends WebInspector.Object
+{
+    constructor(element)
+    {
+        super();
+
+        this._element = element || document.createElement("div");
+        this._element.__view = this;
+        this._subviews = [];
+    }
+
+    // Public
+
+    get element()
+    {
+        return this._element;
+    }
+
+    get subviews()
+    {
+        return this._subviews;
+    }
+
+    addSubview(view)
+    {
+        this.insertSubviewBefore(view, null);
+    }
+
+    insertSubviewBefore(view, referenceView)
+    {
+        console.assert(view instanceof WebInspector.View);
+        console.assert(!referenceView || referenceView instanceof WebInspector.View);
+
+        if (this._subviews.includes(view)) {
+            console.assert(false, "Cannot add view that is already a subview.", view);
+            return;
+        }
+
+        const beforeIndex = referenceView ? this._subviews.indexOf(referenceView) : this._subviews.length;
+        if (beforeIndex === -1) {
+            console.assert(false, "Cannot insert view. Invalid reference view.", referenceView);
+            return;
+        }
+
+        this._subviews.insertAtIndex(view, beforeIndex);
+        this._element.insertBefore(view.element, referenceView ? referenceView.element : null);
+    }
+
+    removeSubview(view)
+    {
+        console.assert(view instanceof WebInspector.View);
+        console.assert(view.element.parentNode === this._element, "Subview DOM element must be a child of the parent view element.");
+
+        if (!this._subviews.includes(view)) {
+            console.assert(false, "Cannot remove view which isn't a subview.", view);
+            return;
+        }
+
+        this._subviews.remove(view, true);
+        this._element.removeChild(view.element);
+    }
+
+    replaceSubview(oldView, newView)
+    {
+        console.assert(oldView !== newView, "Cannot replace subview with itself.");
+
+        this.insertSubviewBefore(newView, oldView);
+        this.removeSubview(oldView);
+    }
+
+    updateLayout()
+    {
+        this._layoutSubtree();
+    }
+
+    updateLayoutIfNeeded()
+    {
+        if (!this._scheduledLayoutUpdateIdentifier)
+            return;
+
+        this.updateLayout();
+    }
+
+    needsLayout()
+    {
+        if (this._scheduledLayoutUpdateIdentifier)
+            return;
+
+        this._scheduledLayoutUpdateIdentifier = requestAnimationFrame(() => {
+            this._scheduledLayoutUpdateIdentifier = undefined;
+            this._layoutSubtree();
+        });
+    }
+
+    // Protected
+
+    layout()
+    {
+        // Overridden by subclasses.
+        // Not responsible for recursing to child views.
+        // Should not be called directly; use updateLayout() instead.
+    }
+
+    // Private
+
+    _layoutSubtree()
+    {
+        if (this._scheduledLayoutUpdateIdentifier) {
+            cancelAnimationFrame(this._scheduledLayoutUpdateIdentifier);
+            this._scheduledLayoutUpdateIdentifier = undefined;
+        }
+
+        this.layout();
+
+        for (let view of this._subviews)
+            view._layoutSubtree();
+    }
+};