blob: c6b19c0220b120642344e0e69bf0cfbe754bc5b8 [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');
63 await Runtime.runtimeReady();
64 Runtime.setPlatform(Host.platform());
65 InspectorFrontendHost.getPreferences(this._gotPreferences.bind(this));
66 }
67
68 /**
69 * @param {!Object<string, string>} prefs
70 */
71 _gotPreferences(prefs) {
72 console.timeStamp('Main._gotPreferences');
73 if (Host.isUnderTest(prefs))
74 self.runtime.useTestBase();
75 this._createSettings(prefs);
76 this._createAppUI();
77 }
78
79 /**
80 * @param {!Object<string, string>} prefs
81 * Note: this function is called from testSettings in Tests.js.
82 */
83 _createSettings(prefs) {
84 this._initializeExperiments();
85 let storagePrefix = '';
86 if (Host.isCustomDevtoolsFrontend())
87 storagePrefix = '__custom__';
88 else if (!Runtime.queryParam('can_dock') && !!Runtime.queryParam('debugFrontend') && !Host.isUnderTest())
89 storagePrefix = '__bundled__';
90
91 let localStorage;
92 if (!Host.isUnderTest() && window.localStorage) {
93 localStorage = new Common.SettingsStorage(
94 window.localStorage, undefined, undefined, () => window.localStorage.clear(), storagePrefix);
95 } else {
96 localStorage = new Common.SettingsStorage({}, undefined, undefined, undefined, storagePrefix);
97 }
98 const globalStorage = new Common.SettingsStorage(
99 prefs, InspectorFrontendHost.setPreference, InspectorFrontendHost.removePreference,
100 InspectorFrontendHost.clearPreferences, storagePrefix);
101 Common.settings = new Common.Settings(globalStorage, localStorage);
102 if (!Host.isUnderTest())
103 new Common.VersionController().updateVersion();
104 }
105
106 _initializeExperiments() {
107 // Keep this sorted alphabetically: both keys and values.
108 Runtime.experiments.register('applyCustomStylesheet', 'Allow custom UI themes');
109 Runtime.experiments.register('blackboxJSFramesOnTimeline', 'Blackbox JavaScript frames on Timeline', true);
110 Runtime.experiments.register('colorContrastRatio', 'Color contrast ratio line in color picker', true);
111 Runtime.experiments.register('emptySourceMapAutoStepping', 'Empty sourcemap auto-stepping');
112 Runtime.experiments.register('inputEventsOnTimelineOverview', 'Input events on Timeline overview', true);
113 Runtime.experiments.register('nativeHeapProfiler', 'Native memory sampling heap profiler', true);
114 Runtime.experiments.register('networkSearch', 'Network search');
115 Runtime.experiments.register('oopifInlineDOM', 'OOPIF: inline DOM ', true);
116 Runtime.experiments.register('protocolMonitor', 'Protocol Monitor');
117 Runtime.experiments.register('sourceDiff', 'Source diff');
118 Runtime.experiments.register(
119 'stepIntoAsync', 'Introduce separate step action, stepInto becomes powerful enough to go inside async call');
120 Runtime.experiments.register('terminalInDrawer', 'Terminal in drawer', true);
121
122 // Timeline
123 Runtime.experiments.register('timelineEventInitiators', 'Timeline: event initiators');
124 Runtime.experiments.register('timelineFlowEvents', 'Timeline: flow events', true);
125 Runtime.experiments.register('timelineInvalidationTracking', 'Timeline: invalidation tracking', true);
126 Runtime.experiments.register('timelinePaintTimingMarkers', 'Timeline: paint timing markers', true);
127 Runtime.experiments.register('timelineShowAllEvents', 'Timeline: show all events', true);
128 Runtime.experiments.register('timelineShowAllProcesses', 'Timeline: show all processes', true);
129 Runtime.experiments.register('timelineTracingJSProfile', 'Timeline: tracing based JS profiler', true);
130 Runtime.experiments.register('timelineV8RuntimeCallStats', 'Timeline: V8 Runtime Call Stats on Timeline', true);
131
132 Runtime.experiments.cleanUpStaleExperiments();
133
134 if (Host.isUnderTest()) {
135 const testPath = Runtime.queryParam('test');
136 // Enable experiments for testing.
137 if (testPath.indexOf('oopif/') !== -1)
138 Runtime.experiments.enableForTest('oopifInlineDOM');
139 if (testPath.indexOf('network/') !== -1)
140 Runtime.experiments.enableForTest('networkSearch');
141 }
142
143 Runtime.experiments.setDefaultExperiments(['colorContrastRatio', 'stepIntoAsync', 'oopifInlineDOM']);
144 }
145
146 /**
147 * @suppressGlobalPropertiesCheck
148 */
149 async _createAppUI() {
150 Main.Main.time('Main._createAppUI');
151
152 UI.viewManager = new UI.ViewManager();
153
154 // Request filesystems early, we won't create connections until callback is fired. Things will happen in parallel.
155 Persistence.isolatedFileSystemManager = new Persistence.IsolatedFileSystemManager();
156
157 const themeSetting = Common.settings.createSetting('uiTheme', 'default');
158 UI.initializeUIUtils(document, themeSetting);
159 themeSetting.addChangeListener(Components.reload.bind(Components));
160
161 UI.installComponentRootStyles(/** @type {!Element} */ (document.body));
162
163 this._addMainEventListeners(document);
164
165 const canDock = !!Runtime.queryParam('can_dock');
166 UI.zoomManager = new UI.ZoomManager(window, InspectorFrontendHost);
167 UI.inspectorView = UI.InspectorView.instance();
168 UI.ContextMenu.initialize();
169 UI.ContextMenu.installHandler(document);
170 UI.Tooltip.installHandler(document);
171 Components.dockController = new Components.DockController(canDock);
172 SDK.consoleModel = new SDK.ConsoleModel();
173 SDK.multitargetNetworkManager = new SDK.MultitargetNetworkManager();
174 SDK.domDebuggerManager = new SDK.DOMDebuggerManager();
175 SDK.targetManager.addEventListener(
176 SDK.TargetManager.Events.SuspendStateChanged, this._onSuspendStateChanged.bind(this));
177
178 UI.shortcutsScreen = new UI.ShortcutsScreen();
179 // set order of some sections explicitly
180 UI.shortcutsScreen.section(Common.UIString('Elements Panel'));
181 UI.shortcutsScreen.section(Common.UIString('Styles Pane'));
182 UI.shortcutsScreen.section(Common.UIString('Debugger'));
183 UI.shortcutsScreen.section(Common.UIString('Console'));
184
185 Workspace.fileManager = new Workspace.FileManager();
186 Workspace.workspace = new Workspace.Workspace();
187
188 Bindings.networkProjectManager = new Bindings.NetworkProjectManager();
189 Bindings.resourceMapping = new Bindings.ResourceMapping(SDK.targetManager, Workspace.workspace);
190 new Bindings.PresentationConsoleMessageManager();
191 Bindings.cssWorkspaceBinding = new Bindings.CSSWorkspaceBinding(SDK.targetManager, Workspace.workspace);
192 Bindings.debuggerWorkspaceBinding = new Bindings.DebuggerWorkspaceBinding(SDK.targetManager, Workspace.workspace);
193 Bindings.breakpointManager =
194 new Bindings.BreakpointManager(Workspace.workspace, SDK.targetManager, Bindings.debuggerWorkspaceBinding);
195 Extensions.extensionServer = new Extensions.ExtensionServer();
196
197 new Persistence.FileSystemWorkspaceBinding(Persistence.isolatedFileSystemManager, Workspace.workspace);
198 Persistence.persistence = new Persistence.Persistence(Workspace.workspace, Bindings.breakpointManager);
199 Persistence.networkPersistenceManager = new Persistence.NetworkPersistenceManager(Workspace.workspace);
200
201 new Main.ExecutionContextSelector(SDK.targetManager, UI.context);
202 Bindings.blackboxManager = new Bindings.BlackboxManager(Bindings.debuggerWorkspaceBinding);
203
204 new Main.Main.PauseListener();
205
206 UI.actionRegistry = new UI.ActionRegistry();
207 UI.shortcutRegistry = new UI.ShortcutRegistry(UI.actionRegistry, document);
208 UI.ShortcutsScreen.registerShortcuts();
209 this._registerForwardedShortcuts();
210 this._registerMessageSinkListener();
211
212 Main.Main.timeEnd('Main._createAppUI');
213 this._showAppUI(await self.runtime.extension(Common.AppProvider).instance());
214 }
215
216 /**
217 * @param {!Object} appProvider
218 * @suppressGlobalPropertiesCheck
219 */
220 _showAppUI(appProvider) {
221 Main.Main.time('Main._showAppUI');
222 const app = /** @type {!Common.AppProvider} */ (appProvider).createApp();
223 // It is important to kick controller lifetime after apps are instantiated.
224 Components.dockController.initialize();
225 app.presentUI(document);
226
227 const toggleSearchNodeAction = UI.actionRegistry.action('elements.toggle-element-search');
228 // TODO: we should not access actions from other modules.
229 if (toggleSearchNodeAction) {
230 InspectorFrontendHost.events.addEventListener(
231 InspectorFrontendHostAPI.Events.EnterInspectElementMode,
232 toggleSearchNodeAction.execute.bind(toggleSearchNodeAction), this);
233 }
234 InspectorFrontendHost.events.addEventListener(
235 InspectorFrontendHostAPI.Events.RevealSourceLine, this._revealSourceLine, this);
236
237 UI.inspectorView.createToolbars();
238 InspectorFrontendHost.loadCompleted();
239
240 const extensions = self.runtime.extensions(Common.QueryParamHandler);
241 for (const extension of extensions) {
242 const value = Runtime.queryParam(extension.descriptor()['name']);
243 if (value !== null)
244 extension.instance().then(handleQueryParam.bind(null, value));
245 }
246
247 /**
248 * @param {string} value
249 * @param {!Common.QueryParamHandler} handler
250 */
251 function handleQueryParam(value, handler) {
252 handler.handleQueryParam(value);
253 }
254
255 // Allow UI cycles to repaint prior to creating connection.
256 setTimeout(this._initializeTarget.bind(this), 0);
257 Main.Main.timeEnd('Main._showAppUI');
258 }
259
260 async _initializeTarget() {
261 Main.Main.time('Main._initializeTarget');
262 const instances =
263 await Promise.all(self.runtime.extensions('early-initialization').map(extension => extension.instance()));
264 for (const instance of instances)
265 /** @type {!Common.Runnable} */ (instance).run();
266 // Used for browser tests.
267 InspectorFrontendHost.readyForTest();
268 // Asynchronously run the extensions.
269 setTimeout(this._lateInitialization.bind(this), 100);
270 Main.Main.timeEnd('Main._initializeTarget');
271 }
272
273 _lateInitialization() {
274 Main.Main.time('Main._lateInitialization');
275 this._registerShortcuts();
276 Extensions.extensionServer.initializeExtensions();
277 if (!Host.isUnderTest()) {
278 for (const extension of self.runtime.extensions('late-initialization'))
279 extension.instance().then(instance => (/** @type {!Common.Runnable} */ (instance)).run());
280 }
281 Main.Main.timeEnd('Main._lateInitialization');
282 }
283
284 _registerForwardedShortcuts() {
285 /** @const */ const forwardedActions = [
286 'main.toggle-dock', 'debugger.toggle-breakpoints-active', 'debugger.toggle-pause', 'commandMenu.show',
287 'console.show'
288 ];
289 const actionKeys =
290 UI.shortcutRegistry.keysForActions(forwardedActions).map(UI.KeyboardShortcut.keyCodeAndModifiersFromKey);
291 InspectorFrontendHost.setWhitelistedShortcuts(JSON.stringify(actionKeys));
292 }
293
294 _registerMessageSinkListener() {
295 Common.console.addEventListener(Common.Console.Events.MessageAdded, messageAdded);
296
297 /**
298 * @param {!Common.Event} event
299 */
300 function messageAdded(event) {
301 const message = /** @type {!Common.Console.Message} */ (event.data);
302 if (message.show)
303 Common.console.show();
304 }
305 }
306
307 /**
308 * @param {!Common.Event} event
309 */
310 _revealSourceLine(event) {
311 const url = /** @type {string} */ (event.data['url']);
312 const lineNumber = /** @type {number} */ (event.data['lineNumber']);
313 const columnNumber = /** @type {number} */ (event.data['columnNumber']);
314
315 const uiSourceCode = Workspace.workspace.uiSourceCodeForURL(url);
316 if (uiSourceCode) {
317 Common.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
318 return;
319 }
320
321 /**
322 * @param {!Common.Event} event
323 */
324 function listener(event) {
325 const uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
326 if (uiSourceCode.url() === url) {
327 Common.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
328 Workspace.workspace.removeEventListener(Workspace.Workspace.Events.UISourceCodeAdded, listener);
329 }
330 }
331
332 Workspace.workspace.addEventListener(Workspace.Workspace.Events.UISourceCodeAdded, listener);
333 }
334
335 _registerShortcuts() {
336 const shortcut = UI.KeyboardShortcut;
337 const section = UI.shortcutsScreen.section(Common.UIString('All Panels'));
338 let keys = [
339 shortcut.makeDescriptor('[', shortcut.Modifiers.CtrlOrMeta),
340 shortcut.makeDescriptor(']', shortcut.Modifiers.CtrlOrMeta)
341 ];
342 section.addRelatedKeys(keys, Common.UIString('Go to the panel to the left/right'));
343
344 const toggleConsoleLabel = Common.UIString('Show console');
345 section.addKey(shortcut.makeDescriptor(shortcut.Keys.Tilde, shortcut.Modifiers.Ctrl), toggleConsoleLabel);
346 section.addKey(shortcut.makeDescriptor(shortcut.Keys.Esc), Common.UIString('Toggle drawer'));
347 if (Components.dockController.canDock()) {
348 section.addKey(
349 shortcut.makeDescriptor('M', shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Shift),
350 Common.UIString('Toggle device mode'));
351 section.addKey(
352 shortcut.makeDescriptor('D', shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Shift),
353 Common.UIString('Toggle dock side'));
354 }
355 section.addKey(shortcut.makeDescriptor('f', shortcut.Modifiers.CtrlOrMeta), Common.UIString('Search'));
356
357 const advancedSearchShortcutModifier = Host.isMac() ?
358 UI.KeyboardShortcut.Modifiers.Meta | UI.KeyboardShortcut.Modifiers.Alt :
359 UI.KeyboardShortcut.Modifiers.Ctrl | UI.KeyboardShortcut.Modifiers.Shift;
360 const advancedSearchShortcut = shortcut.makeDescriptor('f', advancedSearchShortcutModifier);
361 section.addKey(advancedSearchShortcut, Common.UIString('Search across all sources'));
362
363 const inspectElementModeShortcuts =
364 UI.shortcutRegistry.shortcutDescriptorsForAction('elements.toggle-element-search');
365 if (inspectElementModeShortcuts.length)
366 section.addKey(inspectElementModeShortcuts[0], Common.UIString('Select node to inspect'));
367
368 const openResourceShortcut = UI.KeyboardShortcut.makeDescriptor('p', UI.KeyboardShortcut.Modifiers.CtrlOrMeta);
369 section.addKey(openResourceShortcut, Common.UIString('Go to source'));
370
371 if (Host.isMac()) {
372 keys = [
373 shortcut.makeDescriptor('g', shortcut.Modifiers.Meta),
374 shortcut.makeDescriptor('g', shortcut.Modifiers.Meta | shortcut.Modifiers.Shift)
375 ];
376 section.addRelatedKeys(keys, Common.UIString('Find next/previous'));
377 }
378 }
379
380 _postDocumentKeyDown(event) {
381 if (event.handled)
382 return;
383
384 if (!UI.Dialog.hasInstance() && UI.inspectorView.currentPanelDeprecated()) {
385 UI.inspectorView.currentPanelDeprecated().handleShortcut(event);
386 if (event.handled) {
387 event.consume(true);
388 return;
389 }
390 }
391
392 UI.shortcutRegistry.handleShortcut(event);
393 }
394
395 /**
396 * @param {!Event} event
397 */
398 _redispatchClipboardEvent(event) {
399 const eventCopy = new CustomEvent('clipboard-' + event.type, {bubbles: true});
400 eventCopy['original'] = event;
401 const document = event.target && event.target.ownerDocument;
402 const target = document ? document.deepActiveElement() : null;
403 if (target)
404 target.dispatchEvent(eventCopy);
405 if (eventCopy.handled)
406 event.preventDefault();
407 }
408
409 _contextMenuEventFired(event) {
410 if (event.handled || event.target.classList.contains('popup-glasspane'))
411 event.preventDefault();
412 }
413
414 /**
415 * @param {!Document} document
416 */
417 _addMainEventListeners(document) {
418 document.addEventListener('keydown', this._postDocumentKeyDown.bind(this), false);
419 document.addEventListener('beforecopy', this._redispatchClipboardEvent.bind(this), true);
420 document.addEventListener('copy', this._redispatchClipboardEvent.bind(this), false);
421 document.addEventListener('cut', this._redispatchClipboardEvent.bind(this), false);
422 document.addEventListener('paste', this._redispatchClipboardEvent.bind(this), false);
423 document.addEventListener('contextmenu', this._contextMenuEventFired.bind(this), true);
424 }
425
426 _onSuspendStateChanged() {
427 const suspended = SDK.targetManager.allTargetsSuspended();
428 UI.inspectorView.onSuspendStateChanged(suspended);
429 }
430};
431
432/**
433 * @implements {UI.ActionDelegate}
434 * @unrestricted
435 */
436Main.Main.ZoomActionDelegate = class {
437 /**
438 * @override
439 * @param {!UI.Context} context
440 * @param {string} actionId
441 * @return {boolean}
442 */
443 handleAction(context, actionId) {
444 if (InspectorFrontendHost.isHostedMode())
445 return false;
446
447 switch (actionId) {
448 case 'main.zoom-in':
449 InspectorFrontendHost.zoomIn();
450 return true;
451 case 'main.zoom-out':
452 InspectorFrontendHost.zoomOut();
453 return true;
454 case 'main.zoom-reset':
455 InspectorFrontendHost.resetZoom();
456 return true;
457 }
458 return false;
459 }
460};
461
462/**
463 * @implements {UI.ActionDelegate}
464 * @unrestricted
465 */
466Main.Main.SearchActionDelegate = class {
467 /**
468 * @override
469 * @param {!UI.Context} context
470 * @param {string} actionId
471 * @return {boolean}
472 * @suppressGlobalPropertiesCheck
473 */
474 handleAction(context, actionId) {
475 const searchableView = UI.SearchableView.fromElement(document.deepActiveElement()) ||
476 UI.inspectorView.currentPanelDeprecated().searchableView();
477 if (!searchableView)
478 return false;
479 switch (actionId) {
480 case 'main.search-in-panel.find':
481 return searchableView.handleFindShortcut();
482 case 'main.search-in-panel.cancel':
483 return searchableView.handleCancelSearchShortcut();
484 case 'main.search-in-panel.find-next':
485 return searchableView.handleFindNextShortcut();
486 case 'main.search-in-panel.find-previous':
487 return searchableView.handleFindPreviousShortcut();
488 }
489 return false;
490 }
491};
492
493/**
494 * @implements {UI.ToolbarItem.Provider}
495 */
496Main.Main.MainMenuItem = class {
497 constructor() {
498 this._item = new UI.ToolbarMenuButton(this._handleContextMenu.bind(this), true);
499 this._item.setTitle(Common.UIString('Customize and control DevTools'));
500 }
501
502 /**
503 * @override
504 * @return {?UI.ToolbarItem}
505 */
506 item() {
507 return this._item;
508 }
509
510 /**
511 * @param {!UI.ContextMenu} contextMenu
512 */
513 _handleContextMenu(contextMenu) {
514 if (Components.dockController.canDock()) {
515 const dockItemElement = createElementWithClass('div', 'flex-centered flex-auto');
516 const titleElement = dockItemElement.createChild('span', 'flex-auto');
517 titleElement.textContent = Common.UIString('Dock side');
518 const toggleDockSideShorcuts = UI.shortcutRegistry.shortcutDescriptorsForAction('main.toggle-dock');
519 titleElement.title = Common.UIString(
520 'Placement of DevTools relative to the page. (%s to restore last position)', toggleDockSideShorcuts[0].name);
521 dockItemElement.appendChild(titleElement);
522 const dockItemToolbar = new UI.Toolbar('', dockItemElement);
523 dockItemToolbar.makeBlueOnHover();
524 const undock = new UI.ToolbarToggle(Common.UIString('Undock into separate window'), 'largeicon-undock');
525 const bottom = new UI.ToolbarToggle(Common.UIString('Dock to bottom'), 'largeicon-dock-to-bottom');
526 const right = new UI.ToolbarToggle(Common.UIString('Dock to right'), 'largeicon-dock-to-right');
527 const left = new UI.ToolbarToggle(Common.UIString('Dock to left'), 'largeicon-dock-to-left');
528 undock.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
529 bottom.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
530 right.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
531 left.addEventListener(UI.ToolbarButton.Events.MouseDown, event => event.data.consume());
532 undock.addEventListener(
533 UI.ToolbarButton.Events.MouseUp, setDockSide.bind(null, Components.DockController.State.Undocked));
534 bottom.addEventListener(
535 UI.ToolbarButton.Events.MouseUp, setDockSide.bind(null, Components.DockController.State.DockedToBottom));
536 right.addEventListener(
537 UI.ToolbarButton.Events.MouseUp, setDockSide.bind(null, Components.DockController.State.DockedToRight));
538 left.addEventListener(
539 UI.ToolbarButton.Events.MouseUp, setDockSide.bind(null, Components.DockController.State.DockedToLeft));
540 undock.setToggled(Components.dockController.dockSide() === Components.DockController.State.Undocked);
541 bottom.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToBottom);
542 right.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToRight);
543 left.setToggled(Components.dockController.dockSide() === Components.DockController.State.DockedToLeft);
544 dockItemToolbar.appendToolbarItem(undock);
545 dockItemToolbar.appendToolbarItem(left);
546 dockItemToolbar.appendToolbarItem(bottom);
547 dockItemToolbar.appendToolbarItem(right);
548 contextMenu.headerSection().appendCustomItem(dockItemElement);
549 }
550
551 /**
552 * @param {string} side
553 */
554 function setDockSide(side) {
555 Components.dockController.setDockSide(side);
556 contextMenu.discard();
557 }
558
559 if (Components.dockController.dockSide() === Components.DockController.State.Undocked &&
560 SDK.targetManager.mainTarget() && SDK.targetManager.mainTarget().hasBrowserCapability())
561 contextMenu.defaultSection().appendAction('inspector_main.focus-debuggee', Common.UIString('Focus debuggee'));
562
563 contextMenu.defaultSection().appendAction(
564 'main.toggle-drawer',
565 UI.inspectorView.drawerVisible() ? Common.UIString('Hide console drawer') :
566 Common.UIString('Show console drawer'));
567 contextMenu.appendItemsAtLocation('mainMenu');
568 const moreTools = contextMenu.defaultSection().appendSubMenuItem(Common.UIString('More tools'));
569 const extensions = self.runtime.extensions('view', undefined, true);
570 for (const extension of extensions) {
571 const descriptor = extension.descriptor();
572 if (descriptor['persistence'] !== 'closeable')
573 continue;
574 if (descriptor['location'] !== 'drawer-view' && descriptor['location'] !== 'panel')
575 continue;
576 moreTools.defaultSection().appendItem(
577 extension.title(), UI.viewManager.showView.bind(UI.viewManager, descriptor['id']));
578 }
579
580 const helpSubMenu = contextMenu.footerSection().appendSubMenuItem(Common.UIString('Help'));
581 helpSubMenu.appendItemsAtLocation('mainMenuHelp');
582 }
583};
584
585/**
586 * @unrestricted
587 */
588Main.Main.PauseListener = class {
589 constructor() {
590 SDK.targetManager.addModelListener(
591 SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
592 }
593
594 /**
595 * @param {!Common.Event} event
596 */
597 _debuggerPaused(event) {
598 SDK.targetManager.removeModelListener(
599 SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
600 const debuggerModel = /** @type {!SDK.DebuggerModel} */ (event.data);
601 const debuggerPausedDetails = debuggerModel.debuggerPausedDetails();
602 UI.context.setFlavor(SDK.Target, debuggerModel.target());
603 Common.Revealer.reveal(debuggerPausedDetails);
604 }
605};
606
607/**
608 * @param {string} method
609 * @param {?Object} params
610 * @return {!Promise}
611 */
612Main.sendOverProtocol = function(method, params) {
613 return new Promise((resolve, reject) => {
614 Protocol.InspectorBackend.sendRawMessageForTesting(method, params, (err, ...results) => {
615 if (err)
616 return reject(err);
617 return resolve(results);
618 });
619 });
620};
621
622/**
623 * @implements {UI.ActionDelegate}
624 * @unrestricted
625 */
626Main.ReloadActionDelegate = class {
627 /**
628 * @override
629 * @param {!UI.Context} context
630 * @param {string} actionId
631 * @return {boolean}
632 */
633 handleAction(context, actionId) {
634 switch (actionId) {
635 case 'main.debug-reload':
636 Components.reload();
637 return true;
638 }
639 return false;
640 }
641};
642
643new Main.Main();