@theia/core
Version:
Theia is a cloud & desktop IDE framework implemented in TypeScript.
229 lines • 10.2 kB
JavaScript
"use strict";
// *****************************************************************************
// Copyright (C) 2022 Ericsson and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
Object.defineProperty(exports, "__esModule", { value: true });
exports.TabBarToolbarRegistry = exports.TabBarToolbarContribution = void 0;
const tslib_1 = require("tslib");
const debounce = require("lodash.debounce");
const inversify_1 = require("inversify");
// eslint-disable-next-line max-len
const common_1 = require("../../../common");
const context_key_service_1 = require("../../context-key-service");
const tab_bar_toolbar_menu_adapters_1 = require("./tab-bar-toolbar-menu-adapters");
/**
* Clients should implement this interface if they want to contribute to the tab-bar toolbar.
*/
exports.TabBarToolbarContribution = Symbol('TabBarToolbarContribution');
function yes() { return true; }
const menuDelegateSeparator = '=@=';
/**
* Main, shared registry for tab-bar toolbar items.
*/
let TabBarToolbarRegistry = class TabBarToolbarRegistry {
constructor() {
this.items = new Map();
this.menuDelegates = new Map();
this.onDidChangeEmitter = new common_1.Emitter();
this.onDidChange = this.onDidChangeEmitter.event;
// debounce in order to avoid to fire more than once in the same tick
this.fireOnDidChange = debounce(() => this.onDidChangeEmitter.fire(undefined), 0);
}
onStart() {
const contributions = this.contributionProvider.getContributions();
for (const contribution of contributions) {
contribution.registerToolbarItems(this);
}
}
/**
* Registers the given item. Throws an error, if the corresponding command cannot be found or an item has been already registered for the desired command.
*
* @param item the item to register.
*/
registerItem(item) {
const { id } = item;
if (this.items.has(id)) {
throw new Error(`A toolbar item is already registered with the '${id}' ID.`);
}
this.items.set(id, item);
this.fireOnDidChange();
const toDispose = new common_1.DisposableCollection(common_1.Disposable.create(() => this.fireOnDidChange()), common_1.Disposable.create(() => this.items.delete(id)));
if (item.onDidChange) {
toDispose.push(item.onDidChange(() => this.fireOnDidChange()));
}
return toDispose;
}
/**
* Returns an array of tab-bar toolbar items which are visible when the `widget` argument is the current one.
*
* By default returns with all items where the command is enabled and `item.isVisible` is `true`.
*/
visibleItems(widget) {
if (widget.isDisposed) {
return [];
}
const result = [];
for (const item of this.items.values()) {
if (this.isItemVisible(item, widget)) {
result.push(item);
}
}
for (const delegate of this.menuDelegates.values()) {
if (delegate.isVisible(widget)) {
const menu = this.menuRegistry.getMenu(delegate.menuPath);
for (const child of menu.children) {
if (!child.when || this.contextKeyService.match(child.when, widget.node)) {
if (child.children) {
for (const grandchild of child.children) {
if (!grandchild.when || this.contextKeyService.match(grandchild.when, widget.node)) {
const menuPath = this.menuRegistry.getPath(grandchild);
result.push(new tab_bar_toolbar_menu_adapters_1.ToolbarMenuNodeWrapper(grandchild, child.id, delegate.menuPath, menuPath));
}
}
}
else if (child.command) {
const menuPath = this.menuRegistry.getPath(child);
result.push(new tab_bar_toolbar_menu_adapters_1.ToolbarMenuNodeWrapper(child, undefined, delegate.menuPath, menuPath));
}
}
}
}
}
return result;
}
/**
* Query whether a toolbar `item` should be shown in the toolbar.
* This implementation delegates to item-specific checks according to their type.
*
* @param item a menu toolbar item
* @param widget the widget that is updating the toolbar
* @returns `false` if the `item` should be suppressed, otherwise `true`
*/
isItemVisible(item, widget) {
if (!this.isConditionalItemVisible(item, widget)) {
return false;
}
if (item.command && !this.commandRegistry.isVisible(item.command, widget)) {
return false;
}
if (item.menuPath && !this.isNonEmptyMenu(item, widget)) {
return false;
}
// The item is not vetoed. Accept it
return true;
}
/**
* Query whether a conditional toolbar `item` should be shown in the toolbar.
* This implementation delegates to the `item`'s own intrinsic conditionality.
*
* @param item a menu toolbar item
* @param widget the widget that is updating the toolbar
* @returns `false` if the `item` should be suppressed, otherwise `true`
*/
isConditionalItemVisible(item, widget) {
if (item.isVisible && !item.isVisible(widget)) {
return false;
}
if (item.when && !this.contextKeyService.match(item.when, widget.node)) {
return false;
}
return true;
}
/**
* Query whether a menu toolbar `item` should be shown in the toolbar.
* This implementation returns `false` if the `item` does not have any actual menu to show.
*
* @param item a menu toolbar item
* @param widget the widget that is updating the toolbar
* @returns `false` if the `item` should be suppressed, otherwise `true`
*/
isNonEmptyMenu(item, widget) {
if (!item.menuPath) {
return false;
}
const menu = this.menuRegistry.getMenu(item.menuPath);
const isVisible = node => {
var _a, _b;
return ((_a = node.children) === null || _a === void 0 ? void 0 : _a.length)
// Either the node is a sub-menu that has some visible child ...
? (_b = node.children) === null || _b === void 0 ? void 0 : _b.some(isVisible)
// ... or there is a command ...
: !!node.command
// ... that is visible ...
&& this.commandRegistry.isVisible(node.command, widget)
// ... and a "when" clause does not suppress the menu node.
&& (!node.when || this.contextKeyService.match(node.when, widget === null || widget === void 0 ? void 0 : widget.node));
};
return isVisible(menu);
}
unregisterItem(itemOrId) {
const id = typeof itemOrId === 'string' ? itemOrId : itemOrId.id;
if (this.items.delete(id)) {
this.fireOnDidChange();
}
}
registerMenuDelegate(menuPath, when) {
const id = this.toElementId(menuPath);
if (!this.menuDelegates.has(id)) {
const isVisible = !when
? yes
: typeof when === 'function'
? when
: widget => this.contextKeyService.match(when, widget === null || widget === void 0 ? void 0 : widget.node);
this.menuDelegates.set(id, { menuPath, isVisible });
this.fireOnDidChange();
return { dispose: () => this.unregisterMenuDelegate(menuPath) };
}
console.warn('Unable to register menu delegate. Delegate has already been registered', menuPath);
return common_1.Disposable.NULL;
}
unregisterMenuDelegate(menuPath) {
if (this.menuDelegates.delete(this.toElementId(menuPath))) {
this.fireOnDidChange();
}
}
/**
* Generate a single ID string from a menu path that
* is likely to be unique amongst the items in the toolbar.
*
* @param menuPath a menubar path
* @returns a likely unique ID based on the path
*/
toElementId(menuPath) {
return menuPath.join(menuDelegateSeparator);
}
};
exports.TabBarToolbarRegistry = TabBarToolbarRegistry;
tslib_1.__decorate([
(0, inversify_1.inject)(common_1.CommandRegistry),
tslib_1.__metadata("design:type", common_1.CommandRegistry)
], TabBarToolbarRegistry.prototype, "commandRegistry", void 0);
tslib_1.__decorate([
(0, inversify_1.inject)(context_key_service_1.ContextKeyService),
tslib_1.__metadata("design:type", Object)
], TabBarToolbarRegistry.prototype, "contextKeyService", void 0);
tslib_1.__decorate([
(0, inversify_1.inject)(common_1.MenuModelRegistry),
tslib_1.__metadata("design:type", common_1.MenuModelRegistry)
], TabBarToolbarRegistry.prototype, "menuRegistry", void 0);
tslib_1.__decorate([
(0, inversify_1.inject)(common_1.ContributionProvider),
(0, inversify_1.named)(exports.TabBarToolbarContribution),
tslib_1.__metadata("design:type", Object)
], TabBarToolbarRegistry.prototype, "contributionProvider", void 0);
exports.TabBarToolbarRegistry = TabBarToolbarRegistry = tslib_1.__decorate([
(0, inversify_1.injectable)()
], TabBarToolbarRegistry);
//# sourceMappingURL=tab-bar-toolbar-registry.js.map