sprotty-theia
Version:
Glue code for Sprotty diagrams in a Theia IDE
224 lines • 8.83 kB
JavaScript
"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