blob: cf09560de995da8faba34825bc3c315626f77640 [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) {
47 if (Host.isUnderTest())
48 return;
49 console.time(label);
50 }
51
52 /**
53 * @param {string} label
54 */
55 static timeEnd(label) {
56 if (Host.isUnderTest())
57 return;
58 console.timeEnd(label);
59 }
60
61 async _loaded() {
62 console.timeStamp('Main._loaded');
Pavel Feldman63e89eb2018-11-25 05:47:0963 await Runtime.appStarted();
Blink Reformat4c46d092018-04-07 15:32:3764 Runtime.setPlatform(Host.platform());
Vidal Diazleal0b6aff42019-04-20 01:15:4365 Runtime.setL10nCallback(ls);
Blink Reformat4c46d092018-04-07 15:32:3766 InspectorFrontendHost.getPreferences(this._gotPreferences.bind(this));
67 }
68
69 /**
70 * @param {!Object<string, string>} prefs
71 */
72 _gotPreferences(prefs) {
73 console.timeStamp('Main._gotPreferences');
74 if (Host.isUnderTest(prefs))
75 self.runtime.useTestBase();
76 this._createSettings(prefs);
77 this._createAppUI();
78 }
79
80 /**
81 * @param {!Object<string, string>} prefs
82 * Note: this function is called from testSettings in Tests.js.
83 */
84 _createSettings(prefs) {
85 this._initializeExperiments();
86 let storagePrefix = '';
87 if (Host.isCustomDevtoolsFrontend())
88 storagePrefix = '__custom__';
89 else if (!Runtime.queryParam('can_dock') && !!Runtime.queryParam('debugFrontend') && !Host.isUnderTest())
90 storagePrefix = '__bundled__';
91
92 let localStorage;
93 if (!Host.isUnderTest() && window.localStorage) {
94 localStorage = new Common.SettingsStorage(
95 window.localStorage, undefined, undefined, () => window.localStorage.clear(), storagePrefix);
96 } else {
97 localStorage = new Common.SettingsStorage({}, undefined, undefined, undefined, storagePrefix);
98 }
99 const globalStorage = new Common.SettingsStorage(
100 prefs, InspectorFrontendHost.setPreference, InspectorFrontendHost.removePreference,
101 InspectorFrontendHost.clearPreferences, storagePrefix);
102 Common.settings = new Common.Settings(globalStorage, localStorage);
103 if (!Host.isUnderTest())
104 new Common.VersionController().updateVersion();
105 }
106
107 _initializeExperiments() {
108 // Keep this sorted alphabetically: both keys and values.
109 Runtime.experiments.register('applyCustomStylesheet', 'Allow custom UI themes');
Connor Clark5f267212019-07-26 23:59:11110 Runtime.experiments.register('captureNodeCreationStacks', 'Capture node creation stacks');
Alexei Filippovfdfefe02019-03-09 00:33:24111 Runtime.experiments.register('sourcesPrettyPrint', 'Automatically pretty print in the Sources Panel');
Rayan Kanso8fe8ee22019-03-04 14:58:46112 Runtime.experiments.register('backgroundServices', 'Background web platform feature events', true);
Fergus Dall0be4f4c2019-05-21 00:01:29113 Runtime.experiments.register('backgroundServicesNotifications', 'Background services section for Notifications');
Rayan Kanso8d7918a2019-07-03 21:03:38114 Runtime.experiments.register('backgroundServicesPaymentHandler', 'Background services section for Payment Handler');
Fergus Dall0be4f4c2019-05-21 00:01:29115 Runtime.experiments.register('backgroundServicesPushMessaging', 'Background services section for Push Messaging');
Rayan Kanso54809672019-07-24 18:40:28116 Runtime.experiments.register(
117 'backgroundServicesPeriodicBackgroundSync', 'Background services section for Periodic Background Sync');
Blink Reformat4c46d092018-04-07 15:32:37118 Runtime.experiments.register('blackboxJSFramesOnTimeline', 'Blackbox JavaScript frames on Timeline', true);
Blink Reformat4c46d092018-04-07 15:32:37119 Runtime.experiments.register('emptySourceMapAutoStepping', 'Empty sourcemap auto-stepping');
120 Runtime.experiments.register('inputEventsOnTimelineOverview', 'Input events on Timeline overview', true);
Alexei Filippovfdfefe02019-03-09 00:33:24121 Runtime.experiments.register('liveHeapProfile', 'Live heap profile', true);
Blink Reformat4c46d092018-04-07 15:32:37122 Runtime.experiments.register('nativeHeapProfiler', 'Native memory sampling heap profiler', true);
Blink Reformat4c46d092018-04-07 15:32:37123 Runtime.experiments.register('protocolMonitor', 'Protocol Monitor');
Jan Schefflerfc2f3832019-09-24 14:03:32124 Runtime.experiments.register('recordCoverageWithPerformanceTracing', 'Record coverage while performance tracing');
Alexei Filippov6d2eb592018-10-25 21:48:56125 Runtime.experiments.register('samplingHeapProfilerTimeline', 'Sampling heap profiler timeline', true);
Blink Reformat4c46d092018-04-07 15:32:37126 Runtime.experiments.register('sourceDiff', 'Source diff');
Pavel Feldmanc9060ea2018-04-30 04:42:18127 Runtime.experiments.register('splitInDrawer', 'Split in drawer', true);
Joey Arharaef93562019-03-15 23:49:59128 Runtime.experiments.register('spotlight', 'Spotlight', true);
Blink Reformat4c46d092018-04-07 15:32:37129 Runtime.experiments.register('terminalInDrawer', 'Terminal in drawer', true);
130
131 // Timeline
132 Runtime.experiments.register('timelineEventInitiators', 'Timeline: event initiators');
133 Runtime.experiments.register('timelineFlowEvents', 'Timeline: flow events', true);
134 Runtime.experiments.register('timelineInvalidationTracking', 'Timeline: invalidation tracking', true);
Blink Reformat4c46d092018-04-07 15:32:37135 Runtime.experiments.register('timelineShowAllEvents', 'Timeline: show all events', true);
Blink Reformat4c46d092018-04-07 15:32:37136 Runtime.experiments.register('timelineV8RuntimeCallStats', 'Timeline: V8 Runtime Call Stats on Timeline', true);
Alexei Filippov57ccafb2018-08-14 20:59:05137 Runtime.experiments.register('timelineWebGL', 'Timeline: WebGL-based flamechart');
Blink Reformat4c46d092018-04-07 15:32:37138
139 Runtime.experiments.cleanUpStaleExperiments();
Jeff Fisher85b08e12019-06-13 22:24:21140 const enabledExperiments = Runtime.queryParam('enabledExperiments');
141 if (enabledExperiments)
142 Runtime.experiments.setServerEnabledExperiments(enabledExperiments.split(';'));
Rayan Kanso93bacf72019-08-28 12:33:23143 Runtime.experiments.setDefaultExperiments([
144 'backgroundServices',
145 'backgroundServicesNotifications',
146 'backgroundServicesPushMessaging',
147 'backgroundServicesPaymentHandler',
148 ]);
Alexei Filippovfdfefe02019-03-09 00:33:24149
150 if (Host.isUnderTest() && Runtime.queryParam('test').includes('live-line-level-heap-profile.js'))
151 Runtime.experiments.enableForTest('liveHeapProfile');
Blink Reformat4c46d092018-04-07 15:32:37152 }
153
154 /**
155 * @suppressGlobalPropertiesCheck
156 */
157 async _createAppUI() {
158 Main.Main.time('Main._createAppUI');
159
160 UI.viewManager = new UI.ViewManager();
161
162 // Request filesystems early, we won't create connections until callback is fired. Things will happen in parallel.
163 Persistence.isolatedFileSystemManager = new Persistence.IsolatedFileSystemManager();
164
Erik Luo9adba992019-06-26 01:17:52165 const themeSetting = Common.settings.createSetting('uiTheme', 'systemPreferred');
Blink Reformat4c46d092018-04-07 15:32:37166 UI.initializeUIUtils(document, themeSetting);
167 themeSetting.addChangeListener(Components.reload.bind(Components));
168
169 UI.installComponentRootStyles(/** @type {!Element} */ (document.body));
170
171 this._addMainEventListeners(document);
172
173 const canDock = !!Runtime.queryParam('can_dock');
174 UI.zoomManager = new UI.ZoomManager(window, InspectorFrontendHost);
175 UI.inspectorView = UI.InspectorView.instance();
176 UI.ContextMenu.initialize();
177 UI.ContextMenu.installHandler(document);
178 UI.Tooltip.installHandler(document);
179 Components.dockController = new Components.DockController(canDock);
180 SDK.consoleModel = new SDK.ConsoleModel();
181 SDK.multitargetNetworkManager = new SDK.MultitargetNetworkManager();
182 SDK.domDebuggerManager = new SDK.DOMDebuggerManager();
183 SDK.targetManager.addEventListener(
184 SDK.TargetManager.Events.SuspendStateChanged, this._onSuspendStateChanged.bind(this));
185
186 UI.shortcutsScreen = new UI.ShortcutsScreen();
187 // set order of some sections explicitly
188 UI.shortcutsScreen.section(Common.UIString('Elements Panel'));
189 UI.shortcutsScreen.section(Common.UIString('Styles Pane'));
190 UI.shortcutsScreen.section(Common.UIString('Debugger'));
191 UI.shortcutsScreen.section(Common.UIString('Console'));
192
193 Workspace.fileManager = new Workspace.FileManager();
194 Workspace.workspace = new Workspace.Workspace();
195
196 Bindings.networkProjectManager = new Bindings.NetworkProjectManager();
197 Bindings.resourceMapping = new Bindings.ResourceMapping(SDK.targetManager, Workspace.workspace);
198 new Bindings.PresentationConsoleMessageManager();
199 Bindings.cssWorkspaceBinding = new Bindings.CSSWorkspaceBinding(SDK.targetManager, Workspace.workspace);
200 Bindings.debuggerWorkspaceBinding = new Bindings.DebuggerWorkspaceBinding(SDK.targetManager, Workspace.workspace);
201 Bindings.breakpointManager =
202 new Bindings.BreakpointManager(Workspace.workspace, SDK.targetManager, Bindings.debuggerWorkspaceBinding);
203 Extensions.extensionServer = new Extensions.ExtensionServer();
204
205 new Persistence.FileSystemWorkspaceBinding(Persistence.isolatedFileSystemManager, Workspace.workspace);
206 Persistence.persistence = new Persistence.Persistence(Workspace.workspace, Bindings.breakpointManager);
207 Persistence.networkPersistenceManager = new Persistence.NetworkPersistenceManager(Workspace.workspace);
208
209 new Main.ExecutionContextSelector(SDK.targetManager, UI.context);
210 Bindings.blackboxManager = new Bindings.BlackboxManager(Bindings.debuggerWorkspaceBinding);
211
212 new Main.Main.PauseListener();
213
214 UI.actionRegistry = new UI.ActionRegistry();
215 UI.shortcutRegistry = new UI.ShortcutRegistry(UI.actionRegistry, document);
216 UI.ShortcutsScreen.registerShortcuts();
217 this._registerForwardedShortcuts();
218 this._registerMessageSinkListener();
219
220 Main.Main.timeEnd('Main._createAppUI');
221 this._showAppUI(await self.runtime.extension(Common.AppProvider).instance());
222 }
223
224 /**
225 * @param {!Object} appProvider
226 * @suppressGlobalPropertiesCheck
227 */
228 _showAppUI(appProvider) {
229 Main.Main.time('Main._showAppUI');
230 const app = /** @type {!Common.AppProvider} */ (appProvider).createApp();
231 // It is important to kick controller lifetime after apps are instantiated.
232 Components.dockController.initialize();
233 app.presentUI(document);
234
235 const toggleSearchNodeAction = UI.actionRegistry.action('elements.toggle-element-search');
236 // TODO: we should not access actions from other modules.
237 if (toggleSearchNodeAction) {
238 InspectorFrontendHost.events.addEventListener(
Tim van der Lippe7b190162019-09-27 15:10:44239 Host.InspectorFrontendHostAPI.Events.EnterInspectElementMode,
Blink Reformat4c46d092018-04-07 15:32:37240 toggleSearchNodeAction.execute.bind(toggleSearchNodeAction), this);
241 }
242 InspectorFrontendHost.events.addEventListener(
Tim van der Lippe7b190162019-09-27 15:10:44243 Host.InspectorFrontendHostAPI.Events.RevealSourceLine, this._revealSourceLine, this);
Blink Reformat4c46d092018-04-07 15:32:37244
245 UI.inspectorView.createToolbars();
246 InspectorFrontendHost.loadCompleted();
247
248 const extensions = self.runtime.extensions(Common.QueryParamHandler);
249 for (const extension of extensions) {
250 const value = Runtime.queryParam(extension.descriptor()['name']);
251 if (value !== null)
252 extension.instance().then(handleQueryParam.bind(null, value));
253 }
254
255 /**
256 * @param {string} value
257 * @param {!Common.QueryParamHandler} handler
258 */
259 function handleQueryParam(value, handler) {
260 handler.handleQueryParam(value);
261 }
262
263 // Allow UI cycles to repaint prior to creating connection.
264 setTimeout(this._initializeTarget.bind(this), 0);
265 Main.Main.timeEnd('Main._showAppUI');
266 }
267
268 async _initializeTarget() {
269 Main.Main.time('Main._initializeTarget');
270 const instances =
271 await Promise.all(self.runtime.extensions('early-initialization').map(extension => extension.instance()));
272 for (const instance of instances)
Pavel Feldman07ef9722018-12-13 23:52:22273 await /** @type {!Common.Runnable} */ (instance).run();
Blink Reformat4c46d092018-04-07 15:32:37274 // Used for browser tests.
275 InspectorFrontendHost.readyForTest();
276 // Asynchronously run the extensions.
277 setTimeout(this._lateInitialization.bind(this), 100);
278 Main.Main.timeEnd('Main._initializeTarget');
279 }
280
281 _lateInitialization() {
282 Main.Main.time('Main._lateInitialization');
283 this._registerShortcuts();
284 Extensions.extensionServer.initializeExtensions();
Alexei Filippov19be5102019-04-16 20:40:24285 const extensions = self.runtime.extensions('late-initialization');
286 const promises = [];
287 for (const extension of extensions) {
288 const setting = extension.descriptor()['setting'];
289 if (!setting || Common.settings.moduleSetting(setting).get()) {
290 promises.push(extension.instance().then(instance => (/** @type {!Common.Runnable} */ (instance)).run()));
291 continue;
292 }
293 /**
294 * @param {!Common.Event} event
295 */
296 async function changeListener(event) {
297 if (!event.data)
298 return;
299 Common.settings.moduleSetting(setting).removeChangeListener(changeListener);
300 (/** @type {!Common.Runnable} */ (await extension.instance())).run();
301 }
302 Common.settings.moduleSetting(setting).addChangeListener(changeListener);
303 }
304 this._lateInitDonePromise = Promise.all(promises);
Blink Reformat4c46d092018-04-07 15:32:37305 Main.Main.timeEnd('Main._lateInitialization');
306 }
307
Alexei Filippov19be5102019-04-16 20:40:24308 /**
309 * @return {!Promise}
310 */
311 lateInitDonePromiseForTest() {
312 return this._lateInitDonePromise;
313 }
314
Blink Reformat4c46d092018-04-07 15:32:37315 _registerForwardedShortcuts() {
316 /** @const */ const forwardedActions = [
317 'main.toggle-dock', 'debugger.toggle-breakpoints-active', 'debugger.toggle-pause', 'commandMenu.show',
318 'console.show'
319 ];
320 const actionKeys =
321 UI.shortcutRegistry.keysForActions(forwardedActions).map(UI.KeyboardShortcut.keyCodeAndModifiersFromKey);
322 InspectorFrontendHost.setWhitelistedShortcuts(JSON.stringify(actionKeys));
323 }
324
325 _registerMessageSinkListener() {
326 Common.console.addEventListener(Common.Console.Events.MessageAdded, messageAdded);
327
328 /**
329 * @param {!Common.Event} event
330 */
331 function messageAdded(event) {
332 const message = /** @type {!Common.Console.Message} */ (event.data);
333 if (message.show)
334 Common.console.show();
335 }
336 }
337
338 /**
339 * @param {!Common.Event} event
340 */
341 _revealSourceLine(event) {
342 const url = /** @type {string} */ (event.data['url']);
343 const lineNumber = /** @type {number} */ (event.data['lineNumber']);
344 const columnNumber = /** @type {number} */ (event.data['columnNumber']);
345
346 const uiSourceCode = Workspace.workspace.uiSourceCodeForURL(url);
347 if (uiSourceCode) {
348 Common.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
349 return;
350 }
351
352 /**
353 * @param {!Common.Event} event
354 */
355 function listener(event) {
356 const uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
357 if (uiSourceCode.url() === url) {
358 Common.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
359 Workspace.workspace.removeEventListener(Workspace.Workspace.Events.UISourceCodeAdded, listener);
360 }
361 }
362
363 Workspace.workspace.addEventListener(Workspace.Workspace.Events.UISourceCodeAdded, listener);
364 }
365
366 _registerShortcuts() {
367 const shortcut = UI.KeyboardShortcut;
368 const section = UI.shortcutsScreen.section(Common.UIString('All Panels'));
369 let keys = [
370 shortcut.makeDescriptor('[', shortcut.Modifiers.CtrlOrMeta),
371 shortcut.makeDescriptor(']', shortcut.Modifiers.CtrlOrMeta)
372 ];
373 section.addRelatedKeys(keys, Common.UIString('Go to the panel to the left/right'));
374
375 const toggleConsoleLabel = Common.UIString('Show console');
376 section.addKey(shortcut.makeDescriptor(shortcut.Keys.Tilde, shortcut.Modifiers.Ctrl), toggleConsoleLabel);
377 section.addKey(shortcut.makeDescriptor(shortcut.Keys.Esc), Common.UIString('Toggle drawer'));
378 if (Components.dockController.canDock()) {
379 section.addKey(
380 shortcut.makeDescriptor('M', shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Shift),
381 Common.UIString('Toggle device mode'));
382 section.addKey(
383 shortcut.makeDescriptor('D', shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Shift),
384 Common.UIString('Toggle dock side'));
385 }
386 section.addKey(shortcut.makeDescriptor('f', shortcut.Modifiers.CtrlOrMeta), Common.UIString('Search'));
387
388 const advancedSearchShortcutModifier = Host.isMac() ?
389 UI.KeyboardShortcut.Modifiers.Meta | UI.KeyboardShortcut.Modifiers.Alt :
390 UI.KeyboardShortcut.Modifiers.Ctrl | UI.KeyboardShortcut.Modifiers.Shift;
391 const advancedSearchShortcut = shortcut.makeDescriptor('f', advancedSearchShortcutModifier);
392 section.addKey(advancedSearchShortcut, Common.UIString('Search across all sources'));
393
394 const inspectElementModeShortcuts =
395 UI.shortcutRegistry.shortcutDescriptorsForAction('elements.toggle-element-search');
396 if (inspectElementModeShortcuts.length)
397 section.addKey(inspectElementModeShortcuts[0], Common.UIString('Select node to inspect'));
398
399 const openResourceShortcut = UI.KeyboardShortcut.makeDescriptor('p', UI.KeyboardShortcut.Modifiers.CtrlOrMeta);
400 section.addKey(openResourceShortcut, Common.UIString('Go to source'));
401
402 if (Host.isMac()) {
403 keys = [
404 shortcut.makeDescriptor('g', shortcut.Modifiers.Meta),
405 shortcut.makeDescriptor('g', shortcut.Modifiers.Meta | shortcut.Modifiers.Shift)
406 ];
407 section.addRelatedKeys(keys, Common.UIString('Find next/previous'));
408 }
409 }
410
411 _postDocumentKeyDown(event) {
Joel Einbindera66e5bf2018-05-31 01:26:37412 if (!event.handled)
413 UI.shortcutRegistry.handleShortcut(event);
Blink Reformat4c46d092018-04-07 15:32:37414 }
415
416 /**
417 * @param {!Event} event
418 */
419 _redispatchClipboardEvent(event) {
420 const eventCopy = new CustomEvent('clipboard-' + event.type, {bubbles: true});
421 eventCopy['original'] = event;
422 const document = event.target && event.target.ownerDocument;
423 const target = document ? document.deepActiveElement() : null;
424 if (target)
425 target.dispatchEvent(eventCopy);
426 if (eventCopy.handled)
427 event.preventDefault();
428 }
429
430 _contextMenuEventFired(event) {
431 if (event.handled || event.target.classList.contains('popup-glasspane'))
432 event.preventDefault();
433 }
434
435 /**
436 * @param {!Document} document
437 */
438 _addMainEventListeners(document) {
439 document.addEventListener('keydown', this._postDocumentKeyDown.bind(this), false);
440 document.addEventListener('beforecopy', this._redispatchClipboardEvent.bind(this), true);
441 document.addEventListener('copy', this._redispatchClipboardEvent.bind(this), false);
442 document.addEventListener('cut', this._redispatchClipboardEvent.bind(this), false);
443 document.addEventListener('paste', this._redispatchClipboardEvent.bind(this), false);
444 document.addEventListener('contextmenu', this._contextMenuEventFired.bind(this), true);
445 }
446
447 _onSuspendStateChanged() {
448 const suspended = SDK.targetManager.allTargetsSuspended();
449 UI.inspectorView.onSuspendStateChanged(suspended);
450 }
451};
452
453/**
454 * @implements {UI.ActionDelegate}
455 * @unrestricted
456 */
457Main.Main.ZoomActionDelegate = class {
458 /**
459 * @override
460 * @param {!UI.Context} context
461 * @param {string} actionId
462 * @return {boolean}
463 */
464 handleAction(context, actionId) {
465 if (InspectorFrontendHost.isHostedMode())
466 return false;
467
468 switch (actionId) {
469 case 'main.zoom-in':
470 InspectorFrontendHost.zoomIn();
471 return true;
472 case 'main.zoom-out':
473 InspectorFrontendHost.zoomOut();
474 return true;
475 case 'main.zoom-reset':
476 InspectorFrontendHost.resetZoom();
477 return true;
478 }
479 return false;
480 }
481};
482
483/**
484 * @implements {UI.ActionDelegate}
485 * @unrestricted
486 */
487Main.Main.SearchActionDelegate = class {
488 /**
489 * @override
490 * @param {!UI.Context} context
491 * @param {string} actionId
492 * @return {boolean}
493 * @suppressGlobalPropertiesCheck
494 */
495 handleAction(context, actionId) {
496 const searchableView = UI.SearchableView.fromElement(document.deepActiveElement()) ||
497 UI.inspectorView.currentPanelDeprecated().searchableView();
498 if (!searchableView)
499 return false;
500 switch (actionId) {
501 case 'main.search-in-panel.find':
502 return searchableView.handleFindShortcut();
503 case 'main.search-in-panel.cancel':
504 return searchableView.handleCancelSearchShortcut();
505 case 'main.search-in-panel.find-next':
506 return searchableView.handleFindNextShortcut();
507 case 'main.search-in-panel.find-previous':
508 return searchableView.handleFindPreviousShortcut();
509 }
510 return false;
511 }
512};
513
514/**
515 * @implements {UI.ToolbarItem.Provider}
516 */
517Main.Main.MainMenuItem = class {
518 constructor() {
519 this._item = new UI.ToolbarMenuButton(this._handleContextMenu.bind(this), true);
520 this._item.setTitle(Common.UIString('Customize and control DevTools'));
521 }
522
523 /**
524 * @override
525 * @return {?UI.ToolbarItem}
526 */
527 item() {
528 return this._item;
529 }
530
531 /**
532 * @param {!UI.ContextMenu} contextMenu
533 */
534 _handleContextMenu(contextMenu) {
535 if (Components.dockController.canDock()) {
536 const dockItemElement = createElementWithClass('div', 'flex-centered flex-auto');
Joel Einbinder57b9fad2019-02-08 23:31:35537 dockItemElement.tabIndex = -1;
Blink Reformat4c46d092018-04-07 15:32:37538 const titleElement = dockItemElement.createChild('span', 'flex-auto');
539 titleElement.textContent = Common.UIString('Dock side');
540 const toggleDockSideShorcuts = UI.shortcutRegistry.shortcutDescriptorsForAction('main.toggle-dock');
541 titleElement.title = Common.UIString(
542 'Placement of DevTools relative to the page. (%s to restore last position)', toggleDockSideShorcuts[0].name);
543 dockItemElement.appendChild(titleElement);
544 const dockItemToolbar = new UI.Toolbar('', dockItemElement);
Joel Einbinder9a6bead2018-08-06 18:02:35545 if (Host.isMac() && !UI.themeSupport.hasTheme())
546 dockItemToolbar.makeBlueOnHover();
Blink Reformat4c46d092018-04-07 15:32:37547 const undock = new UI.ToolbarToggle(Common.UIString('Undock into separate window'), 'largeicon-undock');
548 const bottom = new UI.ToolbarToggle(Common.UIString('Dock to bottom'), 'largeicon-dock-to-bottom');
549 const right = new UI.ToolbarToggle(Common.UIString('Dock to right'), 'largeicon-dock-to-right');
550 const left = new UI.ToolbarToggle(Common.UIString('Dock to left'), 'largeicon-dock-to-left');
551 undock.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
552 bottom.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
553 right.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
554 left.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
555 undock.addEventListener(
Joel Einbinder57b9fad2019-02-08 23:31:35556 UI.ToolbarButton.Events.Click, setDockSide.bind(null, Components.DockController.State.Undocked));
Blink Reformat4c46d092018-04-07 15:32:37557 bottom.addEventListener(
Joel Einbinder57b9fad2019-02-08 23:31:35558 UI.ToolbarButton.Events.Click, setDockSide.bind(null, Components.DockController.State.DockedToBottom));
Blink Reformat4c46d092018-04-07 15:32:37559 right.addEventListener(
Joel Einbinder57b9fad2019-02-08 23:31:35560 UI.ToolbarButton.Events.Click, setDockSide.bind(null, Components.DockController.State.DockedToRight));
Blink Reformat4c46d092018-04-07 15:32:37561 left.addEventListener(
Joel Einbinder57b9fad2019-02-08 23:31:35562 UI.ToolbarButton.Events.Click, setDockSide.bind(null, Components.DockController.State.DockedToLeft));
Blink Reformat4c46d092018-04-07 15:32:37563 undock.setToggled(Components.dockController.dockSide() === Components.DockController.State.Undocked);
564 bottom.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToBottom);
565 right.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToRight);
566 left.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToLeft);
567 dockItemToolbar.appendToolbarItem(undock);
568 dockItemToolbar.appendToolbarItem(left);
569 dockItemToolbar.appendToolbarItem(bottom);
570 dockItemToolbar.appendToolbarItem(right);
Joel Einbinder57b9fad2019-02-08 23:31:35571 dockItemElement.addEventListener('keydown', event => {
572 let dir = 0;
573 if (event.key === 'ArrowLeft')
574 dir = -1;
575 else if (event.key === 'ArrowRight')
576 dir = 1;
577 else
578 return;
579
580 const buttons = [undock, left, bottom, right];
581 let index = buttons.findIndex(button => button.element.hasFocus());
582 index = Number.constrain(index + dir, 0, buttons.length - 1);
583
584 buttons[index].element.focus();
585 event.consume(true);
586 });
Blink Reformat4c46d092018-04-07 15:32:37587 contextMenu.headerSection().appendCustomItem(dockItemElement);
588 }
589
590 /**
591 * @param {string} side
592 */
593 function setDockSide(side) {
594 Components.dockController.setDockSide(side);
595 contextMenu.discard();
596 }
597
598 if (Components.dockController.dockSide() === Components.DockController.State.Undocked &&
Dmitry Gozmanb24fcc22018-10-31 23:42:42599 SDK.targetManager.mainTarget() && SDK.targetManager.mainTarget().type() === SDK.Target.Type.Frame)
Blink Reformat4c46d092018-04-07 15:32:37600 contextMenu.defaultSection().appendAction('inspector_main.focus-debuggee', Common.UIString('Focus debuggee'));
601
602 contextMenu.defaultSection().appendAction(
603 'main.toggle-drawer',
604 UI.inspectorView.drawerVisible() ? Common.UIString('Hide console drawer') :
605 Common.UIString('Show console drawer'));
606 contextMenu.appendItemsAtLocation('mainMenu');
607 const moreTools = contextMenu.defaultSection().appendSubMenuItem(Common.UIString('More tools'));
608 const extensions = self.runtime.extensions('view', undefined, true);
609 for (const extension of extensions) {
610 const descriptor = extension.descriptor();
611 if (descriptor['persistence'] !== 'closeable')
612 continue;
613 if (descriptor['location'] !== 'drawer-view' && descriptor['location'] !== 'panel')
614 continue;
615 moreTools.defaultSection().appendItem(
616 extension.title(), UI.viewManager.showView.bind(UI.viewManager, descriptor['id']));
617 }
618
619 const helpSubMenu = contextMenu.footerSection().appendSubMenuItem(Common.UIString('Help'));
620 helpSubMenu.appendItemsAtLocation('mainMenuHelp');
621 }
622};
623
624/**
625 * @unrestricted
626 */
627Main.Main.PauseListener = class {
628 constructor() {
629 SDK.targetManager.addModelListener(
630 SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
631 }
632
633 /**
634 * @param {!Common.Event} event
635 */
636 _debuggerPaused(event) {
637 SDK.targetManager.removeModelListener(
638 SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
639 const debuggerModel = /** @type {!SDK.DebuggerModel} */ (event.data);
640 const debuggerPausedDetails = debuggerModel.debuggerPausedDetails();
641 UI.context.setFlavor(SDK.Target, debuggerModel.target());
642 Common.Revealer.reveal(debuggerPausedDetails);
643 }
644};
645
646/**
647 * @param {string} method
648 * @param {?Object} params
649 * @return {!Promise}
650 */
651Main.sendOverProtocol = function(method, params) {
652 return new Promise((resolve, reject) => {
Dmitry Gozman99d7a6c2018-11-12 17:55:11653 Protocol.test.sendRawMessage(method, params, (err, ...results) => {
Blink Reformat4c46d092018-04-07 15:32:37654 if (err)
655 return reject(err);
656 return resolve(results);
657 });
658 });
659};
660
661/**
662 * @implements {UI.ActionDelegate}
663 * @unrestricted
664 */
665Main.ReloadActionDelegate = class {
666 /**
667 * @override
668 * @param {!UI.Context} context
669 * @param {string} actionId
670 * @return {boolean}
671 */
672 handleAction(context, actionId) {
673 switch (actionId) {
674 case 'main.debug-reload':
675 Components.reload();
676 return true;
677 }
678 return false;
679 }
680};
681
682new Main.Main();