1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
18 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
19 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
20 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
21 | return c > 3 && r && Object.defineProperty(target, key, r), r;
|
22 | };
|
23 | var __metadata = (this && this.__metadata) || function (k, v) {
|
24 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
25 | };
|
26 | var __param = (this && this.__param) || function (paramIndex, decorator) {
|
27 | return function (target, key) { decorator(target, key, paramIndex); }
|
28 | };
|
29 | Object.defineProperty(exports, "__esModule", { value: true });
|
30 | exports.MenuCommandRegistry = exports.BrowserMenuBarContribution = exports.DynamicMenuWidget = exports.MenuServices = exports.DynamicMenuBarWidget = exports.BrowserMainMenuFactory = exports.MenuBarWidget = void 0;
|
31 | const inversify_1 = require("inversify");
|
32 | const widgets_1 = require("@phosphor/widgets");
|
33 | const commands_1 = require("@phosphor/commands");
|
34 | const common_1 = require("../../common");
|
35 | const keybinding_1 = require("../keybinding");
|
36 | const context_key_service_1 = require("../context-key-service");
|
37 | const context_menu_context_1 = require("./context-menu-context");
|
38 | const widgets_2 = require("../widgets");
|
39 | const shell_1 = require("../shell");
|
40 | const core_preferences_1 = require("../core-preferences");
|
41 | const preference_service_1 = require("../preferences/preference-service");
|
42 | class MenuBarWidget extends widgets_1.MenuBar {
|
43 | }
|
44 | exports.MenuBarWidget = MenuBarWidget;
|
45 | ;
|
46 | let BrowserMainMenuFactory = class BrowserMainMenuFactory {
|
47 | createMenuBar() {
|
48 | const menuBar = new DynamicMenuBarWidget();
|
49 | menuBar.id = 'theia:menubar';
|
50 | this.corePreferences.ready.then(() => {
|
51 | this.showMenuBar(menuBar, this.corePreferences.get('window.menuBarVisibility', 'classic'));
|
52 | });
|
53 | const preferenceListener = this.corePreferences.onPreferenceChanged(preference => {
|
54 | if (preference.preferenceName === 'window.menuBarVisibility') {
|
55 | this.showMenuBar(menuBar, preference.newValue);
|
56 | }
|
57 | });
|
58 | const keybindingListener = this.keybindingRegistry.onKeybindingsChanged(() => {
|
59 | const preference = this.corePreferences['window.menuBarVisibility'];
|
60 | this.showMenuBar(menuBar, preference);
|
61 | });
|
62 | menuBar.disposed.connect(() => {
|
63 | preferenceListener.dispose();
|
64 | keybindingListener.dispose();
|
65 | });
|
66 | return menuBar;
|
67 | }
|
68 | showMenuBar(menuBar, preference) {
|
69 | if (preference && ['classic', 'visible'].includes(preference)) {
|
70 | menuBar.clearMenus();
|
71 | this.fillMenuBar(menuBar);
|
72 | }
|
73 | else {
|
74 | menuBar.clearMenus();
|
75 | }
|
76 | }
|
77 | fillMenuBar(menuBar) {
|
78 | const menuModel = this.menuProvider.getMenu(common_1.MAIN_MENU_BAR);
|
79 | const menuCommandRegistry = this.createMenuCommandRegistry(menuModel);
|
80 | for (const menu of menuModel.children) {
|
81 | if (common_1.CompoundMenuNode.is(menu)) {
|
82 | const menuWidget = this.createMenuWidget(menu, { commands: menuCommandRegistry, rootMenuPath: common_1.MAIN_MENU_BAR });
|
83 | menuBar.addMenu(menuWidget);
|
84 | }
|
85 | }
|
86 | }
|
87 | createContextMenu(path, args, context, contextKeyService) {
|
88 | const menuModel = this.menuProvider.getMenu(path);
|
89 | const menuCommandRegistry = this.createMenuCommandRegistry(menuModel, args).snapshot(path);
|
90 | const contextMenu = this.createMenuWidget(menuModel, { commands: menuCommandRegistry, context, rootMenuPath: path, contextKeyService });
|
91 | return contextMenu;
|
92 | }
|
93 | createMenuWidget(menu, options) {
|
94 | return new DynamicMenuWidget(menu, options, this.services);
|
95 | }
|
96 | createMenuCommandRegistry(menu, args = []) {
|
97 | const menuCommandRegistry = new MenuCommandRegistry(this.services);
|
98 | this.registerMenu(menuCommandRegistry, menu, args);
|
99 | return menuCommandRegistry;
|
100 | }
|
101 | registerMenu(menuCommandRegistry, menu, args) {
|
102 | if (common_1.CompoundMenuNode.is(menu)) {
|
103 | menu.children.forEach(child => this.registerMenu(menuCommandRegistry, child, args));
|
104 | }
|
105 | else if (common_1.CommandMenuNode.is(menu)) {
|
106 | menuCommandRegistry.registerActionMenu(menu, args);
|
107 | if (common_1.CommandMenuNode.hasAltHandler(menu)) {
|
108 | menuCommandRegistry.registerActionMenu(menu.altNode, args);
|
109 | }
|
110 | }
|
111 | }
|
112 | get services() {
|
113 | return {
|
114 | context: this.context,
|
115 | contextKeyService: this.contextKeyService,
|
116 | commandRegistry: this.commandRegistry,
|
117 | keybindingRegistry: this.keybindingRegistry,
|
118 | menuWidgetFactory: this,
|
119 | commandExecutor: this.menuCommandExecutor,
|
120 | };
|
121 | }
|
122 | };
|
123 | __decorate([
|
124 | (0, inversify_1.inject)(context_key_service_1.ContextKeyService),
|
125 | __metadata("design:type", Object)
|
126 | ], BrowserMainMenuFactory.prototype, "contextKeyService", void 0);
|
127 | __decorate([
|
128 | (0, inversify_1.inject)(context_menu_context_1.ContextMenuContext),
|
129 | __metadata("design:type", context_menu_context_1.ContextMenuContext)
|
130 | ], BrowserMainMenuFactory.prototype, "context", void 0);
|
131 | __decorate([
|
132 | (0, inversify_1.inject)(common_1.CommandRegistry),
|
133 | __metadata("design:type", common_1.CommandRegistry)
|
134 | ], BrowserMainMenuFactory.prototype, "commandRegistry", void 0);
|
135 | __decorate([
|
136 | (0, inversify_1.inject)(common_1.MenuCommandExecutor),
|
137 | __metadata("design:type", Object)
|
138 | ], BrowserMainMenuFactory.prototype, "menuCommandExecutor", void 0);
|
139 | __decorate([
|
140 | (0, inversify_1.inject)(core_preferences_1.CorePreferences),
|
141 | __metadata("design:type", Object)
|
142 | ], BrowserMainMenuFactory.prototype, "corePreferences", void 0);
|
143 | __decorate([
|
144 | (0, inversify_1.inject)(keybinding_1.KeybindingRegistry),
|
145 | __metadata("design:type", keybinding_1.KeybindingRegistry)
|
146 | ], BrowserMainMenuFactory.prototype, "keybindingRegistry", void 0);
|
147 | __decorate([
|
148 | (0, inversify_1.inject)(common_1.MenuModelRegistry),
|
149 | __metadata("design:type", common_1.MenuModelRegistry)
|
150 | ], BrowserMainMenuFactory.prototype, "menuProvider", void 0);
|
151 | BrowserMainMenuFactory = __decorate([
|
152 | (0, inversify_1.injectable)()
|
153 | ], BrowserMainMenuFactory);
|
154 | exports.BrowserMainMenuFactory = BrowserMainMenuFactory;
|
155 | class DynamicMenuBarWidget extends MenuBarWidget {
|
156 | constructor() {
|
157 | super();
|
158 |
|
159 | DynamicMenuBarWidget.prototype['_openChildMenu'] = () => {
|
160 | if (this.activeMenu instanceof DynamicMenuWidget) {
|
161 |
|
162 |
|
163 |
|
164 | if (!this.childMenu) {
|
165 | const { activeElement } = document;
|
166 | if (activeElement instanceof HTMLElement) {
|
167 | this.previousFocusedElement = activeElement;
|
168 | }
|
169 | }
|
170 | this.activeMenu.aboutToShow({ previousFocusedElement: this.previousFocusedElement });
|
171 | }
|
172 | super['_openChildMenu']();
|
173 | };
|
174 | }
|
175 | async activateMenu(label, ...labels) {
|
176 | const menu = this.menus.find(m => m.title.label === label);
|
177 | if (!menu) {
|
178 | throw new Error(`could not find '${label}' menu`);
|
179 | }
|
180 | this.activeMenu = menu;
|
181 | this.openActiveMenu();
|
182 | await (0, widgets_2.waitForRevealed)(menu);
|
183 | const menuPath = [label];
|
184 | let current = menu;
|
185 | for (const itemLabel of labels) {
|
186 | const item = current.items.find(i => i.label === itemLabel);
|
187 | if (!item || !item.submenu) {
|
188 | throw new Error(`could not find '${label}' submenu in ${menuPath.map(l => "'" + l + "'").join(' -> ')} menu`);
|
189 | }
|
190 | current.activeItem = item;
|
191 | current.triggerActiveItem();
|
192 | current = item.submenu;
|
193 | await (0, widgets_2.waitForRevealed)(current);
|
194 | }
|
195 | return current;
|
196 | }
|
197 | async triggerMenuItem(label, ...labels) {
|
198 | if (!labels.length) {
|
199 | throw new Error('menu item label is not specified');
|
200 | }
|
201 | const menuPath = [label, ...labels.slice(0, labels.length - 1)];
|
202 | const menu = await this.activateMenu(menuPath[0], ...menuPath.slice(1));
|
203 | const item = menu.items.find(i => i.label === labels[labels.length - 1]);
|
204 | if (!item) {
|
205 | throw new Error(`could not find '${label}' item in ${menuPath.map(l => "'" + l + "'").join(' -> ')} menu`);
|
206 | }
|
207 | menu.activeItem = item;
|
208 | menu.triggerActiveItem();
|
209 | return item;
|
210 | }
|
211 | }
|
212 | exports.DynamicMenuBarWidget = DynamicMenuBarWidget;
|
213 | class MenuServices {
|
214 | }
|
215 | exports.MenuServices = MenuServices;
|
216 |
|
217 |
|
218 |
|
219 | class DynamicMenuWidget extends widgets_1.Menu {
|
220 | constructor(menu, options, services) {
|
221 | super(options);
|
222 | this.menu = menu;
|
223 | this.options = options;
|
224 | this.services = services;
|
225 | if (menu.label) {
|
226 | this.title.label = menu.label;
|
227 | }
|
228 | if (menu.icon) {
|
229 | this.title.iconClass = menu.icon;
|
230 | }
|
231 | this.updateSubMenus(this, this.menu, this.options.commands);
|
232 | }
|
233 | aboutToShow({ previousFocusedElement }) {
|
234 | this.preserveFocusedElement(previousFocusedElement);
|
235 | this.clearItems();
|
236 | this.runWithPreservedFocusContext(() => {
|
237 | this.options.commands.snapshot(this.options.rootMenuPath);
|
238 | this.updateSubMenus(this, this.menu, this.options.commands);
|
239 | });
|
240 | }
|
241 | open(x, y, options) {
|
242 | const cb = () => {
|
243 | this.restoreFocusedElement();
|
244 | this.aboutToClose.disconnect(cb);
|
245 | };
|
246 | this.aboutToClose.connect(cb);
|
247 | this.preserveFocusedElement();
|
248 | super.open(x, y, options);
|
249 | }
|
250 | updateSubMenus(parent, menu, commands) {
|
251 | var _a;
|
252 | const items = this.buildSubMenus([], menu, commands);
|
253 | while (((_a = items[items.length - 1]) === null || _a === void 0 ? void 0 : _a.type) === 'separator') {
|
254 | items.pop();
|
255 | }
|
256 | for (const item of items) {
|
257 | parent.addItem(item);
|
258 | }
|
259 | }
|
260 | buildSubMenus(parentItems, menu, commands) {
|
261 | var _a, _b;
|
262 | if (common_1.CompoundMenuNode.is(menu)
|
263 | && menu.children.length
|
264 | && this.undefinedOrMatch((_a = this.options.contextKeyService) !== null && _a !== void 0 ? _a : this.services.contextKeyService, menu.when, this.options.context)) {
|
265 | const role = menu === this.menu ? 1 : common_1.CompoundMenuNode.getRole(menu);
|
266 | if (role === 0 ) {
|
267 | const submenu = this.services.menuWidgetFactory.createMenuWidget(menu, this.options);
|
268 | if (submenu.items.length > 0) {
|
269 | parentItems.push({ type: 'submenu', submenu });
|
270 | }
|
271 | }
|
272 | else if (role === 1 && menu.id !== 'inline') {
|
273 | const children = common_1.CompoundMenuNode.getFlatChildren(menu.children);
|
274 | const myItems = [];
|
275 | children.forEach(child => this.buildSubMenus(myItems, child, commands));
|
276 | if (myItems.length) {
|
277 | if (parentItems.length && parentItems[parentItems.length - 1].type !== 'separator') {
|
278 | parentItems.push({ type: 'separator' });
|
279 | }
|
280 | parentItems.push(...myItems);
|
281 | parentItems.push({ type: 'separator' });
|
282 | }
|
283 | }
|
284 | }
|
285 | else if (menu.command) {
|
286 | const node = menu.altNode && this.services.context.altPressed ? menu.altNode : menu;
|
287 | if (commands.isVisible(node.command) && this.undefinedOrMatch((_b = this.options.contextKeyService) !== null && _b !== void 0 ? _b : this.services.contextKeyService, node.when, this.options.context)) {
|
288 | parentItems.push({
|
289 | command: node.command,
|
290 | type: 'command'
|
291 | });
|
292 | }
|
293 | }
|
294 | return parentItems;
|
295 | }
|
296 | undefinedOrMatch(contextKeyService, expression, context) {
|
297 | if (expression) {
|
298 | return contextKeyService.match(expression, context);
|
299 | }
|
300 | return true;
|
301 | }
|
302 | preserveFocusedElement(previousFocusedElement = document.activeElement) {
|
303 | if (!this.previousFocusedElement && previousFocusedElement instanceof HTMLElement) {
|
304 | this.previousFocusedElement = previousFocusedElement;
|
305 | return true;
|
306 | }
|
307 | return false;
|
308 | }
|
309 | restoreFocusedElement() {
|
310 | if (this.previousFocusedElement) {
|
311 | this.previousFocusedElement.focus({ preventScroll: true });
|
312 | this.previousFocusedElement = undefined;
|
313 | return true;
|
314 | }
|
315 | return false;
|
316 | }
|
317 | runWithPreservedFocusContext(what) {
|
318 | let focusToRestore = undefined;
|
319 | const { activeElement } = document;
|
320 | if (this.previousFocusedElement && activeElement instanceof HTMLElement && this.previousFocusedElement !== activeElement) {
|
321 | focusToRestore = activeElement;
|
322 | this.previousFocusedElement.focus({ preventScroll: true });
|
323 | }
|
324 | try {
|
325 | what();
|
326 | }
|
327 | finally {
|
328 | if (focusToRestore) {
|
329 | focusToRestore.focus({ preventScroll: true });
|
330 | }
|
331 | }
|
332 | }
|
333 | }
|
334 | exports.DynamicMenuWidget = DynamicMenuWidget;
|
335 | let BrowserMenuBarContribution = class BrowserMenuBarContribution {
|
336 | constructor(factory) {
|
337 | this.factory = factory;
|
338 | }
|
339 | onStart(app) {
|
340 | this.appendMenu(app.shell);
|
341 | }
|
342 | get menuBar() {
|
343 | return this.shell.topPanel.widgets.find(w => w instanceof MenuBarWidget);
|
344 | }
|
345 | appendMenu(shell) {
|
346 | const logo = this.createLogo();
|
347 | shell.addWidget(logo, { area: 'top' });
|
348 | const menu = this.factory.createMenuBar();
|
349 | shell.addWidget(menu, { area: 'top' });
|
350 |
|
351 |
|
352 | if (common_1.environment.electron.is()) {
|
353 | this.preferenceService.ready.then(() => {
|
354 | menu.setHidden(['compact', 'hidden'].includes(this.preferenceService.get('window.menuBarVisibility', '')));
|
355 | });
|
356 | this.preferenceService.onPreferenceChanged(change => {
|
357 | if (change.preferenceName === 'window.menuBarVisibility') {
|
358 | menu.setHidden(['compact', 'hidden'].includes(change.newValue));
|
359 | }
|
360 | });
|
361 | }
|
362 | }
|
363 | createLogo() {
|
364 | const logo = new widgets_1.Widget();
|
365 | logo.id = 'theia:icon';
|
366 | logo.addClass('theia-icon');
|
367 | return logo;
|
368 | }
|
369 | };
|
370 | __decorate([
|
371 | (0, inversify_1.inject)(shell_1.ApplicationShell),
|
372 | __metadata("design:type", shell_1.ApplicationShell)
|
373 | ], BrowserMenuBarContribution.prototype, "shell", void 0);
|
374 | __decorate([
|
375 | (0, inversify_1.inject)(preference_service_1.PreferenceService),
|
376 | __metadata("design:type", Object)
|
377 | ], BrowserMenuBarContribution.prototype, "preferenceService", void 0);
|
378 | BrowserMenuBarContribution = __decorate([
|
379 | (0, inversify_1.injectable)(),
|
380 | __param(0, (0, inversify_1.inject)(BrowserMainMenuFactory)),
|
381 | __metadata("design:paramtypes", [BrowserMainMenuFactory])
|
382 | ], BrowserMenuBarContribution);
|
383 | exports.BrowserMenuBarContribution = BrowserMenuBarContribution;
|
384 |
|
385 |
|
386 |
|
387 | class MenuCommandRegistry extends commands_1.CommandRegistry {
|
388 | constructor(services) {
|
389 | super();
|
390 | this.services = services;
|
391 | this.actions = new Map();
|
392 | this.toDispose = new common_1.DisposableCollection();
|
393 | }
|
394 | registerActionMenu(menu, args) {
|
395 | const { commandRegistry } = this.services;
|
396 | const command = commandRegistry.getCommand(menu.command);
|
397 | if (!command) {
|
398 | return;
|
399 | }
|
400 | const { id } = command;
|
401 | if (this.actions.has(id)) {
|
402 | return;
|
403 | }
|
404 | this.actions.set(id, [menu, args]);
|
405 | }
|
406 | snapshot(menuPath) {
|
407 | this.toDispose.dispose();
|
408 | for (const [menu, args] of this.actions.values()) {
|
409 | this.toDispose.push(this.registerCommand(menu, args, menuPath));
|
410 | }
|
411 | return this;
|
412 | }
|
413 | registerCommand(menu, args, menuPath) {
|
414 | const { commandRegistry, keybindingRegistry, commandExecutor } = this.services;
|
415 | const command = commandRegistry.getCommand(menu.command);
|
416 | if (!command) {
|
417 | return common_1.Disposable.NULL;
|
418 | }
|
419 | const { id } = command;
|
420 | if (this.hasCommand(id)) {
|
421 |
|
422 | return common_1.Disposable.NULL;
|
423 | }
|
424 |
|
425 | const enabled = commandExecutor.isEnabled(menuPath, id, ...args);
|
426 | const visible = commandExecutor.isVisible(menuPath, id, ...args);
|
427 | const toggled = commandExecutor.isToggled(menuPath, id, ...args);
|
428 | const unregisterCommand = this.addCommand(id, {
|
429 | execute: () => commandExecutor.executeCommand(menuPath, id, ...args),
|
430 | label: menu.label,
|
431 | icon: menu.icon,
|
432 | isEnabled: () => enabled,
|
433 | isVisible: () => visible,
|
434 | isToggled: () => toggled
|
435 | });
|
436 | const bindings = keybindingRegistry.getKeybindingsForCommand(id);
|
437 |
|
438 | if (bindings.length) {
|
439 | const binding = bindings[0];
|
440 | const keys = keybindingRegistry.acceleratorFor(binding, ' ', true);
|
441 | this.addKeyBinding({
|
442 | command: id,
|
443 | keys,
|
444 | selector: '.p-Widget'
|
445 | });
|
446 | }
|
447 | return common_1.Disposable.create(() => unregisterCommand.dispose());
|
448 | }
|
449 | }
|
450 | exports.MenuCommandRegistry = MenuCommandRegistry;
|
451 |
|
\ | No newline at end of file |