blob: d0e24d3055c653da10098a303b2330d5ad99a88e [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371/*
2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Matt Lilek ([email protected]).
4 * Copyright (C) 2009 Joseph Pecoraro
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * @unrestricted
33 */
34Main.Main = class {
35 /**
36 * @suppressGlobalPropertiesCheck
37 */
38 constructor() {
39 Main.Main._instanceForTest = this;
40 runOnWindowLoad(this._loaded.bind(this));
41 }
42
43 /**
44 * @param {string} label
45 */
46 static time(label) {
Tim van der Lippe1d6e57a2019-09-30 11:55:3447 if (Host.isUnderTest()) {
Blink Reformat4c46d092018-04-07 15:32:3748 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:3449 }
Blink Reformat4c46d092018-04-07 15:32:3750 console.time(label);
51 }
52
53 /**
54 * @param {string} label
55 */
56 static timeEnd(label) {
Tim van der Lippe1d6e57a2019-09-30 11:55:3457 if (Host.isUnderTest()) {
Blink Reformat4c46d092018-04-07 15:32:3758 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:3459 }
Blink Reformat4c46d092018-04-07 15:32:3760 console.timeEnd(label);
61 }
62
63 async _loaded() {
64 console.timeStamp('Main._loaded');
Pavel Feldman63e89eb2018-11-25 05:47:0965 await Runtime.appStarted();
Blink Reformat4c46d092018-04-07 15:32:3766 Runtime.setPlatform(Host.platform());
Vidal Diazleal0b6aff42019-04-20 01:15:4367 Runtime.setL10nCallback(ls);
Blink Reformat4c46d092018-04-07 15:32:3768 InspectorFrontendHost.getPreferences(this._gotPreferences.bind(this));
69 }
70
71 /**
72 * @param {!Object<string, string>} prefs
73 */
74 _gotPreferences(prefs) {
75 console.timeStamp('Main._gotPreferences');
Tim van der Lippe1d6e57a2019-09-30 11:55:3476 if (Host.isUnderTest(prefs)) {
Blink Reformat4c46d092018-04-07 15:32:3777 self.runtime.useTestBase();
Tim van der Lippe1d6e57a2019-09-30 11:55:3478 }
Blink Reformat4c46d092018-04-07 15:32:3779 this._createSettings(prefs);
80 this._createAppUI();
81 }
82
83 /**
84 * @param {!Object<string, string>} prefs
85 * Note: this function is called from testSettings in Tests.js.
86 */
87 _createSettings(prefs) {
88 this._initializeExperiments();
89 let storagePrefix = '';
Tim van der Lippe1d6e57a2019-09-30 11:55:3490 if (Host.isCustomDevtoolsFrontend()) {
Blink Reformat4c46d092018-04-07 15:32:3791 storagePrefix = '__custom__';
Tim van der Lippe1d6e57a2019-09-30 11:55:3492 } else if (!Runtime.queryParam('can_dock') && !!Runtime.queryParam('debugFrontend') && !Host.isUnderTest()) {
Blink Reformat4c46d092018-04-07 15:32:3793 storagePrefix = '__bundled__';
Tim van der Lippe1d6e57a2019-09-30 11:55:3494 }
Blink Reformat4c46d092018-04-07 15:32:3795
96 let localStorage;
97 if (!Host.isUnderTest() && window.localStorage) {
98 localStorage = new Common.SettingsStorage(
99 window.localStorage, undefined, undefined, () => window.localStorage.clear(), storagePrefix);
100 } else {
101 localStorage = new Common.SettingsStorage({}, undefined, undefined, undefined, storagePrefix);
102 }
103 const globalStorage = new Common.SettingsStorage(
104 prefs, InspectorFrontendHost.setPreference, InspectorFrontendHost.removePreference,
105 InspectorFrontendHost.clearPreferences, storagePrefix);
106 Common.settings = new Common.Settings(globalStorage, localStorage);
Tim van der Lippe1d6e57a2019-09-30 11:55:34107 if (!Host.isUnderTest()) {
Blink Reformat4c46d092018-04-07 15:32:37108 new Common.VersionController().updateVersion();
Tim van der Lippe1d6e57a2019-09-30 11:55:34109 }
Blink Reformat4c46d092018-04-07 15:32:37110 }
111
112 _initializeExperiments() {
113 // Keep this sorted alphabetically: both keys and values.
114 Runtime.experiments.register('applyCustomStylesheet', 'Allow custom UI themes');
Connor Clark5f267212019-07-26 23:59:11115 Runtime.experiments.register('captureNodeCreationStacks', 'Capture node creation stacks');
Alexei Filippovfdfefe02019-03-09 00:33:24116 Runtime.experiments.register('sourcesPrettyPrint', 'Automatically pretty print in the Sources Panel');
Rayan Kanso8fe8ee22019-03-04 14:58:46117 Runtime.experiments.register('backgroundServices', 'Background web platform feature events', true);
Fergus Dall0be4f4c2019-05-21 00:01:29118 Runtime.experiments.register('backgroundServicesNotifications', 'Background services section for Notifications');
Rayan Kanso8d7918a2019-07-03 21:03:38119 Runtime.experiments.register('backgroundServicesPaymentHandler', 'Background services section for Payment Handler');
Fergus Dall0be4f4c2019-05-21 00:01:29120 Runtime.experiments.register('backgroundServicesPushMessaging', 'Background services section for Push Messaging');
Rayan Kanso54809672019-07-24 18:40:28121 Runtime.experiments.register(
122 'backgroundServicesPeriodicBackgroundSync', 'Background services section for Periodic Background Sync');
Blink Reformat4c46d092018-04-07 15:32:37123 Runtime.experiments.register('blackboxJSFramesOnTimeline', 'Blackbox JavaScript frames on Timeline', true);
Paul Lewis8cddf9932019-09-27 16:40:07124 Runtime.experiments.register('cssOverview', 'CSS Overview');
Blink Reformat4c46d092018-04-07 15:32:37125 Runtime.experiments.register('emptySourceMapAutoStepping', 'Empty sourcemap auto-stepping');
126 Runtime.experiments.register('inputEventsOnTimelineOverview', 'Input events on Timeline overview', true);
Alexei Filippovfdfefe02019-03-09 00:33:24127 Runtime.experiments.register('liveHeapProfile', 'Live heap profile', true);
Blink Reformat4c46d092018-04-07 15:32:37128 Runtime.experiments.register('nativeHeapProfiler', 'Native memory sampling heap profiler', true);
Blink Reformat4c46d092018-04-07 15:32:37129 Runtime.experiments.register('protocolMonitor', 'Protocol Monitor');
Jan Schefflerfc2f3832019-09-24 14:03:32130 Runtime.experiments.register('recordCoverageWithPerformanceTracing', 'Record coverage while performance tracing');
Alexei Filippov6d2eb592018-10-25 21:48:56131 Runtime.experiments.register('samplingHeapProfilerTimeline', 'Sampling heap profiler timeline', true);
Blink Reformat4c46d092018-04-07 15:32:37132 Runtime.experiments.register('sourceDiff', 'Source diff');
Pavel Feldmanc9060ea2018-04-30 04:42:18133 Runtime.experiments.register('splitInDrawer', 'Split in drawer', true);
Joey Arharaef93562019-03-15 23:49:59134 Runtime.experiments.register('spotlight', 'Spotlight', true);
Blink Reformat4c46d092018-04-07 15:32:37135 Runtime.experiments.register('terminalInDrawer', 'Terminal in drawer', true);
136
137 // Timeline
138 Runtime.experiments.register('timelineEventInitiators', 'Timeline: event initiators');
139 Runtime.experiments.register('timelineFlowEvents', 'Timeline: flow events', true);
140 Runtime.experiments.register('timelineInvalidationTracking', 'Timeline: invalidation tracking', true);
Blink Reformat4c46d092018-04-07 15:32:37141 Runtime.experiments.register('timelineShowAllEvents', 'Timeline: show all events', true);
Blink Reformat4c46d092018-04-07 15:32:37142 Runtime.experiments.register('timelineV8RuntimeCallStats', 'Timeline: V8 Runtime Call Stats on Timeline', true);
Alexei Filippov57ccafb2018-08-14 20:59:05143 Runtime.experiments.register('timelineWebGL', 'Timeline: WebGL-based flamechart');
Blink Reformat4c46d092018-04-07 15:32:37144
145 Runtime.experiments.cleanUpStaleExperiments();
Jeff Fisher85b08e12019-06-13 22:24:21146 const enabledExperiments = Runtime.queryParam('enabledExperiments');
Tim van der Lippe1d6e57a2019-09-30 11:55:34147 if (enabledExperiments) {
Jeff Fisher85b08e12019-06-13 22:24:21148 Runtime.experiments.setServerEnabledExperiments(enabledExperiments.split(';'));
Tim van der Lippe1d6e57a2019-09-30 11:55:34149 }
Rayan Kanso93bacf72019-08-28 12:33:23150 Runtime.experiments.setDefaultExperiments([
151 'backgroundServices',
152 'backgroundServicesNotifications',
153 'backgroundServicesPushMessaging',
154 'backgroundServicesPaymentHandler',
155 ]);
Alexei Filippovfdfefe02019-03-09 00:33:24156
Tim van der Lippe1d6e57a2019-09-30 11:55:34157 if (Host.isUnderTest() && Runtime.queryParam('test').includes('live-line-level-heap-profile.js')) {
Alexei Filippovfdfefe02019-03-09 00:33:24158 Runtime.experiments.enableForTest('liveHeapProfile');
Tim van der Lippe1d6e57a2019-09-30 11:55:34159 }
Blink Reformat4c46d092018-04-07 15:32:37160 }
161
162 /**
163 * @suppressGlobalPropertiesCheck
164 */
165 async _createAppUI() {
166 Main.Main.time('Main._createAppUI');
167
168 UI.viewManager = new UI.ViewManager();
169
170 // Request filesystems early, we won't create connections until callback is fired. Things will happen in parallel.
171 Persistence.isolatedFileSystemManager = new Persistence.IsolatedFileSystemManager();
172
Erik Luo9adba992019-06-26 01:17:52173 const themeSetting = Common.settings.createSetting('uiTheme', 'systemPreferred');
Blink Reformat4c46d092018-04-07 15:32:37174 UI.initializeUIUtils(document, themeSetting);
175 themeSetting.addChangeListener(Components.reload.bind(Components));
176
177 UI.installComponentRootStyles(/** @type {!Element} */ (document.body));
178
179 this._addMainEventListeners(document);
180
181 const canDock = !!Runtime.queryParam('can_dock');
182 UI.zoomManager = new UI.ZoomManager(window, InspectorFrontendHost);
183 UI.inspectorView = UI.InspectorView.instance();
184 UI.ContextMenu.initialize();
185 UI.ContextMenu.installHandler(document);
186 UI.Tooltip.installHandler(document);
187 Components.dockController = new Components.DockController(canDock);
188 SDK.consoleModel = new SDK.ConsoleModel();
189 SDK.multitargetNetworkManager = new SDK.MultitargetNetworkManager();
190 SDK.domDebuggerManager = new SDK.DOMDebuggerManager();
191 SDK.targetManager.addEventListener(
192 SDK.TargetManager.Events.SuspendStateChanged, this._onSuspendStateChanged.bind(this));
193
194 UI.shortcutsScreen = new UI.ShortcutsScreen();
195 // set order of some sections explicitly
196 UI.shortcutsScreen.section(Common.UIString('Elements Panel'));
197 UI.shortcutsScreen.section(Common.UIString('Styles Pane'));
198 UI.shortcutsScreen.section(Common.UIString('Debugger'));
199 UI.shortcutsScreen.section(Common.UIString('Console'));
200
201 Workspace.fileManager = new Workspace.FileManager();
202 Workspace.workspace = new Workspace.Workspace();
203
204 Bindings.networkProjectManager = new Bindings.NetworkProjectManager();
205 Bindings.resourceMapping = new Bindings.ResourceMapping(SDK.targetManager, Workspace.workspace);
206 new Bindings.PresentationConsoleMessageManager();
207 Bindings.cssWorkspaceBinding = new Bindings.CSSWorkspaceBinding(SDK.targetManager, Workspace.workspace);
208 Bindings.debuggerWorkspaceBinding = new Bindings.DebuggerWorkspaceBinding(SDK.targetManager, Workspace.workspace);
209 Bindings.breakpointManager =
210 new Bindings.BreakpointManager(Workspace.workspace, SDK.targetManager, Bindings.debuggerWorkspaceBinding);
211 Extensions.extensionServer = new Extensions.ExtensionServer();
212
213 new Persistence.FileSystemWorkspaceBinding(Persistence.isolatedFileSystemManager, Workspace.workspace);
214 Persistence.persistence = new Persistence.Persistence(Workspace.workspace, Bindings.breakpointManager);
215 Persistence.networkPersistenceManager = new Persistence.NetworkPersistenceManager(Workspace.workspace);
216
217 new Main.ExecutionContextSelector(SDK.targetManager, UI.context);
218 Bindings.blackboxManager = new Bindings.BlackboxManager(Bindings.debuggerWorkspaceBinding);
219
220 new Main.Main.PauseListener();
221
222 UI.actionRegistry = new UI.ActionRegistry();
223 UI.shortcutRegistry = new UI.ShortcutRegistry(UI.actionRegistry, document);
224 UI.ShortcutsScreen.registerShortcuts();
225 this._registerForwardedShortcuts();
226 this._registerMessageSinkListener();
227
228 Main.Main.timeEnd('Main._createAppUI');
229 this._showAppUI(await self.runtime.extension(Common.AppProvider).instance());
230 }
231
232 /**
233 * @param {!Object} appProvider
234 * @suppressGlobalPropertiesCheck
235 */
236 _showAppUI(appProvider) {
237 Main.Main.time('Main._showAppUI');
238 const app = /** @type {!Common.AppProvider} */ (appProvider).createApp();
239 // It is important to kick controller lifetime after apps are instantiated.
240 Components.dockController.initialize();
241 app.presentUI(document);
242
243 const toggleSearchNodeAction = UI.actionRegistry.action('elements.toggle-element-search');
244 // TODO: we should not access actions from other modules.
245 if (toggleSearchNodeAction) {
246 InspectorFrontendHost.events.addEventListener(
Tim van der Lippe7b190162019-09-27 15:10:44247 Host.InspectorFrontendHostAPI.Events.EnterInspectElementMode,
Blink Reformat4c46d092018-04-07 15:32:37248 toggleSearchNodeAction.execute.bind(toggleSearchNodeAction), this);
249 }
250 InspectorFrontendHost.events.addEventListener(
Tim van der Lippe7b190162019-09-27 15:10:44251 Host.InspectorFrontendHostAPI.Events.RevealSourceLine, this._revealSourceLine, this);
Blink Reformat4c46d092018-04-07 15:32:37252
253 UI.inspectorView.createToolbars();
254 InspectorFrontendHost.loadCompleted();
255
256 const extensions = self.runtime.extensions(Common.QueryParamHandler);
257 for (const extension of extensions) {
258 const value = Runtime.queryParam(extension.descriptor()['name']);
Tim van der Lippe1d6e57a2019-09-30 11:55:34259 if (value !== null) {
Blink Reformat4c46d092018-04-07 15:32:37260 extension.instance().then(handleQueryParam.bind(null, value));
Tim van der Lippe1d6e57a2019-09-30 11:55:34261 }
Blink Reformat4c46d092018-04-07 15:32:37262 }
263
264 /**
265 * @param {string} value
266 * @param {!Common.QueryParamHandler} handler
267 */
268 function handleQueryParam(value, handler) {
269 handler.handleQueryParam(value);
270 }
271
272 // Allow UI cycles to repaint prior to creating connection.
273 setTimeout(this._initializeTarget.bind(this), 0);
274 Main.Main.timeEnd('Main._showAppUI');
275 }
276
277 async _initializeTarget() {
278 Main.Main.time('Main._initializeTarget');
279 const instances =
280 await Promise.all(self.runtime.extensions('early-initialization').map(extension => extension.instance()));
Tim van der Lippe1d6e57a2019-09-30 11:55:34281 for (const instance of instances) {
Pavel Feldman07ef9722018-12-13 23:52:22282 await /** @type {!Common.Runnable} */ (instance).run();
Tim van der Lippe1d6e57a2019-09-30 11:55:34283 }
Blink Reformat4c46d092018-04-07 15:32:37284 // Used for browser tests.
285 InspectorFrontendHost.readyForTest();
286 // Asynchronously run the extensions.
287 setTimeout(this._lateInitialization.bind(this), 100);
288 Main.Main.timeEnd('Main._initializeTarget');
289 }
290
291 _lateInitialization() {
292 Main.Main.time('Main._lateInitialization');
293 this._registerShortcuts();
294 Extensions.extensionServer.initializeExtensions();
Alexei Filippov19be5102019-04-16 20:40:24295 const extensions = self.runtime.extensions('late-initialization');
296 const promises = [];
297 for (const extension of extensions) {
298 const setting = extension.descriptor()['setting'];
299 if (!setting || Common.settings.moduleSetting(setting).get()) {
300 promises.push(extension.instance().then(instance => (/** @type {!Common.Runnable} */ (instance)).run()));
301 continue;
302 }
303 /**
304 * @param {!Common.Event} event
305 */
306 async function changeListener(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34307 if (!event.data) {
Alexei Filippov19be5102019-04-16 20:40:24308 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34309 }
Alexei Filippov19be5102019-04-16 20:40:24310 Common.settings.moduleSetting(setting).removeChangeListener(changeListener);
311 (/** @type {!Common.Runnable} */ (await extension.instance())).run();
312 }
313 Common.settings.moduleSetting(setting).addChangeListener(changeListener);
314 }
315 this._lateInitDonePromise = Promise.all(promises);
Blink Reformat4c46d092018-04-07 15:32:37316 Main.Main.timeEnd('Main._lateInitialization');
317 }
318
Alexei Filippov19be5102019-04-16 20:40:24319 /**
320 * @return {!Promise}
321 */
322 lateInitDonePromiseForTest() {
323 return this._lateInitDonePromise;
324 }
325
Blink Reformat4c46d092018-04-07 15:32:37326 _registerForwardedShortcuts() {
327 /** @const */ const forwardedActions = [
328 'main.toggle-dock', 'debugger.toggle-breakpoints-active', 'debugger.toggle-pause', 'commandMenu.show',
329 'console.show'
330 ];
331 const actionKeys =
332 UI.shortcutRegistry.keysForActions(forwardedActions).map(UI.KeyboardShortcut.keyCodeAndModifiersFromKey);
333 InspectorFrontendHost.setWhitelistedShortcuts(JSON.stringify(actionKeys));
334 }
335
336 _registerMessageSinkListener() {
337 Common.console.addEventListener(Common.Console.Events.MessageAdded, messageAdded);
338
339 /**
340 * @param {!Common.Event} event
341 */
342 function messageAdded(event) {
343 const message = /** @type {!Common.Console.Message} */ (event.data);
Tim van der Lippe1d6e57a2019-09-30 11:55:34344 if (message.show) {
Blink Reformat4c46d092018-04-07 15:32:37345 Common.console.show();
Tim van der Lippe1d6e57a2019-09-30 11:55:34346 }
Blink Reformat4c46d092018-04-07 15:32:37347 }
348 }
349
350 /**
351 * @param {!Common.Event} event
352 */
353 _revealSourceLine(event) {
354 const url = /** @type {string} */ (event.data['url']);
355 const lineNumber = /** @type {number} */ (event.data['lineNumber']);
356 const columnNumber = /** @type {number} */ (event.data['columnNumber']);
357
358 const uiSourceCode = Workspace.workspace.uiSourceCodeForURL(url);
359 if (uiSourceCode) {
360 Common.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
361 return;
362 }
363
364 /**
365 * @param {!Common.Event} event
366 */
367 function listener(event) {
368 const uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
369 if (uiSourceCode.url() === url) {
370 Common.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
371 Workspace.workspace.removeEventListener(Workspace.Workspace.Events.UISourceCodeAdded, listener);
372 }
373 }
374
375 Workspace.workspace.addEventListener(Workspace.Workspace.Events.UISourceCodeAdded, listener);
376 }
377
378 _registerShortcuts() {
379 const shortcut = UI.KeyboardShortcut;
380 const section = UI.shortcutsScreen.section(Common.UIString('All Panels'));
381 let keys = [
382 shortcut.makeDescriptor('[', shortcut.Modifiers.CtrlOrMeta),
383 shortcut.makeDescriptor(']', shortcut.Modifiers.CtrlOrMeta)
384 ];
385 section.addRelatedKeys(keys, Common.UIString('Go to the panel to the left/right'));
386
387 const toggleConsoleLabel = Common.UIString('Show console');
388 section.addKey(shortcut.makeDescriptor(shortcut.Keys.Tilde, shortcut.Modifiers.Ctrl), toggleConsoleLabel);
389 section.addKey(shortcut.makeDescriptor(shortcut.Keys.Esc), Common.UIString('Toggle drawer'));
390 if (Components.dockController.canDock()) {
391 section.addKey(
392 shortcut.makeDescriptor('M', shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Shift),
393 Common.UIString('Toggle device mode'));
394 section.addKey(
395 shortcut.makeDescriptor('D', shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Shift),
396 Common.UIString('Toggle dock side'));
397 }
398 section.addKey(shortcut.makeDescriptor('f', shortcut.Modifiers.CtrlOrMeta), Common.UIString('Search'));
399
400 const advancedSearchShortcutModifier = Host.isMac() ?
401 UI.KeyboardShortcut.Modifiers.Meta | UI.KeyboardShortcut.Modifiers.Alt :
402 UI.KeyboardShortcut.Modifiers.Ctrl | UI.KeyboardShortcut.Modifiers.Shift;
403 const advancedSearchShortcut = shortcut.makeDescriptor('f', advancedSearchShortcutModifier);
404 section.addKey(advancedSearchShortcut, Common.UIString('Search across all sources'));
405
406 const inspectElementModeShortcuts =
407 UI.shortcutRegistry.shortcutDescriptorsForAction('elements.toggle-element-search');
Tim van der Lippe1d6e57a2019-09-30 11:55:34408 if (inspectElementModeShortcuts.length) {
Blink Reformat4c46d092018-04-07 15:32:37409 section.addKey(inspectElementModeShortcuts[0], Common.UIString('Select node to inspect'));
Tim van der Lippe1d6e57a2019-09-30 11:55:34410 }
Blink Reformat4c46d092018-04-07 15:32:37411
412 const openResourceShortcut = UI.KeyboardShortcut.makeDescriptor('p', UI.KeyboardShortcut.Modifiers.CtrlOrMeta);
413 section.addKey(openResourceShortcut, Common.UIString('Go to source'));
414
415 if (Host.isMac()) {
416 keys = [
417 shortcut.makeDescriptor('g', shortcut.Modifiers.Meta),
418 shortcut.makeDescriptor('g', shortcut.Modifiers.Meta | shortcut.Modifiers.Shift)
419 ];
420 section.addRelatedKeys(keys, Common.UIString('Find next/previous'));
421 }
422 }
423
424 _postDocumentKeyDown(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34425 if (!event.handled) {
Joel Einbindera66e5bf2018-05-31 01:26:37426 UI.shortcutRegistry.handleShortcut(event);
Tim van der Lippe1d6e57a2019-09-30 11:55:34427 }
Blink Reformat4c46d092018-04-07 15:32:37428 }
429
430 /**
431 * @param {!Event} event
432 */
433 _redispatchClipboardEvent(event) {
434 const eventCopy = new CustomEvent('clipboard-' + event.type, {bubbles: true});
435 eventCopy['original'] = event;
436 const document = event.target && event.target.ownerDocument;
437 const target = document ? document.deepActiveElement() : null;
Tim van der Lippe1d6e57a2019-09-30 11:55:34438 if (target) {
Blink Reformat4c46d092018-04-07 15:32:37439 target.dispatchEvent(eventCopy);
Tim van der Lippe1d6e57a2019-09-30 11:55:34440 }
441 if (eventCopy.handled) {
Blink Reformat4c46d092018-04-07 15:32:37442 event.preventDefault();
Tim van der Lippe1d6e57a2019-09-30 11:55:34443 }
Blink Reformat4c46d092018-04-07 15:32:37444 }
445
446 _contextMenuEventFired(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34447 if (event.handled || event.target.classList.contains('popup-glasspane')) {
Blink Reformat4c46d092018-04-07 15:32:37448 event.preventDefault();
Tim van der Lippe1d6e57a2019-09-30 11:55:34449 }
Blink Reformat4c46d092018-04-07 15:32:37450 }
451
452 /**
453 * @param {!Document} document
454 */
455 _addMainEventListeners(document) {
456 document.addEventListener('keydown', this._postDocumentKeyDown.bind(this), false);
457 document.addEventListener('beforecopy', this._redispatchClipboardEvent.bind(this), true);
458 document.addEventListener('copy', this._redispatchClipboardEvent.bind(this), false);
459 document.addEventListener('cut', this._redispatchClipboardEvent.bind(this), false);
460 document.addEventListener('paste', this._redispatchClipboardEvent.bind(this), false);
461 document.addEventListener('contextmenu', this._contextMenuEventFired.bind(this), true);
462 }
463
464 _onSuspendStateChanged() {
465 const suspended = SDK.targetManager.allTargetsSuspended();
466 UI.inspectorView.onSuspendStateChanged(suspended);
467 }
468};
469
470/**
471 * @implements {UI.ActionDelegate}
472 * @unrestricted
473 */
474Main.Main.ZoomActionDelegate = class {
475 /**
476 * @override
477 * @param {!UI.Context} context
478 * @param {string} actionId
479 * @return {boolean}
480 */
481 handleAction(context, actionId) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34482 if (InspectorFrontendHost.isHostedMode()) {
Blink Reformat4c46d092018-04-07 15:32:37483 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34484 }
Blink Reformat4c46d092018-04-07 15:32:37485
486 switch (actionId) {
487 case 'main.zoom-in':
488 InspectorFrontendHost.zoomIn();
489 return true;
490 case 'main.zoom-out':
491 InspectorFrontendHost.zoomOut();
492 return true;
493 case 'main.zoom-reset':
494 InspectorFrontendHost.resetZoom();
495 return true;
496 }
497 return false;
498 }
499};
500
501/**
502 * @implements {UI.ActionDelegate}
503 * @unrestricted
504 */
505Main.Main.SearchActionDelegate = class {
506 /**
507 * @override
508 * @param {!UI.Context} context
509 * @param {string} actionId
510 * @return {boolean}
511 * @suppressGlobalPropertiesCheck
512 */
513 handleAction(context, actionId) {
514 const searchableView = UI.SearchableView.fromElement(document.deepActiveElement()) ||
515 UI.inspectorView.currentPanelDeprecated().searchableView();
Tim van der Lippe1d6e57a2019-09-30 11:55:34516 if (!searchableView) {
Blink Reformat4c46d092018-04-07 15:32:37517 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34518 }
Blink Reformat4c46d092018-04-07 15:32:37519 switch (actionId) {
520 case 'main.search-in-panel.find':
521 return searchableView.handleFindShortcut();
522 case 'main.search-in-panel.cancel':
523 return searchableView.handleCancelSearchShortcut();
524 case 'main.search-in-panel.find-next':
525 return searchableView.handleFindNextShortcut();
526 case 'main.search-in-panel.find-previous':
527 return searchableView.handleFindPreviousShortcut();
528 }
529 return false;
530 }
531};
532
533/**
534 * @implements {UI.ToolbarItem.Provider}
535 */
536Main.Main.MainMenuItem = class {
537 constructor() {
538 this._item = new UI.ToolbarMenuButton(this._handleContextMenu.bind(this), true);
539 this._item.setTitle(Common.UIString('Customize and control DevTools'));
540 }
541
542 /**
543 * @override
544 * @return {?UI.ToolbarItem}
545 */
546 item() {
547 return this._item;
548 }
549
550 /**
551 * @param {!UI.ContextMenu} contextMenu
552 */
553 _handleContextMenu(contextMenu) {
554 if (Components.dockController.canDock()) {
555 const dockItemElement = createElementWithClass('div', 'flex-centered flex-auto');
Joel Einbinder57b9fad2019-02-08 23:31:35556 dockItemElement.tabIndex = -1;
Blink Reformat4c46d092018-04-07 15:32:37557 const titleElement = dockItemElement.createChild('span', 'flex-auto');
558 titleElement.textContent = Common.UIString('Dock side');
559 const toggleDockSideShorcuts = UI.shortcutRegistry.shortcutDescriptorsForAction('main.toggle-dock');
560 titleElement.title = Common.UIString(
561 'Placement of DevTools relative to the page. (%s to restore last position)', toggleDockSideShorcuts[0].name);
562 dockItemElement.appendChild(titleElement);
563 const dockItemToolbar = new UI.Toolbar('', dockItemElement);
Tim van der Lippe1d6e57a2019-09-30 11:55:34564 if (Host.isMac() && !UI.themeSupport.hasTheme()) {
Joel Einbinder9a6bead2018-08-06 18:02:35565 dockItemToolbar.makeBlueOnHover();
Tim van der Lippe1d6e57a2019-09-30 11:55:34566 }
Blink Reformat4c46d092018-04-07 15:32:37567 const undock = new UI.ToolbarToggle(Common.UIString('Undock into separate window'), 'largeicon-undock');
568 const bottom = new UI.ToolbarToggle(Common.UIString('Dock to bottom'), 'largeicon-dock-to-bottom');
569 const right = new UI.ToolbarToggle(Common.UIString('Dock to right'), 'largeicon-dock-to-right');
570 const left = new UI.ToolbarToggle(Common.UIString('Dock to left'), 'largeicon-dock-to-left');
571 undock.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
572 bottom.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
573 right.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
574 left.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
575 undock.addEventListener(
Joel Einbinder57b9fad2019-02-08 23:31:35576 UI.ToolbarButton.Events.Click, setDockSide.bind(null, Components.DockController.State.Undocked));
Blink Reformat4c46d092018-04-07 15:32:37577 bottom.addEventListener(
Joel Einbinder57b9fad2019-02-08 23:31:35578 UI.ToolbarButton.Events.Click, setDockSide.bind(null, Components.DockController.State.DockedToBottom));
Blink Reformat4c46d092018-04-07 15:32:37579 right.addEventListener(
Joel Einbinder57b9fad2019-02-08 23:31:35580 UI.ToolbarButton.Events.Click, setDockSide.bind(null, Components.DockController.State.DockedToRight));
Blink Reformat4c46d092018-04-07 15:32:37581 left.addEventListener(
Joel Einbinder57b9fad2019-02-08 23:31:35582 UI.ToolbarButton.Events.Click, setDockSide.bind(null, Components.DockController.State.DockedToLeft));
Blink Reformat4c46d092018-04-07 15:32:37583 undock.setToggled(Components.dockController.dockSide() === Components.DockController.State.Undocked);
584 bottom.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToBottom);
585 right.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToRight);
586 left.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToLeft);
587 dockItemToolbar.appendToolbarItem(undock);
588 dockItemToolbar.appendToolbarItem(left);
589 dockItemToolbar.appendToolbarItem(bottom);
590 dockItemToolbar.appendToolbarItem(right);
Joel Einbinder57b9fad2019-02-08 23:31:35591 dockItemElement.addEventListener('keydown', event => {
592 let dir = 0;
Tim van der Lippe1d6e57a2019-09-30 11:55:34593 if (event.key === 'ArrowLeft') {
Joel Einbinder57b9fad2019-02-08 23:31:35594 dir = -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34595 } else if (event.key === 'ArrowRight') {
Joel Einbinder57b9fad2019-02-08 23:31:35596 dir = 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34597 } else {
Joel Einbinder57b9fad2019-02-08 23:31:35598 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34599 }
Joel Einbinder57b9fad2019-02-08 23:31:35600
601 const buttons = [undock, left, bottom, right];
602 let index = buttons.findIndex(button => button.element.hasFocus());
603 index = Number.constrain(index + dir, 0, buttons.length - 1);
604
605 buttons[index].element.focus();
606 event.consume(true);
607 });
Blink Reformat4c46d092018-04-07 15:32:37608 contextMenu.headerSection().appendCustomItem(dockItemElement);
609 }
610
611 /**
612 * @param {string} side
613 */
614 function setDockSide(side) {
615 Components.dockController.setDockSide(side);
616 contextMenu.discard();
617 }
618
619 if (Components.dockController.dockSide() === Components.DockController.State.Undocked &&
Tim van der Lippe1d6e57a2019-09-30 11:55:34620 SDK.targetManager.mainTarget() && SDK.targetManager.mainTarget().type() === SDK.Target.Type.Frame) {
Blink Reformat4c46d092018-04-07 15:32:37621 contextMenu.defaultSection().appendAction('inspector_main.focus-debuggee', Common.UIString('Focus debuggee'));
Tim van der Lippe1d6e57a2019-09-30 11:55:34622 }
Blink Reformat4c46d092018-04-07 15:32:37623
624 contextMenu.defaultSection().appendAction(
625 'main.toggle-drawer',
626 UI.inspectorView.drawerVisible() ? Common.UIString('Hide console drawer') :
627 Common.UIString('Show console drawer'));
628 contextMenu.appendItemsAtLocation('mainMenu');
629 const moreTools = contextMenu.defaultSection().appendSubMenuItem(Common.UIString('More tools'));
630 const extensions = self.runtime.extensions('view', undefined, true);
631 for (const extension of extensions) {
632 const descriptor = extension.descriptor();
Tim van der Lippe1d6e57a2019-09-30 11:55:34633 if (descriptor['persistence'] !== 'closeable') {
Blink Reformat4c46d092018-04-07 15:32:37634 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34635 }
636 if (descriptor['location'] !== 'drawer-view' && descriptor['location'] !== 'panel') {
Blink Reformat4c46d092018-04-07 15:32:37637 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34638 }
Blink Reformat4c46d092018-04-07 15:32:37639 moreTools.defaultSection().appendItem(
640 extension.title(), UI.viewManager.showView.bind(UI.viewManager, descriptor['id']));
641 }
642
643 const helpSubMenu = contextMenu.footerSection().appendSubMenuItem(Common.UIString('Help'));
644 helpSubMenu.appendItemsAtLocation('mainMenuHelp');
645 }
646};
647
648/**
649 * @unrestricted
650 */
651Main.Main.PauseListener = class {
652 constructor() {
653 SDK.targetManager.addModelListener(
654 SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
655 }
656
657 /**
658 * @param {!Common.Event} event
659 */
660 _debuggerPaused(event) {
661 SDK.targetManager.removeModelListener(
662 SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
663 const debuggerModel = /** @type {!SDK.DebuggerModel} */ (event.data);
664 const debuggerPausedDetails = debuggerModel.debuggerPausedDetails();
665 UI.context.setFlavor(SDK.Target, debuggerModel.target());
666 Common.Revealer.reveal(debuggerPausedDetails);
667 }
668};
669
670/**
671 * @param {string} method
672 * @param {?Object} params
673 * @return {!Promise}
674 */
675Main.sendOverProtocol = function(method, params) {
676 return new Promise((resolve, reject) => {
Dmitry Gozman99d7a6c2018-11-12 17:55:11677 Protocol.test.sendRawMessage(method, params, (err, ...results) => {
Tim van der Lippe1d6e57a2019-09-30 11:55:34678 if (err) {
Blink Reformat4c46d092018-04-07 15:32:37679 return reject(err);
Tim van der Lippe1d6e57a2019-09-30 11:55:34680 }
Blink Reformat4c46d092018-04-07 15:32:37681 return resolve(results);
682 });
683 });
684};
685
686/**
687 * @implements {UI.ActionDelegate}
688 * @unrestricted
689 */
690Main.ReloadActionDelegate = class {
691 /**
692 * @override
693 * @param {!UI.Context} context
694 * @param {string} actionId
695 * @return {boolean}
696 */
697 handleAction(context, actionId) {
698 switch (actionId) {
699 case 'main.debug-reload':
700 Components.reload();
701 return true;
702 }
703 return false;
704 }
705};
706
707new Main.Main();