UNPKG

sprotty-theia

Version:

Glue code for Sprotty diagrams in a Theia IDE

224 lines 8.83 kB
"use strict"; /******************************************************************************** * Copyright (c) 2017-2018 TypeFox 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 ********************************************************************************/ Object.defineProperty(exports, "__esModule", { value: true }); exports.DiagramWidget = exports.DiagramWidgetOptions = exports.DiagramWidgetFactory = void 0; const sprotty_1 = require("sprotty"); const sprotty_protocol_1 = require("sprotty-protocol"); const widget_1 = require("@theia/core/lib/browser/widgets/widget"); const uri_1 = require("@theia/core/lib/common/uri"); const theia_diagram_server_1 = require("../sprotty/theia-diagram-server"); exports.DiagramWidgetFactory = Symbol('DiagramWidgetFactory'); var DiagramWidgetOptions; (function (DiagramWidgetOptions) { function is(options) { return options.diagramType && options.uri && options.label && options.iconClass; } DiagramWidgetOptions.is = is; })(DiagramWidgetOptions = exports.DiagramWidgetOptions || (exports.DiagramWidgetOptions = {})); /** * The DiagramWidget is the container for Sprotty diagrams. */ class DiagramWidget extends widget_1.BaseWidget { constructor(options, widgetId, diContainer, connector) { super(); this.options = options; this.widgetId = widgetId; this.diContainer = diContainer; this.connector = connector; this.title.closable = true; this.title.label = options.label; this.title.iconClass = options.iconClass; } get uri() { return new uri_1.default(this.options.uri); } get actionDispatcher() { return this.diContainer.get(sprotty_1.TYPES.IActionDispatcher); } get viewerOptions() { return this.diContainer.get(sprotty_1.TYPES.ViewerOptions); } get modelSource() { return this._modelSource; } get clientId() { if (this._modelSource instanceof sprotty_1.DiagramServerProxy) return this._modelSource.clientId; else return this.widgetId; } get id() { return this.widgetId; } onAfterAttach(msg) { if (!this.diagramContainer) { // Create the container and initialize its content upon first attachment this.createContainer(); this.initializeSprotty(); } super.onAfterAttach(msg); } createContainer() { this.diagramContainer = document.createElement('div'); this.diagramContainer.id = this.viewerOptions.baseDiv; this.node.appendChild(this.diagramContainer); const hiddenContainer = document.createElement('div'); hiddenContainer.id = this.viewerOptions.hiddenDiv; document.body.appendChild(hiddenContainer); const statusDiv = document.createElement('div'); statusDiv.setAttribute('class', 'sprotty-status'); this.node.appendChild(statusDiv); this.statusIconDiv = document.createElement('div'); statusDiv.appendChild(this.statusIconDiv); this.statusMessageDiv = document.createElement('div'); this.statusMessageDiv.setAttribute('class', 'sprotty-status-message'); statusDiv.appendChild(this.statusMessageDiv); } initializeSprotty() { const modelSource = this.diContainer.get(sprotty_1.TYPES.ModelSource); this._modelSource = modelSource; if (modelSource instanceof theia_diagram_server_1.TheiaDiagramServer && this.connector) this.connector.connect(modelSource); this.disposed.connect(() => { if (modelSource instanceof theia_diagram_server_1.TheiaDiagramServer && this.connector) this.connector.disconnect(modelSource); }); this.requestModel(); } async requestModel() { try { const response = await this.actionDispatcher.request(sprotty_protocol_1.RequestModelAction.create({ sourceUri: this.options.uri, diagramType: this.options.diagramType })); await this.actionDispatcher.dispatch(response); await this.initializeView(); } catch (err) { const status = new sprotty_1.ServerStatusAction(); status.message = err instanceof Error ? err.message : err.toString(); status.severity = 'FATAL'; this.setStatus(status); } } initializeView() { return this.actionDispatcher.dispatch(sprotty_protocol_1.CenterAction.create([], { animate: false })); } getBoundsInPage(element) { const bounds = element.getBoundingClientRect(); return { x: bounds.left, y: bounds.top, width: bounds.width, height: bounds.height }; } onResize(msg) { super.onResize(msg); const newBounds = this.getBoundsInPage(this.node); this.actionDispatcher.dispatch(sprotty_1.InitializeCanvasBoundsAction.create(newBounds)); } onActivateRequest(msg) { super.onActivateRequest(msg); const svgElement = this.node.querySelector(`#${this.viewerOptions.baseDiv} svg`); if (svgElement !== null) { svgElement.focus(); } else { const tabindex = this.node.getAttribute('tabindex'); if (tabindex === null) this.node.setAttribute('tabindex', '-1'); this.node.focus(); } } /** * We cannot activate the widget before the SVG element is there, as it takes the focus. * This should happen within two animation frames, as the action dispatcher issues * a SetModelCommand in the constructor. OTOH, shell.activateWidget() is synchronous. So * after creating the widget and before activating it, we use this method to wait for the * SVG to be appended to the DOM. */ async getSvgElement() { return new Promise((resolve) => { let frames = 0; const waitForSvg = () => { requestAnimationFrame(() => { const svgElement = this.node.querySelector(`#${this.viewerOptions.baseDiv} svg`); if (svgElement !== null) resolve(svgElement); else if (++frames < 5) waitForSvg(); else resolve(undefined); }); }; waitForSvg(); }); } setStatus(status) { if (this.statusMessageDiv) { this.statusMessageDiv.textContent = status.message; this.removeClasses(this.statusMessageDiv, 1); this.statusMessageDiv.classList.add(status.severity.toLowerCase()); } if (this.statusIconDiv) { this.removeClasses(this.statusIconDiv, 0); const classes = this.statusIconDiv.classList; classes.add(status.severity.toLowerCase()); switch (status.severity) { case 'FATAL': classes.add(...widget_1.codiconArray('error')); break; case 'ERROR': classes.add(...widget_1.codiconArray('warning')); break; case 'WARNING': classes.add(...widget_1.codiconArray('warning')); break; case 'INFO': classes.add(...widget_1.codiconArray('info')); break; } } } removeClasses(element, keep) { const classes = element.classList; while (classes.length > keep) { const item = classes.item(classes.length - 1); if (item) classes.remove(item); } } storeState() { return this.options; } restoreState(oldState) { if (DiagramWidgetOptions.is(oldState)) this.options = oldState; } getResourceUri() { return this.uri; } createMoveToUri(resourceUri) { return this.uri.withPath(resourceUri.path); } } exports.DiagramWidget = DiagramWidget; //# sourceMappingURL=diagram-widget.js.map