monaca-lib
Version:
Monaca cloud API bindings for JavaScript
1,244 lines (1,077 loc) • 73 kB
JavaScript
/*
* 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.
*/
/**
* @constructor
* @implements {WebInspector.Searchable}
* @implements {WebInspector.TargetManager.Observer}
* @extends {WebInspector.VBox}
* @param {!WebInspector.FilterBar} filterBar
* @param {!Element} progressBarContainer
*/
WebInspector.NetworkLogView = function(filterBar, progressBarContainer)
{
WebInspector.VBox.call(this);
this.registerRequiredCSS("network/networkLogView.css");
this.registerRequiredCSS("ui/filter.css");
this._filterBar = filterBar;
this._progressBarContainer = progressBarContainer;
var defaultColumnsVisibility = WebInspector.NetworkLogView._defaultColumnsVisibility;
this._columnsVisibilitySetting = WebInspector.settings.createSetting("networkLogColumnsVisibility", defaultColumnsVisibility);
var savedColumnsVisibility = this._columnsVisibilitySetting.get();
var columnsVisibility = {};
for (var columnId in defaultColumnsVisibility)
columnsVisibility[columnId] = savedColumnsVisibility.hasOwnProperty(columnId) ? savedColumnsVisibility[columnId] : defaultColumnsVisibility[columnId];
this._columnsVisibilitySetting.set(columnsVisibility);
/** @type {!Map.<string, !WebInspector.NetworkDataGridNode>} */
this._nodesByRequestId = new Map();
/** @type {!Object.<string, boolean>} */
this._staleRequestIds = {};
/** @type {number} */
this._mainRequestLoadTime = -1;
/** @type {number} */
this._mainRequestDOMContentLoadedTime = -1;
this._matchedRequestCount = 0;
this._highlightedSubstringChanges = [];
/** @type {!Array.<!WebInspector.NetworkLogView.Filter>} */
this._filters = [];
this._currentMatchedRequestNode = null;
this._currentMatchedRequestIndex = -1;
this._linkifier = new WebInspector.Linkifier();
this._gridMode = true;
this._recording = false;
this._preserveLog = false;
/** @type {number} */
this._rowHeight = 0;
this._addFilters();
this._resetSuggestionBuilder();
this._initializeView();
WebInspector.settings.networkColorCodeResourceTypes.addChangeListener(this._invalidateAllItems, this);
WebInspector.settings.networkLogLargeRows.addChangeListener(this._updateRowsSize, this);
WebInspector.settings.networkLogHideColumns.addChangeListener(this._updateColumns, this);
WebInspector.targetManager.observeTargets(this);
WebInspector.targetManager.addModelListener(WebInspector.NetworkManager, WebInspector.NetworkManager.EventTypes.RequestStarted, this._onRequestStarted, this);
WebInspector.targetManager.addModelListener(WebInspector.NetworkManager, WebInspector.NetworkManager.EventTypes.RequestUpdated, this._onRequestUpdated, this);
WebInspector.targetManager.addModelListener(WebInspector.NetworkManager, WebInspector.NetworkManager.EventTypes.RequestFinished, this._onRequestUpdated, this);
WebInspector.targetManager.addModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameNavigated, this);
WebInspector.targetManager.addModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.EventTypes.Load, this._loadEventFired, this);
WebInspector.targetManager.addModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.EventTypes.DOMContentLoaded, this._domContentLoadedEventFired, this);
}
WebInspector.NetworkLogView._isFilteredOutSymbol = Symbol("isFilteredOut");
WebInspector.NetworkLogView._isMatchingSearchQuerySymbol = Symbol("isMatchingSearchQuery");
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, protocol: false, scheme: false, domain: false, remoteAddress: false, type: true, initiator: true, cookies: false, setCookies: false, size: true, time: true, connectionId: false,
"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 = 200;
WebInspector.NetworkLogView._waterfallMinOvertime = 1;
WebInspector.NetworkLogView._waterfallMaxOvertime = 3;
/** @enum {string} */
WebInspector.NetworkLogView.FilterType = {
Domain: "domain",
HasResponseHeader: "has-response-header",
Is: "is",
LargerThan: "larger-than",
Method: "method",
MimeType: "mime-type",
Scheme: "scheme",
SetCookieDomain: "set-cookie-domain",
SetCookieName: "set-cookie-name",
SetCookieValue: "set-cookie-value",
StatusCode: "status-code"
};
/** @enum {string} */
WebInspector.NetworkLogView.IsFilterType = {
Running: "running"
};
/** @type {!Array.<string>} */
WebInspector.NetworkLogView._searchKeys = Object.values(WebInspector.NetworkLogView.FilterType);
/** @type {!Object.<string, string>} */
WebInspector.NetworkLogView._columnTitles = {
"name": WebInspector.UIString("Name"),
"method": WebInspector.UIString("Method"),
"status": WebInspector.UIString("Status"),
"protocol": WebInspector.UIString("Protocol"),
"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"),
"connectionId": WebInspector.UIString("Connection Id"),
"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 {boolean} recording
*/
setRecording: function(recording)
{
this._recording = recording;
},
/**
* @param {boolean} preserveLog
*/
setPreserveLog: function(preserveLog)
{
this._preserveLog = preserveLog;
},
/**
* @override
* @param {!WebInspector.Target} target
*/
targetAdded: function(target)
{
target.networkLog.requests().forEach(this._appendRequest.bind(this));
},
/**
* @override
* @param {!WebInspector.Target} target
*/
targetRemoved: function(target)
{
},
clearSelection: function()
{
if (this._dataGrid.selectedNode)
this._dataGrid.selectedNode.deselect();
},
_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];
if (resourceType === WebInspector.resourceTypes.TextTrack)
continue;
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.NetworkLogView._searchKeys);
this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.Is, WebInspector.NetworkLogView.IsFilterType.Running);
this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.LargerThan, "100");
this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.LargerThan, "10k");
this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.LargerThan, "1M");
this._textFilterUI.setSuggestionBuilder(this._suggestionBuilder);
},
/**
* @param {!WebInspector.Event} event
*/
_filterChanged: function(event)
{
this._removeAllNodeHighlights();
this._parseFilterQuery(this._textFilterUI.value());
this._filterRequests();
},
_initializeView: function()
{
this.element.id = "network-container";
this._createSortingFunctions();
this._createCalculators();
this._createTable();
this._createTimelineGrid();
this._summaryBarElement = this.element.createChild("div", "network-summary-bar");
this._updateRowsSize();
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(250, 250);
this.switchViewMode(true);
},
/**
* @override
* @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);
this._loadDivider = createElementWithClass("div", "network-event-divider network-red-divider invisible");
this._timelineGrid.addEventDivider(this._loadDivider);
this._domContentLoadedDivider = createElementWithClass("div", "network-event-divider network-blue-divider invisible");
this._timelineGrid.addEventDivider(this._domContentLoadedDivider);
},
_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: "protocol",
title: WebInspector.NetworkLogView._columnTitles["protocol"],
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
});
columns.push({
id: "connectionId",
title: WebInspector.NetworkLogView._columnTitles["connectionId"],
sortable: true,
weight: 6
});
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",
title: WebInspector.NetworkLogView._columnTitles["timeline"],
sortable: false,
weight: 40,
sort: WebInspector.DataGrid.Order.Ascending
});
this._dataGrid = new WebInspector.SortableDataGrid(columns);
this._dataGrid.setStickToBottom(true);
this._updateColumns();
this._dataGrid.setName("networkLog");
this._dataGrid.setResizeMethod(WebInspector.DataGrid.ResizeMethod.Last);
this._dataGrid.element.classList.add("network-log-grid");
this._dataGrid.element.addEventListener("contextmenu", this._contextMenu.bind(this), true);
this._dataGrid.element.addEventListener("mousedown", this._dataGridMouseDown.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();
this._dataGrid.sortNodes(this._sortingFunctions.startTime, false);
},
/**
* @param {!Event} event
*/
_dataGridMouseDown: function(event)
{
if ((!this._dataGrid.selectedNode && event.button) || event.target.enclosingNodeOrSelfWithNodeName("a"))
event.consume();
},
/**
* @param {string} title
* @param {string} subtitle
* @return {!DocumentFragment}
*/
_makeHeaderFragment: function(title, subtitle)
{
var fragment = createDocumentFragment();
fragment.createTextChild(title);
var subtitleDiv = fragment.createChild("div", "network-header-subtitle");
subtitleDiv.createTextChild(subtitle);
return fragment;
},
_patchTimelineHeader: function()
{
var timelineSorting = createElement("select");
var option = createElement("option");
option.value = "startTime";
option.label = WebInspector.UIString("Timeline");
timelineSorting.appendChild(option);
option = createElement("option");
option.value = "startTime";
option.label = WebInspector.UIString("Start Time");
timelineSorting.appendChild(option);
option = createElement("option");
option.value = "responseTime";
option.label = WebInspector.UIString("Response Time");
timelineSorting.appendChild(option);
option = createElement("option");
option.value = "endTime";
option.label = WebInspector.UIString("End Time");
timelineSorting.appendChild(option);
option = createElement("option");
option.value = "duration";
option.label = WebInspector.UIString("Duration");
timelineSorting.appendChild(option);
option = 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.protocol = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "protocol", 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.connectionId = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "connectionId", 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);
},
_createCalculators: function()
{
/** @type {!WebInspector.NetworkTransferTimeCalculator} */
this._timeCalculator = new WebInspector.NetworkTransferTimeCalculator();
/** @type {!WebInspector.NetworkTransferDurationCalculator} */
this._durationCalculator = new WebInspector.NetworkTransferDurationCalculator();
/** @type {!Object.<string, !WebInspector.NetworkTimeCalculator>} */
this._calculators = {};
this._calculators.timeline = this._timeCalculator;
this._calculators.startTime = this._timeCalculator;
this._calculators.endTime = this._timeCalculator;
this._calculators.responseTime = this._timeCalculator;
this._calculators.duration = this._durationCalculator;
this._calculators.latency = this._durationCalculator;
this._calculator = this._timeCalculator;
},
_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._highlightNthMatchedRequestForSearch(this._updateMatchCountAndFindMatchIndex(this._currentMatchedRequestNode), false);
this._timelineSortSelector.selectedIndex = 0;
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;
this._setCalculator(this._calculators[value]);
var sortingFunction = this._sortingFunctions[value];
this._dataGrid.sortNodes(sortingFunction);
this._highlightNthMatchedRequestForSearch(this._updateMatchCountAndFindMatchIndex(this._currentMatchedRequestNode), false);
this._dataGrid.markColumnAsSortedBy("timeline", WebInspector.DataGrid.Order.Ascending);
},
_updateSummaryBar: function()
{
var requestsNumber = this._nodesByRequestId.size;
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.createTextChild(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;
var nodes = this._nodesByRequestId.valuesArray();
for (var i = 0; i < nodes.length; ++i) {
var request = nodes[i].request();
var requestTransferSize = request.transferSize;
transferSize += requestTransferSize;
if (!nodes[i][WebInspector.NetworkLogView._isFilteredOutSymbol]) {
selectedRequestsNumber++;
selectedTransferSize += requestTransferSize;
}
if (request.url === request.target().resourceTreeModel.inspectedPageURL() && request.resourceType() === WebInspector.resourceTypes.Document)
baseTime = request.startTime;
if (request.endTime > maxTime)
maxTime = request.endTime;
}
var summaryBar = this._summaryBarElement;
summaryBar.removeChildren();
var separator = "\u2002\u2758\u2002";
var text = "";
/**
* @param {string} chunk
* @return {!Element}
*/
function appendChunk(chunk)
{
var span = summaryBar.createChild("span");
span.textContent = chunk;
text += chunk;
return span;
}
if (selectedRequestsNumber !== requestsNumber) {
appendChunk(WebInspector.UIString("%d / %d requests", selectedRequestsNumber, requestsNumber));
appendChunk(separator);
appendChunk(WebInspector.UIString("%s / %s transferred", Number.bytesToString(selectedTransferSize), Number.bytesToString(transferSize)));
} else {
appendChunk(WebInspector.UIString("%d requests", requestsNumber));
appendChunk(separator);
appendChunk(WebInspector.UIString("%s transferred", Number.bytesToString(transferSize)));
}
if (baseTime !== -1) {
appendChunk(separator);
appendChunk(WebInspector.UIString("Finish: %s", Number.secondsToString(maxTime - baseTime)));
if (this._mainRequestDOMContentLoadedTime !== -1 && this._mainRequestDOMContentLoadedTime > baseTime) {
appendChunk(separator);
var domContentLoadedText = WebInspector.UIString("DOMContentLoaded: %s", Number.secondsToString(this._mainRequestDOMContentLoadedTime - baseTime));
appendChunk(domContentLoadedText).classList.add("summary-blue");
}
if (this._mainRequestLoadTime !== -1) {
appendChunk(separator);
var loadText = WebInspector.UIString("Load: %s", Number.secondsToString(this._mainRequestLoadTime - baseTime));
appendChunk(loadText).classList.add("summary-red");
}
}
summaryBar.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.isShowing()) {
this._scheduleRefresh();
return;
}
var timelineOffset = this._dataGrid.columnOffset("timeline");
// Position timline grid location.
if (timelineOffset)
this._timelineGrid.element.style.left = timelineOffset + "px";
var calculator = this.calculator();
calculator.setDisplayWindow(this._timelineGrid.dividersElement.clientWidth);
this._timelineGrid.updateDividers(calculator, 50);
if (calculator.startAtZero) {
// 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.
return;
}
var loadTimePercent = calculator.computePercentageFromEventTime(this._mainRequestLoadTime);
this._loadDivider.classList.toggle("invisible", this._mainRequestLoadTime === -1 || loadTimePercent < 0);
this._loadDivider.style.left = loadTimePercent + "%";
var domLoadTimePrecent = calculator.computePercentageFromEventTime(this._mainRequestDOMContentLoadedTime);
this._domContentLoadedDivider.classList.toggle("invisible", this._mainRequestDOMContentLoadedTime === -1 || domLoadTimePrecent < 0);
this._domContentLoadedDivider.style.left = domLoadTimePrecent + "%";
},
_refreshIfNeeded: function()
{
if (this._needsRefresh)
this.refresh();
},
_invalidateAllItems: function()
{
var requestIds = this._nodesByRequestId.keysArray();
for (var i = 0; i < requestIds.length; ++i)
this._staleRequestIds[requestIds[i]] = true;
this.refresh();
},
/**
* @return {!WebInspector.NetworkTimeCalculator}
*/
timeCalculator: function()
{
return this._timeCalculator;
},
/**
* @return {!WebInspector.NetworkTimeCalculator}
*/
calculator: function()
{
return this._calculator;
},
/**
* @param {!WebInspector.NetworkTimeCalculator} x
*/
_setCalculator: function(x)
{
if (!x || this._calculator === x)
return;
this._calculator = x;
this._calculator.reset();
if (this._calculator.startAtZero)
this._timelineGrid.hideEventDividers();
else
this._timelineGrid.showEventDividers();
this._invalidateAllItems();
},
/**
* @param {!WebInspector.Event} event
*/
_loadEventFired: function(event)
{
if (!this._recording)
return;
var data = /** @type {number} */ (event.data);
this._mainRequestLoadTime = data || -1;
// Schedule refresh to update boundaries and draw the new line.
this._scheduleRefresh();
},
/**
* @param {!WebInspector.Event} event
*/
_domContentLoadedEventFired: function(event)
{
if (!this._recording)
return;
var data = /** @type {number} */ (event.data);
this._mainRequestDOMContentLoadedTime = 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 oldBoundary = this.calculator().boundary();
this._timeCalculator.updateBoundariesForEventTime(this._mainRequestLoadTime);
this._durationCalculator.updateBoundariesForEventTime(this._mainRequestLoadTime);
this._timeCalculator.updateBoundariesForEventTime(this._mainRequestDOMContentLoadedTime);
this._durationCalculator.updateBoundariesForEventTime(this._mainRequestDOMContentLoadedTime);
var dataGrid = this._dataGrid;
var rootNode = dataGrid.rootNode();
var nodesToInsert = [];
for (var requestId in this._staleRequestIds) {
var node = this._nodesByRequestId.get(requestId);
if (!node)
continue;
if (!node[WebInspector.NetworkLogView._isFilteredOutSymbol])
rootNode.removeChild(node);
node[WebInspector.NetworkLogView._isFilteredOutSymbol] = !this._applyFilter(node);
if (!node[WebInspector.NetworkLogView._isFilteredOutSymbol])
nodesToInsert.push(node);
var request = node.request();
this._timeCalculator.updateBoundaries(request);
this._durationCalculator.updateBoundaries(request);
}
for (var i = 0; i < nodesToInsert.length; ++i) {
var node = nodesToInsert[i];
var request = node.request();
node.refresh();
dataGrid.insertChild(node);
node[WebInspector.NetworkLogView._isMatchingSearchQuerySymbol] = this._matchRequest(request);
}
this._highlightNthMatchedRequestForSearch(this._updateMatchCountAndFindMatchIndex(this._currentMatchedRequestNode), false);
if (this._shouldSetWaterfallWindow && this._mainRequestLoadTime !== -1) {
var waterfallWindow = this.calculator().boundary();
var overtime = this._mainRequestLoadTime - waterfallWindow.minimum;
overtime = Number.constrain(overtime, WebInspector.NetworkLogView._waterfallMinOvertime, WebInspector.NetworkLogView._waterfallMaxOvertime)
var waterfallEnd = this._mainRequestLoadTime + overtime;
if (waterfallEnd <= waterfallWindow.maximum) {
waterfallWindow.maximum = waterfallEnd;
this._shouldSetWaterfallWindow = false;
this._timeCalculator.setWindow(waterfallWindow);
}
}
if (!this.calculator().boundary().equals(oldBoundary)) {
// The boundaries changed, so all item graphs are stale.
this._updateDividersIfNeeded();
var nodes = this._nodesByRequestId.valuesArray();
for (var i = 0; i < nodes.length; ++i)
nodes[i].refreshGraph();
}
this._staleRequestIds = {};
this._updateSummaryBar();
},
expandTimeline: function()
{
this._shouldSetWaterfallWindow = false;
this._timeCalculator.setWindow(null);
this._updateDividersIfNeeded();
this._invalidateAllItems();
},
reset: function()
{
this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.RequestSelected, null);
/** @type {boolean} */
this._shouldSetWaterfallWindow = Runtime.experiments.isEnabled("showPrimaryLoadWaterfallInNetworkTimeline") && WebInspector.settings.networkShowPrimaryLoadWaterfall.get();
this._clearSearchMatchedList();
if (this._popoverHelper)
this._popoverHelper.hidePopover();
if (this._calculator)
this._calculator.reset();
this._timeCalculator.setWindow(null);
var nodes = this._nodesByRequestId.valuesArray();
for (var i = 0; i < nodes.length; ++i)
nodes[i].dispose();
this._nodesByRequestId.clear();
this._staleRequestIds = {};
this._resetSuggestionBuilder();
if (this._dataGrid) {
this._dataGrid.rootNode().removeChildren();
this._updateDividersIfNeeded();
this._updateSummaryBar();
}
this._mainRequestLoadTime = -1;
this._mainRequestDOMContentLoadedTime = -1;
},
/**
* @param {!WebInspector.Event} event
*/
_onRequestStarted: function(event)
{
if (!this._recording)
return;
var request = /** @type {!WebInspector.NetworkRequest} */ (event.data);
this._appendRequest(request);
},
/**
* @param {!WebInspector.NetworkRequest} request
*/
_appendRequest: function(request)
{
var node = new WebInspector.NetworkDataGridNode(this, request);
node[WebInspector.NetworkLogView._isFilteredOutSymbol] = true;
node[WebInspector.NetworkLogView._isMatchingSearchQuerySymbol] = false;
// In case of redirect request id is reassigned to a redirected
// request and we need to update _nodesByRequestId and search results.
var originalRequestNode = this._nodesByRequestId.get(request.requestId);
if (originalRequestNode)
this._nodesByRequestId.set(originalRequestNode.request().requestId, originalRequestNode);
this._nodesByRequestId.set(request.requestId, node);
// 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._nodesByRequestId.get(request.requestId))
return;
WebInspector.NetworkLogView._subdomains(request.domain).forEach(this._suggestionBuilder.addItem.bind(this._suggestionBuilder, WebInspector.NetworkLogView.FilterType.Domain));
this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.Method, request.requestMethod);
this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.MimeType, request.mimeType);
this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.Scheme, "" + request.scheme);
this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.StatusCode, "" + request.statusCode);
var responseHeaders = request.responseHeaders;
for (var i = 0, l = responseHeaders.length; i < l; ++i)
this._suggestionBuilder.addItem(WebInspector.NetworkLogView.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.NetworkLogView.FilterType.SetCookieDomain, cookie.domain());
this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.SetCookieName, cookie.name());
this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.SetCookieValue, cookie.value());
}
this._staleRequestIds[request.requestId] = true;
this._scheduleRefresh();
},
/**
* @param {!WebInspector.Event} event
*/
_mainFrameNavigated: function(event)
{
if (!this._recording)
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);
}
if (!this._preserveLog) {
this.reset();
for (var i = 0; i < requestsToPick.length; ++i)
this._appendRequest(requestsToPick[i]);
}
for (var i = 0; i < requestsToPick.length; ++i) {
var request = requestsToPick[i];
var node = this._nodesByRequestId.get(request.requestId);
if (node) {
node.markAsNavigationRequest();
break;
}
}
},
/**
* @param {boolean} gridMode
*/
switchViewMode: function(gridMode)
{
if (this._gridMode === gridMode)
return;
this._gridMode = gridMode;
if (gridMode) {
if (this._dataGrid.selectedNode)
this._dataGrid.selectedNode.selected = false;
} else {
this._removeAllNodeHighlights();
this._popoverHelper.hidePopover();
}
this.element.classList.toggle("brief-mode", !gridMode);
this._updateColumns();
},
revealSelectedItem: function()
{
if (this._dataGrid.selectedNode)
this._dataGrid.selectedNode.reveal();
},
/**
* @return {number}
*/
rowHeight: function()
{
return this._rowHeight;
},
_updateRowsSize: function()
{
var largeRows = !!WebInspector.settings.networkLogLargeRows.get();
this._rowHeight = largeRows ? 41 : 21;
this._dataGrid.element.classList.toggle("small", !largeRows);
this._timelineGrid.element.classList.toggle("small", !largeRows);
this._dataGrid.scheduleUpdate();
},
/**
* @param {!Element} element
* @param {!Event} event
* @return {!Element|!AnchorBox|undefined}
*/
_getPopoverAnchor: function(element, event)
{
if (!this._gridMode)
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) {
var initiator = /** @type {!WebInspector.NetworkRequest} */ (anchor.request).initiator();
if (initiator && (initiator.stackTrace || initiator.asyncStackTrace))
return anchor;
}
},
/**
* @param {!Element} anchor
* @param {!WebInspector.Popover} popover
*/
_showPopover: function(anchor, popover)
{
var content;
if (anchor.classList.contains("network-script-initiated")) {
var request = /** @type {!WebInspector.NetworkRequest} */ (anchor.request);
var initiator = /** @type {!NetworkAgent.Initiator} */ (request.initiator());
content = WebInspector.DOMPresentationUtils.buildStackTracePreviewContents(request.target(), this._linkifier, initiator.stackTrace, initiator.asyncStackTrace);
popover.setCanShrink(true);
} else {
content = WebInspector.RequestTimingView.createTimingTable(anchor.parentElement.request, this._timeCalculator.minimumBoundary());
popover.setCanShrink(false);
}
popover.showForAnchor(content, anchor);
},
_onHidePopover: function()
{
this._linkifier.reset();
},
_updateColumns: function()
{
if (!this._dataGrid)
return;
var gridMode = this._gridMode;
var visibleColumns = {"name": true};
if (gridMode)
visibleColumns["timeline"] = true;
if (gridMode && !WebInspector.settings.networkLogHideColumns.get()) {
var columnsVisibility = this._columnsVisibilitySetting.get();
for (var columnIdentifier in columnsVisibility)
visibleColumns[columnIdentifier] = columnsVisibility[columnIdentifier];
}
this._dataGrid.setColumnsVisiblity(visibleColumns);
},
/**
* @param {string} columnIdentifier
*/
_toggleColumnVisibility: function(columnIdentifier)
{
var columnsVisibility = this._columnsVisibilitySetting.get();
columnsVisibility[columnIdentifier] = !columnsVisibility[columnIdentifier];
this._columnsVisibilitySetting.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._columnsVisibilitySetting.get());
this._configurableColumnIDs = columnIDs.sort(compare);
return this._configurableColumnIDs;
},
/**
* @param {!Event} event
*/
_contextMenu: function(event)
{
var contextMenu = new WebInspector.ContextMenu(event);
if (this._gridMode && event.target.isSelfOrDescendant(this._dataGrid.headerTableBody)) {
var columnsVisibility = this._columnsVisibilitySetting.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.appendApplicableItems(request);
if (request.requestHeadersText())
contextMenu.appendItem(WebInspector.UIString.capitalize("Copy ^request ^headers"), this._copyRequestHeaders.bind(this, request));
if (request.responseHeadersText)
contextMenu.appendItem(WebInspector.UIString.capitalize("Copy ^response ^headers"), this._copyResponseHeaders.bind(this, request));
if (request.finished)
contextMenu.appendItem(WebInspector.UIString.capitalize("Copy ^response"), this._copyResponse.bind(this, request));
contextMenu.appendItem(WebInspector.UIString("Copy as cURL"), this._copyCurlCommand.bind(this, request));
}
contextMenu.appendItem(WebInspector.UIString.capitalize("Copy ^all as HAR"), this._copyAll.bind(this));
contextMenu.appendSeparator();
contextMenu.appendItem(WebInspector.UIString.capitalize("Save as HAR with ^content"), this._exportAll.bind(this));
contextMenu.appendSeparator();
contextMenu.appendItem(WebInspector.UIString.capitalize("Clear ^browser ^cache"), this._clearBrowserCache.bind(this));
contextMenu.appendItem(WebInspector.UIString.capitalize("Clear ^browser ^cookies"), this._clearBrowserCookies.bind(this));
if (request && request.resourceType() === WebInspector.resourceTypes.XHR) {
contextMenu.appendSeparator();
contextMenu.appendItem(WebInspector.UIString("Replay XHR"), request.replayXHR.bind(request));
contextMenu.appendSeparator();
}
contextMenu.show();
},
_harRequests: function()
{
var requests = this._nodesByRequestId.valuesArray().map(function(node) { return node.request(); });
var httpRequests = 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));
},
/**
* @param {!WebInspector.NetworkRequest} request
*/
_copyLocation: function(request)
{
InspectorFrontendHost.copyText(request.url);
},
/**
* @param {!WebInspector.NetworkRequest} request
*/
_copyRequestHeaders: function(request)
{
InspectorFrontendHost.copyText(request.requestHeadersText());
},
/**
* @param {!WebInspector.NetworkRequest} request
*/
_copyResponse: function(req