UNPKG

monaca-lib

Version:

Monaca cloud API bindings for JavaScript

1,244 lines (1,077 loc) 73 kB
/* * 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