UNPKG

@dcloudio/uni-debugger

Version:

uni-app debugger

814 lines (726 loc) 28.7 kB
// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /** * @unrestricted */ Network.NetworkLogViewColumns = class { /** * @param {!Network.NetworkLogView} networkLogView * @param {!Network.NetworkTransferTimeCalculator} timeCalculator * @param {!Network.NetworkTransferDurationCalculator} durationCalculator * @param {!Common.Setting} networkLogLargeRowsSetting */ constructor(networkLogView, timeCalculator, durationCalculator, networkLogLargeRowsSetting) { this._networkLogView = networkLogView; /** @type {!Common.Setting} */ this._persistantSettings = Common.settings.createSetting('networkLogColumns', {}); this._networkLogLargeRowsSetting = networkLogLargeRowsSetting; this._networkLogLargeRowsSetting.addChangeListener(this._updateRowsSize, this); /** @type {!Map<string, !Array<number>>} */ this._eventDividers = new Map(); this._eventDividersShown = false; this._gridMode = true; /** @type {!Array.<!Network.NetworkLogViewColumns.Descriptor>} */ this._columns = []; this._waterfallRequestsAreStale = false; this._waterfallScrollerWidthIsStale = true; /** @type {!Components.Linkifier} */ this._popupLinkifier = new Components.Linkifier(); /** @type {!Map<string, !Network.NetworkTimeCalculator>} */ this._calculatorsMap = new Map(); this._calculatorsMap.set(Network.NetworkLogViewColumns._calculatorTypes.Time, timeCalculator); this._calculatorsMap.set(Network.NetworkLogViewColumns._calculatorTypes.Duration, durationCalculator); this._lastWheelTime = 0; this._setupDataGrid(); this._setupWaterfall(); } /** * @param {!Network.NetworkLogViewColumns.Descriptor} columnConfig * @return {!DataGrid.DataGrid.ColumnDescriptor} */ static _convertToDataGridDescriptor(columnConfig) { return /** @type {!DataGrid.DataGrid.ColumnDescriptor} */ ({ id: columnConfig.id, title: columnConfig.title, sortable: columnConfig.sortable, align: columnConfig.align, nonSelectable: columnConfig.nonSelectable, weight: columnConfig.weight }); } wasShown() { this._updateRowsSize(); } willHide() { this._popoverHelper.hidePopover(); } reset() { if (this._popoverHelper) this._popoverHelper.hidePopover(); this._eventDividers.clear(); } _setupDataGrid() { const defaultColumns = Network.NetworkLogViewColumns._defaultColumns; const defaultColumnConfig = Network.NetworkLogViewColumns._defaultColumnConfig; this._columns = /** @type {!Array<!Network.NetworkLogViewColumns.Descriptor>} */ ([]); for (const currentConfigColumn of defaultColumns) { const columnConfig = /** @type {!Network.NetworkLogViewColumns.Descriptor} */ ( Object.assign({}, defaultColumnConfig, currentConfigColumn)); columnConfig.id = columnConfig.id; if (columnConfig.subtitle) columnConfig.titleDOMFragment = this._makeHeaderFragment(columnConfig.title, columnConfig.subtitle); this._columns.push(columnConfig); } this._loadCustomColumnsAndSettings(); this._popoverHelper = new UI.PopoverHelper(this._networkLogView.element, this._getPopoverRequest.bind(this)); this._popoverHelper.setHasPadding(true); this._popoverHelper.setTimeout(300, 300); /** @type {!DataGrid.SortableDataGrid<!Network.NetworkNode>} */ this._dataGrid = new DataGrid.SortableDataGrid(this._columns.map(Network.NetworkLogViewColumns._convertToDataGridDescriptor)); this._dataGrid.element.addEventListener('mousedown', event => { if (!this._dataGrid.selectedNode && event.button) event.consume(); }, true); this._dataGridScroller = this._dataGrid.scrollContainer; this._updateColumns(); this._dataGrid.addEventListener(DataGrid.DataGrid.Events.SortingChanged, this._sortHandler, this); this._dataGrid.setHeaderContextMenuCallback(this._innerHeaderContextMenu.bind(this)); this._activeWaterfallSortId = Network.NetworkLogViewColumns.WaterfallSortIds.StartTime; this._dataGrid.markColumnAsSortedBy( Network.NetworkLogViewColumns._initialSortColumn, DataGrid.DataGrid.Order.Ascending); this._splitWidget = new UI.SplitWidget(true, true, 'networkPanelSplitViewWaterfall', 200); const widget = this._dataGrid.asWidget(); widget.setMinimumSize(150, 0); this._splitWidget.setMainWidget(widget); } _setupWaterfall() { this._waterfallColumn = new Network.NetworkWaterfallColumn(this._networkLogView.calculator()); this._waterfallColumn.element.addEventListener('contextmenu', handleContextMenu.bind(this)); this._waterfallColumn.element.addEventListener('mousewheel', this._onMouseWheel.bind(this, false), {passive: true}); this._dataGridScroller.addEventListener('mousewheel', this._onMouseWheel.bind(this, true), true); this._waterfallScroller = this._waterfallColumn.contentElement.createChild('div', 'network-waterfall-v-scroll'); this._waterfallScrollerContent = this._waterfallScroller.createChild('div', 'network-waterfall-v-scroll-content'); this._dataGrid.addEventListener(DataGrid.DataGrid.Events.PaddingChanged, () => { this._waterfallScrollerWidthIsStale = true; this._syncScrollers(); }); this._dataGrid.addEventListener( DataGrid.ViewportDataGrid.Events.ViewportCalculated, this._redrawWaterfallColumn.bind(this)); this._createWaterfallHeader(); this._waterfallColumn.contentElement.classList.add('network-waterfall-view'); this._waterfallColumn.setMinimumSize(100, 0); this._splitWidget.setSidebarWidget(this._waterfallColumn); this.switchViewMode(false); /** * @param {!Event} event * @this {Network.NetworkLogViewColumns} */ function handleContextMenu(event) { const node = this._waterfallColumn.getNodeFromPoint(event.offsetX, event.offsetY); if (!node) return; const request = node.request(); if (!request) return; const contextMenu = new UI.ContextMenu(event); this._networkLogView.handleContextMenuForRequest(contextMenu, request); contextMenu.show(); } } /** * @param {boolean} shouldConsume * @param {!Event} event */ _onMouseWheel(shouldConsume, event) { if (shouldConsume) event.consume(true); const hasRecentWheel = Date.now() - this._lastWheelTime < 80; this._activeScroller.scrollBy({top: -event.wheelDeltaY, behavior: hasRecentWheel ? 'instant' : 'smooth'}); this._syncScrollers(); this._lastWheelTime = Date.now(); } _syncScrollers() { if (!this._waterfallColumn.isShowing()) return; this._waterfallScrollerContent.style.height = this._dataGridScroller.scrollHeight + 'px'; this._updateScrollerWidthIfNeeded(); this._dataGridScroller.scrollTop = this._waterfallScroller.scrollTop; } _updateScrollerWidthIfNeeded() { if (this._waterfallScrollerWidthIsStale) { this._waterfallScrollerWidthIsStale = false; this._waterfallColumn.setRightPadding( this._waterfallScroller.offsetWidth - this._waterfallScrollerContent.offsetWidth); } } _redrawWaterfallColumn() { if (!this._waterfallRequestsAreStale) { this._updateScrollerWidthIfNeeded(); this._waterfallColumn.update( this._activeScroller.scrollTop, this._eventDividersShown ? this._eventDividers : undefined); return; } this._syncScrollers(); const nodes = this._networkLogView.flatNodesList(); this._waterfallColumn.update(this._activeScroller.scrollTop, this._eventDividers, nodes); } _createWaterfallHeader() { this._waterfallHeaderElement = this._waterfallColumn.contentElement.createChild('div', 'network-waterfall-header'); this._waterfallHeaderElement.addEventListener('click', waterfallHeaderClicked.bind(this)); this._waterfallHeaderElement.addEventListener( 'contextmenu', event => this._innerHeaderContextMenu(new UI.ContextMenu(event))); const innerElement = this._waterfallHeaderElement.createChild('div'); innerElement.textContent = Common.UIString('Waterfall'); this._waterfallColumnSortIcon = UI.Icon.create('', 'sort-order-icon'); this._waterfallHeaderElement.createChild('div', 'sort-order-icon-container') .appendChild(this._waterfallColumnSortIcon); /** * @this {Network.NetworkLogViewColumns} */ function waterfallHeaderClicked() { const sortOrders = DataGrid.DataGrid.Order; const sortOrder = this._dataGrid.sortOrder() === sortOrders.Ascending ? sortOrders.Descending : sortOrders.Ascending; this._dataGrid.markColumnAsSortedBy('waterfall', sortOrder); this._sortHandler(); } } /** * @param {!Network.NetworkTimeCalculator} x */ setCalculator(x) { this._waterfallColumn.setCalculator(x); } scheduleRefresh() { this._waterfallColumn.scheduleDraw(); } _updateRowsSize() { const largeRows = !!this._networkLogLargeRowsSetting.get(); this._dataGrid.element.classList.toggle('small', !largeRows); this._dataGrid.scheduleUpdate(); this._waterfallScrollerWidthIsStale = true; this._waterfallColumn.setRowHeight(largeRows ? 41 : 21); this._waterfallScroller.classList.toggle('small', !largeRows); this._waterfallHeaderElement.classList.toggle('small', !largeRows); this._waterfallColumn.setHeaderHeight(this._waterfallScroller.offsetTop); } /** * @param {!Element} element */ show(element) { this._splitWidget.show(element); } /** * @return {!DataGrid.SortableDataGrid<!Network.NetworkNode>} dataGrid */ dataGrid() { return this._dataGrid; } sortByCurrentColumn() { this._sortHandler(); } _sortHandler() { const columnId = this._dataGrid.sortColumnId(); this._networkLogView.removeAllNodeHighlights(); this._waterfallRequestsAreStale = true; if (columnId === 'waterfall') { if (this._dataGrid.sortOrder() === DataGrid.DataGrid.Order.Ascending) this._waterfallColumnSortIcon.setIconType('smallicon-triangle-up'); else this._waterfallColumnSortIcon.setIconType('smallicon-triangle-down'); const sortFunction = Network.NetworkRequestNode.RequestPropertyComparator.bind(null, this._activeWaterfallSortId); this._dataGrid.sortNodes(sortFunction, !this._dataGrid.isSortOrderAscending()); this._dataGridSortedForTest(); return; } this._waterfallColumnSortIcon.setIconType(''); const columnConfig = this._columns.find(columnConfig => columnConfig.id === columnId); if (!columnConfig || !columnConfig.sortingFunction) return; this._dataGrid.sortNodes(columnConfig.sortingFunction, !this._dataGrid.isSortOrderAscending()); this._dataGridSortedForTest(); } _dataGridSortedForTest() { } _updateColumns() { if (!this._dataGrid) return; const visibleColumns = /** @type {!Object.<string, boolean>} */ ({}); if (this._gridMode) { for (const columnConfig of this._columns) visibleColumns[columnConfig.id] = columnConfig.visible; } else { visibleColumns.name = true; } this._dataGrid.setColumnsVisiblity(visibleColumns); } /** * @param {boolean} gridMode */ switchViewMode(gridMode) { if (this._gridMode === gridMode) return; this._gridMode = gridMode; if (gridMode) { if (this._dataGrid.selectedNode) this._dataGrid.selectedNode.selected = false; this._splitWidget.showBoth(); this._activeScroller = this._waterfallScroller; this._waterfallScroller.scrollTop = this._dataGridScroller.scrollTop; this._dataGrid.setScrollContainer(this._waterfallScroller); } else { this._networkLogView.removeAllNodeHighlights(); this._splitWidget.hideSidebar(); this._activeScroller = this._dataGridScroller; this._dataGrid.setScrollContainer(this._dataGridScroller); } this._networkLogView.element.classList.toggle('brief-mode', !gridMode); this._updateColumns(); this._updateRowsSize(); } /** * @param {!Network.NetworkLogViewColumns.Descriptor} columnConfig */ _toggleColumnVisibility(columnConfig) { this._loadCustomColumnsAndSettings(); columnConfig.visible = !columnConfig.visible; this._saveColumnsSettings(); this._updateColumns(); } _saveColumnsSettings() { const saveableSettings = {}; for (const columnConfig of this._columns) saveableSettings[columnConfig.id] = {visible: columnConfig.visible, title: columnConfig.title}; this._persistantSettings.set(saveableSettings); } _loadCustomColumnsAndSettings() { const savedSettings = this._persistantSettings.get(); const columnIds = Object.keys(savedSettings); for (const columnId of columnIds) { const setting = savedSettings[columnId]; let columnConfig = this._columns.find(columnConfig => columnConfig.id === columnId); if (!columnConfig) columnConfig = this._addCustomHeader(setting.title, columnId); if (columnConfig.hideable && typeof setting.visible === 'boolean') columnConfig.visible = !!setting.visible; if (typeof setting.title === 'string') columnConfig.title = setting.title; } } /** * @param {string} title * @param {string} subtitle * @return {!DocumentFragment} */ _makeHeaderFragment(title, subtitle) { const fragment = createDocumentFragment(); fragment.createTextChild(title); const subtitleDiv = fragment.createChild('div', 'network-header-subtitle'); subtitleDiv.createTextChild(subtitle); return fragment; } /** * @param {!UI.ContextMenu} contextMenu */ _innerHeaderContextMenu(contextMenu) { const columnConfigs = this._columns.filter(columnConfig => columnConfig.hideable); const nonResponseHeaders = columnConfigs.filter(columnConfig => !columnConfig.isResponseHeader); for (const columnConfig of nonResponseHeaders) { contextMenu.headerSection().appendCheckboxItem( columnConfig.title, this._toggleColumnVisibility.bind(this, columnConfig), columnConfig.visible); } const responseSubMenu = contextMenu.footerSection().appendSubMenuItem(Common.UIString('Response Headers')); const responseHeaders = columnConfigs.filter(columnConfig => columnConfig.isResponseHeader); for (const columnConfig of responseHeaders) { responseSubMenu.defaultSection().appendCheckboxItem( columnConfig.title, this._toggleColumnVisibility.bind(this, columnConfig), columnConfig.visible); } responseSubMenu.footerSection().appendItem( Common.UIString('Manage Header Columns\u2026'), this._manageCustomHeaderDialog.bind(this)); const waterfallSortIds = Network.NetworkLogViewColumns.WaterfallSortIds; const waterfallSubMenu = contextMenu.footerSection().appendSubMenuItem(Common.UIString('Waterfall')); waterfallSubMenu.defaultSection().appendCheckboxItem( Common.UIString('Start Time'), setWaterfallMode.bind(this, waterfallSortIds.StartTime), this._activeWaterfallSortId === waterfallSortIds.StartTime); waterfallSubMenu.defaultSection().appendCheckboxItem( Common.UIString('Response Time'), setWaterfallMode.bind(this, waterfallSortIds.ResponseTime), this._activeWaterfallSortId === waterfallSortIds.ResponseTime); waterfallSubMenu.defaultSection().appendCheckboxItem( Common.UIString('End Time'), setWaterfallMode.bind(this, waterfallSortIds.EndTime), this._activeWaterfallSortId === waterfallSortIds.EndTime); waterfallSubMenu.defaultSection().appendCheckboxItem( Common.UIString('Total Duration'), setWaterfallMode.bind(this, waterfallSortIds.Duration), this._activeWaterfallSortId === waterfallSortIds.Duration); waterfallSubMenu.defaultSection().appendCheckboxItem( Common.UIString('Latency'), setWaterfallMode.bind(this, waterfallSortIds.Latency), this._activeWaterfallSortId === waterfallSortIds.Latency); contextMenu.show(); /** * @param {!Network.NetworkLogViewColumns.WaterfallSortIds} sortId * @this {Network.NetworkLogViewColumns} */ function setWaterfallMode(sortId) { let calculator = this._calculatorsMap.get(Network.NetworkLogViewColumns._calculatorTypes.Time); const waterfallSortIds = Network.NetworkLogViewColumns.WaterfallSortIds; if (sortId === waterfallSortIds.Duration || sortId === waterfallSortIds.Latency) calculator = this._calculatorsMap.get(Network.NetworkLogViewColumns._calculatorTypes.Duration); this._networkLogView.setCalculator(calculator); this._activeWaterfallSortId = sortId; this._dataGrid.markColumnAsSortedBy('waterfall', DataGrid.DataGrid.Order.Ascending); this._sortHandler(); } } _manageCustomHeaderDialog() { const customHeaders = []; for (const columnConfig of this._columns) { if (columnConfig.isResponseHeader) customHeaders.push({title: columnConfig.title, editable: columnConfig.isCustomHeader}); } const manageCustomHeaders = new Network.NetworkManageCustomHeadersView( customHeaders, headerTitle => !!this._addCustomHeader(headerTitle), this._changeCustomHeader.bind(this), this._removeCustomHeader.bind(this)); const dialog = new UI.Dialog(); manageCustomHeaders.show(dialog.contentElement); dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent); dialog.show(this._networkLogView.element); } /** * @param {string} headerId * @return {boolean} */ _removeCustomHeader(headerId) { headerId = headerId.toLowerCase(); const index = this._columns.findIndex(columnConfig => columnConfig.id === headerId); if (index === -1) return false; this._columns.splice(index, 1); this._dataGrid.removeColumn(headerId); this._saveColumnsSettings(); this._updateColumns(); return true; } /** * @param {string} headerTitle * @param {string=} headerId * @param {number=} index * @return {?Network.NetworkLogViewColumns.Descriptor} */ _addCustomHeader(headerTitle, headerId, index) { if (!headerId) headerId = headerTitle.toLowerCase(); if (index === undefined) index = this._columns.length - 1; const currentColumnConfig = this._columns.find(columnConfig => columnConfig.id === headerId); if (currentColumnConfig) return null; const columnConfig = /** @type {!Network.NetworkLogViewColumns.Descriptor} */ ( Object.assign({}, Network.NetworkLogViewColumns._defaultColumnConfig, { id: headerId, title: headerTitle, isResponseHeader: true, isCustomHeader: true, visible: true, sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, headerId) })); this._columns.splice(index, 0, columnConfig); if (this._dataGrid) this._dataGrid.addColumn(Network.NetworkLogViewColumns._convertToDataGridDescriptor(columnConfig), index); this._saveColumnsSettings(); this._updateColumns(); return columnConfig; } /** * @param {string} oldHeaderId * @param {string} newHeaderTitle * @param {string=} newHeaderId * @return {boolean} */ _changeCustomHeader(oldHeaderId, newHeaderTitle, newHeaderId) { if (!newHeaderId) newHeaderId = newHeaderTitle.toLowerCase(); oldHeaderId = oldHeaderId.toLowerCase(); const oldIndex = this._columns.findIndex(columnConfig => columnConfig.id === oldHeaderId); const oldColumnConfig = this._columns[oldIndex]; const currentColumnConfig = this._columns.find(columnConfig => columnConfig.id === newHeaderId); if (!oldColumnConfig || (currentColumnConfig && oldHeaderId !== newHeaderId)) return false; this._removeCustomHeader(oldHeaderId); this._addCustomHeader(newHeaderTitle, newHeaderId, oldIndex); return true; } /** * @param {!Event} event * @return {?UI.PopoverRequest} */ _getPopoverRequest(event) { if (!this._gridMode) return null; const hoveredNode = this._networkLogView.hoveredNode(); if (!hoveredNode) return null; const anchor = event.target.enclosingNodeOrSelfWithClass('network-script-initiated'); if (!anchor) return null; const request = hoveredNode.request(); const initiator = request ? request.initiator() : null; if (!initiator || !initiator.stack) return null; return { box: anchor.boxInWindow(), show: popover => { const manager = anchor.request ? SDK.NetworkManager.forRequest(anchor.request) : null; const content = Components.JSPresentationUtils.buildStackTracePreviewContents( manager ? manager.target() : null, this._popupLinkifier, initiator.stack, () => popover.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent)); popover.contentElement.appendChild(content); return Promise.resolve(true); }, hide: this._popupLinkifier.reset.bind(this._popupLinkifier) }; } /** * @param {!Array<number>} times * @param {string} className */ addEventDividers(times, className) { // TODO(allada) Remove this and pass in the color. let color = 'transparent'; switch (className) { case 'network-blue-divider': color = 'hsla(240, 100%, 80%, 0.7)'; break; case 'network-red-divider': color = 'rgba(255, 0, 0, 0.5)'; break; default: return; } const currentTimes = this._eventDividers.get(color) || []; this._eventDividers.set(color, currentTimes.concat(times)); this._networkLogView.scheduleRefresh(); } hideEventDividers() { this._eventDividersShown = true; this._redrawWaterfallColumn(); } showEventDividers() { this._eventDividersShown = false; this._redrawWaterfallColumn(); } /** * @param {number} time */ selectFilmStripFrame(time) { this._eventDividers.set(Network.NetworkLogViewColumns._filmStripDividerColor, [time]); this._redrawWaterfallColumn(); } clearFilmStripFrame() { this._eventDividers.delete(Network.NetworkLogViewColumns._filmStripDividerColor); this._redrawWaterfallColumn(); } }; Network.NetworkLogViewColumns._initialSortColumn = 'waterfall'; /** * @typedef {{ * id: string, * title: string, * titleDOMFragment: (!DocumentFragment|undefined), * subtitle: (string|null), * visible: boolean, * weight: number, * hideable: boolean, * nonSelectable: boolean, * sortable: boolean, * align: (?DataGrid.DataGrid.Align|undefined), * isResponseHeader: boolean, * sortingFunction: (!function(!Network.NetworkNode, !Network.NetworkNode):number|undefined), * isCustomHeader: boolean * }} */ Network.NetworkLogViewColumns.Descriptor; /** @enum {string} */ Network.NetworkLogViewColumns._calculatorTypes = { Duration: 'Duration', Time: 'Time' }; /** * @type {!Object} column */ Network.NetworkLogViewColumns._defaultColumnConfig = { subtitle: null, visible: false, weight: 6, sortable: true, hideable: true, nonSelectable: true, isResponseHeader: false, alwaysVisible: false, isCustomHeader: false }; /** * @type {!Array.<!Network.NetworkLogViewColumns.Descriptor>} column */ Network.NetworkLogViewColumns._defaultColumns = [ { id: 'name', title: Common.UIString('Name'), subtitle: Common.UIString('Path'), visible: true, weight: 20, hideable: false, nonSelectable: false, alwaysVisible: true, sortingFunction: Network.NetworkRequestNode.NameComparator }, { id: 'method', title: Common.UIString('Method'), sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'requestMethod') }, { id: 'status', title: Common.UIString('Status'), visible: true, subtitle: Common.UIString('Text'), sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'statusCode') }, { id: 'protocol', title: Common.UIString('Protocol'), sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'protocol') }, { id: 'scheme', title: Common.UIString('Scheme'), sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'scheme') }, { id: 'domain', title: Common.UIString('Domain'), sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'domain') }, { id: 'remoteaddress', title: Common.UIString('Remote Address'), weight: 10, align: DataGrid.DataGrid.Align.Right, sortingFunction: Network.NetworkRequestNode.RemoteAddressComparator }, { id: 'type', title: Common.UIString('Type'), visible: true, sortingFunction: Network.NetworkRequestNode.TypeComparator }, { id: 'initiator', title: Common.UIString('Initiator'), visible: true, weight: 10, sortingFunction: Network.NetworkRequestNode.InitiatorComparator }, { id: 'cookies', title: Common.UIString('Cookies'), align: DataGrid.DataGrid.Align.Right, sortingFunction: Network.NetworkRequestNode.RequestCookiesCountComparator }, { id: 'setcookies', title: Common.UIString('Set Cookies'), align: DataGrid.DataGrid.Align.Right, sortingFunction: Network.NetworkRequestNode.ResponseCookiesCountComparator }, { id: 'size', title: Common.UIString('Size'), visible: true, subtitle: Common.UIString('Content'), align: DataGrid.DataGrid.Align.Right, sortingFunction: Network.NetworkRequestNode.SizeComparator }, { id: 'time', title: Common.UIString('Time'), visible: true, subtitle: Common.UIString('Latency'), align: DataGrid.DataGrid.Align.Right, sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'duration') }, {id: 'priority', title: Common.UIString('Priority'), sortingFunction: Network.NetworkRequestNode.PriorityComparator}, { id: 'connectionid', title: Common.UIString('Connection ID'), sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'connectionId') }, { id: 'cache-control', isResponseHeader: true, title: Common.UIString('Cache-Control'), sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'cache-control') }, { id: 'connection', isResponseHeader: true, title: Common.UIString('Connection'), sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'connection') }, { id: 'content-encoding', isResponseHeader: true, title: Common.UIString('Content-Encoding'), sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'content-encoding') }, { id: 'content-length', isResponseHeader: true, title: Common.UIString('Content-Length'), align: DataGrid.DataGrid.Align.Right, sortingFunction: Network.NetworkRequestNode.ResponseHeaderNumberComparator.bind(null, 'content-length') }, { id: 'etag', isResponseHeader: true, title: Common.UIString('ETag'), sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'etag') }, { id: 'keep-alive', isResponseHeader: true, title: Common.UIString('Keep-Alive'), sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'keep-alive') }, { id: 'last-modified', isResponseHeader: true, title: Common.UIString('Last-Modified'), sortingFunction: Network.NetworkRequestNode.ResponseHeaderDateComparator.bind(null, 'last-modified') }, { id: 'server', isResponseHeader: true, title: Common.UIString('Server'), sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'server') }, { id: 'vary', isResponseHeader: true, title: Common.UIString('Vary'), sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'vary') }, // This header is a placeholder to let datagrid know that it can be sorted by this column, but never shown. {id: 'waterfall', title: '', visible: false, hideable: false} ]; Network.NetworkLogViewColumns._filmStripDividerColor = '#fccc49'; /** * @enum {string} */ Network.NetworkLogViewColumns.WaterfallSortIds = { StartTime: 'startTime', ResponseTime: 'responseReceivedTime', EndTime: 'endTime', Duration: 'duration', Latency: 'latency' };