UNPKG

@eclipse-glsp/client

Version:

A sprotty-based client for GLSP

551 lines 24.2 kB
"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