blob: 5df794ed59f03b2e04cbd971cd47ceea39a44374 [file] [log] [blame]
/*
* 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.
*/
/**
* @implements {UI.ContextMenu.Provider}
* @implements {UI.ViewLocationResolver}
*/
export default class NetworkPanel extends UI.Panel {
constructor() {
super('network');
this.registerRequiredCSS('network/networkPanel.css');
this._networkLogShowOverviewSetting = Common.settings.createSetting('networkLogShowOverview', true);
this._networkLogLargeRowsSetting = Common.settings.createSetting('networkLogLargeRows', false);
this._networkRecordFilmStripSetting = Common.settings.createSetting('networkRecordFilmStripSetting', false);
this._toggleRecordAction = /** @type {!UI.Action }*/ (UI.actionRegistry.action('network.toggle-recording'));
/** @type {number|undefined} */
this._pendingStopTimer;
/** @type {?Network.NetworkItemView} */
this._networkItemView = null;
/** @type {?PerfUI.FilmStripView} */
this._filmStripView = null;
/** @type {?FilmStripRecorder} */
this._filmStripRecorder = null;
/** @type {?SDK.NetworkRequest} */
this._currentRequest = null;
const panel = new UI.VBox();
const networkToolbarContainer = panel.contentElement.createChild('div', 'network-toolbar-container');
this._panelToolbar = new UI.Toolbar('', networkToolbarContainer);
this._rightToolbar = new UI.Toolbar('', networkToolbarContainer);
this._filterBar = new UI.FilterBar('networkPanel', true);
this._filterBar.show(panel.contentElement);
this._settingsPane = new UI.HBox();
this._settingsPane.element.classList.add('network-settings-pane');
this._settingsPane.show(panel.contentElement);
this._showSettingsPaneSetting = Common.settings.createSetting('networkShowSettingsToolbar', false);
this._showSettingsPaneSetting.addChangeListener(this._updateSettingsPaneVisibility.bind(this));
this._updateSettingsPaneVisibility();
this._filmStripPlaceholderElement = panel.contentElement.createChild('div', 'network-film-strip-placeholder');
// Create top overview component.
this._overviewPane = new PerfUI.TimelineOverviewPane('network');
this._overviewPane.addEventListener(
PerfUI.TimelineOverviewPane.Events.WindowChanged, this._onWindowChanged.bind(this));
this._overviewPane.element.id = 'network-overview-panel';
this._networkOverview = new Network.NetworkOverview();
this._overviewPane.setOverviewControls([this._networkOverview]);
this._overviewPlaceholderElement = panel.contentElement.createChild('div');
this._calculator = new Network.NetworkTransferTimeCalculator();
this._splitWidget = new UI.SplitWidget(true, false, 'networkPanelSplitViewState');
this._splitWidget.hideMain();
this._splitWidget.show(panel.contentElement);
panel.setDefaultFocusedChild(this._filterBar);
const initialSidebarWidth = 225;
const splitWidget = new UI.SplitWidget(true, false, 'networkPanelSidebarState', initialSidebarWidth);
splitWidget.hideSidebar();
splitWidget.enableShowModeSaving();
splitWidget.show(this.element);
this._sidebarLocation = UI.viewManager.createTabbedLocation(async () => {
UI.viewManager.showView('network');
splitWidget.showBoth();
}, 'network-sidebar', true);
const tabbedPane = this._sidebarLocation.tabbedPane();
tabbedPane.setMinimumSize(100, 25);
tabbedPane.element.classList.add('network-tabbed-pane');
tabbedPane.element.addEventListener('keydown', event => {
if (event.key !== 'Escape') {
return;
}
splitWidget.hideSidebar();
event.consume();
});
const closeSidebar = new UI.ToolbarButton(Common.UIString('Close'), 'largeicon-delete');
closeSidebar.addEventListener(UI.ToolbarButton.Events.Click, () => splitWidget.hideSidebar());
tabbedPane.rightToolbar().appendToolbarItem(closeSidebar);
splitWidget.setSidebarWidget(tabbedPane);
splitWidget.setMainWidget(panel);
splitWidget.setDefaultFocusedChild(panel);
this.setDefaultFocusedChild(splitWidget);
this._progressBarContainer = createElement('div');
/** @type {!Network.NetworkLogView} */
this._networkLogView =
new Network.NetworkLogView(this._filterBar, this._progressBarContainer, this._networkLogLargeRowsSetting);
this._splitWidget.setSidebarWidget(this._networkLogView);
this._fileSelectorElement =
UI.createFileSelectorElement(this._networkLogView.onLoadFromFile.bind(this._networkLogView));
panel.element.appendChild(this._fileSelectorElement);
this._detailsWidget = new UI.VBox();
this._detailsWidget.element.classList.add('network-details-view');
this._splitWidget.setMainWidget(this._detailsWidget);
this._closeButtonElement = createElement('div', 'dt-close-button');
this._closeButtonElement.addEventListener(
'click', async () => await UI.actionRegistry.action('network.hide-request-details').execute(), false);
this._closeButtonElement.style.margin = '0 5px';
this._networkLogShowOverviewSetting.addChangeListener(this._toggleShowOverview, this);
this._networkLogLargeRowsSetting.addChangeListener(this._toggleLargerRequests, this);
this._networkRecordFilmStripSetting.addChangeListener(this._toggleRecordFilmStrip, this);
this._preserveLogSetting = Common.moduleSetting('network_log.preserve-log');
this._throttlingSelect = this._createThrottlingConditionsSelect();
this._setupToolbarButtons(splitWidget);
this._toggleRecord(true);
this._toggleShowOverview();
this._toggleLargerRequests();
this._toggleRecordFilmStrip();
this._updateUI();
SDK.targetManager.addModelListener(
SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.WillReloadPage, this._willReloadPage, this);
SDK.targetManager.addModelListener(SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.Load, this._load, this);
this._networkLogView.addEventListener(Network.NetworkLogView.Events.RequestSelected, this._onRequestSelected, this);
this._networkLogView.addEventListener(
Network.NetworkLogView.Events.RequestActivated, this._onRequestActivated, this);
SDK.networkLog.addEventListener(SDK.NetworkLog.Events.RequestAdded, this._onUpdateRequest, this);
SDK.networkLog.addEventListener(SDK.NetworkLog.Events.RequestUpdated, this._onUpdateRequest, this);
SDK.networkLog.addEventListener(SDK.NetworkLog.Events.Reset, this._onNetworkLogReset, this);
}
/**
* @param {!Array<{filterType: !Network.NetworkLogView.FilterType, filterValue: string}>} filters
*/
static revealAndFilter(filters) {
const panel = NetworkPanel._instance();
let filterString = '';
for (const filter of filters) {
filterString += `${filter.filterType}:${filter.filterValue} `;
}
panel._networkLogView.setTextFilterValue(filterString);
UI.viewManager.showView('network');
}
/**
* @return {!NetworkPanel}
*/
static _instance() {
return /** @type {!NetworkPanel} */ (self.runtime.sharedInstance(NetworkPanel));
}
/**
* @return {!UI.ToolbarComboBox}
*/
throttlingSelectForTest() {
return this._throttlingSelect;
}
/**
* @param {!Common.Event} event
*/
_onWindowChanged(event) {
const startTime = Math.max(this._calculator.minimumBoundary(), event.data.startTime / 1000);
const endTime = Math.min(this._calculator.maximumBoundary(), event.data.endTime / 1000);
this._networkLogView.setWindow(startTime, endTime);
}
_setupToolbarButtons(splitWidget) {
const searchToggle = new UI.ToolbarToggle(ls`Search`, 'largeicon-search');
function updateSidebarToggle() {
const isSidebarShowing = splitWidget.showMode() !== UI.SplitWidget.ShowMode.OnlyMain;
searchToggle.setToggled(isSidebarShowing);
if (!isSidebarShowing) {
searchToggle.element.focus();
}
}
this._panelToolbar.appendToolbarItem(UI.Toolbar.createActionButton(this._toggleRecordAction));
const clearButton = new UI.ToolbarButton(Common.UIString('Clear'), 'largeicon-clear');
clearButton.addEventListener(UI.ToolbarButton.Events.Click, () => SDK.networkLog.reset(), this);
this._panelToolbar.appendToolbarItem(clearButton);
this._panelToolbar.appendSeparator();
this._panelToolbar.appendToolbarItem(this._filterBar.filterButton());
updateSidebarToggle();
splitWidget.addEventListener(UI.SplitWidget.Events.ShowModeChanged, updateSidebarToggle);
searchToggle.addEventListener(UI.ToolbarButton.Events.Click, () => {
if (splitWidget.showMode() === UI.SplitWidget.ShowMode.OnlyMain) {
splitWidget.showBoth();
} else {
splitWidget.hideSidebar();
}
});
this._panelToolbar.appendToolbarItem(searchToggle);
this._panelToolbar.appendSeparator();
this._panelToolbar.appendToolbarItem(new UI.ToolbarSettingCheckbox(
this._preserveLogSetting, Common.UIString('Do not clear log on page reload / navigation'),
Common.UIString('Preserve log')));
const disableCacheCheckbox = new UI.ToolbarSettingCheckbox(
Common.moduleSetting('cacheDisabled'), Common.UIString('Disable cache (while DevTools is open)'),
Common.UIString('Disable cache'));
this._panelToolbar.appendToolbarItem(disableCacheCheckbox);
this._panelToolbar.appendSeparator();
this._panelToolbar.appendToolbarItem(this._throttlingSelect);
this._rightToolbar.appendToolbarItem(new UI.ToolbarItem(this._progressBarContainer));
this._rightToolbar.appendSeparator();
this._rightToolbar.appendToolbarItem(
new UI.ToolbarSettingToggle(this._showSettingsPaneSetting, 'largeicon-settings-gear', ls`Network settings`));
const settingsToolbarLeft = new UI.Toolbar('', this._settingsPane.element);
settingsToolbarLeft.makeVertical();
settingsToolbarLeft.appendToolbarItem(
new UI.ToolbarSettingCheckbox(this._networkLogLargeRowsSetting, '', ls`Use large request rows`));
settingsToolbarLeft.appendToolbarItem(
new UI.ToolbarSettingCheckbox(this._networkLogShowOverviewSetting, '', ls`Show overview`));
const settingsToolbarRight = new UI.Toolbar('', this._settingsPane.element);
settingsToolbarRight.makeVertical();
settingsToolbarRight.appendToolbarItem(
new UI.ToolbarSettingCheckbox(Common.moduleSetting('network.group-by-frame'), '', ls`Group by frame`));
settingsToolbarRight.appendToolbarItem(
new UI.ToolbarSettingCheckbox(this._networkRecordFilmStripSetting, '', ls`Capture screenshots`));
this._panelToolbar.appendSeparator();
const importHarButton = new UI.ToolbarButton(ls`Import HAR file...`, 'largeicon-load');
importHarButton.addEventListener(UI.ToolbarButton.Events.Click, () => this._fileSelectorElement.click(), this);
this._panelToolbar.appendToolbarItem(importHarButton);
const exportHarButton = new UI.ToolbarButton(ls`Export HAR...`, 'largeicon-download');
exportHarButton.addEventListener(UI.ToolbarButton.Events.Click, () => this._networkLogView.exportAll(), this);
this._panelToolbar.appendToolbarItem(exportHarButton);
}
_updateSettingsPaneVisibility() {
this._settingsPane.element.classList.toggle('hidden', !this._showSettingsPaneSetting.get());
}
/**
* @return {!UI.ToolbarComboBox}
*/
_createThrottlingConditionsSelect() {
const toolbarItem = new UI.ToolbarComboBox(null, ls`Throttling`);
toolbarItem.setMaxWidth(160);
MobileThrottling.throttlingManager().decorateSelectWithNetworkThrottling(toolbarItem.selectElement());
return toolbarItem;
}
_toggleRecording() {
if (!this._preserveLogSetting.get() && !this._toggleRecordAction.toggled()) {
SDK.networkLog.reset();
}
this._toggleRecord(!this._toggleRecordAction.toggled());
}
/**
* @param {boolean} toggled
*/
_toggleRecord(toggled) {
this._toggleRecordAction.setToggled(toggled);
this._networkLogView.setRecording(toggled);
if (!toggled && this._filmStripRecorder) {
this._filmStripRecorder.stopRecording(this._filmStripAvailable.bind(this));
}
// TODO(einbinder) This should be moved to a setting/action that NetworkLog owns but NetworkPanel controls, but
// always be present in the command menu.
SDK.networkLog.setIsRecording(toggled);
}
/**
* @param {?SDK.FilmStripModel} filmStripModel
*/
_filmStripAvailable(filmStripModel) {
if (!filmStripModel) {
return;
}
const calculator = this._networkLogView.timeCalculator();
this._filmStripView.setModel(filmStripModel, calculator.minimumBoundary() * 1000, calculator.boundarySpan() * 1000);
this._networkOverview.setFilmStripModel(filmStripModel);
const timestamps = filmStripModel.frames().map(mapTimestamp);
/**
* @param {!SDK.FilmStripModel.Frame} frame
* @return {number}
*/
function mapTimestamp(frame) {
return frame.timestamp / 1000;
}
this._networkLogView.addFilmStripFrames(timestamps);
}
_onNetworkLogReset() {
Network.BlockedURLsPane.reset();
if (!this._preserveLogSetting.get()) {
this._calculator.reset();
this._overviewPane.reset();
}
if (this._filmStripView) {
this._resetFilmStripView();
}
}
/**
* @param {!Common.Event} event
*/
_willReloadPage(event) {
this._toggleRecord(true);
if (this._pendingStopTimer) {
clearTimeout(this._pendingStopTimer);
delete this._pendingStopTimer;
}
if (this.isShowing() && this._filmStripRecorder) {
this._filmStripRecorder.startRecording();
}
}
/**
* @param {!Common.Event} event
*/
_load(event) {
if (this._filmStripRecorder && this._filmStripRecorder.isRecording()) {
this._pendingStopTimer = setTimeout(this._stopFilmStripRecording.bind(this), displayScreenshotDelay);
}
}
_stopFilmStripRecording() {
this._filmStripRecorder.stopRecording(this._filmStripAvailable.bind(this));
delete this._pendingStopTimer;
}
_toggleLargerRequests() {
this._updateUI();
}
_toggleShowOverview() {
const toggled = this._networkLogShowOverviewSetting.get();
if (toggled) {
this._overviewPane.show(this._overviewPlaceholderElement);
} else {
this._overviewPane.detach();
}
this.doResize();
}
_toggleRecordFilmStrip() {
const toggled = this._networkRecordFilmStripSetting.get();
if (toggled && !this._filmStripRecorder) {
this._filmStripView = new PerfUI.FilmStripView();
this._filmStripView.setMode(PerfUI.FilmStripView.Modes.FrameBased);
this._filmStripView.element.classList.add('network-film-strip');
this._filmStripRecorder = new FilmStripRecorder(this._networkLogView.timeCalculator(), this._filmStripView);
this._filmStripView.show(this._filmStripPlaceholderElement);
this._filmStripView.addEventListener(PerfUI.FilmStripView.Events.FrameSelected, this._onFilmFrameSelected, this);
this._filmStripView.addEventListener(PerfUI.FilmStripView.Events.FrameEnter, this._onFilmFrameEnter, this);
this._filmStripView.addEventListener(PerfUI.FilmStripView.Events.FrameExit, this._onFilmFrameExit, this);
this._resetFilmStripView();
}
if (!toggled && this._filmStripRecorder) {
this._filmStripView.detach();
this._filmStripView = null;
this._filmStripRecorder = null;
}
}
_resetFilmStripView() {
const reloadShortcutDescriptor = UI.shortcutRegistry.shortcutDescriptorsForAction('inspector_main.reload')[0];
this._filmStripView.reset();
if (reloadShortcutDescriptor) {
this._filmStripView.setStatusText(
Common.UIString('Hit %s to reload and capture filmstrip.', reloadShortcutDescriptor.name));
}
}
/**
* @override
* @return {!Array.<!Element>}
*/
elementsToRestoreScrollPositionsFor() {
return this._networkLogView.elementsToRestoreScrollPositionsFor();
}
/**
* @override
*/
wasShown() {
UI.context.setFlavor(NetworkPanel, this);
// Record the network tool load time after the panel has loaded.
Host.userMetrics.panelLoaded('network', 'DevTools.Launch.Network');
}
/**
* @override
*/
willHide() {
UI.context.setFlavor(NetworkPanel, null);
}
/**
* @param {!SDK.NetworkRequest} request
*/
revealAndHighlightRequest(request) {
this._hideRequestPanel();
if (request) {
this._networkLogView.revealAndHighlightRequest(request);
}
}
/**
* @param {!SDK.NetworkRequest} request
* @return {!Promise<?Network.NetworkItemView>}
*/
async selectRequest(request) {
await UI.viewManager.showView('network');
this._networkLogView.selectRequest(request);
return this._networkItemView;
}
/**
* @param {!Common.Event} event
*/
_onRowSizeChanged(event) {
this._updateUI();
}
/**
* @param {!Common.Event} event
*/
_onRequestSelected(event) {
const request = /** @type {?SDK.NetworkRequest} */ (event.data);
this._currentRequest = request;
this._networkOverview.setHighlightedRequest(request);
this._updateNetworkItemView();
}
/**
* @param {!Common.Event} event
*/
_onRequestActivated(event) {
const showPanel = /** @type {boolean} */ (event.data);
if (showPanel) {
this._showRequestPanel();
} else {
this._hideRequestPanel();
}
}
_showRequestPanel() {
this._clearNetworkItemView();
if (this._currentRequest) {
this._createNetworkItemView();
}
this._updateUI();
}
_hideRequestPanel() {
this._clearNetworkItemView();
this._splitWidget.hideMain();
this._updateUI();
}
_updateNetworkItemView() {
if (this._splitWidget.showMode() === UI.SplitWidget.ShowMode.Both) {
this._clearNetworkItemView();
this._createNetworkItemView();
this._updateUI();
}
}
_clearNetworkItemView() {
if (this._networkItemView) {
this._networkItemView.detach();
this._networkItemView = null;
}
}
_createNetworkItemView() {
if (!this._currentRequest) {
return;
}
this._networkItemView = new Network.NetworkItemView(this._currentRequest, this._networkLogView.timeCalculator());
this._networkItemView.leftToolbar().appendToolbarItem(new UI.ToolbarItem(this._closeButtonElement));
this._networkItemView.show(this._detailsWidget.element);
this._splitWidget.showBoth();
}
_updateUI() {
this._detailsWidget.element.classList.toggle(
'network-details-view-tall-header', this._networkLogLargeRowsSetting.get());
this._networkLogView.switchViewMode(!this._splitWidget.isResizable());
}
/**
* @override
* @param {!Event} event
* @param {!UI.ContextMenu} contextMenu
* @param {!Object} target
* @this {NetworkPanel}
*/
appendApplicableItems(event, contextMenu, target) {
/**
* @this {NetworkPanel}
*/
function reveal(request) {
UI.viewManager.showView('network').then(this.revealAndHighlightRequest.bind(this, request));
}
/**
* @this {NetworkPanel}
*/
function appendRevealItem(request) {
contextMenu.revealSection().appendItem(Common.UIString('Reveal in Network panel'), reveal.bind(this, request));
}
if (event.target.isSelfOrDescendant(this.element)) {
return;
}
if (target instanceof SDK.Resource) {
const resource = /** @type {!SDK.Resource} */ (target);
if (resource.request) {
appendRevealItem.call(this, resource.request);
}
return;
}
if (target instanceof Workspace.UISourceCode) {
const uiSourceCode = /** @type {!Workspace.UISourceCode} */ (target);
const resource = Bindings.resourceForURL(uiSourceCode.url());
if (resource && resource.request) {
appendRevealItem.call(this, resource.request);
}
return;
}
if (!(target instanceof SDK.NetworkRequest)) {
return;
}
const request = /** @type {!SDK.NetworkRequest} */ (target);
if (this._networkItemView && this._networkItemView.isShowing() && this._networkItemView.request() === request) {
return;
}
appendRevealItem.call(this, request);
}
/**
* @param {!Common.Event} event
*/
_onFilmFrameSelected(event) {
const timestamp = /** @type {number} */ (event.data);
this._overviewPane.setWindowTimes(0, timestamp);
}
/**
* @param {!Common.Event} event
*/
_onFilmFrameEnter(event) {
const timestamp = /** @type {number} */ (event.data);
this._networkOverview.selectFilmStripFrame(timestamp);
this._networkLogView.selectFilmStripFrame(timestamp / 1000);
}
/**
* @param {!Common.Event} event
*/
_onFilmFrameExit(event) {
this._networkOverview.clearFilmStripFrame();
this._networkLogView.clearFilmStripFrame();
}
/**
* @param {!Common.Event} event
*/
_onUpdateRequest(event) {
const request = /** @type {!SDK.NetworkRequest} */ (event.data);
this._calculator.updateBoundaries(request);
// FIXME: Unify all time units across the frontend!
this._overviewPane.setBounds(this._calculator.minimumBoundary() * 1000, this._calculator.maximumBoundary() * 1000);
this._networkOverview.updateRequest(request);
this._overviewPane.scheduleUpdate();
}
/**
* @override
* @param {string} locationName
* @return {?UI.ViewLocation}
*/
resolveLocation(locationName) {
if (locationName === 'network-sidebar') {
return this._sidebarLocation;
}
return null;
}
}
export const displayScreenshotDelay = 1000;
/**
* @implements {UI.ContextMenu.Provider}
* @unrestricted
*/
export class ContextMenuProvider {
/**
* @override
* @param {!Event} event
* @param {!UI.ContextMenu} contextMenu
* @param {!Object} target
*/
appendApplicableItems(event, contextMenu, target) {
NetworkPanel._instance().appendApplicableItems(event, contextMenu, target);
}
}
/**
* @implements {Common.Revealer}
* @unrestricted
*/
export class RequestRevealer {
/**
* @override
* @param {!Object} request
* @return {!Promise}
*/
reveal(request) {
if (!(request instanceof SDK.NetworkRequest)) {
return Promise.reject(new Error('Internal error: not a network request'));
}
const panel = NetworkPanel._instance();
return UI.viewManager.showView('network').then(panel.revealAndHighlightRequest.bind(panel, request));
}
}
/**
* @implements {SDK.TracingManagerClient}
*/
export class FilmStripRecorder {
/**
* @param {!Network.NetworkTimeCalculator} timeCalculator
* @param {!PerfUI.FilmStripView} filmStripView
*/
constructor(timeCalculator, filmStripView) {
/** @type {?SDK.TracingManager} */
this._tracingManager = null;
/** @type {?SDK.ResourceTreeModel} */
this._resourceTreeModel = null;
this._timeCalculator = timeCalculator;
this._filmStripView = filmStripView;
/** @type {?SDK.TracingModel} */
this._tracingModel = null;
/** @type {?function(?SDK.FilmStripModel)} */
this._callback = null;
}
/**
* @override
* @param {!Array.<!SDK.TracingManager.EventPayload>} events
*/
traceEventsCollected(events) {
if (this._tracingModel) {
this._tracingModel.addEvents(events);
}
}
/**
* @override
*/
tracingComplete() {
if (!this._tracingModel || !this._tracingManager) {
return;
}
this._tracingModel.tracingComplete();
this._tracingManager = null;
this._callback(new SDK.FilmStripModel(this._tracingModel, this._timeCalculator.minimumBoundary() * 1000));
this._callback = null;
if (this._resourceTreeModel) {
this._resourceTreeModel.resumeReload();
}
this._resourceTreeModel = null;
}
/**
* @override
*/
tracingBufferUsage() {
}
/**
* @override
* @param {number} progress
*/
eventsRetrievalProgress(progress) {
}
startRecording() {
this._filmStripView.reset();
this._filmStripView.setStatusText(Common.UIString('Recording frames...'));
const tracingManagers = SDK.targetManager.models(SDK.TracingManager);
if (this._tracingManager || !tracingManagers.length) {
return;
}
this._tracingManager = tracingManagers[0];
this._resourceTreeModel = this._tracingManager.target().model(SDK.ResourceTreeModel);
if (this._tracingModel) {
this._tracingModel.dispose();
}
this._tracingModel = new SDK.TracingModel(new Bindings.TempFileBackingStorage());
this._tracingManager.start(this, '-*,disabled-by-default-devtools.screenshot', '');
Host.userMetrics.actionTaken(Host.UserMetrics.Action.FilmStripStartedRecording);
}
/**
* @return {boolean}
*/
isRecording() {
return !!this._tracingManager;
}
/**
* @param {function(?SDK.FilmStripModel)} callback
*/
stopRecording(callback) {
if (!this._tracingManager) {
return;
}
this._tracingManager.stop();
if (this._resourceTreeModel) {
this._resourceTreeModel.suspendReload();
}
this._callback = callback;
this._filmStripView.setStatusText(Common.UIString('Fetching frames...'));
}
}
/**
* @implements {UI.ActionDelegate}
*/
export class ActionDelegate {
/**
* @override
* @param {!UI.Context} context
* @param {string} actionId
* @return {boolean}
*/
handleAction(context, actionId) {
const panel = UI.context.flavor(NetworkPanel);
console.assert(panel && panel instanceof NetworkPanel);
switch (actionId) {
case 'network.toggle-recording':
panel._toggleRecording();
return true;
case 'network.hide-request-details':
if (!panel._networkItemView) {
return false;
}
panel._hideRequestPanel();
panel._networkLogView.resetFocus();
return true;
case 'network.search':
const selection = UI.inspectorView.element.window().getSelection();
let queryCandidate = '';
if (selection.rangeCount) {
queryCandidate = selection.toString().replace(/\r?\n.*/, '');
}
Network.SearchNetworkView.openSearch(queryCandidate);
return true;
}
return false;
}
}
/**
* @implements {Common.Revealer}
*/
export class RequestLocationRevealer {
/**
* @override
* @param {!Object} match
* @return {!Promise}
*/
async reveal(match) {
const location = /** @type {!Network.UIRequestLocation} */ (match);
const view = await NetworkPanel._instance().selectRequest(location.request);
if (!view) {
return;
}
if (location.searchMatch) {
await view.revealResponseBody(location.searchMatch.lineNumber);
}
if (location.requestHeader) {
view.revealRequestHeader(location.requestHeader.name);
}
if (location.responseHeader) {
view.revealResponseHeader(location.responseHeader.name);
}
}
}
export class SearchNetworkView extends Search.SearchView {
constructor() {
super('network');
}
/**
* @param {string} query
* @param {boolean=} searchImmediately
* @return {!Promise<!Search.SearchView>}
*/
static async openSearch(query, searchImmediately) {
await UI.viewManager.showView('network.search-network-tab');
const searchView =
/** @type {!Network.SearchNetworkView} */ (self.runtime.sharedInstance(Network.SearchNetworkView));
searchView.toggle(query, !!searchImmediately);
return searchView;
}
/**
* @override
* @return {!Search.SearchScope}
*/
createScope() {
return new Network.NetworkSearchScope();
}
}
/* Legacy exported object */
self.Network = self.Network || {};
/* Legacy exported object */
Network = Network || {};
/**
* @constructor
*/
Network.NetworkPanel = NetworkPanel;
Network.NetworkPanel.displayScreenshotDelay = displayScreenshotDelay;
/**
* @constructor
*/
Network.SearchNetworkView = SearchNetworkView;
/**
* @constructor
*/
Network.NetworkPanel.ContextMenuProvider = ContextMenuProvider;
/**
* @constructor
*/
Network.NetworkPanel.RequestRevealer = RequestRevealer;
/**
* @constructor
*/
Network.NetworkPanel.FilmStripRecorder = FilmStripRecorder;
/**
* @constructor
*/
Network.NetworkPanel.ActionDelegate = ActionDelegate;
/**
* @constructor
*/
Network.NetworkPanel.RequestLocationRevealer = RequestLocationRevealer;