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