summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js')
-rw-r--r--chromium/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js2966
1 files changed, 2966 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js b/chromium/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
new file mode 100644
index 00000000000..84ceac2db6f
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
@@ -0,0 +1,2966 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Anthony Ricaud <rik@webkit.org>
+ * Copyright (C) 2011 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ */
+
+importScript("HAREntry.js");
+importScript("RequestView.js");
+importScript("NetworkItemView.js");
+importScript("RequestCookiesView.js");
+importScript("RequestHeadersView.js");
+importScript("RequestHTMLView.js");
+importScript("RequestJSONView.js");
+importScript("RequestPreviewView.js");
+importScript("RequestResponseView.js");
+importScript("RequestTimingView.js");
+importScript("ResourceWebSocketFrameView.js");
+
+/**
+ * @constructor
+ * @implements {WebInspector.Searchable}
+ * @implements {WebInspector.TargetManager.Observer}
+ * @extends {WebInspector.VBox}
+ * @param {!WebInspector.FilterBar} filterBar
+ * @param {!WebInspector.Setting} coulmnsVisibilitySetting
+ */
+WebInspector.NetworkLogView = function(filterBar, coulmnsVisibilitySetting)
+{
+ WebInspector.VBox.call(this);
+ this.registerRequiredCSS("networkLogView.css");
+ this.registerRequiredCSS("filter.css");
+ this.registerRequiredCSS("suggestBox.css");
+
+ this._filterBar = filterBar;
+ this._coulmnsVisibilitySetting = coulmnsVisibilitySetting;
+ this._allowRequestSelection = false;
+ this._requests = [];
+ this._requestsById = {};
+ this._requestsByURL = {};
+ this._staleRequests = {};
+ this._requestGridNodes = {};
+ this._lastRequestGridNodeId = 0;
+ this._mainRequestLoadTime = -1;
+ this._mainRequestDOMContentLoadedTime = -1;
+ this._matchedRequests = [];
+ this._highlightedSubstringChanges = [];
+ this._filteredOutRequests = new Map();
+
+ /** @type {!Array.<!WebInspector.NetworkLogView.Filter>} */
+ this._filters = [];
+
+ this._matchedRequestsMap = {};
+ this._currentMatchedRequestIndex = -1;
+
+ this._createStatusbarButtons();
+ this._createStatusBarItems();
+ this._linkifier = new WebInspector.Linkifier();
+
+ this._addFilters();
+ this._resetSuggestionBuilder();
+ this._initializeView();
+ this._recordButton.toggled = true;
+
+ WebInspector.targetManager.observeTargets(this);
+}
+
+WebInspector.NetworkLogView.HTTPSchemas = {"http": true, "https": true, "ws": true, "wss": true};
+WebInspector.NetworkLogView._responseHeaderColumns = ["Cache-Control", "Connection", "Content-Encoding", "Content-Length", "ETag", "Keep-Alive", "Last-Modified", "Server", "Vary"];
+WebInspector.NetworkLogView._defaultColumnsVisibility = {
+ method: true, status: true, scheme: false, domain: false, remoteAddress: false, type: true, initiator: true, cookies: false, setCookies: false, size: true, time: true,
+ "Cache-Control": false, "Connection": false, "Content-Encoding": false, "Content-Length": false, "ETag": false, "Keep-Alive": false, "Last-Modified": false, "Server": false, "Vary": false
+};
+WebInspector.NetworkLogView._defaultRefreshDelay = 500;
+
+/** @type {!Object.<string, string>} */
+WebInspector.NetworkLogView._columnTitles = {
+ "name": WebInspector.UIString("Name"),
+ "method": WebInspector.UIString("Method"),
+ "status": WebInspector.UIString("Status"),
+ "scheme": WebInspector.UIString("Scheme"),
+ "domain": WebInspector.UIString("Domain"),
+ "remoteAddress": WebInspector.UIString("Remote Address"),
+ "type": WebInspector.UIString("Type"),
+ "initiator": WebInspector.UIString("Initiator"),
+ "cookies": WebInspector.UIString("Cookies"),
+ "setCookies": WebInspector.UIString("Set-Cookies"),
+ "size": WebInspector.UIString("Size"),
+ "time": WebInspector.UIString("Time"),
+ "timeline": WebInspector.UIString("Timeline"),
+
+ // Response header columns
+ "Cache-Control": WebInspector.UIString("Cache-Control"),
+ "Connection": WebInspector.UIString("Connection"),
+ "Content-Encoding": WebInspector.UIString("Content-Encoding"),
+ "Content-Length": WebInspector.UIString("Content-Length"),
+ "ETag": WebInspector.UIString("ETag"),
+ "Keep-Alive": WebInspector.UIString("Keep-Alive"),
+ "Last-Modified": WebInspector.UIString("Last-Modified"),
+ "Server": WebInspector.UIString("Server"),
+ "Vary": WebInspector.UIString("Vary")
+};
+
+WebInspector.NetworkLogView.prototype = {
+ /**
+ * @param {!WebInspector.Target} target
+ */
+ targetAdded: function(target)
+ {
+ target.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestStarted, this._onRequestStarted, this);
+ target.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestUpdated, this._onRequestUpdated, this);
+ target.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestFinished, this._onRequestUpdated, this);
+
+ target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._willReloadPage, this);
+ target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameNavigated, this);
+ target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._loadEventFired, this);
+ target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.DOMContentLoaded, this._domContentLoadedEventFired, this);
+
+ target.networkLog.requests.forEach(this._appendRequest.bind(this));
+ },
+
+ /**
+ * @param {!WebInspector.Target} target
+ */
+ targetRemoved: function(target)
+ {
+ target.networkManager.removeEventListener(WebInspector.NetworkManager.EventTypes.RequestStarted, this._onRequestStarted, this);
+ target.networkManager.removeEventListener(WebInspector.NetworkManager.EventTypes.RequestUpdated, this._onRequestUpdated, this);
+ target.networkManager.removeEventListener(WebInspector.NetworkManager.EventTypes.RequestFinished, this._onRequestUpdated, this);
+
+ target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._willReloadPage, this);
+ target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameNavigated, this);
+ target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._loadEventFired, this);
+ target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.DOMContentLoaded, this._domContentLoadedEventFired, this);
+ },
+
+ _addFilters: function()
+ {
+ this._textFilterUI = new WebInspector.TextFilterUI();
+ this._textFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChanged, this._filterChanged, this);
+ this._filterBar.addFilter(this._textFilterUI);
+
+ var types = [];
+ for (var typeId in WebInspector.resourceTypes) {
+ var resourceType = WebInspector.resourceTypes[typeId];
+ types.push({name: resourceType.name(), label: resourceType.categoryTitle()});
+ }
+ this._resourceTypeFilterUI = new WebInspector.NamedBitSetFilterUI(types, WebInspector.settings.networkResourceTypeFilters);
+ this._resourceTypeFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChanged, this._filterChanged.bind(this), this);
+ this._filterBar.addFilter(this._resourceTypeFilterUI);
+
+ var dataURLSetting = WebInspector.settings.networkHideDataURL;
+ this._dataURLFilterUI = new WebInspector.CheckboxFilterUI("hide-data-url", WebInspector.UIString("Hide data URLs"), true, dataURLSetting);
+ this._dataURLFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChanged, this._filterChanged.bind(this), this);
+ this._filterBar.addFilter(this._dataURLFilterUI);
+ },
+
+ _resetSuggestionBuilder: function()
+ {
+ this._suggestionBuilder = new WebInspector.FilterSuggestionBuilder(WebInspector.NetworkPanel._searchKeys);
+ this._textFilterUI.setSuggestionBuilder(this._suggestionBuilder);
+ },
+
+ _filterChanged: function(event)
+ {
+ this._removeAllNodeHighlights();
+ this.searchCanceled();
+ this._parseFilterQuery(this._textFilterUI.value());
+ this._filterRequests();
+ },
+
+ _initializeView: function()
+ {
+ this.element.id = "network-container";
+
+ this._createSortingFunctions();
+ this._createTable();
+ this._createTimelineGrid();
+ this._summaryBarElement = this.element.createChild("div", "network-summary-bar");
+
+ if (!this.useLargeRows)
+ this._setLargerRequests(this.useLargeRows);
+
+ this._allowPopover = true;
+ this._popoverHelper = new WebInspector.PopoverHelper(this.element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this), this._onHidePopover.bind(this));
+ // Enable faster hint.
+ this._popoverHelper.setTimeout(100);
+
+ this.calculator = new WebInspector.NetworkTransferTimeCalculator();
+
+ this.switchToDetailedView();
+ },
+
+ get statusBarItems()
+ {
+ return [
+ this._recordButton.element,
+ this._clearButton.element,
+ this._filterBar.filterButton().element,
+ this._largerRequestsButton.element,
+ this._preserveLogCheckbox.element,
+ this._disableCacheCheckbox.element,
+ this._progressBarContainer];
+ },
+
+ get useLargeRows()
+ {
+ return WebInspector.settings.resourcesLargeRows.get();
+ },
+
+ set allowPopover(flag)
+ {
+ this._allowPopover = flag;
+ },
+
+ /**
+ * @return {!Array.<!Element>}
+ */
+ elementsToRestoreScrollPositionsFor: function()
+ {
+ if (!this._dataGrid) // Not initialized yet.
+ return [];
+ return [this._dataGrid.scrollContainer];
+ },
+
+ _createTimelineGrid: function()
+ {
+ this._timelineGrid = new WebInspector.TimelineGrid();
+ this._timelineGrid.element.classList.add("network-timeline-grid");
+ this._dataGrid.element.appendChild(this._timelineGrid.element);
+ },
+
+ _createTable: function()
+ {
+ var columns = [];
+ columns.push({
+ id: "name",
+ titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Name"), WebInspector.UIString("Path")),
+ title: WebInspector.NetworkLogView._columnTitles["name"],
+ sortable: true,
+ weight: 20,
+ disclosure: true
+ });
+
+ columns.push({
+ id: "method",
+ title: WebInspector.NetworkLogView._columnTitles["method"],
+ sortable: true,
+ weight: 6
+ });
+
+ columns.push({
+ id: "status",
+ titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Status"), WebInspector.UIString("Text")),
+ title: WebInspector.NetworkLogView._columnTitles["status"],
+ sortable: true,
+ weight: 6
+ });
+
+ columns.push({
+ id: "scheme",
+ title: WebInspector.NetworkLogView._columnTitles["scheme"],
+ sortable: true,
+ weight: 6
+ });
+
+ columns.push({
+ id: "domain",
+ title: WebInspector.NetworkLogView._columnTitles["domain"],
+ sortable: true,
+ weight: 6
+ });
+
+ columns.push({
+ id: "remoteAddress",
+ title: WebInspector.NetworkLogView._columnTitles["remoteAddress"],
+ sortable: true,
+ weight: 10,
+ align: WebInspector.DataGrid.Align.Right
+ });
+
+ columns.push({
+ id: "type",
+ title: WebInspector.NetworkLogView._columnTitles["type"],
+ sortable: true,
+ weight: 6
+ });
+
+ columns.push({
+ id: "initiator",
+ title: WebInspector.NetworkLogView._columnTitles["initiator"],
+ sortable: true,
+ weight: 10
+ });
+
+ columns.push({
+ id: "cookies",
+ title: WebInspector.NetworkLogView._columnTitles["cookies"],
+ sortable: true,
+ weight: 6,
+ align: WebInspector.DataGrid.Align.Right
+ });
+
+ columns.push({
+ id: "setCookies",
+ title: WebInspector.NetworkLogView._columnTitles["setCookies"],
+ sortable: true,
+ weight: 6,
+ align: WebInspector.DataGrid.Align.Right
+ });
+
+ columns.push({
+ id: "size",
+ titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Size"), WebInspector.UIString("Content")),
+ title: WebInspector.NetworkLogView._columnTitles["size"],
+ sortable: true,
+ weight: 6,
+ align: WebInspector.DataGrid.Align.Right
+ });
+
+ columns.push({
+ id: "time",
+ titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Time"), WebInspector.UIString("Latency")),
+ title: WebInspector.NetworkLogView._columnTitles["time"],
+ sortable: true,
+ weight: 6,
+ align: WebInspector.DataGrid.Align.Right
+ });
+
+ var responseHeaderColumns = WebInspector.NetworkLogView._responseHeaderColumns;
+ for (var i = 0; i < responseHeaderColumns.length; ++i) {
+ var headerName = responseHeaderColumns[i];
+ var descriptor = {
+ id: headerName,
+ title: WebInspector.NetworkLogView._columnTitles[headerName],
+ weight: 6
+ }
+ if (headerName === "Content-Length")
+ descriptor.align = WebInspector.DataGrid.Align.Right;
+ columns.push(descriptor);
+ }
+
+ columns.push({
+ id: "timeline",
+ titleDOMFragment: document.createDocumentFragment(),
+ title: WebInspector.NetworkLogView._columnTitles["timeline"],
+ sortable: false,
+ weight: 40,
+ sort: WebInspector.DataGrid.Order.Ascending
+ });
+
+ this._dataGrid = new WebInspector.DataGrid(columns);
+ this._updateColumns();
+ this._dataGrid.setName("networkLog");
+ this._dataGrid.resizeMethod = WebInspector.DataGrid.ResizeMethod.Last;
+ this._dataGrid.element.classList.add("network-log-grid");
+ this._dataGrid.element.addEventListener("contextmenu", this._contextMenu.bind(this), true);
+ this._dataGrid.show(this.element);
+
+ // Event listeners need to be added _after_ we attach to the document, so that owner document is properly update.
+ this._dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._sortItems, this);
+ this._dataGrid.addEventListener(WebInspector.DataGrid.Events.ColumnsResized, this._updateDividersIfNeeded, this);
+
+ this._patchTimelineHeader();
+ },
+
+ _makeHeaderFragment: function(title, subtitle)
+ {
+ var fragment = document.createDocumentFragment();
+ fragment.createTextChild(title);
+ var subtitleDiv = fragment.createChild("div", "network-header-subtitle");
+ subtitleDiv.createTextChild(subtitle);
+ return fragment;
+ },
+
+ _patchTimelineHeader: function()
+ {
+ var timelineSorting = document.createElement("select");
+
+ var option = document.createElement("option");
+ option.value = "startTime";
+ option.label = WebInspector.UIString("Timeline");
+ timelineSorting.appendChild(option);
+
+ option = document.createElement("option");
+ option.value = "startTime";
+ option.label = WebInspector.UIString("Start Time");
+ timelineSorting.appendChild(option);
+
+ option = document.createElement("option");
+ option.value = "responseTime";
+ option.label = WebInspector.UIString("Response Time");
+ timelineSorting.appendChild(option);
+
+ option = document.createElement("option");
+ option.value = "endTime";
+ option.label = WebInspector.UIString("End Time");
+ timelineSorting.appendChild(option);
+
+ option = document.createElement("option");
+ option.value = "duration";
+ option.label = WebInspector.UIString("Duration");
+ timelineSorting.appendChild(option);
+
+ option = document.createElement("option");
+ option.value = "latency";
+ option.label = WebInspector.UIString("Latency");
+ timelineSorting.appendChild(option);
+
+ var header = this._dataGrid.headerTableHeader("timeline");
+ header.replaceChild(timelineSorting, header.firstChild);
+
+ timelineSorting.addEventListener("click", function(event) { event.consume() }, false);
+ timelineSorting.addEventListener("change", this._sortByTimeline.bind(this), false);
+ this._timelineSortSelector = timelineSorting;
+ },
+
+ _createSortingFunctions: function()
+ {
+ this._sortingFunctions = {};
+ this._sortingFunctions.name = WebInspector.NetworkDataGridNode.NameComparator;
+ this._sortingFunctions.method = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "method", false);
+ this._sortingFunctions.status = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "statusCode", false);
+ this._sortingFunctions.scheme = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "scheme", false);
+ this._sortingFunctions.domain = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "domain", false);
+ this._sortingFunctions.remoteAddress = WebInspector.NetworkDataGridNode.RemoteAddressComparator;
+ this._sortingFunctions.type = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "mimeType", false);
+ this._sortingFunctions.initiator = WebInspector.NetworkDataGridNode.InitiatorComparator;
+ this._sortingFunctions.cookies = WebInspector.NetworkDataGridNode.RequestCookiesCountComparator;
+ this._sortingFunctions.setCookies = WebInspector.NetworkDataGridNode.ResponseCookiesCountComparator;
+ this._sortingFunctions.size = WebInspector.NetworkDataGridNode.SizeComparator;
+ this._sortingFunctions.time = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "duration", false);
+ this._sortingFunctions.timeline = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "startTime", false);
+ this._sortingFunctions.startTime = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "startTime", false);
+ this._sortingFunctions.endTime = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "endTime", false);
+ this._sortingFunctions.responseTime = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "responseReceivedTime", false);
+ this._sortingFunctions.duration = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "duration", true);
+ this._sortingFunctions.latency = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "latency", true);
+
+ var timeCalculator = new WebInspector.NetworkTransferTimeCalculator();
+ var durationCalculator = new WebInspector.NetworkTransferDurationCalculator();
+
+ this._calculators = {};
+ this._calculators.timeline = timeCalculator;
+ this._calculators.startTime = timeCalculator;
+ this._calculators.endTime = timeCalculator;
+ this._calculators.responseTime = timeCalculator;
+ this._calculators.duration = durationCalculator;
+ this._calculators.latency = durationCalculator;
+ },
+
+ _sortItems: function()
+ {
+ this._removeAllNodeHighlights();
+ var columnIdentifier = this._dataGrid.sortColumnIdentifier();
+ if (columnIdentifier === "timeline") {
+ this._sortByTimeline();
+ return;
+ }
+ var sortingFunction = this._sortingFunctions[columnIdentifier];
+ if (!sortingFunction)
+ return;
+
+ this._dataGrid.sortNodes(sortingFunction, !this._dataGrid.isSortOrderAscending());
+ this._timelineSortSelector.selectedIndex = 0;
+
+ this.searchCanceled();
+
+ WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, {
+ action: WebInspector.UserMetrics.UserActionNames.NetworkSort,
+ column: columnIdentifier,
+ sortOrder: this._dataGrid.sortOrder()
+ });
+ },
+
+ _sortByTimeline: function()
+ {
+ this._removeAllNodeHighlights();
+ var selectedIndex = this._timelineSortSelector.selectedIndex;
+ if (!selectedIndex)
+ selectedIndex = 1; // Sort by start time by default.
+ var selectedOption = this._timelineSortSelector[selectedIndex];
+ var value = selectedOption.value;
+
+ var sortingFunction = this._sortingFunctions[value];
+ this._dataGrid.sortNodes(sortingFunction);
+ this.calculator = this._calculators[value];
+ if (this.calculator.startAtZero)
+ this._timelineGrid.hideEventDividers();
+ else
+ this._timelineGrid.showEventDividers();
+ this._dataGrid.markColumnAsSortedBy("timeline", WebInspector.DataGrid.Order.Ascending);
+ },
+
+ _createStatusBarItems: function()
+ {
+ this._progressBarContainer = document.createElement("div");
+ this._progressBarContainer.className = "status-bar-item";
+ },
+
+ _updateSummaryBar: function()
+ {
+ var requestsNumber = this._requests.length;
+
+ if (!requestsNumber) {
+ if (this._summaryBarElement._isDisplayingWarning)
+ return;
+ this._summaryBarElement._isDisplayingWarning = true;
+ this._summaryBarElement.removeChildren();
+ this._summaryBarElement.createChild("div", "warning-icon-small");
+ var text = WebInspector.UIString("No requests captured. Reload the page to see detailed information on the network activity.");
+ this._summaryBarElement.appendChild(document.createTextNode(text));
+ this._summaryBarElement.title = text;
+ return;
+ }
+ delete this._summaryBarElement._isDisplayingWarning;
+
+ var transferSize = 0;
+ var selectedRequestsNumber = 0;
+ var selectedTransferSize = 0;
+ var baseTime = -1;
+ var maxTime = -1;
+ for (var i = 0; i < this._requests.length; ++i) {
+ var request = this._requests[i];
+ var requestTransferSize = request.transferSize;
+ transferSize += requestTransferSize;
+ if (!this._filteredOutRequests.get(request)) {
+ selectedRequestsNumber++;
+ selectedTransferSize += requestTransferSize;
+ }
+ if (request.url === request.target().resourceTreeModel.inspectedPageURL())
+ baseTime = request.startTime;
+ if (request.endTime > maxTime)
+ maxTime = request.endTime;
+ }
+ var text = "";
+ if (selectedRequestsNumber !== requestsNumber) {
+ text += String.sprintf(WebInspector.UIString("%d / %d requests"), selectedRequestsNumber, requestsNumber);
+ text += " \u2758 " + String.sprintf(WebInspector.UIString("%s / %s transferred"), Number.bytesToString(selectedTransferSize), Number.bytesToString(transferSize));
+ } else {
+ text += String.sprintf(WebInspector.UIString("%d requests"), requestsNumber);
+ text += " \u2758 " + String.sprintf(WebInspector.UIString("%s transferred"), Number.bytesToString(transferSize));
+ }
+ if (baseTime !== -1 && this._mainRequestLoadTime !== -1 && this._mainRequestDOMContentLoadedTime !== -1 && this._mainRequestDOMContentLoadedTime > baseTime) {
+ text += " \u2758 " + String.sprintf(WebInspector.UIString("%s (load: %s, DOMContentLoaded: %s)"),
+ Number.secondsToString(maxTime - baseTime),
+ Number.secondsToString(this._mainRequestLoadTime - baseTime),
+ Number.secondsToString(this._mainRequestDOMContentLoadedTime - baseTime));
+ }
+ this._summaryBarElement.textContent = text;
+ this._summaryBarElement.title = text;
+ },
+
+ _scheduleRefresh: function()
+ {
+ if (this._needsRefresh)
+ return;
+
+ this._needsRefresh = true;
+
+ if (this.isShowing() && !this._refreshTimeout)
+ this._refreshTimeout = setTimeout(this.refresh.bind(this), WebInspector.NetworkLogView._defaultRefreshDelay);
+ },
+
+ _updateDividersIfNeeded: function()
+ {
+ if (!this._dataGrid)
+ return;
+ var timelineOffset = this._dataGrid.columnOffset("timeline");
+ // Position timline grid location.
+ if (timelineOffset)
+ this._timelineGrid.element.style.left = timelineOffset + "px";
+
+ var proceed = true;
+ if (!this.isShowing()) {
+ this._scheduleRefresh();
+ proceed = false;
+ } else {
+ this.calculator.setDisplayWindow(this._timelineGrid.dividersElement.clientWidth);
+ proceed = this._timelineGrid.updateDividers(this.calculator);
+ }
+ if (!proceed)
+ return;
+
+ if (this.calculator.startAtZero || !this.calculator.computePercentageFromEventTime) {
+ // If our current sorting method starts at zero, that means it shows all
+ // requests starting at the same point, and so onLoad event and DOMContent
+ // event lines really wouldn't make much sense here, so don't render them.
+ // Additionally, if the calculator doesn't have the computePercentageFromEventTime
+ // function defined, we are probably sorting by size, and event times aren't relevant
+ // in this case.
+ return;
+ }
+
+ this._timelineGrid.removeEventDividers();
+ if (this._mainRequestLoadTime !== -1) {
+ var percent = this.calculator.computePercentageFromEventTime(this._mainRequestLoadTime);
+
+ var loadDivider = document.createElement("div");
+ loadDivider.className = "network-event-divider network-red-divider";
+
+ var loadDividerPadding = document.createElement("div");
+ loadDividerPadding.className = "network-event-divider-padding";
+ loadDividerPadding.title = WebInspector.UIString("Load event");
+ loadDividerPadding.appendChild(loadDivider);
+ loadDividerPadding.style.left = percent + "%";
+ this._timelineGrid.addEventDivider(loadDividerPadding);
+ }
+
+ if (this._mainRequestDOMContentLoadedTime !== -1) {
+ var percent = this.calculator.computePercentageFromEventTime(this._mainRequestDOMContentLoadedTime);
+
+ var domContentLoadedDivider = document.createElement("div");
+ domContentLoadedDivider.className = "network-event-divider network-blue-divider";
+
+ var domContentLoadedDividerPadding = document.createElement("div");
+ domContentLoadedDividerPadding.className = "network-event-divider-padding";
+ domContentLoadedDividerPadding.title = WebInspector.UIString("DOMContentLoaded event");
+ domContentLoadedDividerPadding.appendChild(domContentLoadedDivider);
+ domContentLoadedDividerPadding.style.left = percent + "%";
+ this._timelineGrid.addEventDivider(domContentLoadedDividerPadding);
+ }
+ },
+
+ _refreshIfNeeded: function()
+ {
+ if (this._needsRefresh)
+ this.refresh();
+ },
+
+ _invalidateAllItems: function()
+ {
+ for (var i = 0; i < this._requests.length; ++i) {
+ var request = this._requests[i];
+ this._staleRequests[request.requestId] = request;
+ }
+ },
+
+ get calculator()
+ {
+ return this._calculator;
+ },
+
+ set calculator(x)
+ {
+ if (!x || this._calculator === x)
+ return;
+
+ this._calculator = x;
+ this._calculator.reset();
+
+ this._invalidateAllItems();
+ this.refresh();
+ },
+
+ _requestGridNode: function(request)
+ {
+ return this._requestGridNodes[request.__gridNodeId];
+ },
+
+ _createRequestGridNode: function(request)
+ {
+ var node = new WebInspector.NetworkDataGridNode(this, request);
+ request.__gridNodeId = this._lastRequestGridNodeId++;
+ this._requestGridNodes[request.__gridNodeId] = node;
+ return node;
+ },
+
+ _createStatusbarButtons: function()
+ {
+ this._recordButton = new WebInspector.StatusBarButton(WebInspector.UIString("Record Network Log"), "record-profile-status-bar-item");
+ this._recordButton.addEventListener("click", this._onRecordButtonClicked, this);
+
+ this._clearButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear"), "clear-status-bar-item");
+ this._clearButton.addEventListener("click", this._reset, this);
+
+ this._largerRequestsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Use small resource rows."), "network-larger-resources-status-bar-item");
+ this._largerRequestsButton.toggled = WebInspector.settings.resourcesLargeRows.get();
+ this._largerRequestsButton.addEventListener("click", this._toggleLargerRequests, this);
+
+ this._preserveLogCheckbox = new WebInspector.StatusBarCheckbox(WebInspector.UIString("Preserve log"));
+ this._preserveLogCheckbox.element.title = WebInspector.UIString("Do not clear log on page reload / navigation.");
+
+ this._disableCacheCheckbox = new WebInspector.StatusBarCheckbox(WebInspector.UIString("Disable cache"));
+ WebInspector.SettingsUI.bindCheckbox(this._disableCacheCheckbox.inputElement, WebInspector.settings.cacheDisabled);
+ this._disableCacheCheckbox.element.title = WebInspector.UIString("Disable cache (while DevTools is open).");
+ },
+
+ _loadEventFired: function(event)
+ {
+ if (!this._recordButton.toggled)
+ return;
+
+ this._mainRequestLoadTime = event.data || -1;
+ // Schedule refresh to update boundaries and draw the new line.
+ this._scheduleRefresh();
+ },
+
+ _domContentLoadedEventFired: function(event)
+ {
+ if (!this._recordButton.toggled)
+ return;
+ this._mainRequestDOMContentLoadedTime = event.data || -1;
+ // Schedule refresh to update boundaries and draw the new line.
+ this._scheduleRefresh();
+ },
+
+ wasShown: function()
+ {
+ this._refreshIfNeeded();
+ },
+
+ willHide: function()
+ {
+ this._popoverHelper.hidePopover();
+ },
+
+ refresh: function()
+ {
+ this._needsRefresh = false;
+ if (this._refreshTimeout) {
+ clearTimeout(this._refreshTimeout);
+ delete this._refreshTimeout;
+ }
+
+ this._removeAllNodeHighlights();
+ var wasScrolledToLastRow = this._dataGrid.isScrolledToLastRow();
+ var boundariesChanged = false;
+ if (this.calculator.updateBoundariesForEventTime) {
+ boundariesChanged = this.calculator.updateBoundariesForEventTime(this._mainRequestLoadTime) || boundariesChanged;
+ boundariesChanged = this.calculator.updateBoundariesForEventTime(this._mainRequestDOMContentLoadedTime) || boundariesChanged;
+ }
+
+ for (var requestId in this._staleRequests) {
+ var request = this._staleRequests[requestId];
+ var node = this._requestGridNode(request);
+ if (!node) {
+ // Create the timeline tree element and graph.
+ node = this._createRequestGridNode(request);
+ this._dataGrid.rootNode().appendChild(node);
+ }
+ node.refresh();
+ this._applyFilter(node);
+
+ if (this.calculator.updateBoundaries(request))
+ boundariesChanged = true;
+
+ if (!node.isFilteredOut())
+ this._updateHighlightIfMatched(request);
+ }
+
+ if (boundariesChanged) {
+ // The boundaries changed, so all item graphs are stale.
+ this._invalidateAllItems();
+ }
+
+ for (var requestId in this._staleRequests)
+ this._requestGridNode(this._staleRequests[requestId]).refreshGraph(this.calculator);
+
+ this._staleRequests = {};
+ this._sortItems();
+ this._updateSummaryBar();
+ this._dataGrid.updateWidths();
+ // FIXME: evaluate performance impact of moving this before a call to sortItems()
+ if (wasScrolledToLastRow)
+ this._dataGrid.scrollToLastRow();
+ },
+
+ _onRecordButtonClicked: function()
+ {
+ if (!this._recordButton.toggled)
+ this._reset();
+ this._recordButton.toggled = !this._recordButton.toggled;
+ },
+
+ _reset: function()
+ {
+ this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.ViewCleared);
+
+ this._clearSearchMatchedList();
+ if (this._popoverHelper)
+ this._popoverHelper.hidePopover();
+
+ if (this._calculator)
+ this._calculator.reset();
+
+ this._requests = [];
+ this._requestsById = {};
+ this._requestsByURL = {};
+ this._staleRequests = {};
+ this._requestGridNodes = {};
+ this._resetSuggestionBuilder();
+
+ if (this._dataGrid) {
+ this._dataGrid.rootNode().removeChildren();
+ this._updateDividersIfNeeded();
+ this._updateSummaryBar();
+ }
+
+ this._mainRequestLoadTime = -1;
+ this._mainRequestDOMContentLoadedTime = -1;
+ },
+
+ get requests()
+ {
+ return this._requests;
+ },
+
+ _onRequestStarted: function(event)
+ {
+ if (this._recordButton.toggled)
+ this._appendRequest(event.data);
+ },
+
+ _appendRequest: function(request)
+ {
+ this._requests.push(request);
+
+ // In case of redirect request id is reassigned to a redirected
+ // request and we need to update _requestsById and search results.
+ if (this._requestsById[request.requestId]) {
+ var oldRequest = request.redirects[request.redirects.length - 1];
+ this._requestsById[oldRequest.requestId] = oldRequest;
+
+ this._updateSearchMatchedListAfterRequestIdChanged(request.requestId, oldRequest.requestId);
+ }
+ this._requestsById[request.requestId] = request;
+
+ this._requestsByURL[request.url] = request;
+
+ // Pull all the redirects of the main request upon commit load.
+ if (request.redirects) {
+ for (var i = 0; i < request.redirects.length; ++i)
+ this._refreshRequest(request.redirects[i]);
+ }
+
+ this._refreshRequest(request);
+ },
+
+ /**
+ * @param {!WebInspector.Event} event
+ */
+ _onRequestUpdated: function(event)
+ {
+ var request = /** @type {!WebInspector.NetworkRequest} */ (event.data);
+ this._refreshRequest(request);
+ },
+
+ /**
+ * @param {!WebInspector.NetworkRequest} request
+ */
+ _refreshRequest: function(request)
+ {
+ if (!this._requestsById[request.requestId])
+ return;
+
+ this._suggestionBuilder.addItem(WebInspector.NetworkPanel.FilterType.Domain, request.domain);
+ this._suggestionBuilder.addItem(WebInspector.NetworkPanel.FilterType.Method, request.requestMethod);
+ this._suggestionBuilder.addItem(WebInspector.NetworkPanel.FilterType.MimeType, request.mimeType);
+ this._suggestionBuilder.addItem(WebInspector.NetworkPanel.FilterType.StatusCode, "" + request.statusCode);
+
+ var responseHeaders = request.responseHeaders;
+ for (var i = 0, l = responseHeaders.length; i < l; ++i)
+ this._suggestionBuilder.addItem(WebInspector.NetworkPanel.FilterType.HasResponseHeader, responseHeaders[i].name);
+ var cookies = request.responseCookies;
+ for (var i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
+ var cookie = cookies[i];
+ this._suggestionBuilder.addItem(WebInspector.NetworkPanel.FilterType.SetCookieDomain, cookie.domain());
+ this._suggestionBuilder.addItem(WebInspector.NetworkPanel.FilterType.SetCookieName, cookie.name());
+ this._suggestionBuilder.addItem(WebInspector.NetworkPanel.FilterType.SetCookieValue, cookie.value());
+ }
+
+ this._staleRequests[request.requestId] = request;
+ this._scheduleRefresh();
+ },
+
+ _willReloadPage: function(event)
+ {
+ this._recordButton.toggled = true;
+ if (!this._preserveLogCheckbox.checked())
+ this._reset();
+ },
+
+ /**
+ * @param {!WebInspector.Event} event
+ */
+ _mainFrameNavigated: function(event)
+ {
+ if (!this._recordButton.toggled || this._preserveLogCheckbox.checked())
+ return;
+
+ var frame = /** @type {!WebInspector.ResourceTreeFrame} */ (event.data);
+ var loaderId = frame.loaderId;
+
+ // Pick provisional load requests.
+ var requestsToPick = [];
+ var requests = frame.target().networkLog.requests;
+ for (var i = 0; i < requests.length; ++i) {
+ var request = requests[i];
+ if (request.loaderId === loaderId)
+ requestsToPick.push(request);
+ }
+
+ this._reset();
+
+ for (var i = 0; i < requestsToPick.length; ++i)
+ this._appendRequest(requestsToPick[i]);
+ },
+
+ switchToDetailedView: function()
+ {
+ if (!this._dataGrid)
+ return;
+ if (this._dataGrid.selectedNode)
+ this._dataGrid.selectedNode.selected = false;
+
+ this.element.classList.remove("brief-mode");
+ this._detailedMode = true;
+ this._updateColumns();
+ },
+
+ switchToBriefView: function()
+ {
+ this.element.classList.add("brief-mode");
+ this._removeAllNodeHighlights();
+ this._detailedMode = false;
+ this._updateColumns();
+ this._popoverHelper.hidePopover();
+ },
+
+ _toggleLargerRequests: function()
+ {
+ WebInspector.settings.resourcesLargeRows.set(!WebInspector.settings.resourcesLargeRows.get());
+ this._setLargerRequests(WebInspector.settings.resourcesLargeRows.get());
+ },
+
+ _setLargerRequests: function(enabled)
+ {
+ this._largerRequestsButton.toggled = enabled;
+ if (!enabled) {
+ this._largerRequestsButton.title = WebInspector.UIString("Use large resource rows.");
+ this._dataGrid.element.classList.add("small");
+ this._timelineGrid.element.classList.add("small");
+ } else {
+ this._largerRequestsButton.title = WebInspector.UIString("Use small resource rows.");
+ this._dataGrid.element.classList.remove("small");
+ this._timelineGrid.element.classList.remove("small");
+ }
+ this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.RowSizeChanged, { largeRows: enabled });
+ },
+
+ _getPopoverAnchor: function(element)
+ {
+ if (!this._allowPopover)
+ return;
+ var anchor = element.enclosingNodeOrSelfWithClass("network-graph-bar") || element.enclosingNodeOrSelfWithClass("network-graph-label");
+ if (anchor && anchor.parentElement.request && anchor.parentElement.request.timing)
+ return anchor;
+ anchor = element.enclosingNodeOrSelfWithClass("network-script-initiated");
+ if (anchor && anchor.request && anchor.request.initiator)
+ return anchor;
+
+ return null;
+ },
+
+ /**
+ * @param {!Element} anchor
+ * @param {!WebInspector.Popover} popover
+ */
+ _showPopover: function(anchor, popover)
+ {
+ var content;
+ if (anchor.classList.contains("network-script-initiated"))
+ content = this._generateScriptInitiatedPopoverContent(anchor.request);
+ else
+ content = WebInspector.RequestTimingView.createTimingTable(anchor.parentElement.request);
+ popover.show(content, anchor);
+ },
+
+ _onHidePopover: function()
+ {
+ this._linkifier.reset();
+ },
+
+ /**
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {!Element}
+ */
+ _generateScriptInitiatedPopoverContent: function(request)
+ {
+ var stackTrace = request.initiator.stackTrace;
+ var framesTable = document.createElement("table");
+ for (var i = 0; i < stackTrace.length; ++i) {
+ var stackFrame = stackTrace[i];
+ var row = document.createElement("tr");
+ row.createChild("td").textContent = stackFrame.functionName || WebInspector.UIString("(anonymous function)");
+ row.createChild("td").textContent = " @ ";
+ row.createChild("td").appendChild(this._linkifier.linkifyLocation(request.target(), stackFrame.url, stackFrame.lineNumber - 1, stackFrame.columnNumber - 1));
+ framesTable.appendChild(row);
+ }
+ return framesTable;
+ },
+
+ _updateColumns: function()
+ {
+ var detailedMode = !!this._detailedMode;
+ var visibleColumns = {"name": true};
+ if (detailedMode) {
+ visibleColumns["timeline"] = true;
+ var columnsVisibility = this._coulmnsVisibilitySetting.get();
+ for (var columnIdentifier in columnsVisibility)
+ visibleColumns[columnIdentifier] = columnsVisibility[columnIdentifier];
+ }
+
+ this._dataGrid.setColumnsVisiblity(visibleColumns);
+ },
+
+ /**
+ * @param {string} columnIdentifier
+ */
+ _toggleColumnVisibility: function(columnIdentifier)
+ {
+ var columnsVisibility = this._coulmnsVisibilitySetting.get();
+ columnsVisibility[columnIdentifier] = !columnsVisibility[columnIdentifier];
+ this._coulmnsVisibilitySetting.set(columnsVisibility);
+
+ this._updateColumns();
+ },
+
+ /**
+ * @return {!Array.<string>}
+ */
+ _getConfigurableColumnIDs: function()
+ {
+ if (this._configurableColumnIDs)
+ return this._configurableColumnIDs;
+
+ var columnTitles = WebInspector.NetworkLogView._columnTitles;
+ function compare(id1, id2)
+ {
+ return columnTitles[id1].compareTo(columnTitles[id2]);
+ }
+
+ var columnIDs = Object.keys(this._coulmnsVisibilitySetting.get());
+ this._configurableColumnIDs = columnIDs.sort(compare);
+ return this._configurableColumnIDs;
+ },
+
+ _contextMenu: function(event)
+ {
+ var contextMenu = new WebInspector.ContextMenu(event);
+
+ if (this._detailedMode && event.target.isSelfOrDescendant(this._dataGrid.headerTableBody)) {
+ var columnsVisibility = this._coulmnsVisibilitySetting.get();
+ var columnIDs = this._getConfigurableColumnIDs();
+ var columnTitles = WebInspector.NetworkLogView._columnTitles;
+ for (var i = 0; i < columnIDs.length; ++i) {
+ var columnIdentifier = columnIDs[i];
+ contextMenu.appendCheckboxItem(columnTitles[columnIdentifier], this._toggleColumnVisibility.bind(this, columnIdentifier), !!columnsVisibility[columnIdentifier]);
+ }
+ contextMenu.show();
+ return;
+ }
+
+ var gridNode = this._dataGrid.dataGridNodeFromNode(event.target);
+ var request = gridNode && gridNode._request;
+
+ /**
+ * @param {string} url
+ */
+ function openResourceInNewTab(url)
+ {
+ InspectorFrontendHost.openInNewTab(url);
+ }
+
+ if (request) {
+ contextMenu.appendItem(WebInspector.openLinkExternallyLabel(), openResourceInNewTab.bind(null, request.url));
+ contextMenu.appendSeparator();
+ contextMenu.appendItem(WebInspector.copyLinkAddressLabel(), this._copyLocation.bind(this, request));
+ if (request.requestHeadersText())
+ contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy request headers" : "Copy Request Headers"), this._copyRequestHeaders.bind(this, request));
+ if (request.responseHeadersText)
+ contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy response headers" : "Copy Response Headers"), this._copyResponseHeaders.bind(this, request));
+ if (request.finished)
+ contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy response" : "Copy Response"), this._copyResponse.bind(this, request));
+ contextMenu.appendItem(WebInspector.UIString("Copy as cURL"), this._copyCurlCommand.bind(this, request));
+ }
+ contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy all as HAR" : "Copy All as HAR"), this._copyAll.bind(this));
+
+ contextMenu.appendSeparator();
+ contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Save as HAR with content" : "Save as HAR with Content"), this._exportAll.bind(this));
+
+ contextMenu.appendSeparator();
+ contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear browser cache" : "Clear Browser Cache"), this._clearBrowserCache.bind(this));
+ contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear browser cookies" : "Clear Browser Cookies"), this._clearBrowserCookies.bind(this));
+
+ if (request && request.type === WebInspector.resourceTypes.XHR) {
+ contextMenu.appendSeparator();
+ contextMenu.appendItem(WebInspector.UIString("Replay XHR"), this._replayXHR.bind(this, request.requestId));
+ contextMenu.appendSeparator();
+ }
+
+ contextMenu.show();
+ },
+
+ _replayXHR: function(requestId)
+ {
+ NetworkAgent.replayXHR(requestId);
+ },
+
+ _harRequests: function()
+ {
+ var httpRequests = this._requests.filter(WebInspector.NetworkLogView.HTTPRequestsFilter);
+ httpRequests = httpRequests.filter(WebInspector.NetworkLogView.FinishedRequestsFilter);
+ return httpRequests.filter(WebInspector.NetworkLogView.NonDevToolsRequestsFilter);
+ },
+
+ _copyAll: function()
+ {
+ var harArchive = {
+ log: (new WebInspector.HARLog(this._harRequests())).build()
+ };
+ InspectorFrontendHost.copyText(JSON.stringify(harArchive, null, 2));
+ },
+
+ _copyLocation: function(request)
+ {
+ InspectorFrontendHost.copyText(request.url);
+ },
+
+ _copyRequestHeaders: function(request)
+ {
+ InspectorFrontendHost.copyText(request.requestHeadersText());
+ },
+
+ _copyResponse: function(request)
+ {
+ function callback(content)
+ {
+ if (request.contentEncoded)
+ content = request.asDataURL();
+ InspectorFrontendHost.copyText(content || "");
+ }
+ request.requestContent(callback);
+ },
+
+ _copyResponseHeaders: function(request)
+ {
+ InspectorFrontendHost.copyText(request.responseHeadersText);
+ },
+
+ /**
+ * @param {!WebInspector.NetworkRequest} request
+ */
+ _copyCurlCommand: function(request)
+ {
+ InspectorFrontendHost.copyText(this._generateCurlCommand(request));
+ },
+
+ _exportAll: function()
+ {
+ var filename = WebInspector.resourceTreeModel.inspectedPageDomain() + ".har";
+ var stream = new WebInspector.FileOutputStream();
+ stream.open(filename, openCallback.bind(this));
+
+ /**
+ * @param {boolean} accepted
+ * @this {WebInspector.NetworkLogView}
+ */
+ function openCallback(accepted)
+ {
+ if (!accepted)
+ return;
+ var progressIndicator = new WebInspector.ProgressIndicator();
+ this._progressBarContainer.appendChild(progressIndicator.element);
+ var harWriter = new WebInspector.HARWriter();
+ harWriter.write(stream, this._harRequests(), progressIndicator);
+ }
+ },
+
+ _clearBrowserCache: function()
+ {
+ if (confirm(WebInspector.UIString("Are you sure you want to clear browser cache?")))
+ NetworkAgent.clearBrowserCache();
+ },
+
+ _clearBrowserCookies: function()
+ {
+ if (confirm(WebInspector.UIString("Are you sure you want to clear browser cookies?")))
+ NetworkAgent.clearBrowserCookies();
+ },
+
+ _matchRequest: function(request)
+ {
+ if (!this._searchRegExp)
+ return -1;
+
+ if (!request.name().match(this._searchRegExp) && !request.path().match(this._searchRegExp))
+ return -1;
+
+ if (request.requestId in this._matchedRequestsMap)
+ return this._matchedRequestsMap[request.requestId];
+
+ var matchedRequestIndex = this._matchedRequests.length;
+ this._matchedRequestsMap[request.requestId] = matchedRequestIndex;
+ this._matchedRequests.push(request.requestId);
+
+ return matchedRequestIndex;
+ },
+
+ _clearSearchMatchedList: function()
+ {
+ delete this._searchRegExp;
+ this._matchedRequests = [];
+ this._matchedRequestsMap = {};
+ this._removeAllHighlights();
+ },
+
+ _updateSearchMatchedListAfterRequestIdChanged: function(oldRequestId, newRequestId)
+ {
+ var requestIndex = this._matchedRequestsMap[oldRequestId];
+ if (requestIndex) {
+ delete this._matchedRequestsMap[oldRequestId];
+ this._matchedRequestsMap[newRequestId] = requestIndex;
+ this._matchedRequests[requestIndex] = newRequestId;
+ }
+ },
+
+ _updateHighlightIfMatched: function(request)
+ {
+ var matchedRequestIndex = this._matchRequest(request);
+ if (matchedRequestIndex === -1)
+ return;
+
+ this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.SearchCountUpdated, this._matchedRequests.length);
+
+ if (this._currentMatchedRequestIndex !== -1 && this._currentMatchedRequestIndex !== matchedRequestIndex)
+ return;
+
+ this._highlightNthMatchedRequestForSearch(matchedRequestIndex, false);
+ },
+
+ _removeAllHighlights: function()
+ {
+ this._removeAllNodeHighlights();
+ for (var i = 0; i < this._highlightedSubstringChanges.length; ++i)
+ WebInspector.revertDomChanges(this._highlightedSubstringChanges[i]);
+ this._highlightedSubstringChanges = [];
+ },
+
+ /**
+ * @param {!WebInspector.NetworkRequest} request
+ * @param {boolean} reveal
+ * @param {!RegExp=} regExp
+ */
+ _highlightMatchedRequest: function(request, reveal, regExp)
+ {
+ var node = this._requestGridNode(request);
+ if (!node)
+ return;
+
+ var nameMatched = request.name().match(regExp);
+ var pathMatched = request.path().match(regExp);
+ if (!nameMatched && pathMatched && !this._largerRequestsButton.toggled)
+ this._toggleLargerRequests();
+ var highlightedSubstringChanges = node._highlightMatchedSubstring(regExp);
+ this._highlightedSubstringChanges.push(highlightedSubstringChanges);
+ if (reveal) {
+ node.reveal();
+ this._highlightNode(node);
+ }
+ },
+
+ /**
+ * @param {number} matchedRequestIndex
+ * @param {boolean} reveal
+ */
+ _highlightNthMatchedRequestForSearch: function(matchedRequestIndex, reveal)
+ {
+ var request = this._requestsById[this._matchedRequests[matchedRequestIndex]];
+ if (!request)
+ return;
+ this._removeAllHighlights();
+ this._highlightMatchedRequest(request, reveal, this._searchRegExp);
+ var node = this._requestGridNode(request);
+ if (node)
+ this._currentMatchedRequestIndex = matchedRequestIndex;
+
+ this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.SearchIndexUpdated, this._currentMatchedRequestIndex);
+ },
+
+ /**
+ * @param {string} query
+ * @param {boolean} shouldJump
+ * @param {boolean=} jumpBackwards
+ */
+ performSearch: function(query, shouldJump, jumpBackwards)
+ {
+ var newMatchedRequestIndex = jumpBackwards ? -1 : 0;
+ var currentMatchedRequestId;
+ if (this._currentMatchedRequestIndex !== -1)
+ currentMatchedRequestId = this._matchedRequests[this._currentMatchedRequestIndex];
+
+ this._clearSearchMatchedList();
+ this._searchRegExp = createPlainTextSearchRegex(query, "i");
+
+ var childNodes = this._dataGrid.dataTableBody.childNodes;
+ var requestNodes = Array.prototype.slice.call(childNodes, 0, childNodes.length - 1); // drop the filler row.
+
+ for (var i = 0; i < requestNodes.length; ++i) {
+ var dataGridNode = this._dataGrid.dataGridNodeFromNode(requestNodes[i]);
+ if (dataGridNode.isFilteredOut())
+ continue;
+ if (this._matchRequest(dataGridNode._request) !== -1 && dataGridNode._request.requestId === currentMatchedRequestId) {
+ // Keep current search result the same if it still matches.
+ newMatchedRequestIndex = this._matchedRequests.length - 1;
+ }
+ }
+
+ this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.SearchCountUpdated, this._matchedRequests.length);
+ if (shouldJump) {
+ var index = this._normalizeSearchResultIndex(newMatchedRequestIndex);
+ this._highlightNthMatchedRequestForSearch(index, true);
+ }
+ },
+
+ _normalizeSearchResultIndex: function(index)
+ {
+ return (index + this._matchedRequests.length) % this._matchedRequests.length;
+ },
+
+ /**
+ * @param {!WebInspector.NetworkDataGridNode} node
+ */
+ _applyFilter: function(node)
+ {
+ var request = node._request;
+ var matches = this._resourceTypeFilterUI.accept(request.type.name());
+ if (this._dataURLFilterUI.checked() && request.parsedURL.isDataURL())
+ matches = false;
+ for (var i = 0; matches && (i < this._filters.length); ++i)
+ matches = this._filters[i](request);
+
+ node.element.classList.toggle("filtered-out", !matches);
+ if (matches)
+ this._filteredOutRequests.remove(request);
+ else
+ this._filteredOutRequests.put(request, true);
+ },
+
+ /**
+ * @param {string} query
+ */
+ _parseFilterQuery: function(query)
+ {
+ var parsedQuery = this._suggestionBuilder.parseQuery(query);
+ this._filters = parsedQuery.text.map(this._createTextFilter);
+ for (var key in parsedQuery.filters) {
+ var filterType = /** @type {!WebInspector.NetworkPanel.FilterType} */ (key);
+ this._filters.push(this._createFilter(filterType, parsedQuery.filters[key]));
+ }
+ },
+
+ /**
+ * @param {string} text
+ * @return {!WebInspector.NetworkLogView.Filter}
+ */
+ _createTextFilter: function(text)
+ {
+ var regexp = new RegExp(text.escapeForRegExp(), "i");
+ return WebInspector.NetworkLogView._requestNameOrPathFilter.bind(null, regexp);
+ },
+
+ /**
+ * @param {!WebInspector.NetworkPanel.FilterType} type
+ * @param {string} value
+ * @return {!WebInspector.NetworkLogView.Filter}
+ */
+ _createFilter: function(type, value) {
+ switch (type) {
+ case WebInspector.NetworkPanel.FilterType.Domain:
+ return WebInspector.NetworkLogView._requestDomainFilter.bind(null, value);
+
+ case WebInspector.NetworkPanel.FilterType.HasResponseHeader:
+ return WebInspector.NetworkLogView._requestResponseHeaderFilter.bind(null, value);
+
+ case WebInspector.NetworkPanel.FilterType.Method:
+ return WebInspector.NetworkLogView._requestMethodFilter.bind(null, value);
+
+ case WebInspector.NetworkPanel.FilterType.MimeType:
+ return WebInspector.NetworkLogView._requestMimeTypeFilter.bind(null, value);
+
+ case WebInspector.NetworkPanel.FilterType.SetCookieDomain:
+ return WebInspector.NetworkLogView._requestSetCookieDomainFilter.bind(null, value);
+
+ case WebInspector.NetworkPanel.FilterType.SetCookieName:
+ return WebInspector.NetworkLogView._requestSetCookieNameFilter.bind(null, value);
+
+ case WebInspector.NetworkPanel.FilterType.SetCookieValue:
+ return WebInspector.NetworkLogView._requestSetCookieValueFilter.bind(null, value);
+
+ case WebInspector.NetworkPanel.FilterType.StatusCode:
+ return WebInspector.NetworkLogView._statusCodeFilter.bind(null, value);
+ }
+ return this._createTextFilter(type + ":" + value);
+ },
+
+ _filterRequests: function()
+ {
+ this._removeAllHighlights();
+ this._filteredOutRequests.clear();
+
+ var nodes = this._dataGrid.rootNode().children;
+ for (var i = 0; i < nodes.length; ++i)
+ this._applyFilter(nodes[i]);
+ this._updateSummaryBar();
+ },
+
+ jumpToPreviousSearchResult: function()
+ {
+ if (!this._matchedRequests.length)
+ return;
+ var index = this._normalizeSearchResultIndex(this._currentMatchedRequestIndex - 1);
+ this._highlightNthMatchedRequestForSearch(index, true);
+ },
+
+ jumpToNextSearchResult: function()
+ {
+ if (!this._matchedRequests.length)
+ return;
+ var index = this._normalizeSearchResultIndex(this._currentMatchedRequestIndex + 1);
+ this._highlightNthMatchedRequestForSearch(index, true);
+ },
+
+ searchCanceled: function()
+ {
+ this._clearSearchMatchedList();
+ this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.SearchCountUpdated, 0);
+ },
+
+ revealAndHighlightRequest: function(request)
+ {
+ this._removeAllNodeHighlights();
+
+ var node = this._requestGridNode(request);
+ if (node) {
+ this._dataGrid.element.focus();
+ node.reveal();
+ this._highlightNode(node);
+ }
+ },
+
+ _removeAllNodeHighlights: function()
+ {
+ if (this._highlightedNode) {
+ this._highlightedNode.element.classList.remove("highlighted-row");
+ delete this._highlightedNode;
+ }
+ },
+
+ _highlightNode: function(node)
+ {
+ WebInspector.runCSSAnimationOnce(node.element, "highlighted-row");
+ this._highlightedNode = node;
+ },
+
+ /**
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {string}
+ */
+ _generateCurlCommand: function(request)
+ {
+ var command = ["curl"];
+ // These headers are derived from URL (except "version") and would be added by cURL anyway.
+ var ignoredHeaders = {"host": 1, "method": 1, "path": 1, "scheme": 1, "version": 1};
+
+ function escapeStringWin(str)
+ {
+ /* Replace quote by double quote (but not by \") because it is
+ recognized by both cmd.exe and MS Crt arguments parser.
+
+ Replace % by "%" because it could be expanded to an environment
+ variable value. So %% becomes "%""%". Even if an env variable ""
+ (2 doublequotes) is declared, the cmd.exe will not
+ substitute it with its value.
+
+ Replace each backslash with double backslash to make sure
+ MS Crt arguments parser won't collapse them.
+
+ Replace new line outside of quotes since cmd.exe doesn't let
+ to do it inside.
+ */
+ return "\"" + str.replace(/"/g, "\"\"")
+ .replace(/%/g, "\"%\"")
+ .replace(/\\/g, "\\\\")
+ .replace(/[\r\n]+/g, "\"^$&\"") + "\"";
+ }
+
+ function escapeStringPosix(str)
+ {
+ function escapeCharacter(x)
+ {
+ var code = x.charCodeAt(0);
+ if (code < 256) {
+ // Add leading zero when needed to not care about the next character.
+ return code < 16 ? "\\x0" + code.toString(16) : "\\x" + code.toString(16);
+ }
+ code = code.toString(16);
+ return "\\u" + ("0000" + code).substr(code.length, 4);
+ }
+
+ if (/[^\x20-\x7E]|\'/.test(str)) {
+ // Use ANSI-C quoting syntax.
+ return "$\'" + str.replace(/\\/g, "\\\\")
+ .replace(/\'/g, "\\\'")
+ .replace(/\n/g, "\\n")
+ .replace(/\r/g, "\\r")
+ .replace(/[^\x20-\x7E]/g, escapeCharacter) + "'";
+ } else {
+ // Use single quote syntax.
+ return "'" + str + "'";
+ }
+ }
+
+ // cURL command expected to run on the same platform that DevTools run
+ // (it may be different from the inspected page platform).
+ var escapeString = WebInspector.isWin() ? escapeStringWin : escapeStringPosix;
+
+ command.push(escapeString(request.url).replace(/[[{}\]]/g, "\\$&"));
+
+ var inferredMethod = "GET";
+ var data = [];
+ var requestContentType = request.requestContentType();
+ if (requestContentType && requestContentType.startsWith("application/x-www-form-urlencoded") && request.requestFormData) {
+ data.push("--data");
+ data.push(escapeString(request.requestFormData));
+ ignoredHeaders["content-length"] = true;
+ inferredMethod = "POST";
+ } else if (request.requestFormData) {
+ data.push("--data-binary");
+ data.push(escapeString(request.requestFormData));
+ ignoredHeaders["content-length"] = true;
+ inferredMethod = "POST";
+ }
+
+ if (request.requestMethod !== inferredMethod) {
+ command.push("-X");
+ command.push(request.requestMethod);
+ }
+
+ var requestHeaders = request.requestHeaders();
+ for (var i = 0; i < requestHeaders.length; i++) {
+ var header = requestHeaders[i];
+ var name = header.name.replace(/^:/, ""); // Translate SPDY v3 headers to HTTP headers.
+ if (name.toLowerCase() in ignoredHeaders)
+ continue;
+ command.push("-H");
+ command.push(escapeString(name + ": " + header.value));
+ }
+ command = command.concat(data);
+ command.push("--compressed");
+ return command.join(" ");
+ },
+
+ __proto__: WebInspector.VBox.prototype
+}
+
+/** @typedef {function(!WebInspector.NetworkRequest): boolean} */
+WebInspector.NetworkLogView.Filter;
+
+/**
+ * @param {!RegExp} regex
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {boolean}
+ */
+WebInspector.NetworkLogView._requestNameOrPathFilter = function(regex, request)
+{
+ return regex.test(request.name()) || regex.test(request.path());
+}
+
+/**
+ * @param {string} value
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {boolean}
+ */
+WebInspector.NetworkLogView._requestDomainFilter = function(value, request)
+{
+ return request.domain === value;
+}
+
+/**
+ * @param {string} value
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {boolean}
+ */
+WebInspector.NetworkLogView._requestResponseHeaderFilter = function(value, request)
+{
+ return request.responseHeaderValue(value) !== undefined;
+}
+
+/**
+ * @param {string} value
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {boolean}
+ */
+WebInspector.NetworkLogView._requestMethodFilter = function(value, request)
+{
+ return request.requestMethod === value;
+}
+
+/**
+ * @param {string} value
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {boolean}
+ */
+WebInspector.NetworkLogView._requestMimeTypeFilter = function(value, request)
+{
+ return request.mimeType === value;
+}
+
+/**
+ * @param {string} value
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {boolean}
+ */
+WebInspector.NetworkLogView._requestSetCookieDomainFilter = function(value, request)
+{
+ var cookies = request.responseCookies;
+ for (var i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
+ if (cookies[i].domain() === value)
+ return false;
+ }
+ return false;
+}
+
+/**
+ * @param {string} value
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {boolean}
+ */
+WebInspector.NetworkLogView._requestSetCookieNameFilter = function(value, request)
+{
+ var cookies = request.responseCookies;
+ for (var i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
+ if (cookies[i].name() === value)
+ return false;
+ }
+ return false;
+}
+
+/**
+ * @param {string} value
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {boolean}
+ */
+WebInspector.NetworkLogView._requestSetCookieValueFilter = function(value, request)
+{
+ var cookies = request.responseCookies;
+ for (var i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
+ if (cookies[i].value() === value)
+ return false;
+ }
+ return false;
+}
+
+/**
+ * @param {string} value
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {boolean}
+ */
+WebInspector.NetworkLogView._statusCodeFilter = function(value, request)
+{
+ return ("" + request.statusCode) === value;
+}
+
+/**
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {boolean}
+ */
+WebInspector.NetworkLogView.HTTPRequestsFilter = function(request)
+{
+ return request.parsedURL.isValid && (request.scheme in WebInspector.NetworkLogView.HTTPSchemas);
+}
+
+/**
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {boolean}
+ */
+WebInspector.NetworkLogView.NonDevToolsRequestsFilter = function(request)
+{
+ return !WebInspector.NetworkManager.hasDevToolsRequestHeader(request);
+}
+
+/**
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {boolean}
+ */
+WebInspector.NetworkLogView.FinishedRequestsFilter = function(request)
+{
+ return request.finished;
+}
+
+WebInspector.NetworkLogView.EventTypes = {
+ ViewCleared: "ViewCleared",
+ RowSizeChanged: "RowSizeChanged",
+ RequestSelected: "RequestSelected",
+ SearchCountUpdated: "SearchCountUpdated",
+ SearchIndexUpdated: "SearchIndexUpdated"
+};
+
+/**
+ * @constructor
+ * @implements {WebInspector.ContextMenu.Provider}
+ * @implements {WebInspector.Searchable}
+ * @extends {WebInspector.Panel}
+ */
+WebInspector.NetworkPanel = function()
+{
+ WebInspector.Panel.call(this, "network");
+ this.registerRequiredCSS("networkPanel.css");
+ this._injectStyles();
+
+ this._panelStatusBarElement = this.element.createChild("div", "panel-status-bar");
+ this._filterBar = new WebInspector.FilterBar();
+ this._filtersContainer = this.element.createChild("div", "network-filters-header hidden");
+ this._filtersContainer.appendChild(this._filterBar.filtersElement());
+ this._filterBar.addEventListener(WebInspector.FilterBar.Events.FiltersToggled, this._onFiltersToggled, this);
+ this._filterBar.setName("networkPanel");
+
+ this._searchableView = new WebInspector.SearchableView(this);
+ this._searchableView.show(this.element);
+ this._contentsElement = this._searchableView.element;
+
+ this._splitView = new WebInspector.SplitView(true, false, "networkPanelSplitViewState");
+ this._splitView.show(this._contentsElement);
+ this._splitView.hideMain();
+
+ var defaultColumnsVisibility = WebInspector.NetworkLogView._defaultColumnsVisibility;
+ var networkLogColumnsVisibilitySetting = WebInspector.settings.createSetting("networkLogColumnsVisibility", defaultColumnsVisibility);
+ var savedColumnsVisibility = networkLogColumnsVisibilitySetting.get();
+ var columnsVisibility = {};
+ for (var columnId in defaultColumnsVisibility)
+ columnsVisibility[columnId] = savedColumnsVisibility.hasOwnProperty(columnId) ? savedColumnsVisibility[columnId] : defaultColumnsVisibility[columnId];
+ networkLogColumnsVisibilitySetting.set(columnsVisibility);
+
+ this._networkLogView = new WebInspector.NetworkLogView(this._filterBar, networkLogColumnsVisibilitySetting);
+ this._networkLogView.show(this._splitView.sidebarElement());
+
+ var viewsContainerView = new WebInspector.VBox();
+ this._viewsContainerElement = viewsContainerView.element;
+ this._viewsContainerElement.id = "network-views";
+ if (!this._networkLogView.useLargeRows)
+ this._viewsContainerElement.classList.add("small");
+ viewsContainerView.show(this._splitView.mainElement());
+
+ this._networkLogView.addEventListener(WebInspector.NetworkLogView.EventTypes.ViewCleared, this._onViewCleared, this);
+ this._networkLogView.addEventListener(WebInspector.NetworkLogView.EventTypes.RowSizeChanged, this._onRowSizeChanged, this);
+ this._networkLogView.addEventListener(WebInspector.NetworkLogView.EventTypes.RequestSelected, this._onRequestSelected, this);
+ this._networkLogView.addEventListener(WebInspector.NetworkLogView.EventTypes.SearchCountUpdated, this._onSearchCountUpdated, this);
+ this._networkLogView.addEventListener(WebInspector.NetworkLogView.EventTypes.SearchIndexUpdated, this._onSearchIndexUpdated, this);
+
+ this._closeButtonElement = this._viewsContainerElement.createChild("div", "close-button");
+ this._closeButtonElement.id = "network-close-button";
+ this._closeButtonElement.addEventListener("click", this._toggleGridMode.bind(this), false);
+ this._viewsContainerElement.appendChild(this._closeButtonElement);
+
+ for (var i = 0; i < this._networkLogView.statusBarItems.length; ++i)
+ this._panelStatusBarElement.appendChild(this._networkLogView.statusBarItems[i]);
+
+ /**
+ * @this {WebInspector.NetworkPanel}
+ * @return {?WebInspector.SourceFrame}
+ */
+ function sourceFrameGetter()
+ {
+ return this._networkItemView.currentSourceFrame();
+ }
+ WebInspector.GoToLineDialog.install(this, sourceFrameGetter.bind(this));
+}
+
+/** @enum {string} */
+WebInspector.NetworkPanel.FilterType = {
+ Domain: "Domain",
+ HasResponseHeader: "HasResponseHeader",
+ Method: "Method",
+ MimeType: "MimeType",
+ SetCookieDomain: "SetCookieDomain",
+ SetCookieName: "SetCookieName",
+ SetCookieValue: "SetCookieValue",
+ StatusCode: "StatusCode"
+};
+
+/** @type {!Array.<string>} */
+WebInspector.NetworkPanel._searchKeys = Object.values(WebInspector.NetworkPanel.FilterType);
+
+WebInspector.NetworkPanel.prototype = {
+ _onFiltersToggled: function(event)
+ {
+ var toggled = /** @type {boolean} */ (event.data);
+ this._filtersContainer.classList.toggle("hidden", !toggled);
+ this.element.classList.toggle("filters-toggled", toggled);
+ this.doResize();
+ },
+
+ /**
+ * @return {!Array.<!Element>}
+ */
+ elementsToRestoreScrollPositionsFor: function()
+ {
+ return this._networkLogView.elementsToRestoreScrollPositionsFor();
+ },
+
+ /**
+ * @return {!WebInspector.SearchableView}
+ */
+ searchableView: function()
+ {
+ return this._searchableView;
+ },
+
+ // FIXME: only used by the layout tests, should not be exposed.
+ _reset: function()
+ {
+ this._networkLogView._reset();
+ },
+
+ handleShortcut: function(event)
+ {
+ if (this._viewingRequestMode && event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code) {
+ this._toggleGridMode();
+ event.handled = true;
+ return;
+ }
+
+ WebInspector.Panel.prototype.handleShortcut.call(this, event);
+ },
+
+ wasShown: function()
+ {
+ WebInspector.Panel.prototype.wasShown.call(this);
+ },
+
+ get requests()
+ {
+ return this._networkLogView.requests;
+ },
+
+ /**
+ * @param {!WebInspector.NetworkRequest} request
+ */
+ revealAndHighlightRequest: function(request)
+ {
+ this._toggleGridMode();
+ if (request)
+ this._networkLogView.revealAndHighlightRequest(request);
+ },
+
+ _onViewCleared: function(event)
+ {
+ this._closeVisibleRequest();
+ this._toggleGridMode();
+ this._viewsContainerElement.removeChildren();
+ this._viewsContainerElement.appendChild(this._closeButtonElement);
+ },
+
+ _onRowSizeChanged: function(event)
+ {
+ this._viewsContainerElement.classList.toggle("small", !event.data.largeRows);
+ },
+
+ _onSearchCountUpdated: function(event)
+ {
+ this._searchableView.updateSearchMatchesCount(event.data);
+ },
+
+ _onSearchIndexUpdated: function(event)
+ {
+ this._searchableView.updateCurrentMatchIndex(event.data);
+ },
+
+ _onRequestSelected: function(event)
+ {
+ this._showRequest(event.data);
+ },
+
+ /**
+ * @param {?WebInspector.NetworkRequest} request
+ */
+ _showRequest: function(request)
+ {
+ if (!request)
+ return;
+
+ this._toggleViewingRequestMode();
+
+ if (this._networkItemView) {
+ this._networkItemView.detach();
+ delete this._networkItemView;
+ }
+
+ var view = new WebInspector.NetworkItemView(request);
+ view.show(this._viewsContainerElement);
+ this._networkItemView = view;
+ },
+
+ _closeVisibleRequest: function()
+ {
+ this.element.classList.remove("viewing-resource");
+
+ if (this._networkItemView) {
+ this._networkItemView.detach();
+ delete this._networkItemView;
+ }
+ },
+
+ _toggleGridMode: function()
+ {
+ if (this._viewingRequestMode) {
+ this._viewingRequestMode = false;
+ this.element.classList.remove("viewing-resource");
+ this._splitView.hideMain();
+ }
+
+ this._networkLogView.switchToDetailedView();
+ this._networkLogView.allowPopover = true;
+ this._networkLogView._allowRequestSelection = false;
+ },
+
+ _toggleViewingRequestMode: function()
+ {
+ if (this._viewingRequestMode)
+ return;
+ this._viewingRequestMode = true;
+
+ this.element.classList.add("viewing-resource");
+ this._splitView.showBoth();
+ this._networkLogView.allowPopover = false;
+ this._networkLogView._allowRequestSelection = true;
+ this._networkLogView.switchToBriefView();
+ },
+
+ /**
+ * @param {string} query
+ * @param {boolean} shouldJump
+ * @param {boolean=} jumpBackwards
+ */
+ performSearch: function(query, shouldJump, jumpBackwards)
+ {
+ this._networkLogView.performSearch(query, shouldJump, jumpBackwards);
+ },
+
+ jumpToPreviousSearchResult: function()
+ {
+ this._networkLogView.jumpToPreviousSearchResult();
+ },
+
+ jumpToNextSearchResult: function()
+ {
+ this._networkLogView.jumpToNextSearchResult();
+ },
+
+ searchCanceled: function()
+ {
+ this._networkLogView.searchCanceled();
+ },
+
+ /**
+ * @param {!Event} event
+ * @param {!WebInspector.ContextMenu} contextMenu
+ * @param {!Object} target
+ * @this {WebInspector.NetworkPanel}
+ */
+ appendApplicableItems: function(event, contextMenu, target)
+ {
+ /**
+ * @this {WebInspector.NetworkPanel}
+ */
+ function reveal(request)
+ {
+ WebInspector.inspectorView.setCurrentPanel(this);
+ this.revealAndHighlightRequest(request);
+ }
+
+ /**
+ * @this {WebInspector.NetworkPanel}
+ */
+ function appendRevealItem(request)
+ {
+ var revealText = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Network panel" : "Reveal in Network Panel");
+ contextMenu.appendItem(revealText, reveal.bind(this, request));
+ }
+
+ if (target instanceof WebInspector.Resource) {
+ var resource = /** @type {!WebInspector.Resource} */ (target);
+ if (resource.request)
+ appendRevealItem.call(this, resource.request);
+ return;
+ }
+ if (target instanceof WebInspector.UISourceCode) {
+ var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (target);
+ var resource = WebInspector.resourceForURL(uiSourceCode.url);
+ if (resource && resource.request)
+ appendRevealItem.call(this, resource.request);
+ return;
+ }
+
+ if (!(target instanceof WebInspector.NetworkRequest))
+ return;
+ var request = /** @type {!WebInspector.NetworkRequest} */ (target);
+ if (this._networkItemView && this._networkItemView.isShowing() && this._networkItemView.request() === request)
+ return;
+
+ appendRevealItem.call(this, request);
+ },
+
+ _injectStyles: function()
+ {
+ var style = document.createElement("style");
+ var rules = [];
+
+ var columns = WebInspector.NetworkLogView._defaultColumnsVisibility;
+
+ var hideSelectors = [];
+ var bgSelectors = [];
+ for (var columnId in columns) {
+ hideSelectors.push("#network-container .hide-" + columnId + "-column ." + columnId + "-column");
+ bgSelectors.push(".network-log-grid.data-grid td." + columnId + "-column");
+ }
+ rules.push(hideSelectors.join(", ") + "{border-left: 0 none transparent;}");
+ rules.push(bgSelectors.join(", ") + "{background-color: rgba(0, 0, 0, 0.07);}");
+
+ style.textContent = rules.join("\n");
+ document.head.appendChild(style);
+ },
+
+ __proto__: WebInspector.Panel.prototype
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.ContextMenu.Provider}
+ */
+WebInspector.NetworkPanel.ContextMenuProvider = function()
+{
+}
+
+WebInspector.NetworkPanel.ContextMenuProvider.prototype = {
+ /**
+ * @param {!Event} event
+ * @param {!WebInspector.ContextMenu} contextMenu
+ * @param {!Object} target
+ */
+ appendApplicableItems: function(event, contextMenu, target)
+ {
+ WebInspector.inspectorView.panel("network").appendApplicableItems(event, contextMenu, target);
+ }
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.Revealer}
+ */
+WebInspector.NetworkPanel.RequestRevealer = function()
+{
+}
+
+WebInspector.NetworkPanel.RequestRevealer.prototype = {
+ /**
+ * @param {!Object} request
+ */
+ reveal: function(request)
+ {
+ if (request instanceof WebInspector.NetworkRequest)
+ /** @type {!WebInspector.NetworkPanel} */ (WebInspector.inspectorView.showPanel("network")).revealAndHighlightRequest(request);
+ }
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.TimelineGrid.Calculator}
+ */
+WebInspector.NetworkBaseCalculator = function()
+{
+}
+
+WebInspector.NetworkBaseCalculator.prototype = {
+ /**
+ * @param {number} time
+ * @return {number}
+ */
+ computePosition: function(time)
+ {
+ return (time - this._minimumBoundary) / this.boundarySpan() * this._workingArea;
+ },
+
+ /**
+ * @return {!{start: number, middle: number, end: number}}
+ */
+ computeBarGraphPercentages: function(item)
+ {
+ return {start: 0, middle: 0, end: (this._value(item) / this.boundarySpan()) * 100};
+ },
+
+ /**
+ * @return {!{left: string, right: string, tooltip: string}}
+ */
+ computeBarGraphLabels: function(item)
+ {
+ const label = this.formatTime(this._value(item));
+ return {left: label, right: label, tooltip: label};
+ },
+
+ /**
+ * @return {number}
+ */
+ boundarySpan: function()
+ {
+ return this._maximumBoundary - this._minimumBoundary;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ updateBoundaries: function(item)
+ {
+ this._minimumBoundary = 0;
+
+ var value = this._value(item);
+ if (typeof this._maximumBoundary === "undefined" || value > this._maximumBoundary) {
+ this._maximumBoundary = value;
+ return true;
+ }
+ return false;
+ },
+
+ reset: function()
+ {
+ delete this._minimumBoundary;
+ delete this._maximumBoundary;
+ },
+
+ /**
+ * @return {number}
+ */
+ maximumBoundary: function()
+ {
+ return this._maximumBoundary;
+ },
+
+ /**
+ * @return {number}
+ */
+ minimumBoundary: function()
+ {
+ return this._minimumBoundary;
+ },
+
+ /**
+ * @return {number}
+ */
+ zeroTime: function()
+ {
+ return this._minimumBoundary;
+ },
+
+ /**
+ * @return {number}
+ */
+ _value: function(item)
+ {
+ return 0;
+ },
+
+ /**
+ * @param {number} value
+ * @param {number=} precision
+ * @return {string}
+ */
+ formatTime: function(value, precision)
+ {
+ return value.toString();
+ },
+
+ setDisplayWindow: function(clientWidth)
+ {
+ this._workingArea = clientWidth;
+ },
+
+ /**
+ * @return {number}
+ */
+ paddingLeft: function()
+ {
+ return 0;
+ }
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.NetworkBaseCalculator}
+ */
+WebInspector.NetworkTimeCalculator = function(startAtZero)
+{
+ WebInspector.NetworkBaseCalculator.call(this);
+ this.startAtZero = startAtZero;
+}
+
+WebInspector.NetworkTimeCalculator.prototype = {
+ /**
+ * @param {!WebInspector.NetworkRequest} request
+ * @return {!{start: number, middle: number, end: number}}
+ */
+ computeBarGraphPercentages: function(request)
+ {
+ if (request.startTime !== -1)
+ var start = ((request.startTime - this._minimumBoundary) / this.boundarySpan()) * 100;
+ else
+ var start = 0;
+
+ if (request.responseReceivedTime !== -1)
+ var middle = ((request.responseReceivedTime - this._minimumBoundary) / this.boundarySpan()) * 100;
+ else
+ var middle = (this.startAtZero ? start : 100);
+
+ if (request.endTime !== -1)
+ var end = ((request.endTime - this._minimumBoundary) / this.boundarySpan()) * 100;
+ else
+ var end = (this.startAtZero ? middle : 100);
+
+ if (this.startAtZero) {
+ end -= start;
+ middle -= start;
+ start = 0;
+ }
+
+ return {start: start, middle: middle, end: end};
+ },
+
+ /**
+ * @return {number}
+ */
+ computePercentageFromEventTime: function(eventTime)
+ {
+ // This function computes a percentage in terms of the total loading time
+ // of a specific event. If startAtZero is set, then this is useless, and we
+ // want to return 0.
+ if (eventTime !== -1 && !this.startAtZero)
+ return ((eventTime - this._minimumBoundary) / this.boundarySpan()) * 100;
+
+ return 0;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ updateBoundariesForEventTime: function(eventTime)
+ {
+ if (eventTime === -1 || this.startAtZero)
+ return false;
+
+ if (typeof this._maximumBoundary === "undefined" || eventTime > this._maximumBoundary) {
+ this._maximumBoundary = eventTime;
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * @return {!{left: string, right: string, tooltip: (string|undefined)}}
+ */
+ computeBarGraphLabels: function(request)
+ {
+ var rightLabel = "";
+ if (request.responseReceivedTime !== -1 && request.endTime !== -1)
+ rightLabel = Number.secondsToString(request.endTime - request.responseReceivedTime);
+
+ var hasLatency = request.latency > 0;
+ if (hasLatency)
+ var leftLabel = Number.secondsToString(request.latency);
+ else
+ var leftLabel = rightLabel;
+
+ if (request.timing)
+ return {left: leftLabel, right: rightLabel};
+
+ if (hasLatency && rightLabel) {
+ var total = Number.secondsToString(request.duration);
+ var tooltip = WebInspector.UIString("%s latency, %s download (%s total)", leftLabel, rightLabel, total);
+ } else if (hasLatency)
+ var tooltip = WebInspector.UIString("%s latency", leftLabel);
+ else if (rightLabel)
+ var tooltip = WebInspector.UIString("%s download", rightLabel);
+
+ if (request.cached)
+ tooltip = WebInspector.UIString("%s (from cache)", tooltip);
+ return {left: leftLabel, right: rightLabel, tooltip: tooltip};
+ },
+
+ /**
+ * @return {boolean}
+ */
+ updateBoundaries: function(request)
+ {
+ var didChange = false;
+
+ var lowerBound;
+ if (this.startAtZero)
+ lowerBound = 0;
+ else
+ lowerBound = this._lowerBound(request);
+
+ if (lowerBound !== -1 && (typeof this._minimumBoundary === "undefined" || lowerBound < this._minimumBoundary)) {
+ this._minimumBoundary = lowerBound;
+ didChange = true;
+ }
+
+ var upperBound = this._upperBound(request);
+ if (upperBound !== -1 && (typeof this._maximumBoundary === "undefined" || upperBound > this._maximumBoundary)) {
+ this._maximumBoundary = upperBound;
+ didChange = true;
+ }
+
+ return didChange;
+ },
+
+ /**
+ * @return {string}
+ */
+ formatTime: function(value)
+ {
+ return Number.secondsToString(value);
+ },
+
+ _lowerBound: function(request)
+ {
+ return 0;
+ },
+
+ _upperBound: function(request)
+ {
+ return 0;
+ },
+
+ __proto__: WebInspector.NetworkBaseCalculator.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.NetworkTimeCalculator}
+ */
+WebInspector.NetworkTransferTimeCalculator = function()
+{
+ WebInspector.NetworkTimeCalculator.call(this, false);
+}
+
+WebInspector.NetworkTransferTimeCalculator.prototype = {
+ /**
+ * @param {number} value
+ * @return {string}
+ */
+ formatTime: function(value)
+ {
+ return Number.secondsToString(value - this.zeroTime());
+ },
+
+ _lowerBound: function(request)
+ {
+ return request.startTime;
+ },
+
+ _upperBound: function(request)
+ {
+ return request.endTime;
+ },
+
+ __proto__: WebInspector.NetworkTimeCalculator.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.NetworkTimeCalculator}
+ */
+WebInspector.NetworkTransferDurationCalculator = function()
+{
+ WebInspector.NetworkTimeCalculator.call(this, true);
+}
+
+WebInspector.NetworkTransferDurationCalculator.prototype = {
+ /**
+ * @param {number} value
+ * @return {string}
+ */
+ formatTime: function(value)
+ {
+ return Number.secondsToString(value);
+ },
+
+ _upperBound: function(request)
+ {
+ return request.duration;
+ },
+
+ __proto__: WebInspector.NetworkTimeCalculator.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.DataGridNode}
+ * @param {!WebInspector.NetworkLogView} parentView
+ * @param {!WebInspector.NetworkRequest} request
+ */
+WebInspector.NetworkDataGridNode = function(parentView, request)
+{
+ WebInspector.DataGridNode.call(this, {});
+ this._parentView = parentView;
+ this._request = request;
+ this._linkifier = new WebInspector.Linkifier();
+}
+
+WebInspector.NetworkDataGridNode.prototype = {
+ /** override */
+ createCells: function()
+ {
+ this._nameCell = null;
+ this._timelineCell = null;
+
+ var element = this._element;
+ element.classList.toggle("network-error-row", this._isFailed());
+ element.classList.toggle("resource-cached", this._request.cached);
+ var typeClassName = "network-type-" + this._request.type.name();
+ if (!element.classList.contains(typeClassName)) {
+ element.removeMatchingStyleClasses("network-type-\\w+");
+ element.classList.add(typeClassName);
+ }
+
+ WebInspector.DataGridNode.prototype.createCells.call(this);
+
+ this.refreshGraph(this._parentView.calculator);
+ },
+
+ /**
+ * @override
+ * @param {string} columnIdentifier
+ * @return {!Element}
+ */
+ createCell: function(columnIdentifier)
+ {
+ var cell = this.createTD(columnIdentifier);
+ switch (columnIdentifier) {
+ case "name": this._renderNameCell(cell); break;
+ case "timeline": this._createTimelineBar(cell); break;
+ case "method": cell.setTextAndTitle(this._request.requestMethod); break;
+ case "status": this._renderStatusCell(cell); break;
+ case "scheme": cell.setTextAndTitle(this._request.scheme); break;
+ case "domain": cell.setTextAndTitle(this._request.domain); break;
+ case "remoteAddress": cell.setTextAndTitle(this._request.remoteAddress()); break;
+ case "cookies": cell.setTextAndTitle(this._arrayLength(this._request.requestCookies)); break;
+ case "setCookies": cell.setTextAndTitle(this._arrayLength(this._request.responseCookies)); break;
+ case "type": this._renderTypeCell(cell); break;
+ case "initiator": this._renderInitiatorCell(cell); break;
+ case "size": this._renderSizeCell(cell); break;
+ case "time": this._renderTimeCell(cell); break;
+ default: cell.setTextAndTitle(this._request.responseHeaderValue(columnIdentifier) || ""); break;
+ }
+
+ return cell;
+ },
+
+ /**
+ * @param {?Array} array
+ * @return {string}
+ */
+ _arrayLength: function(array)
+ {
+ return array ? "" + array.length : "";
+ },
+
+ wasDetached: function()
+ {
+ this._linkifier.reset();
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isFilteredOut: function()
+ {
+ return !!this._parentView._filteredOutRequests.get(this._request);
+ },
+
+ _onClick: function()
+ {
+ if (!this._parentView._allowRequestSelection)
+ this.select();
+ },
+
+ select: function()
+ {
+ this._parentView.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.RequestSelected, this._request);
+ WebInspector.DataGridNode.prototype.select.apply(this, arguments);
+
+ WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, {
+ action: WebInspector.UserMetrics.UserActionNames.NetworkRequestSelected,
+ url: this._request.url
+ });
+ },
+
+ _highlightMatchedSubstring: function(regexp)
+ {
+ var domChanges = [];
+ var matchInfo = this._element.textContent.match(regexp);
+ if (matchInfo)
+ WebInspector.highlightSearchResult(this._nameCell, matchInfo.index, matchInfo[0].length, domChanges);
+ return domChanges;
+ },
+
+ _openInNewTab: function()
+ {
+ InspectorFrontendHost.openInNewTab(this._request.url);
+ },
+
+ get selectable()
+ {
+ return this._parentView._allowRequestSelection && !this.isFilteredOut();
+ },
+
+ /**
+ * @param {!Element} cell
+ */
+ _createTimelineBar: function(cell)
+ {
+ cell = cell.createChild("div");
+ this._timelineCell = cell;
+
+ cell.className = "network-graph-side";
+
+ this._barAreaElement = document.createElement("div");
+ // this._barAreaElement.className = "network-graph-bar-area hidden";
+ this._barAreaElement.className = "network-graph-bar-area";
+ this._barAreaElement.request = this._request;
+ cell.appendChild(this._barAreaElement);
+
+ this._barLeftElement = document.createElement("div");
+ this._barLeftElement.className = "network-graph-bar waiting";
+ this._barAreaElement.appendChild(this._barLeftElement);
+
+ this._barRightElement = document.createElement("div");
+ this._barRightElement.className = "network-graph-bar";
+ this._barAreaElement.appendChild(this._barRightElement);
+
+
+ this._labelLeftElement = document.createElement("div");
+ this._labelLeftElement.className = "network-graph-label waiting";
+ this._barAreaElement.appendChild(this._labelLeftElement);
+
+ this._labelRightElement = document.createElement("div");
+ this._labelRightElement.className = "network-graph-label";
+ this._barAreaElement.appendChild(this._labelRightElement);
+
+ cell.addEventListener("mouseover", this._refreshLabelPositions.bind(this), false);
+ },
+
+ /**
+ * @return {boolean}
+ */
+ _isFailed: function()
+ {
+ return !!this._request.failed || (this._request.statusCode >= 400);
+ },
+
+ /**
+ * @param {!Element} cell
+ */
+ _renderNameCell: function(cell)
+ {
+ this._nameCell = cell;
+ cell.addEventListener("click", this._onClick.bind(this), false);
+ cell.addEventListener("dblclick", this._openInNewTab.bind(this), false);
+
+ if (this._request.type === WebInspector.resourceTypes.Image) {
+ var previewImage = document.createElement("img");
+ previewImage.className = "image-network-icon-preview";
+ this._request.populateImageSource(previewImage);
+
+ var iconElement = document.createElement("div");
+ iconElement.className = "icon";
+ iconElement.appendChild(previewImage);
+ } else {
+ var iconElement = document.createElement("img");
+ iconElement.className = "icon";
+ }
+ cell.appendChild(iconElement);
+ cell.appendChild(document.createTextNode(this._request.name()));
+ this._appendSubtitle(cell, this._request.path());
+ cell.title = this._request.url;
+ },
+
+ /**
+ * @param {!Element} cell
+ */
+ _renderStatusCell: function(cell)
+ {
+ cell.classList.toggle("network-dim-cell", !this._isFailed() && (this._request.cached || !this._request.statusCode));
+
+ if (this._request.failed && !this._request.canceled) {
+ var failText = WebInspector.UIString("(failed)");
+ if (this._request.localizedFailDescription) {
+ cell.appendChild(document.createTextNode(failText));
+ this._appendSubtitle(cell, this._request.localizedFailDescription);
+ cell.title = failText + " " + this._request.localizedFailDescription;
+ } else
+ cell.setTextAndTitle(failText);
+ } else if (this._request.statusCode) {
+ cell.appendChild(document.createTextNode("" + this._request.statusCode));
+ this._appendSubtitle(cell, this._request.statusText);
+ cell.title = this._request.statusCode + " " + this._request.statusText;
+ } else if (this._request.parsedURL.isDataURL()) {
+ cell.setTextAndTitle(WebInspector.UIString("(data)"));
+ } else if (this._request.isPingRequest()) {
+ cell.setTextAndTitle(WebInspector.UIString("(ping)"));
+ } else if (this._request.canceled) {
+ cell.setTextAndTitle(WebInspector.UIString("(canceled)"));
+ } else if (this._request.finished) {
+ cell.setTextAndTitle(WebInspector.UIString("Finished"));
+ } else {
+ cell.setTextAndTitle(WebInspector.UIString("(pending)"));
+ }
+ },
+
+ /**
+ * @param {!Element} cell
+ */
+ _renderTypeCell: function(cell)
+ {
+ if (this._request.mimeType) {
+ cell.setTextAndTitle(this._request.mimeType);
+ } else {
+ cell.classList.toggle("network-dim-cell", !this._request.isPingRequest());
+ cell.setTextAndTitle(this._request.requestContentType() || "");
+ }
+ },
+
+ /**
+ * @param {!Element} cell
+ */
+ _renderInitiatorCell: function(cell)
+ {
+ var request = this._request;
+ var initiator = request.initiatorInfo();
+
+ switch (initiator.type) {
+ case WebInspector.NetworkRequest.InitiatorType.Parser:
+ cell.title = initiator.url + ":" + initiator.lineNumber;
+ cell.appendChild(WebInspector.linkifyResourceAsNode(initiator.url, initiator.lineNumber - 1));
+ this._appendSubtitle(cell, WebInspector.UIString("Parser"));
+ break;
+
+ case WebInspector.NetworkRequest.InitiatorType.Redirect:
+ cell.title = initiator.url;
+ console.assert(request.redirectSource);
+ var redirectSource = /** @type {!WebInspector.NetworkRequest} */ (request.redirectSource);
+ cell.appendChild(WebInspector.linkifyRequestAsNode(redirectSource));
+ this._appendSubtitle(cell, WebInspector.UIString("Redirect"));
+ break;
+
+ case WebInspector.NetworkRequest.InitiatorType.Script:
+ var urlElement = this._linkifier.linkifyLocation(request.target(), initiator.url, initiator.lineNumber - 1, initiator.columnNumber - 1);
+ urlElement.title = "";
+ cell.appendChild(urlElement);
+ this._appendSubtitle(cell, WebInspector.UIString("Script"));
+ cell.classList.add("network-script-initiated");
+ cell.request = request;
+ break;
+
+ default:
+ cell.title = "";
+ cell.classList.add("network-dim-cell");
+ cell.setTextAndTitle(WebInspector.UIString("Other"));
+ }
+ },
+
+ /**
+ * @param {!Element} cell
+ */
+ _renderSizeCell: function(cell)
+ {
+ if (this._request.cached) {
+ cell.setTextAndTitle(WebInspector.UIString("(from cache)"));
+ cell.classList.add("network-dim-cell");
+ } else {
+ var resourceSize = Number.bytesToString(this._request.resourceSize);
+ var transferSize = Number.bytesToString(this._request.transferSize);
+ cell.setTextAndTitle(transferSize);
+ this._appendSubtitle(cell, resourceSize);
+ }
+ },
+
+ /**
+ * @param {!Element} cell
+ */
+ _renderTimeCell: function(cell)
+ {
+ if (this._request.duration > 0) {
+ cell.setTextAndTitle(Number.secondsToString(this._request.duration));
+ this._appendSubtitle(cell, Number.secondsToString(this._request.latency));
+ } else {
+ cell.classList.add("network-dim-cell");
+ cell.setTextAndTitle(WebInspector.UIString("Pending"));
+ }
+ },
+
+ _appendSubtitle: function(cellElement, subtitleText)
+ {
+ var subtitleElement = document.createElement("div");
+ subtitleElement.className = "network-cell-subtitle";
+ subtitleElement.textContent = subtitleText;
+ cellElement.appendChild(subtitleElement);
+ },
+
+ refreshGraph: function(calculator)
+ {
+ if (!this._timelineCell)
+ return;
+
+ var percentages = calculator.computeBarGraphPercentages(this._request);
+ this._percentages = percentages;
+
+ this._barAreaElement.classList.remove("hidden");
+
+ this._barLeftElement.style.setProperty("left", percentages.start + "%");
+ this._barRightElement.style.setProperty("right", (100 - percentages.end) + "%");
+
+ this._barLeftElement.style.setProperty("right", (100 - percentages.end) + "%");
+ this._barRightElement.style.setProperty("left", percentages.middle + "%");
+
+ var labels = calculator.computeBarGraphLabels(this._request);
+ this._labelLeftElement.textContent = labels.left;
+ this._labelRightElement.textContent = labels.right;
+
+ var tooltip = (labels.tooltip || "");
+ this._barLeftElement.title = tooltip;
+ this._labelLeftElement.title = tooltip;
+ this._labelRightElement.title = tooltip;
+ this._barRightElement.title = tooltip;
+ },
+
+ _refreshLabelPositions: function()
+ {
+ if (!this._percentages)
+ return;
+ this._labelLeftElement.style.removeProperty("left");
+ this._labelLeftElement.style.removeProperty("right");
+ this._labelLeftElement.classList.remove("before");
+ this._labelLeftElement.classList.remove("hidden");
+
+ this._labelRightElement.style.removeProperty("left");
+ this._labelRightElement.style.removeProperty("right");
+ this._labelRightElement.classList.remove("after");
+ this._labelRightElement.classList.remove("hidden");
+
+ const labelPadding = 10;
+ const barRightElementOffsetWidth = this._barRightElement.offsetWidth;
+ const barLeftElementOffsetWidth = this._barLeftElement.offsetWidth;
+
+ if (this._barLeftElement) {
+ var leftBarWidth = barLeftElementOffsetWidth - labelPadding;
+ var rightBarWidth = (barRightElementOffsetWidth - barLeftElementOffsetWidth) - labelPadding;
+ } else {
+ var leftBarWidth = (barLeftElementOffsetWidth - barRightElementOffsetWidth) - labelPadding;
+ var rightBarWidth = barRightElementOffsetWidth - labelPadding;
+ }
+
+ const labelLeftElementOffsetWidth = this._labelLeftElement.offsetWidth;
+ const labelRightElementOffsetWidth = this._labelRightElement.offsetWidth;
+
+ const labelBefore = (labelLeftElementOffsetWidth > leftBarWidth);
+ const labelAfter = (labelRightElementOffsetWidth > rightBarWidth);
+ const graphElementOffsetWidth = this._timelineCell.offsetWidth;
+
+ if (labelBefore && (graphElementOffsetWidth * (this._percentages.start / 100)) < (labelLeftElementOffsetWidth + 10))
+ var leftHidden = true;
+
+ if (labelAfter && (graphElementOffsetWidth * ((100 - this._percentages.end) / 100)) < (labelRightElementOffsetWidth + 10))
+ var rightHidden = true;
+
+ if (barLeftElementOffsetWidth == barRightElementOffsetWidth) {
+ // The left/right label data are the same, so a before/after label can be replaced by an on-bar label.
+ if (labelBefore && !labelAfter)
+ leftHidden = true;
+ else if (labelAfter && !labelBefore)
+ rightHidden = true;
+ }
+
+ if (labelBefore) {
+ if (leftHidden)
+ this._labelLeftElement.classList.add("hidden");
+ this._labelLeftElement.style.setProperty("right", (100 - this._percentages.start) + "%");
+ this._labelLeftElement.classList.add("before");
+ } else {
+ this._labelLeftElement.style.setProperty("left", this._percentages.start + "%");
+ this._labelLeftElement.style.setProperty("right", (100 - this._percentages.middle) + "%");
+ }
+
+ if (labelAfter) {
+ if (rightHidden)
+ this._labelRightElement.classList.add("hidden");
+ this._labelRightElement.style.setProperty("left", this._percentages.end + "%");
+ this._labelRightElement.classList.add("after");
+ } else {
+ this._labelRightElement.style.setProperty("left", this._percentages.middle + "%");
+ this._labelRightElement.style.setProperty("right", (100 - this._percentages.end) + "%");
+ }
+ },
+
+ __proto__: WebInspector.DataGridNode.prototype
+}
+
+/**
+ * @param {!WebInspector.NetworkDataGridNode} a
+ * @param {!WebInspector.NetworkDataGridNode} b
+ * @return {number}
+ */
+WebInspector.NetworkDataGridNode.NameComparator = function(a, b)
+{
+ var aFileName = a._request.name();
+ var bFileName = b._request.name();
+ if (aFileName > bFileName)
+ return 1;
+ if (bFileName > aFileName)
+ return -1;
+ return 0;
+}
+
+/**
+ * @param {!WebInspector.NetworkDataGridNode} a
+ * @param {!WebInspector.NetworkDataGridNode} b
+ * @return {number}
+ */
+WebInspector.NetworkDataGridNode.RemoteAddressComparator = function(a, b)
+{
+ var aRemoteAddress = a._request.remoteAddress();
+ var bRemoteAddress = b._request.remoteAddress();
+ if (aRemoteAddress > bRemoteAddress)
+ return 1;
+ if (bRemoteAddress > aRemoteAddress)
+ return -1;
+ return 0;
+}
+
+/**
+ * @param {!WebInspector.NetworkDataGridNode} a
+ * @param {!WebInspector.NetworkDataGridNode} b
+ * @return {number}
+ */
+WebInspector.NetworkDataGridNode.SizeComparator = function(a, b)
+{
+ if (b._request.cached && !a._request.cached)
+ return 1;
+ if (a._request.cached && !b._request.cached)
+ return -1;
+
+ return a._request.transferSize - b._request.transferSize;
+}
+
+/**
+ * @param {!WebInspector.NetworkDataGridNode} a
+ * @param {!WebInspector.NetworkDataGridNode} b
+ * @return {number}
+ */
+WebInspector.NetworkDataGridNode.InitiatorComparator = function(a, b)
+{
+ var aInitiator = a._request.initiatorInfo();
+ var bInitiator = b._request.initiatorInfo();
+
+ if (aInitiator.type < bInitiator.type)
+ return -1;
+ if (aInitiator.type > bInitiator.type)
+ return 1;
+
+ if (typeof aInitiator.__source === "undefined")
+ aInitiator.__source = WebInspector.displayNameForURL(aInitiator.url);
+ if (typeof bInitiator.__source === "undefined")
+ bInitiator.__source = WebInspector.displayNameForURL(bInitiator.url);
+
+ if (aInitiator.__source < bInitiator.__source)
+ return -1;
+ if (aInitiator.__source > bInitiator.__source)
+ return 1;
+
+ if (aInitiator.lineNumber < bInitiator.lineNumber)
+ return -1;
+ if (aInitiator.lineNumber > bInitiator.lineNumber)
+ return 1;
+
+ if (aInitiator.columnNumber < bInitiator.columnNumber)
+ return -1;
+ if (aInitiator.columnNumber > bInitiator.columnNumber)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * @param {!WebInspector.NetworkDataGridNode} a
+ * @param {!WebInspector.NetworkDataGridNode} b
+ * @return {number}
+ */
+WebInspector.NetworkDataGridNode.RequestCookiesCountComparator = function(a, b)
+{
+ var aScore = a._request.requestCookies ? a._request.requestCookies.length : 0;
+ var bScore = b._request.requestCookies ? b._request.requestCookies.length : 0;
+ return aScore - bScore;
+}
+
+/**
+ * @param {!WebInspector.NetworkDataGridNode} a
+ * @param {!WebInspector.NetworkDataGridNode} b
+ * @return {number}
+ */
+WebInspector.NetworkDataGridNode.ResponseCookiesCountComparator = function(a, b)
+{
+ var aScore = a._request.responseCookies ? a._request.responseCookies.length : 0;
+ var bScore = b._request.responseCookies ? b._request.responseCookies.length : 0;
+ return aScore - bScore;
+}
+
+/**
+ * @param {string} propertyName
+ * @param {boolean} revert
+ * @param {!WebInspector.NetworkDataGridNode} a
+ * @param {!WebInspector.NetworkDataGridNode} b
+ * @return {number}
+ */
+WebInspector.NetworkDataGridNode.RequestPropertyComparator = function(propertyName, revert, a, b)
+{
+ var aValue = a._request[propertyName];
+ var bValue = b._request[propertyName];
+ if (aValue > bValue)
+ return revert ? -1 : 1;
+ if (bValue > aValue)
+ return revert ? 1 : -1;
+ return 0;
+}