UNPKG

diagram-js

Version:

A toolbox for displaying and modifying diagrams on the web

251 lines (219 loc) 6.75 kB
import { forEach, isFunction, isArray, isNumber, isObject } from 'min-dash'; /** * @typedef {import('../core/Types').ElementLike} ElementLike * @typedef {import('../core/EventBus').default} EventBus * @typedef {import('./CommandStack').CommandContext} CommandContext * * @typedef {string|string[]} Events * @typedef { (context: CommandContext) => ElementLike[] | void } HandlerFunction * @typedef { (context: CommandContext) => void } ComposeHandlerFunction */ var DEFAULT_PRIORITY = 1000; /** * A utility that can be used to plug into the command execution for * extension and/or validation. * * @class * @constructor * * @example * * ```javascript * import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor'; * * class CommandLogger extends CommandInterceptor { * constructor(eventBus) { * super(eventBus); * * this.preExecute('shape.create', (event) => { * console.log('commandStack.shape-create.preExecute', event); * }); * } * ``` * * @param {EventBus} eventBus */ export default function CommandInterceptor(eventBus) { /** * @type {EventBus} */ this._eventBus = eventBus; } CommandInterceptor.$inject = [ 'eventBus' ]; function unwrapEvent(fn, that) { return function(event) { return fn.call(that || null, event.context, event.command, event); }; } /** * Intercept a command during one of the phases. * * @param {Events} [events] command(s) to intercept * @param {string} [hook] phase to intercept * @param {number} [priority] * @param {ComposeHandlerFunction|HandlerFunction} handlerFn * @param {boolean} [unwrap] whether the event should be unwrapped * @param {any} [that] */ CommandInterceptor.prototype.on = function(events, hook, priority, handlerFn, unwrap, that) { if (isFunction(hook) || isNumber(hook)) { that = unwrap; unwrap = handlerFn; handlerFn = priority; priority = hook; hook = null; } if (isFunction(priority)) { that = unwrap; unwrap = handlerFn; handlerFn = priority; priority = DEFAULT_PRIORITY; } if (isObject(unwrap)) { that = unwrap; unwrap = false; } if (!isFunction(handlerFn)) { throw new Error('handlerFn must be a function'); } if (!isArray(events)) { events = [ events ]; } var eventBus = this._eventBus; forEach(events, function(event) { // concat commandStack(.event)?(.hook)? var fullEvent = [ 'commandStack', event, hook ].filter(function(e) { return e; }).join('.'); eventBus.on(fullEvent, priority, unwrap ? unwrapEvent(handlerFn, that) : handlerFn, that); }); }; /** * Add a <canExecute> phase of command interceptor. * * @param {Events} [events] command(s) to intercept * @param {number} [priority] * @param {ComposeHandlerFunction|HandlerFunction} handlerFn * @param {boolean} [unwrap] whether the event should be unwrapped * @param {any} [that] */ CommandInterceptor.prototype.canExecute = createHook('canExecute'); /** * Add a <preExecute> phase of command interceptor. * * @param {Events} [events] command(s) to intercept * @param {number} [priority] * @param {ComposeHandlerFunction|HandlerFunction} handlerFn * @param {boolean} [unwrap] whether the event should be unwrapped * @param {any} [that] */ CommandInterceptor.prototype.preExecute = createHook('preExecute'); /** * Add a <preExecuted> phase of command interceptor. * * @param {Events} [events] command(s) to intercept * @param {number} [priority] * @param {ComposeHandlerFunction|HandlerFunction} handlerFn * @param {boolean} [unwrap] whether the event should be unwrapped * @param {any} [that] */ CommandInterceptor.prototype.preExecuted = createHook('preExecuted'); /** * Add a <execute> phase of command interceptor. * * @param {Events} [events] command(s) to intercept * @param {number} [priority] * @param {ComposeHandlerFunction|HandlerFunction} handlerFn * @param {boolean} [unwrap] whether the event should be unwrapped * @param {any} [that] */ CommandInterceptor.prototype.execute = createHook('execute'); /** * Add a <executed> phase of command interceptor. * * @param {Events} [events] command(s) to intercept * @param {number} [priority] * @param {ComposeHandlerFunction|HandlerFunction} handlerFn * @param {boolean} [unwrap] whether the event should be unwrapped * @param {any} [that] */ CommandInterceptor.prototype.executed = createHook('executed'); /** * Add a <postExecute> phase of command interceptor. * * @param {Events} [events] command(s) to intercept * @param {number} [priority] * @param {ComposeHandlerFunction|HandlerFunction} handlerFn * @param {boolean} [unwrap] whether the event should be unwrapped * @param {any} [that] */ CommandInterceptor.prototype.postExecute = createHook('postExecute'); /** * Add a <postExecuted> phase of command interceptor. * * @param {Events} [events] command(s) to intercept * @param {number} [priority] * @param {ComposeHandlerFunction|HandlerFunction} handlerFn * @param {boolean} [unwrap] whether the event should be unwrapped * @param {any} [that] */ CommandInterceptor.prototype.postExecuted = createHook('postExecuted'); /** * Add a <revert> phase of command interceptor. * * @param {Events} [events] command(s) to intercept * @param {number} [priority] * @param {ComposeHandlerFunction|HandlerFunction} handlerFn * @param {boolean} [unwrap] whether the event should be unwrapped * @param {any} [that] */ CommandInterceptor.prototype.revert = createHook('revert'); /** * Add a <reverted> phase of command interceptor. * * @param {Events} [events] command(s) to intercept * @param {number} [priority] * @param {ComposeHandlerFunction|HandlerFunction} handlerFn * @param {boolean} [unwrap] whether the event should be unwrapped * @param {any} [that] */ CommandInterceptor.prototype.reverted = createHook('reverted'); /* * Add prototype methods for each phase of command execution (e.g. execute, * revert). * * @param {string} hook * * @return { ( * events?: Events, * priority?: number, * handlerFn: ComposeHandlerFunction|HandlerFunction, * unwrap?: boolean * ) => any } */ function createHook(hook) { /** * @this {CommandInterceptor} * * @param {Events} [events] * @param {number} [priority] * @param {ComposeHandlerFunction|HandlerFunction} handlerFn * @param {boolean} [unwrap] * @param {any} [that] */ const hookFn = function(events, priority, handlerFn, unwrap, that) { if (isFunction(events) || isNumber(events)) { that = unwrap; unwrap = handlerFn; handlerFn = priority; priority = events; events = null; } this.on(events, hook, priority, handlerFn, unwrap, that); }; return hookFn; }