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