UNPKG

camunda-dmn-js

Version:

Embeddable Camunda modeling distributions based on dmn-js

1,844 lines (1,732 loc) 3.15 MB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.DmnModeler = factory()); })(this, (function () { 'use strict'; function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey$1(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _defineProperty$4(e, r, t) { return (r = _toPropertyKey$1(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function () { return !!t; })(); } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function ownKeys$1(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2$1(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$1(Object(t), !0).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var s = Object.getOwnPropertySymbols(e); for (r = 0; r < s.length; r++) o = s[r], t.includes(o) || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; } function _possibleConstructorReturn(t, e) { if (e && ("object" == typeof e || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _toPrimitive$1(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return (String )(t); } function _toPropertyKey$1(t) { var i = _toPrimitive$1(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } /** * Flatten array, one level deep. * * @template T * * @param {T[][] | T[] | null} [arr] * * @return {T[]} */ function flatten$1(arr) { return Array.prototype.concat.apply([], arr); } const nativeToString$1 = Object.prototype.toString; const nativeHasOwnProperty$1 = Object.prototype.hasOwnProperty; function isUndefined$3(obj) { return obj === undefined; } function isDefined(obj) { return obj !== undefined; } function isNil(obj) { return obj == null; } function isArray$4(obj) { return nativeToString$1.call(obj) === '[object Array]'; } function isObject(obj) { return nativeToString$1.call(obj) === '[object Object]'; } function isNumber$3(obj) { return nativeToString$1.call(obj) === '[object Number]'; } /** * @param {any} obj * * @return {boolean} */ function isFunction$1(obj) { const tag = nativeToString$1.call(obj); return tag === '[object Function]' || tag === '[object AsyncFunction]' || tag === '[object GeneratorFunction]' || tag === '[object AsyncGeneratorFunction]' || tag === '[object Proxy]'; } function isString$1(obj) { return nativeToString$1.call(obj) === '[object String]'; } /** * Return true, if target owns a property with the given key. * * @param {Object} target * @param {String} key * * @return {Boolean} */ function has$1(target, key) { return !isNil(target) && nativeHasOwnProperty$1.call(target, key); } /** * @template T * @typedef { ( * ((e: T) => boolean) | * ((e: T, idx: number) => boolean) | * ((e: T, key: string) => boolean) | * string | * number * ) } Matcher */ /** * @template T * @template U * * @typedef { ( * ((e: T) => U) | string | number * ) } Extractor */ /** * @template T * @typedef { (val: T, key: any) => boolean } MatchFn */ /** * @template T * @typedef { T[] } ArrayCollection */ /** * @template T * @typedef { { [key: string]: T } } StringKeyValueCollection */ /** * @template T * @typedef { { [key: number]: T } } NumberKeyValueCollection */ /** * @template T * @typedef { StringKeyValueCollection<T> | NumberKeyValueCollection<T> } KeyValueCollection */ /** * @template T * @typedef { KeyValueCollection<T> | ArrayCollection<T> } Collection */ /** * Find element in collection. * * @template T * @param {Collection<T>} collection * @param {Matcher<T>} matcher * * @return {Object} */ function find$1(collection, matcher) { const matchFn = toMatcher(matcher); let match; forEach$1(collection, function (val, key) { if (matchFn(val, key)) { match = val; return false; } }); return match; } /** * Find element index in collection. * * @template T * @param {Collection<T>} collection * @param {Matcher<T>} matcher * * @return {number | string | undefined} */ function findIndex$1(collection, matcher) { const matchFn = toMatcher(matcher); let idx = isArray$4(collection) ? -1 : undefined; forEach$1(collection, function (val, key) { if (matchFn(val, key)) { idx = key; return false; } }); return idx; } /** * Filter elements in collection. * * @template T * @param {Collection<T>} collection * @param {Matcher<T>} matcher * * @return {T[]} result */ function filter$1(collection, matcher) { const matchFn = toMatcher(matcher); let result = []; forEach$1(collection, function (val, key) { if (matchFn(val, key)) { result.push(val); } }); return result; } /** * Iterate over collection; returning something * (non-undefined) will stop iteration. * * @template T * @param {Collection<T>} collection * @param { ((item: T, idx: number) => (boolean|void)) | ((item: T, key: string) => (boolean|void)) } iterator * * @return {T} return result that stopped the iteration */ function forEach$1(collection, iterator) { let val, result; if (isUndefined$3(collection)) { return; } const convertKey = isArray$4(collection) ? toNum$1 : identity$1; for (let key in collection) { if (has$1(collection, key)) { val = collection[key]; result = iterator(val, convertKey(key)); if (result === false) { return val; } } } } /** * Reduce collection, returning a single result. * * @template T * @template V * * @param {Collection<T>} collection * @param {(result: V, entry: T, index: any) => V} iterator * @param {V} result * * @return {V} result returned from last iterator */ function reduce(collection, iterator, result) { forEach$1(collection, function (value, idx) { result = iterator(result, value, idx); }); return result; } /** * Return true if every element in the collection * matches the criteria. * * @param {Object|Array} collection * @param {Function} matcher * * @return {Boolean} */ function every(collection, matcher) { return !!reduce(collection, function (matches, val, key) { return matches && matcher(val, key); }, true); } /** * Return true if some elements in the collection * match the criteria. * * @param {Object|Array} collection * @param {Function} matcher * * @return {Boolean} */ function some(collection, matcher) { return !!find$1(collection, matcher); } /** * Transform a collection into another collection * by piping each member through the given fn. * * @param {Object|Array} collection * @param {Function} fn * * @return {Array} transformed collection */ function map$b(collection, fn) { let result = []; forEach$1(collection, function (val, key) { result.push(fn(val, key)); }); return result; } /** * Get the collections keys. * * @param {Object|Array} collection * * @return {Array} */ function keys(collection) { return collection && Object.keys(collection) || []; } /** * Shorthand for `keys(o).length`. * * @param {Object|Array} collection * * @return {Number} */ function size(collection) { return keys(collection).length; } /** * Get the values in the collection. * * @param {Object|Array} collection * * @return {Array} */ function values$1(collection) { return map$b(collection, val => val); } /** * Group collection members by attribute. * * @param {Object|Array} collection * @param {Extractor} extractor * * @return {Object} map with { attrValue => [ a, b, c ] } */ function groupBy(collection, extractor, grouped = {}) { extractor = toExtractor(extractor); forEach$1(collection, function (val) { let discriminator = extractor(val) || '_'; let group = grouped[discriminator]; if (!group) { group = grouped[discriminator] = []; } group.push(val); }); return grouped; } function uniqueBy(extractor, ...collections) { extractor = toExtractor(extractor); let grouped = {}; forEach$1(collections, c => groupBy(c, extractor, grouped)); let result = map$b(grouped, function (val, key) { return val[0]; }); return result; } /** * Sort collection by criteria. * * @template T * * @param {Collection<T>} collection * @param {Extractor<T, number | string>} extractor * * @return {Array} */ function sortBy(collection, extractor) { extractor = toExtractor(extractor); let sorted = []; forEach$1(collection, function (value, key) { let disc = extractor(value, key); let entry = { d: disc, v: value }; for (var idx = 0; idx < sorted.length; idx++) { let { d } = sorted[idx]; if (disc < d) { sorted.splice(idx, 0, entry); return; } } // not inserted, append (!) sorted.push(entry); }); return map$b(sorted, e => e.v); } /** * Create an object pattern matcher. * * @example * * ```javascript * const matcher = matchPattern({ id: 1 }); * * let element = find(elements, matcher); * ``` * * @template T * * @param {T} pattern * * @return { (el: any) => boolean } matcherFn */ function matchPattern(pattern) { return function (el) { return every(pattern, function (val, key) { return el[key] === val; }); }; } /** * @param {string | ((e: any) => any) } extractor * * @return { (e: any) => any } */ function toExtractor(extractor) { /** * @satisfies { (e: any) => any } */ return isFunction$1(extractor) ? extractor : e => { // @ts-ignore: just works return e[extractor]; }; } /** * @template T * @param {Matcher<T>} matcher * * @return {MatchFn<T>} */ function toMatcher(matcher) { return isFunction$1(matcher) ? matcher : e => { return e === matcher; }; } function identity$1(arg) { return arg; } function toNum$1(arg) { return Number(arg); } /* global setTimeout clearTimeout */ /** * @typedef { { * (...args: any[]): any; * flush: () => void; * cancel: () => void; * } } DebouncedFunction */ /** * Debounce fn, calling it only once if the given time * elapsed between calls. * * Lodash-style the function exposes methods to `#clear` * and `#flush` to control internal behavior. * * @param {Function} fn * @param {Number} timeout * * @return {DebouncedFunction} debounced function */ function debounce(fn, timeout) { let timer; let lastArgs; let lastThis; let lastNow; function fire(force) { let now = Date.now(); let scheduledDiff = force ? 0 : lastNow + timeout - now; if (scheduledDiff > 0) { return schedule(scheduledDiff); } fn.apply(lastThis, lastArgs); clear(); } function schedule(timeout) { timer = setTimeout(fire, timeout); } function clear() { if (timer) { clearTimeout(timer); } timer = lastNow = lastArgs = lastThis = undefined; } function flush() { if (timer) { fire(true); } clear(); } /** * @type { DebouncedFunction } */ function callback(...args) { lastNow = Date.now(); lastArgs = args; lastThis = this; // ensure an execution is scheduled if (!timer) { schedule(timeout); } } callback.flush = flush; callback.cancel = clear; return callback; } /** * Throttle fn, calling at most once * in the given interval. * * @param {Function} fn * @param {Number} interval * * @return {Function} throttled function */ function throttle(fn, interval) { let throttling = false; return function (...args) { if (throttling) { return; } fn(...args); throttling = true; setTimeout(() => { throttling = false; }, interval); }; } /** * Bind function against target <this>. * * @param {Function} fn * @param {Object} target * * @return {Function} bound function */ function bind$4(fn, target) { return fn.bind(target); } /** * Convenience wrapper for `Object.assign`. * * @param {Object} target * @param {...Object} others * * @return {Object} the target */ function assign$1(target, ...others) { return Object.assign(target, ...others); } /** * Sets a nested property of a given object to the specified value. * * This mutates the object and returns it. * * @template T * * @param {T} target The target of the set operation. * @param {(string|number)[]} path The path to the nested value. * @param {any} value The value to set. * * @return {T} */ function set$1(target, path, value) { let currentTarget = target; forEach$1(path, function (key, idx) { if (typeof key !== 'number' && typeof key !== 'string') { throw new Error('illegal key type: ' + typeof key + '. Key should be of type number or string.'); } if (key === 'constructor') { throw new Error('illegal key: constructor'); } if (key === '__proto__') { throw new Error('illegal key: __proto__'); } let nextKey = path[idx + 1]; let nextTarget = currentTarget[key]; if (isDefined(nextKey) && isNil(nextTarget)) { nextTarget = currentTarget[key] = isNaN(+nextKey) ? {} : []; } if (isUndefined$3(nextKey)) { if (isUndefined$3(value)) { delete currentTarget[key]; } else { currentTarget[key] = value; } } else { currentTarget = nextTarget; } }); return target; } /** * Gets a nested property of a given object. * * @param {Object} target The target of the get operation. * @param {(string|number)[]} path The path to the nested value. * @param {any} [defaultValue] The value to return if no value exists. * * @return {any} */ function get$3(target, path, defaultValue) { let currentTarget = target; forEach$1(path, function (key) { // accessing nil property yields <undefined> if (isNil(currentTarget)) { currentTarget = undefined; return false; } currentTarget = currentTarget[key]; }); return isUndefined$3(currentTarget) ? defaultValue : currentTarget; } /** * Pick properties from the given target. * * @template T * @template {any[]} V * * @param {T} target * @param {V} properties * * @return Pick<T, V> */ function pick(target, properties) { let result = {}; let obj = Object(target); forEach$1(properties, function (prop) { if (prop in obj) { result[prop] = target[prop]; } }); return result; } /** * Pick all target properties, excluding the given ones. * * @template T * @template {any[]} V * * @param {T} target * @param {V} properties * * @return {Omit<T, V>} target */ function omit(target, properties) { let result = {}; let obj = Object(target); forEach$1(obj, function (prop, key) { if (properties.indexOf(key) === -1) { result[key] = prop; } }); return result; } var FN_REF = '__fn'; var DEFAULT_PRIORITY$9 = 1000; var slice = Array.prototype.slice; /** * @typedef { { * stopPropagation(): void; * preventDefault(): void; * cancelBubble: boolean; * defaultPrevented: boolean; * returnValue: any; * } } Event */ /** * @template E * * @typedef { (event: E & Event, ...any) => any } EventBusEventCallback */ /** * @typedef { { * priority: number; * next: EventBusListener | null; * callback: EventBusEventCallback<any>; * } } EventBusListener */ /** * A general purpose event bus. * * This component is used to communicate across a diagram instance. * Other parts of a diagram can use it to listen to and broadcast events. * * * ## Registering for Events * * The event bus provides the {@link EventBus#on} and {@link EventBus#once} * methods to register for events. {@link EventBus#off} can be used to * remove event registrations. Listeners receive an instance of {@link Event} * as the first argument. It allows them to hook into the event execution. * * ```javascript * * // listen for event * eventBus.on('foo', function(event) { * * // access event type * event.type; // 'foo' * * // stop propagation to other listeners * event.stopPropagation(); * * // prevent event default * event.preventDefault(); * }); * * // listen for event with custom payload * eventBus.on('bar', function(event, payload) { * console.log(payload); * }); * * // listen for event returning value * eventBus.on('foobar', function(event) { * * // stop event propagation + prevent default * return false; * * // stop event propagation + return custom result * return { * complex: 'listening result' * }; * }); * * * // listen with custom priority (default=1000, higher is better) * eventBus.on('priorityfoo', 1500, function(event) { * console.log('invoked first!'); * }); * * * // listen for event and pass the context (`this`) * eventBus.on('foobar', function(event) { * this.foo(); * }, this); * ``` * * * ## Emitting Events * * Events can be emitted via the event bus using {@link EventBus#fire}. * * ```javascript * * // false indicates that the default action * // was prevented by listeners * if (eventBus.fire('foo') === false) { * console.log('default has been prevented!'); * }; * * * // custom args + return value listener * eventBus.on('sum', function(event, a, b) { * return a + b; * }); * * // you can pass custom arguments + retrieve result values. * var sum = eventBus.fire('sum', 1, 2); * console.log(sum); // 3 * ``` * * @template [EventMap=null] */ function EventBus() { /** * @type { Record<string, EventBusListener> } */ this._listeners = {}; // cleanup on destroy on lowest priority to allow // message passing until the bitter end this.on('diagram.destroy', 1, this._destroy, this); } /** * @overlord * * Register an event listener for events with the given name. * * The callback will be invoked with `event, ...additionalArguments` * that have been passed to {@link EventBus#fire}. * * Returning false from a listener will prevent the events default action * (if any is specified). To stop an event from being processed further in * other listeners execute {@link Event#stopPropagation}. * * Returning anything but `undefined` from a listener will stop the listener propagation. * * @template T * * @param {string|string[]} events to subscribe to * @param {number} [priority=1000] listen priority * @param {EventBusEventCallback<T>} callback * @param {any} [that] callback context */ /** * Register an event listener for events with the given name. * * The callback will be invoked with `event, ...additionalArguments` * that have been passed to {@link EventBus#fire}. * * Returning false from a listener will prevent the events default action * (if any is specified). To stop an event from being processed further in * other listeners execute {@link Event#stopPropagation}. * * Returning anything but `undefined` from a listener will stop the listener propagation. * * @template {keyof EventMap} EventName * * @param {EventName} events to subscribe to * @param {number} [priority=1000] listen priority * @param {EventBusEventCallback<EventMap[EventName]>} callback * @param {any} [that] callback context */ EventBus.prototype.on = function (events, priority, callback, that) { events = isArray$4(events) ? events : [events]; if (isFunction$1(priority)) { that = callback; callback = priority; priority = DEFAULT_PRIORITY$9; } if (!isNumber$3(priority)) { throw new Error('priority must be a number'); } var actualCallback = callback; if (that) { actualCallback = bind$4(callback, that); // make sure we remember and are able to remove // bound callbacks via {@link #off} using the original // callback actualCallback[FN_REF] = callback[FN_REF] || callback; } var self = this; events.forEach(function (e) { self._addListener(e, { priority: priority, callback: actualCallback, next: null }); }); }; /** * @overlord * * Register an event listener that is called only once. * * @template T * * @param {string|string[]} events to subscribe to * @param {number} [priority=1000] the listen priority * @param {EventBusEventCallback<T>} callback * @param {any} [that] callback context */ /** * Register an event listener that is called only once. * * @template {keyof EventMap} EventName * * @param {EventName} events to subscribe to * @param {number} [priority=1000] listen priority * @param {EventBusEventCallback<EventMap[EventName]>} callback * @param {any} [that] callback context */ EventBus.prototype.once = function (events, priority, callback, that) { var self = this; if (isFunction$1(priority)) { that = callback; callback = priority; priority = DEFAULT_PRIORITY$9; } if (!isNumber$3(priority)) { throw new Error('priority must be a number'); } function wrappedCallback() { wrappedCallback.__isTomb = true; var result = callback.apply(that, arguments); self.off(events, wrappedCallback); return result; } // make sure we remember and are able to remove // bound callbacks via {@link #off} using the original // callback wrappedCallback[FN_REF] = callback; this.on(events, priority, wrappedCallback); }; /** * Removes event listeners by event and callback. * * If no callback is given, all listeners for a given event name are being removed. * * @param {string|string[]} events * @param {EventBusEventCallback} [callback] */ EventBus.prototype.off = function (events, callback) { events = isArray$4(events) ? events : [events]; var self = this; events.forEach(function (event) { self._removeListener(event, callback); }); }; /** * Create an event recognized be the event bus. * * @param {Object} data Event data. * * @return {Event} An event that will be recognized by the event bus. */ EventBus.prototype.createEvent = function (data) { var event = new InternalEvent(); event.init(data); return event; }; /** * Fires an event. * * @example * * ```javascript * // fire event by name * events.fire('foo'); * * // fire event object with nested type * var event = { type: 'foo' }; * events.fire(event); * * // fire event with explicit type * var event = { x: 10, y: 20 }; * events.fire('element.moved', event); * * // pass additional arguments to the event * events.on('foo', function(event, bar) { * alert(bar); * }); * * events.fire({ type: 'foo' }, 'I am bar!'); * ``` * * @param {string} [type] event type * @param {Object} [data] event or event data * @param {...any} [args] additional arguments the callback will be called with. * * @return {any} The return value. Will be set to `false` if the default was prevented. */ EventBus.prototype.fire = function (type, data) { var event, firstListener, returnValue, args; args = slice.call(arguments); if (typeof type === 'object') { data = type; type = data.type; } if (!type) { throw new Error('no event type specified'); } firstListener = this._listeners[type]; if (!firstListener) { return; } // we make sure we fire instances of our home made // events here. We wrap them only once, though if (data instanceof InternalEvent) { // we are fine, we alread have an event event = data; } else { event = this.createEvent(data); } // ensure we pass the event as the first parameter args[0] = event; // original event type (in case we delegate) var originalType = event.type; // update event type before delegation if (type !== originalType) { event.type = type; } try { returnValue = this._invokeListeners(event, args, firstListener); } finally { // reset event type after delegation if (type !== originalType) { event.type = originalType; } } // set the return value to false if the event default // got prevented and no other return value exists if (returnValue === undefined && event.defaultPrevented) { returnValue = false; } return returnValue; }; /** * Handle an error by firing an event. * * @param {Error} error The error to be handled. * * @return {boolean} Whether the error was handled. */ EventBus.prototype.handleError = function (error) { return this.fire('error', { error: error }) === false; }; EventBus.prototype._destroy = function () { this._listeners = {}; }; /** * @param {Event} event * @param {any[]} args * @param {EventBusListener} listener * * @return {any} */ EventBus.prototype._invokeListeners = function (event, args, listener) { var returnValue; while (listener) { // handle stopped propagation if (event.cancelBubble) { break; } returnValue = this._invokeListener(event, args, listener); listener = listener.next; } return returnValue; }; /** * @param {Event} event * @param {any[]} args * @param {EventBusListener} listener * * @return {any} */ EventBus.prototype._invokeListener = function (event, args, listener) { var returnValue; if (listener.callback.__isTomb) { return returnValue; } try { // returning false prevents the default action returnValue = invokeFunction(listener.callback, args); // stop propagation on return value if (returnValue !== undefined) { event.returnValue = returnValue; event.stopPropagation(); } // prevent default on return false if (returnValue === false) { event.preventDefault(); } } catch (error) { if (!this.handleError(error)) { console.error('unhandled error in event listener', error); throw error; } } return returnValue; }; /** * Add new listener with a certain priority to the list * of listeners (for the given event). * * The semantics of listener registration / listener execution are * first register, first serve: New listeners will always be inserted * after existing listeners with the same priority. * * Example: Inserting two listeners with priority 1000 and 1300 * * * before: [ 1500, 1500, 1000, 1000 ] * * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ] * * @param {string} event * @param {EventBusListener} newListener */ EventBus.prototype._addListener = function (event, newListener) { var listener = this._getListeners(event), previousListener; // no prior listeners if (!listener) { this._setListeners(event, newListener); return; } // ensure we order listeners by priority from // 0 (high) to n > 0 (low) while (listener) { if (listener.priority < newListener.priority) { newListener.next = listener; if (previousListener) { previousListener.next = newListener; } else { this._setListeners(event, newListener); } return; } previousListener = listener; listener = listener.next; } // add new listener to back previousListener.next = newListener; }; /** * @param {string} name * * @return {EventBusListener} */ EventBus.prototype._getListeners = function (name) { return this._listeners[name]; }; /** * @param {string} name * @param {EventBusListener} listener */ EventBus.prototype._setListeners = function (name, listener) { this._listeners[name] = listener; }; EventBus.prototype._removeListener = function (event, callback) { var listener = this._getListeners(event), nextListener, previousListener, listenerCallback; if (!callback) { // clear listeners this._setListeners(event, null); return; } while (listener) { nextListener = listener.next; listenerCallback = listener.callback; if (listenerCallback === callback || listenerCallback[FN_REF] === callback) { if (previousListener) { previousListener.next = nextListener; } else { // new first listener this._setListeners(event, nextListener); } } previousListener = listener; listener = nextListener; } }; /** * A event that is emitted via the event bus. */ function InternalEvent() {} InternalEvent.prototype.stopPropagation = function () { this.cancelBubble = true; }; InternalEvent.prototype.preventDefault = function () { this.defaultPrevented = true; }; InternalEvent.prototype.init = function (data) { assign$1(this, data || {}); }; /** * Invoke function. Be fast... * * @param {Function} fn * @param {any[]} args * * @return {any} */ function invokeFunction(fn, args) { return fn.apply(null, args); } /** * Moddle base element. */ function Base$1() {} Base$1.prototype.get = function (name) { return this.$model.properties.get(this, name); }; Base$1.prototype.set = function (name, value) { this.$model.properties.set(this, name, value); }; /** * A model element factory. * * @param {Moddle} model * @param {Properties} properties */ function Factory(model, properties) { this.model = model; this.properties = properties; } Factory.prototype.createType = function (descriptor) { var model = this.model; var props = this.properties, prototype = Object.create(Base$1.prototype); // initialize default values forEach$1(descriptor.properties, function (p) { if (!p.isMany && p.default !== undefined) { prototype[p.name] = p.default; } }); props.defineModel(prototype, model); props.defineDescriptor(prototype, descriptor); var name = descriptor.ns.name; /** * The new type constructor */ function ModdleElement(attrs) { props.define(this, '$type', { value: name, enumerable: true }); props.define(this, '$attrs', { value: {} }); props.define(this, '$parent', { writable: true }); forEach$1(attrs, bind$4(function (val, key) { this.set(key, val); }, this)); } ModdleElement.prototype = prototype; ModdleElement.hasType = prototype.$instanceOf = this.model.hasType; // static links props.defineModel(ModdleElement, model); props.defineDescriptor(ModdleElement, descriptor); return ModdleElement; }; /** * Built-in moddle types */ var BUILTINS = { String: true, Boolean: true, Integer: true, Real: true, Element: true }; /** * Converters for built in types from string representations */ var TYPE_CONVERTERS = { String: function (s) { return s; }, Boolean: function (s) { return s === 'true'; }, Integer: function (s) { return parseInt(s, 10); }, Real: function (s) { return parseFloat(s); } }; /** * Convert a type to its real representation */ function coerceType(type, value) { var converter = TYPE_CONVERTERS[type]; if (converter) { return converter(value); } else { return value; } } /** * Return whether the given type is built-in */ function isBuiltIn(type) { return !!BUILTINS[type]; } /** * Return whether the given type is simple */ function isSimple(type) { return !!TYPE_CONVERTERS[type]; } /** * Parses a namespaced attribute name of the form (ns:)localName to an object, * given a default prefix to assume in case no explicit namespace is given. * * @param {String} name * @param {String} [defaultPrefix] the default prefix to take, if none is present. * * @return {Object} the parsed name */ function parseName$3(name, defaultPrefix) { var parts = name.split(/:/), localName, prefix; // no prefix (i.e. only local name) if (parts.length === 1) { localName = name; prefix = defaultPrefix; } // prefix + local name else if (parts.length === 2) { localName = parts[1]; prefix = parts[0]; } else { throw new Error('expected <prefix:localName> or <localName>, got ' + name); } name = (prefix ? prefix + ':' : '') + localName; return { name: name, prefix: prefix, localName: localName }; } /** * A utility to build element descriptors. */ function DescriptorBuilder(nameNs) { this.ns = nameNs; this.name = nameNs.name; this.allTypes = []; this.allTypesByName = {}; this.properties = []; this.propertiesByName = {}; } DescriptorBuilder.prototype.build = function () { return pick(this, ['ns', 'name', 'allTypes', 'allTypesByName', 'properties', 'propertiesByName', 'bodyProperty', 'idProperty']); }; /** * Add property at given index. * * @param {Object} p * @param {Number} [idx] * @param {Boolean} [validate=true] */ DescriptorBuilder.prototype.addProperty = function (p, idx, validate) { if (typeof idx === 'boolean') { validate = idx; idx = undefined; } this.addNamedProperty(p, validate !== false); var properties = this.properties; if (idx !== undefined) { properties.splice(idx, 0, p); } else { properties.push(p); } }; DescriptorBuilder.prototype.replaceProperty = function (oldProperty, newProperty, replace) { var oldNameNs = oldProperty.ns; var props = this.properties, propertiesByName = this.propertiesByName, rename = oldProperty.name !== newProperty.name; if (oldProperty.isId) { if (!newProperty.isId) { throw new Error('property <' + newProperty.ns.name + '> must be id property ' + 'to refine <' + oldProperty.ns.name + '>'); } this.setIdProperty(newProperty, false); } if (oldProperty.isBody) { if (!newProperty.isBody) { throw new Error('property <' + newProperty.ns.name + '> must be body property ' + 'to refine <' + oldProperty.ns.name + '>'); } // TODO: Check compatibility this.setBodyProperty(newProperty, false); } // validate existence and get location of old property var idx = props.indexOf(oldProperty); if (idx === -1) { throw new Error('property <' + oldNameNs.name + '> not found in property list'); } // remove old property props.splice(idx, 1); // replacing the named property is intentional // // * validate only if this is a "rename" operation // * add at specific index unless we "replace" // this.addProperty(newProperty, replace ? undefined : idx, rename); // make new property available under old name propertiesByName[oldNameNs.name] = propertiesByName[oldNameNs.localName] = newProperty; }; DescriptorBuilder.prototype.redefineProperty = function (p, targetPropertyName, replace) { var nsPrefix = p.ns.prefix; var parts = targetPropertyName.split('#'); var name = parseName$3(parts[0], nsPrefix); var attrName = parseName$3(parts[1], name.prefix).name; var redefinedProperty = this.propertiesByName[attrName]; if (!redefinedProperty) { throw new Error('refined property <' + attrName + '> not found'); } else { this.replaceProperty(redefinedProperty, p, replace); } delete p.redefines; }; DescriptorBuilder.prototype.addNamedProperty = function (p, validate) { var ns = p.ns, propsByName = this.propertiesByName; if (validate) { this.assertNotDefined(p, ns.name); this.assertNotDefined(p, ns.localName); } propsByName[ns.name] = propsByName[ns.localName] = p; }; DescriptorBuilder.prototype.removeNamedProperty = function (p) { var ns = p.ns, propsByName = this.propertiesByName; delete propsByName[ns.name]; delete propsByName[ns.localName]; }; DescriptorBuilder.prototype.setBodyProperty = function (p, validate) { if (validate && this.bodyProperty) { throw new Error('body property defined multiple times ' + '(<' + this.bodyProperty.ns.name + '>, <' + p.ns.name + '>)'); } this.bodyProperty = p; }; DescriptorBuilder.prototype.setIdProperty = function (p, validate) { if (validate && this.idProperty) { throw new Error('id property defined multiple times ' + '(<' + this.idProperty.ns.name + '>, <' + p.ns.name + '>)'); } this.idProperty = p; }; DescriptorBuilder.prototype.assertNotTrait = function (typeDescriptor) { const _extends = typeDescriptor.extends || []; if (_extends.length) { throw new Error(`cannot create <${typeDescriptor.name}> extending <${typeDescriptor.extends}>`); } }; DescriptorBuilder.prototype.assertNotDefined = function (p, name) { var propertyName = p.name, definedProperty = this.propertiesByName[propertyName]; if (definedProperty) { throw new Error('property <' + propertyName + '> already defined; ' + 'override of <' + definedProperty.definedBy.ns.name + '#' + definedProperty.ns.name + '> by ' + '<' + p.definedBy.ns.name + '#' + p.ns.name + '> not allowed without redefines'); } }; DescriptorBuilder.prototype.hasProperty = function (name) { return this.propertiesByName[name]; }; DescriptorBuilder.prototype.addTrait = function (t, inherited) { if (inherited) { this.assertNotTrait(t); } var typesByName = this.allTypesByName, types = this.allTypes; var typeName = t.name; if (typeName in typesByName) { return; } forEach$1(t.properties, bind$4(function (p) { // clone property to allow extensions p = assign$1({}, p, { name: p.ns.localName, inherited: inherited }); Object.defineProperty(p, 'definedBy', { value: t }); var replaces = p.replaces, redefines = p.redefines; // add replace/redefine support if (replaces || redefines) { this.redefineProperty(p, replaces || redefines, replaces); } else { if (p.isBody) { this.setBodyProperty(p); } if (p.isId) { this.setIdProperty(p); } this.addProperty(p); } }, this)); types.push(t); typesByName[typeName] = t; }; /** * A registry of Moddle packages. * * @param {Array<Package>} packages * @param {Properties} properties */ function Registry(packages, properties) { this.packageMap = {}; this.typeMap = {}; this.packages = []; this.properties = properties; forEach$1(packages, bind$4(this.registerPackage, this)); } Registry.prototype.getPackage = function (uriOrPrefix) { return this.packageMap[uriOrPrefix]; }; Registry.prototype.getPackages = function () { return this.packages; }; Registry.prototype.registerPackage = function (pkg) { // copy package pkg = assign$1({}, pkg); var pkgMap = this.packageMap; ensureAvailable(pkgMap, pkg, 'prefix'); ensureAvailable(pkgMap, pkg, 'uri'); // register types forEach$1(pkg.types, bind$4(function (descriptor) { this.registerType(descriptor, pkg); }, this)); pkgMap[pkg.uri] = pkgMap[pkg.prefix] = pkg; this.packages.push(pkg); }; /** * Register a type from a specific package with us */ Registry.prototype.registerType = function (type, pkg) { type = assign$1({}, type, { superClass: (type.superClass || []).slice(), extends: (type.extends || []).slice(), properties: (type.properties || []).slice(), meta: assign$1(type.meta || {}) }); var ns = parseName$3(type.name, pkg.prefix), name = ns.name, propertiesByName = {}; // parse properties forEach$1(type.properties, bind$4(function (p) { // namespace property names var propertyNs = parseName$3(p.name, ns.prefix), propertyName = propertyNs.name; // namespace property types if (!isBuiltIn(p.type)) { p.type = parseName$3(p.type, propertyNs.prefix).name; } assign$1(p, { ns: propertyNs, name: propertyName }); propertiesByName[propertyName] = p; }, this)); // update ns + name assign$1(type, { ns: ns, name: name, propertiesByName: propertiesByName }); forEach$1(type.extends, bind$4(function (extendsName) { var extendsNameNs = parseName$3(extendsName, ns.prefix); var extended = this.typeMap[extendsNameNs.name]; extended.traits = extended.traits || []; extended.traits.push(name); }, this)); // link to package this.definePackage(type, pkg); // register this.typeMap[name] = type; }; /** * Traverse the type hierarchy from bottom to top, * calling iterator with (type, inherited) for all elements in * the inheritance chain. * * @param {Object} nsName * @param {Function} iterator * @param {Boolean} [trait=false] */ Registry.prototype.mapTypes = function (nsName, iterator, trait) { var type = isBuiltIn(nsName.name) ? { name: nsName.name } : this.typeMap[nsName.name]; var self = this; /** * Traverse the selected super type or trait * * @param {String} cls * @param {Boolean} [trait=false] */ function traverse(cls, trait) { var parentNs = parseName$3(cls, isBuiltIn(cls) ? '' : nsName.prefix); self.mapTypes(parentNs, iterator, trait); } /** * Traverse the selected trait. * * @param {String} cls */ function traverseTrait(cls) { return traverse(cls, true); } /** * Traverse the selected super type * * @param {String} cls */ function traverseSuper(cls) { return traverse(cls, false); } if (!type) { throw new Error('unknown type <' + nsName.name + '>'); } forEach$1(type.superClass, trait ? traverseTrait : traverseSuper); // call iterator with (type, inherited=!trait) iterator(type, !trait); forEach$1(type.traits, traverseTrait); }; /** * Returns the effective descriptor for a type. * * @param {String} type the namespaced name (ns:localName) of the type * * @return {Descriptor} the resulting effective descriptor */ Registry.prototype.getEffectiveDescriptor = function (name) { var nsName = parseName$3(name); var builder = new DescriptorBuilder(nsName); this.mapTypes(nsName, function (type, inherited) { builder.addTrait(type, inherited); }); var descriptor = builder.build(); // define package link this.definePackage(descriptor, descriptor.allTypes[descriptor.allTypes.length - 1].$pkg); return descriptor; }; Registry.prototype.definePackage = function (target, pkg) { this.properties.define(target, '$pkg', { value: pkg }); }; // helpers //////////////////////////// function ensureAvailable(packageMap, pkg, identifierKey) { var value = pkg[identifierKey]; if (value in packageMap) { throw new Error('package with ' + identifierKey + ' <' + value + '> already defined'); } } /** * A utility that gets and sets properties of model elements. * * @param {Model} model */ function Properties(model) { this.model = model; } /** * Sets a named property on the target element. * If the value is undefined, the property gets deleted. * * @param {Object} target * @param {String} name * @param {Object} value */ Properties.prototype.set = function (target, name, value) { if (!isString$1(name) || !name.length) { throw new TypeError('property name must be a non-empty string'); } var property = this.getProperty(target, name);