@eclipse-glsp/client
Version:
A sprotty-based client for GLSP
551 lines • 24.2 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var ToolPalette_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ToolPalette = exports.EnableToolPaletteAction = void 0;
exports.compare = compare;
exports.createIcon = createIcon;
exports.createToolGroup = createToolGroup;
exports.changeCSSClass = changeCSSClass;
exports.changeCodiconClass = changeCodiconClass;
/********************************************************************************
* Copyright (c) 2019-2025 EclipseSource 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 WITH Classpath-exception-2.0
********************************************************************************/
const sprotty_1 = require("@eclipse-glsp/sprotty");
const inversify_1 = require("inversify");
const editor_context_service_1 = require("../../base/editor-context-service");
const focus_tracker_1 = require("../../base/focus/focus-tracker");
const messages_1 = require("../../base/messages");
const tool_1 = require("../../base/tool-manager/tool");
const ui_extension_1 = require("../../base/ui-extension/ui-extension");
const delete_tool_1 = require("../tools/deletion/delete-tool");
const marquee_mouse_tool_1 = require("../tools/marquee-selection/marquee-mouse-tool");
const origin_viewport_1 = require("../viewport/origin-viewport");
const CLICKED_CSS_CLASS = 'clicked';
const SEARCH_ICON_ID = 'search';
const PALETTE_ICON_ID = 'tools';
const CHEVRON_DOWN_ICON_ID = 'chevron-right';
const PALETTE_HEIGHT = '500px';
var EnableToolPaletteAction;
(function (EnableToolPaletteAction) {
EnableToolPaletteAction.KIND = 'enableToolPalette';
function is(object) {
return sprotty_1.Action.hasKind(object, EnableToolPaletteAction.KIND);
}
EnableToolPaletteAction.is = is;
function create() {
return { kind: EnableToolPaletteAction.KIND };
}
EnableToolPaletteAction.create = create;
})(EnableToolPaletteAction || (exports.EnableToolPaletteAction = EnableToolPaletteAction = {}));
let ToolPalette = ToolPalette_1 = class ToolPalette extends ui_extension_1.GLSPAbstractUIExtension {
constructor() {
super(...arguments);
this.paletteItemsCopy = [];
this.dynamic = false;
}
id() {
return ToolPalette_1.ID;
}
containerClass() {
return ToolPalette_1.ID;
}
postConstruct() {
this.editorContext.onEditModeChanged(change => this.editModeChanged(change.newValue, change.oldValue));
(0, messages_1.repeatOnMessagesUpdated)(() => {
this.createHeader();
this.addMinimizePaletteButton();
}, { initial: false });
}
initialize() {
if (!this.paletteItems) {
return false;
}
return super.initialize();
}
initializeContents(containerElement) {
this.addMinimizePaletteButton();
this.createHeader();
this.createBody();
this.lastActiveButton = this.defaultToolsButton;
containerElement.setAttribute('aria-label', messages_1.messages.tool_palette.label);
}
onBeforeShow(_containerElement, root) {
this.modelRootId = root.id;
this.containerElement.style.maxHeight = PALETTE_HEIGHT;
}
addMinimizePaletteButton() {
const baseDiv = document.getElementById(this.options.baseDiv);
if (!baseDiv) {
return;
}
const toggleButton = document.createElement('div');
toggleButton.classList.add('minimize-palette-button');
this.containerElement.classList.add('collapsible-palette');
const minimizeIcon = createIcon(CHEVRON_DOWN_ICON_ID);
this.updateMinimizePaletteButtonTooltip(toggleButton);
minimizeIcon.onclick = _event => {
if (this.isPaletteMaximized()) {
this.containerElement.style.maxHeight = '0px';
}
else {
this.containerElement.style.maxHeight = PALETTE_HEIGHT;
}
this.updateMinimizePaletteButtonTooltip(toggleButton);
changeCodiconClass(minimizeIcon, PALETTE_ICON_ID);
changeCodiconClass(minimizeIcon, CHEVRON_DOWN_ICON_ID);
};
toggleButton.appendChild(minimizeIcon);
// Replace existing header to refresh
if (this.toggleButton) {
this.toggleButton.replaceWith(toggleButton);
}
else {
baseDiv.insertBefore(toggleButton, baseDiv.firstChild);
}
this.toggleButton = toggleButton;
}
updateMinimizePaletteButtonTooltip(button) {
if (this.isPaletteMaximized()) {
button.title = messages_1.messages.tool_palette.minimize;
}
else {
button.title = messages_1.messages.tool_palette.maximize;
}
}
isPaletteMaximized() {
return this.containerElement && this.containerElement.style.maxHeight !== '0px';
}
createBody() {
const bodyDiv = document.createElement('div');
bodyDiv.classList.add('palette-body');
let tabIndex = 0;
this.paletteItems.sort(compare).forEach(item => {
if (item.children) {
const group = createToolGroup(item);
item.children.sort(compare).forEach(child => group.appendChild(this.createToolButton(child, tabIndex++)));
bodyDiv.appendChild(group);
}
else {
bodyDiv.appendChild(this.createToolButton(item, tabIndex++));
}
});
if (this.paletteItems.length === 0) {
const noResultsDiv = document.createElement('div');
noResultsDiv.innerText = messages_1.messages.tool_palette.no_items;
noResultsDiv.classList.add('tool-button');
bodyDiv.appendChild(noResultsDiv);
}
// Remove existing body to refresh filtered entries
if (this.bodyDiv) {
this.bodyDiv.replaceWith(bodyDiv);
}
else {
this.containerElement.appendChild(bodyDiv);
}
this.bodyDiv = bodyDiv;
}
createHeader() {
const headerCompartment = document.createElement('div');
headerCompartment.classList.add('palette-header');
headerCompartment.append(this.createHeaderTitle());
headerCompartment.appendChild(this.createHeaderTools());
headerCompartment.appendChild((this.searchField = this.createHeaderSearchField()));
// Replace existing header to refresh
if (this.headerDiv) {
this.headerDiv.replaceWith(headerCompartment);
}
else {
this.containerElement.appendChild(headerCompartment);
}
this.headerDiv = headerCompartment;
}
createHeaderTools() {
const headerTools = document.createElement('div');
headerTools.classList.add('header-tools');
this.defaultToolsButton = this.createDefaultToolButton();
headerTools.appendChild(this.defaultToolsButton);
const deleteToolButton = this.createMouseDeleteToolButton();
headerTools.appendChild(deleteToolButton);
const marqueeToolButton = this.createMarqueeToolButton();
headerTools.appendChild(marqueeToolButton);
const validateActionButton = this.createValidateButton();
headerTools.appendChild(validateActionButton);
const resetViewportButton = this.createResetViewportButton();
headerTools.appendChild(resetViewportButton);
if (this.gridManager) {
const toggleGridButton = this.createToggleGridButton();
headerTools.appendChild(toggleGridButton);
}
if (this.debugManager) {
const toggleDebugButton = this.createToggleDebugButton();
headerTools.appendChild(toggleDebugButton);
}
// Create button for Search
const searchIcon = this.createSearchButton();
headerTools.appendChild(searchIcon);
return headerTools;
}
createDefaultToolButton() {
const button = createIcon('inspect');
button.id = 'btn_default_tools';
button.title = messages_1.messages.tool_palette.selection_button;
button.onclick = this.onClickStaticToolButton(button);
button.ariaLabel = button.title;
button.tabIndex = 1;
return button;
}
createMouseDeleteToolButton() {
const deleteToolButton = createIcon('eraser');
deleteToolButton.title = messages_1.messages.tool_palette.delete_button;
deleteToolButton.onclick = this.onClickStaticToolButton(deleteToolButton, delete_tool_1.MouseDeleteTool.ID);
deleteToolButton.ariaLabel = deleteToolButton.title;
deleteToolButton.tabIndex = 1;
return deleteToolButton;
}
createMarqueeToolButton() {
const marqueeToolButton = createIcon('screen-full');
marqueeToolButton.title = messages_1.messages.tool_palette.marquee_button;
marqueeToolButton.onclick = this.onClickStaticToolButton(marqueeToolButton, marquee_mouse_tool_1.MarqueeMouseTool.ID);
marqueeToolButton.ariaLabel = marqueeToolButton.title;
marqueeToolButton.tabIndex = 1;
return marqueeToolButton;
}
createValidateButton() {
const validateActionButton = createIcon('pass');
validateActionButton.title = messages_1.messages.tool_palette.validate_button;
validateActionButton.onclick = _event => {
const modelIds = [this.modelRootId];
this.actionDispatcher.dispatch(sprotty_1.RequestMarkersAction.create(modelIds, { reason: sprotty_1.MarkersReason.BATCH }));
validateActionButton.focus();
};
validateActionButton.ariaLabel = validateActionButton.title;
validateActionButton.tabIndex = 1;
return validateActionButton;
}
createResetViewportButton() {
const resetViewportButton = createIcon('screen-normal');
resetViewportButton.title = messages_1.messages.tool_palette.reset_viewport_button;
resetViewportButton.onclick = _event => {
this.actionDispatcher.dispatch(origin_viewport_1.OriginViewportAction.create());
resetViewportButton.focus();
};
resetViewportButton.ariaLabel = resetViewportButton.title;
resetViewportButton.tabIndex = 1;
return resetViewportButton;
}
createToggleGridButton() {
var _a;
const toggleGridButton = createIcon('symbol-numeric');
toggleGridButton.title = messages_1.messages.tool_palette.toggle_grid_button;
toggleGridButton.onclick = () => {
var _a, _b, _c;
if ((_a = this.gridManager) === null || _a === void 0 ? void 0 : _a.isGridVisible) {
toggleGridButton.classList.remove(CLICKED_CSS_CLASS);
(_b = this.gridManager) === null || _b === void 0 ? void 0 : _b.setGridVisible(false);
}
else {
toggleGridButton.classList.add(CLICKED_CSS_CLASS);
(_c = this.gridManager) === null || _c === void 0 ? void 0 : _c.setGridVisible(true);
}
};
if ((_a = this.gridManager) === null || _a === void 0 ? void 0 : _a.isGridVisible) {
toggleGridButton.classList.add(CLICKED_CSS_CLASS);
}
toggleGridButton.ariaLabel = toggleGridButton.title;
toggleGridButton.tabIndex = 1;
return toggleGridButton;
}
createToggleDebugButton() {
var _a;
const toggleDebugButton = createIcon('debug');
toggleDebugButton.title = messages_1.messages.tool_palette.debug_mode_button;
toggleDebugButton.onclick = () => {
var _a, _b, _c;
if ((_a = this.debugManager) === null || _a === void 0 ? void 0 : _a.isDebugEnabled) {
toggleDebugButton.classList.remove(CLICKED_CSS_CLASS);
(_b = this.debugManager) === null || _b === void 0 ? void 0 : _b.setDebugEnabled(false);
}
else {
toggleDebugButton.classList.add(CLICKED_CSS_CLASS);
(_c = this.debugManager) === null || _c === void 0 ? void 0 : _c.setDebugEnabled(true);
}
};
if ((_a = this.debugManager) === null || _a === void 0 ? void 0 : _a.isDebugEnabled) {
toggleDebugButton.classList.add(CLICKED_CSS_CLASS);
}
toggleDebugButton.ariaLabel = toggleDebugButton.title;
toggleDebugButton.tabIndex = 1;
return toggleDebugButton;
}
createSearchButton() {
const searchIcon = createIcon(SEARCH_ICON_ID);
searchIcon.onclick = _ev => {
const searchField = document.getElementById(this.containerElement.id + '_search_field');
if (searchField) {
if (searchField.style.display === 'none') {
searchField.style.display = '';
searchField.focus();
}
else {
searchField.style.display = 'none';
}
}
};
searchIcon.classList.add('search-icon');
searchIcon.title = messages_1.messages.tool_palette.search_button;
searchIcon.ariaLabel = searchIcon.title;
searchIcon.tabIndex = 1;
return searchIcon;
}
createHeaderSearchField() {
const searchField = document.createElement('input');
searchField.classList.add('search-input');
searchField.id = this.containerElement.id + '_search_field';
searchField.type = 'text';
searchField.placeholder = messages_1.messages.tool_palette.search_placeholder;
searchField.style.display = 'none';
searchField.onkeyup = () => this.requestFilterUpdate(this.searchField.value);
searchField.onkeydown = ev => this.clearOnEscape(ev);
return searchField;
}
createHeaderTitle() {
const header = document.createElement('div');
header.classList.add('header-icon');
header.appendChild(createIcon(PALETTE_ICON_ID));
header.insertAdjacentText('beforeend', 'Palette');
return header;
}
createToolButton(item, index) {
const button = document.createElement('div');
button.tabIndex = index;
button.classList.add('tool-button');
if (item.icon) {
button.appendChild(createIcon(item.icon));
}
button.insertAdjacentText('beforeend', item.label);
button.onclick = this.onClickCreateToolButton(button, item);
button.onkeydown = ev => this.clearToolOnEscape(ev);
return button;
}
onClickCreateToolButton(button, item) {
return (_ev) => {
if (!this.editorContext.isReadonly) {
this.actionDispatcher.dispatchAll(item.actions);
this.changeActiveButton(button);
button.focus();
}
};
}
onClickStaticToolButton(button, toolId) {
return (_ev) => {
if (!this.editorContext.isReadonly) {
const action = toolId ? tool_1.EnableToolsAction.create([toolId]) : tool_1.EnableDefaultToolsAction.create();
this.actionDispatcher.dispatch(action);
this.changeActiveButton(button);
button.focus();
}
};
}
changeActiveButton(button) {
if (this.lastActiveButton) {
this.lastActiveButton.classList.remove(CLICKED_CSS_CLASS);
}
if (button) {
button.classList.add(CLICKED_CSS_CLASS);
this.lastActiveButton = button;
}
else if (this.defaultToolsButton) {
this.defaultToolsButton.classList.add(CLICKED_CSS_CLASS);
this.lastActiveButton = this.defaultToolsButton;
}
}
handle(action) {
var _a;
this.changeActiveButton();
if (sprotty_1.UpdateModelAction.is(action) || sprotty_1.SetModelAction.is(action)) {
this.reloadPaletteBody();
}
else if (tool_1.EnableDefaultToolsAction.is(action)) {
if (this.focusTracker.hasFocus) {
// if focus was deliberately taken do not restore focus to the palette
(_a = this.focusTracker.diagramElement) === null || _a === void 0 ? void 0 : _a.focus();
}
}
}
editModeChanged(_newValue, _oldValue) {
this.actionDispatcher.dispatch(sprotty_1.SetUIExtensionVisibilityAction.create({ extensionId: ToolPalette_1.ID, visible: !this.editorContext.isReadonly }));
}
clearOnEscape(event) {
if ((0, sprotty_1.matchesKeystroke)(event, 'Escape')) {
this.searchField.value = '';
this.requestFilterUpdate('');
}
}
clearToolOnEscape(event) {
if ((0, sprotty_1.matchesKeystroke)(event, 'Escape')) {
this.actionDispatcher.dispatch(tool_1.EnableDefaultToolsAction.create());
}
}
requestFilterUpdate(filter) {
// Initialize the copy if it's empty
if (this.paletteItemsCopy.length === 0) {
// Creating deep copy
this.paletteItemsCopy = JSON.parse(JSON.stringify(this.paletteItems));
}
// Reset the paletteItems before searching
this.paletteItems = JSON.parse(JSON.stringify(this.paletteItemsCopy));
// Filter the entries
const filteredPaletteItems = [];
for (const itemGroup of this.paletteItems) {
if (itemGroup.children) {
// Fetch the labels according to the filter
const matchingChildren = itemGroup.children.filter(child => child.label.toLowerCase().includes(filter.toLowerCase()));
// Add the itemgroup containing the correct entries
if (matchingChildren.length > 0) {
// Clear existing children
itemGroup.children.splice(0, itemGroup.children.length);
// Push the matching children
matchingChildren.forEach(child => itemGroup.children.push(child));
filteredPaletteItems.push(itemGroup);
}
}
}
this.paletteItems = filteredPaletteItems;
this.createBody();
}
/**
* @deprecated This hook is no longer used by the ToolPalette.
* It is kept for compatibility reasons and will be removed in the future.
* Move initialization logic to the `postRequestModel` method.
* This ensures that tool palette initialization does not block the diagram loading process.
*/
async preRequestModel() { }
async postRequestModel() {
await this.setPaletteItems();
if (!this.editorContext.isReadonly) {
this.show(this.editorContext.modelRoot);
}
}
async setPaletteItems() {
const requestAction = sprotty_1.RequestContextActions.create({
contextId: ToolPalette_1.ID,
editorContext: {
selectedElementIds: []
}
});
const response = await this.actionDispatcher.request(requestAction);
this.paletteItems = response.actions.map(action => action);
this.dynamic = this.paletteItems.some(item => this.hasDynamicAction(item));
}
hasDynamicAction(item) {
var _a;
const dynamic = !!item.actions.find(action => { var _a; return sprotty_1.TriggerNodeCreationAction.is(action) && ((_a = action.ghostElement) === null || _a === void 0 ? void 0 : _a.dynamic); });
if (dynamic) {
return dynamic;
}
return ((_a = item.children) === null || _a === void 0 ? void 0 : _a.some(child => this.hasDynamicAction(child))) || false;
}
async reloadPaletteBody() {
if (!this.editorContext.isReadonly && this.dynamic) {
await this.setPaletteItems();
this.paletteItemsCopy = [];
this.requestFilterUpdate(this.searchField.value);
}
}
};
exports.ToolPalette = ToolPalette;
ToolPalette.ID = 'tool-palette';
__decorate([
(0, inversify_1.inject)(sprotty_1.TYPES.IActionDispatcher),
__metadata("design:type", Object)
], ToolPalette.prototype, "actionDispatcher", void 0);
__decorate([
(0, inversify_1.inject)(editor_context_service_1.EditorContextService),
__metadata("design:type", editor_context_service_1.EditorContextService)
], ToolPalette.prototype, "editorContext", void 0);
__decorate([
(0, inversify_1.inject)(focus_tracker_1.FocusTracker),
__metadata("design:type", focus_tracker_1.FocusTracker)
], ToolPalette.prototype, "focusTracker", void 0);
__decorate([
(0, inversify_1.inject)(sprotty_1.TYPES.IGridManager),
(0, inversify_1.optional)(),
__metadata("design:type", Object)
], ToolPalette.prototype, "gridManager", void 0);
__decorate([
(0, inversify_1.inject)(sprotty_1.TYPES.IDebugManager),
(0, inversify_1.optional)(),
__metadata("design:type", Object)
], ToolPalette.prototype, "debugManager", void 0);
__decorate([
(0, inversify_1.postConstruct)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], ToolPalette.prototype, "postConstruct", null);
exports.ToolPalette = ToolPalette = ToolPalette_1 = __decorate([
(0, inversify_1.injectable)()
], ToolPalette);
function compare(a, b) {
const sortStringBased = a.sortString.localeCompare(b.sortString);
if (sortStringBased !== 0) {
return sortStringBased;
}
return a.label.localeCompare(b.label);
}
function createIcon(codiconId) {
const icon = document.createElement('i');
icon.classList.add(...(0, sprotty_1.codiconCSSClasses)(codiconId));
return icon;
}
function createToolGroup(item) {
const group = document.createElement('div');
group.classList.add('tool-group');
group.id = item.id;
const header = document.createElement('div');
header.classList.add('group-header');
if (item.icon) {
header.appendChild(createIcon(item.icon));
}
header.insertAdjacentText('beforeend', item.label);
header.ondblclick = _ev => {
const css = 'collapsed';
changeCSSClass(group, css);
Array.from(group.children).forEach(child => changeCSSClass(child, css));
window.getSelection().removeAllRanges();
};
group.appendChild(header);
return group;
}
function changeCSSClass(element, css) {
// eslint-disable-next-line chai-friendly/no-unused-expressions
element.classList.contains(css) ? element.classList.remove(css) : element.classList.add(css);
}
function changeCodiconClass(element, codiconId) {
// eslint-disable-next-line chai-friendly/no-unused-expressions
element.classList.contains((0, sprotty_1.codiconCSSClasses)(codiconId)[1])
? element.classList.remove((0, sprotty_1.codiconCSSClasses)(codiconId)[1])
: element.classList.add((0, sprotty_1.codiconCSSClasses)(codiconId)[1]);
}
//# sourceMappingURL=tool-palette.js.map