diff options
author | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-02 18:28:52 +0000 |
---|---|---|
committer | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-02 18:28:52 +0000 |
commit | daac7521c5e097c788aed05258228ce7d81c8bb4 (patch) | |
tree | acc814b017eb9ec0ddb9fbfd4cebbeb96aba1cf6 | |
parent | 4da9faca3b8cb8687017ca4acc9c1164964062ad (diff) | |
download | chromium_src-daac7521c5e097c788aed05258228ce7d81c8bb4.zip chromium_src-daac7521c5e097c788aed05258228ce7d81c8bb4.tar.gz chromium_src-daac7521c5e097c788aed05258228ce7d81c8bb4.tar.bz2 |
Add extra views to the new net internals page. This adds tabs along the top for proxy, dns, sockets, requests, and http cache subsections. The actual subviews are placeholders.
BUG=37421
Review URL: http://codereview.chromium.org/1593009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@43502 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/resources/net_internals/detailsview.js | 139 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/index.html | 41 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/layoutmanager.js | 151 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/main.css | 55 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/main.js | 57 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/requestsview.js | 58 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/resizableverticalsplitview.js | 125 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/tabswitcherview.js | 141 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/topmidbottomview.js | 59 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/util.js | 18 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/view.js | 130 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 5 |
12 files changed, 737 insertions, 242 deletions
diff --git a/chrome/browser/resources/net_internals/detailsview.js b/chrome/browser/resources/net_internals/detailsview.js index 271c19f..847d94b 100644 --- a/chrome/browser/resources/net_internals/detailsview.js +++ b/chrome/browser/resources/net_internals/detailsview.js @@ -9,85 +9,118 @@ * * @constructor */ -function DetailsView(logTabHandleId, - timelineTabHandleId, - detailsTabContentId) { - // The DOM nodes that which contain the tab title. - this.tabHandles_ = {}; +function DetailsView(tabHandlesContainerId, + logTabId, + timelineTabId, + logBoxId, + timelineBoxId) { + TabSwitcherView.call(this, new DivView(tabHandlesContainerId)); - this.tabHandles_['timeline'] = document.getElementById(timelineTabHandleId); - this.tabHandles_['log'] = document.getElementById(logTabHandleId); + this.logView_ = new DetailsLogView(logBoxId); + this.timelineView_ = new DetailsTimelineView(timelineBoxId); - // The DOM node that contains the currently active tab sheet. - this.contentArea_ = document.getElementById(detailsTabContentId); - - // Attach listeners to the "tab handles" so when you click them, it switches - // active view. - - var self = this; - - this.tabHandles_['timeline'].onclick = function() { - self.switchToView_('timeline'); - }; - - this.tabHandles_['log'].onclick = function() { - self.switchToView_('log'); - }; - - this.currentData_ = []; + this.addTab(logTabId, this.logView_); + this.addTab(timelineTabId, this.timelineView_); // Default to the log view. - this.switchToView_('log'); + this.switchToTab(logTabId); }; +inherits(DetailsView, TabSwitcherView); + // The delay between updates to repaint. DetailsView.REPAINT_TIMEOUT_MS = 50; /** - * Switches to the tab with name |viewName|. (Either 'log' or 'timeline'. + * Updates the data this view is using. */ -DetailsView.prototype.switchToView_ = function(viewName) { - if (this.currentView_) { - // Remove the selected styling on currently selected tab. - changeClassName(this.tabHandles_[this.currentView_], 'selected', false); - } +DetailsView.prototype.setData = function(currentData) { + // Make a copy of the array (in case the caller mutates it), and sort it + // by the source ID. + var sortedCurrentData = DetailsView.createSortedCopy_(currentData); - this.currentView_ = viewName; - changeClassName(this.tabHandles_[this.currentView_], 'selected', true); - this.repaint_(); + for (var i = 0; i < this.tabs_.length; ++i) + this.tabs_[i].contentView.setData(sortedCurrentData); }; +DetailsView.createSortedCopy_ = function(origArray) { + var sortedArray = origArray.slice(0); + sortedArray.sort(function(a, b) { + return a.getSourceId() - b.getSourceId(); + }); + return sortedArray; +}; + +//----------------------------------------------------------------------------- + /** - * Updates the data this view is using. + * Base class for the Log view and Timeline view. + * + * @constructor */ -DetailsView.prototype.setData = function(currentData) { - // Make a copy of the array (in case the caller mutates it), and sort it - // by the source ID. - this.currentData_ = DetailsView.createSortedCopy_(currentData); +function DetailsSubView(boxId) { + DivView.call(this, boxId); + this.sourceEntries_ = []; +} + +inherits(DetailsSubView, DivView); - // Invalidate the view. - if (!this.outstandingRepaint_) { +DetailsSubView.prototype.setData = function(sourceEntries) { + this.sourceEntries_ = sourceEntries; + + // Repaint the view. + if (this.isVisible() && !this.outstandingRepaint_) { this.outstandingRepaint_ = true; - window.setTimeout(this.repaint_.bind(this), + window.setTimeout(this.repaint.bind(this), DetailsView.REPAINT_TIMEOUT_MS); } }; -DetailsView.prototype.repaint_ = function() { +DetailsSubView.prototype.repaint = function() { this.outstandingRepaint_ = false; - this.contentArea_.innerHTML = ''; + this.getNode().innerHTML = ''; +}; - if (this.currentView_ == 'log') { - PaintLogView(this.currentData_, this.contentArea_); +DetailsSubView.prototype.show = function(isVisible) { + DetailsSubView.superClass_.show.call(this, isVisible); + if (isVisible) { + this.repaint(); } else { - PaintTimelineView(this.currentData_, this.contentArea_); + this.getNode().innerHTML = ''; } }; -DetailsView.createSortedCopy_ = function(origArray) { - var sortedArray = origArray.slice(0); - sortedArray.sort(function(a, b) { - return a.getSourceId() - b.getSourceId(); - }); - return sortedArray; +//----------------------------------------------------------------------------- + + +/** + * Subview that is displayed in the log tab. + * @constructor + */ +function DetailsLogView(boxId) { + DetailsSubView.call(this, boxId); +} + +inherits(DetailsLogView, DetailsSubView); + +DetailsLogView.prototype.repaint = function() { + DetailsLogView.superClass_.repaint.call(this); + PaintLogView(this.sourceEntries_, this.getNode()); +}; + +//----------------------------------------------------------------------------- + +/** + * Subview that is displayed in the timeline tab. + * @constructor + */ +function DetailsTimelineView(boxId) { + DetailsSubView.call(this, boxId); +} + +inherits(DetailsTimelineView, DetailsSubView); + +DetailsTimelineView.prototype.repaint = function() { + DetailsTimelineView.superClass_.repaint.call(this); + PaintTimelineView(this.sourceEntries_, this.getNode()); }; diff --git a/chrome/browser/resources/net_internals/index.html b/chrome/browser/resources/net_internals/index.html index fab3304..fb7ff9a 100644 --- a/chrome/browser/resources/net_internals/index.html +++ b/chrome/browser/resources/net_internals/index.html @@ -6,20 +6,42 @@ found in the LICENSE file. --> <head> <link tyle="text/css" rel="stylesheet" href="main.css" /> - <script src="main.js"></script> <script src="util.js"></script> + <script src="view.js"></script> + <script src="tabswitcherview.js"></script> + <script src="main.js"></script> <script src="requestsview.js"></script> <script src="detailsview.js"></script> <script src="sourceentry.js"></script> - <script src="layoutmanager.js"></script> + <script src="resizableverticalsplitview.js"></script> + <script src="topmidbottomview.js"></script> <script src="timelineviewpainter.js"></script> <script src="logviewpainter.js"></script> <script src="loggrouper.js"></script> </head> <body onload="onLoaded()"> + <!-- Tab switcher for main categories. --> + <div id=categoryTabHandles> + <ul> + <li><a href="#" id=proxyTab>Proxy</a></li> + <li><a href="#" id=requestsTab>Requests</a></li> + <li><a href="#" id=dnsTab>DNS</a></li> + <li><a href="#" id=socketsTab>Sockets</a></li> + <li><a href="#" id=httpCacheTab>HTTP Cache</a></li> + </ul> + <div style="clear: both;"></div> + </div> + <!-- Sections TODO --> + <div id=proxyTabContent>TODO: display proxy information (PAC error log, initialization log, current settings.)</div> + <div id=dnsTabContent>TODO: display dns information (outstanding jobs, host cache).</div> + <div id=socketsTabContent>TODO: display socket information (outstanding connect jobs)</div> + <div id=httpCacheTabContent>TODO: display http cache information (disk cache navigator)</div> + + <!-- ================= Requests view =================== --> + <!-- Filter Box: This the top bar which contains the search box. --> <div id=filterBox> - <table width=100% height=100%> + <table width=100%> <tr> <td width=1%>Filter:</td> <td width=98%><input type="search" incremental id=filterInput /></td> @@ -29,13 +51,13 @@ found in the LICENSE file. </div> <!-- Requests Box: This the panel on the left which lists the requests --> <div id=requestsBox> - <table id=requestsListTable cellspacing=0 cellpadding=0> + <table id=requestsListTable cellspacing=0 cellpadding=0 width=100%> <thead> <tr> <td><input type=checkbox id=selectAll /></td> <td>ID</td> <td>Source</td> - <td>URL</td> + <td width=99%>URL</td> </tr> </thead> <!-- Requests table body: This is where request rows go into --> @@ -50,16 +72,17 @@ found in the LICENSE file. <!-- Splitter Box: This is a handle to resize the vertical divider --> <div id=splitterBox></div> <!-- Details box: This is the panel on the right which shows information --> - <div id=detailsBox> + <div id=detailsTabHandles> <table class=tabSwitcher cellspacing=0> <tr> - <th id=detailsLogTabHandle>Log</th> + <th id=detailsLogTab>Log</th> <td class=tabSwitcherSpacer> </td> - <th id=detailsTimelineTabHandle>Timeline</th> + <th id=detailsTimelineTab>Timeline</th> </tr> </table> <div class=tabSwitcherLine></div> - <div id=detailsTabArea></div> </div> + <div id=detailsLogBox></div> + <div id=detailsTimelineBox></div> </body> </html> diff --git a/chrome/browser/resources/net_internals/layoutmanager.js b/chrome/browser/resources/net_internals/layoutmanager.js deleted file mode 100644 index 0491a63..0000000 --- a/chrome/browser/resources/net_internals/layoutmanager.js +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * The class LayoutManager implements a vertically split layout that takes up - * the whole window, and provides a draggable bar to resize the left and right - * panes. Its elements are layed out as follows: - * - * - * <<-- sizer -->> - * - * +----------------------++----------------+ - * | topbar || | - * +----------------------+| | - * | || | - * | || | - * | || | - * | || | - * | middlebox || rightbox | - * | || | - * | || | - * | || | - * | || | - * | || | - * +----------------------++ | - * | bottombar || | - * +----------------------++----------------+ - * - * The "topbar" and "bottombar" have a fixed height which is determined - * by their initial content height. The rest of the boxes fill to occupy the - * remaining space. - * - * The consumer provides DIVs for each of these regions, and the LayoutManager - * positions them correctly in the window. - * - * @constructor - */ -function LayoutManager(topbarId, - middleboxId, - bottombarId, - sizerId, - rightboxId) { - // Lookup the elements. - this.topbar_ = document.getElementById(topbarId); - this.middlebox_ = document.getElementById(middleboxId); - this.bottombar_ = document.getElementById(bottombarId); - this.sizer_ = document.getElementById(sizerId); - this.rightbox_ = document.getElementById(rightboxId); - - // Make all the elements absolutely positioned. - this.topbar_.style.position = "absolute"; - this.middlebox_.style.position = "absolute"; - this.bottombar_.style.position = "absolute"; - this.sizer_.style.position = "absolute"; - this.rightbox_.style.position = "absolute"; - - // Set the initial split position at 50%. - setNodeWidth(this.rightbox_, window.innerWidth / 2); - - // Setup the "sizer" so it can be dragged left/right to reposition the - // vertical split. - this.sizer_.addEventListener("mousedown", this.onDragSizerStart_.bind(this), - true); - - // Recalculate the layout whenever the window size changes. - window.addEventListener("resize", this.recalculateLayout_.bind(this), true); - - // Do the initial layout . - this.recalculateLayout_(); -} - -// Minimum width to size panels to, in pixels. -LayoutManager.MIN_PANEL_WIDTH = 50; - -/** - * Repositions all of the elements to fit the window. - */ -LayoutManager.prototype.recalculateLayout_ = function() { - // Calculate the horizontal split points. - var totalWidth = window.innerWidth; - var rightboxWidth = this.rightbox_.offsetWidth; - var sizerWidth = this.sizer_.offsetWidth; - var leftPaneWidth = totalWidth - (rightboxWidth + sizerWidth); - - // Don't let the left pane get too small. - if (leftPaneWidth < LayoutManager.MIN_PANEL_WIDTH) { - leftPaneWidth = LayoutManager.MIN_PANEL_WIDTH; - rightboxWidth = totalWidth - (sizerWidth + leftPaneWidth); - } - - // Calculate the vertical split points. - var totalHeight = window.innerHeight; - var topbarHeight = this.topbar_.offsetHeight; - var bottombarHeight = this.bottombar_.offsetHeight; - var middleboxHeight = totalHeight - (topbarHeight + bottombarHeight); - - // Position the boxes using calculated split points. - setNodePosition(this.topbar_, 0, 0, - leftPaneWidth, topbarHeight); - setNodePosition(this.middlebox_, 0, topbarHeight, - leftPaneWidth, - middleboxHeight); - setNodePosition(this.bottombar_, 0, (topbarHeight + middleboxHeight), - leftPaneWidth, bottombarHeight); - - setNodePosition(this.sizer_, leftPaneWidth, 0, - sizerWidth, totalHeight); - setNodePosition(this.rightbox_, leftPaneWidth + sizerWidth, 0, - rightboxWidth, totalHeight); -}; - -/** - * Called once we have clicked into the sizer. Starts capturing the mouse - * position to implement dragging. - */ -LayoutManager.prototype.onDragSizerStart_ = function(event) { - this.sizerMouseMoveListener_ = this.onDragSizer.bind(this); - this.sizerMouseUpListener_ = this.onDragSizerEnd.bind(this); - - window.addEventListener("mousemove", this.sizerMouseMoveListener_, true); - window.addEventListener("mouseup", this.sizerMouseUpListener_, true); - - event.preventDefault(); -}; - -/** - * Called when the mouse has moved after dragging started. - */ -LayoutManager.prototype.onDragSizer = function(event) { - var newWidth = window.innerWidth - event.pageX; - - // Avoid shrinking the right box too much. - newWidth = Math.max(newWidth, LayoutManager.MIN_PANEL_WIDTH); - - setNodeWidth(this.rightbox_, newWidth); - this.recalculateLayout_(); -}; - -/** - * Called once the mouse has been released, and the dragging is over. - */ -LayoutManager.prototype.onDragSizerEnd = function(event) { - window.removeEventListener("mousemove", this.sizerMouseMoveListener_, true); - window.removeEventListener("mouseup", this.sizerMouseUpListener_, true); - - this.sizerMouseMoveListener_ = null; - this.sizerMouseUpListener_ = null; - - event.preventDefault(); -}; diff --git a/chrome/browser/resources/net_internals/main.css b/chrome/browser/resources/net_internals/main.css index e6d6437..cc87520 100644 --- a/chrome/browser/resources/net_internals/main.css +++ b/chrome/browser/resources/net_internals/main.css @@ -6,6 +6,7 @@ found in the LICENSE file. * { -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; } body { font-family: sans-serif; @@ -116,8 +117,8 @@ body { height: 10px; } -#detailsTabArea { - margin-top: 10px; +#detailsTabHandles { + border: 1px solid white; } .logSourceEntry { @@ -132,3 +133,53 @@ body { .logSourceEntry * td { font-size: 10px; } + +#categoryTabHandles ul { + list-style: none; + padding: 0; + margin: 0; +} + +#categoryTabHandles { + border-bottom: 1px solid #555; + background: #aaa; +} + +#categoryTabHandles li { + float: left; + margin-left: 5px; +} + +#categoryTabHandles a { + text-decoration: none; + text-align: center; + display: block; + width: 9em; + padding: 5px; + background: #ccc; +} + +#categoryTabHandles a:hover { + background: #eee; +} + +#categoryTabHandles a:visited, +#categoryTabHandles a { + color: blue; +} + +#categoryTabHandles .selected { + background: white; +} + +#categoryTabHandles a.selected { + position:relative; + top: 1px; + font-weight: bold; + color: black; +} + +#detailsLogBox, +#detailsTimelineBox { + overflow: auto; +} diff --git a/chrome/browser/resources/net_internals/main.js b/chrome/browser/resources/net_internals/main.js index b23d71f..7b9d3c9 100644 --- a/chrome/browser/resources/net_internals/main.js +++ b/chrome/browser/resources/net_internals/main.js @@ -14,26 +14,47 @@ var LogSourceType = null; * Main entry point. called once the page has loaded. */ function onLoaded() { - // Layout the various DIVs in a vertically split fashion. - new LayoutManager("filterBox", - "requestsBox", - "actionBox", - "splitterBox", - "detailsBox"); - - // Create the view which displays information on the current selection. - var detailsView = new DetailsView("detailsLogTabHandle", - "detailsTimelineTabHandle", - "detailsTabArea"); - // Create the view which displays requests lists, and lets you select, filter // and delete them. - new RequestsView('requestsListTableBody', - 'filterInput', - 'filterCount', - 'deleteSelected', - 'selectAll', - detailsView); + var requestsView = new RequestsView('requestsListTableBody', + 'filterInput', + 'filterCount', + 'deleteSelected', + 'selectAll', + + // IDs for the details view. + "detailsTabHandles", + "detailsLogTab", + "detailsTimelineTab", + "detailsLogBox", + "detailsTimelineBox", + + // IDs for the layout boxes. + "filterBox", + "requestsBox", + "actionBox", + "splitterBox"); + + // Create a view which lets you tab between the different sub-views. + var categoryTabSwitcher = + new TabSwitcherView(new DivView('categoryTabHandles')); + + // Populate the main tabs. + categoryTabSwitcher.addTab('requestsTab', requestsView); + categoryTabSwitcher.addTab('proxyTab', new DivView('proxyTabContent')); + categoryTabSwitcher.addTab('dnsTab', new DivView('dnsTabContent')); + categoryTabSwitcher.addTab('socketsTab', new DivView('socketsTabContent')); + categoryTabSwitcher.addTab('httpCacheTab', + new DivView('httpCacheTabContent')); + + // Select the requests tab as the default. + categoryTabSwitcher.switchToTab('requestsTab'); + + // Make this category tab widget the primary view, that fills the whole page. + var windowView = new WindowView(categoryTabSwitcher); + + // Trigger initial layout. + windowView.resetGeometry(); // Tell the browser that we are ready to start receiving log events. notifyApplicationReady(); diff --git a/chrome/browser/resources/net_internals/requestsview.js b/chrome/browser/resources/net_internals/requestsview.js index 40707a4..16b39b9 100644 --- a/chrome/browser/resources/net_internals/requestsview.js +++ b/chrome/browser/resources/net_internals/requestsview.js @@ -3,25 +3,55 @@ // found in the LICENSE file. /** - * RequestsView is the class which glues together the different components to - * form the primary UI: + * RequestsView displays a filtered list of all the requests, and a details + * pane for the selected requests. * - * - The search filter - * - The requests table - * - The details panel - * - The action bar + * +----------------------++----------------+ + * | filter box || | + * +----------------------+| | + * | || | + * | || | + * | || | + * | || | + * | requests list || details | + * | || view | + * | || | + * | || | + * | || | + * | || | + * +----------------------++ | + * | action bar || | + * +----------------------++----------------+ * * @constructor */ function RequestsView(tableBodyId, filterInputId, filterCountId, - deleteSelectedId, selectAllId, detailsView) { + deleteSelectedId, selectAllId, + tabHandlesContainerId, logTabId, timelineTabId, + detailsLogBoxId, detailsTimelineBoxId, + topbarId, middleboxId, bottombarId, sizerId) { + View.call(this); + + // Initialize the sub-views. + var leftPane = new TopMidBottomView(new DivView(topbarId), + new DivView(middleboxId), + new DivView(bottombarId)); + + this.detailsView_ = new DetailsView(tabHandlesContainerId, + logTabId, + timelineTabId, + detailsLogBoxId, + detailsTimelineBoxId); + + this.splitterView_ = new ResizableVerticalSplitView( + leftPane, this.detailsView_, new DivView(sizerId)); + this.sourceIdToEntryMap_ = {}; this.currentSelectedSources_ = []; LogDataProvider.addObserver(this); this.tableBody_ = document.getElementById(tableBodyId); - this.detailsView_ = detailsView; this.filterInput_ = document.getElementById(filterInputId); this.filterCount_ = document.getElementById(filterCountId); @@ -43,9 +73,21 @@ function RequestsView(tableBodyId, filterInputId, filterCountId, this.invalidateDetailsView_(); } +inherits(RequestsView, View); + // How soon after updating the filter list the counter should be updated. RequestsView.REPAINT_FILTER_COUNTER_TIMEOUT_MS = 0; +RequestsView.prototype.setGeometry = function(left, top, width, height) { + RequestsView.superClass_.setGeometry.call(this, left, top, width, height); + this.splitterView_.setGeometry(left, top, width, height); +}; + +RequestsView.prototype.show = function(isVisible) { + RequestsView.superClass_.show.call(this, isVisible); + this.splitterView_.show(isVisible); +}; + RequestsView.prototype.onFilterTextChanged_ = function() { this.setFilter_(this.filterInput_.value); }; diff --git a/chrome/browser/resources/net_internals/resizableverticalsplitview.js b/chrome/browser/resources/net_internals/resizableverticalsplitview.js new file mode 100644 index 0000000..78b62a0 --- /dev/null +++ b/chrome/browser/resources/net_internals/resizableverticalsplitview.js @@ -0,0 +1,125 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * This view implements a vertically split display with a draggable divider. + * + * <<-- sizer -->> + * + * +----------------------++----------------+ + * | || | + * | || | + * | || | + * | || | + * | leftView || rightView | + * | || | + * | || | + * | || | + * | || | + * | || | + * +----------------------++----------------+ + * + * @param {!View} leftView The widget to position on the left. + * @param {!View} rightView The widget to position on the right. + * @param {!DivView} sizerView The widget that will serve as draggable divider. + * @constructor + */ +function ResizableVerticalSplitView(leftView, rightView, sizerView) { + View.call(this); + + this.leftView_ = leftView; + this.rightView_ = rightView; + this.sizerView_ = sizerView; + + // Setup the "sizer" so it can be dragged left/right to reposition the + // vertical split. + sizerView.getNode().addEventListener( + "mousedown", this.onDragSizerStart_.bind(this), true); +} + +inherits(ResizableVerticalSplitView, View); + +// Minimum width to size panels to, in pixels. +ResizableVerticalSplitView.MIN_PANEL_WIDTH = 50; + +/** + * Repositions all of the elements to fit the window. + */ +ResizableVerticalSplitView.prototype.setGeometry = function( + left, top, width, height) { + ResizableVerticalSplitView.superClass_.setGeometry.call( + this, left, top, width, height); + + // If this is the first setGeometry(), initialize the split point at 50%. + if (!this.rightSplit_) + this.rightSplit_ = parseInt((width / 2).toFixed(0)); + + // Calculate the horizontal split points. + var rightboxWidth = this.rightSplit_; + var sizerWidth = this.sizerView_.getWidth(); + var leftboxWidth = width - (rightboxWidth + sizerWidth); + + // Don't let the left pane get too small. + if (leftboxWidth < ResizableVerticalSplitView.MIN_PANEL_WIDTH) { + leftboxWidth = ResizableVerticalSplitView.MIN_PANEL_WIDTH; + rightboxWidth = width - (sizerWidth + leftboxWidth); + } + + // Position the boxes using calculated split points. + this.leftView_.setGeometry(left, top, leftboxWidth, height); + this.sizerView_.setGeometry(this.leftView_.getRight(), top, + sizerWidth, height); + this.rightView_.setGeometry(this.sizerView_.getRight(), top, + rightboxWidth, height); +}; + +ResizableVerticalSplitView.prototype.show = function(isVisible) { + ResizableVerticalSplitView.superClass_.show.call(this, isVisible); + this.leftView_.show(isVisible); + this.sizerView_.show(isVisible); + this.rightView_.show(isVisible); +}; + +/** + * Called once we have clicked into the sizer. Starts capturing the mouse + * position to implement dragging. + */ +ResizableVerticalSplitView.prototype.onDragSizerStart_ = function(event) { + this.sizerMouseMoveListener_ = this.onDragSizer.bind(this); + this.sizerMouseUpListener_ = this.onDragSizerEnd.bind(this); + + window.addEventListener("mousemove", this.sizerMouseMoveListener_, true); + window.addEventListener("mouseup", this.sizerMouseUpListener_, true); + + event.preventDefault(); +}; + +/** + * Called when the mouse has moved after dragging started. + */ +ResizableVerticalSplitView.prototype.onDragSizer = function(event) { + // Convert from page coordinates, to view coordinates. + this.rightSplit_ = this.getWidth() - (event.pageX - this.getLeft()); + + // Avoid shrinking the right box too much. + this.rightSplit_ = Math.max( + this.rightSplit_, ResizableVerticalSplitView.MIN_PANEL_WIDTH); + + // Force a layout with the new |rightSplit_|. + this.setGeometry( + this.getLeft(), this.getTop(), this.getWidth(), this.getHeight()); +}; + +/** + * Called once the mouse has been released, and the dragging is over. + */ +ResizableVerticalSplitView.prototype.onDragSizerEnd = function(event) { + window.removeEventListener("mousemove", this.sizerMouseMoveListener_, true); + window.removeEventListener("mouseup", this.sizerMouseUpListener_, true); + + this.sizerMouseMoveListener_ = null; + this.sizerMouseUpListener_ = null; + + event.preventDefault(); +}; diff --git a/chrome/browser/resources/net_internals/tabswitcherview.js b/chrome/browser/resources/net_internals/tabswitcherview.js new file mode 100644 index 0000000..b712edc --- /dev/null +++ b/chrome/browser/resources/net_internals/tabswitcherview.js @@ -0,0 +1,141 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * TabSwitcher is an implementation of View that handles tab switching. + * + * +-----------------------------------+ + * | Tab1 / Tab2 / Tab3 / .. | <- tab handle view + * +-----------------------------------+ + * | | + * | | + * | | + * | stacked tab content areas | + * | (only 1 is visible at a time) | + * | | + * | | + * | | + * +-----------------------------------+ + * + * @parameter {!View} tabHandleView the view that contains the tab handles. + * + * @constructor + */ +function TabSwitcherView(tabHandleView) { + View.call(this); + this.tabHandleView_ = tabHandleView; + this.tabs_ = []; +} + +inherits(TabSwitcherView, View); + +TabSwitcherView.prototype.setGeometry = function(left, top, width, height) { + TabSwitcherView.superClass_.setGeometry.call(this, left, top, width, height); + + this.tabHandleView_.setGeometry( + left, top, width, this.tabHandleView_.getHeight()); + + var contentTop = this.tabHandleView_.getBottom(); + var contentHeight = height - this.tabHandleView_.getHeight(); + + // Position each of the tabs content areas. + for (var i = 0; i < this.tabs_.length; ++i) { + var tab = this.tabs_[i]; + tab.contentView.setGeometry(left, contentTop, width, contentHeight); + } +}; + +TabSwitcherView.prototype.show = function(isVisible) { + TabSwitcherView.superClass_.show.call(this, isVisible); + + this.tabHandleView_.show(isVisible); + + var activeTab = this.findActiveTab(); + if (activeTab) + activeTab.contentView.show(isVisible); +}; + +/** + * Adds a new tab (initially hidden). + * + * @param {String} id The ID for DOM node that will be made clickable to select + * this tab. This is also the ID we use to identify the + * "tab". + * @param {!View} view The tab's actual contents. + */ +TabSwitcherView.prototype.addTab = function(id, contentView) { + var tab = new TabEntry(id, contentView); + this.tabs_.push(tab); + + // Attach a click handler, used to switch to the tab. + var self = this; + tab.getTabHandleNode().onclick = function() { + self.switchToTab(id); + }; + + // Start tabs off as hidden. + tab.contentView.show(false); +}; + +/** + * Returns the currently selected tab, or null if there is none. + * @returns {!TabEntry} + */ +TabSwitcherView.prototype.findActiveTab = function() { + for (var i = 0; i < this.tabs_.length; ++i) { + var tab = this.tabs_[i]; + if (tab.active) + return tab; + } + return null; +}; + +/** + * Returns the tab with ID |id|. + * @returns {!TabEntry} + */ +TabSwitcherView.prototype.findTabById = function(id) { + for (var i = 0; i < this.tabs_.length; ++i) { + var tab = this.tabs_[i]; + if (tab.id == id) + return tab; + } + return null; +}; + +/** + * Focuses on tab with ID |id|. + */ +TabSwitcherView.prototype.switchToTab = function(id) { + var oldTab = this.findActiveTab(); + if (oldTab) + oldTab.setSelected(false); + + var newTab = this.findTabById(id); + newTab.setSelected(true); +}; + +//----------------------------------------------------------------------------- + +/** + * @constructor + */ +function TabEntry(id, contentView) { + this.id = id; + this.contentView = contentView; +} + +TabEntry.prototype.setSelected = function(isSelected) { + this.active = isSelected; + changeClassName(this.getTabHandleNode(), 'selected', isSelected); + this.contentView.show(isSelected); +}; + +/** + * Returns the DOM node that is used to select the tab. + */ +TabEntry.prototype.getTabHandleNode = function() { + return document.getElementById(this.id); +}; + diff --git a/chrome/browser/resources/net_internals/topmidbottomview.js b/chrome/browser/resources/net_internals/topmidbottomview.js new file mode 100644 index 0000000..2b045c7 --- /dev/null +++ b/chrome/browser/resources/net_internals/topmidbottomview.js @@ -0,0 +1,59 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * This view stacks three boxes -- one at the top, one at the bottom, and + * one that fills the remaining space between those two. + * + * +----------------------+ + * | topbar | + * +----------------------+ + * | | + * | | + * | | + * | | + * | middlebox | + * | | + * | | + * | | + * | | + * | | + * +----------------------+ + * | bottombar | + * +----------------------+ + * + * @constructor + */ +function TopMidBottomView(topView, midView, bottomView) { + View.call(this); + + this.topView_ = topView; + this.midView_ = midView; + this.bottomView_ = bottomView; +} + +inherits(TopMidBottomView, View); + +TopMidBottomView.prototype.setGeometry = function(left, top, width, height) { + TopMidBottomView.superClass_.setGeometry.call(this, left, top, width, height); + + // Calculate the vertical split points. + var topbarHeight = this.topView_.getHeight(); + var bottombarHeight = this.bottomView_.getHeight(); + var middleboxHeight = height - (topbarHeight + bottombarHeight); + + // Position the boxes using calculated split points. + this.topView_.setGeometry(left, top, width, topbarHeight); + this.midView_.setGeometry(left, this.topView_.getBottom(), + width, middleboxHeight); + this.bottomView_.setGeometry(left, this.midView_.getBottom(), + width, bottombarHeight); +}; + +TopMidBottomView.prototype.show = function(isVisible) { + TopMidBottomView.superClass_.show.call(this, isVisible); + this.topView_.show(isVisible); + this.midView_.show(isVisible); + this.bottomView_.show(isVisible); +}; diff --git a/chrome/browser/resources/net_internals/util.js b/chrome/browser/resources/net_internals/util.js index 780a030..27b5cc5 100644 --- a/chrome/browser/resources/net_internals/util.js +++ b/chrome/browser/resources/net_internals/util.js @@ -15,6 +15,17 @@ Function.prototype.bind = function(thisObj) { }; /** + * Inherit the prototype methods from one constructor into another. + */ +function inherits(childCtor, parentCtor) { + function tempCtor() {}; + tempCtor.prototype = parentCtor.prototype; + childCtor.superClass_ = parentCtor.prototype; + childCtor.prototype = new tempCtor(); + childCtor.prototype.constructor = childCtor; +}; + +/** * Sets the width (in pixels) on a DOM node. */ function setNodeWidth(node, widthPx) { @@ -39,6 +50,13 @@ function setNodePosition(node, leftPx, topPx, widthPx, heightPx) { } /** + * Sets the visibility for a DOM node. + */ +function setNodeDisplay(node, isVisible) { + node.style.display = isVisible ? '' : 'none'; +} + +/** * Adds a node to |parentNode|, of type |tagName|. */ function addNode(parentNode, tagName) { diff --git a/chrome/browser/resources/net_internals/view.js b/chrome/browser/resources/net_internals/view.js new file mode 100644 index 0000000..1338d4f --- /dev/null +++ b/chrome/browser/resources/net_internals/view.js @@ -0,0 +1,130 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * Base class to represent a "view". A view is an absolutely positioned box on + * the page. + * + * @constructor + */ +function View() { + this.isVisible_ = true; +} + +/** + * Called to reposition the view on the page. Measurements are in pixels. + */ +View.prototype.setGeometry = function(left, top, width, height) { + this.left_ = left; + this.top_ = top; + this.width_ = width; + this.height_ = height; +}; + +/** + * Called to show/hide the view. + */ +View.prototype.show = function(isVisible) { + this.isVisible_ = isVisible; +}; + +View.prototype.isVisible = function() { + return this.isVisible_; +}; + +View.prototype.getLeft = function() { + return this.left_; +}; + +View.prototype.getTop = function() { + return this.top_; +}; + +View.prototype.getWidth = function() { + return this.width_; +}; + +View.prototype.getHeight = function() { + return this.height_; +}; + +View.prototype.getRight = function() { + return this.getLeft() + this.getWidth(); +}; + +View.prototype.getBottom = function() { + return this.getTop() + this.getHeight(); +}; + + +//----------------------------------------------------------------------------- + +/** + * DivView is an implementation of View that wraps a DIV. + * + * @constructor + */ +function DivView(divId) { + View.call(this); + + this.node_ = document.getElementById(divId); + + // Initialize the default values to those of the DIV. + this.width_ = this.node_.offsetWidth; + this.height_ = this.node_.offsetHeight; + this.isVisible_ = this.node_.style.display != 'none'; +} + +inherits(DivView, View); + +DivView.prototype.setGeometry = function(left, top, width, height) { + DivView.superClass_.setGeometry.call(this, left, top, width, height); + + this.node_.style.position = "absolute"; + setNodePosition(this.node_, left, top, width, height); +}; + +DivView.prototype.show = function(isVisible) { + DivView.superClass_.show.call(this, isVisible); + setNodeDisplay(this.node_, isVisible); +}; + +/** + * Returns the wrapped DIV + */ +DivView.prototype.getNode = function() { + return this.node_; +}; + +//----------------------------------------------------------------------------- + +/** + * Implementation of View that sizes its child to fit the entire window. + * + * @param {!View} childView + * + * @constructor + */ +function WindowView(childView) { + View.call(this); + this.childView_ = childView; + window.addEventListener("resize", this.resetGeometry.bind(this), true); +} + +inherits(WindowView, View); + +WindowView.prototype.setGeometry = function(left, top, width, height) { + WindowView.superClass_.setGeometry.call(this, left, top, width, height); + this.childView_.setGeometry(left, top, width, height); +}; + +WindowView.prototype.show = function() { + WindowView.superClass_.show.call(this, isVisible); + this.childView_.show(isVisible); +}; + +WindowView.prototype.resetGeometry = function() { + this.setGeometry(0, 0, window.innerWidth, window.innerHeight); +}; + diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 0a48364..961419e 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -3174,15 +3174,18 @@ 'files': [ 'browser/resources/net_internals/detailsview.js', 'browser/resources/net_internals/index.html', - 'browser/resources/net_internals/layoutmanager.js', 'browser/resources/net_internals/loggrouper.js', 'browser/resources/net_internals/logviewpainter.js', 'browser/resources/net_internals/main.css', 'browser/resources/net_internals/main.js', 'browser/resources/net_internals/requestsview.js', + 'browser/resources/net_internals/resizableverticalsplitview.js', 'browser/resources/net_internals/sourceentry.js', + 'browser/resources/net_internals/tabswitcherview.js', 'browser/resources/net_internals/timelineviewpainter.js', + 'browser/resources/net_internals/topmidbottomview.js', 'browser/resources/net_internals/util.js', + 'browser/resources/net_internals/view.js', ] }, ] |