summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/resources/net_internals/detailsview.js139
-rw-r--r--chrome/browser/resources/net_internals/index.html41
-rw-r--r--chrome/browser/resources/net_internals/layoutmanager.js151
-rw-r--r--chrome/browser/resources/net_internals/main.css55
-rw-r--r--chrome/browser/resources/net_internals/main.js57
-rw-r--r--chrome/browser/resources/net_internals/requestsview.js58
-rw-r--r--chrome/browser/resources/net_internals/resizableverticalsplitview.js125
-rw-r--r--chrome/browser/resources/net_internals/tabswitcherview.js141
-rw-r--r--chrome/browser/resources/net_internals/topmidbottomview.js59
-rw-r--r--chrome/browser/resources/net_internals/util.js18
-rw-r--r--chrome/browser/resources/net_internals/view.js130
-rwxr-xr-xchrome/chrome_browser.gypi5
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>&nbsp;</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',
]
},
]