blob: 0c17d6a1415b54c2dba5121802aea8e148d1451f [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');
Alexei Filippov6d2eb592018-10-25 21:48:56124 Runtime.experiments.register('samplingHeapProfilerTimeline', 'Sampling heap profiler timeline', true);
Blink Reformat4c46d092018-04-07 15:32:37125 Runtime.experiments.register('sourceDiff', 'Source diff');
Pavel Feldmanc9060ea2018-04-30 04:42:18126 Runtime.experiments.register('splitInDrawer', 'Split in drawer', true);
Joey Arharaef93562019-03-15 23:49:59127 Runtime.experiments.register('spotlight', 'Spotlight', true);
Blink Reformat4c46d092018-04-07 15:32:37128 Runtime.experiments.register('terminalInDrawer', 'Terminal in drawer', true);
129
130 // Timeline
131 Runtime.experiments.register('timelineEventInitiators', 'Timeline: event initiators');
132 Runtime.experiments.register('timelineFlowEvents', 'Timeline: flow events', true);
133 Runtime.experiments.register('timelineInvalidationTracking', 'Timeline: invalidation tracking', true);
Blink Reformat4c46d092018-04-07 15:32:37134 Runtime.experiments.register('timelineShowAllEvents', 'Timeline: show all events', true);
Blink Reformat4c46d092018-04-07 15:32:37135 Runtime.experiments.register('timelineV8RuntimeCallStats', 'Timeline: V8 Runtime Call Stats on Timeline', true);
Alexei Filippov57ccafb2018-08-14 20:59:05136 Runtime.experiments.register('timelineWebGL', 'Timeline: WebGL-based flamechart');
Blink Reformat4c46d092018-04-07 15:32:37137
138 Runtime.experiments.cleanUpStaleExperiments();
Jeff Fisher85b08e12019-06-13 22:24:21139 const enabledExperiments = Runtime.queryParam('enabledExperiments');
140 if (enabledExperiments)
141 Runtime.experiments.setServerEnabledExperiments(enabledExperiments.split(';'));
Rayan Kanso93bacf72019-08-28 12:33:23142 Runtime.experiments.setDefaultExperiments([
143 'backgroundServices',
144 'backgroundServicesNotifications',
145 'backgroundServicesPushMessaging',
146 'backgroundServicesPaymentHandler',
147 ]);
Alexei Filippovfdfefe02019-03-09 00:33:24148
149 if (Host.isUnderTest() && Runtime.queryParam('test').includes('live-line-level-heap-profile.js'))
150 Runtime.experiments.enableForTest('liveHeapProfile');
Blink Reformat4c46d092018-04-07 15:32:37151 }
152
153 /**
154 * @suppressGlobalPropertiesCheck
155 */
156 async _createAppUI() {
157 Main.Main.time('Main._createAppUI');
158
159 UI.viewManager = new UI.ViewManager();
160
161 // Request filesystems early, we won't create connections until callback is fired. Things will happen in parallel.
162 Persistence.isolatedFileSystemManager = new Persistence.IsolatedFileSystemManager();
163
Erik Luo9adba992019-06-26 01:17:52164 const themeSetting = Common.settings.createSetting('uiTheme', 'systemPreferred');
Blink Reformat4c46d092018-04-07 15:32:37165 UI.initializeUIUtils(document, themeSetting);
166 themeSetting.addChangeListener(Components.reload.bind(Components));
167
168 UI.installComponentRootStyles(/** @type {!Element} */ (document.body));
169
170 this._addMainEventListeners(document);
171
172 const canDock = !!Runtime.queryParam('can_dock');
173 UI.zoomManager = new UI.ZoomManager(window, InspectorFrontendHost);
174 UI.inspectorView = UI.InspectorView.instance();
175 UI.ContextMenu.initialize();
176 UI.ContextMenu.installHandler(document);
177 UI.Tooltip.installHandler(document);
178 Components.dockController = new Components.DockController(canDock);
179 SDK.consoleModel = new SDK.ConsoleModel();
180 SDK.multitargetNetworkManager = new SDK.MultitargetNetworkManager();
181 SDK.domDebuggerManager = new SDK.DOMDebuggerManager();
182 SDK.targetManager.addEventListener(
183 SDK.TargetManager.Events.SuspendStateChanged, this._onSuspendStateChanged.bind(this));
184
185 UI.shortcutsScreen = new UI.ShortcutsScreen();
186 // set order of some sections explicitly
187 UI.shortcutsScreen.section(Common.UIString('Elements Panel'));
188 UI.shortcutsScreen.section(Common.UIString('Styles Pane'));
189 UI.shortcutsScreen.section(Common.UIString('Debugger'));
190 UI.shortcutsScreen.section(Common.UIString('Console'));
191
192 Workspace.fileManager = new Workspace.FileManager();
193 Workspace.workspace = new Workspace.Workspace();
194
195 Bindings.networkProjectManager = new Bindings.NetworkProjectManager();
196 Bindings.resourceMapping = new Bindings.ResourceMapping(SDK.targetManager, Workspace.workspace);
197 new Bindings.PresentationConsoleMessageManager();
198 Bindings.cssWorkspaceBinding = new Bindings.CSSWorkspaceBinding(SDK.targetManager, Workspace.workspace);
199 Bindings.debuggerWorkspaceBinding = new Bindings.DebuggerWorkspaceBinding(SDK.targetManager, Workspace.workspace);
200 Bindings.breakpointManager =
201 new Bindings.BreakpointManager(Workspace.workspace, SDK.targetManager, Bindings.debuggerWorkspaceBinding);
202 Extensions.extensionServer = new Extensions.ExtensionServer();
203
204 new Persistence.FileSystemWorkspaceBinding(Persistence.isolatedFileSystemManager, Workspace.workspace);
205 Persistence.persistence = new Persistence.Persistence(Workspace.workspace, Bindings.breakpointManager);
206 Persistence.networkPersistenceManager = new Persistence.NetworkPersistenceManager(Workspace.workspace);
207
208 new Main.ExecutionContextSelector(SDK.targetManager, UI.context);
209 Bindings.blackboxManager = new Bindings.BlackboxManager(Bindings.debuggerWorkspaceBinding);
210
211 new Main.Main.PauseListener();
212
213 UI.actionRegistry = new UI.ActionRegistry();
214 UI.shortcutRegistry = new UI.ShortcutRegistry(UI.actionRegistry, document);
215 UI.ShortcutsScreen.registerShortcuts();
216 this._registerForwardedShortcuts();
217 this._registerMessageSinkListener();
218
219 Main.Main.timeEnd('Main._createAppUI');
220 this._showAppUI(await self.runtime.extension(Common.AppProvider).instance());
221 }
222
223 /**
224 * @param {!Object} appProvider
225 * @suppressGlobalPropertiesCheck
226 */
227 _showAppUI(appProvider) {
228 Main.Main.time('Main._showAppUI');
229 const app = /** @type {!Common.AppProvider} */ (appProvider).createApp();
230 // It is important to kick controller lifetime after apps are instantiated.
231 Components.dockController.initialize();
232 app.presentUI(document);
233
234 const toggleSearchNodeAction = UI.actionRegistry.action('elements.toggle-element-search');
235 // TODO: we should not access actions from other modules.
236 if (toggleSearchNodeAction) {
237 InspectorFrontendHost.events.addEventListener(
238 InspectorFrontendHostAPI.Events.EnterInspectElementMode,
239 toggleSearchNodeAction.execute.bind(toggleSearchNodeAction), this);
240 }
241 InspectorFrontendHost.events.addEventListener(
242 InspectorFrontendHostAPI.Events.RevealSourceLine, this._revealSourceLine, this);
243
244 UI.inspectorView.createToolbars();
245 InspectorFrontendHost.loadCompleted();
246
247 const extensions = self.runtime.extensions(Common.QueryParamHandler);
248 for (const extension of extensions) {
249 const value = Runtime.queryParam(extension.descriptor()['name']);
250 if (value !== null)
251 extension.instance().then(handleQueryParam.bind(null, value));
252 }
253
254 /**
255 * @param {string} value
256 * @param {!Common.QueryParamHandler} handler
257 */
258 function handleQueryParam(value, handler) {
259 handler.handleQueryParam(value);
260 }
261
262 // Allow UI cycles to repaint prior to creating connection.
263 setTimeout(this._initializeTarget.bind(this), 0);
264 Main.Main.timeEnd('Main._showAppUI');
265 }
266
267 async _initializeTarget() {
268 Main.Main.time('Main._initializeTarget');
269 const instances =
270 await Promise.all(self.runtime.extensions('early-initialization').map(extension => extension.instance()));
271 for (const instance of instances)
Pavel Feldman07ef9722018-12-13 23:52:22272 await /** @type {!Common.Runnable} */ (instance).run();
Blink Reformat4c46d092018-04-07 15:32:37273 // Used for browser tests.
274 InspectorFrontendHost.readyForTest();
275 // Asynchronously run the extensions.
276 setTimeout(this._lateInitialization.bind(this), 100);
277 Main.Main.timeEnd('Main._initializeTarget');
278 }
279
280 _lateInitialization() {
281 Main.Main.time('Main._lateInitialization');
282 this._registerShortcuts();
283 Extensions.extensionServer.initializeExtensions();
Alexei Filippov19be5102019-04-16 20:40:24284 const extensions = self.runtime.extensions('late-initialization');
285 const promises = [];
286 for (const extension of extensions) {
287 const setting = extension.descriptor()['setting'];
288 if (!setting || Common.settings.moduleSetting(setting).get()) {
289 promises.push(extension.instance().then(instance => (/** @type {!Common.Runnable} */ (instance)).run()));
290 continue;
291 }
292 /**
293 * @param {!Common.Event} event
294 */
295 async function changeListener(event) {
296 if (!event.data)
297 return;
298 Common.settings.moduleSetting(setting).removeChangeListener(changeListener);
299 (/** @type {!Common.Runnable} */ (await extension.instance())).run();
300 }
301 Common.settings.moduleSetting(setting).addChangeListener(changeListener);
302 }
303 this._lateInitDonePromise = Promise.all(promises);
Blink Reformat4c46d092018-04-07 15:32:37304 Main.Main.timeEnd('Main._lateInitialization');
305 }
306
Alexei Filippov19be5102019-04-16 20:40:24307 /**
308 * @return {!Promise}
309 */
310 lateInitDonePromiseForTest() {
311 return this._lateInitDonePromise;
312 }
313
Blink Reformat4c46d092018-04-07 15:32:37314 _registerForwardedShortcuts() {
315 /** @const */ const forwardedActions = [
316 'main.toggle-dock', 'debugger.toggle-breakpoints-active', 'debugger.toggle-pause', 'commandMenu.show',
317 'console.show'
318 ];
319 const actionKeys =
320 UI.shortcutRegistry.keysForActions(forwardedActions).map(UI.KeyboardShortcut.keyCodeAndModifiersFromKey);
321 InspectorFrontendHost.setWhitelistedShortcuts(JSON.stringify(actionKeys));
322 }
323
324 _registerMessageSinkListener() {
325 Common.console.addEventListener(Common.Console.Events.MessageAdded, messageAdded);
326
327 /**
328 * @param {!Common.Event} event
329 */
330 function messageAdded(event) {
331 const message = /** @type {!Common.Console.Message} */ (event.data);
332 if (message.show)
333 Common.console.show();
334 }
335 }
336
337 /**
338 * @param {!Common.Event} event
339 */
340 _revealSourceLine(event) {
341 const url = /** @type {string} */ (event.data['url']);
342 const lineNumber = /** @type {number} */ (event.data['lineNumber']);
343 const columnNumber = /** @type {number} */ (event.data['columnNumber']);
344
345 const uiSourceCode = Workspace.workspace.uiSourceCodeForURL(url);
346 if (uiSourceCode) {
347 Common.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
348 return;
349 }
350
351 /**
352 * @param {!Common.Event} event
353 */
354 function listener(event) {
355 const uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
356 if (uiSourceCode.url() === url) {
357 Common.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
358 Workspace.workspace.removeEventListener(Workspace.Workspace.Events.UISourceCodeAdded, listener);
359 }
360 }
361
362 Workspace.workspace.addEventListener(Workspace.Workspace.Events.UISourceCodeAdded, listener);
363 }
364
365 _registerShortcuts() {
366 const shortcut = UI.KeyboardShortcut;
367 const section = UI.shortcutsScreen.section(Common.UIString('All Panels'));
368 let keys = [
369 shortcut.makeDescriptor('[', shortcut.Modifiers.CtrlOrMeta),
370 shortcut.makeDescriptor(']', shortcut.Modifiers.CtrlOrMeta)
371 ];
372 section.addRelatedKeys(keys, Common.UIString('Go to the panel to the left/right'));
373
374 const toggleConsoleLabel = Common.UIString('Show console');
375 section.addKey(shortcut.makeDescriptor(shortcut.Keys.Tilde, shortcut.Modifiers.Ctrl), toggleConsoleLabel);
376 section.addKey(shortcut.makeDescriptor(shortcut.Keys.Esc), Common.UIString('Toggle drawer'));
377 if (Components.dockController.canDock()) {
378 section.addKey(
379 shortcut.makeDescriptor('M', shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Shift),
380 Common.UIString('Toggle device mode'));
381 section.addKey(
382 shortcut.makeDescriptor('D', shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Shift),
383 Common.UIString('Toggle dock side'));
384 }
385 section.addKey(shortcut.makeDescriptor('f', shortcut.Modifiers.CtrlOrMeta), Common.UIString('Search'));
386
387 const advancedSearchShortcutModifier = Host.isMac() ?
388 UI.KeyboardShortcut.Modifiers.Meta | UI.KeyboardShortcut.Modifiers.Alt :
389 UI.KeyboardShortcut.Modifiers.Ctrl | UI.KeyboardShortcut.Modifiers.Shift;
390 const advancedSearchShortcut = shortcut.makeDescriptor('f', advancedSearchShortcutModifier);
391 section.addKey(advancedSearchShortcut, Common.UIString('Search across all sources'));
392
393 const inspectElementModeShortcuts =
394 UI.shortcutRegistry.shortcutDescriptorsForAction('elements.toggle-element-search');
395 if (inspectElementModeShortcuts.length)
396 section.addKey(inspectElementModeShortcuts[0], Common.UIString('Select node to inspect'));
397
398 const openResourceShortcut = UI.KeyboardShortcut.makeDescriptor('p', UI.KeyboardShortcut.Modifiers.CtrlOrMeta);
399 section.addKey(openResourceShortcut, Common.UIString('Go to source'));
400
401 if (Host.isMac()) {
402 keys = [
403 shortcut.makeDescriptor('g', shortcut.Modifiers.Meta),
404 shortcut.makeDescriptor('g', shortcut.Modifiers.Meta | shortcut.Modifiers.Shift)
405 ];
406 section.addRelatedKeys(keys, Common.UIString('Find next/previous'));
407 }
408 }
409
410 _postDocumentKeyDown(event) {
Joel Einbindera66e5bf2018-05-31 01:26:37411 if (!event.handled)
412 UI.shortcutRegistry.handleShortcut(event);
Blink Reformat4c46d092018-04-07 15:32:37413 }
414
415 /**
416 * @param {!Event} event
417 */
418 _redispatchClipboardEvent(event) {
419 const eventCopy = new CustomEvent('clipboard-' + event.type, {bubbles: true});
420 eventCopy['original'] = event;
421 const document = event.target && event.target.ownerDocument;
422 const target = document ? document.deepActiveElement() : null;
423 if (target)
424 target.dispatchEvent(eventCopy);
425 if (eventCopy.handled)
426 event.preventDefault();
427 }
428
429 _contextMenuEventFired(event) {
430 if (event.handled || event.target.classList.contains('popup-glasspane'))
431 event.preventDefault();
432 }
433
434 /**
435 * @param {!Document} document
436 */
437 _addMainEventListeners(document) {
438 document.addEventListener('keydown', this._postDocumentKeyDown.bind(this), false);
439 document.addEventListener('beforecopy', this._redispatchClipboardEvent.bind(this), true);
440 document.addEventListener('copy', this._redispatchClipboardEvent.bind(this), false);
441 document.addEventListener('cut', this._redispatchClipboardEvent.bind(this), false);
442 document.addEventListener('paste', this._redispatchClipboardEvent.bind(this), false);
443 document.addEventListener('contextmenu', this._contextMenuEventFired.bind(this), true);
444 }
445
446 _onSuspendStateChanged() {
447 const suspended = SDK.targetManager.allTargetsSuspended();
448 UI.inspectorView.onSuspendStateChanged(suspended);
449 }
450};
451
452/**
453 * @implements {UI.ActionDelegate}
454 * @unrestricted
455 */
456Main.Main.ZoomActionDelegate = class {
457 /**
458 * @override
459 * @param {!UI.Context} context
460 * @param {string} actionId
461 * @return {boolean}
462 */
463 handleAction(context, actionId) {
464 if (InspectorFrontendHost.isHostedMode())
465 return false;
466
467 switch (actionId) {
468 case 'main.zoom-in':
469 InspectorFrontendHost.zoomIn();
470 return true;
471 case 'main.zoom-out':
472 InspectorFrontendHost.zoomOut();
473 return true;
474 case 'main.zoom-reset':
475 InspectorFrontendHost.resetZoom();
476 return true;
477 }
478 return false;
479 }
480};
481
482/**
483 * @implements {UI.ActionDelegate}
484 * @unrestricted
485 */
486Main.Main.SearchActionDelegate = class {
487 /**
488 * @override
489 * @param {!UI.Context} context
490 * @param {string} actionId
491 * @return {boolean}
492 * @suppressGlobalPropertiesCheck
493 */
494 handleAction(context, actionId) {
495 const searchableView = UI.SearchableView.fromElement(document.deepActiveElement()) ||
496 UI.inspectorView.currentPanelDeprecated().searchableView();
497 if (!searchableView)
498 return false;
499 switch (actionId) {
500 case 'main.search-in-panel.find':
501 return searchableView.handleFindShortcut();
502 case 'main.search-in-panel.cancel':
503 return searchableView.handleCancelSearchShortcut();
504 case 'main.search-in-panel.find-next':
505 return searchableView.handleFindNextShortcut();
506 case 'main.search-in-panel.find-previous':
507 return searchableView.handleFindPreviousShortcut();
508 }
509 return false;
510 }
511};
512
513/**
514 * @implements {UI.ToolbarItem.Provider}
515 */
516Main.Main.MainMenuItem = class {
517 constructor() {
518 this._item = new UI.ToolbarMenuButton(this._handleContextMenu.bind(this), true);
519 this._item.setTitle(Common.UIString('Customize and control DevTools'));
520 }
521
522 /**
523 * @override
524 * @return {?UI.ToolbarItem}
525 */
526 item() {
527 return this._item;
528 }
529
530 /**
531 * @param {!UI.ContextMenu} contextMenu
532 */
533 _handleContextMenu(contextMenu) {
534 if (Components.dockController.canDock()) {
535 const dockItemElement = createElementWithClass('div', 'flex-centered flex-auto');
Joel Einbinder57b9fad2019-02-08 23:31:35536 dockItemElement.tabIndex = -1;
Blink Reformat4c46d092018-04-07 15:32:37537 const titleElement = dockItemElement.createChild('span', 'flex-auto');
538 titleElement.textContent = Common.UIString('Dock side');
539 const toggleDockSideShorcuts = UI.shortcutRegistry.shortcutDescriptorsForAction('main.toggle-dock');
540 titleElement.title = Common.UIString(
541 'Placement of DevTools relative to the page. (%s to restore last position)', toggleDockSideShorcuts[0].name);
542 dockItemElement.appendChild(titleElement);
543 const dockItemToolbar = new UI.Toolbar('', dockItemElement);
Joel Einbinder9a6bead2018-08-06 18:02:35544 if (Host.isMac() && !UI.themeSupport.hasTheme())
545 dockItemToolbar.makeBlueOnHover();
Blink Reformat4c46d092018-04-07 15:32:37546 const undock = new UI.ToolbarToggle(Common.UIString('Undock into separate window'), 'largeicon-undock');
547 const bottom = new UI.ToolbarToggle(Common.UIString('Dock to bottom'), 'largeicon-dock-to-bottom');
548 const right = new UI.ToolbarToggle(Common.UIString('Dock to right'), 'largeicon-dock-to-right');
549 const left = new UI.ToolbarToggle(Common.UIString('Dock to left'), 'largeicon-dock-to-left');
550 undock.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
551 bottom.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
552 right.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
553 left.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
554 undock.addEventListener(
Joel Einbinder57b9fad2019-02-08 23:31:35555 UI.ToolbarButton.Events.Click, setDockSide.bind(null, Components.DockController.State.Undocked));
Blink Reformat4c46d092018-04-07 15:32:37556 bottom.addEventListener(
Joel Einbinder57b9fad2019-02-08 23:31:35557 UI.ToolbarButton.Events.Click, setDockSide.bind(null, Components.DockController.State.DockedToBottom));
Blink Reformat4c46d092018-04-07 15:32:37558 right.addEventListener(
Joel Einbinder57b9fad2019-02-08 23:31:35559 UI.ToolbarButton.Events.Click, setDockSide.bind(null, Components.DockController.State.DockedToRight));
Blink Reformat4c46d092018-04-07 15:32:37560 left.addEventListener(
Joel Einbinder57b9fad2019-02-08 23:31:35561 UI.ToolbarButton.Events.Click, setDockSide.bind(null, Components.DockController.State.DockedToLeft));
Blink Reformat4c46d092018-04-07 15:32:37562 undock.setToggled(Components.dockController.dockSide() === Components.DockController.State.Undocked);
563 bottom.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToBottom);
564 right.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToRight);
565 left.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToLeft);
566 dockItemToolbar.appendToolbarItem(undock);
567 dockItemToolbar.appendToolbarItem(left);
568 dockItemToolbar.appendToolbarItem(bottom);
569 dockItemToolbar.appendToolbarItem(right);
Joel Einbinder57b9fad2019-02-08 23:31:35570 dockItemElement.addEventListener('keydown', event => {
571 let dir = 0;
572 if (event.key === 'ArrowLeft')
573 dir = -1;
574 else if (event.key === 'ArrowRight')
575 dir = 1;
576 else
577 return;
578
579 const buttons = [undock, left, bottom, right];
580 let index = buttons.findIndex(button => button.element.hasFocus());
581 index = Number.constrain(index + dir, 0, buttons.length - 1);
582
583 buttons[index].element.focus();
584 event.consume(true);
585 });
Blink Reformat4c46d092018-04-07 15:32:37586 contextMenu.headerSection().appendCustomItem(dockItemElement);
587 }
588
589 /**
590 * @param {string} side
591 */
592 function setDockSide(side) {
593 Components.dockController.setDockSide(side);
594 contextMenu.discard();
595 }
596
597 if (Components.dockController.dockSide() === Components.DockController.State.Undocked &&
Dmitry Gozmanb24fcc22018-10-31 23:42:42598 SDK.targetManager.mainTarget() && SDK.targetManager.mainTarget().type() === SDK.Target.Type.Frame)
Blink Reformat4c46d092018-04-07 15:32:37599 contextMenu.defaultSection().appendAction('inspector_main.focus-debuggee', Common.UIString('Focus debuggee'));
600
601 contextMenu.defaultSection().appendAction(
602 'main.toggle-drawer',
603 UI.inspectorView.drawerVisible() ? Common.UIString('Hide console drawer') :
604 Common.UIString('Show console drawer'));
605 contextMenu.appendItemsAtLocation('mainMenu');
606 const moreTools = contextMenu.defaultSection().appendSubMenuItem(Common.UIString('More tools'));
607 const extensions = self.runtime.extensions('view', undefined, true);
608 for (const extension of extensions) {
609 const descriptor = extension.descriptor();
610 if (descriptor['persistence'] !== 'closeable')
611 continue;
612 if (descriptor['location'] !== 'drawer-view' && descriptor['location'] !== 'panel')
613 continue;
614 moreTools.defaultSection().appendItem(
615 extension.title(), UI.viewManager.showView.bind(UI.viewManager, descriptor['id']));
616 }
617
618 const helpSubMenu = contextMenu.footerSection().appendSubMenuItem(Common.UIString('Help'));
619 helpSubMenu.appendItemsAtLocation('mainMenuHelp');
620 }
621};
622
623/**
624 * @unrestricted
625 */
626Main.Main.PauseListener = class {
627 constructor() {
628 SDK.targetManager.addModelListener(
629 SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
630 }
631
632 /**
633 * @param {!Common.Event} event
634 */
635 _debuggerPaused(event) {
636 SDK.targetManager.removeModelListener(
637 SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
638 const debuggerModel = /** @type {!SDK.DebuggerModel} */ (event.data);
639 const debuggerPausedDetails = debuggerModel.debuggerPausedDetails();
640 UI.context.setFlavor(SDK.Target, debuggerModel.target());
641 Common.Revealer.reveal(debuggerPausedDetails);
642 }
643};
644
645/**
646 * @param {string} method
647 * @param {?Object} params
648 * @return {!Promise}
649 */
650Main.sendOverProtocol = function(method, params) {
651 return new Promise((resolve, reject) => {
Dmitry Gozman99d7a6c2018-11-12 17:55:11652 Protocol.test.sendRawMessage(method, params, (err, ...results) => {
Blink Reformat4c46d092018-04-07 15:32:37653 if (err)
654 return reject(err);
655 return resolve(results);
656 });
657 });
658};
659
660/**
661 * @implements {UI.ActionDelegate}
662 * @unrestricted
663 */
664Main.ReloadActionDelegate = class {
665 /**
666 * @override
667 * @param {!UI.Context} context
668 * @param {string} actionId
669 * @return {boolean}
670 */
671 handleAction(context, actionId) {
672 switch (actionId) {
673 case 'main.debug-reload':
674 Components.reload();
675 return true;
676 }
677 return false;
678 }
679};
680
681new Main.Main();