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