blob: 5e5968afdc295a09814318c2feef0fc1df8c3b0a [file] [log] [blame]
/*
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com).
* Copyright (C) 2009 Joseph Pecoraro
*
* 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.
*/
/**
* @unrestricted
*/
Main.Main = class {
/**
* @suppressGlobalPropertiesCheck
*/
constructor() {
Main.Main._instanceForTest = this;
runOnWindowLoad(this._loaded.bind(this));
}
/**
* @param {boolean} hard
*/
static _reloadPage(hard) {
SDK.ResourceTreeModel.reloadAllPages(hard);
}
/**
* @param {string} label
*/
static time(label) {
if (Host.isUnderTest())
return;
console.time(label);
}
/**
* @param {string} label
*/
static timeEnd(label) {
if (Host.isUnderTest())
return;
console.timeEnd(label);
}
_loaded() {
console.timeStamp('Main._loaded');
Runtime.setPlatform(Host.platform());
InspectorFrontendHost.getPreferences(this._gotPreferences.bind(this));
}
/**
* @param {!Object<string, string>} prefs
*/
_gotPreferences(prefs) {
console.timeStamp('Main._gotPreferences');
if (Host.isUnderTest(prefs))
self.runtime.useTestBase();
this._createSettings(prefs);
this._createAppUI();
}
/**
* @param {!Object<string, string>} prefs
* Note: this function is called from testSettings in Tests.js.
*/
_createSettings(prefs) {
this._initializeExperiments(prefs);
var storagePrefix = '';
if (Host.isCustomDevtoolsFrontend())
storagePrefix = '__custom__';
else if (!Runtime.queryParam('can_dock') && !!Runtime.queryParam('debugFrontend') && !Host.isUnderTest(prefs))
storagePrefix = '__bundled__';
var clearLocalStorage = window.localStorage ? window.localStorage.clear.bind(window.localStorage) : undefined;
var localStorage =
new Common.SettingsStorage(window.localStorage || {}, undefined, undefined, clearLocalStorage, storagePrefix);
var globalStorage = new Common.SettingsStorage(
prefs, InspectorFrontendHost.setPreference, InspectorFrontendHost.removePreference,
InspectorFrontendHost.clearPreferences, storagePrefix);
Common.settings = new Common.Settings(globalStorage, localStorage);
if (!Host.isUnderTest(prefs))
new Common.VersionController().updateVersion();
}
/**
* @param {!Object<string, string>} prefs
*/
_initializeExperiments(prefs) {
// Keep this sorted alphabetically: both keys and values.
Runtime.experiments.register('accessibilityInspection', 'Accessibility Inspection');
Runtime.experiments.register('applyCustomStylesheet', 'Allow custom UI themes');
Runtime.experiments.register('audits2', 'Audits 2.0');
Runtime.experiments.register('autoAttachToCrossProcessSubframes', 'Auto-attach to cross-process subframes', true);
Runtime.experiments.register('blackboxJSFramesOnTimeline', 'Blackbox JavaScript frames on Timeline', true);
Runtime.experiments.register('changesDrawer', 'Changes drawer', true);
Runtime.experiments.register('colorContrastRatio', 'Color contrast ratio line in color picker', true);
Runtime.experiments.register('continueToLocationMarkers', 'Continue to location markers', true);
Runtime.experiments.register('emptySourceMapAutoStepping', 'Empty sourcemap auto-stepping');
Runtime.experiments.register('inputEventsOnTimelineOverview', 'Input events on Timeline overview', true);
Runtime.experiments.register('liveSASS', 'Live SASS');
Runtime.experiments.register('networkGroupingRequests', 'Network request groups support', true);
Runtime.experiments.register('objectPreviews', 'Object previews', true);
Runtime.experiments.register('networkInWorkers', 'Network in workers', true);
Runtime.experiments.register('persistence2', 'Persistence 2.0');
Runtime.experiments.register('sourceDiff', 'Source diff');
Runtime.experiments.register('terminalInDrawer', 'Terminal in drawer', true);
// Timeline
Runtime.experiments.register('timelineColorByProduct', 'Timeline: color by product', true);
Runtime.experiments.register('timelineEventInitiators', 'Timeline: event initiators');
Runtime.experiments.register('timelineFlowEvents', 'Timeline: flow events', true);
Runtime.experiments.register('timelineInvalidationTracking', 'Timeline: invalidation tracking', true);
Runtime.experiments.register('timelineKeepHistory', 'Timeline: keep recording history');
Runtime.experiments.register('timelineMultipleMainViews', 'Timeline: multiple main views');
Runtime.experiments.register('timelinePaintTimingMarkers', 'Timeline: paint timing markers', true);
Runtime.experiments.register('timelinePerFrameTrack', 'Timeline: per-frame tracks', true);
Runtime.experiments.register('timelineShowAllEvents', 'Timeline: show all events', true);
Runtime.experiments.register('timelineShowAllProcesses', 'Timeline: show all processes', true);
Runtime.experiments.register('timelineTracingJSProfile', 'Timeline: tracing based JS profiler', true);
Runtime.experiments.register('timelineV8RuntimeCallStats', 'Timeline: V8 Runtime Call Stats on Timeline', true);
Runtime.experiments.cleanUpStaleExperiments();
if (Host.isUnderTest(prefs)) {
var testPath = JSON.parse(prefs['testPath'] || '""');
// Enable experiments for testing.
if (testPath.indexOf('accessibility/') !== -1)
Runtime.experiments.enableForTest('accessibilityInspection');
if (testPath.indexOf('audits2/') !== -1)
Runtime.experiments.enableForTest('audits2');
if (testPath.indexOf('coverage/') !== -1)
Runtime.experiments.enableForTest('cssTrackerPanel');
if (testPath.indexOf('changes/') !== -1)
Runtime.experiments.enableForTest('changesDrawer');
if (testPath.indexOf('sass/') !== -1)
Runtime.experiments.enableForTest('liveSASS');
}
Runtime.experiments.setDefaultExperiments([
'continueToLocationMarkers', 'autoAttachToCrossProcessSubframes', 'objectPreviews', 'audits2',
'networkGroupingRequests', 'timelineColorByProduct'
]);
}
/**
* @suppressGlobalPropertiesCheck
*/
_createAppUI() {
Main.Main.time('Main._createAppUI');
UI.viewManager = new UI.ViewManager();
// Request filesystems early, we won't create connections until callback is fired. Things will happen in parallel.
Persistence.isolatedFileSystemManager = new Persistence.IsolatedFileSystemManager();
var themeSetting = Common.settings.createSetting('uiTheme', 'default');
UI.initializeUIUtils(document, themeSetting);
themeSetting.addChangeListener(Components.reload.bind(Components));
UI.installComponentRootStyles(/** @type {!Element} */ (document.body));
this._addMainEventListeners(document);
var canDock = !!Runtime.queryParam('can_dock');
UI.zoomManager = new UI.ZoomManager(window, InspectorFrontendHost);
UI.inspectorView = UI.InspectorView.instance();
UI.ContextMenu.initialize();
UI.ContextMenu.installHandler(document);
UI.Tooltip.installHandler(document);
Components.dockController = new Components.DockController(canDock);
ConsoleModel.consoleModel = new ConsoleModel.ConsoleModel();
SDK.multitargetNetworkManager = new SDK.MultitargetNetworkManager();
NetworkLog.networkLog = new NetworkLog.NetworkLog();
SDK.domDebuggerManager = new SDK.DOMDebuggerManager();
SDK.targetManager.addEventListener(
SDK.TargetManager.Events.SuspendStateChanged, this._onSuspendStateChanged.bind(this));
UI.shortcutsScreen = new UI.ShortcutsScreen();
// set order of some sections explicitly
UI.shortcutsScreen.section(Common.UIString('Elements Panel'));
UI.shortcutsScreen.section(Common.UIString('Styles Pane'));
UI.shortcutsScreen.section(Common.UIString('Debugger'));
UI.shortcutsScreen.section(Common.UIString('Console'));
Workspace.fileManager = new Workspace.FileManager();
Workspace.workspace = new Workspace.Workspace();
Persistence.fileSystemMapping = new Persistence.FileSystemMapping(Persistence.isolatedFileSystemManager);
Bindings.networkProjectManager = new Bindings.NetworkProjectManager(SDK.targetManager, Workspace.workspace);
Bindings.resourceMapping = new Bindings.ResourceMapping(SDK.targetManager, Workspace.workspace);
Bindings.presentationConsoleMessageHelper = new Bindings.PresentationConsoleMessageHelper(Workspace.workspace);
Bindings.cssWorkspaceBinding = new Bindings.CSSWorkspaceBinding(SDK.targetManager, Workspace.workspace);
Bindings.debuggerWorkspaceBinding = new Bindings.DebuggerWorkspaceBinding(SDK.targetManager, Workspace.workspace);
Bindings.breakpointManager =
new Bindings.BreakpointManager(null, Workspace.workspace, SDK.targetManager, Bindings.debuggerWorkspaceBinding);
Extensions.extensionServer = new Extensions.ExtensionServer();
new Persistence.FileSystemWorkspaceBinding(Persistence.isolatedFileSystemManager, Workspace.workspace);
Persistence.persistence =
new Persistence.Persistence(Workspace.workspace, Bindings.breakpointManager, Persistence.fileSystemMapping);
new Main.ExecutionContextSelector(SDK.targetManager, UI.context);
Bindings.blackboxManager = new Bindings.BlackboxManager(Bindings.debuggerWorkspaceBinding);
new Main.Main.PauseListener();
new Main.Main.InspectedNodeRevealer();
new Main.NetworkPanelIndicator();
new Main.SourcesPanelIndicator();
new Main.BackendSettingsSync();
UI.actionRegistry = new UI.ActionRegistry();
UI.shortcutRegistry = new UI.ShortcutRegistry(UI.actionRegistry, document);
UI.ShortcutsScreen.registerShortcuts();
this._registerForwardedShortcuts();
this._registerMessageSinkListener();
self.runtime.extension(Common.AppProvider).instance().then(this._showAppUI.bind(this));
Main.Main.timeEnd('Main._createAppUI');
}
/**
* @param {!Object} appProvider
* @suppressGlobalPropertiesCheck
*/
_showAppUI(appProvider) {
Main.Main.time('Main._showAppUI');
var app = /** @type {!Common.AppProvider} */ (appProvider).createApp();
// It is important to kick controller lifetime after apps are instantiated.
Components.dockController.initialize();
app.presentUI(document);
var toggleSearchNodeAction = UI.actionRegistry.action('elements.toggle-element-search');
// TODO: we should not access actions from other modules.
if (toggleSearchNodeAction) {
InspectorFrontendHost.events.addEventListener(
InspectorFrontendHostAPI.Events.EnterInspectElementMode,
toggleSearchNodeAction.execute.bind(toggleSearchNodeAction), this);
}
InspectorFrontendHost.events.addEventListener(
InspectorFrontendHostAPI.Events.RevealSourceLine, this._revealSourceLine, this);
UI.inspectorView.createToolbars();
InspectorFrontendHost.loadCompleted();
InspectorFrontendHost.events.addEventListener(
InspectorFrontendHostAPI.Events.ReloadInspectedPage, this._reloadInspectedPage, this);
var extensions = self.runtime.extensions(Common.QueryParamHandler);
for (var extension of extensions) {
var value = Runtime.queryParam(extension.descriptor()['name']);
if (value !== null)
extension.instance().then(handleQueryParam.bind(null, value));
}
/**
* @param {string} value
* @param {!Common.QueryParamHandler} handler
*/
function handleQueryParam(value, handler) {
handler.handleQueryParam(value);
}
// Allow UI cycles to repaint prior to creating connection.
setTimeout(this._initializeTarget.bind(this), 0);
Main.Main.timeEnd('Main._showAppUI');
}
_initializeTarget() {
Main.Main.time('Main._initializeTarget');
SDK.targetManager.connectToMainTarget(webSocketConnectionLost);
InspectorFrontendHost.readyForTest();
// Asynchronously run the extensions.
setTimeout(this._lateInitialization.bind(this), 100);
Main.Main.timeEnd('Main._initializeTarget');
function webSocketConnectionLost() {
if (!Main._disconnectedScreenWithReasonWasShown)
Main.RemoteDebuggingTerminatedScreen.show('WebSocket disconnected');
}
}
_lateInitialization() {
console.timeStamp('Main._lateInitialization');
this._registerShortcuts();
Extensions.extensionServer.initializeExtensions();
if (!Host.isUnderTest())
Help.showReleaseNoteIfNeeded();
}
_registerForwardedShortcuts() {
/** @const */ var forwardedActions = [
'main.toggle-dock', 'debugger.toggle-breakpoints-active', 'debugger.toggle-pause', 'commandMenu.show',
'console.show'
];
var actionKeys =
UI.shortcutRegistry.keysForActions(forwardedActions).map(UI.KeyboardShortcut.keyCodeAndModifiersFromKey);
InspectorFrontendHost.setWhitelistedShortcuts(JSON.stringify(actionKeys));
}
_registerMessageSinkListener() {
Common.console.addEventListener(Common.Console.Events.MessageAdded, messageAdded);
/**
* @param {!Common.Event} event
*/
function messageAdded(event) {
var message = /** @type {!Common.Console.Message} */ (event.data);
if (message.show)
Common.console.show();
}
}
/**
* @param {!Common.Event} event
*/
_revealSourceLine(event) {
var url = /** @type {string} */ (event.data['url']);
var lineNumber = /** @type {number} */ (event.data['lineNumber']);
var columnNumber = /** @type {number} */ (event.data['columnNumber']);
var uiSourceCode = Workspace.workspace.uiSourceCodeForURL(url);
if (uiSourceCode) {
Common.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
return;
}
/**
* @param {!Common.Event} event
*/
function listener(event) {
var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
if (uiSourceCode.url() === url) {
Common.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
Workspace.workspace.removeEventListener(Workspace.Workspace.Events.UISourceCodeAdded, listener);
}
}
Workspace.workspace.addEventListener(Workspace.Workspace.Events.UISourceCodeAdded, listener);
}
_registerShortcuts() {
var shortcut = UI.KeyboardShortcut;
var section = UI.shortcutsScreen.section(Common.UIString('All Panels'));
var keys = [
shortcut.makeDescriptor('[', shortcut.Modifiers.CtrlOrMeta),
shortcut.makeDescriptor(']', shortcut.Modifiers.CtrlOrMeta)
];
section.addRelatedKeys(keys, Common.UIString('Go to the panel to the left/right'));
var toggleConsoleLabel = Common.UIString('Show console');
section.addKey(shortcut.makeDescriptor(shortcut.Keys.Tilde, shortcut.Modifiers.Ctrl), toggleConsoleLabel);
section.addKey(shortcut.makeDescriptor(shortcut.Keys.Esc), Common.UIString('Toggle drawer'));
if (Components.dockController.canDock()) {
section.addKey(
shortcut.makeDescriptor('M', shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Shift),
Common.UIString('Toggle device mode'));
section.addKey(
shortcut.makeDescriptor('D', shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Shift),
Common.UIString('Toggle dock side'));
}
section.addKey(shortcut.makeDescriptor('f', shortcut.Modifiers.CtrlOrMeta), Common.UIString('Search'));
var advancedSearchShortcutModifier = Host.isMac() ?
UI.KeyboardShortcut.Modifiers.Meta | UI.KeyboardShortcut.Modifiers.Alt :
UI.KeyboardShortcut.Modifiers.Ctrl | UI.KeyboardShortcut.Modifiers.Shift;
var advancedSearchShortcut = shortcut.makeDescriptor('f', advancedSearchShortcutModifier);
section.addKey(advancedSearchShortcut, Common.UIString('Search across all sources'));
var inspectElementModeShortcuts =
UI.shortcutRegistry.shortcutDescriptorsForAction('elements.toggle-element-search');
if (inspectElementModeShortcuts.length)
section.addKey(inspectElementModeShortcuts[0], Common.UIString('Select node to inspect'));
var openResourceShortcut = UI.KeyboardShortcut.makeDescriptor('p', UI.KeyboardShortcut.Modifiers.CtrlOrMeta);
section.addKey(openResourceShortcut, Common.UIString('Go to source'));
if (Host.isMac()) {
keys = [
shortcut.makeDescriptor('g', shortcut.Modifiers.Meta),
shortcut.makeDescriptor('g', shortcut.Modifiers.Meta | shortcut.Modifiers.Shift)
];
section.addRelatedKeys(keys, Common.UIString('Find next/previous'));
}
}
_postDocumentKeyDown(event) {
if (event.handled)
return;
if (!UI.Dialog.hasInstance() && UI.inspectorView.currentPanelDeprecated()) {
UI.inspectorView.currentPanelDeprecated().handleShortcut(event);
if (event.handled) {
event.consume(true);
return;
}
}
UI.shortcutRegistry.handleShortcut(event);
}
/**
* @param {!Event} event
*/
_redispatchClipboardEvent(event) {
var eventCopy = new CustomEvent('clipboard-' + event.type, {bubbles: true});
eventCopy['original'] = event;
var document = event.target && event.target.ownerDocument;
var target = document ? document.deepActiveElement() : null;
if (target)
target.dispatchEvent(eventCopy);
if (eventCopy.handled)
event.preventDefault();
}
_contextMenuEventFired(event) {
if (event.handled || event.target.classList.contains('popup-glasspane'))
event.preventDefault();
}
/**
* @param {!Document} document
*/
_addMainEventListeners(document) {
document.addEventListener('keydown', this._postDocumentKeyDown.bind(this), false);
document.addEventListener('beforecopy', this._redispatchClipboardEvent.bind(this), true);
document.addEventListener('copy', this._redispatchClipboardEvent.bind(this), false);
document.addEventListener('cut', this._redispatchClipboardEvent.bind(this), false);
document.addEventListener('paste', this._redispatchClipboardEvent.bind(this), false);
document.addEventListener('contextmenu', this._contextMenuEventFired.bind(this), true);
}
/**
* @param {!Common.Event} event
*/
_reloadInspectedPage(event) {
var hard = /** @type {boolean} */ (event.data);
Main.Main._reloadPage(hard);
}
_onSuspendStateChanged() {
var suspended = SDK.targetManager.allTargetsSuspended();
UI.inspectorView.onSuspendStateChanged(suspended);
}
};
/**
* @implements {Protocol.InspectorDispatcher}
*/
Main.Main.InspectorModel = class extends SDK.SDKModel {
/**
* @param {!SDK.Target} target
*/
constructor(target) {
super(target);
target.registerInspectorDispatcher(this);
target.inspectorAgent().enable();
}
/**
* @override
* @param {string} reason
*/
detached(reason) {
Main._disconnectedScreenWithReasonWasShown = true;
Main.RemoteDebuggingTerminatedScreen.show(reason);
}
/**
* @override
*/
targetCrashed() {
var debuggerModel = this.target().model(SDK.DebuggerModel);
if (debuggerModel)
Main.TargetCrashedScreen.show(debuggerModel);
}
};
SDK.SDKModel.register(Main.Main.InspectorModel, SDK.Target.Capability.Inspector, true);
/**
* @implements {UI.ActionDelegate}
* @unrestricted
*/
Main.Main.ReloadActionDelegate = class {
/**
* @override
* @param {!UI.Context} context
* @param {string} actionId
* @return {boolean}
*/
handleAction(context, actionId) {
switch (actionId) {
case 'main.reload':
Main.Main._reloadPage(false);
return true;
case 'main.hard-reload':
Main.Main._reloadPage(true);
return true;
case 'main.debug-reload':
Components.reload();
return true;
}
return false;
}
};
/**
* @implements {UI.ActionDelegate}
* @unrestricted
*/
Main.Main.ZoomActionDelegate = class {
/**
* @override
* @param {!UI.Context} context
* @param {string} actionId
* @return {boolean}
*/
handleAction(context, actionId) {
if (InspectorFrontendHost.isHostedMode())
return false;
switch (actionId) {
case 'main.zoom-in':
InspectorFrontendHost.zoomIn();
return true;
case 'main.zoom-out':
InspectorFrontendHost.zoomOut();
return true;
case 'main.zoom-reset':
InspectorFrontendHost.resetZoom();
return true;
}
return false;
}
};
/**
* @implements {UI.ActionDelegate}
* @unrestricted
*/
Main.Main.SearchActionDelegate = class {
/**
* @override
* @param {!UI.Context} context
* @param {string} actionId
* @return {boolean}
* @suppressGlobalPropertiesCheck
*/
handleAction(context, actionId) {
var searchableView = UI.SearchableView.fromElement(document.deepActiveElement()) ||
UI.inspectorView.currentPanelDeprecated().searchableView();
if (!searchableView)
return false;
switch (actionId) {
case 'main.search-in-panel.find':
return searchableView.handleFindShortcut();
case 'main.search-in-panel.cancel':
return searchableView.handleCancelSearchShortcut();
case 'main.search-in-panel.find-next':
return searchableView.handleFindNextShortcut();
case 'main.search-in-panel.find-previous':
return searchableView.handleFindPreviousShortcut();
}
return false;
}
};
/**
* @implements {UI.ToolbarItem.Provider}
* @unrestricted
*/
Main.Main.WarningErrorCounter = class {
constructor() {
Main.Main.WarningErrorCounter._instanceForTest = this;
this._counter = createElement('div');
this._counter.addEventListener('click', Common.console.show.bind(Common.console), false);
this._toolbarItem = new UI.ToolbarItem(this._counter);
var shadowRoot = UI.createShadowRootWithCoreStyles(this._counter, 'main/errorWarningCounter.css');
this._errors = this._createItem(shadowRoot, 'smallicon-error');
this._warnings = this._createItem(shadowRoot, 'smallicon-warning');
this._titles = [];
ConsoleModel.consoleModel.addEventListener(ConsoleModel.ConsoleModel.Events.ConsoleCleared, this._update, this);
ConsoleModel.consoleModel.addEventListener(ConsoleModel.ConsoleModel.Events.MessageAdded, this._update, this);
ConsoleModel.consoleModel.addEventListener(ConsoleModel.ConsoleModel.Events.MessageUpdated, this._update, this);
this._update();
}
/**
* @param {!Node} shadowRoot
* @param {string} iconType
* @return {!{item: !Element, text: !Element}}
*/
_createItem(shadowRoot, iconType) {
var item = createElementWithClass('span', 'counter-item');
var icon = item.createChild('label', '', 'dt-icon-label');
icon.type = iconType;
var text = icon.createChild('span');
shadowRoot.appendChild(item);
return {item: item, text: text};
}
/**
* @param {!{item: !Element, text: !Element}} item
* @param {number} count
* @param {boolean} first
* @param {string} title
*/
_updateItem(item, count, first, title) {
item.item.classList.toggle('hidden', !count);
item.item.classList.toggle('counter-item-first', first);
item.text.textContent = count;
if (count)
this._titles.push(title);
}
_update() {
var errors = ConsoleModel.consoleModel.errors();
var warnings = ConsoleModel.consoleModel.warnings();
this._titles = [];
this._toolbarItem.setVisible(!!(errors || warnings));
this._updateItem(this._errors, errors, false, Common.UIString(errors === 1 ? '%d error' : '%d errors', errors));
this._updateItem(
this._warnings, warnings, !errors, Common.UIString(warnings === 1 ? '%d warning' : '%d warnings', warnings));
this._counter.title = this._titles.join(', ');
UI.inspectorView.toolbarItemResized();
}
/**
* @override
* @return {?UI.ToolbarItem}
*/
item() {
return this._toolbarItem;
}
};
/**
* @implements {UI.ToolbarItem.Provider}
*/
Main.Main.MainMenuItem = class {
constructor() {
this._item = new UI.ToolbarMenuButton(this._handleContextMenu.bind(this), true);
this._item.setTitle(Common.UIString('Customize and control DevTools'));
}
/**
* @override
* @return {?UI.ToolbarItem}
*/
item() {
return this._item;
}
/**
* @param {!UI.ContextMenu} contextMenu
*/
_handleContextMenu(contextMenu) {
if (Components.dockController.canDock()) {
var dockItemElement = createElementWithClass('div', 'flex-centered flex-auto');
var titleElement = dockItemElement.createChild('span', 'flex-auto');
titleElement.textContent = Common.UIString('Dock side');
var toggleDockSideShorcuts = UI.shortcutRegistry.shortcutDescriptorsForAction('main.toggle-dock');
titleElement.title = Common.UIString(
'Placement of DevTools relative to the page. (%s to restore last position)', toggleDockSideShorcuts[0].name);
dockItemElement.appendChild(titleElement);
var dockItemToolbar = new UI.Toolbar('', dockItemElement);
dockItemToolbar.makeBlueOnHover();
var undock = new UI.ToolbarToggle(Common.UIString('Undock into separate window'), 'largeicon-undock');
var bottom = new UI.ToolbarToggle(Common.UIString('Dock to bottom'), 'largeicon-dock-to-bottom');
var right = new UI.ToolbarToggle(Common.UIString('Dock to right'), 'largeicon-dock-to-right');
var left = new UI.ToolbarToggle(Common.UIString('Dock to left'), 'largeicon-dock-to-left');
undock.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
bottom.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
right.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
left.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
undock.addEventListener(
UI.ToolbarButton.Events.MouseUp, setDockSide.bind(null, Components.DockController.State.Undocked));
bottom.addEventListener(
UI.ToolbarButton.Events.MouseUp, setDockSide.bind(null, Components.DockController.State.DockedToBottom));
right.addEventListener(
UI.ToolbarButton.Events.MouseUp, setDockSide.bind(null, Components.DockController.State.DockedToRight));
left.addEventListener(
UI.ToolbarButton.Events.MouseUp, setDockSide.bind(null, Components.DockController.State.DockedToLeft));
undock.setToggled(Components.dockController.dockSide() === Components.DockController.State.Undocked);
bottom.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToBottom);
right.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToRight);
left.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToLeft);
dockItemToolbar.appendToolbarItem(undock);
dockItemToolbar.appendToolbarItem(left);
dockItemToolbar.appendToolbarItem(bottom);
dockItemToolbar.appendToolbarItem(right);
contextMenu.appendCustomItem(dockItemElement);
contextMenu.appendSeparator();
}
/**
* @param {string} side
*/
function setDockSide(side) {
Components.dockController.setDockSide(side);
contextMenu.discard();
}
contextMenu.appendAction(
'main.toggle-drawer', UI.inspectorView.drawerVisible() ? Common.UIString('Hide console drawer') :
Common.UIString('Show console drawer'));
contextMenu.appendItemsAtLocation('mainMenu');
var moreTools = contextMenu.namedSubMenu('mainMenuMoreTools');
var extensions = self.runtime.extensions('view', undefined, true);
for (var extension of extensions) {
var descriptor = extension.descriptor();
if (descriptor['persistence'] !== 'closeable')
continue;
if (descriptor['location'] !== 'drawer-view' && descriptor['location'] !== 'panel')
continue;
moreTools.appendItem(extension.title(), UI.viewManager.showView.bind(UI.viewManager, descriptor['id']));
}
var helpSubMenu = contextMenu.namedSubMenu('mainMenuHelp');
helpSubMenu.appendAction('settings.documentation');
helpSubMenu.appendItem('Release Notes', () => InspectorFrontendHost.openInNewTab(Help.latestReleaseNote().link));
}
};
/**
* @implements {UI.ToolbarItem.Provider}
*/
Main.Main.NodeIndicator = class {
constructor() {
var element = createElement('div');
var shadowRoot = UI.createShadowRootWithCoreStyles(element, 'main/nodeIcon.css');
this._element = shadowRoot.createChild('div', 'node-icon');
element.addEventListener('click', () => InspectorFrontendHost.openNodeFrontend(), false);
this._button = new UI.ToolbarItem(element);
this._button.setTitle(Common.UIString('Open dedicated DevTools for Node.js'));
SDK.targetManager.addEventListener(SDK.TargetManager.Events.AvailableNodeTargetsChanged, this._update, this);
this._button.setVisible(false);
this._update();
}
_update() {
this._element.classList.toggle('inactive', !SDK.targetManager.availableNodeTargetsCount());
if (SDK.targetManager.availableNodeTargetsCount())
this._button.setVisible(true);
}
/**
* @override
* @return {?UI.ToolbarItem}
*/
item() {
return this._button;
}
};
Main.NetworkPanelIndicator = class {
constructor() {
// TODO: we should not access network from other modules.
if (!UI.inspectorView.hasPanel('network'))
return;
var manager = SDK.multitargetNetworkManager;
manager.addEventListener(SDK.MultitargetNetworkManager.Events.ConditionsChanged, updateVisibility);
manager.addEventListener(SDK.MultitargetNetworkManager.Events.BlockedPatternsChanged, updateVisibility);
updateVisibility();
function updateVisibility() {
var icon = null;
if (manager.isThrottling()) {
icon = UI.Icon.create('smallicon-warning');
icon.title = Common.UIString('Network throttling is enabled');
} else if (manager.isBlocking()) {
icon = UI.Icon.create('smallicon-warning');
icon.title = Common.UIString('Requests may be blocked');
}
UI.inspectorView.setPanelIcon('network', icon);
}
}
};
/**
* @unrestricted
*/
Main.SourcesPanelIndicator = class {
constructor() {
Common.moduleSetting('javaScriptDisabled').addChangeListener(javaScriptDisabledChanged);
javaScriptDisabledChanged();
function javaScriptDisabledChanged() {
var icon = null;
var javaScriptDisabled = Common.moduleSetting('javaScriptDisabled').get();
if (javaScriptDisabled) {
icon = UI.Icon.create('smallicon-warning');
icon.title = Common.UIString('JavaScript is disabled');
}
UI.inspectorView.setPanelIcon('sources', icon);
}
}
};
/**
* @unrestricted
*/
Main.Main.PauseListener = class {
constructor() {
SDK.targetManager.addModelListener(
SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
}
/**
* @param {!Common.Event} event
*/
_debuggerPaused(event) {
SDK.targetManager.removeModelListener(
SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
var debuggerModel = /** @type {!SDK.DebuggerModel} */ (event.data);
var debuggerPausedDetails = debuggerModel.debuggerPausedDetails();
UI.context.setFlavor(SDK.Target, debuggerModel.target());
Common.Revealer.reveal(debuggerPausedDetails);
}
};
/**
* @unrestricted
*/
Main.Main.InspectedNodeRevealer = class {
constructor() {
SDK.targetManager.addModelListener(
SDK.OverlayModel, SDK.OverlayModel.Events.InspectNodeRequested, this._inspectNode, this);
}
/**
* @param {!Common.Event} event
*/
_inspectNode(event) {
var deferredNode = /** @type {!SDK.DeferredDOMNode} */ (event.data);
Common.Revealer.reveal(deferredNode);
}
};
/**
* @param {string} method
* @param {?Object} params
* @return {!Promise}
*/
Main.sendOverProtocol = function(method, params) {
return new Promise((resolve, reject) => {
Protocol.InspectorBackend.sendRawMessageForTesting(method, params, (err, ...results) => {
if (err)
return reject(err);
return resolve(results);
});
});
};
/**
* @unrestricted
*/
Main.RemoteDebuggingTerminatedScreen = class extends UI.VBox {
/**
* @param {string} reason
*/
constructor(reason) {
super(true);
this.registerRequiredCSS('main/remoteDebuggingTerminatedScreen.css');
var message = this.contentElement.createChild('div', 'message');
message.createChild('span').textContent = Common.UIString('Debugging connection was closed. Reason: ');
message.createChild('span', 'reason').textContent = reason;
this.contentElement.createChild('div', 'message').textContent =
Common.UIString('Reconnect when ready by reopening DevTools.');
var button = UI.createTextButton(Common.UIString('Reconnect DevTools'), () => window.location.reload());
this.contentElement.createChild('div', 'button').appendChild(button);
}
/**
* @param {string} reason
*/
static show(reason) {
var dialog = new UI.Dialog();
dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent);
dialog.addCloseButton();
dialog.setDimmed(true);
new Main.RemoteDebuggingTerminatedScreen(reason).show(dialog.contentElement);
dialog.show();
}
};
/**
* @unrestricted
*/
Main.TargetCrashedScreen = class extends UI.VBox {
/**
* @param {function()} hideCallback
*/
constructor(hideCallback) {
super(true);
this.registerRequiredCSS('main/targetCrashedScreen.css');
this.contentElement.createChild('div', 'message').textContent =
Common.UIString('DevTools was disconnected from the page.');
this.contentElement.createChild('div', 'message').textContent =
Common.UIString('Once page is reloaded, DevTools will automatically reconnect.');
this._hideCallback = hideCallback;
}
/**
* @param {!SDK.DebuggerModel} debuggerModel
*/
static show(debuggerModel) {
var dialog = new UI.Dialog();
dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent);
dialog.addCloseButton();
dialog.setDimmed(true);
var hideBound = dialog.hide.bind(dialog);
debuggerModel.addEventListener(SDK.DebuggerModel.Events.GlobalObjectCleared, hideBound);
new Main.TargetCrashedScreen(onHide).show(dialog.contentElement);
dialog.show();
function onHide() {
debuggerModel.removeEventListener(SDK.DebuggerModel.Events.GlobalObjectCleared, hideBound);
}
}
/**
* @override
*/
willHide() {
this._hideCallback.call(null);
}
};
/**
* @implements {SDK.TargetManager.Observer}
* @unrestricted
*/
Main.BackendSettingsSync = class {
constructor() {
this._autoAttachSetting = Common.settings.moduleSetting('autoAttachToCreatedPages');
this._autoAttachSetting.addChangeListener(this._update, this);
SDK.targetManager.observeTargets(this, SDK.Target.Capability.Browser);
}
/**
* @param {!SDK.Target} target
*/
_updateTarget(target) {
target.pageAgent().setAutoAttachToCreatedPages(this._autoAttachSetting.get());
}
_update() {
SDK.targetManager.targets(SDK.Target.Capability.Browser).forEach(this._updateTarget, this);
}
/**
* @param {!SDK.Target} target
* @override
*/
targetAdded(target) {
this._updateTarget(target);
}
/**
* @param {!SDK.Target} target
* @override
*/
targetRemoved(target) {
}
};
/**
* @implements {UI.SettingUI}
* @unrestricted
*/
Main.ShowMetricsRulersSettingUI = class {
/**
* @override
* @return {?Element}
*/
settingElement() {
return UI.SettingsUI.createSettingCheckbox(
Common.UIString('Show rulers'), Common.moduleSetting('showMetricsRulers'));
}
};
new Main.Main();