UNPKG

sprotty

Version:

A next-gen framework for graphical views

187 lines 8.54 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 ********************************************************************************/ 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); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ActionDispatcher = void 0; const inversify_1 = require("inversify"); const actions_1 = require("sprotty-protocol/lib/actions"); const async_1 = require("sprotty-protocol/lib/utils/async"); const types_1 = require("../types"); const smodel_factory_1 = require("../model/smodel-factory"); const animation_frame_syncer_1 = require("../animations/animation-frame-syncer"); // This code should be used only in the client part of a Sprotty application. // We set the request context to 'client' to avoid collisions with requests created by the server. (0, actions_1.setRequestContext)('client'); /** * Collects actions, converts them to commands and dispatches them. * Also acts as the proxy to model sources such as diagram servers. */ let ActionDispatcher = class ActionDispatcher { constructor() { this.postponedActions = []; this.requests = new Map(); } initialize() { if (!this.initialized) { this.initialized = this.actionHandlerRegistryProvider().then(registry => { this.actionHandlerRegistry = registry; this.handleAction(actions_1.SetModelAction.create(smodel_factory_1.EMPTY_ROOT)).catch(() => { }); }); } return this.initialized; } /** * Dispatch an action by querying all handlers that are registered for its kind. * The returned promise is resolved when all handler results (commands or actions) * have been processed. */ dispatch(action) { return this.initialize().then(() => { if (this.blockUntil !== undefined) { return this.handleBlocked(action, this.blockUntil); } else if (this.diagramLocker.isAllowed(action)) { return this.handleAction(action); } return undefined; }); } /** * Calls `dispatch` on every action in the given array. The returned promise * is resolved when the promises of all `dispatch` calls have been resolved. */ dispatchAll(actions) { return Promise.all(actions.map(action => this.dispatch(action))); } /** * Dispatch a request. The returned promise is resolved when a response with matching * identifier is dispatched. That response is _not_ passed to the registered action * handlers. Instead, it is the responsibility of the caller of this method to handle * the response properly. For example, it can be sent to the registered handlers by * passing it again to the `dispatch` method. */ request(action) { if (!action.requestId) { return Promise.reject(new Error('Request without requestId')); } const deferred = new async_1.Deferred(); this.requests.set(action.requestId, deferred); this.dispatch(action).catch(() => { }); return deferred.promise; } handleAction(action) { if (action.kind === actions_1.UndoAction.KIND) { return this.commandStack.undo().then(() => { }); } if (action.kind === actions_1.RedoAction.KIND) { return this.commandStack.redo().then(() => { }); } if ((0, actions_1.isResponseAction)(action)) { const deferred = this.requests.get(action.responseId); if (deferred !== undefined) { this.requests.delete(action.responseId); if (action.kind === actions_1.RejectAction.KIND) { const rejectAction = action; deferred.reject(new Error(rejectAction.message)); this.logger.warn(this, `Request with id ${action.responseId} failed.`, rejectAction.message, rejectAction.detail); } else { deferred.resolve(action); } return Promise.resolve(); } this.logger.log(this, 'No matching request for response', action); } const handlers = this.actionHandlerRegistry.get(action.kind); if (handlers.length === 0) { this.logger.warn(this, 'Missing handler for action', action); const error = new Error(`Missing handler for action '${action.kind}'`); if ((0, actions_1.isRequestAction)(action)) { const deferred = this.requests.get(action.requestId); if (deferred !== undefined) { this.requests.delete(action.requestId); deferred.reject(error); } } return Promise.reject(error); } this.logger.log(this, 'Handle', action); const promises = []; for (const handler of handlers) { const result = handler.handle(action); if ((0, actions_1.isAction)(result)) { promises.push(this.dispatch(result)); } else if (result !== undefined) { promises.push(this.commandStack.execute(result)); this.blockUntil = result.blockUntil; } } return Promise.all(promises); } handleBlocked(action, predicate) { if (predicate(action)) { this.blockUntil = undefined; const result = this.handleAction(action); const actions = this.postponedActions; this.postponedActions = []; for (const a of actions) { this.dispatch(a.action).then(a.resolve, a.reject); } return result; } else { this.logger.log(this, 'Action is postponed due to block condition', action); return new Promise((resolve, reject) => { this.postponedActions.push({ action, resolve, reject }); }); } } }; exports.ActionDispatcher = ActionDispatcher; __decorate([ (0, inversify_1.inject)(types_1.TYPES.ActionHandlerRegistryProvider), __metadata("design:type", Function) ], ActionDispatcher.prototype, "actionHandlerRegistryProvider", void 0); __decorate([ (0, inversify_1.inject)(types_1.TYPES.ICommandStack), __metadata("design:type", Object) ], ActionDispatcher.prototype, "commandStack", void 0); __decorate([ (0, inversify_1.inject)(types_1.TYPES.ILogger), __metadata("design:type", Object) ], ActionDispatcher.prototype, "logger", void 0); __decorate([ (0, inversify_1.inject)(types_1.TYPES.AnimationFrameSyncer), __metadata("design:type", animation_frame_syncer_1.AnimationFrameSyncer) ], ActionDispatcher.prototype, "syncer", void 0); __decorate([ (0, inversify_1.inject)(types_1.TYPES.IDiagramLocker), __metadata("design:type", Object) ], ActionDispatcher.prototype, "diagramLocker", void 0); exports.ActionDispatcher = ActionDispatcher = __decorate([ (0, inversify_1.injectable)() ], ActionDispatcher); //# sourceMappingURL=action-dispatcher.js.map