UNPKG

463 kBJavaScriptView Raw
1/*!
2 * bpmn-js - bpmn-navigated-viewer v7.2.1
3 *
4 * Copyright (c) 2014-present, camunda Services GmbH
5 *
6 * Released under the bpmn.io license
7 * http://bpmn.io/license
8 *
9 * Source Code: https://github.com/bpmn-io/bpmn-js
10 *
11 * Date: 2020-08-03
12 */
13(function (global, factory) {
14 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
15 typeof define === 'function' && define.amd ? define(factory) :
16 (global = global || self, global.BpmnJS = factory());
17}(this, function () { 'use strict';
18
19 function createCommonjsModule(fn, module) {
20 return module = { exports: {} }, fn(module, module.exports), module.exports;
21 }
22
23 var inherits_browser = createCommonjsModule(function (module) {
24 if (typeof Object.create === 'function') {
25 // implementation from standard node.js 'util' module
26 module.exports = function inherits(ctor, superCtor) {
27 ctor.super_ = superCtor;
28 ctor.prototype = Object.create(superCtor.prototype, {
29 constructor: {
30 value: ctor,
31 enumerable: false,
32 writable: true,
33 configurable: true
34 }
35 });
36 };
37 } else {
38 // old school shim for old browsers
39 module.exports = function inherits(ctor, superCtor) {
40 ctor.super_ = superCtor;
41 var TempCtor = function () {};
42 TempCtor.prototype = superCtor.prototype;
43 ctor.prototype = new TempCtor();
44 ctor.prototype.constructor = ctor;
45 };
46 }
47 });
48
49 /**
50 * Flatten array, one level deep.
51 *
52 * @param {Array<?>} arr
53 *
54 * @return {Array<?>}
55 */
56
57 var nativeToString = Object.prototype.toString;
58 var nativeHasOwnProperty = Object.prototype.hasOwnProperty;
59 function isUndefined(obj) {
60 return obj === undefined;
61 }
62 function isDefined(obj) {
63 return obj !== undefined;
64 }
65 function isArray(obj) {
66 return nativeToString.call(obj) === '[object Array]';
67 }
68 function isObject(obj) {
69 return nativeToString.call(obj) === '[object Object]';
70 }
71 function isNumber(obj) {
72 return nativeToString.call(obj) === '[object Number]';
73 }
74 function isFunction(obj) {
75 var tag = nativeToString.call(obj);
76 return tag === '[object Function]' || tag === '[object AsyncFunction]' || tag === '[object GeneratorFunction]' || tag === '[object AsyncGeneratorFunction]' || tag === '[object Proxy]';
77 }
78 function isString(obj) {
79 return nativeToString.call(obj) === '[object String]';
80 }
81 /**
82 * Return true, if target owns a property with the given key.
83 *
84 * @param {Object} target
85 * @param {String} key
86 *
87 * @return {Boolean}
88 */
89
90 function has(target, key) {
91 return nativeHasOwnProperty.call(target, key);
92 }
93
94 /**
95 * Find element in collection.
96 *
97 * @param {Array|Object} collection
98 * @param {Function|Object} matcher
99 *
100 * @return {Object}
101 */
102
103 function find(collection, matcher) {
104 matcher = toMatcher(matcher);
105 var match;
106 forEach(collection, function (val, key) {
107 if (matcher(val, key)) {
108 match = val;
109 return false;
110 }
111 });
112 return match;
113 }
114 /**
115 * Find element in collection.
116 *
117 * @param {Array|Object} collection
118 * @param {Function} matcher
119 *
120 * @return {Array} result
121 */
122
123 function filter(collection, matcher) {
124 var result = [];
125 forEach(collection, function (val, key) {
126 if (matcher(val, key)) {
127 result.push(val);
128 }
129 });
130 return result;
131 }
132 /**
133 * Iterate over collection; returning something
134 * (non-undefined) will stop iteration.
135 *
136 * @param {Array|Object} collection
137 * @param {Function} iterator
138 *
139 * @return {Object} return result that stopped the iteration
140 */
141
142 function forEach(collection, iterator) {
143 var val, result;
144
145 if (isUndefined(collection)) {
146 return;
147 }
148
149 var convertKey = isArray(collection) ? toNum : identity;
150
151 for (var key in collection) {
152 if (has(collection, key)) {
153 val = collection[key];
154 result = iterator(val, convertKey(key));
155
156 if (result === false) {
157 return val;
158 }
159 }
160 }
161 }
162 /**
163 * Reduce collection, returning a single result.
164 *
165 * @param {Object|Array} collection
166 * @param {Function} iterator
167 * @param {Any} result
168 *
169 * @return {Any} result returned from last iterator
170 */
171
172 function reduce(collection, iterator, result) {
173 forEach(collection, function (value, idx) {
174 result = iterator(result, value, idx);
175 });
176 return result;
177 }
178 /**
179 * Return true if every element in the collection
180 * matches the criteria.
181 *
182 * @param {Object|Array} collection
183 * @param {Function} matcher
184 *
185 * @return {Boolean}
186 */
187
188 function every(collection, matcher) {
189 return !!reduce(collection, function (matches, val, key) {
190 return matches && matcher(val, key);
191 }, true);
192 }
193 /**
194 * Return true if some elements in the collection
195 * match the criteria.
196 *
197 * @param {Object|Array} collection
198 * @param {Function} matcher
199 *
200 * @return {Boolean}
201 */
202
203 function some(collection, matcher) {
204 return !!find(collection, matcher);
205 }
206 /**
207 * Transform a collection into another collection
208 * by piping each member through the given fn.
209 *
210 * @param {Object|Array} collection
211 * @param {Function} fn
212 *
213 * @return {Array} transformed collection
214 */
215
216 function map(collection, fn) {
217 var result = [];
218 forEach(collection, function (val, key) {
219 result.push(fn(val, key));
220 });
221 return result;
222 }
223 /**
224 * Create an object pattern matcher.
225 *
226 * @example
227 *
228 * const matcher = matchPattern({ id: 1 });
229 *
230 * var element = find(elements, matcher);
231 *
232 * @param {Object} pattern
233 *
234 * @return {Function} matcherFn
235 */
236
237 function matchPattern(pattern) {
238 return function (el) {
239 return every(pattern, function (val, key) {
240 return el[key] === val;
241 });
242 };
243 }
244
245 function toMatcher(matcher) {
246 return isFunction(matcher) ? matcher : function (e) {
247 return e === matcher;
248 };
249 }
250
251 function identity(arg) {
252 return arg;
253 }
254
255 function toNum(arg) {
256 return Number(arg);
257 }
258
259 /**
260 * Debounce fn, calling it only once if
261 * the given time elapsed between calls.
262 *
263 * @param {Function} fn
264 * @param {Number} timeout
265 *
266 * @return {Function} debounced function
267 */
268 function debounce(fn, timeout) {
269 var timer;
270 var lastArgs;
271 var lastThis;
272 var lastNow;
273
274 function fire() {
275 var now = Date.now();
276 var scheduledDiff = lastNow + timeout - now;
277
278 if (scheduledDiff > 0) {
279 return schedule(scheduledDiff);
280 }
281
282 fn.apply(lastThis, lastArgs);
283 timer = lastNow = lastArgs = lastThis = undefined;
284 }
285
286 function schedule(timeout) {
287 timer = setTimeout(fire, timeout);
288 }
289
290 return function () {
291 lastNow = Date.now();
292
293 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
294 args[_key] = arguments[_key];
295 }
296
297 lastArgs = args;
298 lastThis = this; // ensure an execution is scheduled
299
300 if (!timer) {
301 schedule(timeout);
302 }
303 };
304 }
305 /**
306 * Bind function against target <this>.
307 *
308 * @param {Function} fn
309 * @param {Object} target
310 *
311 * @return {Function} bound function
312 */
313
314 function bind(fn, target) {
315 return fn.bind(target);
316 }
317
318 function _extends() {
319 _extends = Object.assign || function (target) {
320 for (var i = 1; i < arguments.length; i++) {
321 var source = arguments[i];
322
323 for (var key in source) {
324 if (Object.prototype.hasOwnProperty.call(source, key)) {
325 target[key] = source[key];
326 }
327 }
328 }
329
330 return target;
331 };
332
333 return _extends.apply(this, arguments);
334 }
335
336 /**
337 * Convenience wrapper for `Object.assign`.
338 *
339 * @param {Object} target
340 * @param {...Object} others
341 *
342 * @return {Object} the target
343 */
344
345 function assign(target) {
346 for (var _len = arguments.length, others = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
347 others[_key - 1] = arguments[_key];
348 }
349
350 return _extends.apply(void 0, [target].concat(others));
351 }
352 /**
353 * Pick given properties from the target object.
354 *
355 * @param {Object} target
356 * @param {Array} properties
357 *
358 * @return {Object} target
359 */
360
361 function pick(target, properties) {
362 var result = {};
363 var obj = Object(target);
364 forEach(properties, function (prop) {
365 if (prop in obj) {
366 result[prop] = target[prop];
367 }
368 });
369 return result;
370 }
371 /**
372 * Pick all target properties, excluding the given ones.
373 *
374 * @param {Object} target
375 * @param {Array} properties
376 *
377 * @return {Object} target
378 */
379
380 function omit(target, properties) {
381 var result = {};
382 var obj = Object(target);
383 forEach(obj, function (prop, key) {
384 if (properties.indexOf(key) === -1) {
385 result[key] = prop;
386 }
387 });
388 return result;
389 }
390
391 var DEFAULT_RENDER_PRIORITY = 1000;
392
393 /**
394 * The base implementation of shape and connection renderers.
395 *
396 * @param {EventBus} eventBus
397 * @param {number} [renderPriority=1000]
398 */
399 function BaseRenderer(eventBus, renderPriority) {
400 var self = this;
401
402 renderPriority = renderPriority || DEFAULT_RENDER_PRIORITY;
403
404 eventBus.on([ 'render.shape', 'render.connection' ], renderPriority, function(evt, context) {
405 var type = evt.type,
406 element = context.element,
407 visuals = context.gfx;
408
409 if (self.canRender(element)) {
410 if (type === 'render.shape') {
411 return self.drawShape(visuals, element);
412 } else {
413 return self.drawConnection(visuals, element);
414 }
415 }
416 });
417
418 eventBus.on([ 'render.getShapePath', 'render.getConnectionPath'], renderPriority, function(evt, element) {
419 if (self.canRender(element)) {
420 if (evt.type === 'render.getShapePath') {
421 return self.getShapePath(element);
422 } else {
423 return self.getConnectionPath(element);
424 }
425 }
426 });
427 }
428
429 /**
430 * Should check whether *this* renderer can render
431 * the element/connection.
432 *
433 * @param {element} element
434 *
435 * @returns {boolean}
436 */
437 BaseRenderer.prototype.canRender = function() {};
438
439 /**
440 * Provides the shape's snap svg element to be drawn on the `canvas`.
441 *
442 * @param {djs.Graphics} visuals
443 * @param {Shape} shape
444 *
445 * @returns {Snap.svg} [returns a Snap.svg paper element ]
446 */
447 BaseRenderer.prototype.drawShape = function() {};
448
449 /**
450 * Provides the shape's snap svg element to be drawn on the `canvas`.
451 *
452 * @param {djs.Graphics} visuals
453 * @param {Connection} connection
454 *
455 * @returns {Snap.svg} [returns a Snap.svg paper element ]
456 */
457 BaseRenderer.prototype.drawConnection = function() {};
458
459 /**
460 * Gets the SVG path of a shape that represents it's visual bounds.
461 *
462 * @param {Shape} shape
463 *
464 * @return {string} svg path
465 */
466 BaseRenderer.prototype.getShapePath = function() {};
467
468 /**
469 * Gets the SVG path of a connection that represents it's visual bounds.
470 *
471 * @param {Connection} connection
472 *
473 * @return {string} svg path
474 */
475 BaseRenderer.prototype.getConnectionPath = function() {};
476
477 /**
478 * Is an element of the given BPMN type?
479 *
480 * @param {djs.model.Base|ModdleElement} element
481 * @param {string} type
482 *
483 * @return {boolean}
484 */
485 function is(element, type) {
486 var bo = getBusinessObject(element);
487
488 return bo && (typeof bo.$instanceOf === 'function') && bo.$instanceOf(type);
489 }
490
491
492 /**
493 * Return the business object for a given element.
494 *
495 * @param {djs.model.Base|ModdleElement} element
496 *
497 * @return {ModdleElement}
498 */
499 function getBusinessObject(element) {
500 return (element && element.businessObject) || element;
501 }
502
503 function isExpanded(element) {
504
505 if (is(element, 'bpmn:CallActivity')) {
506 return false;
507 }
508
509 if (is(element, 'bpmn:SubProcess')) {
510 return !!getBusinessObject(element).di.isExpanded;
511 }
512
513 if (is(element, 'bpmn:Participant')) {
514 return !!getBusinessObject(element).processRef;
515 }
516
517 return true;
518 }
519
520 function isEventSubProcess(element) {
521 return element && !!getBusinessObject(element).triggeredByEvent;
522 }
523
524 function getLabelAttr(semantic) {
525 if (
526 is(semantic, 'bpmn:FlowElement') ||
527 is(semantic, 'bpmn:Participant') ||
528 is(semantic, 'bpmn:Lane') ||
529 is(semantic, 'bpmn:SequenceFlow') ||
530 is(semantic, 'bpmn:MessageFlow') ||
531 is(semantic, 'bpmn:DataInput') ||
532 is(semantic, 'bpmn:DataOutput')
533 ) {
534 return 'name';
535 }
536
537 if (is(semantic, 'bpmn:TextAnnotation')) {
538 return 'text';
539 }
540
541 if (is(semantic, 'bpmn:Group')) {
542 return 'categoryValueRef';
543 }
544 }
545
546 function getCategoryValue(semantic) {
547 var categoryValueRef = semantic['categoryValueRef'];
548
549 if (!categoryValueRef) {
550 return '';
551 }
552
553
554 return categoryValueRef.value || '';
555 }
556
557 function getLabel(element) {
558 var semantic = element.businessObject,
559 attr = getLabelAttr(semantic);
560
561 if (attr) {
562
563 if (attr === 'categoryValueRef') {
564
565 return getCategoryValue(semantic);
566 }
567
568 return semantic[attr] || '';
569 }
570 }
571
572 function ensureImported(element, target) {
573
574 if (element.ownerDocument !== target.ownerDocument) {
575 try {
576 // may fail on webkit
577 return target.ownerDocument.importNode(element, true);
578 } catch (e) {
579 // ignore
580 }
581 }
582
583 return element;
584 }
585
586 /**
587 * appendTo utility
588 */
589
590 /**
591 * Append a node to a target element and return the appended node.
592 *
593 * @param {SVGElement} element
594 * @param {SVGElement} target
595 *
596 * @return {SVGElement} the appended node
597 */
598 function appendTo(element, target) {
599 return target.appendChild(ensureImported(element, target));
600 }
601
602 /**
603 * append utility
604 */
605
606 /**
607 * Append a node to an element
608 *
609 * @param {SVGElement} element
610 * @param {SVGElement} node
611 *
612 * @return {SVGElement} the element
613 */
614 function append(target, node) {
615 appendTo(node, target);
616 return target;
617 }
618
619 /**
620 * attribute accessor utility
621 */
622
623 var LENGTH_ATTR = 2;
624
625 var CSS_PROPERTIES = {
626 'alignment-baseline': 1,
627 'baseline-shift': 1,
628 'clip': 1,
629 'clip-path': 1,
630 'clip-rule': 1,
631 'color': 1,
632 'color-interpolation': 1,
633 'color-interpolation-filters': 1,
634 'color-profile': 1,
635 'color-rendering': 1,
636 'cursor': 1,
637 'direction': 1,
638 'display': 1,
639 'dominant-baseline': 1,
640 'enable-background': 1,
641 'fill': 1,
642 'fill-opacity': 1,
643 'fill-rule': 1,
644 'filter': 1,
645 'flood-color': 1,
646 'flood-opacity': 1,
647 'font': 1,
648 'font-family': 1,
649 'font-size': LENGTH_ATTR,
650 'font-size-adjust': 1,
651 'font-stretch': 1,
652 'font-style': 1,
653 'font-variant': 1,
654 'font-weight': 1,
655 'glyph-orientation-horizontal': 1,
656 'glyph-orientation-vertical': 1,
657 'image-rendering': 1,
658 'kerning': 1,
659 'letter-spacing': 1,
660 'lighting-color': 1,
661 'marker': 1,
662 'marker-end': 1,
663 'marker-mid': 1,
664 'marker-start': 1,
665 'mask': 1,
666 'opacity': 1,
667 'overflow': 1,
668 'pointer-events': 1,
669 'shape-rendering': 1,
670 'stop-color': 1,
671 'stop-opacity': 1,
672 'stroke': 1,
673 'stroke-dasharray': 1,
674 'stroke-dashoffset': 1,
675 'stroke-linecap': 1,
676 'stroke-linejoin': 1,
677 'stroke-miterlimit': 1,
678 'stroke-opacity': 1,
679 'stroke-width': LENGTH_ATTR,
680 'text-anchor': 1,
681 'text-decoration': 1,
682 'text-rendering': 1,
683 'unicode-bidi': 1,
684 'visibility': 1,
685 'word-spacing': 1,
686 'writing-mode': 1
687 };
688
689
690 function getAttribute(node, name) {
691 if (CSS_PROPERTIES[name]) {
692 return node.style[name];
693 } else {
694 return node.getAttributeNS(null, name);
695 }
696 }
697
698 function setAttribute(node, name, value) {
699 var hyphenated = name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
700
701 var type = CSS_PROPERTIES[hyphenated];
702
703 if (type) {
704 // append pixel unit, unless present
705 if (type === LENGTH_ATTR && typeof value === 'number') {
706 value = String(value) + 'px';
707 }
708
709 node.style[hyphenated] = value;
710 } else {
711 node.setAttributeNS(null, name, value);
712 }
713 }
714
715 function setAttributes(node, attrs) {
716
717 var names = Object.keys(attrs), i, name;
718
719 for (i = 0, name; (name = names[i]); i++) {
720 setAttribute(node, name, attrs[name]);
721 }
722 }
723
724 /**
725 * Gets or sets raw attributes on a node.
726 *
727 * @param {SVGElement} node
728 * @param {Object} [attrs]
729 * @param {String} [name]
730 * @param {String} [value]
731 *
732 * @return {String}
733 */
734 function attr(node, name, value) {
735 if (typeof name === 'string') {
736 if (value !== undefined) {
737 setAttribute(node, name, value);
738 } else {
739 return getAttribute(node, name);
740 }
741 } else {
742 setAttributes(node, name);
743 }
744
745 return node;
746 }
747
748 /**
749 * Clear utility
750 */
751 function index(arr, obj) {
752 if (arr.indexOf) {
753 return arr.indexOf(obj);
754 }
755
756
757 for (var i = 0; i < arr.length; ++i) {
758 if (arr[i] === obj) {
759 return i;
760 }
761 }
762
763 return -1;
764 }
765
766 var re = /\s+/;
767
768 var toString = Object.prototype.toString;
769
770 function defined(o) {
771 return typeof o !== 'undefined';
772 }
773
774 /**
775 * Wrap `el` in a `ClassList`.
776 *
777 * @param {Element} el
778 * @return {ClassList}
779 * @api public
780 */
781
782 function classes(el) {
783 return new ClassList(el);
784 }
785
786 function ClassList(el) {
787 if (!el || !el.nodeType) {
788 throw new Error('A DOM element reference is required');
789 }
790 this.el = el;
791 this.list = el.classList;
792 }
793
794 /**
795 * Add class `name` if not already present.
796 *
797 * @param {String} name
798 * @return {ClassList}
799 * @api public
800 */
801
802 ClassList.prototype.add = function(name) {
803
804 // classList
805 if (this.list) {
806 this.list.add(name);
807 return this;
808 }
809
810 // fallback
811 var arr = this.array();
812 var i = index(arr, name);
813 if (!~i) {
814 arr.push(name);
815 }
816
817 if (defined(this.el.className.baseVal)) {
818 this.el.className.baseVal = arr.join(' ');
819 } else {
820 this.el.className = arr.join(' ');
821 }
822
823 return this;
824 };
825
826 /**
827 * Remove class `name` when present, or
828 * pass a regular expression to remove
829 * any which match.
830 *
831 * @param {String|RegExp} name
832 * @return {ClassList}
833 * @api public
834 */
835
836 ClassList.prototype.remove = function(name) {
837 if ('[object RegExp]' === toString.call(name)) {
838 return this.removeMatching(name);
839 }
840
841 // classList
842 if (this.list) {
843 this.list.remove(name);
844 return this;
845 }
846
847 // fallback
848 var arr = this.array();
849 var i = index(arr, name);
850 if (~i) {
851 arr.splice(i, 1);
852 }
853 this.el.className.baseVal = arr.join(' ');
854 return this;
855 };
856
857 /**
858 * Remove all classes matching `re`.
859 *
860 * @param {RegExp} re
861 * @return {ClassList}
862 * @api private
863 */
864
865 ClassList.prototype.removeMatching = function(re) {
866 var arr = this.array();
867 for (var i = 0; i < arr.length; i++) {
868 if (re.test(arr[i])) {
869 this.remove(arr[i]);
870 }
871 }
872 return this;
873 };
874
875 /**
876 * Toggle class `name`, can force state via `force`.
877 *
878 * For browsers that support classList, but do not support `force` yet,
879 * the mistake will be detected and corrected.
880 *
881 * @param {String} name
882 * @param {Boolean} force
883 * @return {ClassList}
884 * @api public
885 */
886
887 ClassList.prototype.toggle = function(name, force) {
888 // classList
889 if (this.list) {
890 if (defined(force)) {
891 if (force !== this.list.toggle(name, force)) {
892 this.list.toggle(name); // toggle again to correct
893 }
894 } else {
895 this.list.toggle(name);
896 }
897 return this;
898 }
899
900 // fallback
901 if (defined(force)) {
902 if (!force) {
903 this.remove(name);
904 } else {
905 this.add(name);
906 }
907 } else {
908 if (this.has(name)) {
909 this.remove(name);
910 } else {
911 this.add(name);
912 }
913 }
914
915 return this;
916 };
917
918 /**
919 * Return an array of classes.
920 *
921 * @return {Array}
922 * @api public
923 */
924
925 ClassList.prototype.array = function() {
926 var className = this.el.getAttribute('class') || '';
927 var str = className.replace(/^\s+|\s+$/g, '');
928 var arr = str.split(re);
929 if ('' === arr[0]) {
930 arr.shift();
931 }
932 return arr;
933 };
934
935 /**
936 * Check if class `name` is present.
937 *
938 * @param {String} name
939 * @return {ClassList}
940 * @api public
941 */
942
943 ClassList.prototype.has =
944 ClassList.prototype.contains = function(name) {
945 return (
946 this.list ?
947 this.list.contains(name) :
948 !! ~index(this.array(), name)
949 );
950 };
951
952 function remove(element) {
953 var parent = element.parentNode;
954
955 if (parent) {
956 parent.removeChild(element);
957 }
958
959 return element;
960 }
961
962 /**
963 * Clear utility
964 */
965
966 /**
967 * Removes all children from the given element
968 *
969 * @param {DOMElement} element
970 * @return {DOMElement} the element (for chaining)
971 */
972 function clear(element) {
973 var child;
974
975 while ((child = element.firstChild)) {
976 remove(child);
977 }
978
979 return element;
980 }
981
982 var ns = {
983 svg: 'http://www.w3.org/2000/svg'
984 };
985
986 /**
987 * DOM parsing utility
988 */
989
990 var SVG_START = '<svg xmlns="' + ns.svg + '"';
991
992 function parse(svg) {
993
994 var unwrap = false;
995
996 // ensure we import a valid svg document
997 if (svg.substring(0, 4) === '<svg') {
998 if (svg.indexOf(ns.svg) === -1) {
999 svg = SVG_START + svg.substring(4);
1000 }
1001 } else {
1002 // namespace svg
1003 svg = SVG_START + '>' + svg + '</svg>';
1004 unwrap = true;
1005 }
1006
1007 var parsed = parseDocument(svg);
1008
1009 if (!unwrap) {
1010 return parsed;
1011 }
1012
1013 var fragment = document.createDocumentFragment();
1014
1015 var parent = parsed.firstChild;
1016
1017 while (parent.firstChild) {
1018 fragment.appendChild(parent.firstChild);
1019 }
1020
1021 return fragment;
1022 }
1023
1024 function parseDocument(svg) {
1025
1026 var parser;
1027
1028 // parse
1029 parser = new DOMParser();
1030 parser.async = false;
1031
1032 return parser.parseFromString(svg, 'text/xml');
1033 }
1034
1035 /**
1036 * Create utility for SVG elements
1037 */
1038
1039
1040 /**
1041 * Create a specific type from name or SVG markup.
1042 *
1043 * @param {String} name the name or markup of the element
1044 * @param {Object} [attrs] attributes to set on the element
1045 *
1046 * @returns {SVGElement}
1047 */
1048 function create(name, attrs) {
1049 var element;
1050
1051 if (name.charAt(0) === '<') {
1052 element = parse(name).firstChild;
1053 element = document.importNode(element, true);
1054 } else {
1055 element = document.createElementNS(ns.svg, name);
1056 }
1057
1058 if (attrs) {
1059 attr(element, attrs);
1060 }
1061
1062 return element;
1063 }
1064
1065 /**
1066 * Geometry helpers
1067 */
1068
1069 // fake node used to instantiate svg geometry elements
1070 var node = create('svg');
1071
1072 function extend(object, props) {
1073 var i, k, keys = Object.keys(props);
1074
1075 for (i = 0; (k = keys[i]); i++) {
1076 object[k] = props[k];
1077 }
1078
1079 return object;
1080 }
1081
1082 /**
1083 * Create matrix via args.
1084 *
1085 * @example
1086 *
1087 * createMatrix({ a: 1, b: 1 });
1088 * createMatrix();
1089 * createMatrix(1, 2, 0, 0, 30, 20);
1090 *
1091 * @return {SVGMatrix}
1092 */
1093 function createMatrix(a, b, c, d, e, f) {
1094 var matrix = node.createSVGMatrix();
1095
1096 switch (arguments.length) {
1097 case 0:
1098 return matrix;
1099 case 1:
1100 return extend(matrix, a);
1101 case 6:
1102 return extend(matrix, {
1103 a: a,
1104 b: b,
1105 c: c,
1106 d: d,
1107 e: e,
1108 f: f
1109 });
1110 }
1111 }
1112
1113 function createTransform(matrix) {
1114 if (matrix) {
1115 return node.createSVGTransformFromMatrix(matrix);
1116 } else {
1117 return node.createSVGTransform();
1118 }
1119 }
1120
1121 /**
1122 * Serialization util
1123 */
1124
1125 var TEXT_ENTITIES = /([&<>]{1})/g;
1126 var ATTR_ENTITIES = /([\n\r"]{1})/g;
1127
1128 var ENTITY_REPLACEMENT = {
1129 '&': '&amp;',
1130 '<': '&lt;',
1131 '>': '&gt;',
1132 '"': '\''
1133 };
1134
1135 function escape(str, pattern) {
1136
1137 function replaceFn(match, entity) {
1138 return ENTITY_REPLACEMENT[entity] || entity;
1139 }
1140
1141 return str.replace(pattern, replaceFn);
1142 }
1143
1144 function serialize(node, output) {
1145
1146 var i, len, attrMap, attrNode, childNodes;
1147
1148 switch (node.nodeType) {
1149 // TEXT
1150 case 3:
1151 // replace special XML characters
1152 output.push(escape(node.textContent, TEXT_ENTITIES));
1153 break;
1154
1155 // ELEMENT
1156 case 1:
1157 output.push('<', node.tagName);
1158
1159 if (node.hasAttributes()) {
1160 attrMap = node.attributes;
1161 for (i = 0, len = attrMap.length; i < len; ++i) {
1162 attrNode = attrMap.item(i);
1163 output.push(' ', attrNode.name, '="', escape(attrNode.value, ATTR_ENTITIES), '"');
1164 }
1165 }
1166
1167 if (node.hasChildNodes()) {
1168 output.push('>');
1169 childNodes = node.childNodes;
1170 for (i = 0, len = childNodes.length; i < len; ++i) {
1171 serialize(childNodes.item(i), output);
1172 }
1173 output.push('</', node.tagName, '>');
1174 } else {
1175 output.push('/>');
1176 }
1177 break;
1178
1179 // COMMENT
1180 case 8:
1181 output.push('<!--', escape(node.nodeValue, TEXT_ENTITIES), '-->');
1182 break;
1183
1184 // CDATA
1185 case 4:
1186 output.push('<![CDATA[', node.nodeValue, ']]>');
1187 break;
1188
1189 default:
1190 throw new Error('unable to handle node ' + node.nodeType);
1191 }
1192
1193 return output;
1194 }
1195
1196 /**
1197 * innerHTML like functionality for SVG elements.
1198 * based on innerSVG (https://code.google.com/p/innersvg)
1199 */
1200
1201
1202 function set(element, svg) {
1203
1204 var parsed = parse(svg);
1205
1206 // clear element contents
1207 clear(element);
1208
1209 if (!svg) {
1210 return;
1211 }
1212
1213 if (!isFragment(parsed)) {
1214 // extract <svg> from parsed document
1215 parsed = parsed.documentElement;
1216 }
1217
1218 var nodes = slice(parsed.childNodes);
1219
1220 // import + append each node
1221 for (var i = 0; i < nodes.length; i++) {
1222 appendTo(nodes[i], element);
1223 }
1224
1225 }
1226
1227 function get(element) {
1228 var child = element.firstChild,
1229 output = [];
1230
1231 while (child) {
1232 serialize(child, output);
1233 child = child.nextSibling;
1234 }
1235
1236 return output.join('');
1237 }
1238
1239 function isFragment(node) {
1240 return node.nodeName === '#document-fragment';
1241 }
1242
1243 function innerSVG(element, svg) {
1244
1245 if (svg !== undefined) {
1246
1247 try {
1248 set(element, svg);
1249 } catch (e) {
1250 throw new Error('error parsing SVG: ' + e.message);
1251 }
1252
1253 return element;
1254 } else {
1255 return get(element);
1256 }
1257 }
1258
1259
1260 function slice(arr) {
1261 return Array.prototype.slice.call(arr);
1262 }
1263
1264 /**
1265 * transform accessor utility
1266 */
1267
1268 function wrapMatrix(transformList, transform) {
1269 if (transform instanceof SVGMatrix) {
1270 return transformList.createSVGTransformFromMatrix(transform);
1271 }
1272
1273 return transform;
1274 }
1275
1276
1277 function setTransforms(transformList, transforms) {
1278 var i, t;
1279
1280 transformList.clear();
1281
1282 for (i = 0; (t = transforms[i]); i++) {
1283 transformList.appendItem(wrapMatrix(transformList, t));
1284 }
1285 }
1286
1287 /**
1288 * Get or set the transforms on the given node.
1289 *
1290 * @param {SVGElement} node
1291 * @param {SVGTransform|SVGMatrix|Array<SVGTransform|SVGMatrix>} [transforms]
1292 *
1293 * @return {SVGTransform} the consolidated transform
1294 */
1295 function transform(node, transforms) {
1296 var transformList = node.transform.baseVal;
1297
1298 if (transforms) {
1299
1300 if (!Array.isArray(transforms)) {
1301 transforms = [ transforms ];
1302 }
1303
1304 setTransforms(transformList, transforms);
1305 }
1306
1307 return transformList.consolidate();
1308 }
1309
1310 function componentsToPath(elements) {
1311 return elements.join(',').replace(/,?([A-z]),?/g, '$1');
1312 }
1313
1314 function toSVGPoints(points) {
1315 var result = '';
1316
1317 for (var i = 0, p; (p = points[i]); i++) {
1318 result += p.x + ',' + p.y + ' ';
1319 }
1320
1321 return result;
1322 }
1323
1324 function createLine(points, attrs) {
1325
1326 var line = create('polyline');
1327 attr(line, { points: toSVGPoints(points) });
1328
1329 if (attrs) {
1330 attr(line, attrs);
1331 }
1332
1333 return line;
1334 }
1335
1336 function updateLine(gfx, points) {
1337 attr(gfx, { points: toSVGPoints(points) });
1338
1339 return gfx;
1340 }
1341
1342 // element utils //////////////////////
1343
1344 /**
1345 * Checks if eventDefinition of the given element matches with semantic type.
1346 *
1347 * @return {boolean} true if element is of the given semantic type
1348 */
1349 function isTypedEvent(event, eventDefinitionType, filter) {
1350
1351 function matches(definition, filter) {
1352 return every(filter, function(val, key) {
1353
1354 // we want a == conversion here, to be able to catch
1355 // undefined == false and friends
1356 /* jshint -W116 */
1357 return definition[key] == val;
1358 });
1359 }
1360
1361 return some(event.eventDefinitions, function(definition) {
1362 return definition.$type === eventDefinitionType && matches(event, filter);
1363 });
1364 }
1365
1366 function isThrowEvent(event) {
1367 return (event.$type === 'bpmn:IntermediateThrowEvent') || (event.$type === 'bpmn:EndEvent');
1368 }
1369
1370 function isCollection(element) {
1371 var dataObject = element.dataObjectRef;
1372
1373 return element.isCollection || (dataObject && dataObject.isCollection);
1374 }
1375
1376 function getDi(element) {
1377 return element.businessObject.di;
1378 }
1379
1380 function getSemantic(element) {
1381 return element.businessObject;
1382 }
1383
1384
1385 // color access //////////////////////
1386
1387 function getFillColor(element, defaultColor) {
1388 return getDi(element).get('bioc:fill') || defaultColor || 'white';
1389 }
1390
1391 function getStrokeColor(element, defaultColor) {
1392 return getDi(element).get('bioc:stroke') || defaultColor || 'black';
1393 }
1394
1395
1396 // cropping path customizations //////////////////////
1397
1398 function getCirclePath(shape) {
1399
1400 var cx = shape.x + shape.width / 2,
1401 cy = shape.y + shape.height / 2,
1402 radius = shape.width / 2;
1403
1404 var circlePath = [
1405 ['M', cx, cy],
1406 ['m', 0, -radius],
1407 ['a', radius, radius, 0, 1, 1, 0, 2 * radius],
1408 ['a', radius, radius, 0, 1, 1, 0, -2 * radius],
1409 ['z']
1410 ];
1411
1412 return componentsToPath(circlePath);
1413 }
1414
1415 function getRoundRectPath(shape, borderRadius) {
1416
1417 var x = shape.x,
1418 y = shape.y,
1419 width = shape.width,
1420 height = shape.height;
1421
1422 var roundRectPath = [
1423 ['M', x + borderRadius, y],
1424 ['l', width - borderRadius * 2, 0],
1425 ['a', borderRadius, borderRadius, 0, 0, 1, borderRadius, borderRadius],
1426 ['l', 0, height - borderRadius * 2],
1427 ['a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, borderRadius],
1428 ['l', borderRadius * 2 - width, 0],
1429 ['a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, -borderRadius],
1430 ['l', 0, borderRadius * 2 - height],
1431 ['a', borderRadius, borderRadius, 0, 0, 1, borderRadius, -borderRadius],
1432 ['z']
1433 ];
1434
1435 return componentsToPath(roundRectPath);
1436 }
1437
1438 function getDiamondPath(shape) {
1439
1440 var width = shape.width,
1441 height = shape.height,
1442 x = shape.x,
1443 y = shape.y,
1444 halfWidth = width / 2,
1445 halfHeight = height / 2;
1446
1447 var diamondPath = [
1448 ['M', x + halfWidth, y],
1449 ['l', halfWidth, halfHeight],
1450 ['l', -halfWidth, halfHeight],
1451 ['l', -halfWidth, -halfHeight],
1452 ['z']
1453 ];
1454
1455 return componentsToPath(diamondPath);
1456 }
1457
1458 function getRectPath(shape) {
1459 var x = shape.x,
1460 y = shape.y,
1461 width = shape.width,
1462 height = shape.height;
1463
1464 var rectPath = [
1465 ['M', x, y],
1466 ['l', width, 0],
1467 ['l', 0, height],
1468 ['l', -width, 0],
1469 ['z']
1470 ];
1471
1472 return componentsToPath(rectPath);
1473 }
1474
1475 /**
1476 * Set attribute `name` to `val`, or get attr `name`.
1477 *
1478 * @param {Element} el
1479 * @param {String} name
1480 * @param {String} [val]
1481 * @api public
1482 */
1483 function attr$1(el, name, val) {
1484 // get
1485 if (arguments.length == 2) {
1486 return el.getAttribute(name);
1487 }
1488
1489 // remove
1490 if (val === null) {
1491 return el.removeAttribute(name);
1492 }
1493
1494 // set
1495 el.setAttribute(name, val);
1496
1497 return el;
1498 }
1499
1500 var indexOf = [].indexOf;
1501
1502 var indexof = function(arr, obj){
1503 if (indexOf) return arr.indexOf(obj);
1504 for (var i = 0; i < arr.length; ++i) {
1505 if (arr[i] === obj) return i;
1506 }
1507 return -1;
1508 };
1509
1510 /**
1511 * Taken from https://github.com/component/classes
1512 *
1513 * Without the component bits.
1514 */
1515
1516 /**
1517 * Whitespace regexp.
1518 */
1519
1520 var re$1 = /\s+/;
1521
1522 /**
1523 * toString reference.
1524 */
1525
1526 var toString$1 = Object.prototype.toString;
1527
1528 /**
1529 * Wrap `el` in a `ClassList`.
1530 *
1531 * @param {Element} el
1532 * @return {ClassList}
1533 * @api public
1534 */
1535
1536 function classes$1(el) {
1537 return new ClassList$1(el);
1538 }
1539
1540 /**
1541 * Initialize a new ClassList for `el`.
1542 *
1543 * @param {Element} el
1544 * @api private
1545 */
1546
1547 function ClassList$1(el) {
1548 if (!el || !el.nodeType) {
1549 throw new Error('A DOM element reference is required');
1550 }
1551 this.el = el;
1552 this.list = el.classList;
1553 }
1554
1555 /**
1556 * Add class `name` if not already present.
1557 *
1558 * @param {String} name
1559 * @return {ClassList}
1560 * @api public
1561 */
1562
1563 ClassList$1.prototype.add = function (name) {
1564 // classList
1565 if (this.list) {
1566 this.list.add(name);
1567 return this;
1568 }
1569
1570 // fallback
1571 var arr = this.array();
1572 var i = indexof(arr, name);
1573 if (!~i) arr.push(name);
1574 this.el.className = arr.join(' ');
1575 return this;
1576 };
1577
1578 /**
1579 * Remove class `name` when present, or
1580 * pass a regular expression to remove
1581 * any which match.
1582 *
1583 * @param {String|RegExp} name
1584 * @return {ClassList}
1585 * @api public
1586 */
1587
1588 ClassList$1.prototype.remove = function (name) {
1589 if ('[object RegExp]' == toString$1.call(name)) {
1590 return this.removeMatching(name);
1591 }
1592
1593 // classList
1594 if (this.list) {
1595 this.list.remove(name);
1596 return this;
1597 }
1598
1599 // fallback
1600 var arr = this.array();
1601 var i = indexof(arr, name);
1602 if (~i) arr.splice(i, 1);
1603 this.el.className = arr.join(' ');
1604 return this;
1605 };
1606
1607 /**
1608 * Remove all classes matching `re`.
1609 *
1610 * @param {RegExp} re
1611 * @return {ClassList}
1612 * @api private
1613 */
1614
1615 ClassList$1.prototype.removeMatching = function (re) {
1616 var arr = this.array();
1617 for (var i = 0; i < arr.length; i++) {
1618 if (re.test(arr[i])) {
1619 this.remove(arr[i]);
1620 }
1621 }
1622 return this;
1623 };
1624
1625 /**
1626 * Toggle class `name`, can force state via `force`.
1627 *
1628 * For browsers that support classList, but do not support `force` yet,
1629 * the mistake will be detected and corrected.
1630 *
1631 * @param {String} name
1632 * @param {Boolean} force
1633 * @return {ClassList}
1634 * @api public
1635 */
1636
1637 ClassList$1.prototype.toggle = function (name, force) {
1638 // classList
1639 if (this.list) {
1640 if ('undefined' !== typeof force) {
1641 if (force !== this.list.toggle(name, force)) {
1642 this.list.toggle(name); // toggle again to correct
1643 }
1644 } else {
1645 this.list.toggle(name);
1646 }
1647 return this;
1648 }
1649
1650 // fallback
1651 if ('undefined' !== typeof force) {
1652 if (!force) {
1653 this.remove(name);
1654 } else {
1655 this.add(name);
1656 }
1657 } else {
1658 if (this.has(name)) {
1659 this.remove(name);
1660 } else {
1661 this.add(name);
1662 }
1663 }
1664
1665 return this;
1666 };
1667
1668 /**
1669 * Return an array of classes.
1670 *
1671 * @return {Array}
1672 * @api public
1673 */
1674
1675 ClassList$1.prototype.array = function () {
1676 var className = this.el.getAttribute('class') || '';
1677 var str = className.replace(/^\s+|\s+$/g, '');
1678 var arr = str.split(re$1);
1679 if ('' === arr[0]) arr.shift();
1680 return arr;
1681 };
1682
1683 /**
1684 * Check if class `name` is present.
1685 *
1686 * @param {String} name
1687 * @return {ClassList}
1688 * @api public
1689 */
1690
1691 ClassList$1.prototype.has = ClassList$1.prototype.contains = function (name) {
1692 return this.list ? this.list.contains(name) : !!~indexof(this.array(), name);
1693 };
1694
1695 /**
1696 * Remove all children from the given element.
1697 */
1698 function clear$1(el) {
1699
1700 var c;
1701
1702 while (el.childNodes.length) {
1703 c = el.childNodes[0];
1704 el.removeChild(c);
1705 }
1706
1707 return el;
1708 }
1709
1710 var proto = typeof Element !== 'undefined' ? Element.prototype : {};
1711 var vendor = proto.matches
1712 || proto.matchesSelector
1713 || proto.webkitMatchesSelector
1714 || proto.mozMatchesSelector
1715 || proto.msMatchesSelector
1716 || proto.oMatchesSelector;
1717
1718 var matchesSelector = match;
1719
1720 /**
1721 * Match `el` to `selector`.
1722 *
1723 * @param {Element} el
1724 * @param {String} selector
1725 * @return {Boolean}
1726 * @api public
1727 */
1728
1729 function match(el, selector) {
1730 if (!el || el.nodeType !== 1) return false;
1731 if (vendor) return vendor.call(el, selector);
1732 var nodes = el.parentNode.querySelectorAll(selector);
1733 for (var i = 0; i < nodes.length; i++) {
1734 if (nodes[i] == el) return true;
1735 }
1736 return false;
1737 }
1738
1739 /**
1740 * Closest
1741 *
1742 * @param {Element} el
1743 * @param {String} selector
1744 * @param {Boolean} checkYourSelf (optional)
1745 */
1746 function closest (element, selector, checkYourSelf) {
1747 var currentElem = checkYourSelf ? element : element.parentNode;
1748
1749 while (currentElem && currentElem.nodeType !== document.DOCUMENT_NODE && currentElem.nodeType !== document.DOCUMENT_FRAGMENT_NODE) {
1750
1751 if (matchesSelector(currentElem, selector)) {
1752 return currentElem;
1753 }
1754
1755 currentElem = currentElem.parentNode;
1756 }
1757
1758 return matchesSelector(currentElem, selector) ? currentElem : null;
1759 }
1760
1761 /**
1762 * Element prototype.
1763 */
1764
1765 var proto$1 = Element.prototype;
1766
1767 /**
1768 * Vendor function.
1769 */
1770
1771 var vendor$1 = proto$1.matchesSelector
1772 || proto$1.webkitMatchesSelector
1773 || proto$1.mozMatchesSelector
1774 || proto$1.msMatchesSelector
1775 || proto$1.oMatchesSelector;
1776
1777 /**
1778 * Expose `match()`.
1779 */
1780
1781 var matchesSelector$1 = match$1;
1782
1783 /**
1784 * Match `el` to `selector`.
1785 *
1786 * @param {Element} el
1787 * @param {String} selector
1788 * @return {Boolean}
1789 * @api public
1790 */
1791
1792 function match$1(el, selector) {
1793 if (vendor$1) return vendor$1.call(el, selector);
1794 var nodes = el.parentNode.querySelectorAll(selector);
1795 for (var i = 0; i < nodes.length; ++i) {
1796 if (nodes[i] == el) return true;
1797 }
1798 return false;
1799 }
1800
1801 var closest$1 = function (element, selector, checkYoSelf) {
1802 var parent = checkYoSelf ? element : element.parentNode;
1803
1804 while (parent && parent !== document) {
1805 if (matchesSelector$1(parent, selector)) return parent;
1806 parent = parent.parentNode;
1807 }
1808 };
1809
1810 var bind$1 = window.addEventListener ? 'addEventListener' : 'attachEvent',
1811 unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
1812 prefix = bind$1 !== 'addEventListener' ? 'on' : '';
1813
1814 /**
1815 * Bind `el` event `type` to `fn`.
1816 *
1817 * @param {Element} el
1818 * @param {String} type
1819 * @param {Function} fn
1820 * @param {Boolean} capture
1821 * @return {Function}
1822 * @api public
1823 */
1824
1825 var bind_1 = function(el, type, fn, capture){
1826 el[bind$1](prefix + type, fn, capture || false);
1827 return fn;
1828 };
1829
1830 /**
1831 * Unbind `el` event `type`'s callback `fn`.
1832 *
1833 * @param {Element} el
1834 * @param {String} type
1835 * @param {Function} fn
1836 * @param {Boolean} capture
1837 * @return {Function}
1838 * @api public
1839 */
1840
1841 var unbind_1 = function(el, type, fn, capture){
1842 el[unbind](prefix + type, fn, capture || false);
1843 return fn;
1844 };
1845
1846 var componentEvent = {
1847 bind: bind_1,
1848 unbind: unbind_1
1849 };
1850
1851 /**
1852 * Module dependencies.
1853 */
1854
1855
1856
1857 /**
1858 * Delegate event `type` to `selector`
1859 * and invoke `fn(e)`. A callback function
1860 * is returned which may be passed to `.unbind()`.
1861 *
1862 * @param {Element} el
1863 * @param {String} selector
1864 * @param {String} type
1865 * @param {Function} fn
1866 * @param {Boolean} capture
1867 * @return {Function}
1868 * @api public
1869 */
1870
1871 // Some events don't bubble, so we want to bind to the capture phase instead
1872 // when delegating.
1873 var forceCaptureEvents = ['focus', 'blur'];
1874
1875 var bind$1$1 = function(el, selector, type, fn, capture){
1876 if (forceCaptureEvents.indexOf(type) !== -1) capture = true;
1877
1878 return componentEvent.bind(el, type, function(e){
1879 var target = e.target || e.srcElement;
1880 e.delegateTarget = closest$1(target, selector, true);
1881 if (e.delegateTarget) fn.call(el, e);
1882 }, capture);
1883 };
1884
1885 /**
1886 * Unbind event `type`'s callback `fn`.
1887 *
1888 * @param {Element} el
1889 * @param {String} type
1890 * @param {Function} fn
1891 * @param {Boolean} capture
1892 * @api public
1893 */
1894
1895 var unbind$1 = function(el, type, fn, capture){
1896 if (forceCaptureEvents.indexOf(type) !== -1) capture = true;
1897
1898 componentEvent.unbind(el, type, fn, capture);
1899 };
1900
1901 var delegateEvents = {
1902 bind: bind$1$1,
1903 unbind: unbind$1
1904 };
1905
1906 /**
1907 * Expose `parse`.
1908 */
1909
1910 var domify = parse$1;
1911
1912 /**
1913 * Tests for browser support.
1914 */
1915
1916 var innerHTMLBug = false;
1917 var bugTestDiv;
1918 if (typeof document !== 'undefined') {
1919 bugTestDiv = document.createElement('div');
1920 // Setup
1921 bugTestDiv.innerHTML = ' <link/><table></table><a href="/a">a</a><input type="checkbox"/>';
1922 // Make sure that link elements get serialized correctly by innerHTML
1923 // This requires a wrapper element in IE
1924 innerHTMLBug = !bugTestDiv.getElementsByTagName('link').length;
1925 bugTestDiv = undefined;
1926 }
1927
1928 /**
1929 * Wrap map from jquery.
1930 */
1931
1932 var map$1 = {
1933 legend: [1, '<fieldset>', '</fieldset>'],
1934 tr: [2, '<table><tbody>', '</tbody></table>'],
1935 col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
1936 // for script/link/style tags to work in IE6-8, you have to wrap
1937 // in a div with a non-whitespace character in front, ha!
1938 _default: innerHTMLBug ? [1, 'X<div>', '</div>'] : [0, '', '']
1939 };
1940
1941 map$1.td =
1942 map$1.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
1943
1944 map$1.option =
1945 map$1.optgroup = [1, '<select multiple="multiple">', '</select>'];
1946
1947 map$1.thead =
1948 map$1.tbody =
1949 map$1.colgroup =
1950 map$1.caption =
1951 map$1.tfoot = [1, '<table>', '</table>'];
1952
1953 map$1.polyline =
1954 map$1.ellipse =
1955 map$1.polygon =
1956 map$1.circle =
1957 map$1.text =
1958 map$1.line =
1959 map$1.path =
1960 map$1.rect =
1961 map$1.g = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>'];
1962
1963 /**
1964 * Parse `html` and return a DOM Node instance, which could be a TextNode,
1965 * HTML DOM Node of some kind (<div> for example), or a DocumentFragment
1966 * instance, depending on the contents of the `html` string.
1967 *
1968 * @param {String} html - HTML string to "domify"
1969 * @param {Document} doc - The `document` instance to create the Node for
1970 * @return {DOMNode} the TextNode, DOM Node, or DocumentFragment instance
1971 * @api private
1972 */
1973
1974 function parse$1(html, doc) {
1975 if ('string' != typeof html) throw new TypeError('String expected');
1976
1977 // default to the global `document` object
1978 if (!doc) doc = document;
1979
1980 // tag name
1981 var m = /<([\w:]+)/.exec(html);
1982 if (!m) return doc.createTextNode(html);
1983
1984 html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace
1985
1986 var tag = m[1];
1987
1988 // body support
1989 if (tag == 'body') {
1990 var el = doc.createElement('html');
1991 el.innerHTML = html;
1992 return el.removeChild(el.lastChild);
1993 }
1994
1995 // wrap map
1996 var wrap = map$1[tag] || map$1._default;
1997 var depth = wrap[0];
1998 var prefix = wrap[1];
1999 var suffix = wrap[2];
2000 var el = doc.createElement('div');
2001 el.innerHTML = prefix + html + suffix;
2002 while (depth--) el = el.lastChild;
2003
2004 // one element
2005 if (el.firstChild == el.lastChild) {
2006 return el.removeChild(el.firstChild);
2007 }
2008
2009 // several elements
2010 var fragment = doc.createDocumentFragment();
2011 while (el.firstChild) {
2012 fragment.appendChild(el.removeChild(el.firstChild));
2013 }
2014
2015 return fragment;
2016 }
2017
2018 function query(selector, el) {
2019 el = el || document;
2020
2021 return el.querySelector(selector);
2022 }
2023
2024 function all(selector, el) {
2025 el = el || document;
2026
2027 return el.querySelectorAll(selector);
2028 }
2029
2030 function remove$1(el) {
2031 el.parentNode && el.parentNode.removeChild(el);
2032 }
2033
2034 /**
2035 * @param {<SVGElement>} element
2036 * @param {number} x
2037 * @param {number} y
2038 * @param {number} angle
2039 * @param {number} amount
2040 */
2041 function transform$1(gfx, x, y, angle, amount) {
2042 var translate = createTransform();
2043 translate.setTranslate(x, y);
2044
2045 var rotate = createTransform();
2046 rotate.setRotate(angle || 0, 0, 0);
2047
2048 var scale = createTransform();
2049 scale.setScale(amount || 1, amount || 1);
2050
2051 transform(gfx, [ translate, rotate, scale ]);
2052 }
2053
2054
2055 /**
2056 * @param {SVGElement} element
2057 * @param {number} x
2058 * @param {number} y
2059 */
2060 function translate(gfx, x, y) {
2061 var translate = createTransform();
2062 translate.setTranslate(x, y);
2063
2064 transform(gfx, translate);
2065 }
2066
2067
2068 /**
2069 * @param {SVGElement} element
2070 * @param {number} angle
2071 */
2072 function rotate(gfx, angle) {
2073 var rotate = createTransform();
2074 rotate.setRotate(angle, 0, 0);
2075
2076 transform(gfx, rotate);
2077 }
2078
2079 function createCommonjsModule$1(fn, module) {
2080 return module = { exports: {} }, fn(module, module.exports), module.exports;
2081 }
2082
2083 var hat_1 = createCommonjsModule$1(function (module) {
2084 var hat = module.exports = function (bits, base) {
2085 if (!base) base = 16;
2086 if (bits === undefined) bits = 128;
2087 if (bits <= 0) return '0';
2088
2089 var digits = Math.log(Math.pow(2, bits)) / Math.log(base);
2090 for (var i = 2; digits === Infinity; i *= 2) {
2091 digits = Math.log(Math.pow(2, bits / i)) / Math.log(base) * i;
2092 }
2093
2094 var rem = digits - Math.floor(digits);
2095
2096 var res = '';
2097
2098 for (var i = 0; i < Math.floor(digits); i++) {
2099 var x = Math.floor(Math.random() * base).toString(base);
2100 res = x + res;
2101 }
2102
2103 if (rem) {
2104 var b = Math.pow(base, rem);
2105 var x = Math.floor(Math.random() * b).toString(base);
2106 res = x + res;
2107 }
2108
2109 var parsed = parseInt(res, base);
2110 if (parsed !== Infinity && parsed >= Math.pow(2, bits)) {
2111 return hat(bits, base)
2112 }
2113 else return res;
2114 };
2115
2116 hat.rack = function (bits, base, expandBy) {
2117 var fn = function (data) {
2118 var iters = 0;
2119 do {
2120 if (iters ++ > 10) {
2121 if (expandBy) bits += expandBy;
2122 else throw new Error('too many ID collisions, use more bits')
2123 }
2124
2125 var id = hat(bits, base);
2126 } while (Object.hasOwnProperty.call(hats, id));
2127
2128 hats[id] = data;
2129 return id;
2130 };
2131 var hats = fn.hats = {};
2132
2133 fn.get = function (id) {
2134 return fn.hats[id];
2135 };
2136
2137 fn.set = function (id, value) {
2138 fn.hats[id] = value;
2139 return fn;
2140 };
2141
2142 fn.bits = bits || 128;
2143 fn.base = base || 16;
2144 return fn;
2145 };
2146 });
2147
2148 /**
2149 * Create a new id generator / cache instance.
2150 *
2151 * You may optionally provide a seed that is used internally.
2152 *
2153 * @param {Seed} seed
2154 */
2155
2156 function Ids(seed) {
2157 if (!(this instanceof Ids)) {
2158 return new Ids(seed);
2159 }
2160
2161 seed = seed || [128, 36, 1];
2162 this._seed = seed.length ? hat_1.rack(seed[0], seed[1], seed[2]) : seed;
2163 }
2164 /**
2165 * Generate a next id.
2166 *
2167 * @param {Object} [element] element to bind the id to
2168 *
2169 * @return {String} id
2170 */
2171
2172 Ids.prototype.next = function (element) {
2173 return this._seed(element || true);
2174 };
2175 /**
2176 * Generate a next id with a given prefix.
2177 *
2178 * @param {Object} [element] element to bind the id to
2179 *
2180 * @return {String} id
2181 */
2182
2183
2184 Ids.prototype.nextPrefixed = function (prefix, element) {
2185 var id;
2186
2187 do {
2188 id = prefix + this.next(true);
2189 } while (this.assigned(id)); // claim {prefix}{random}
2190
2191
2192 this.claim(id, element); // return
2193
2194 return id;
2195 };
2196 /**
2197 * Manually claim an existing id.
2198 *
2199 * @param {String} id
2200 * @param {String} [element] element the id is claimed by
2201 */
2202
2203
2204 Ids.prototype.claim = function (id, element) {
2205 this._seed.set(id, element || true);
2206 };
2207 /**
2208 * Returns true if the given id has already been assigned.
2209 *
2210 * @param {String} id
2211 * @return {Boolean}
2212 */
2213
2214
2215 Ids.prototype.assigned = function (id) {
2216 return this._seed.get(id) || false;
2217 };
2218 /**
2219 * Unclaim an id.
2220 *
2221 * @param {String} id the id to unclaim
2222 */
2223
2224
2225 Ids.prototype.unclaim = function (id) {
2226 delete this._seed.hats[id];
2227 };
2228 /**
2229 * Clear all claimed ids.
2230 */
2231
2232
2233 Ids.prototype.clear = function () {
2234 var hats = this._seed.hats,
2235 id;
2236
2237 for (id in hats) {
2238 this.unclaim(id);
2239 }
2240 };
2241
2242 var RENDERER_IDS = new Ids();
2243
2244 var TASK_BORDER_RADIUS = 10;
2245 var INNER_OUTER_DIST = 3;
2246
2247 var DEFAULT_FILL_OPACITY = .95,
2248 HIGH_FILL_OPACITY = .35;
2249
2250
2251 function BpmnRenderer(
2252 config, eventBus, styles, pathMap,
2253 canvas, textRenderer, priority) {
2254
2255 BaseRenderer.call(this, eventBus, priority);
2256
2257 var defaultFillColor = config && config.defaultFillColor,
2258 defaultStrokeColor = config && config.defaultStrokeColor;
2259
2260 var rendererId = RENDERER_IDS.next();
2261
2262 var markers = {};
2263
2264 var computeStyle = styles.computeStyle;
2265
2266 function addMarker(id, options) {
2267 var attrs = assign({
2268 fill: 'black',
2269 strokeWidth: 1,
2270 strokeLinecap: 'round',
2271 strokeDasharray: 'none'
2272 }, options.attrs);
2273
2274 var ref = options.ref || { x: 0, y: 0 };
2275
2276 var scale = options.scale || 1;
2277
2278 // fix for safari / chrome / firefox bug not correctly
2279 // resetting stroke dash array
2280 if (attrs.strokeDasharray === 'none') {
2281 attrs.strokeDasharray = [10000, 1];
2282 }
2283
2284 var marker = create('marker');
2285
2286 attr(options.element, attrs);
2287
2288 append(marker, options.element);
2289
2290 attr(marker, {
2291 id: id,
2292 viewBox: '0 0 20 20',
2293 refX: ref.x,
2294 refY: ref.y,
2295 markerWidth: 20 * scale,
2296 markerHeight: 20 * scale,
2297 orient: 'auto'
2298 });
2299
2300 var defs = query('defs', canvas._svg);
2301
2302 if (!defs) {
2303 defs = create('defs');
2304
2305 append(canvas._svg, defs);
2306 }
2307
2308 append(defs, marker);
2309
2310 markers[id] = marker;
2311 }
2312
2313 function colorEscape(str) {
2314
2315 // only allow characters and numbers
2316 return str.replace(/[^0-9a-zA-z]+/g, '_');
2317 }
2318
2319 function marker(type, fill, stroke) {
2320 var id = type + '-' + colorEscape(fill) + '-' + colorEscape(stroke) + '-' + rendererId;
2321
2322 if (!markers[id]) {
2323 createMarker(id, type, fill, stroke);
2324 }
2325
2326 return 'url(#' + id + ')';
2327 }
2328
2329 function createMarker(id, type, fill, stroke) {
2330
2331 if (type === 'sequenceflow-end') {
2332 var sequenceflowEnd = create('path');
2333 attr(sequenceflowEnd, { d: 'M 1 5 L 11 10 L 1 15 Z' });
2334
2335 addMarker(id, {
2336 element: sequenceflowEnd,
2337 ref: { x: 11, y: 10 },
2338 scale: 0.5,
2339 attrs: {
2340 fill: stroke,
2341 stroke: stroke
2342 }
2343 });
2344 }
2345
2346 if (type === 'messageflow-start') {
2347 var messageflowStart = create('circle');
2348 attr(messageflowStart, { cx: 6, cy: 6, r: 3.5 });
2349
2350 addMarker(id, {
2351 element: messageflowStart,
2352 attrs: {
2353 fill: fill,
2354 stroke: stroke
2355 },
2356 ref: { x: 6, y: 6 }
2357 });
2358 }
2359
2360 if (type === 'messageflow-end') {
2361 var messageflowEnd = create('path');
2362 attr(messageflowEnd, { d: 'm 1 5 l 0 -3 l 7 3 l -7 3 z' });
2363
2364 addMarker(id, {
2365 element: messageflowEnd,
2366 attrs: {
2367 fill: fill,
2368 stroke: stroke,
2369 strokeLinecap: 'butt'
2370 },
2371 ref: { x: 8.5, y: 5 }
2372 });
2373 }
2374
2375 if (type === 'association-start') {
2376 var associationStart = create('path');
2377 attr(associationStart, { d: 'M 11 5 L 1 10 L 11 15' });
2378
2379 addMarker(id, {
2380 element: associationStart,
2381 attrs: {
2382 fill: 'none',
2383 stroke: stroke,
2384 strokeWidth: 1.5
2385 },
2386 ref: { x: 1, y: 10 },
2387 scale: 0.5
2388 });
2389 }
2390
2391 if (type === 'association-end') {
2392 var associationEnd = create('path');
2393 attr(associationEnd, { d: 'M 1 5 L 11 10 L 1 15' });
2394
2395 addMarker(id, {
2396 element: associationEnd,
2397 attrs: {
2398 fill: 'none',
2399 stroke: stroke,
2400 strokeWidth: 1.5
2401 },
2402 ref: { x: 12, y: 10 },
2403 scale: 0.5
2404 });
2405 }
2406
2407 if (type === 'conditional-flow-marker') {
2408 var conditionalflowMarker = create('path');
2409 attr(conditionalflowMarker, { d: 'M 0 10 L 8 6 L 16 10 L 8 14 Z' });
2410
2411 addMarker(id, {
2412 element: conditionalflowMarker,
2413 attrs: {
2414 fill: fill,
2415 stroke: stroke
2416 },
2417 ref: { x: -1, y: 10 },
2418 scale: 0.5
2419 });
2420 }
2421
2422 if (type === 'conditional-default-flow-marker') {
2423 var conditionaldefaultflowMarker = create('path');
2424 attr(conditionaldefaultflowMarker, { d: 'M 6 4 L 10 16' });
2425
2426 addMarker(id, {
2427 element: conditionaldefaultflowMarker,
2428 attrs: {
2429 stroke: stroke
2430 },
2431 ref: { x: 0, y: 10 },
2432 scale: 0.5
2433 });
2434 }
2435 }
2436
2437 function drawCircle(parentGfx, width, height, offset, attrs) {
2438
2439 if (isObject(offset)) {
2440 attrs = offset;
2441 offset = 0;
2442 }
2443
2444 offset = offset || 0;
2445
2446 attrs = computeStyle(attrs, {
2447 stroke: 'black',
2448 strokeWidth: 2,
2449 fill: 'white'
2450 });
2451
2452 if (attrs.fill === 'none') {
2453 delete attrs.fillOpacity;
2454 }
2455
2456 var cx = width / 2,
2457 cy = height / 2;
2458
2459 var circle = create('circle');
2460 attr(circle, {
2461 cx: cx,
2462 cy: cy,
2463 r: Math.round((width + height) / 4 - offset)
2464 });
2465 attr(circle, attrs);
2466
2467 append(parentGfx, circle);
2468
2469 return circle;
2470 }
2471
2472 function drawRect(parentGfx, width, height, r, offset, attrs) {
2473
2474 if (isObject(offset)) {
2475 attrs = offset;
2476 offset = 0;
2477 }
2478
2479 offset = offset || 0;
2480
2481 attrs = computeStyle(attrs, {
2482 stroke: 'black',
2483 strokeWidth: 2,
2484 fill: 'white'
2485 });
2486
2487 var rect = create('rect');
2488 attr(rect, {
2489 x: offset,
2490 y: offset,
2491 width: width - offset * 2,
2492 height: height - offset * 2,
2493 rx: r,
2494 ry: r
2495 });
2496 attr(rect, attrs);
2497
2498 append(parentGfx, rect);
2499
2500 return rect;
2501 }
2502
2503 function drawDiamond(parentGfx, width, height, attrs) {
2504
2505 var x_2 = width / 2;
2506 var y_2 = height / 2;
2507
2508 var points = [{ x: x_2, y: 0 }, { x: width, y: y_2 }, { x: x_2, y: height }, { x: 0, y: y_2 }];
2509
2510 var pointsString = points.map(function(point) {
2511 return point.x + ',' + point.y;
2512 }).join(' ');
2513
2514 attrs = computeStyle(attrs, {
2515 stroke: 'black',
2516 strokeWidth: 2,
2517 fill: 'white'
2518 });
2519
2520 var polygon = create('polygon');
2521 attr(polygon, {
2522 points: pointsString
2523 });
2524 attr(polygon, attrs);
2525
2526 append(parentGfx, polygon);
2527
2528 return polygon;
2529 }
2530
2531 function drawLine(parentGfx, waypoints, attrs) {
2532 attrs = computeStyle(attrs, [ 'no-fill' ], {
2533 stroke: 'black',
2534 strokeWidth: 2,
2535 fill: 'none'
2536 });
2537
2538 var line = createLine(waypoints, attrs);
2539
2540 append(parentGfx, line);
2541
2542 return line;
2543 }
2544
2545 function drawPath(parentGfx, d, attrs) {
2546
2547 attrs = computeStyle(attrs, [ 'no-fill' ], {
2548 strokeWidth: 2,
2549 stroke: 'black'
2550 });
2551
2552 var path = create('path');
2553 attr(path, { d: d });
2554 attr(path, attrs);
2555
2556 append(parentGfx, path);
2557
2558 return path;
2559 }
2560
2561 function drawMarker(type, parentGfx, path, attrs) {
2562 return drawPath(parentGfx, path, assign({ 'data-marker': type }, attrs));
2563 }
2564
2565 function as(type) {
2566 return function(parentGfx, element) {
2567 return handlers[type](parentGfx, element);
2568 };
2569 }
2570
2571 function renderer(type) {
2572 return handlers[type];
2573 }
2574
2575 function renderEventContent(element, parentGfx) {
2576
2577 var event = getSemantic(element);
2578 var isThrowing = isThrowEvent(event);
2579
2580 if (event.eventDefinitions && event.eventDefinitions.length>1) {
2581 if (event.parallelMultiple) {
2582 return renderer('bpmn:ParallelMultipleEventDefinition')(parentGfx, element, isThrowing);
2583 }
2584 else {
2585 return renderer('bpmn:MultipleEventDefinition')(parentGfx, element, isThrowing);
2586 }
2587 }
2588
2589 if (isTypedEvent(event, 'bpmn:MessageEventDefinition')) {
2590 return renderer('bpmn:MessageEventDefinition')(parentGfx, element, isThrowing);
2591 }
2592
2593 if (isTypedEvent(event, 'bpmn:TimerEventDefinition')) {
2594 return renderer('bpmn:TimerEventDefinition')(parentGfx, element, isThrowing);
2595 }
2596
2597 if (isTypedEvent(event, 'bpmn:ConditionalEventDefinition')) {
2598 return renderer('bpmn:ConditionalEventDefinition')(parentGfx, element);
2599 }
2600
2601 if (isTypedEvent(event, 'bpmn:SignalEventDefinition')) {
2602 return renderer('bpmn:SignalEventDefinition')(parentGfx, element, isThrowing);
2603 }
2604
2605 if (isTypedEvent(event, 'bpmn:EscalationEventDefinition')) {
2606 return renderer('bpmn:EscalationEventDefinition')(parentGfx, element, isThrowing);
2607 }
2608
2609 if (isTypedEvent(event, 'bpmn:LinkEventDefinition')) {
2610 return renderer('bpmn:LinkEventDefinition')(parentGfx, element, isThrowing);
2611 }
2612
2613 if (isTypedEvent(event, 'bpmn:ErrorEventDefinition')) {
2614 return renderer('bpmn:ErrorEventDefinition')(parentGfx, element, isThrowing);
2615 }
2616
2617 if (isTypedEvent(event, 'bpmn:CancelEventDefinition')) {
2618 return renderer('bpmn:CancelEventDefinition')(parentGfx, element, isThrowing);
2619 }
2620
2621 if (isTypedEvent(event, 'bpmn:CompensateEventDefinition')) {
2622 return renderer('bpmn:CompensateEventDefinition')(parentGfx, element, isThrowing);
2623 }
2624
2625 if (isTypedEvent(event, 'bpmn:TerminateEventDefinition')) {
2626 return renderer('bpmn:TerminateEventDefinition')(parentGfx, element, isThrowing);
2627 }
2628
2629 return null;
2630 }
2631
2632 function renderLabel(parentGfx, label, options) {
2633
2634 options = assign({
2635 size: {
2636 width: 100
2637 }
2638 }, options);
2639
2640 var text = textRenderer.createText(label || '', options);
2641
2642 classes(text).add('djs-label');
2643
2644 append(parentGfx, text);
2645
2646 return text;
2647 }
2648
2649 function renderEmbeddedLabel(parentGfx, element, align) {
2650 var semantic = getSemantic(element);
2651
2652 return renderLabel(parentGfx, semantic.name, {
2653 box: element,
2654 align: align,
2655 padding: 5,
2656 style: {
2657 fill: getStrokeColor(element, defaultStrokeColor)
2658 }
2659 });
2660 }
2661
2662 function renderExternalLabel(parentGfx, element) {
2663
2664 var box = {
2665 width: 90,
2666 height: 30,
2667 x: element.width / 2 + element.x,
2668 y: element.height / 2 + element.y
2669 };
2670
2671 return renderLabel(parentGfx, getLabel(element), {
2672 box: box,
2673 fitBox: true,
2674 style: assign(
2675 {},
2676 textRenderer.getExternalStyle(),
2677 {
2678 fill: getStrokeColor(element, defaultStrokeColor)
2679 }
2680 )
2681 });
2682 }
2683
2684 function renderLaneLabel(parentGfx, text, element) {
2685 var textBox = renderLabel(parentGfx, text, {
2686 box: {
2687 height: 30,
2688 width: element.height
2689 },
2690 align: 'center-middle',
2691 style: {
2692 fill: getStrokeColor(element, defaultStrokeColor)
2693 }
2694 });
2695
2696 var top = -1 * element.height;
2697
2698 transform$1(textBox, 0, -top, 270);
2699 }
2700
2701 function createPathFromConnection(connection) {
2702 var waypoints = connection.waypoints;
2703
2704 var pathData = 'm ' + waypoints[0].x + ',' + waypoints[0].y;
2705 for (var i = 1; i < waypoints.length; i++) {
2706 pathData += 'L' + waypoints[i].x + ',' + waypoints[i].y + ' ';
2707 }
2708 return pathData;
2709 }
2710
2711 var handlers = this.handlers = {
2712 'bpmn:Event': function(parentGfx, element, attrs) {
2713
2714 if (!('fillOpacity' in attrs)) {
2715 attrs.fillOpacity = DEFAULT_FILL_OPACITY;
2716 }
2717
2718 return drawCircle(parentGfx, element.width, element.height, attrs);
2719 },
2720 'bpmn:StartEvent': function(parentGfx, element) {
2721 var attrs = {
2722 fill: getFillColor(element, defaultFillColor),
2723 stroke: getStrokeColor(element, defaultStrokeColor)
2724 };
2725
2726 var semantic = getSemantic(element);
2727
2728 if (!semantic.isInterrupting) {
2729 attrs = {
2730 strokeDasharray: '6',
2731 strokeLinecap: 'round',
2732 fill: getFillColor(element, defaultFillColor),
2733 stroke: getStrokeColor(element, defaultStrokeColor)
2734 };
2735 }
2736
2737 var circle = renderer('bpmn:Event')(parentGfx, element, attrs);
2738
2739 renderEventContent(element, parentGfx);
2740
2741 return circle;
2742 },
2743 'bpmn:MessageEventDefinition': function(parentGfx, element, isThrowing) {
2744 var pathData = pathMap.getScaledPath('EVENT_MESSAGE', {
2745 xScaleFactor: 0.9,
2746 yScaleFactor: 0.9,
2747 containerWidth: element.width,
2748 containerHeight: element.height,
2749 position: {
2750 mx: 0.235,
2751 my: 0.315
2752 }
2753 });
2754
2755 var fill = isThrowing ? getStrokeColor(element, defaultStrokeColor) : getFillColor(element, defaultFillColor);
2756 var stroke = isThrowing ? getFillColor(element, defaultFillColor) : getStrokeColor(element, defaultStrokeColor);
2757
2758 var messagePath = drawPath(parentGfx, pathData, {
2759 strokeWidth: 1,
2760 fill: fill,
2761 stroke: stroke
2762 });
2763
2764 return messagePath;
2765 },
2766 'bpmn:TimerEventDefinition': function(parentGfx, element) {
2767 var circle = drawCircle(parentGfx, element.width, element.height, 0.2 * element.height, {
2768 strokeWidth: 2,
2769 fill: getFillColor(element, defaultFillColor),
2770 stroke: getStrokeColor(element, defaultStrokeColor)
2771 });
2772
2773 var pathData = pathMap.getScaledPath('EVENT_TIMER_WH', {
2774 xScaleFactor: 0.75,
2775 yScaleFactor: 0.75,
2776 containerWidth: element.width,
2777 containerHeight: element.height,
2778 position: {
2779 mx: 0.5,
2780 my: 0.5
2781 }
2782 });
2783
2784 drawPath(parentGfx, pathData, {
2785 strokeWidth: 2,
2786 strokeLinecap: 'square',
2787 stroke: getStrokeColor(element, defaultStrokeColor)
2788 });
2789
2790 for (var i = 0;i < 12; i++) {
2791
2792 var linePathData = pathMap.getScaledPath('EVENT_TIMER_LINE', {
2793 xScaleFactor: 0.75,
2794 yScaleFactor: 0.75,
2795 containerWidth: element.width,
2796 containerHeight: element.height,
2797 position: {
2798 mx: 0.5,
2799 my: 0.5
2800 }
2801 });
2802
2803 var width = element.width / 2;
2804 var height = element.height / 2;
2805
2806 drawPath(parentGfx, linePathData, {
2807 strokeWidth: 1,
2808 strokeLinecap: 'square',
2809 transform: 'rotate(' + (i * 30) + ',' + height + ',' + width + ')',
2810 stroke: getStrokeColor(element, defaultStrokeColor)
2811 });
2812 }
2813
2814 return circle;
2815 },
2816 'bpmn:EscalationEventDefinition': function(parentGfx, event, isThrowing) {
2817 var pathData = pathMap.getScaledPath('EVENT_ESCALATION', {
2818 xScaleFactor: 1,
2819 yScaleFactor: 1,
2820 containerWidth: event.width,
2821 containerHeight: event.height,
2822 position: {
2823 mx: 0.5,
2824 my: 0.2
2825 }
2826 });
2827
2828 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2829
2830 return drawPath(parentGfx, pathData, {
2831 strokeWidth: 1,
2832 fill: fill,
2833 stroke: getStrokeColor(event, defaultStrokeColor)
2834 });
2835 },
2836 'bpmn:ConditionalEventDefinition': function(parentGfx, event) {
2837 var pathData = pathMap.getScaledPath('EVENT_CONDITIONAL', {
2838 xScaleFactor: 1,
2839 yScaleFactor: 1,
2840 containerWidth: event.width,
2841 containerHeight: event.height,
2842 position: {
2843 mx: 0.5,
2844 my: 0.222
2845 }
2846 });
2847
2848 return drawPath(parentGfx, pathData, {
2849 strokeWidth: 1,
2850 stroke: getStrokeColor(event, defaultStrokeColor)
2851 });
2852 },
2853 'bpmn:LinkEventDefinition': function(parentGfx, event, isThrowing) {
2854 var pathData = pathMap.getScaledPath('EVENT_LINK', {
2855 xScaleFactor: 1,
2856 yScaleFactor: 1,
2857 containerWidth: event.width,
2858 containerHeight: event.height,
2859 position: {
2860 mx: 0.57,
2861 my: 0.263
2862 }
2863 });
2864
2865 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2866
2867 return drawPath(parentGfx, pathData, {
2868 strokeWidth: 1,
2869 fill: fill,
2870 stroke: getStrokeColor(event, defaultStrokeColor)
2871 });
2872 },
2873 'bpmn:ErrorEventDefinition': function(parentGfx, event, isThrowing) {
2874 var pathData = pathMap.getScaledPath('EVENT_ERROR', {
2875 xScaleFactor: 1.1,
2876 yScaleFactor: 1.1,
2877 containerWidth: event.width,
2878 containerHeight: event.height,
2879 position: {
2880 mx: 0.2,
2881 my: 0.722
2882 }
2883 });
2884
2885 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2886
2887 return drawPath(parentGfx, pathData, {
2888 strokeWidth: 1,
2889 fill: fill,
2890 stroke: getStrokeColor(event, defaultStrokeColor)
2891 });
2892 },
2893 'bpmn:CancelEventDefinition': function(parentGfx, event, isThrowing) {
2894 var pathData = pathMap.getScaledPath('EVENT_CANCEL_45', {
2895 xScaleFactor: 1.0,
2896 yScaleFactor: 1.0,
2897 containerWidth: event.width,
2898 containerHeight: event.height,
2899 position: {
2900 mx: 0.638,
2901 my: -0.055
2902 }
2903 });
2904
2905 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2906
2907 var path = drawPath(parentGfx, pathData, {
2908 strokeWidth: 1,
2909 fill: fill,
2910 stroke: getStrokeColor(event, defaultStrokeColor)
2911 });
2912
2913 rotate(path, 45);
2914
2915 return path;
2916 },
2917 'bpmn:CompensateEventDefinition': function(parentGfx, event, isThrowing) {
2918 var pathData = pathMap.getScaledPath('EVENT_COMPENSATION', {
2919 xScaleFactor: 1,
2920 yScaleFactor: 1,
2921 containerWidth: event.width,
2922 containerHeight: event.height,
2923 position: {
2924 mx: 0.22,
2925 my: 0.5
2926 }
2927 });
2928
2929 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2930
2931 return drawPath(parentGfx, pathData, {
2932 strokeWidth: 1,
2933 fill: fill,
2934 stroke: getStrokeColor(event, defaultStrokeColor)
2935 });
2936 },
2937 'bpmn:SignalEventDefinition': function(parentGfx, event, isThrowing) {
2938 var pathData = pathMap.getScaledPath('EVENT_SIGNAL', {
2939 xScaleFactor: 0.9,
2940 yScaleFactor: 0.9,
2941 containerWidth: event.width,
2942 containerHeight: event.height,
2943 position: {
2944 mx: 0.5,
2945 my: 0.2
2946 }
2947 });
2948
2949 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2950
2951 return drawPath(parentGfx, pathData, {
2952 strokeWidth: 1,
2953 fill: fill,
2954 stroke: getStrokeColor(event, defaultStrokeColor)
2955 });
2956 },
2957 'bpmn:MultipleEventDefinition': function(parentGfx, event, isThrowing) {
2958 var pathData = pathMap.getScaledPath('EVENT_MULTIPLE', {
2959 xScaleFactor: 1.1,
2960 yScaleFactor: 1.1,
2961 containerWidth: event.width,
2962 containerHeight: event.height,
2963 position: {
2964 mx: 0.222,
2965 my: 0.36
2966 }
2967 });
2968
2969 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2970
2971 return drawPath(parentGfx, pathData, {
2972 strokeWidth: 1,
2973 fill: fill
2974 });
2975 },
2976 'bpmn:ParallelMultipleEventDefinition': function(parentGfx, event) {
2977 var pathData = pathMap.getScaledPath('EVENT_PARALLEL_MULTIPLE', {
2978 xScaleFactor: 1.2,
2979 yScaleFactor: 1.2,
2980 containerWidth: event.width,
2981 containerHeight: event.height,
2982 position: {
2983 mx: 0.458,
2984 my: 0.194
2985 }
2986 });
2987
2988 return drawPath(parentGfx, pathData, {
2989 strokeWidth: 1,
2990 fill: getStrokeColor(event, defaultStrokeColor),
2991 stroke: getStrokeColor(event, defaultStrokeColor)
2992 });
2993 },
2994 'bpmn:EndEvent': function(parentGfx, element) {
2995 var circle = renderer('bpmn:Event')(parentGfx, element, {
2996 strokeWidth: 4,
2997 fill: getFillColor(element, defaultFillColor),
2998 stroke: getStrokeColor(element, defaultStrokeColor)
2999 });
3000
3001 renderEventContent(element, parentGfx);
3002
3003 return circle;
3004 },
3005 'bpmn:TerminateEventDefinition': function(parentGfx, element) {
3006 var circle = drawCircle(parentGfx, element.width, element.height, 8, {
3007 strokeWidth: 4,
3008 fill: getStrokeColor(element, defaultStrokeColor),
3009 stroke: getStrokeColor(element, defaultStrokeColor)
3010 });
3011
3012 return circle;
3013 },
3014 'bpmn:IntermediateEvent': function(parentGfx, element) {
3015 var outer = renderer('bpmn:Event')(parentGfx, element, {
3016 strokeWidth: 1,
3017 fill: getFillColor(element, defaultFillColor),
3018 stroke: getStrokeColor(element, defaultStrokeColor)
3019 });
3020
3021 /* inner */
3022 drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, {
3023 strokeWidth: 1,
3024 fill: getFillColor(element, 'none'),
3025 stroke: getStrokeColor(element, defaultStrokeColor)
3026 });
3027
3028 renderEventContent(element, parentGfx);
3029
3030 return outer;
3031 },
3032 'bpmn:IntermediateCatchEvent': as('bpmn:IntermediateEvent'),
3033 'bpmn:IntermediateThrowEvent': as('bpmn:IntermediateEvent'),
3034
3035 'bpmn:Activity': function(parentGfx, element, attrs) {
3036
3037 attrs = attrs || {};
3038
3039 if (!('fillOpacity' in attrs)) {
3040 attrs.fillOpacity = DEFAULT_FILL_OPACITY;
3041 }
3042
3043 return drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, attrs);
3044 },
3045
3046 'bpmn:Task': function(parentGfx, element) {
3047 var attrs = {
3048 fill: getFillColor(element, defaultFillColor),
3049 stroke: getStrokeColor(element, defaultStrokeColor)
3050 };
3051
3052 var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
3053
3054 renderEmbeddedLabel(parentGfx, element, 'center-middle');
3055 attachTaskMarkers(parentGfx, element);
3056
3057 return rect;
3058 },
3059 'bpmn:ServiceTask': function(parentGfx, element) {
3060 var task = renderer('bpmn:Task')(parentGfx, element);
3061
3062 var pathDataBG = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
3063 abspos: {
3064 x: 12,
3065 y: 18
3066 }
3067 });
3068
3069 /* service bg */ drawPath(parentGfx, pathDataBG, {
3070 strokeWidth: 1,
3071 fill: getFillColor(element, defaultFillColor),
3072 stroke: getStrokeColor(element, defaultStrokeColor)
3073 });
3074
3075 var fillPathData = pathMap.getScaledPath('TASK_TYPE_SERVICE_FILL', {
3076 abspos: {
3077 x: 17.2,
3078 y: 18
3079 }
3080 });
3081
3082 /* service fill */ drawPath(parentGfx, fillPathData, {
3083 strokeWidth: 0,
3084 fill: getFillColor(element, defaultFillColor)
3085 });
3086
3087 var pathData = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
3088 abspos: {
3089 x: 17,
3090 y: 22
3091 }
3092 });
3093
3094 /* service */ drawPath(parentGfx, pathData, {
3095 strokeWidth: 1,
3096 fill: getFillColor(element, defaultFillColor),
3097 stroke: getStrokeColor(element, defaultStrokeColor)
3098 });
3099
3100 return task;
3101 },
3102 'bpmn:UserTask': function(parentGfx, element) {
3103 var task = renderer('bpmn:Task')(parentGfx, element);
3104
3105 var x = 15;
3106 var y = 12;
3107
3108 var pathData = pathMap.getScaledPath('TASK_TYPE_USER_1', {
3109 abspos: {
3110 x: x,
3111 y: y
3112 }
3113 });
3114
3115 /* user path */ drawPath(parentGfx, pathData, {
3116 strokeWidth: 0.5,
3117 fill: getFillColor(element, defaultFillColor),
3118 stroke: getStrokeColor(element, defaultStrokeColor)
3119 });
3120
3121 var pathData2 = pathMap.getScaledPath('TASK_TYPE_USER_2', {
3122 abspos: {
3123 x: x,
3124 y: y
3125 }
3126 });
3127
3128 /* user2 path */ drawPath(parentGfx, pathData2, {
3129 strokeWidth: 0.5,
3130 fill: getFillColor(element, defaultFillColor),
3131 stroke: getStrokeColor(element, defaultStrokeColor)
3132 });
3133
3134 var pathData3 = pathMap.getScaledPath('TASK_TYPE_USER_3', {
3135 abspos: {
3136 x: x,
3137 y: y
3138 }
3139 });
3140
3141 /* user3 path */ drawPath(parentGfx, pathData3, {
3142 strokeWidth: 0.5,
3143 fill: getStrokeColor(element, defaultStrokeColor),
3144 stroke: getStrokeColor(element, defaultStrokeColor)
3145 });
3146
3147 return task;
3148 },
3149 'bpmn:ManualTask': function(parentGfx, element) {
3150 var task = renderer('bpmn:Task')(parentGfx, element);
3151
3152 var pathData = pathMap.getScaledPath('TASK_TYPE_MANUAL', {
3153 abspos: {
3154 x: 17,
3155 y: 15
3156 }
3157 });
3158
3159 /* manual path */ drawPath(parentGfx, pathData, {
3160 strokeWidth: 0.5, // 0.25,
3161 fill: getFillColor(element, defaultFillColor),
3162 stroke: getStrokeColor(element, defaultStrokeColor)
3163 });
3164
3165 return task;
3166 },
3167 'bpmn:SendTask': function(parentGfx, element) {
3168 var task = renderer('bpmn:Task')(parentGfx, element);
3169
3170 var pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
3171 xScaleFactor: 1,
3172 yScaleFactor: 1,
3173 containerWidth: 21,
3174 containerHeight: 14,
3175 position: {
3176 mx: 0.285,
3177 my: 0.357
3178 }
3179 });
3180
3181 /* send path */ drawPath(parentGfx, pathData, {
3182 strokeWidth: 1,
3183 fill: getStrokeColor(element, defaultStrokeColor),
3184 stroke: getFillColor(element, defaultFillColor)
3185 });
3186
3187 return task;
3188 },
3189 'bpmn:ReceiveTask' : function(parentGfx, element) {
3190 var semantic = getSemantic(element);
3191
3192 var task = renderer('bpmn:Task')(parentGfx, element);
3193 var pathData;
3194
3195 if (semantic.instantiate) {
3196 drawCircle(parentGfx, 28, 28, 20 * 0.22, { strokeWidth: 1 });
3197
3198 pathData = pathMap.getScaledPath('TASK_TYPE_INSTANTIATING_SEND', {
3199 abspos: {
3200 x: 7.77,
3201 y: 9.52
3202 }
3203 });
3204 } else {
3205
3206 pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
3207 xScaleFactor: 0.9,
3208 yScaleFactor: 0.9,
3209 containerWidth: 21,
3210 containerHeight: 14,
3211 position: {
3212 mx: 0.3,
3213 my: 0.4
3214 }
3215 });
3216 }
3217
3218 /* receive path */ drawPath(parentGfx, pathData, {
3219 strokeWidth: 1,
3220 fill: getFillColor(element, defaultFillColor),
3221 stroke: getStrokeColor(element, defaultStrokeColor)
3222 });
3223
3224 return task;
3225 },
3226 'bpmn:ScriptTask': function(parentGfx, element) {
3227 var task = renderer('bpmn:Task')(parentGfx, element);
3228
3229 var pathData = pathMap.getScaledPath('TASK_TYPE_SCRIPT', {
3230 abspos: {
3231 x: 15,
3232 y: 20
3233 }
3234 });
3235
3236 /* script path */ drawPath(parentGfx, pathData, {
3237 strokeWidth: 1,
3238 stroke: getStrokeColor(element, defaultStrokeColor)
3239 });
3240
3241 return task;
3242 },
3243 'bpmn:BusinessRuleTask': function(parentGfx, element) {
3244 var task = renderer('bpmn:Task')(parentGfx, element);
3245
3246 var headerPathData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_HEADER', {
3247 abspos: {
3248 x: 8,
3249 y: 8
3250 }
3251 });
3252
3253 var businessHeaderPath = drawPath(parentGfx, headerPathData);
3254 attr(businessHeaderPath, {
3255 strokeWidth: 1,
3256 fill: getFillColor(element, '#aaaaaa'),
3257 stroke: getStrokeColor(element, defaultStrokeColor)
3258 });
3259
3260 var headerData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_MAIN', {
3261 abspos: {
3262 x: 8,
3263 y: 8
3264 }
3265 });
3266
3267 var businessPath = drawPath(parentGfx, headerData);
3268 attr(businessPath, {
3269 strokeWidth: 1,
3270 stroke: getStrokeColor(element, defaultStrokeColor)
3271 });
3272
3273 return task;
3274 },
3275 'bpmn:SubProcess': function(parentGfx, element, attrs) {
3276 attrs = assign({
3277 fill: getFillColor(element, defaultFillColor),
3278 stroke: getStrokeColor(element, defaultStrokeColor)
3279 }, attrs);
3280
3281 var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
3282
3283 var expanded = isExpanded(element);
3284
3285 if (isEventSubProcess(element)) {
3286 attr(rect, {
3287 strokeDasharray: '1,2'
3288 });
3289 }
3290
3291 renderEmbeddedLabel(parentGfx, element, expanded ? 'center-top' : 'center-middle');
3292
3293 if (expanded) {
3294 attachTaskMarkers(parentGfx, element);
3295 } else {
3296 attachTaskMarkers(parentGfx, element, ['SubProcessMarker']);
3297 }
3298
3299 return rect;
3300 },
3301 'bpmn:AdHocSubProcess': function(parentGfx, element) {
3302 return renderer('bpmn:SubProcess')(parentGfx, element);
3303 },
3304 'bpmn:Transaction': function(parentGfx, element) {
3305 var outer = renderer('bpmn:SubProcess')(parentGfx, element);
3306
3307 var innerAttrs = styles.style([ 'no-fill', 'no-events' ], {
3308 stroke: getStrokeColor(element, defaultStrokeColor)
3309 });
3310
3311 /* inner path */ drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS - 2, INNER_OUTER_DIST, innerAttrs);
3312
3313 return outer;
3314 },
3315 'bpmn:CallActivity': function(parentGfx, element) {
3316 return renderer('bpmn:SubProcess')(parentGfx, element, {
3317 strokeWidth: 5
3318 });
3319 },
3320 'bpmn:Participant': function(parentGfx, element) {
3321
3322 var attrs = {
3323 fillOpacity: DEFAULT_FILL_OPACITY,
3324 fill: getFillColor(element, defaultFillColor),
3325 stroke: getStrokeColor(element, defaultStrokeColor)
3326 };
3327
3328 var lane = renderer('bpmn:Lane')(parentGfx, element, attrs);
3329
3330 var expandedPool = isExpanded(element);
3331
3332 if (expandedPool) {
3333 drawLine(parentGfx, [
3334 { x: 30, y: 0 },
3335 { x: 30, y: element.height }
3336 ], {
3337 stroke: getStrokeColor(element, defaultStrokeColor)
3338 });
3339 var text = getSemantic(element).name;
3340 renderLaneLabel(parentGfx, text, element);
3341 } else {
3342
3343 // Collapsed pool draw text inline
3344 var text2 = getSemantic(element).name;
3345 renderLabel(parentGfx, text2, {
3346 box: element, align: 'center-middle',
3347 style: {
3348 fill: getStrokeColor(element, defaultStrokeColor)
3349 }
3350 });
3351 }
3352
3353 var participantMultiplicity = !!(getSemantic(element).participantMultiplicity);
3354
3355 if (participantMultiplicity) {
3356 renderer('ParticipantMultiplicityMarker')(parentGfx, element);
3357 }
3358
3359 return lane;
3360 },
3361 'bpmn:Lane': function(parentGfx, element, attrs) {
3362 var rect = drawRect(parentGfx, element.width, element.height, 0, assign({
3363 fill: getFillColor(element, defaultFillColor),
3364 fillOpacity: HIGH_FILL_OPACITY,
3365 stroke: getStrokeColor(element, defaultStrokeColor)
3366 }, attrs));
3367
3368 var semantic = getSemantic(element);
3369
3370 if (semantic.$type === 'bpmn:Lane') {
3371 var text = semantic.name;
3372 renderLaneLabel(parentGfx, text, element);
3373 }
3374
3375 return rect;
3376 },
3377 'bpmn:InclusiveGateway': function(parentGfx, element) {
3378 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3379
3380 /* circle path */
3381 drawCircle(parentGfx, element.width, element.height, element.height * 0.24, {
3382 strokeWidth: 2.5,
3383 fill: getFillColor(element, defaultFillColor),
3384 stroke: getStrokeColor(element, defaultStrokeColor)
3385 });
3386
3387 return diamond;
3388 },
3389 'bpmn:ExclusiveGateway': function(parentGfx, element) {
3390 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3391
3392 var pathData = pathMap.getScaledPath('GATEWAY_EXCLUSIVE', {
3393 xScaleFactor: 0.4,
3394 yScaleFactor: 0.4,
3395 containerWidth: element.width,
3396 containerHeight: element.height,
3397 position: {
3398 mx: 0.32,
3399 my: 0.3
3400 }
3401 });
3402
3403 if ((getDi(element).isMarkerVisible)) {
3404 drawPath(parentGfx, pathData, {
3405 strokeWidth: 1,
3406 fill: getStrokeColor(element, defaultStrokeColor),
3407 stroke: getStrokeColor(element, defaultStrokeColor)
3408 });
3409 }
3410
3411 return diamond;
3412 },
3413 'bpmn:ComplexGateway': function(parentGfx, element) {
3414 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3415
3416 var pathData = pathMap.getScaledPath('GATEWAY_COMPLEX', {
3417 xScaleFactor: 0.5,
3418 yScaleFactor:0.5,
3419 containerWidth: element.width,
3420 containerHeight: element.height,
3421 position: {
3422 mx: 0.46,
3423 my: 0.26
3424 }
3425 });
3426
3427 /* complex path */ drawPath(parentGfx, pathData, {
3428 strokeWidth: 1,
3429 fill: getStrokeColor(element, defaultStrokeColor),
3430 stroke: getStrokeColor(element, defaultStrokeColor)
3431 });
3432
3433 return diamond;
3434 },
3435 'bpmn:ParallelGateway': function(parentGfx, element) {
3436 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3437
3438 var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
3439 xScaleFactor: 0.6,
3440 yScaleFactor:0.6,
3441 containerWidth: element.width,
3442 containerHeight: element.height,
3443 position: {
3444 mx: 0.46,
3445 my: 0.2
3446 }
3447 });
3448
3449 /* parallel path */ drawPath(parentGfx, pathData, {
3450 strokeWidth: 1,
3451 fill: getStrokeColor(element, defaultStrokeColor),
3452 stroke: getStrokeColor(element, defaultStrokeColor)
3453 });
3454
3455 return diamond;
3456 },
3457 'bpmn:EventBasedGateway': function(parentGfx, element) {
3458
3459 var semantic = getSemantic(element);
3460
3461 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3462
3463 /* outer circle path */ drawCircle(parentGfx, element.width, element.height, element.height * 0.20, {
3464 strokeWidth: 1,
3465 fill: 'none',
3466 stroke: getStrokeColor(element, defaultStrokeColor)
3467 });
3468
3469 var type = semantic.eventGatewayType;
3470 var instantiate = !!semantic.instantiate;
3471
3472 function drawEvent() {
3473
3474 var pathData = pathMap.getScaledPath('GATEWAY_EVENT_BASED', {
3475 xScaleFactor: 0.18,
3476 yScaleFactor: 0.18,
3477 containerWidth: element.width,
3478 containerHeight: element.height,
3479 position: {
3480 mx: 0.36,
3481 my: 0.44
3482 }
3483 });
3484
3485 var attrs = {
3486 strokeWidth: 2,
3487 fill: getFillColor(element, 'none'),
3488 stroke: getStrokeColor(element, defaultStrokeColor)
3489 };
3490
3491 /* event path */ drawPath(parentGfx, pathData, attrs);
3492 }
3493
3494 if (type === 'Parallel') {
3495
3496 var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
3497 xScaleFactor: 0.4,
3498 yScaleFactor:0.4,
3499 containerWidth: element.width,
3500 containerHeight: element.height,
3501 position: {
3502 mx: 0.474,
3503 my: 0.296
3504 }
3505 });
3506
3507 var parallelPath = drawPath(parentGfx, pathData);
3508 attr(parallelPath, {
3509 strokeWidth: 1,
3510 fill: 'none'
3511 });
3512 } else if (type === 'Exclusive') {
3513
3514 if (!instantiate) {
3515 var innerCircle = drawCircle(parentGfx, element.width, element.height, element.height * 0.26);
3516 attr(innerCircle, {
3517 strokeWidth: 1,
3518 fill: 'none',
3519 stroke: getStrokeColor(element, defaultStrokeColor)
3520 });
3521 }
3522
3523 drawEvent();
3524 }
3525
3526
3527 return diamond;
3528 },
3529 'bpmn:Gateway': function(parentGfx, element) {
3530 var attrs = {
3531 fill: getFillColor(element, defaultFillColor),
3532 fillOpacity: DEFAULT_FILL_OPACITY,
3533 stroke: getStrokeColor(element, defaultStrokeColor)
3534 };
3535
3536 return drawDiamond(parentGfx, element.width, element.height, attrs);
3537 },
3538 'bpmn:SequenceFlow': function(parentGfx, element) {
3539 var pathData = createPathFromConnection(element);
3540
3541 var fill = getFillColor(element, defaultFillColor),
3542 stroke = getStrokeColor(element, defaultStrokeColor);
3543
3544 var attrs = {
3545 strokeLinejoin: 'round',
3546 markerEnd: marker('sequenceflow-end', fill, stroke),
3547 stroke: getStrokeColor(element, defaultStrokeColor)
3548 };
3549
3550 var path = drawPath(parentGfx, pathData, attrs);
3551
3552 var sequenceFlow = getSemantic(element);
3553
3554 var source;
3555
3556 if (element.source) {
3557 source = element.source.businessObject;
3558
3559 // conditional flow marker
3560 if (sequenceFlow.conditionExpression && source.$instanceOf('bpmn:Activity')) {
3561 attr(path, {
3562 markerStart: marker('conditional-flow-marker', fill, stroke)
3563 });
3564 }
3565
3566 // default marker
3567 if (source.default && (source.$instanceOf('bpmn:Gateway') || source.$instanceOf('bpmn:Activity')) &&
3568 source.default === sequenceFlow) {
3569 attr(path, {
3570 markerStart: marker('conditional-default-flow-marker', fill, stroke)
3571 });
3572 }
3573 }
3574
3575 return path;
3576 },
3577 'bpmn:Association': function(parentGfx, element, attrs) {
3578
3579 var semantic = getSemantic(element);
3580
3581 var fill = getFillColor(element, defaultFillColor),
3582 stroke = getStrokeColor(element, defaultStrokeColor);
3583
3584 attrs = assign({
3585 strokeDasharray: '0.5, 5',
3586 strokeLinecap: 'round',
3587 strokeLinejoin: 'round',
3588 stroke: getStrokeColor(element, defaultStrokeColor)
3589 }, attrs || {});
3590
3591 if (semantic.associationDirection === 'One' ||
3592 semantic.associationDirection === 'Both') {
3593 attrs.markerEnd = marker('association-end', fill, stroke);
3594 }
3595
3596 if (semantic.associationDirection === 'Both') {
3597 attrs.markerStart = marker('association-start', fill, stroke);
3598 }
3599
3600 return drawLine(parentGfx, element.waypoints, attrs);
3601 },
3602 'bpmn:DataInputAssociation': function(parentGfx, element) {
3603 var fill = getFillColor(element, defaultFillColor),
3604 stroke = getStrokeColor(element, defaultStrokeColor);
3605
3606 return renderer('bpmn:Association')(parentGfx, element, {
3607 markerEnd: marker('association-end', fill, stroke)
3608 });
3609 },
3610 'bpmn:DataOutputAssociation': function(parentGfx, element) {
3611 var fill = getFillColor(element, defaultFillColor),
3612 stroke = getStrokeColor(element, defaultStrokeColor);
3613
3614 return renderer('bpmn:Association')(parentGfx, element, {
3615 markerEnd: marker('association-end', fill, stroke)
3616 });
3617 },
3618 'bpmn:MessageFlow': function(parentGfx, element) {
3619
3620 var semantic = getSemantic(element),
3621 di = getDi(element);
3622
3623 var fill = getFillColor(element, defaultFillColor),
3624 stroke = getStrokeColor(element, defaultStrokeColor);
3625
3626 var pathData = createPathFromConnection(element);
3627
3628 var attrs = {
3629 markerEnd: marker('messageflow-end', fill, stroke),
3630 markerStart: marker('messageflow-start', fill, stroke),
3631 strokeDasharray: '10, 12',
3632 strokeLinecap: 'round',
3633 strokeLinejoin: 'round',
3634 strokeWidth: '1.5px',
3635 stroke: getStrokeColor(element, defaultStrokeColor)
3636 };
3637
3638 var path = drawPath(parentGfx, pathData, attrs);
3639
3640 if (semantic.messageRef) {
3641 var midPoint = path.getPointAtLength(path.getTotalLength() / 2);
3642
3643 var markerPathData = pathMap.getScaledPath('MESSAGE_FLOW_MARKER', {
3644 abspos: {
3645 x: midPoint.x,
3646 y: midPoint.y
3647 }
3648 });
3649
3650 var messageAttrs = { strokeWidth: 1 };
3651
3652 if (di.messageVisibleKind === 'initiating') {
3653 messageAttrs.fill = 'white';
3654 messageAttrs.stroke = 'black';
3655 } else {
3656 messageAttrs.fill = '#888';
3657 messageAttrs.stroke = 'white';
3658 }
3659
3660 drawPath(parentGfx, markerPathData, messageAttrs);
3661 }
3662
3663 return path;
3664 },
3665 'bpmn:DataObject': function(parentGfx, element) {
3666 var pathData = pathMap.getScaledPath('DATA_OBJECT_PATH', {
3667 xScaleFactor: 1,
3668 yScaleFactor: 1,
3669 containerWidth: element.width,
3670 containerHeight: element.height,
3671 position: {
3672 mx: 0.474,
3673 my: 0.296
3674 }
3675 });
3676
3677 var elementObject = drawPath(parentGfx, pathData, {
3678 fill: getFillColor(element, defaultFillColor),
3679 fillOpacity: DEFAULT_FILL_OPACITY,
3680 stroke: getStrokeColor(element, defaultStrokeColor)
3681 });
3682
3683 var semantic = getSemantic(element);
3684
3685 if (isCollection(semantic)) {
3686 renderDataItemCollection(parentGfx, element);
3687 }
3688
3689 return elementObject;
3690 },
3691 'bpmn:DataObjectReference': as('bpmn:DataObject'),
3692 'bpmn:DataInput': function(parentGfx, element) {
3693
3694 var arrowPathData = pathMap.getRawPath('DATA_ARROW');
3695
3696 // page
3697 var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
3698
3699 /* input arrow path */ drawPath(parentGfx, arrowPathData, { strokeWidth: 1 });
3700
3701 return elementObject;
3702 },
3703 'bpmn:DataOutput': function(parentGfx, element) {
3704 var arrowPathData = pathMap.getRawPath('DATA_ARROW');
3705
3706 // page
3707 var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
3708
3709 /* output arrow path */ drawPath(parentGfx, arrowPathData, {
3710 strokeWidth: 1,
3711 fill: 'black'
3712 });
3713
3714 return elementObject;
3715 },
3716 'bpmn:DataStoreReference': function(parentGfx, element) {
3717 var DATA_STORE_PATH = pathMap.getScaledPath('DATA_STORE', {
3718 xScaleFactor: 1,
3719 yScaleFactor: 1,
3720 containerWidth: element.width,
3721 containerHeight: element.height,
3722 position: {
3723 mx: 0,
3724 my: 0.133
3725 }
3726 });
3727
3728 var elementStore = drawPath(parentGfx, DATA_STORE_PATH, {
3729 strokeWidth: 2,
3730 fill: getFillColor(element, defaultFillColor),
3731 fillOpacity: DEFAULT_FILL_OPACITY,
3732 stroke: getStrokeColor(element, defaultStrokeColor)
3733 });
3734
3735 return elementStore;
3736 },
3737 'bpmn:BoundaryEvent': function(parentGfx, element) {
3738
3739 var semantic = getSemantic(element),
3740 cancel = semantic.cancelActivity;
3741
3742 var attrs = {
3743 strokeWidth: 1,
3744 fill: getFillColor(element, defaultFillColor),
3745 stroke: getStrokeColor(element, defaultStrokeColor)
3746 };
3747
3748 if (!cancel) {
3749 attrs.strokeDasharray = '6';
3750 attrs.strokeLinecap = 'round';
3751 }
3752
3753 // apply fillOpacity
3754 var outerAttrs = assign({}, attrs, {
3755 fillOpacity: 1
3756 });
3757
3758 // apply no-fill
3759 var innerAttrs = assign({}, attrs, {
3760 fill: 'none'
3761 });
3762
3763 var outer = renderer('bpmn:Event')(parentGfx, element, outerAttrs);
3764
3765 /* inner path */ drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, innerAttrs);
3766
3767 renderEventContent(element, parentGfx);
3768
3769 return outer;
3770 },
3771 'bpmn:Group': function(parentGfx, element) {
3772
3773 var group = drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, {
3774 stroke: getStrokeColor(element, defaultStrokeColor),
3775 strokeWidth: 1,
3776 strokeDasharray: '8,3,1,3',
3777 fill: 'none',
3778 pointerEvents: 'none'
3779 });
3780
3781 return group;
3782 },
3783 'label': function(parentGfx, element) {
3784 return renderExternalLabel(parentGfx, element);
3785 },
3786 'bpmn:TextAnnotation': function(parentGfx, element) {
3787 var style = {
3788 'fill': 'none',
3789 'stroke': 'none'
3790 };
3791
3792 var textElement = drawRect(parentGfx, element.width, element.height, 0, 0, style);
3793
3794 var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', {
3795 xScaleFactor: 1,
3796 yScaleFactor: 1,
3797 containerWidth: element.width,
3798 containerHeight: element.height,
3799 position: {
3800 mx: 0.0,
3801 my: 0.0
3802 }
3803 });
3804
3805 drawPath(parentGfx, textPathData, {
3806 stroke: getStrokeColor(element, defaultStrokeColor)
3807 });
3808
3809 var text = getSemantic(element).text || '';
3810 renderLabel(parentGfx, text, {
3811 box: element,
3812 align: 'left-top',
3813 padding: 5,
3814 style: {
3815 fill: getStrokeColor(element, defaultStrokeColor)
3816 }
3817 });
3818
3819 return textElement;
3820 },
3821 'ParticipantMultiplicityMarker': function(parentGfx, element) {
3822 var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
3823 xScaleFactor: 1,
3824 yScaleFactor: 1,
3825 containerWidth: element.width,
3826 containerHeight: element.height,
3827 position: {
3828 mx: ((element.width / 2) / element.width),
3829 my: (element.height - 15) / element.height
3830 }
3831 });
3832
3833 drawMarker('participant-multiplicity', parentGfx, markerPath, {
3834 strokeWidth: 1,
3835 fill: getFillColor(element, defaultFillColor),
3836 stroke: getStrokeColor(element, defaultStrokeColor)
3837 });
3838 },
3839 'SubProcessMarker': function(parentGfx, element) {
3840 var markerRect = drawRect(parentGfx, 14, 14, 0, {
3841 strokeWidth: 1,
3842 fill: getFillColor(element, defaultFillColor),
3843 stroke: getStrokeColor(element, defaultStrokeColor)
3844 });
3845
3846 // Process marker is placed in the middle of the box
3847 // therefore fixed values can be used here
3848 translate(markerRect, element.width / 2 - 7.5, element.height - 20);
3849
3850 var markerPath = pathMap.getScaledPath('MARKER_SUB_PROCESS', {
3851 xScaleFactor: 1.5,
3852 yScaleFactor: 1.5,
3853 containerWidth: element.width,
3854 containerHeight: element.height,
3855 position: {
3856 mx: (element.width / 2 - 7.5) / element.width,
3857 my: (element.height - 20) / element.height
3858 }
3859 });
3860
3861 drawMarker('sub-process', parentGfx, markerPath, {
3862 fill: getFillColor(element, defaultFillColor),
3863 stroke: getStrokeColor(element, defaultStrokeColor)
3864 });
3865 },
3866 'ParallelMarker': function(parentGfx, element, position) {
3867 var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
3868 xScaleFactor: 1,
3869 yScaleFactor: 1,
3870 containerWidth: element.width,
3871 containerHeight: element.height,
3872 position: {
3873 mx: ((element.width / 2 + position.parallel) / element.width),
3874 my: (element.height - 20) / element.height
3875 }
3876 });
3877
3878 drawMarker('parallel', parentGfx, markerPath, {
3879 fill: getFillColor(element, defaultFillColor),
3880 stroke: getStrokeColor(element, defaultStrokeColor)
3881 });
3882 },
3883 'SequentialMarker': function(parentGfx, element, position) {
3884 var markerPath = pathMap.getScaledPath('MARKER_SEQUENTIAL', {
3885 xScaleFactor: 1,
3886 yScaleFactor: 1,
3887 containerWidth: element.width,
3888 containerHeight: element.height,
3889 position: {
3890 mx: ((element.width / 2 + position.seq) / element.width),
3891 my: (element.height - 19) / element.height
3892 }
3893 });
3894
3895 drawMarker('sequential', parentGfx, markerPath, {
3896 fill: getFillColor(element, defaultFillColor),
3897 stroke: getStrokeColor(element, defaultStrokeColor)
3898 });
3899 },
3900 'CompensationMarker': function(parentGfx, element, position) {
3901 var markerMath = pathMap.getScaledPath('MARKER_COMPENSATION', {
3902 xScaleFactor: 1,
3903 yScaleFactor: 1,
3904 containerWidth: element.width,
3905 containerHeight: element.height,
3906 position: {
3907 mx: ((element.width / 2 + position.compensation) / element.width),
3908 my: (element.height - 13) / element.height
3909 }
3910 });
3911
3912 drawMarker('compensation', parentGfx, markerMath, {
3913 strokeWidth: 1,
3914 fill: getFillColor(element, defaultFillColor),
3915 stroke: getStrokeColor(element, defaultStrokeColor)
3916 });
3917 },
3918 'LoopMarker': function(parentGfx, element, position) {
3919 var markerPath = pathMap.getScaledPath('MARKER_LOOP', {
3920 xScaleFactor: 1,
3921 yScaleFactor: 1,
3922 containerWidth: element.width,
3923 containerHeight: element.height,
3924 position: {
3925 mx: ((element.width / 2 + position.loop) / element.width),
3926 my: (element.height - 7) / element.height
3927 }
3928 });
3929
3930 drawMarker('loop', parentGfx, markerPath, {
3931 strokeWidth: 1,
3932 fill: getFillColor(element, defaultFillColor),
3933 stroke: getStrokeColor(element, defaultStrokeColor),
3934 strokeLinecap: 'round',
3935 strokeMiterlimit: 0.5
3936 });
3937 },
3938 'AdhocMarker': function(parentGfx, element, position) {
3939 var markerPath = pathMap.getScaledPath('MARKER_ADHOC', {
3940 xScaleFactor: 1,
3941 yScaleFactor: 1,
3942 containerWidth: element.width,
3943 containerHeight: element.height,
3944 position: {
3945 mx: ((element.width / 2 + position.adhoc) / element.width),
3946 my: (element.height - 15) / element.height
3947 }
3948 });
3949
3950 drawMarker('adhoc', parentGfx, markerPath, {
3951 strokeWidth: 1,
3952 fill: getStrokeColor(element, defaultStrokeColor),
3953 stroke: getStrokeColor(element, defaultStrokeColor)
3954 });
3955 }
3956 };
3957
3958 function attachTaskMarkers(parentGfx, element, taskMarkers) {
3959 var obj = getSemantic(element);
3960
3961 var subprocess = taskMarkers && taskMarkers.indexOf('SubProcessMarker') !== -1;
3962 var position;
3963
3964 if (subprocess) {
3965 position = {
3966 seq: -21,
3967 parallel: -22,
3968 compensation: -42,
3969 loop: -18,
3970 adhoc: 10
3971 };
3972 } else {
3973 position = {
3974 seq: -3,
3975 parallel: -6,
3976 compensation: -27,
3977 loop: 0,
3978 adhoc: 10
3979 };
3980 }
3981
3982 forEach(taskMarkers, function(marker) {
3983 renderer(marker)(parentGfx, element, position);
3984 });
3985
3986 if (obj.isForCompensation) {
3987 renderer('CompensationMarker')(parentGfx, element, position);
3988 }
3989
3990 if (obj.$type === 'bpmn:AdHocSubProcess') {
3991 renderer('AdhocMarker')(parentGfx, element, position);
3992 }
3993
3994 var loopCharacteristics = obj.loopCharacteristics,
3995 isSequential = loopCharacteristics && loopCharacteristics.isSequential;
3996
3997 if (loopCharacteristics) {
3998
3999 if (isSequential === undefined) {
4000 renderer('LoopMarker')(parentGfx, element, position);
4001 }
4002
4003 if (isSequential === false) {
4004 renderer('ParallelMarker')(parentGfx, element, position);
4005 }
4006
4007 if (isSequential === true) {
4008 renderer('SequentialMarker')(parentGfx, element, position);
4009 }
4010 }
4011 }
4012
4013 function renderDataItemCollection(parentGfx, element) {
4014
4015 var yPosition = (element.height - 16) / element.height;
4016
4017 var pathData = pathMap.getScaledPath('DATA_OBJECT_COLLECTION_PATH', {
4018 xScaleFactor: 1,
4019 yScaleFactor: 1,
4020 containerWidth: element.width,
4021 containerHeight: element.height,
4022 position: {
4023 mx: 0.451,
4024 my: yPosition
4025 }
4026 });
4027
4028 /* collection path */ drawPath(parentGfx, pathData, {
4029 strokeWidth: 2
4030 });
4031 }
4032
4033
4034 // extension API, use at your own risk
4035 this._drawPath = drawPath;
4036
4037 }
4038
4039
4040 inherits_browser(BpmnRenderer, BaseRenderer);
4041
4042 BpmnRenderer.$inject = [
4043 'config.bpmnRenderer',
4044 'eventBus',
4045 'styles',
4046 'pathMap',
4047 'canvas',
4048 'textRenderer'
4049 ];
4050
4051
4052 BpmnRenderer.prototype.canRender = function(element) {
4053 return is(element, 'bpmn:BaseElement');
4054 };
4055
4056 BpmnRenderer.prototype.drawShape = function(parentGfx, element) {
4057 var type = element.type;
4058 var h = this.handlers[type];
4059
4060 /* jshint -W040 */
4061 return h(parentGfx, element);
4062 };
4063
4064 BpmnRenderer.prototype.drawConnection = function(parentGfx, element) {
4065 var type = element.type;
4066 var h = this.handlers[type];
4067
4068 /* jshint -W040 */
4069 return h(parentGfx, element);
4070 };
4071
4072 BpmnRenderer.prototype.getShapePath = function(element) {
4073
4074 if (is(element, 'bpmn:Event')) {
4075 return getCirclePath(element);
4076 }
4077
4078 if (is(element, 'bpmn:Activity')) {
4079 return getRoundRectPath(element, TASK_BORDER_RADIUS);
4080 }
4081
4082 if (is(element, 'bpmn:Gateway')) {
4083 return getDiamondPath(element);
4084 }
4085
4086 return getRectPath(element);
4087 };
4088
4089 var DEFAULT_BOX_PADDING = 0;
4090
4091 var DEFAULT_LABEL_SIZE = {
4092 width: 150,
4093 height: 50
4094 };
4095
4096
4097 function parseAlign(align) {
4098
4099 var parts = align.split('-');
4100
4101 return {
4102 horizontal: parts[0] || 'center',
4103 vertical: parts[1] || 'top'
4104 };
4105 }
4106
4107 function parsePadding(padding) {
4108
4109 if (isObject(padding)) {
4110 return assign({ top: 0, left: 0, right: 0, bottom: 0 }, padding);
4111 } else {
4112 return {
4113 top: padding,
4114 left: padding,
4115 right: padding,
4116 bottom: padding
4117 };
4118 }
4119 }
4120
4121 function getTextBBox(text, fakeText) {
4122
4123 fakeText.textContent = text;
4124
4125 var textBBox;
4126
4127 try {
4128 var bbox,
4129 emptyLine = text === '';
4130
4131 // add dummy text, when line is empty to
4132 // determine correct height
4133 fakeText.textContent = emptyLine ? 'dummy' : text;
4134
4135 textBBox = fakeText.getBBox();
4136
4137 // take text rendering related horizontal
4138 // padding into account
4139 bbox = {
4140 width: textBBox.width + textBBox.x * 2,
4141 height: textBBox.height
4142 };
4143
4144 if (emptyLine) {
4145
4146 // correct width
4147 bbox.width = 0;
4148 }
4149
4150 return bbox;
4151 } catch (e) {
4152 return { width: 0, height: 0 };
4153 }
4154 }
4155
4156
4157 /**
4158 * Layout the next line and return the layouted element.
4159 *
4160 * Alters the lines passed.
4161 *
4162 * @param {Array<string>} lines
4163 * @return {Object} the line descriptor, an object { width, height, text }
4164 */
4165 function layoutNext(lines, maxWidth, fakeText) {
4166
4167 var originalLine = lines.shift(),
4168 fitLine = originalLine;
4169
4170 var textBBox;
4171
4172 for (;;) {
4173 textBBox = getTextBBox(fitLine, fakeText);
4174
4175 textBBox.width = fitLine ? textBBox.width : 0;
4176
4177 // try to fit
4178 if (fitLine === ' ' || fitLine === '' || textBBox.width < Math.round(maxWidth) || fitLine.length < 2) {
4179 return fit(lines, fitLine, originalLine, textBBox);
4180 }
4181
4182 fitLine = shortenLine(fitLine, textBBox.width, maxWidth);
4183 }
4184 }
4185
4186 function fit(lines, fitLine, originalLine, textBBox) {
4187 if (fitLine.length < originalLine.length) {
4188 var remainder = originalLine.slice(fitLine.length).trim();
4189
4190 lines.unshift(remainder);
4191 }
4192
4193 return {
4194 width: textBBox.width,
4195 height: textBBox.height,
4196 text: fitLine
4197 };
4198 }
4199
4200
4201 /**
4202 * Shortens a line based on spacing and hyphens.
4203 * Returns the shortened result on success.
4204 *
4205 * @param {string} line
4206 * @param {number} maxLength the maximum characters of the string
4207 * @return {string} the shortened string
4208 */
4209 function semanticShorten(line, maxLength) {
4210 var parts = line.split(/(\s|-)/g),
4211 part,
4212 shortenedParts = [],
4213 length = 0;
4214
4215 // try to shorten via spaces + hyphens
4216 if (parts.length > 1) {
4217 while ((part = parts.shift())) {
4218 if (part.length + length < maxLength) {
4219 shortenedParts.push(part);
4220 length += part.length;
4221 } else {
4222
4223 // remove previous part, too if hyphen does not fit anymore
4224 if (part === '-') {
4225 shortenedParts.pop();
4226 }
4227
4228 break;
4229 }
4230 }
4231 }
4232
4233 return shortenedParts.join('');
4234 }
4235
4236
4237 function shortenLine(line, width, maxWidth) {
4238 var length = Math.max(line.length * (maxWidth / width), 1);
4239
4240 // try to shorten semantically (i.e. based on spaces and hyphens)
4241 var shortenedLine = semanticShorten(line, length);
4242
4243 if (!shortenedLine) {
4244
4245 // force shorten by cutting the long word
4246 shortenedLine = line.slice(0, Math.max(Math.round(length - 1), 1));
4247 }
4248
4249 return shortenedLine;
4250 }
4251
4252
4253 function getHelperSvg() {
4254 var helperSvg = document.getElementById('helper-svg');
4255
4256 if (!helperSvg) {
4257 helperSvg = create('svg');
4258
4259 attr(helperSvg, {
4260 id: 'helper-svg',
4261 width: 0,
4262 height: 0,
4263 style: 'visibility: hidden; position: fixed'
4264 });
4265
4266 document.body.appendChild(helperSvg);
4267 }
4268
4269 return helperSvg;
4270 }
4271
4272
4273 /**
4274 * Creates a new label utility
4275 *
4276 * @param {Object} config
4277 * @param {Dimensions} config.size
4278 * @param {number} config.padding
4279 * @param {Object} config.style
4280 * @param {string} config.align
4281 */
4282 function Text(config) {
4283
4284 this._config = assign({}, {
4285 size: DEFAULT_LABEL_SIZE,
4286 padding: DEFAULT_BOX_PADDING,
4287 style: {},
4288 align: 'center-top'
4289 }, config || {});
4290 }
4291
4292 /**
4293 * Returns the layouted text as an SVG element.
4294 *
4295 * @param {string} text
4296 * @param {Object} options
4297 *
4298 * @return {SVGElement}
4299 */
4300 Text.prototype.createText = function(text, options) {
4301 return this.layoutText(text, options).element;
4302 };
4303
4304 /**
4305 * Returns a labels layouted dimensions.
4306 *
4307 * @param {string} text to layout
4308 * @param {Object} options
4309 *
4310 * @return {Dimensions}
4311 */
4312 Text.prototype.getDimensions = function(text, options) {
4313 return this.layoutText(text, options).dimensions;
4314 };
4315
4316 /**
4317 * Creates and returns a label and its bounding box.
4318 *
4319 * @method Text#createText
4320 *
4321 * @param {string} text the text to render on the label
4322 * @param {Object} options
4323 * @param {string} options.align how to align in the bounding box.
4324 * Any of { 'center-middle', 'center-top' },
4325 * defaults to 'center-top'.
4326 * @param {string} options.style style to be applied to the text
4327 * @param {boolean} options.fitBox indicates if box will be recalculated to
4328 * fit text
4329 *
4330 * @return {Object} { element, dimensions }
4331 */
4332 Text.prototype.layoutText = function(text, options) {
4333 var box = assign({}, this._config.size, options.box),
4334 style = assign({}, this._config.style, options.style),
4335 align = parseAlign(options.align || this._config.align),
4336 padding = parsePadding(options.padding !== undefined ? options.padding : this._config.padding),
4337 fitBox = options.fitBox || false;
4338
4339 var lineHeight = getLineHeight(style);
4340
4341 var lines = text.split(/\r?\n/g),
4342 layouted = [];
4343
4344 var maxWidth = box.width - padding.left - padding.right;
4345
4346 // ensure correct rendering by attaching helper text node to invisible SVG
4347 var helperText = create('text');
4348 attr(helperText, { x: 0, y: 0 });
4349 attr(helperText, style);
4350
4351 var helperSvg = getHelperSvg();
4352
4353 append(helperSvg, helperText);
4354
4355 while (lines.length) {
4356 layouted.push(layoutNext(lines, maxWidth, helperText));
4357 }
4358
4359 if (align.vertical === 'middle') {
4360 padding.top = padding.bottom = 0;
4361 }
4362
4363 var totalHeight = reduce(layouted, function(sum, line, idx) {
4364 return sum + (lineHeight || line.height);
4365 }, 0) + padding.top + padding.bottom;
4366
4367 var maxLineWidth = reduce(layouted, function(sum, line, idx) {
4368 return line.width > sum ? line.width : sum;
4369 }, 0);
4370
4371 // the y position of the next line
4372 var y = padding.top;
4373
4374 if (align.vertical === 'middle') {
4375 y += (box.height - totalHeight) / 2;
4376 }
4377
4378 // magic number initial offset
4379 y -= (lineHeight || layouted[0].height) / 4;
4380
4381
4382 var textElement = create('text');
4383
4384 attr(textElement, style);
4385
4386 // layout each line taking into account that parent
4387 // shape might resize to fit text size
4388 forEach(layouted, function(line) {
4389
4390 var x;
4391
4392 y += (lineHeight || line.height);
4393
4394 switch (align.horizontal) {
4395 case 'left':
4396 x = padding.left;
4397 break;
4398
4399 case 'right':
4400 x = ((fitBox ? maxLineWidth : maxWidth)
4401 - padding.right - line.width);
4402 break;
4403
4404 default:
4405
4406 // aka center
4407 x = Math.max((((fitBox ? maxLineWidth : maxWidth)
4408 - line.width) / 2 + padding.left), 0);
4409 }
4410
4411 var tspan = create('tspan');
4412 attr(tspan, { x: x, y: y });
4413
4414 tspan.textContent = line.text;
4415
4416 append(textElement, tspan);
4417 });
4418
4419 remove(helperText);
4420
4421 var dimensions = {
4422 width: maxLineWidth,
4423 height: totalHeight
4424 };
4425
4426 return {
4427 dimensions: dimensions,
4428 element: textElement
4429 };
4430 };
4431
4432
4433 function getLineHeight(style) {
4434 if ('fontSize' in style && 'lineHeight' in style) {
4435 return style.lineHeight * parseInt(style.fontSize, 10);
4436 }
4437 }
4438
4439 var DEFAULT_FONT_SIZE = 12;
4440 var LINE_HEIGHT_RATIO = 1.2;
4441
4442 var MIN_TEXT_ANNOTATION_HEIGHT = 30;
4443
4444
4445 function TextRenderer(config) {
4446
4447 var defaultStyle = assign({
4448 fontFamily: 'Arial, sans-serif',
4449 fontSize: DEFAULT_FONT_SIZE,
4450 fontWeight: 'normal',
4451 lineHeight: LINE_HEIGHT_RATIO
4452 }, config && config.defaultStyle || {});
4453
4454 var fontSize = parseInt(defaultStyle.fontSize, 10) - 1;
4455
4456 var externalStyle = assign({}, defaultStyle, {
4457 fontSize: fontSize
4458 }, config && config.externalStyle || {});
4459
4460 var textUtil = new Text({
4461 style: defaultStyle
4462 });
4463
4464 /**
4465 * Get the new bounds of an externally rendered,
4466 * layouted label.
4467 *
4468 * @param {Bounds} bounds
4469 * @param {string} text
4470 *
4471 * @return {Bounds}
4472 */
4473 this.getExternalLabelBounds = function(bounds, text) {
4474
4475 var layoutedDimensions = textUtil.getDimensions(text, {
4476 box: {
4477 width: 90,
4478 height: 30,
4479 x: bounds.width / 2 + bounds.x,
4480 y: bounds.height / 2 + bounds.y
4481 },
4482 style: externalStyle
4483 });
4484
4485 // resize label shape to fit label text
4486 return {
4487 x: Math.round(bounds.x + bounds.width / 2 - layoutedDimensions.width / 2),
4488 y: Math.round(bounds.y),
4489 width: Math.ceil(layoutedDimensions.width),
4490 height: Math.ceil(layoutedDimensions.height)
4491 };
4492
4493 };
4494
4495 /**
4496 * Get the new bounds of text annotation.
4497 *
4498 * @param {Bounds} bounds
4499 * @param {string} text
4500 *
4501 * @return {Bounds}
4502 */
4503 this.getTextAnnotationBounds = function(bounds, text) {
4504
4505 var layoutedDimensions = textUtil.getDimensions(text, {
4506 box: bounds,
4507 style: defaultStyle,
4508 align: 'left-top',
4509 padding: 5
4510 });
4511
4512 return {
4513 x: bounds.x,
4514 y: bounds.y,
4515 width: bounds.width,
4516 height: Math.max(MIN_TEXT_ANNOTATION_HEIGHT, Math.round(layoutedDimensions.height))
4517 };
4518 };
4519
4520 /**
4521 * Create a layouted text element.
4522 *
4523 * @param {string} text
4524 * @param {Object} [options]
4525 *
4526 * @return {SVGElement} rendered text
4527 */
4528 this.createText = function(text, options) {
4529 return textUtil.createText(text, options || {});
4530 };
4531
4532 /**
4533 * Get default text style.
4534 */
4535 this.getDefaultStyle = function() {
4536 return defaultStyle;
4537 };
4538
4539 /**
4540 * Get the external text style.
4541 */
4542 this.getExternalStyle = function() {
4543 return externalStyle;
4544 };
4545
4546 }
4547
4548 TextRenderer.$inject = [
4549 'config.textRenderer'
4550 ];
4551
4552 /**
4553 * Map containing SVG paths needed by BpmnRenderer.
4554 */
4555
4556 function PathMap() {
4557
4558 /**
4559 * Contains a map of path elements
4560 *
4561 * <h1>Path definition</h1>
4562 * A parameterized path is defined like this:
4563 * <pre>
4564 * 'GATEWAY_PARALLEL': {
4565 * d: 'm {mx},{my} {e.x0},0 0,{e.x1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
4566 '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
4567 * height: 17.5,
4568 * width: 17.5,
4569 * heightElements: [2.5, 7.5],
4570 * widthElements: [2.5, 7.5]
4571 * }
4572 * </pre>
4573 * <p>It's important to specify a correct <b>height and width</b> for the path as the scaling
4574 * is based on the ratio between the specified height and width in this object and the
4575 * height and width that is set as scale target (Note x,y coordinates will be scaled with
4576 * individual ratios).</p>
4577 * <p>The '<b>heightElements</b>' and '<b>widthElements</b>' array must contain the values that will be scaled.
4578 * The scaling is based on the computed ratios.
4579 * Coordinates on the y axis should be in the <b>heightElement</b>'s array, they will be scaled using
4580 * the computed ratio coefficient.
4581 * In the parameterized path the scaled values can be accessed through the 'e' object in {} brackets.
4582 * <ul>
4583 * <li>The values for the y axis can be accessed in the path string using {e.y0}, {e.y1}, ....</li>
4584 * <li>The values for the x axis can be accessed in the path string using {e.x0}, {e.x1}, ....</li>
4585 * </ul>
4586 * The numbers x0, x1 respectively y0, y1, ... map to the corresponding array index.
4587 * </p>
4588 */
4589 this.pathMap = {
4590 'EVENT_MESSAGE': {
4591 d: 'm {mx},{my} l 0,{e.y1} l {e.x1},0 l 0,-{e.y1} z l {e.x0},{e.y0} l {e.x0},-{e.y0}',
4592 height: 36,
4593 width: 36,
4594 heightElements: [6, 14],
4595 widthElements: [10.5, 21]
4596 },
4597 'EVENT_SIGNAL': {
4598 d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x1},0 Z',
4599 height: 36,
4600 width: 36,
4601 heightElements: [18],
4602 widthElements: [10, 20]
4603 },
4604 'EVENT_ESCALATION': {
4605 d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x0},-{e.y1} l -{e.x0},{e.y1} Z',
4606 height: 36,
4607 width: 36,
4608 heightElements: [20, 7],
4609 widthElements: [8]
4610 },
4611 'EVENT_CONDITIONAL': {
4612 d: 'M {e.x0},{e.y0} l {e.x1},0 l 0,{e.y2} l -{e.x1},0 Z ' +
4613 'M {e.x2},{e.y3} l {e.x0},0 ' +
4614 'M {e.x2},{e.y4} l {e.x0},0 ' +
4615 'M {e.x2},{e.y5} l {e.x0},0 ' +
4616 'M {e.x2},{e.y6} l {e.x0},0 ' +
4617 'M {e.x2},{e.y7} l {e.x0},0 ' +
4618 'M {e.x2},{e.y8} l {e.x0},0 ',
4619 height: 36,
4620 width: 36,
4621 heightElements: [8.5, 14.5, 18, 11.5, 14.5, 17.5, 20.5, 23.5, 26.5],
4622 widthElements: [10.5, 14.5, 12.5]
4623 },
4624 'EVENT_LINK': {
4625 d: 'm {mx},{my} 0,{e.y0} -{e.x1},0 0,{e.y1} {e.x1},0 0,{e.y0} {e.x0},-{e.y2} -{e.x0},-{e.y2} z',
4626 height: 36,
4627 width: 36,
4628 heightElements: [4.4375, 6.75, 7.8125],
4629 widthElements: [9.84375, 13.5]
4630 },
4631 'EVENT_ERROR': {
4632 d: 'm {mx},{my} {e.x0},-{e.y0} {e.x1},-{e.y1} {e.x2},{e.y2} {e.x3},-{e.y3} -{e.x4},{e.y4} -{e.x5},-{e.y5} z',
4633 height: 36,
4634 width: 36,
4635 heightElements: [0.023, 8.737, 8.151, 16.564, 10.591, 8.714],
4636 widthElements: [0.085, 6.672, 6.97, 4.273, 5.337, 6.636]
4637 },
4638 'EVENT_CANCEL_45': {
4639 d: 'm {mx},{my} -{e.x1},0 0,{e.x0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
4640 '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
4641 height: 36,
4642 width: 36,
4643 heightElements: [4.75, 8.5],
4644 widthElements: [4.75, 8.5]
4645 },
4646 'EVENT_COMPENSATION': {
4647 d: 'm {mx},{my} {e.x0},-{e.y0} 0,{e.y1} z m {e.x1},-{e.y2} {e.x2},-{e.y3} 0,{e.y1} -{e.x2},-{e.y3} z',
4648 height: 36,
4649 width: 36,
4650 heightElements: [6.5, 13, 0.4, 6.1],
4651 widthElements: [9, 9.3, 8.7]
4652 },
4653 'EVENT_TIMER_WH': {
4654 d: 'M {mx},{my} l {e.x0},-{e.y0} m -{e.x0},{e.y0} l {e.x1},{e.y1} ',
4655 height: 36,
4656 width: 36,
4657 heightElements: [10, 2],
4658 widthElements: [3, 7]
4659 },
4660 'EVENT_TIMER_LINE': {
4661 d: 'M {mx},{my} ' +
4662 'm {e.x0},{e.y0} l -{e.x1},{e.y1} ',
4663 height: 36,
4664 width: 36,
4665 heightElements: [10, 3],
4666 widthElements: [0, 0]
4667 },
4668 'EVENT_MULTIPLE': {
4669 d:'m {mx},{my} {e.x1},-{e.y0} {e.x1},{e.y0} -{e.x0},{e.y1} -{e.x2},0 z',
4670 height: 36,
4671 width: 36,
4672 heightElements: [6.28099, 12.56199],
4673 widthElements: [3.1405, 9.42149, 12.56198]
4674 },
4675 'EVENT_PARALLEL_MULTIPLE': {
4676 d:'m {mx},{my} {e.x0},0 0,{e.y1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
4677 '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
4678 height: 36,
4679 width: 36,
4680 heightElements: [2.56228, 7.68683],
4681 widthElements: [2.56228, 7.68683]
4682 },
4683 'GATEWAY_EXCLUSIVE': {
4684 d:'m {mx},{my} {e.x0},{e.y0} {e.x1},{e.y0} {e.x2},0 {e.x4},{e.y2} ' +
4685 '{e.x4},{e.y1} {e.x2},0 {e.x1},{e.y3} {e.x0},{e.y3} ' +
4686 '{e.x3},0 {e.x5},{e.y1} {e.x5},{e.y2} {e.x3},0 z',
4687 height: 17.5,
4688 width: 17.5,
4689 heightElements: [8.5, 6.5312, -6.5312, -8.5],
4690 widthElements: [6.5, -6.5, 3, -3, 5, -5]
4691 },
4692 'GATEWAY_PARALLEL': {
4693 d:'m {mx},{my} 0,{e.y1} -{e.x1},0 0,{e.y0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
4694 '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
4695 height: 30,
4696 width: 30,
4697 heightElements: [5, 12.5],
4698 widthElements: [5, 12.5]
4699 },
4700 'GATEWAY_EVENT_BASED': {
4701 d:'m {mx},{my} {e.x0},{e.y0} {e.x0},{e.y1} {e.x1},{e.y2} {e.x2},0 z',
4702 height: 11,
4703 width: 11,
4704 heightElements: [-6, 6, 12, -12],
4705 widthElements: [9, -3, -12]
4706 },
4707 'GATEWAY_COMPLEX': {
4708 d:'m {mx},{my} 0,{e.y0} -{e.x0},-{e.y1} -{e.x1},{e.y2} {e.x0},{e.y1} -{e.x2},0 0,{e.y3} ' +
4709 '{e.x2},0 -{e.x0},{e.y1} l {e.x1},{e.y2} {e.x0},-{e.y1} 0,{e.y0} {e.x3},0 0,-{e.y0} {e.x0},{e.y1} ' +
4710 '{e.x1},-{e.y2} -{e.x0},-{e.y1} {e.x2},0 0,-{e.y3} -{e.x2},0 {e.x0},-{e.y1} -{e.x1},-{e.y2} ' +
4711 '-{e.x0},{e.y1} 0,-{e.y0} -{e.x3},0 z',
4712 height: 17.125,
4713 width: 17.125,
4714 heightElements: [4.875, 3.4375, 2.125, 3],
4715 widthElements: [3.4375, 2.125, 4.875, 3]
4716 },
4717 'DATA_OBJECT_PATH': {
4718 d:'m 0,0 {e.x1},0 {e.x0},{e.y0} 0,{e.y1} -{e.x2},0 0,-{e.y2} {e.x1},0 0,{e.y0} {e.x0},0',
4719 height: 61,
4720 width: 51,
4721 heightElements: [10, 50, 60],
4722 widthElements: [10, 40, 50, 60]
4723 },
4724 'DATA_OBJECT_COLLECTION_PATH': {
4725 d:'m {mx}, {my} ' +
4726 'm 0 15 l 0 -15 ' +
4727 'm 4 15 l 0 -15 ' +
4728 'm 4 15 l 0 -15 ',
4729 height: 61,
4730 width: 51,
4731 heightElements: [12],
4732 widthElements: [1, 6, 12, 15]
4733 },
4734 'DATA_ARROW': {
4735 d:'m 5,9 9,0 0,-3 5,5 -5,5 0,-3 -9,0 z',
4736 height: 61,
4737 width: 51,
4738 heightElements: [],
4739 widthElements: []
4740 },
4741 'DATA_STORE': {
4742 d:'m {mx},{my} ' +
4743 'l 0,{e.y2} ' +
4744 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' +
4745 'l 0,-{e.y2} ' +
4746 'c -{e.x0},-{e.y1} -{e.x1},-{e.y1} -{e.x2},0' +
4747 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' +
4748 'm -{e.x2},{e.y0}' +
4749 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0' +
4750 'm -{e.x2},{e.y0}' +
4751 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0',
4752 height: 61,
4753 width: 61,
4754 heightElements: [7, 10, 45],
4755 widthElements: [2, 58, 60]
4756 },
4757 'TEXT_ANNOTATION': {
4758 d: 'm {mx}, {my} m 10,0 l -10,0 l 0,{e.y0} l 10,0',
4759 height: 30,
4760 width: 10,
4761 heightElements: [30],
4762 widthElements: [10]
4763 },
4764 'MARKER_SUB_PROCESS': {
4765 d: 'm{mx},{my} m 7,2 l 0,10 m -5,-5 l 10,0',
4766 height: 10,
4767 width: 10,
4768 heightElements: [],
4769 widthElements: []
4770 },
4771 'MARKER_PARALLEL': {
4772 d: 'm{mx},{my} m 3,2 l 0,10 m 3,-10 l 0,10 m 3,-10 l 0,10',
4773 height: 10,
4774 width: 10,
4775 heightElements: [],
4776 widthElements: []
4777 },
4778 'MARKER_SEQUENTIAL': {
4779 d: 'm{mx},{my} m 0,3 l 10,0 m -10,3 l 10,0 m -10,3 l 10,0',
4780 height: 10,
4781 width: 10,
4782 heightElements: [],
4783 widthElements: []
4784 },
4785 'MARKER_COMPENSATION': {
4786 d: 'm {mx},{my} 7,-5 0,10 z m 7.1,-0.3 6.9,-4.7 0,10 -6.9,-4.7 z',
4787 height: 10,
4788 width: 21,
4789 heightElements: [],
4790 widthElements: []
4791 },
4792 'MARKER_LOOP': {
4793 d: 'm {mx},{my} c 3.526979,0 6.386161,-2.829858 6.386161,-6.320661 0,-3.490806 -2.859182,-6.320661 ' +
4794 '-6.386161,-6.320661 -3.526978,0 -6.38616,2.829855 -6.38616,6.320661 0,1.745402 ' +
4795 '0.714797,3.325567 1.870463,4.469381 0.577834,0.571908 1.265885,1.034728 2.029916,1.35457 ' +
4796 'l -0.718163,-3.909793 m 0.718163,3.909793 -3.885211,0.802902',
4797 height: 13.9,
4798 width: 13.7,
4799 heightElements: [],
4800 widthElements: []
4801 },
4802 'MARKER_ADHOC': {
4803 d: 'm {mx},{my} m 0.84461,2.64411 c 1.05533,-1.23780996 2.64337,-2.07882 4.29653,-1.97997996 2.05163,0.0805 ' +
4804 '3.85579,1.15803 5.76082,1.79107 1.06385,0.34139996 2.24454,0.1438 3.18759,-0.43767 0.61743,-0.33642 ' +
4805 '1.2775,-0.64078 1.7542,-1.17511 0,0.56023 0,1.12046 0,1.6807 -0.98706,0.96237996 -2.29792,1.62393996 ' +
4806 '-3.6918,1.66181996 -1.24459,0.0927 -2.46671,-0.2491 -3.59505,-0.74812 -1.35789,-0.55965 ' +
4807 '-2.75133,-1.33436996 -4.27027,-1.18121996 -1.37741,0.14601 -2.41842,1.13685996 -3.44288,1.96782996 z',
4808 height: 4,
4809 width: 15,
4810 heightElements: [],
4811 widthElements: []
4812 },
4813 'TASK_TYPE_SEND': {
4814 d: 'm {mx},{my} l 0,{e.y1} l {e.x1},0 l 0,-{e.y1} z l {e.x0},{e.y0} l {e.x0},-{e.y0}',
4815 height: 14,
4816 width: 21,
4817 heightElements: [6, 14],
4818 widthElements: [10.5, 21]
4819 },
4820 'TASK_TYPE_SCRIPT': {
4821 d: 'm {mx},{my} c 9.966553,-6.27276 -8.000926,-7.91932 2.968968,-14.938 l -8.802728,0 ' +
4822 'c -10.969894,7.01868 6.997585,8.66524 -2.968967,14.938 z ' +
4823 'm -7,-12 l 5,0 ' +
4824 'm -4.5,3 l 4.5,0 ' +
4825 'm -3,3 l 5,0' +
4826 'm -4,3 l 5,0',
4827 height: 15,
4828 width: 12.6,
4829 heightElements: [6, 14],
4830 widthElements: [10.5, 21]
4831 },
4832 'TASK_TYPE_USER_1': {
4833 d: 'm {mx},{my} c 0.909,-0.845 1.594,-2.049 1.594,-3.385 0,-2.554 -1.805,-4.62199999 ' +
4834 '-4.357,-4.62199999 -2.55199998,0 -4.28799998,2.06799999 -4.28799998,4.62199999 0,1.348 ' +
4835 '0.974,2.562 1.89599998,3.405 -0.52899998,0.187 -5.669,2.097 -5.794,4.7560005 v 6.718 ' +
4836 'h 17 v -6.718 c 0,-2.2980005 -5.5279996,-4.5950005 -6.0509996,-4.7760005 z' +
4837 'm -8,6 l 0,5.5 m 11,0 l 0,-5'
4838 },
4839 'TASK_TYPE_USER_2': {
4840 d: 'm {mx},{my} m 2.162,1.009 c 0,2.4470005 -2.158,4.4310005 -4.821,4.4310005 ' +
4841 '-2.66499998,0 -4.822,-1.981 -4.822,-4.4310005 '
4842 },
4843 'TASK_TYPE_USER_3': {
4844 d: 'm {mx},{my} m -6.9,-3.80 c 0,0 2.25099998,-2.358 4.27399998,-1.177 2.024,1.181 4.221,1.537 ' +
4845 '4.124,0.965 -0.098,-0.57 -0.117,-3.79099999 -4.191,-4.13599999 -3.57499998,0.001 ' +
4846 '-4.20799998,3.36699999 -4.20699998,4.34799999 z'
4847 },
4848 'TASK_TYPE_MANUAL': {
4849 d: 'm {mx},{my} c 0.234,-0.01 5.604,0.008 8.029,0.004 0.808,0 1.271,-0.172 1.417,-0.752 0.227,-0.898 ' +
4850 '-0.334,-1.314 -1.338,-1.316 -2.467,-0.01 -7.886,-0.004 -8.108,-0.004 -0.014,-0.079 0.016,-0.533 0,-0.61 ' +
4851 '0.195,-0.042 8.507,0.006 9.616,0.002 0.877,-0.007 1.35,-0.438 1.353,-1.208 0.003,-0.768 -0.479,-1.09 ' +
4852 '-1.35,-1.091 -2.968,-0.002 -9.619,-0.013 -9.619,-0.013 v -0.591 c 0,0 5.052,-0.016 7.225,-0.016 ' +
4853 '0.888,-0.002 1.354,-0.416 1.351,-1.193 -0.006,-0.761 -0.492,-1.196 -1.361,-1.196 -3.473,-0.005 ' +
4854 '-10.86,-0.003 -11.0829995,-0.003 -0.022,-0.047 -0.045,-0.094 -0.069,-0.139 0.3939995,-0.319 ' +
4855 '2.0409995,-1.626 2.4149995,-2.017 0.469,-0.4870005 0.519,-1.1650005 0.162,-1.6040005 -0.414,-0.511 ' +
4856 '-0.973,-0.5 -1.48,-0.236 -1.4609995,0.764 -6.5999995,3.6430005 -7.7329995,4.2710005 -0.9,0.499 ' +
4857 '-1.516,1.253 -1.882,2.19 -0.37000002,0.95 -0.17,2.01 -0.166,2.979 0.004,0.718 -0.27300002,1.345 ' +
4858 '-0.055,2.063 0.629,2.087 2.425,3.312 4.859,3.318 4.6179995,0.014 9.2379995,-0.139 13.8569995,-0.158 ' +
4859 '0.755,-0.004 1.171,-0.301 1.182,-1.033 0.012,-0.754 -0.423,-0.969 -1.183,-0.973 -1.778,-0.01 ' +
4860 '-5.824,-0.004 -6.04,-0.004 10e-4,-0.084 0.003,-0.586 10e-4,-0.67 z'
4861 },
4862 'TASK_TYPE_INSTANTIATING_SEND': {
4863 d: 'm {mx},{my} l 0,8.4 l 12.6,0 l 0,-8.4 z l 6.3,3.6 l 6.3,-3.6'
4864 },
4865 'TASK_TYPE_SERVICE': {
4866 d: 'm {mx},{my} v -1.71335 c 0.352326,-0.0705 0.703932,-0.17838 1.047628,-0.32133 ' +
4867 '0.344416,-0.14465 0.665822,-0.32133 0.966377,-0.52145 l 1.19431,1.18005 1.567487,-1.57688 ' +
4868 '-1.195028,-1.18014 c 0.403376,-0.61394 0.683079,-1.29908 0.825447,-2.01824 l 1.622133,-0.01 ' +
4869 'v -2.2196 l -1.636514,0.01 c -0.07333,-0.35153 -0.178319,-0.70024 -0.323564,-1.04372 ' +
4870 '-0.145244,-0.34406 -0.321407,-0.6644 -0.522735,-0.96217 l 1.131035,-1.13631 -1.583305,-1.56293 ' +
4871 '-1.129598,1.13589 c -0.614052,-0.40108 -1.302883,-0.68093 -2.022633,-0.82247 l 0.0093,-1.61852 ' +
4872 'h -2.241173 l 0.0042,1.63124 c -0.353763,0.0736 -0.705369,0.17977 -1.049785,0.32371 -0.344415,0.14437 ' +
4873 '-0.665102,0.32092 -0.9635006,0.52046 l -1.1698628,-1.15823 -1.5667691,1.5792 1.1684265,1.15669 ' +
4874 'c -0.4026573,0.61283 -0.68308,1.29797 -0.8247287,2.01713 l -1.6588041,0.003 v 2.22174 ' +
4875 'l 1.6724648,-0.006 c 0.073327,0.35077 0.1797598,0.70243 0.3242851,1.04472 0.1452428,0.34448 ' +
4876 '0.3214064,0.6644 0.5227339,0.96066 l -1.1993431,1.19723 1.5840256,1.56011 1.1964668,-1.19348 ' +
4877 'c 0.6140517,0.40346 1.3028827,0.68232 2.0233517,0.82331 l 7.19e-4,1.69892 h 2.226848 z ' +
4878 'm 0.221462,-3.9957 c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
4879 '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
4880 '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
4881 },
4882 'TASK_TYPE_SERVICE_FILL': {
4883 d: 'm {mx},{my} c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
4884 '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
4885 '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
4886 },
4887 'TASK_TYPE_BUSINESS_RULE_HEADER': {
4888 d: 'm {mx},{my} 0,4 20,0 0,-4 z'
4889 },
4890 'TASK_TYPE_BUSINESS_RULE_MAIN': {
4891 d: 'm {mx},{my} 0,12 20,0 0,-12 z' +
4892 'm 0,8 l 20,0 ' +
4893 'm -13,-4 l 0,8'
4894 },
4895 'MESSAGE_FLOW_MARKER': {
4896 d: 'm {mx},{my} m -10.5 ,-7 l 0,14 l 21,0 l 0,-14 z l 10.5,6 l 10.5,-6'
4897 }
4898 };
4899
4900 this.getRawPath = function getRawPath(pathId) {
4901 return this.pathMap[pathId].d;
4902 };
4903
4904 /**
4905 * Scales the path to the given height and width.
4906 * <h1>Use case</h1>
4907 * <p>Use case is to scale the content of elements (event, gateways) based
4908 * on the element bounding box's size.
4909 * </p>
4910 * <h1>Why not transform</h1>
4911 * <p>Scaling a path with transform() will also scale the stroke and IE does not support
4912 * the option 'non-scaling-stroke' to prevent this.
4913 * Also there are use cases where only some parts of a path should be
4914 * scaled.</p>
4915 *
4916 * @param {string} pathId The ID of the path.
4917 * @param {Object} param <p>
4918 * Example param object scales the path to 60% size of the container (data.width, data.height).
4919 * <pre>
4920 * {
4921 * xScaleFactor: 0.6,
4922 * yScaleFactor:0.6,
4923 * containerWidth: data.width,
4924 * containerHeight: data.height,
4925 * position: {
4926 * mx: 0.46,
4927 * my: 0.2,
4928 * }
4929 * }
4930 * </pre>
4931 * <ul>
4932 * <li>targetpathwidth = xScaleFactor * containerWidth</li>
4933 * <li>targetpathheight = yScaleFactor * containerHeight</li>
4934 * <li>Position is used to set the starting coordinate of the path. M is computed:
4935 * <ul>
4936 * <li>position.x * containerWidth</li>
4937 * <li>position.y * containerHeight</li>
4938 * </ul>
4939 * Center of the container <pre> position: {
4940 * mx: 0.5,
4941 * my: 0.5,
4942 * }</pre>
4943 * Upper left corner of the container
4944 * <pre> position: {
4945 * mx: 0.0,
4946 * my: 0.0,
4947 * }</pre>
4948 * </li>
4949 * </ul>
4950 * </p>
4951 *
4952 */
4953 this.getScaledPath = function getScaledPath(pathId, param) {
4954 var rawPath = this.pathMap[pathId];
4955
4956 // positioning
4957 // compute the start point of the path
4958 var mx, my;
4959
4960 if (param.abspos) {
4961 mx = param.abspos.x;
4962 my = param.abspos.y;
4963 } else {
4964 mx = param.containerWidth * param.position.mx;
4965 my = param.containerHeight * param.position.my;
4966 }
4967
4968 var coordinates = {}; // map for the scaled coordinates
4969 if (param.position) {
4970
4971 // path
4972 var heightRatio = (param.containerHeight / rawPath.height) * param.yScaleFactor;
4973 var widthRatio = (param.containerWidth / rawPath.width) * param.xScaleFactor;
4974
4975
4976 // Apply height ratio
4977 for (var heightIndex = 0; heightIndex < rawPath.heightElements.length; heightIndex++) {
4978 coordinates['y' + heightIndex] = rawPath.heightElements[heightIndex] * heightRatio;
4979 }
4980
4981 // Apply width ratio
4982 for (var widthIndex = 0; widthIndex < rawPath.widthElements.length; widthIndex++) {
4983 coordinates['x' + widthIndex] = rawPath.widthElements[widthIndex] * widthRatio;
4984 }
4985 }
4986
4987 // Apply value to raw path
4988 var path = format(
4989 rawPath.d, {
4990 mx: mx,
4991 my: my,
4992 e: coordinates
4993 }
4994 );
4995 return path;
4996 };
4997 }
4998
4999 // helpers //////////////////////
5000
5001 // copied from https://github.com/adobe-webplatform/Snap.svg/blob/master/src/svg.js
5002 var tokenRegex = /\{([^}]+)\}/g,
5003 objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g; // matches .xxxxx or ["xxxxx"] to run over object properties
5004
5005 function replacer(all, key, obj) {
5006 var res = obj;
5007 key.replace(objNotationRegex, function(all, name, quote, quotedName, isFunc) {
5008 name = name || quotedName;
5009 if (res) {
5010 if (name in res) {
5011 res = res[name];
5012 }
5013 typeof res == 'function' && isFunc && (res = res());
5014 }
5015 });
5016 res = (res == null || res == obj ? all : res) + '';
5017
5018 return res;
5019 }
5020
5021 function format(str, obj) {
5022 return String(str).replace(tokenRegex, function(all, key) {
5023 return replacer(all, key, obj);
5024 });
5025 }
5026
5027 var DrawModule = {
5028 __init__: [ 'bpmnRenderer' ],
5029 bpmnRenderer: [ 'type', BpmnRenderer ],
5030 textRenderer: [ 'type', TextRenderer ],
5031 pathMap: [ 'type', PathMap ]
5032 };
5033
5034 /**
5035 * A simple translation stub to be used for multi-language support
5036 * in diagrams. Can be easily replaced with a more sophisticated
5037 * solution.
5038 *
5039 * @example
5040 *
5041 * // use it inside any diagram component by injecting `translate`.
5042 *
5043 * function MyService(translate) {
5044 * alert(translate('HELLO {you}', { you: 'You!' }));
5045 * }
5046 *
5047 * @param {string} template to interpolate
5048 * @param {Object} [replacements] a map with substitutes
5049 *
5050 * @return {string} the translated string
5051 */
5052 function translate$1(template, replacements) {
5053
5054 replacements = replacements || {};
5055
5056 return template.replace(/{([^}]+)}/g, function(_, key) {
5057 return replacements[key] || '{' + key + '}';
5058 });
5059 }
5060
5061 var TranslateModule = {
5062 translate: [ 'value', translate$1 ]
5063 };
5064
5065 var DEFAULT_LABEL_SIZE$1 = {
5066 width: 90,
5067 height: 20
5068 };
5069
5070 var FLOW_LABEL_INDENT = 15;
5071
5072
5073 /**
5074 * Returns true if the given semantic has an external label
5075 *
5076 * @param {BpmnElement} semantic
5077 * @return {boolean} true if has label
5078 */
5079 function isLabelExternal(semantic) {
5080 return is(semantic, 'bpmn:Event') ||
5081 is(semantic, 'bpmn:Gateway') ||
5082 is(semantic, 'bpmn:DataStoreReference') ||
5083 is(semantic, 'bpmn:DataObjectReference') ||
5084 is(semantic, 'bpmn:DataInput') ||
5085 is(semantic, 'bpmn:DataOutput') ||
5086 is(semantic, 'bpmn:SequenceFlow') ||
5087 is(semantic, 'bpmn:MessageFlow') ||
5088 is(semantic, 'bpmn:Group');
5089 }
5090
5091 /**
5092 * Get the position for sequence flow labels
5093 *
5094 * @param {Array<Point>} waypoints
5095 * @return {Point} the label position
5096 */
5097 function getFlowLabelPosition(waypoints) {
5098
5099 // get the waypoints mid
5100 var mid = waypoints.length / 2 - 1;
5101
5102 var first = waypoints[Math.floor(mid)];
5103 var second = waypoints[Math.ceil(mid + 0.01)];
5104
5105 // get position
5106 var position = getWaypointsMid(waypoints);
5107
5108 // calculate angle
5109 var angle = Math.atan((second.y - first.y) / (second.x - first.x));
5110
5111 var x = position.x,
5112 y = position.y;
5113
5114 if (Math.abs(angle) < Math.PI / 2) {
5115 y -= FLOW_LABEL_INDENT;
5116 } else {
5117 x += FLOW_LABEL_INDENT;
5118 }
5119
5120 return { x: x, y: y };
5121 }
5122
5123
5124 /**
5125 * Get the middle of a number of waypoints
5126 *
5127 * @param {Array<Point>} waypoints
5128 * @return {Point} the mid point
5129 */
5130 function getWaypointsMid(waypoints) {
5131
5132 var mid = waypoints.length / 2 - 1;
5133
5134 var first = waypoints[Math.floor(mid)];
5135 var second = waypoints[Math.ceil(mid + 0.01)];
5136
5137 return {
5138 x: first.x + (second.x - first.x) / 2,
5139 y: first.y + (second.y - first.y) / 2
5140 };
5141 }
5142
5143
5144 function getExternalLabelMid(element) {
5145
5146 if (element.waypoints) {
5147 return getFlowLabelPosition(element.waypoints);
5148 } else if (is(element, 'bpmn:Group')) {
5149 return {
5150 x: element.x + element.width / 2,
5151 y: element.y + DEFAULT_LABEL_SIZE$1.height / 2
5152 };
5153 } else {
5154 return {
5155 x: element.x + element.width / 2,
5156 y: element.y + element.height + DEFAULT_LABEL_SIZE$1.height / 2
5157 };
5158 }
5159 }
5160
5161
5162 /**
5163 * Returns the bounds of an elements label, parsed from the elements DI or
5164 * generated from its bounds.
5165 *
5166 * @param {BpmnElement} semantic
5167 * @param {djs.model.Base} element
5168 */
5169 function getExternalLabelBounds(semantic, element) {
5170
5171 var mid,
5172 size,
5173 bounds,
5174 di = semantic.di,
5175 label = di.label;
5176
5177 if (label && label.bounds) {
5178 bounds = label.bounds;
5179
5180 size = {
5181 width: Math.max(DEFAULT_LABEL_SIZE$1.width, bounds.width),
5182 height: bounds.height
5183 };
5184
5185 mid = {
5186 x: bounds.x + bounds.width / 2,
5187 y: bounds.y + bounds.height / 2
5188 };
5189 } else {
5190
5191 mid = getExternalLabelMid(element);
5192
5193 size = DEFAULT_LABEL_SIZE$1;
5194 }
5195
5196 return assign({
5197 x: mid.x - size.width / 2,
5198 y: mid.y - size.height / 2
5199 }, size);
5200 }
5201
5202 /**
5203 * This file contains source code adapted from Snap.svg (licensed Apache-2.0).
5204 *
5205 * @see https://github.com/adobe-webplatform/Snap.svg/blob/master/src/path.js
5206 */
5207
5208 /* eslint no-fallthrough: "off" */
5209
5210 var math = Math,
5211 PI = math.PI;
5212
5213 function roundPoint(point) {
5214
5215 return {
5216 x: Math.round(point.x),
5217 y: Math.round(point.y)
5218 };
5219 }
5220
5221
5222 /**
5223 * Get the mid of the given bounds or point.
5224 *
5225 * @param {Bounds|Point} bounds
5226 *
5227 * @return {Point}
5228 */
5229 function getMid(bounds) {
5230 return roundPoint({
5231 x: bounds.x + (bounds.width || 0) / 2,
5232 y: bounds.y + (bounds.height || 0) / 2
5233 });
5234 }
5235
5236 function elementToString(e) {
5237 if (!e) {
5238 return '<null>';
5239 }
5240
5241 return '<' + e.$type + (e.id ? ' id="' + e.id : '') + '" />';
5242 }
5243
5244 function elementData(semantic, attrs) {
5245 return assign({
5246 id: semantic.id,
5247 type: semantic.$type,
5248 businessObject: semantic
5249 }, attrs);
5250 }
5251
5252 function getWaypoints(bo, source, target) {
5253
5254 var waypoints = bo.di.waypoint;
5255
5256 if (!waypoints || waypoints.length < 2) {
5257 return [ getMid(source), getMid(target) ];
5258 }
5259
5260 return waypoints.map(function(p) {
5261 return { x: p.x, y: p.y };
5262 });
5263 }
5264
5265 function notYetDrawn(translate, semantic, refSemantic, property) {
5266 return new Error(translate('element {element} referenced by {referenced}#{property} not yet drawn', {
5267 element: elementToString(refSemantic),
5268 referenced: elementToString(semantic),
5269 property: property
5270 }));
5271 }
5272
5273
5274 /**
5275 * An importer that adds bpmn elements to the canvas
5276 *
5277 * @param {EventBus} eventBus
5278 * @param {Canvas} canvas
5279 * @param {ElementFactory} elementFactory
5280 * @param {ElementRegistry} elementRegistry
5281 * @param {Function} translate
5282 * @param {TextRenderer} textRenderer
5283 */
5284 function BpmnImporter(
5285 eventBus, canvas, elementFactory,
5286 elementRegistry, translate, textRenderer) {
5287
5288 this._eventBus = eventBus;
5289 this._canvas = canvas;
5290 this._elementFactory = elementFactory;
5291 this._elementRegistry = elementRegistry;
5292 this._translate = translate;
5293 this._textRenderer = textRenderer;
5294 }
5295
5296 BpmnImporter.$inject = [
5297 'eventBus',
5298 'canvas',
5299 'elementFactory',
5300 'elementRegistry',
5301 'translate',
5302 'textRenderer'
5303 ];
5304
5305
5306 /**
5307 * Add bpmn element (semantic) to the canvas onto the
5308 * specified parent shape.
5309 */
5310 BpmnImporter.prototype.add = function(semantic, parentElement) {
5311
5312 var di = semantic.di,
5313 element,
5314 translate = this._translate,
5315 hidden;
5316
5317 var parentIndex;
5318
5319 // ROOT ELEMENT
5320 // handle the special case that we deal with a
5321 // invisible root element (process or collaboration)
5322 if (is(di, 'bpmndi:BPMNPlane')) {
5323
5324 // add a virtual element (not being drawn)
5325 element = this._elementFactory.createRoot(elementData(semantic));
5326
5327 this._canvas.setRootElement(element);
5328 }
5329
5330 // SHAPE
5331 else if (is(di, 'bpmndi:BPMNShape')) {
5332
5333 var collapsed = !isExpanded(semantic),
5334 isFrame = isFrameElement(semantic);
5335 hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
5336
5337 var bounds = semantic.di.bounds;
5338
5339 element = this._elementFactory.createShape(elementData(semantic, {
5340 collapsed: collapsed,
5341 hidden: hidden,
5342 x: Math.round(bounds.x),
5343 y: Math.round(bounds.y),
5344 width: Math.round(bounds.width),
5345 height: Math.round(bounds.height),
5346 isFrame: isFrame
5347 }));
5348
5349 if (is(semantic, 'bpmn:BoundaryEvent')) {
5350 this._attachBoundary(semantic, element);
5351 }
5352
5353 // insert lanes behind other flow nodes (cf. #727)
5354 if (is(semantic, 'bpmn:Lane')) {
5355 parentIndex = 0;
5356 }
5357
5358 if (is(semantic, 'bpmn:DataStoreReference')) {
5359
5360 // check whether data store is inside our outside of its semantic parent
5361 if (!isPointInsideBBox(parentElement, getMid(bounds))) {
5362 parentElement = this._canvas.getRootElement();
5363 }
5364 }
5365
5366 this._canvas.addShape(element, parentElement, parentIndex);
5367 }
5368
5369 // CONNECTION
5370 else if (is(di, 'bpmndi:BPMNEdge')) {
5371
5372 var source = this._getSource(semantic),
5373 target = this._getTarget(semantic);
5374
5375 hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
5376
5377 element = this._elementFactory.createConnection(elementData(semantic, {
5378 hidden: hidden,
5379 source: source,
5380 target: target,
5381 waypoints: getWaypoints(semantic, source, target)
5382 }));
5383
5384 if (is(semantic, 'bpmn:DataAssociation')) {
5385
5386 // render always on top; this ensures DataAssociations
5387 // are rendered correctly across different "hacks" people
5388 // love to model such as cross participant / sub process
5389 // associations
5390 parentElement = null;
5391 }
5392
5393 // insert sequence flows behind other flow nodes (cf. #727)
5394 if (is(semantic, 'bpmn:SequenceFlow')) {
5395 parentIndex = 0;
5396 }
5397
5398 this._canvas.addConnection(element, parentElement, parentIndex);
5399 } else {
5400 throw new Error(translate('unknown di {di} for element {semantic}', {
5401 di: elementToString(di),
5402 semantic: elementToString(semantic)
5403 }));
5404 }
5405
5406 // (optional) LABEL
5407 if (isLabelExternal(semantic) && getLabel(element)) {
5408 this.addLabel(semantic, element);
5409 }
5410
5411
5412 this._eventBus.fire('bpmnElement.added', { element: element });
5413
5414 return element;
5415 };
5416
5417
5418 /**
5419 * Attach the boundary element to the given host
5420 *
5421 * @param {ModdleElement} boundarySemantic
5422 * @param {djs.model.Base} boundaryElement
5423 */
5424 BpmnImporter.prototype._attachBoundary = function(boundarySemantic, boundaryElement) {
5425 var translate = this._translate;
5426 var hostSemantic = boundarySemantic.attachedToRef;
5427
5428 if (!hostSemantic) {
5429 throw new Error(translate('missing {semantic}#attachedToRef', {
5430 semantic: elementToString(boundarySemantic)
5431 }));
5432 }
5433
5434 var host = this._elementRegistry.get(hostSemantic.id),
5435 attachers = host && host.attachers;
5436
5437 if (!host) {
5438 throw notYetDrawn(translate, boundarySemantic, hostSemantic, 'attachedToRef');
5439 }
5440
5441 // wire element.host <> host.attachers
5442 boundaryElement.host = host;
5443
5444 if (!attachers) {
5445 host.attachers = attachers = [];
5446 }
5447
5448 if (attachers.indexOf(boundaryElement) === -1) {
5449 attachers.push(boundaryElement);
5450 }
5451 };
5452
5453
5454 /**
5455 * add label for an element
5456 */
5457 BpmnImporter.prototype.addLabel = function(semantic, element) {
5458 var bounds,
5459 text,
5460 label;
5461
5462 bounds = getExternalLabelBounds(semantic, element);
5463
5464 text = getLabel(element);
5465
5466 if (text) {
5467
5468 // get corrected bounds from actual layouted text
5469 bounds = this._textRenderer.getExternalLabelBounds(bounds, text);
5470 }
5471
5472 label = this._elementFactory.createLabel(elementData(semantic, {
5473 id: semantic.id + '_label',
5474 labelTarget: element,
5475 type: 'label',
5476 hidden: element.hidden || !getLabel(element),
5477 x: Math.round(bounds.x),
5478 y: Math.round(bounds.y),
5479 width: Math.round(bounds.width),
5480 height: Math.round(bounds.height)
5481 }));
5482
5483 return this._canvas.addShape(label, element.parent);
5484 };
5485
5486 /**
5487 * Return the drawn connection end based on the given side.
5488 *
5489 * @throws {Error} if the end is not yet drawn
5490 */
5491 BpmnImporter.prototype._getEnd = function(semantic, side) {
5492
5493 var element,
5494 refSemantic,
5495 type = semantic.$type,
5496 translate = this._translate;
5497
5498 refSemantic = semantic[side + 'Ref'];
5499
5500 // handle mysterious isMany DataAssociation#sourceRef
5501 if (side === 'source' && type === 'bpmn:DataInputAssociation') {
5502 refSemantic = refSemantic && refSemantic[0];
5503 }
5504
5505 // fix source / target for DataInputAssociation / DataOutputAssociation
5506 if (side === 'source' && type === 'bpmn:DataOutputAssociation' ||
5507 side === 'target' && type === 'bpmn:DataInputAssociation') {
5508
5509 refSemantic = semantic.$parent;
5510 }
5511
5512 element = refSemantic && this._getElement(refSemantic);
5513
5514 if (element) {
5515 return element;
5516 }
5517
5518 if (refSemantic) {
5519 throw notYetDrawn(translate, semantic, refSemantic, side + 'Ref');
5520 } else {
5521 throw new Error(translate('{semantic}#{side} Ref not specified', {
5522 semantic: elementToString(semantic),
5523 side: side
5524 }));
5525 }
5526 };
5527
5528 BpmnImporter.prototype._getSource = function(semantic) {
5529 return this._getEnd(semantic, 'source');
5530 };
5531
5532 BpmnImporter.prototype._getTarget = function(semantic) {
5533 return this._getEnd(semantic, 'target');
5534 };
5535
5536
5537 BpmnImporter.prototype._getElement = function(semantic) {
5538 return this._elementRegistry.get(semantic.id);
5539 };
5540
5541
5542 // helpers ////////////////////
5543
5544 function isPointInsideBBox(bbox, point) {
5545 var x = point.x,
5546 y = point.y;
5547
5548 return x >= bbox.x &&
5549 x <= bbox.x + bbox.width &&
5550 y >= bbox.y &&
5551 y <= bbox.y + bbox.height;
5552 }
5553
5554 function isFrameElement(semantic) {
5555 return is(semantic, 'bpmn:Group');
5556 }
5557
5558 var ImportModule = {
5559 __depends__: [
5560 TranslateModule
5561 ],
5562 bpmnImporter: [ 'type', BpmnImporter ]
5563 };
5564
5565 var CoreModule = {
5566 __depends__: [
5567 DrawModule,
5568 ImportModule
5569 ]
5570 };
5571
5572 function getOriginal(event) {
5573 return event.originalEvent || event.srcEvent;
5574 }
5575
5576
5577 function toPoint(event) {
5578
5579 if (event.pointers && event.pointers.length) {
5580 event = event.pointers[0];
5581 }
5582
5583 if (event.touches && event.touches.length) {
5584 event = event.touches[0];
5585 }
5586
5587 return event ? {
5588 x: event.clientX,
5589 y: event.clientY
5590 } : null;
5591 }
5592
5593 function isMac() {
5594 return (/mac/i).test(navigator.platform);
5595 }
5596
5597 function isPrimaryButton(event) {
5598
5599 // button === 0 -> left áka primary mouse button
5600 return !(getOriginal(event) || event).button;
5601 }
5602
5603 function hasPrimaryModifier(event) {
5604 var originalEvent = getOriginal(event) || event;
5605
5606 if (!isPrimaryButton(event)) {
5607 return false;
5608 }
5609
5610 // Use alt as primary modifier key for mac OS
5611 if (isMac()) {
5612 return originalEvent.metaKey;
5613 } else {
5614 return originalEvent.ctrlKey;
5615 }
5616 }
5617
5618 function allowAll(e) { return true; }
5619
5620 var LOW_PRIORITY = 500;
5621
5622
5623 /**
5624 * A plugin that provides interaction events for diagram elements.
5625 *
5626 * It emits the following events:
5627 *
5628 * * element.click
5629 * * element.contextmenu
5630 * * element.dblclick
5631 * * element.hover
5632 * * element.mousedown
5633 * * element.mousemove
5634 * * element.mouseup
5635 * * element.out
5636 *
5637 * Each event is a tuple { element, gfx, originalEvent }.
5638 *
5639 * Canceling the event via Event#preventDefault()
5640 * prevents the original DOM operation.
5641 *
5642 * @param {EventBus} eventBus
5643 */
5644 function InteractionEvents(eventBus, elementRegistry, styles) {
5645
5646 var self = this;
5647
5648 /**
5649 * Fire an interaction event.
5650 *
5651 * @param {string} type local event name, e.g. element.click.
5652 * @param {DOMEvent} event native event
5653 * @param {djs.model.Base} [element] the diagram element to emit the event on;
5654 * defaults to the event target
5655 */
5656 function fire(type, event, element) {
5657
5658 if (isIgnored(type, event)) {
5659 return;
5660 }
5661
5662 var target, gfx, returnValue;
5663
5664 if (!element) {
5665 target = event.delegateTarget || event.target;
5666
5667 if (target) {
5668 gfx = target;
5669 element = elementRegistry.get(gfx);
5670 }
5671 } else {
5672 gfx = elementRegistry.getGraphics(element);
5673 }
5674
5675 if (!gfx || !element) {
5676 return;
5677 }
5678
5679 returnValue = eventBus.fire(type, {
5680 element: element,
5681 gfx: gfx,
5682 originalEvent: event
5683 });
5684
5685 if (returnValue === false) {
5686 event.stopPropagation();
5687 event.preventDefault();
5688 }
5689 }
5690
5691 // TODO(nikku): document this
5692 var handlers = {};
5693
5694 function mouseHandler(localEventName) {
5695 return handlers[localEventName];
5696 }
5697
5698 function isIgnored(localEventName, event) {
5699
5700 var filter = ignoredFilters[localEventName] || isPrimaryButton;
5701
5702 // only react on left mouse button interactions
5703 // except for interaction events that are enabled
5704 // for secundary mouse button
5705 return !filter(event);
5706 }
5707
5708 var bindings = {
5709 click: 'element.click',
5710 contextmenu: 'element.contextmenu',
5711 dblclick: 'element.dblclick',
5712 mousedown: 'element.mousedown',
5713 mousemove: 'element.mousemove',
5714 mouseover: 'element.hover',
5715 mouseout: 'element.out',
5716 mouseup: 'element.mouseup',
5717 };
5718
5719 var ignoredFilters = {
5720 'element.contextmenu': allowAll
5721 };
5722
5723
5724 // manual event trigger //////////
5725
5726 /**
5727 * Trigger an interaction event (based on a native dom event)
5728 * on the target shape or connection.
5729 *
5730 * @param {string} eventName the name of the triggered DOM event
5731 * @param {MouseEvent} event
5732 * @param {djs.model.Base} targetElement
5733 */
5734 function triggerMouseEvent(eventName, event, targetElement) {
5735
5736 // i.e. element.mousedown...
5737 var localEventName = bindings[eventName];
5738
5739 if (!localEventName) {
5740 throw new Error('unmapped DOM event name <' + eventName + '>');
5741 }
5742
5743 return fire(localEventName, event, targetElement);
5744 }
5745
5746
5747 var ELEMENT_SELECTOR = 'svg, .djs-element';
5748
5749 // event handling ///////
5750
5751 function registerEvent(node, event, localEvent, ignoredFilter) {
5752
5753 var handler = handlers[localEvent] = function(event) {
5754 fire(localEvent, event);
5755 };
5756
5757 if (ignoredFilter) {
5758 ignoredFilters[localEvent] = ignoredFilter;
5759 }
5760
5761 handler.$delegate = delegateEvents.bind(node, ELEMENT_SELECTOR, event, handler);
5762 }
5763
5764 function unregisterEvent(node, event, localEvent) {
5765
5766 var handler = mouseHandler(localEvent);
5767
5768 if (!handler) {
5769 return;
5770 }
5771
5772 delegateEvents.unbind(node, event, handler.$delegate);
5773 }
5774
5775 function registerEvents(svg) {
5776 forEach(bindings, function(val, key) {
5777 registerEvent(svg, key, val);
5778 });
5779 }
5780
5781 function unregisterEvents(svg) {
5782 forEach(bindings, function(val, key) {
5783 unregisterEvent(svg, key, val);
5784 });
5785 }
5786
5787 eventBus.on('canvas.destroy', function(event) {
5788 unregisterEvents(event.svg);
5789 });
5790
5791 eventBus.on('canvas.init', function(event) {
5792 registerEvents(event.svg);
5793 });
5794
5795
5796 // hit box updating ////////////////
5797
5798 eventBus.on([ 'shape.added', 'connection.added' ], function(event) {
5799 var element = event.element,
5800 gfx = event.gfx;
5801
5802 eventBus.fire('interactionEvents.createHit', { element: element, gfx: gfx });
5803 });
5804
5805 // Update djs-hit on change.
5806 // A low priortity is necessary, because djs-hit of labels has to be updated
5807 // after the label bounds have been updated in the renderer.
5808 eventBus.on([
5809 'shape.changed',
5810 'connection.changed'
5811 ], LOW_PRIORITY, function(event) {
5812
5813 var element = event.element,
5814 gfx = event.gfx;
5815
5816 eventBus.fire('interactionEvents.updateHit', { element: element, gfx: gfx });
5817 });
5818
5819 eventBus.on('interactionEvents.createHit', LOW_PRIORITY, function(event) {
5820 var element = event.element,
5821 gfx = event.gfx;
5822
5823 self.createDefaultHit(element, gfx);
5824 });
5825
5826 eventBus.on('interactionEvents.updateHit', function(event) {
5827 var element = event.element,
5828 gfx = event.gfx;
5829
5830 self.updateDefaultHit(element, gfx);
5831 });
5832
5833
5834 // hit styles ////////////
5835
5836 var STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-stroke');
5837
5838 var CLICK_STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-click-stroke');
5839
5840 var ALL_HIT_STYLE = createHitStyle('djs-hit djs-hit-all');
5841
5842 var HIT_TYPES = {
5843 'all': ALL_HIT_STYLE,
5844 'click-stroke': CLICK_STROKE_HIT_STYLE,
5845 'stroke': STROKE_HIT_STYLE
5846 };
5847
5848 function createHitStyle(classNames, attrs) {
5849
5850 attrs = assign({
5851 stroke: 'white',
5852 strokeWidth: 15
5853 }, attrs || {});
5854
5855 return styles.cls(classNames, [ 'no-fill', 'no-border' ], attrs);
5856 }
5857
5858
5859 // style helpers ///////////////
5860
5861 function applyStyle(hit, type) {
5862
5863 var attrs = HIT_TYPES[type];
5864
5865 if (!attrs) {
5866 throw new Error('invalid hit type <' + type + '>');
5867 }
5868
5869 attr(hit, attrs);
5870
5871 return hit;
5872 }
5873
5874 function appendHit(gfx, hit) {
5875 append(gfx, hit);
5876 }
5877
5878
5879 // API
5880
5881 /**
5882 * Remove hints on the given graphics.
5883 *
5884 * @param {SVGElement} gfx
5885 */
5886 this.removeHits = function(gfx) {
5887 var hits = all('.djs-hit', gfx);
5888
5889 forEach(hits, remove);
5890 };
5891
5892 /**
5893 * Create default hit for the given element.
5894 *
5895 * @param {djs.model.Base} element
5896 * @param {SVGElement} gfx
5897 *
5898 * @return {SVGElement} created hit
5899 */
5900 this.createDefaultHit = function(element, gfx) {
5901 var waypoints = element.waypoints,
5902 isFrame = element.isFrame,
5903 boxType;
5904
5905 if (waypoints) {
5906 return this.createWaypointsHit(gfx, waypoints);
5907 } else {
5908
5909 boxType = isFrame ? 'stroke' : 'all';
5910
5911 return this.createBoxHit(gfx, boxType, {
5912 width: element.width,
5913 height: element.height
5914 });
5915 }
5916 };
5917
5918 /**
5919 * Create hits for the given waypoints.
5920 *
5921 * @param {SVGElement} gfx
5922 * @param {Array<Point>} waypoints
5923 *
5924 * @return {SVGElement}
5925 */
5926 this.createWaypointsHit = function(gfx, waypoints) {
5927
5928 var hit = createLine(waypoints);
5929
5930 applyStyle(hit, 'stroke');
5931
5932 appendHit(gfx, hit);
5933
5934 return hit;
5935 };
5936
5937 /**
5938 * Create hits for a box.
5939 *
5940 * @param {SVGElement} gfx
5941 * @param {string} hitType
5942 * @param {Object} attrs
5943 *
5944 * @return {SVGElement}
5945 */
5946 this.createBoxHit = function(gfx, type, attrs) {
5947
5948 attrs = assign({
5949 x: 0,
5950 y: 0
5951 }, attrs);
5952
5953 var hit = create('rect');
5954
5955 applyStyle(hit, type);
5956
5957 attr(hit, attrs);
5958
5959 appendHit(gfx, hit);
5960
5961 return hit;
5962 };
5963
5964 /**
5965 * Update default hit of the element.
5966 *
5967 * @param {djs.model.Base} element
5968 * @param {SVGElement} gfx
5969 *
5970 * @return {SVGElement} updated hit
5971 */
5972 this.updateDefaultHit = function(element, gfx) {
5973
5974 var hit = query('.djs-hit', gfx);
5975
5976 if (!hit) {
5977 return;
5978 }
5979
5980 if (element.waypoints) {
5981 updateLine(hit, element.waypoints);
5982 } else {
5983 attr(hit, {
5984 width: element.width,
5985 height: element.height
5986 });
5987 }
5988
5989 return hit;
5990 };
5991
5992 this.fire = fire;
5993
5994 this.triggerMouseEvent = triggerMouseEvent;
5995
5996 this.mouseHandler = mouseHandler;
5997
5998 this.registerEvent = registerEvent;
5999 this.unregisterEvent = unregisterEvent;
6000 }
6001
6002
6003 InteractionEvents.$inject = [
6004 'eventBus',
6005 'elementRegistry',
6006 'styles'
6007 ];
6008
6009
6010 /**
6011 * An event indicating that the mouse hovered over an element
6012 *
6013 * @event element.hover
6014 *
6015 * @type {Object}
6016 * @property {djs.model.Base} element
6017 * @property {SVGElement} gfx
6018 * @property {Event} originalEvent
6019 */
6020
6021 /**
6022 * An event indicating that the mouse has left an element
6023 *
6024 * @event element.out
6025 *
6026 * @type {Object}
6027 * @property {djs.model.Base} element
6028 * @property {SVGElement} gfx
6029 * @property {Event} originalEvent
6030 */
6031
6032 /**
6033 * An event indicating that the mouse has clicked an element
6034 *
6035 * @event element.click
6036 *
6037 * @type {Object}
6038 * @property {djs.model.Base} element
6039 * @property {SVGElement} gfx
6040 * @property {Event} originalEvent
6041 */
6042
6043 /**
6044 * An event indicating that the mouse has double clicked an element
6045 *
6046 * @event element.dblclick
6047 *
6048 * @type {Object}
6049 * @property {djs.model.Base} element
6050 * @property {SVGElement} gfx
6051 * @property {Event} originalEvent
6052 */
6053
6054 /**
6055 * An event indicating that the mouse has gone down on an element.
6056 *
6057 * @event element.mousedown
6058 *
6059 * @type {Object}
6060 * @property {djs.model.Base} element
6061 * @property {SVGElement} gfx
6062 * @property {Event} originalEvent
6063 */
6064
6065 /**
6066 * An event indicating that the mouse has gone up on an element.
6067 *
6068 * @event element.mouseup
6069 *
6070 * @type {Object}
6071 * @property {djs.model.Base} element
6072 * @property {SVGElement} gfx
6073 * @property {Event} originalEvent
6074 */
6075
6076 /**
6077 * An event indicating that the context menu action is triggered
6078 * via mouse or touch controls.
6079 *
6080 * @event element.contextmenu
6081 *
6082 * @type {Object}
6083 * @property {djs.model.Base} element
6084 * @property {SVGElement} gfx
6085 * @property {Event} originalEvent
6086 */
6087
6088 var InteractionEventsModule = {
6089 __init__: [ 'interactionEvents' ],
6090 interactionEvents: [ 'type', InteractionEvents ]
6091 };
6092
6093 /**
6094 * Returns the surrounding bbox for all elements in
6095 * the array or the element primitive.
6096 *
6097 * @param {Array<djs.model.Shape>|djs.model.Shape} elements
6098 * @param {boolean} stopRecursion
6099 */
6100 function getBBox(elements, stopRecursion) {
6101
6102 stopRecursion = !!stopRecursion;
6103 if (!isArray(elements)) {
6104 elements = [elements];
6105 }
6106
6107 var minX,
6108 minY,
6109 maxX,
6110 maxY;
6111
6112 forEach(elements, function(element) {
6113
6114 // If element is a connection the bbox must be computed first
6115 var bbox = element;
6116 if (element.waypoints && !stopRecursion) {
6117 bbox = getBBox(element.waypoints, true);
6118 }
6119
6120 var x = bbox.x,
6121 y = bbox.y,
6122 height = bbox.height || 0,
6123 width = bbox.width || 0;
6124
6125 if (x < minX || minX === undefined) {
6126 minX = x;
6127 }
6128 if (y < minY || minY === undefined) {
6129 minY = y;
6130 }
6131
6132 if ((x + width) > maxX || maxX === undefined) {
6133 maxX = x + width;
6134 }
6135 if ((y + height) > maxY || maxY === undefined) {
6136 maxY = y + height;
6137 }
6138 });
6139
6140 return {
6141 x: minX,
6142 y: minY,
6143 height: maxY - minY,
6144 width: maxX - minX
6145 };
6146 }
6147
6148
6149 function getType(element) {
6150
6151 if ('waypoints' in element) {
6152 return 'connection';
6153 }
6154
6155 if ('x' in element) {
6156 return 'shape';
6157 }
6158
6159 return 'root';
6160 }
6161
6162 function isFrameElement$1(element) {
6163
6164 return !!(element && element.isFrame);
6165 }
6166
6167 var LOW_PRIORITY$1 = 500;
6168
6169
6170 /**
6171 * @class
6172 *
6173 * A plugin that adds an outline to shapes and connections that may be activated and styled
6174 * via CSS classes.
6175 *
6176 * @param {EventBus} eventBus
6177 * @param {Styles} styles
6178 * @param {ElementRegistry} elementRegistry
6179 */
6180 function Outline(eventBus, styles, elementRegistry) {
6181
6182 this.offset = 6;
6183
6184 var OUTLINE_STYLE = styles.cls('djs-outline', [ 'no-fill' ]);
6185
6186 var self = this;
6187
6188 function createOutline(gfx, bounds) {
6189 var outline = create('rect');
6190
6191 attr(outline, assign({
6192 x: 10,
6193 y: 10,
6194 width: 100,
6195 height: 100
6196 }, OUTLINE_STYLE));
6197
6198 append(gfx, outline);
6199
6200 return outline;
6201 }
6202
6203 // A low priortity is necessary, because outlines of labels have to be updated
6204 // after the label bounds have been updated in the renderer.
6205 eventBus.on([ 'shape.added', 'shape.changed' ], LOW_PRIORITY$1, function(event) {
6206 var element = event.element,
6207 gfx = event.gfx;
6208
6209 var outline = query('.djs-outline', gfx);
6210
6211 if (!outline) {
6212 outline = createOutline(gfx);
6213 }
6214
6215 self.updateShapeOutline(outline, element);
6216 });
6217
6218 eventBus.on([ 'connection.added', 'connection.changed' ], function(event) {
6219 var element = event.element,
6220 gfx = event.gfx;
6221
6222 var outline = query('.djs-outline', gfx);
6223
6224 if (!outline) {
6225 outline = createOutline(gfx);
6226 }
6227
6228 self.updateConnectionOutline(outline, element);
6229 });
6230 }
6231
6232
6233 /**
6234 * Updates the outline of a shape respecting the dimension of the
6235 * element and an outline offset.
6236 *
6237 * @param {SVGElement} outline
6238 * @param {djs.model.Base} element
6239 */
6240 Outline.prototype.updateShapeOutline = function(outline, element) {
6241
6242 attr(outline, {
6243 x: -this.offset,
6244 y: -this.offset,
6245 width: element.width + this.offset * 2,
6246 height: element.height + this.offset * 2
6247 });
6248
6249 };
6250
6251
6252 /**
6253 * Updates the outline of a connection respecting the bounding box of
6254 * the connection and an outline offset.
6255 *
6256 * @param {SVGElement} outline
6257 * @param {djs.model.Base} element
6258 */
6259 Outline.prototype.updateConnectionOutline = function(outline, connection) {
6260
6261 var bbox = getBBox(connection);
6262
6263 attr(outline, {
6264 x: bbox.x - this.offset,
6265 y: bbox.y - this.offset,
6266 width: bbox.width + this.offset * 2,
6267 height: bbox.height + this.offset * 2
6268 });
6269
6270 };
6271
6272
6273 Outline.$inject = ['eventBus', 'styles', 'elementRegistry'];
6274
6275 var OutlineModule = {
6276 __init__: [ 'outline' ],
6277 outline: [ 'type', Outline ]
6278 };
6279
6280 /**
6281 * A service that offers the current selection in a diagram.
6282 * Offers the api to control the selection, too.
6283 *
6284 * @class
6285 *
6286 * @param {EventBus} eventBus the event bus
6287 */
6288 function Selection(eventBus) {
6289
6290 this._eventBus = eventBus;
6291
6292 this._selectedElements = [];
6293
6294 var self = this;
6295
6296 eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
6297 var element = e.element;
6298 self.deselect(element);
6299 });
6300
6301 eventBus.on([ 'diagram.clear' ], function(e) {
6302 self.select(null);
6303 });
6304 }
6305
6306 Selection.$inject = [ 'eventBus' ];
6307
6308
6309 Selection.prototype.deselect = function(element) {
6310 var selectedElements = this._selectedElements;
6311
6312 var idx = selectedElements.indexOf(element);
6313
6314 if (idx !== -1) {
6315 var oldSelection = selectedElements.slice();
6316
6317 selectedElements.splice(idx, 1);
6318
6319 this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
6320 }
6321 };
6322
6323
6324 Selection.prototype.get = function() {
6325 return this._selectedElements;
6326 };
6327
6328 Selection.prototype.isSelected = function(element) {
6329 return this._selectedElements.indexOf(element) !== -1;
6330 };
6331
6332
6333 /**
6334 * This method selects one or more elements on the diagram.
6335 *
6336 * By passing an additional add parameter you can decide whether or not the element(s)
6337 * should be added to the already existing selection or not.
6338 *
6339 * @method Selection#select
6340 *
6341 * @param {Object|Object[]} elements element or array of elements to be selected
6342 * @param {boolean} [add] whether the element(s) should be appended to the current selection, defaults to false
6343 */
6344 Selection.prototype.select = function(elements, add) {
6345 var selectedElements = this._selectedElements,
6346 oldSelection = selectedElements.slice();
6347
6348 if (!isArray(elements)) {
6349 elements = elements ? [ elements ] : [];
6350 }
6351
6352 // selection may be cleared by passing an empty array or null
6353 // to the method
6354 if (add) {
6355 forEach(elements, function(element) {
6356 if (selectedElements.indexOf(element) !== -1) {
6357
6358 // already selected
6359 return;
6360 } else {
6361 selectedElements.push(element);
6362 }
6363 });
6364 } else {
6365 this._selectedElements = selectedElements = elements.slice();
6366 }
6367
6368 this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
6369 };
6370
6371 var MARKER_HOVER = 'hover',
6372 MARKER_SELECTED = 'selected';
6373
6374
6375 /**
6376 * A plugin that adds a visible selection UI to shapes and connections
6377 * by appending the <code>hover</code> and <code>selected</code> classes to them.
6378 *
6379 * @class
6380 *
6381 * Makes elements selectable, too.
6382 *
6383 * @param {EventBus} events
6384 * @param {SelectionService} selection
6385 * @param {Canvas} canvas
6386 */
6387 function SelectionVisuals(events, canvas, selection, styles) {
6388
6389 this._multiSelectionBox = null;
6390
6391 function addMarker(e, cls) {
6392 canvas.addMarker(e, cls);
6393 }
6394
6395 function removeMarker(e, cls) {
6396 canvas.removeMarker(e, cls);
6397 }
6398
6399 events.on('element.hover', function(event) {
6400 addMarker(event.element, MARKER_HOVER);
6401 });
6402
6403 events.on('element.out', function(event) {
6404 removeMarker(event.element, MARKER_HOVER);
6405 });
6406
6407 events.on('selection.changed', function(event) {
6408
6409 function deselect(s) {
6410 removeMarker(s, MARKER_SELECTED);
6411 }
6412
6413 function select(s) {
6414 addMarker(s, MARKER_SELECTED);
6415 }
6416
6417 var oldSelection = event.oldSelection,
6418 newSelection = event.newSelection;
6419
6420 forEach(oldSelection, function(e) {
6421 if (newSelection.indexOf(e) === -1) {
6422 deselect(e);
6423 }
6424 });
6425
6426 forEach(newSelection, function(e) {
6427 if (oldSelection.indexOf(e) === -1) {
6428 select(e);
6429 }
6430 });
6431 });
6432 }
6433
6434 SelectionVisuals.$inject = [
6435 'eventBus',
6436 'canvas',
6437 'selection',
6438 'styles'
6439 ];
6440
6441 function SelectionBehavior(
6442 eventBus, selection, canvas,
6443 elementRegistry) {
6444
6445 eventBus.on('create.end', 500, function(e) {
6446
6447 var context = e.context,
6448 canExecute = context.canExecute,
6449 elements = context.elements,
6450 hints = context.hints || {},
6451 autoSelect = hints.autoSelect;
6452
6453 // select elements after they have been created
6454 if (canExecute) {
6455 if (autoSelect === false) {
6456
6457 // select no elements
6458 return;
6459 }
6460
6461 if (isArray(autoSelect)) {
6462 selection.select(autoSelect);
6463 } else {
6464
6465 // select all elements by default
6466 selection.select(elements.filter(isShown));
6467 }
6468 }
6469 });
6470
6471 eventBus.on('connect.end', 500, function(e) {
6472
6473 // select the connect end target
6474 // after a connect operation
6475 if (e.context.canExecute && e.context.hover) {
6476 selection.select(e.context.hover);
6477 }
6478 });
6479
6480 eventBus.on('shape.move.end', 500, function(e) {
6481 var previousSelection = e.previousSelection || [];
6482
6483 var shape = elementRegistry.get(e.context.shape.id);
6484
6485 // make sure at least the main moved element is being
6486 // selected after a move operation
6487 var inSelection = find(previousSelection, function(selectedShape) {
6488 return shape.id === selectedShape.id;
6489 });
6490
6491 if (!inSelection) {
6492 selection.select(shape);
6493 }
6494 });
6495
6496 // Shift + click selection
6497 eventBus.on('element.click', function(event) {
6498
6499 var element = event.element;
6500
6501 // do not select the root element
6502 // or connections
6503 if (element === canvas.getRootElement()) {
6504 element = null;
6505 }
6506
6507 var isSelected = selection.isSelected(element),
6508 isMultiSelect = selection.get().length > 1;
6509
6510 // mouse-event: SELECTION_KEY
6511 var add = hasPrimaryModifier(event);
6512
6513 // select OR deselect element in multi selection
6514 if (isSelected && isMultiSelect) {
6515 if (add) {
6516 return selection.deselect(element);
6517 } else {
6518 return selection.select(element);
6519 }
6520 } else
6521 if (!isSelected) {
6522 selection.select(element, add);
6523 } else {
6524 selection.deselect(element);
6525 }
6526 });
6527 }
6528
6529 SelectionBehavior.$inject = [
6530 'eventBus',
6531 'selection',
6532 'canvas',
6533 'elementRegistry'
6534 ];
6535
6536
6537 function isShown(element) {
6538 return !element.hidden;
6539 }
6540
6541 var SelectionModule = {
6542 __init__: [ 'selectionVisuals', 'selectionBehavior' ],
6543 __depends__: [
6544 InteractionEventsModule,
6545 OutlineModule
6546 ],
6547 selection: [ 'type', Selection ],
6548 selectionVisuals: [ 'type', SelectionVisuals ],
6549 selectionBehavior: [ 'type', SelectionBehavior ]
6550 };
6551
6552 /**
6553 * Util that provides unique IDs.
6554 *
6555 * @class djs.util.IdGenerator
6556 * @constructor
6557 * @memberOf djs.util
6558 *
6559 * The ids can be customized via a given prefix and contain a random value to avoid collisions.
6560 *
6561 * @param {string} prefix a prefix to prepend to generated ids (for better readability)
6562 */
6563 function IdGenerator(prefix) {
6564
6565 this._counter = 0;
6566 this._prefix = (prefix ? prefix + '-' : '') + Math.floor(Math.random() * 1000000000) + '-';
6567 }
6568
6569 /**
6570 * Returns a next unique ID.
6571 *
6572 * @method djs.util.IdGenerator#next
6573 *
6574 * @returns {string} the id
6575 */
6576 IdGenerator.prototype.next = function() {
6577 return this._prefix + (++this._counter);
6578 };
6579
6580 // document wide unique overlay ids
6581 var ids = new IdGenerator('ov');
6582
6583 var LOW_PRIORITY$2 = 500;
6584
6585
6586 /**
6587 * A service that allows users to attach overlays to diagram elements.
6588 *
6589 * The overlay service will take care of overlay positioning during updates.
6590 *
6591 * @example
6592 *
6593 * // add a pink badge on the top left of the shape
6594 * overlays.add(someShape, {
6595 * position: {
6596 * top: -5,
6597 * left: -5
6598 * },
6599 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
6600 * });
6601 *
6602 * // or add via shape id
6603 *
6604 * overlays.add('some-element-id', {
6605 * position: {
6606 * top: -5,
6607 * left: -5
6608 * }
6609 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
6610 * });
6611 *
6612 * // or add with optional type
6613 *
6614 * overlays.add(someShape, 'badge', {
6615 * position: {
6616 * top: -5,
6617 * left: -5
6618 * }
6619 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
6620 * });
6621 *
6622 *
6623 * // remove an overlay
6624 *
6625 * var id = overlays.add(...);
6626 * overlays.remove(id);
6627 *
6628 *
6629 * You may configure overlay defaults during tool by providing a `config` module
6630 * with `overlays.defaults` as an entry:
6631 *
6632 * {
6633 * overlays: {
6634 * defaults: {
6635 * show: {
6636 * minZoom: 0.7,
6637 * maxZoom: 5.0
6638 * },
6639 * scale: {
6640 * min: 1
6641 * }
6642 * }
6643 * }
6644 *
6645 * @param {Object} config
6646 * @param {EventBus} eventBus
6647 * @param {Canvas} canvas
6648 * @param {ElementRegistry} elementRegistry
6649 */
6650 function Overlays(config, eventBus, canvas, elementRegistry) {
6651
6652 this._eventBus = eventBus;
6653 this._canvas = canvas;
6654 this._elementRegistry = elementRegistry;
6655
6656 this._ids = ids;
6657
6658 this._overlayDefaults = assign({
6659
6660 // no show constraints
6661 show: null,
6662
6663 // always scale
6664 scale: true
6665 }, config && config.defaults);
6666
6667 /**
6668 * Mapping overlayId -> overlay
6669 */
6670 this._overlays = {};
6671
6672 /**
6673 * Mapping elementId -> overlay container
6674 */
6675 this._overlayContainers = [];
6676
6677 // root html element for all overlays
6678 this._overlayRoot = createRoot(canvas.getContainer());
6679
6680 this._init();
6681 }
6682
6683
6684 Overlays.$inject = [
6685 'config.overlays',
6686 'eventBus',
6687 'canvas',
6688 'elementRegistry'
6689 ];
6690
6691
6692 /**
6693 * Returns the overlay with the specified id or a list of overlays
6694 * for an element with a given type.
6695 *
6696 * @example
6697 *
6698 * // return the single overlay with the given id
6699 * overlays.get('some-id');
6700 *
6701 * // return all overlays for the shape
6702 * overlays.get({ element: someShape });
6703 *
6704 * // return all overlays on shape with type 'badge'
6705 * overlays.get({ element: someShape, type: 'badge' });
6706 *
6707 * // shape can also be specified as id
6708 * overlays.get({ element: 'element-id', type: 'badge' });
6709 *
6710 *
6711 * @param {Object} search
6712 * @param {string} [search.id]
6713 * @param {string|djs.model.Base} [search.element]
6714 * @param {string} [search.type]
6715 *
6716 * @return {Object|Array<Object>} the overlay(s)
6717 */
6718 Overlays.prototype.get = function(search) {
6719
6720 if (isString(search)) {
6721 search = { id: search };
6722 }
6723
6724 if (isString(search.element)) {
6725 search.element = this._elementRegistry.get(search.element);
6726 }
6727
6728 if (search.element) {
6729 var container = this._getOverlayContainer(search.element, true);
6730
6731 // return a list of overlays when searching by element (+type)
6732 if (container) {
6733 return search.type ? filter(container.overlays, matchPattern({ type: search.type })) : container.overlays.slice();
6734 } else {
6735 return [];
6736 }
6737 } else
6738 if (search.type) {
6739 return filter(this._overlays, matchPattern({ type: search.type }));
6740 } else {
6741
6742 // return single element when searching by id
6743 return search.id ? this._overlays[search.id] : null;
6744 }
6745 };
6746
6747 /**
6748 * Adds a HTML overlay to an element.
6749 *
6750 * @param {string|djs.model.Base} element attach overlay to this shape
6751 * @param {string} [type] optional type to assign to the overlay
6752 * @param {Object} overlay the overlay configuration
6753 *
6754 * @param {string|DOMElement} overlay.html html element to use as an overlay
6755 * @param {Object} [overlay.show] show configuration
6756 * @param {number} [overlay.show.minZoom] minimal zoom level to show the overlay
6757 * @param {number} [overlay.show.maxZoom] maximum zoom level to show the overlay
6758 * @param {Object} overlay.position where to attach the overlay
6759 * @param {number} [overlay.position.left] relative to element bbox left attachment
6760 * @param {number} [overlay.position.top] relative to element bbox top attachment
6761 * @param {number} [overlay.position.bottom] relative to element bbox bottom attachment
6762 * @param {number} [overlay.position.right] relative to element bbox right attachment
6763 * @param {boolean|Object} [overlay.scale=true] false to preserve the same size regardless of
6764 * diagram zoom
6765 * @param {number} [overlay.scale.min]
6766 * @param {number} [overlay.scale.max]
6767 *
6768 * @return {string} id that may be used to reference the overlay for update or removal
6769 */
6770 Overlays.prototype.add = function(element, type, overlay) {
6771
6772 if (isObject(type)) {
6773 overlay = type;
6774 type = null;
6775 }
6776
6777 if (!element.id) {
6778 element = this._elementRegistry.get(element);
6779 }
6780
6781 if (!overlay.position) {
6782 throw new Error('must specifiy overlay position');
6783 }
6784
6785 if (!overlay.html) {
6786 throw new Error('must specifiy overlay html');
6787 }
6788
6789 if (!element) {
6790 throw new Error('invalid element specified');
6791 }
6792
6793 var id = this._ids.next();
6794
6795 overlay = assign({}, this._overlayDefaults, overlay, {
6796 id: id,
6797 type: type,
6798 element: element,
6799 html: overlay.html
6800 });
6801
6802 this._addOverlay(overlay);
6803
6804 return id;
6805 };
6806
6807
6808 /**
6809 * Remove an overlay with the given id or all overlays matching the given filter.
6810 *
6811 * @see Overlays#get for filter options.
6812 *
6813 * @param {string} [id]
6814 * @param {Object} [filter]
6815 */
6816 Overlays.prototype.remove = function(filter) {
6817
6818 var overlays = this.get(filter) || [];
6819
6820 if (!isArray(overlays)) {
6821 overlays = [ overlays ];
6822 }
6823
6824 var self = this;
6825
6826 forEach(overlays, function(overlay) {
6827
6828 var container = self._getOverlayContainer(overlay.element, true);
6829
6830 if (overlay) {
6831 remove$1(overlay.html);
6832 remove$1(overlay.htmlContainer);
6833
6834 delete overlay.htmlContainer;
6835 delete overlay.element;
6836
6837 delete self._overlays[overlay.id];
6838 }
6839
6840 if (container) {
6841 var idx = container.overlays.indexOf(overlay);
6842 if (idx !== -1) {
6843 container.overlays.splice(idx, 1);
6844 }
6845 }
6846 });
6847
6848 };
6849
6850
6851 Overlays.prototype.show = function() {
6852 setVisible(this._overlayRoot);
6853 };
6854
6855
6856 Overlays.prototype.hide = function() {
6857 setVisible(this._overlayRoot, false);
6858 };
6859
6860 Overlays.prototype.clear = function() {
6861 this._overlays = {};
6862
6863 this._overlayContainers = [];
6864
6865 clear$1(this._overlayRoot);
6866 };
6867
6868 Overlays.prototype._updateOverlayContainer = function(container) {
6869 var element = container.element,
6870 html = container.html;
6871
6872 // update container left,top according to the elements x,y coordinates
6873 // this ensures we can attach child elements relative to this container
6874
6875 var x = element.x,
6876 y = element.y;
6877
6878 if (element.waypoints) {
6879 var bbox = getBBox(element);
6880 x = bbox.x;
6881 y = bbox.y;
6882 }
6883
6884 setPosition(html, x, y);
6885
6886 attr$1(container.html, 'data-container-id', element.id);
6887 };
6888
6889
6890 Overlays.prototype._updateOverlay = function(overlay) {
6891
6892 var position = overlay.position,
6893 htmlContainer = overlay.htmlContainer,
6894 element = overlay.element;
6895
6896 // update overlay html relative to shape because
6897 // it is already positioned on the element
6898
6899 // update relative
6900 var left = position.left,
6901 top = position.top;
6902
6903 if (position.right !== undefined) {
6904
6905 var width;
6906
6907 if (element.waypoints) {
6908 width = getBBox(element).width;
6909 } else {
6910 width = element.width;
6911 }
6912
6913 left = position.right * -1 + width;
6914 }
6915
6916 if (position.bottom !== undefined) {
6917
6918 var height;
6919
6920 if (element.waypoints) {
6921 height = getBBox(element).height;
6922 } else {
6923 height = element.height;
6924 }
6925
6926 top = position.bottom * -1 + height;
6927 }
6928
6929 setPosition(htmlContainer, left || 0, top || 0);
6930 };
6931
6932
6933 Overlays.prototype._createOverlayContainer = function(element) {
6934 var html = domify('<div class="djs-overlays" style="position: absolute" />');
6935
6936 this._overlayRoot.appendChild(html);
6937
6938 var container = {
6939 html: html,
6940 element: element,
6941 overlays: []
6942 };
6943
6944 this._updateOverlayContainer(container);
6945
6946 this._overlayContainers.push(container);
6947
6948 return container;
6949 };
6950
6951
6952 Overlays.prototype._updateRoot = function(viewbox) {
6953 var scale = viewbox.scale || 1;
6954
6955 var matrix = 'matrix(' +
6956 [
6957 scale,
6958 0,
6959 0,
6960 scale,
6961 -1 * viewbox.x * scale,
6962 -1 * viewbox.y * scale
6963 ].join(',') +
6964 ')';
6965
6966 setTransform(this._overlayRoot, matrix);
6967 };
6968
6969
6970 Overlays.prototype._getOverlayContainer = function(element, raw) {
6971 var container = find(this._overlayContainers, function(c) {
6972 return c.element === element;
6973 });
6974
6975
6976 if (!container && !raw) {
6977 return this._createOverlayContainer(element);
6978 }
6979
6980 return container;
6981 };
6982
6983
6984 Overlays.prototype._addOverlay = function(overlay) {
6985
6986 var id = overlay.id,
6987 element = overlay.element,
6988 html = overlay.html,
6989 htmlContainer,
6990 overlayContainer;
6991
6992 // unwrap jquery (for those who need it)
6993 if (html.get && html.constructor.prototype.jquery) {
6994 html = html.get(0);
6995 }
6996
6997 // create proper html elements from
6998 // overlay HTML strings
6999 if (isString(html)) {
7000 html = domify(html);
7001 }
7002
7003 overlayContainer = this._getOverlayContainer(element);
7004
7005 htmlContainer = domify('<div class="djs-overlay" data-overlay-id="' + id + '" style="position: absolute">');
7006
7007 htmlContainer.appendChild(html);
7008
7009 if (overlay.type) {
7010 classes$1(htmlContainer).add('djs-overlay-' + overlay.type);
7011 }
7012
7013 overlay.htmlContainer = htmlContainer;
7014
7015 overlayContainer.overlays.push(overlay);
7016 overlayContainer.html.appendChild(htmlContainer);
7017
7018 this._overlays[id] = overlay;
7019
7020 this._updateOverlay(overlay);
7021 this._updateOverlayVisibilty(overlay, this._canvas.viewbox());
7022 };
7023
7024
7025 Overlays.prototype._updateOverlayVisibilty = function(overlay, viewbox) {
7026 var show = overlay.show,
7027 minZoom = show && show.minZoom,
7028 maxZoom = show && show.maxZoom,
7029 htmlContainer = overlay.htmlContainer,
7030 visible = true;
7031
7032 if (show) {
7033 if (
7034 (isDefined(minZoom) && minZoom > viewbox.scale) ||
7035 (isDefined(maxZoom) && maxZoom < viewbox.scale)
7036 ) {
7037 visible = false;
7038 }
7039
7040 setVisible(htmlContainer, visible);
7041 }
7042
7043 this._updateOverlayScale(overlay, viewbox);
7044 };
7045
7046
7047 Overlays.prototype._updateOverlayScale = function(overlay, viewbox) {
7048 var shouldScale = overlay.scale,
7049 minScale,
7050 maxScale,
7051 htmlContainer = overlay.htmlContainer;
7052
7053 var scale, transform = '';
7054
7055 if (shouldScale !== true) {
7056
7057 if (shouldScale === false) {
7058 minScale = 1;
7059 maxScale = 1;
7060 } else {
7061 minScale = shouldScale.min;
7062 maxScale = shouldScale.max;
7063 }
7064
7065 if (isDefined(minScale) && viewbox.scale < minScale) {
7066 scale = (1 / viewbox.scale || 1) * minScale;
7067 }
7068
7069 if (isDefined(maxScale) && viewbox.scale > maxScale) {
7070 scale = (1 / viewbox.scale || 1) * maxScale;
7071 }
7072 }
7073
7074 if (isDefined(scale)) {
7075 transform = 'scale(' + scale + ',' + scale + ')';
7076 }
7077
7078 setTransform(htmlContainer, transform);
7079 };
7080
7081
7082 Overlays.prototype._updateOverlaysVisibilty = function(viewbox) {
7083
7084 var self = this;
7085
7086 forEach(this._overlays, function(overlay) {
7087 self._updateOverlayVisibilty(overlay, viewbox);
7088 });
7089 };
7090
7091
7092 Overlays.prototype._init = function() {
7093
7094 var eventBus = this._eventBus;
7095
7096 var self = this;
7097
7098
7099 // scroll/zoom integration
7100
7101 function updateViewbox(viewbox) {
7102 self._updateRoot(viewbox);
7103 self._updateOverlaysVisibilty(viewbox);
7104
7105 self.show();
7106 }
7107
7108 eventBus.on('canvas.viewbox.changing', function(event) {
7109 self.hide();
7110 });
7111
7112 eventBus.on('canvas.viewbox.changed', function(event) {
7113 updateViewbox(event.viewbox);
7114 });
7115
7116
7117 // remove integration
7118
7119 eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
7120 var element = e.element;
7121 var overlays = self.get({ element: element });
7122
7123 forEach(overlays, function(o) {
7124 self.remove(o.id);
7125 });
7126
7127 var container = self._getOverlayContainer(element);
7128
7129 if (container) {
7130 remove$1(container.html);
7131 var i = self._overlayContainers.indexOf(container);
7132 if (i !== -1) {
7133 self._overlayContainers.splice(i, 1);
7134 }
7135 }
7136 });
7137
7138
7139 // move integration
7140
7141 eventBus.on('element.changed', LOW_PRIORITY$2, function(e) {
7142 var element = e.element;
7143
7144 var container = self._getOverlayContainer(element, true);
7145
7146 if (container) {
7147 forEach(container.overlays, function(overlay) {
7148 self._updateOverlay(overlay);
7149 });
7150
7151 self._updateOverlayContainer(container);
7152 }
7153 });
7154
7155
7156 // marker integration, simply add them on the overlays as classes, too.
7157
7158 eventBus.on('element.marker.update', function(e) {
7159 var container = self._getOverlayContainer(e.element, true);
7160 if (container) {
7161 classes$1(container.html)[e.add ? 'add' : 'remove'](e.marker);
7162 }
7163 });
7164
7165
7166 // clear overlays with diagram
7167
7168 eventBus.on('diagram.clear', this.clear, this);
7169 };
7170
7171
7172
7173 // helpers /////////////////////////////
7174
7175 function createRoot(parentNode) {
7176 var root = domify(
7177 '<div class="djs-overlay-container" style="position: absolute; width: 0; height: 0;" />'
7178 );
7179
7180 parentNode.insertBefore(root, parentNode.firstChild);
7181
7182 return root;
7183 }
7184
7185 function setPosition(el, x, y) {
7186 assign(el.style, { left: x + 'px', top: y + 'px' });
7187 }
7188
7189 function setVisible(el, visible) {
7190 el.style.display = visible === false ? 'none' : '';
7191 }
7192
7193 function setTransform(el, transform) {
7194
7195 el.style['transform-origin'] = 'top left';
7196
7197 [ '', '-ms-', '-webkit-' ].forEach(function(prefix) {
7198 el.style[prefix + 'transform'] = transform;
7199 });
7200 }
7201
7202 var OverlaysModule = {
7203 __init__: [ 'overlays' ],
7204 overlays: [ 'type', Overlays ]
7205 };
7206
7207 var CLASS_PATTERN = /^class /;
7208
7209 function isClass(fn) {
7210 return CLASS_PATTERN.test(fn.toString());
7211 }
7212
7213 function isArray$1(obj) {
7214 return Object.prototype.toString.call(obj) === '[object Array]';
7215 }
7216
7217 function annotate() {
7218 var args = Array.prototype.slice.call(arguments);
7219
7220 if (args.length === 1 && isArray$1(args[0])) {
7221 args = args[0];
7222 }
7223
7224 var fn = args.pop();
7225
7226 fn.$inject = args;
7227
7228 return fn;
7229 }
7230
7231 // Current limitations:
7232 // - can't put into "function arg" comments
7233 // function /* (no parenthesis like this) */ (){}
7234 // function abc( /* xx (no parenthesis like this) */ a, b) {}
7235 //
7236 // Just put the comment before function or inside:
7237 // /* (((this is fine))) */ function(a, b) {}
7238 // function abc(a) { /* (((this is fine))) */}
7239 //
7240 // - can't reliably auto-annotate constructor; we'll match the
7241 // first constructor(...) pattern found which may be the one
7242 // of a nested class, too.
7243
7244 var CONSTRUCTOR_ARGS = /constructor\s*[^(]*\(\s*([^)]*)\)/m;
7245 var FN_ARGS = /^function\s*[^(]*\(\s*([^)]*)\)/m;
7246 var FN_ARG = /\/\*([^*]*)\*\//m;
7247
7248 function parse$2(fn) {
7249
7250 if (typeof fn !== 'function') {
7251 throw new Error('Cannot annotate "' + fn + '". Expected a function!');
7252 }
7253
7254 var match = fn.toString().match(isClass(fn) ? CONSTRUCTOR_ARGS : FN_ARGS);
7255
7256 // may parse class without constructor
7257 if (!match) {
7258 return [];
7259 }
7260
7261 return match[1] && match[1].split(',').map(function (arg) {
7262 match = arg.match(FN_ARG);
7263 return match ? match[1].trim() : arg.trim();
7264 }) || [];
7265 }
7266
7267 function Module() {
7268 var providers = [];
7269
7270 this.factory = function (name, factory) {
7271 providers.push([name, 'factory', factory]);
7272 return this;
7273 };
7274
7275 this.value = function (name, value) {
7276 providers.push([name, 'value', value]);
7277 return this;
7278 };
7279
7280 this.type = function (name, type) {
7281 providers.push([name, 'type', type]);
7282 return this;
7283 };
7284
7285 this.forEach = function (iterator) {
7286 providers.forEach(iterator);
7287 };
7288 }
7289
7290 var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
7291
7292 function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
7293
7294 function Injector(modules, parent) {
7295 parent = parent || {
7296 get: function get(name, strict) {
7297 currentlyResolving.push(name);
7298
7299 if (strict === false) {
7300 return null;
7301 } else {
7302 throw error('No provider for "' + name + '"!');
7303 }
7304 }
7305 };
7306
7307 var currentlyResolving = [];
7308 var providers = this._providers = Object.create(parent._providers || null);
7309 var instances = this._instances = Object.create(null);
7310
7311 var self = instances.injector = this;
7312
7313 var error = function error(msg) {
7314 var stack = currentlyResolving.join(' -> ');
7315 currentlyResolving.length = 0;
7316 return new Error(stack ? msg + ' (Resolving: ' + stack + ')' : msg);
7317 };
7318
7319 /**
7320 * Return a named service.
7321 *
7322 * @param {String} name
7323 * @param {Boolean} [strict=true] if false, resolve missing services to null
7324 *
7325 * @return {Object}
7326 */
7327 var get = function get(name, strict) {
7328 if (!providers[name] && name.indexOf('.') !== -1) {
7329 var parts = name.split('.');
7330 var pivot = get(parts.shift());
7331
7332 while (parts.length) {
7333 pivot = pivot[parts.shift()];
7334 }
7335
7336 return pivot;
7337 }
7338
7339 if (hasProp(instances, name)) {
7340 return instances[name];
7341 }
7342
7343 if (hasProp(providers, name)) {
7344 if (currentlyResolving.indexOf(name) !== -1) {
7345 currentlyResolving.push(name);
7346 throw error('Cannot resolve circular dependency!');
7347 }
7348
7349 currentlyResolving.push(name);
7350 instances[name] = providers[name][0](providers[name][1]);
7351 currentlyResolving.pop();
7352
7353 return instances[name];
7354 }
7355
7356 return parent.get(name, strict);
7357 };
7358
7359 var fnDef = function fnDef(fn) {
7360 var locals = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7361
7362 if (typeof fn !== 'function') {
7363 if (isArray$1(fn)) {
7364 fn = annotate(fn.slice());
7365 } else {
7366 throw new Error('Cannot invoke "' + fn + '". Expected a function!');
7367 }
7368 }
7369
7370 var inject = fn.$inject || parse$2(fn);
7371 var dependencies = inject.map(function (dep) {
7372 if (hasProp(locals, dep)) {
7373 return locals[dep];
7374 } else {
7375 return get(dep);
7376 }
7377 });
7378
7379 return {
7380 fn: fn,
7381 dependencies: dependencies
7382 };
7383 };
7384
7385 var instantiate = function instantiate(Type) {
7386 var _fnDef = fnDef(Type),
7387 dependencies = _fnDef.dependencies,
7388 fn = _fnDef.fn;
7389
7390 return new (Function.prototype.bind.apply(fn, [null].concat(_toConsumableArray(dependencies))))();
7391 };
7392
7393 var invoke = function invoke(func, context, locals) {
7394 var _fnDef2 = fnDef(func, locals),
7395 dependencies = _fnDef2.dependencies,
7396 fn = _fnDef2.fn;
7397
7398 return fn.call.apply(fn, [context].concat(_toConsumableArray(dependencies)));
7399 };
7400
7401 var createPrivateInjectorFactory = function createPrivateInjectorFactory(privateChildInjector) {
7402 return annotate(function (key) {
7403 return privateChildInjector.get(key);
7404 });
7405 };
7406
7407 var createChild = function createChild(modules, forceNewInstances) {
7408 if (forceNewInstances && forceNewInstances.length) {
7409 var fromParentModule = Object.create(null);
7410 var matchedScopes = Object.create(null);
7411
7412 var privateInjectorsCache = [];
7413 var privateChildInjectors = [];
7414 var privateChildFactories = [];
7415
7416 var provider;
7417 var cacheIdx;
7418 var privateChildInjector;
7419 var privateChildInjectorFactory;
7420 for (var name in providers) {
7421 provider = providers[name];
7422
7423 if (forceNewInstances.indexOf(name) !== -1) {
7424 if (provider[2] === 'private') {
7425 cacheIdx = privateInjectorsCache.indexOf(provider[3]);
7426 if (cacheIdx === -1) {
7427 privateChildInjector = provider[3].createChild([], forceNewInstances);
7428 privateChildInjectorFactory = createPrivateInjectorFactory(privateChildInjector);
7429 privateInjectorsCache.push(provider[3]);
7430 privateChildInjectors.push(privateChildInjector);
7431 privateChildFactories.push(privateChildInjectorFactory);
7432 fromParentModule[name] = [privateChildInjectorFactory, name, 'private', privateChildInjector];
7433 } else {
7434 fromParentModule[name] = [privateChildFactories[cacheIdx], name, 'private', privateChildInjectors[cacheIdx]];
7435 }
7436 } else {
7437 fromParentModule[name] = [provider[2], provider[1]];
7438 }
7439 matchedScopes[name] = true;
7440 }
7441
7442 if ((provider[2] === 'factory' || provider[2] === 'type') && provider[1].$scope) {
7443 /* jshint -W083 */
7444 forceNewInstances.forEach(function (scope) {
7445 if (provider[1].$scope.indexOf(scope) !== -1) {
7446 fromParentModule[name] = [provider[2], provider[1]];
7447 matchedScopes[scope] = true;
7448 }
7449 });
7450 }
7451 }
7452
7453 forceNewInstances.forEach(function (scope) {
7454 if (!matchedScopes[scope]) {
7455 throw new Error('No provider for "' + scope + '". Cannot use provider from the parent!');
7456 }
7457 });
7458
7459 modules.unshift(fromParentModule);
7460 }
7461
7462 return new Injector(modules, self);
7463 };
7464
7465 var factoryMap = {
7466 factory: invoke,
7467 type: instantiate,
7468 value: function value(_value) {
7469 return _value;
7470 }
7471 };
7472
7473 modules.forEach(function (module) {
7474
7475 function arrayUnwrap(type, value) {
7476 if (type !== 'value' && isArray$1(value)) {
7477 value = annotate(value.slice());
7478 }
7479
7480 return value;
7481 }
7482
7483 // TODO(vojta): handle wrong inputs (modules)
7484 if (module instanceof Module) {
7485 module.forEach(function (provider) {
7486 var name = provider[0];
7487 var type = provider[1];
7488 var value = provider[2];
7489
7490 providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
7491 });
7492 } else if ((typeof module === 'undefined' ? 'undefined' : _typeof(module)) === 'object') {
7493 if (module.__exports__) {
7494 var clonedModule = Object.keys(module).reduce(function (m, key) {
7495 if (key.substring(0, 2) !== '__') {
7496 m[key] = module[key];
7497 }
7498 return m;
7499 }, Object.create(null));
7500
7501 var privateInjector = new Injector((module.__modules__ || []).concat([clonedModule]), self);
7502 var getFromPrivateInjector = annotate(function (key) {
7503 return privateInjector.get(key);
7504 });
7505 module.__exports__.forEach(function (key) {
7506 providers[key] = [getFromPrivateInjector, key, 'private', privateInjector];
7507 });
7508 } else {
7509 Object.keys(module).forEach(function (name) {
7510 if (module[name][2] === 'private') {
7511 providers[name] = module[name];
7512 return;
7513 }
7514
7515 var type = module[name][0];
7516 var value = module[name][1];
7517
7518 providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
7519 });
7520 }
7521 }
7522 });
7523
7524 // public API
7525 this.get = get;
7526 this.invoke = invoke;
7527 this.instantiate = instantiate;
7528 this.createChild = createChild;
7529 }
7530
7531 // helpers /////////////////
7532
7533 function hasProp(obj, prop) {
7534 return Object.hasOwnProperty.call(obj, prop);
7535 }
7536
7537 // apply default renderer with lowest possible priority
7538 // so that it only kicks in if noone else could render
7539 var DEFAULT_RENDER_PRIORITY$1 = 1;
7540
7541 /**
7542 * The default renderer used for shapes and connections.
7543 *
7544 * @param {EventBus} eventBus
7545 * @param {Styles} styles
7546 */
7547 function DefaultRenderer(eventBus, styles) {
7548
7549 //
7550 BaseRenderer.call(this, eventBus, DEFAULT_RENDER_PRIORITY$1);
7551
7552 this.CONNECTION_STYLE = styles.style([ 'no-fill' ], { strokeWidth: 5, stroke: 'fuchsia' });
7553 this.SHAPE_STYLE = styles.style({ fill: 'white', stroke: 'fuchsia', strokeWidth: 2 });
7554 this.FRAME_STYLE = styles.style([ 'no-fill' ], { stroke: 'fuchsia', strokeDasharray: 4, strokeWidth: 2 });
7555 }
7556
7557 inherits_browser(DefaultRenderer, BaseRenderer);
7558
7559
7560 DefaultRenderer.prototype.canRender = function() {
7561 return true;
7562 };
7563
7564 DefaultRenderer.prototype.drawShape = function drawShape(visuals, element) {
7565 var rect = create('rect');
7566
7567 attr(rect, {
7568 x: 0,
7569 y: 0,
7570 width: element.width || 0,
7571 height: element.height || 0
7572 });
7573
7574 if (isFrameElement$1(element)) {
7575 attr(rect, this.FRAME_STYLE);
7576 } else {
7577 attr(rect, this.SHAPE_STYLE);
7578 }
7579
7580 append(visuals, rect);
7581
7582 return rect;
7583 };
7584
7585 DefaultRenderer.prototype.drawConnection = function drawConnection(visuals, connection) {
7586
7587 var line = createLine(connection.waypoints, this.CONNECTION_STYLE);
7588 append(visuals, line);
7589
7590 return line;
7591 };
7592
7593 DefaultRenderer.prototype.getShapePath = function getShapePath(shape) {
7594
7595 var x = shape.x,
7596 y = shape.y,
7597 width = shape.width,
7598 height = shape.height;
7599
7600 var shapePath = [
7601 ['M', x, y],
7602 ['l', width, 0],
7603 ['l', 0, height],
7604 ['l', -width, 0],
7605 ['z']
7606 ];
7607
7608 return componentsToPath(shapePath);
7609 };
7610
7611 DefaultRenderer.prototype.getConnectionPath = function getConnectionPath(connection) {
7612 var waypoints = connection.waypoints;
7613
7614 var idx, point, connectionPath = [];
7615
7616 for (idx = 0; (point = waypoints[idx]); idx++) {
7617
7618 // take invisible docking into account
7619 // when creating the path
7620 point = point.original || point;
7621
7622 connectionPath.push([ idx === 0 ? 'M' : 'L', point.x, point.y ]);
7623 }
7624
7625 return componentsToPath(connectionPath);
7626 };
7627
7628
7629 DefaultRenderer.$inject = [ 'eventBus', 'styles' ];
7630
7631 /**
7632 * A component that manages shape styles
7633 */
7634 function Styles() {
7635
7636 var defaultTraits = {
7637
7638 'no-fill': {
7639 fill: 'none'
7640 },
7641 'no-border': {
7642 strokeOpacity: 0.0
7643 },
7644 'no-events': {
7645 pointerEvents: 'none'
7646 }
7647 };
7648
7649 var self = this;
7650
7651 /**
7652 * Builds a style definition from a className, a list of traits and an object of additional attributes.
7653 *
7654 * @param {string} className
7655 * @param {Array<string>} traits
7656 * @param {Object} additionalAttrs
7657 *
7658 * @return {Object} the style defintion
7659 */
7660 this.cls = function(className, traits, additionalAttrs) {
7661 var attrs = this.style(traits, additionalAttrs);
7662
7663 return assign(attrs, { 'class': className });
7664 };
7665
7666 /**
7667 * Builds a style definition from a list of traits and an object of additional attributes.
7668 *
7669 * @param {Array<string>} traits
7670 * @param {Object} additionalAttrs
7671 *
7672 * @return {Object} the style defintion
7673 */
7674 this.style = function(traits, additionalAttrs) {
7675
7676 if (!isArray(traits) && !additionalAttrs) {
7677 additionalAttrs = traits;
7678 traits = [];
7679 }
7680
7681 var attrs = reduce(traits, function(attrs, t) {
7682 return assign(attrs, defaultTraits[t] || {});
7683 }, {});
7684
7685 return additionalAttrs ? assign(attrs, additionalAttrs) : attrs;
7686 };
7687
7688 this.computeStyle = function(custom, traits, defaultStyles) {
7689 if (!isArray(traits)) {
7690 defaultStyles = traits;
7691 traits = [];
7692 }
7693
7694 return self.style(traits || [], assign({}, defaultStyles, custom || {}));
7695 };
7696 }
7697
7698 var DrawModule$1 = {
7699 __init__: [ 'defaultRenderer' ],
7700 defaultRenderer: [ 'type', DefaultRenderer ],
7701 styles: [ 'type', Styles ]
7702 };
7703
7704 /**
7705 * Failsafe remove an element from a collection
7706 *
7707 * @param {Array<Object>} [collection]
7708 * @param {Object} [element]
7709 *
7710 * @return {number} the previous index of the element
7711 */
7712 function remove$2(collection, element) {
7713
7714 if (!collection || !element) {
7715 return -1;
7716 }
7717
7718 var idx = collection.indexOf(element);
7719
7720 if (idx !== -1) {
7721 collection.splice(idx, 1);
7722 }
7723
7724 return idx;
7725 }
7726
7727 /**
7728 * Fail save add an element to the given connection, ensuring
7729 * it does not yet exist.
7730 *
7731 * @param {Array<Object>} collection
7732 * @param {Object} element
7733 * @param {number} idx
7734 */
7735 function add(collection, element, idx) {
7736
7737 if (!collection || !element) {
7738 return;
7739 }
7740
7741 if (typeof idx !== 'number') {
7742 idx = -1;
7743 }
7744
7745 var currentIdx = collection.indexOf(element);
7746
7747 if (currentIdx !== -1) {
7748
7749 if (currentIdx === idx) {
7750
7751 // nothing to do, position has not changed
7752 return;
7753 } else {
7754
7755 if (idx !== -1) {
7756
7757 // remove from current position
7758 collection.splice(currentIdx, 1);
7759 } else {
7760
7761 // already exists in collection
7762 return;
7763 }
7764 }
7765 }
7766
7767 if (idx !== -1) {
7768
7769 // insert at specified position
7770 collection.splice(idx, 0, element);
7771 } else {
7772
7773 // push to end
7774 collection.push(element);
7775 }
7776 }
7777
7778 function round(number, resolution) {
7779 return Math.round(number * resolution) / resolution;
7780 }
7781
7782 function ensurePx(number) {
7783 return isNumber(number) ? number + 'px' : number;
7784 }
7785
7786 /**
7787 * Creates a HTML container element for a SVG element with
7788 * the given configuration
7789 *
7790 * @param {Object} options
7791 * @return {HTMLElement} the container element
7792 */
7793 function createContainer(options) {
7794
7795 options = assign({}, { width: '100%', height: '100%' }, options);
7796
7797 var container = options.container || document.body;
7798
7799 // create a <div> around the svg element with the respective size
7800 // this way we can always get the correct container size
7801 // (this is impossible for <svg> elements at the moment)
7802 var parent = document.createElement('div');
7803 parent.setAttribute('class', 'djs-container');
7804
7805 assign(parent.style, {
7806 position: 'relative',
7807 overflow: 'hidden',
7808 width: ensurePx(options.width),
7809 height: ensurePx(options.height)
7810 });
7811
7812 container.appendChild(parent);
7813
7814 return parent;
7815 }
7816
7817 function createGroup(parent, cls, childIndex) {
7818 var group = create('g');
7819 classes(group).add(cls);
7820
7821 var index = childIndex !== undefined ? childIndex : parent.childNodes.length - 1;
7822
7823 // must ensure second argument is node or _null_
7824 // cf. https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore
7825 parent.insertBefore(group, parent.childNodes[index] || null);
7826
7827 return group;
7828 }
7829
7830 var BASE_LAYER = 'base';
7831
7832
7833 var REQUIRED_MODEL_ATTRS = {
7834 shape: [ 'x', 'y', 'width', 'height' ],
7835 connection: [ 'waypoints' ]
7836 };
7837
7838 /**
7839 * The main drawing canvas.
7840 *
7841 * @class
7842 * @constructor
7843 *
7844 * @emits Canvas#canvas.init
7845 *
7846 * @param {Object} config
7847 * @param {EventBus} eventBus
7848 * @param {GraphicsFactory} graphicsFactory
7849 * @param {ElementRegistry} elementRegistry
7850 */
7851 function Canvas(config, eventBus, graphicsFactory, elementRegistry) {
7852
7853 this._eventBus = eventBus;
7854 this._elementRegistry = elementRegistry;
7855 this._graphicsFactory = graphicsFactory;
7856
7857 this._init(config || {});
7858 }
7859
7860 Canvas.$inject = [
7861 'config.canvas',
7862 'eventBus',
7863 'graphicsFactory',
7864 'elementRegistry'
7865 ];
7866
7867
7868 Canvas.prototype._init = function(config) {
7869
7870 var eventBus = this._eventBus;
7871
7872 // Creates a <svg> element that is wrapped into a <div>.
7873 // This way we are always able to correctly figure out the size of the svg element
7874 // by querying the parent node.
7875 //
7876 // (It is not possible to get the size of a svg element cross browser @ 2014-04-01)
7877 //
7878 // <div class="djs-container" style="width: {desired-width}, height: {desired-height}">
7879 // <svg width="100%" height="100%">
7880 // ...
7881 // </svg>
7882 // </div>
7883
7884 // html container
7885 var container = this._container = createContainer(config);
7886
7887 var svg = this._svg = create('svg');
7888 attr(svg, { width: '100%', height: '100%' });
7889
7890 append(container, svg);
7891
7892 var viewport = this._viewport = createGroup(svg, 'viewport');
7893
7894 this._layers = {};
7895
7896 // debounce canvas.viewbox.changed events
7897 // for smoother diagram interaction
7898 if (config.deferUpdate !== false) {
7899 this._viewboxChanged = debounce(bind(this._viewboxChanged, this), 300);
7900 }
7901
7902 eventBus.on('diagram.init', function() {
7903
7904 /**
7905 * An event indicating that the canvas is ready to be drawn on.
7906 *
7907 * @memberOf Canvas
7908 *
7909 * @event canvas.init
7910 *
7911 * @type {Object}
7912 * @property {SVGElement} svg the created svg element
7913 * @property {SVGElement} viewport the direct parent of diagram elements and shapes
7914 */
7915 eventBus.fire('canvas.init', {
7916 svg: svg,
7917 viewport: viewport
7918 });
7919
7920 }, this);
7921
7922 // reset viewbox on shape changes to
7923 // recompute the viewbox
7924 eventBus.on([
7925 'shape.added',
7926 'connection.added',
7927 'shape.removed',
7928 'connection.removed',
7929 'elements.changed'
7930 ], function() {
7931 delete this._cachedViewbox;
7932 }, this);
7933
7934 eventBus.on('diagram.destroy', 500, this._destroy, this);
7935 eventBus.on('diagram.clear', 500, this._clear, this);
7936 };
7937
7938 Canvas.prototype._destroy = function(emit) {
7939 this._eventBus.fire('canvas.destroy', {
7940 svg: this._svg,
7941 viewport: this._viewport
7942 });
7943
7944 var parent = this._container.parentNode;
7945
7946 if (parent) {
7947 parent.removeChild(this._container);
7948 }
7949
7950 delete this._svg;
7951 delete this._container;
7952 delete this._layers;
7953 delete this._rootElement;
7954 delete this._viewport;
7955 };
7956
7957 Canvas.prototype._clear = function() {
7958
7959 var self = this;
7960
7961 var allElements = this._elementRegistry.getAll();
7962
7963 // remove all elements
7964 allElements.forEach(function(element) {
7965 var type = getType(element);
7966
7967 if (type === 'root') {
7968 self.setRootElement(null, true);
7969 } else {
7970 self._removeElement(element, type);
7971 }
7972 });
7973
7974 // force recomputation of view box
7975 delete this._cachedViewbox;
7976 };
7977
7978 /**
7979 * Returns the default layer on which
7980 * all elements are drawn.
7981 *
7982 * @returns {SVGElement}
7983 */
7984 Canvas.prototype.getDefaultLayer = function() {
7985 return this.getLayer(BASE_LAYER, 0);
7986 };
7987
7988 /**
7989 * Returns a layer that is used to draw elements
7990 * or annotations on it.
7991 *
7992 * Non-existing layers retrieved through this method
7993 * will be created. During creation, the optional index
7994 * may be used to create layers below or above existing layers.
7995 * A layer with a certain index is always created above all
7996 * existing layers with the same index.
7997 *
7998 * @param {string} name
7999 * @param {number} index
8000 *
8001 * @returns {SVGElement}
8002 */
8003 Canvas.prototype.getLayer = function(name, index) {
8004
8005 if (!name) {
8006 throw new Error('must specify a name');
8007 }
8008
8009 var layer = this._layers[name];
8010
8011 if (!layer) {
8012 layer = this._layers[name] = this._createLayer(name, index);
8013 }
8014
8015 // throw an error if layer creation / retrival is
8016 // requested on different index
8017 if (typeof index !== 'undefined' && layer.index !== index) {
8018 throw new Error('layer <' + name + '> already created at index <' + index + '>');
8019 }
8020
8021 return layer.group;
8022 };
8023
8024 /**
8025 * Creates a given layer and returns it.
8026 *
8027 * @param {string} name
8028 * @param {number} [index=0]
8029 *
8030 * @return {Object} layer descriptor with { index, group: SVGGroup }
8031 */
8032 Canvas.prototype._createLayer = function(name, index) {
8033
8034 if (!index) {
8035 index = 0;
8036 }
8037
8038 var childIndex = reduce(this._layers, function(childIndex, layer) {
8039 if (index >= layer.index) {
8040 childIndex++;
8041 }
8042
8043 return childIndex;
8044 }, 0);
8045
8046 return {
8047 group: createGroup(this._viewport, 'layer-' + name, childIndex),
8048 index: index
8049 };
8050
8051 };
8052
8053 /**
8054 * Returns the html element that encloses the
8055 * drawing canvas.
8056 *
8057 * @return {DOMNode}
8058 */
8059 Canvas.prototype.getContainer = function() {
8060 return this._container;
8061 };
8062
8063
8064 // markers //////////////////////
8065
8066 Canvas.prototype._updateMarker = function(element, marker, add) {
8067 var container;
8068
8069 if (!element.id) {
8070 element = this._elementRegistry.get(element);
8071 }
8072
8073 // we need to access all
8074 container = this._elementRegistry._elements[element.id];
8075
8076 if (!container) {
8077 return;
8078 }
8079
8080 forEach([ container.gfx, container.secondaryGfx ], function(gfx) {
8081 if (gfx) {
8082
8083 // invoke either addClass or removeClass based on mode
8084 if (add) {
8085 classes(gfx).add(marker);
8086 } else {
8087 classes(gfx).remove(marker);
8088 }
8089 }
8090 });
8091
8092 /**
8093 * An event indicating that a marker has been updated for an element
8094 *
8095 * @event element.marker.update
8096 * @type {Object}
8097 * @property {djs.model.Element} element the shape
8098 * @property {Object} gfx the graphical representation of the shape
8099 * @property {string} marker
8100 * @property {boolean} add true if the marker was added, false if it got removed
8101 */
8102 this._eventBus.fire('element.marker.update', { element: element, gfx: container.gfx, marker: marker, add: !!add });
8103 };
8104
8105
8106 /**
8107 * Adds a marker to an element (basically a css class).
8108 *
8109 * Fires the element.marker.update event, making it possible to
8110 * integrate extension into the marker life-cycle, too.
8111 *
8112 * @example
8113 * canvas.addMarker('foo', 'some-marker');
8114 *
8115 * var fooGfx = canvas.getGraphics('foo');
8116 *
8117 * fooGfx; // <g class="... some-marker"> ... </g>
8118 *
8119 * @param {string|djs.model.Base} element
8120 * @param {string} marker
8121 */
8122 Canvas.prototype.addMarker = function(element, marker) {
8123 this._updateMarker(element, marker, true);
8124 };
8125
8126
8127 /**
8128 * Remove a marker from an element.
8129 *
8130 * Fires the element.marker.update event, making it possible to
8131 * integrate extension into the marker life-cycle, too.
8132 *
8133 * @param {string|djs.model.Base} element
8134 * @param {string} marker
8135 */
8136 Canvas.prototype.removeMarker = function(element, marker) {
8137 this._updateMarker(element, marker, false);
8138 };
8139
8140 /**
8141 * Check the existence of a marker on element.
8142 *
8143 * @param {string|djs.model.Base} element
8144 * @param {string} marker
8145 */
8146 Canvas.prototype.hasMarker = function(element, marker) {
8147 if (!element.id) {
8148 element = this._elementRegistry.get(element);
8149 }
8150
8151 var gfx = this.getGraphics(element);
8152
8153 return classes(gfx).has(marker);
8154 };
8155
8156 /**
8157 * Toggles a marker on an element.
8158 *
8159 * Fires the element.marker.update event, making it possible to
8160 * integrate extension into the marker life-cycle, too.
8161 *
8162 * @param {string|djs.model.Base} element
8163 * @param {string} marker
8164 */
8165 Canvas.prototype.toggleMarker = function(element, marker) {
8166 if (this.hasMarker(element, marker)) {
8167 this.removeMarker(element, marker);
8168 } else {
8169 this.addMarker(element, marker);
8170 }
8171 };
8172
8173 Canvas.prototype.getRootElement = function() {
8174 if (!this._rootElement) {
8175 this.setRootElement({ id: '__implicitroot', children: [] });
8176 }
8177
8178 return this._rootElement;
8179 };
8180
8181
8182
8183 // root element handling //////////////////////
8184
8185 /**
8186 * Sets a given element as the new root element for the canvas
8187 * and returns the new root element.
8188 *
8189 * @param {Object|djs.model.Root} element
8190 * @param {boolean} [override] whether to override the current root element, if any
8191 *
8192 * @return {Object|djs.model.Root} new root element
8193 */
8194 Canvas.prototype.setRootElement = function(element, override) {
8195
8196 if (element) {
8197 this._ensureValid('root', element);
8198 }
8199
8200 var currentRoot = this._rootElement,
8201 elementRegistry = this._elementRegistry,
8202 eventBus = this._eventBus;
8203
8204 if (currentRoot) {
8205 if (!override) {
8206 throw new Error('rootElement already set, need to specify override');
8207 }
8208
8209 // simulate element remove event sequence
8210 eventBus.fire('root.remove', { element: currentRoot });
8211 eventBus.fire('root.removed', { element: currentRoot });
8212
8213 elementRegistry.remove(currentRoot);
8214 }
8215
8216 if (element) {
8217 var gfx = this.getDefaultLayer();
8218
8219 // resemble element add event sequence
8220 eventBus.fire('root.add', { element: element });
8221
8222 elementRegistry.add(element, gfx, this._svg);
8223
8224 eventBus.fire('root.added', { element: element, gfx: gfx });
8225 }
8226
8227 this._rootElement = element;
8228
8229 return element;
8230 };
8231
8232
8233
8234 // add functionality //////////////////////
8235
8236 Canvas.prototype._ensureValid = function(type, element) {
8237 if (!element.id) {
8238 throw new Error('element must have an id');
8239 }
8240
8241 if (this._elementRegistry.get(element.id)) {
8242 throw new Error('element with id ' + element.id + ' already exists');
8243 }
8244
8245 var requiredAttrs = REQUIRED_MODEL_ATTRS[type];
8246
8247 var valid = every(requiredAttrs, function(attr) {
8248 return typeof element[attr] !== 'undefined';
8249 });
8250
8251 if (!valid) {
8252 throw new Error(
8253 'must supply { ' + requiredAttrs.join(', ') + ' } with ' + type);
8254 }
8255 };
8256
8257 Canvas.prototype._setParent = function(element, parent, parentIndex) {
8258 add(parent.children, element, parentIndex);
8259 element.parent = parent;
8260 };
8261
8262 /**
8263 * Adds an element to the canvas.
8264 *
8265 * This wires the parent <-> child relationship between the element and
8266 * a explicitly specified parent or an implicit root element.
8267 *
8268 * During add it emits the events
8269 *
8270 * * <{type}.add> (element, parent)
8271 * * <{type}.added> (element, gfx)
8272 *
8273 * Extensions may hook into these events to perform their magic.
8274 *
8275 * @param {string} type
8276 * @param {Object|djs.model.Base} element
8277 * @param {Object|djs.model.Base} [parent]
8278 * @param {number} [parentIndex]
8279 *
8280 * @return {Object|djs.model.Base} the added element
8281 */
8282 Canvas.prototype._addElement = function(type, element, parent, parentIndex) {
8283
8284 parent = parent || this.getRootElement();
8285
8286 var eventBus = this._eventBus,
8287 graphicsFactory = this._graphicsFactory;
8288
8289 this._ensureValid(type, element);
8290
8291 eventBus.fire(type + '.add', { element: element, parent: parent });
8292
8293 this._setParent(element, parent, parentIndex);
8294
8295 // create graphics
8296 var gfx = graphicsFactory.create(type, element, parentIndex);
8297
8298 this._elementRegistry.add(element, gfx);
8299
8300 // update its visual
8301 graphicsFactory.update(type, element, gfx);
8302
8303 eventBus.fire(type + '.added', { element: element, gfx: gfx });
8304
8305 return element;
8306 };
8307
8308 /**
8309 * Adds a shape to the canvas
8310 *
8311 * @param {Object|djs.model.Shape} shape to add to the diagram
8312 * @param {djs.model.Base} [parent]
8313 * @param {number} [parentIndex]
8314 *
8315 * @return {djs.model.Shape} the added shape
8316 */
8317 Canvas.prototype.addShape = function(shape, parent, parentIndex) {
8318 return this._addElement('shape', shape, parent, parentIndex);
8319 };
8320
8321 /**
8322 * Adds a connection to the canvas
8323 *
8324 * @param {Object|djs.model.Connection} connection to add to the diagram
8325 * @param {djs.model.Base} [parent]
8326 * @param {number} [parentIndex]
8327 *
8328 * @return {djs.model.Connection} the added connection
8329 */
8330 Canvas.prototype.addConnection = function(connection, parent, parentIndex) {
8331 return this._addElement('connection', connection, parent, parentIndex);
8332 };
8333
8334
8335 /**
8336 * Internal remove element
8337 */
8338 Canvas.prototype._removeElement = function(element, type) {
8339
8340 var elementRegistry = this._elementRegistry,
8341 graphicsFactory = this._graphicsFactory,
8342 eventBus = this._eventBus;
8343
8344 element = elementRegistry.get(element.id || element);
8345
8346 if (!element) {
8347
8348 // element was removed already
8349 return;
8350 }
8351
8352 eventBus.fire(type + '.remove', { element: element });
8353
8354 graphicsFactory.remove(element);
8355
8356 // unset parent <-> child relationship
8357 remove$2(element.parent && element.parent.children, element);
8358 element.parent = null;
8359
8360 eventBus.fire(type + '.removed', { element: element });
8361
8362 elementRegistry.remove(element);
8363
8364 return element;
8365 };
8366
8367
8368 /**
8369 * Removes a shape from the canvas
8370 *
8371 * @param {string|djs.model.Shape} shape or shape id to be removed
8372 *
8373 * @return {djs.model.Shape} the removed shape
8374 */
8375 Canvas.prototype.removeShape = function(shape) {
8376
8377 /**
8378 * An event indicating that a shape is about to be removed from the canvas.
8379 *
8380 * @memberOf Canvas
8381 *
8382 * @event shape.remove
8383 * @type {Object}
8384 * @property {djs.model.Shape} element the shape descriptor
8385 * @property {Object} gfx the graphical representation of the shape
8386 */
8387
8388 /**
8389 * An event indicating that a shape has been removed from the canvas.
8390 *
8391 * @memberOf Canvas
8392 *
8393 * @event shape.removed
8394 * @type {Object}
8395 * @property {djs.model.Shape} element the shape descriptor
8396 * @property {Object} gfx the graphical representation of the shape
8397 */
8398 return this._removeElement(shape, 'shape');
8399 };
8400
8401
8402 /**
8403 * Removes a connection from the canvas
8404 *
8405 * @param {string|djs.model.Connection} connection or connection id to be removed
8406 *
8407 * @return {djs.model.Connection} the removed connection
8408 */
8409 Canvas.prototype.removeConnection = function(connection) {
8410
8411 /**
8412 * An event indicating that a connection is about to be removed from the canvas.
8413 *
8414 * @memberOf Canvas
8415 *
8416 * @event connection.remove
8417 * @type {Object}
8418 * @property {djs.model.Connection} element the connection descriptor
8419 * @property {Object} gfx the graphical representation of the connection
8420 */
8421
8422 /**
8423 * An event indicating that a connection has been removed from the canvas.
8424 *
8425 * @memberOf Canvas
8426 *
8427 * @event connection.removed
8428 * @type {Object}
8429 * @property {djs.model.Connection} element the connection descriptor
8430 * @property {Object} gfx the graphical representation of the connection
8431 */
8432 return this._removeElement(connection, 'connection');
8433 };
8434
8435
8436 /**
8437 * Return the graphical object underlaying a certain diagram element
8438 *
8439 * @param {string|djs.model.Base} element descriptor of the element
8440 * @param {boolean} [secondary=false] whether to return the secondary connected element
8441 *
8442 * @return {SVGElement}
8443 */
8444 Canvas.prototype.getGraphics = function(element, secondary) {
8445 return this._elementRegistry.getGraphics(element, secondary);
8446 };
8447
8448
8449 /**
8450 * Perform a viewbox update via a given change function.
8451 *
8452 * @param {Function} changeFn
8453 */
8454 Canvas.prototype._changeViewbox = function(changeFn) {
8455
8456 // notify others of the upcoming viewbox change
8457 this._eventBus.fire('canvas.viewbox.changing');
8458
8459 // perform actual change
8460 changeFn.apply(this);
8461
8462 // reset the cached viewbox so that
8463 // a new get operation on viewbox or zoom
8464 // triggers a viewbox re-computation
8465 this._cachedViewbox = null;
8466
8467 // notify others of the change; this step
8468 // may or may not be debounced
8469 this._viewboxChanged();
8470 };
8471
8472 Canvas.prototype._viewboxChanged = function() {
8473 this._eventBus.fire('canvas.viewbox.changed', { viewbox: this.viewbox() });
8474 };
8475
8476
8477 /**
8478 * Gets or sets the view box of the canvas, i.e. the
8479 * area that is currently displayed.
8480 *
8481 * The getter may return a cached viewbox (if it is currently
8482 * changing). To force a recomputation, pass `false` as the first argument.
8483 *
8484 * @example
8485 *
8486 * canvas.viewbox({ x: 100, y: 100, width: 500, height: 500 })
8487 *
8488 * // sets the visible area of the diagram to (100|100) -> (600|100)
8489 * // and and scales it according to the diagram width
8490 *
8491 * var viewbox = canvas.viewbox(); // pass `false` to force recomputing the box.
8492 *
8493 * console.log(viewbox);
8494 * // {
8495 * // inner: Dimensions,
8496 * // outer: Dimensions,
8497 * // scale,
8498 * // x, y,
8499 * // width, height
8500 * // }
8501 *
8502 * // if the current diagram is zoomed and scrolled, you may reset it to the
8503 * // default zoom via this method, too:
8504 *
8505 * var zoomedAndScrolledViewbox = canvas.viewbox();
8506 *
8507 * canvas.viewbox({
8508 * x: 0,
8509 * y: 0,
8510 * width: zoomedAndScrolledViewbox.outer.width,
8511 * height: zoomedAndScrolledViewbox.outer.height
8512 * });
8513 *
8514 * @param {Object} [box] the new view box to set
8515 * @param {number} box.x the top left X coordinate of the canvas visible in view box
8516 * @param {number} box.y the top left Y coordinate of the canvas visible in view box
8517 * @param {number} box.width the visible width
8518 * @param {number} box.height
8519 *
8520 * @return {Object} the current view box
8521 */
8522 Canvas.prototype.viewbox = function(box) {
8523
8524 if (box === undefined && this._cachedViewbox) {
8525 return this._cachedViewbox;
8526 }
8527
8528 var viewport = this._viewport,
8529 innerBox,
8530 outerBox = this.getSize(),
8531 matrix,
8532 transform$1,
8533 scale,
8534 x, y;
8535
8536 if (!box) {
8537
8538 // compute the inner box based on the
8539 // diagrams default layer. This allows us to exclude
8540 // external components, such as overlays
8541 innerBox = this.getDefaultLayer().getBBox();
8542
8543 transform$1 = transform(viewport);
8544 matrix = transform$1 ? transform$1.matrix : createMatrix();
8545 scale = round(matrix.a, 1000);
8546
8547 x = round(-matrix.e || 0, 1000);
8548 y = round(-matrix.f || 0, 1000);
8549
8550 box = this._cachedViewbox = {
8551 x: x ? x / scale : 0,
8552 y: y ? y / scale : 0,
8553 width: outerBox.width / scale,
8554 height: outerBox.height / scale,
8555 scale: scale,
8556 inner: {
8557 width: innerBox.width,
8558 height: innerBox.height,
8559 x: innerBox.x,
8560 y: innerBox.y
8561 },
8562 outer: outerBox
8563 };
8564
8565 return box;
8566 } else {
8567
8568 this._changeViewbox(function() {
8569 scale = Math.min(outerBox.width / box.width, outerBox.height / box.height);
8570
8571 var matrix = this._svg.createSVGMatrix()
8572 .scale(scale)
8573 .translate(-box.x, -box.y);
8574
8575 transform(viewport, matrix);
8576 });
8577 }
8578
8579 return box;
8580 };
8581
8582
8583 /**
8584 * Gets or sets the scroll of the canvas.
8585 *
8586 * @param {Object} [delta] the new scroll to apply.
8587 *
8588 * @param {number} [delta.dx]
8589 * @param {number} [delta.dy]
8590 */
8591 Canvas.prototype.scroll = function(delta) {
8592
8593 var node = this._viewport;
8594 var matrix = node.getCTM();
8595
8596 if (delta) {
8597 this._changeViewbox(function() {
8598 delta = assign({ dx: 0, dy: 0 }, delta || {});
8599
8600 matrix = this._svg.createSVGMatrix().translate(delta.dx, delta.dy).multiply(matrix);
8601
8602 setCTM(node, matrix);
8603 });
8604 }
8605
8606 return { x: matrix.e, y: matrix.f };
8607 };
8608
8609
8610 /**
8611 * Gets or sets the current zoom of the canvas, optionally zooming
8612 * to the specified position.
8613 *
8614 * The getter may return a cached zoom level. Call it with `false` as
8615 * the first argument to force recomputation of the current level.
8616 *
8617 * @param {string|number} [newScale] the new zoom level, either a number, i.e. 0.9,
8618 * or `fit-viewport` to adjust the size to fit the current viewport
8619 * @param {string|Point} [center] the reference point { x: .., y: ..} to zoom to, 'auto' to zoom into mid or null
8620 *
8621 * @return {number} the current scale
8622 */
8623 Canvas.prototype.zoom = function(newScale, center) {
8624
8625 if (!newScale) {
8626 return this.viewbox(newScale).scale;
8627 }
8628
8629 if (newScale === 'fit-viewport') {
8630 return this._fitViewport(center);
8631 }
8632
8633 var outer,
8634 matrix;
8635
8636 this._changeViewbox(function() {
8637
8638 if (typeof center !== 'object') {
8639 outer = this.viewbox().outer;
8640
8641 center = {
8642 x: outer.width / 2,
8643 y: outer.height / 2
8644 };
8645 }
8646
8647 matrix = this._setZoom(newScale, center);
8648 });
8649
8650 return round(matrix.a, 1000);
8651 };
8652
8653 function setCTM(node, m) {
8654 var mstr = 'matrix(' + m.a + ',' + m.b + ',' + m.c + ',' + m.d + ',' + m.e + ',' + m.f + ')';
8655 node.setAttribute('transform', mstr);
8656 }
8657
8658 Canvas.prototype._fitViewport = function(center) {
8659
8660 var vbox = this.viewbox(),
8661 outer = vbox.outer,
8662 inner = vbox.inner,
8663 newScale,
8664 newViewbox;
8665
8666 // display the complete diagram without zooming in.
8667 // instead of relying on internal zoom, we perform a
8668 // hard reset on the canvas viewbox to realize this
8669 //
8670 // if diagram does not need to be zoomed in, we focus it around
8671 // the diagram origin instead
8672
8673 if (inner.x >= 0 &&
8674 inner.y >= 0 &&
8675 inner.x + inner.width <= outer.width &&
8676 inner.y + inner.height <= outer.height &&
8677 !center) {
8678
8679 newViewbox = {
8680 x: 0,
8681 y: 0,
8682 width: Math.max(inner.width + inner.x, outer.width),
8683 height: Math.max(inner.height + inner.y, outer.height)
8684 };
8685 } else {
8686
8687 newScale = Math.min(1, outer.width / inner.width, outer.height / inner.height);
8688 newViewbox = {
8689 x: inner.x + (center ? inner.width / 2 - outer.width / newScale / 2 : 0),
8690 y: inner.y + (center ? inner.height / 2 - outer.height / newScale / 2 : 0),
8691 width: outer.width / newScale,
8692 height: outer.height / newScale
8693 };
8694 }
8695
8696 this.viewbox(newViewbox);
8697
8698 return this.viewbox(false).scale;
8699 };
8700
8701
8702 Canvas.prototype._setZoom = function(scale, center) {
8703
8704 var svg = this._svg,
8705 viewport = this._viewport;
8706
8707 var matrix = svg.createSVGMatrix();
8708 var point = svg.createSVGPoint();
8709
8710 var centerPoint,
8711 originalPoint,
8712 currentMatrix,
8713 scaleMatrix,
8714 newMatrix;
8715
8716 currentMatrix = viewport.getCTM();
8717
8718 var currentScale = currentMatrix.a;
8719
8720 if (center) {
8721 centerPoint = assign(point, center);
8722
8723 // revert applied viewport transformations
8724 originalPoint = centerPoint.matrixTransform(currentMatrix.inverse());
8725
8726 // create scale matrix
8727 scaleMatrix = matrix
8728 .translate(originalPoint.x, originalPoint.y)
8729 .scale(1 / currentScale * scale)
8730 .translate(-originalPoint.x, -originalPoint.y);
8731
8732 newMatrix = currentMatrix.multiply(scaleMatrix);
8733 } else {
8734 newMatrix = matrix.scale(scale);
8735 }
8736
8737 setCTM(this._viewport, newMatrix);
8738
8739 return newMatrix;
8740 };
8741
8742
8743 /**
8744 * Returns the size of the canvas
8745 *
8746 * @return {Dimensions}
8747 */
8748 Canvas.prototype.getSize = function() {
8749 return {
8750 width: this._container.clientWidth,
8751 height: this._container.clientHeight
8752 };
8753 };
8754
8755
8756 /**
8757 * Return the absolute bounding box for the given element
8758 *
8759 * The absolute bounding box may be used to display overlays in the
8760 * callers (browser) coordinate system rather than the zoomed in/out
8761 * canvas coordinates.
8762 *
8763 * @param {ElementDescriptor} element
8764 * @return {Bounds} the absolute bounding box
8765 */
8766 Canvas.prototype.getAbsoluteBBox = function(element) {
8767 var vbox = this.viewbox();
8768 var bbox;
8769
8770 // connection
8771 // use svg bbox
8772 if (element.waypoints) {
8773 var gfx = this.getGraphics(element);
8774
8775 bbox = gfx.getBBox();
8776 }
8777
8778 // shapes
8779 // use data
8780 else {
8781 bbox = element;
8782 }
8783
8784 var x = bbox.x * vbox.scale - vbox.x * vbox.scale;
8785 var y = bbox.y * vbox.scale - vbox.y * vbox.scale;
8786
8787 var width = bbox.width * vbox.scale;
8788 var height = bbox.height * vbox.scale;
8789
8790 return {
8791 x: x,
8792 y: y,
8793 width: width,
8794 height: height
8795 };
8796 };
8797
8798 /**
8799 * Fires an event in order other modules can react to the
8800 * canvas resizing
8801 */
8802 Canvas.prototype.resized = function() {
8803
8804 // force recomputation of view box
8805 delete this._cachedViewbox;
8806
8807 this._eventBus.fire('canvas.resized');
8808 };
8809
8810 var ELEMENT_ID = 'data-element-id';
8811
8812
8813 /**
8814 * @class
8815 *
8816 * A registry that keeps track of all shapes in the diagram.
8817 */
8818 function ElementRegistry(eventBus) {
8819 this._elements = {};
8820
8821 this._eventBus = eventBus;
8822 }
8823
8824 ElementRegistry.$inject = [ 'eventBus' ];
8825
8826 /**
8827 * Register a pair of (element, gfx, (secondaryGfx)).
8828 *
8829 * @param {djs.model.Base} element
8830 * @param {SVGElement} gfx
8831 * @param {SVGElement} [secondaryGfx] optional other element to register, too
8832 */
8833 ElementRegistry.prototype.add = function(element, gfx, secondaryGfx) {
8834
8835 var id = element.id;
8836
8837 this._validateId(id);
8838
8839 // associate dom node with element
8840 attr(gfx, ELEMENT_ID, id);
8841
8842 if (secondaryGfx) {
8843 attr(secondaryGfx, ELEMENT_ID, id);
8844 }
8845
8846 this._elements[id] = { element: element, gfx: gfx, secondaryGfx: secondaryGfx };
8847 };
8848
8849 /**
8850 * Removes an element from the registry.
8851 *
8852 * @param {djs.model.Base} element
8853 */
8854 ElementRegistry.prototype.remove = function(element) {
8855 var elements = this._elements,
8856 id = element.id || element,
8857 container = id && elements[id];
8858
8859 if (container) {
8860
8861 // unset element id on gfx
8862 attr(container.gfx, ELEMENT_ID, '');
8863
8864 if (container.secondaryGfx) {
8865 attr(container.secondaryGfx, ELEMENT_ID, '');
8866 }
8867
8868 delete elements[id];
8869 }
8870 };
8871
8872 /**
8873 * Update the id of an element
8874 *
8875 * @param {djs.model.Base} element
8876 * @param {string} newId
8877 */
8878 ElementRegistry.prototype.updateId = function(element, newId) {
8879
8880 this._validateId(newId);
8881
8882 if (typeof element === 'string') {
8883 element = this.get(element);
8884 }
8885
8886 this._eventBus.fire('element.updateId', {
8887 element: element,
8888 newId: newId
8889 });
8890
8891 var gfx = this.getGraphics(element),
8892 secondaryGfx = this.getGraphics(element, true);
8893
8894 this.remove(element);
8895
8896 element.id = newId;
8897
8898 this.add(element, gfx, secondaryGfx);
8899 };
8900
8901 /**
8902 * Return the model element for a given id or graphics.
8903 *
8904 * @example
8905 *
8906 * elementRegistry.get('SomeElementId_1');
8907 * elementRegistry.get(gfx);
8908 *
8909 *
8910 * @param {string|SVGElement} filter for selecting the element
8911 *
8912 * @return {djs.model.Base}
8913 */
8914 ElementRegistry.prototype.get = function(filter) {
8915 var id;
8916
8917 if (typeof filter === 'string') {
8918 id = filter;
8919 } else {
8920 id = filter && attr(filter, ELEMENT_ID);
8921 }
8922
8923 var container = this._elements[id];
8924 return container && container.element;
8925 };
8926
8927 /**
8928 * Return all elements that match a given filter function.
8929 *
8930 * @param {Function} fn
8931 *
8932 * @return {Array<djs.model.Base>}
8933 */
8934 ElementRegistry.prototype.filter = function(fn) {
8935
8936 var filtered = [];
8937
8938 this.forEach(function(element, gfx) {
8939 if (fn(element, gfx)) {
8940 filtered.push(element);
8941 }
8942 });
8943
8944 return filtered;
8945 };
8946
8947 /**
8948 * Return all rendered model elements.
8949 *
8950 * @return {Array<djs.model.Base>}
8951 */
8952 ElementRegistry.prototype.getAll = function() {
8953 return this.filter(function(e) { return e; });
8954 };
8955
8956 /**
8957 * Iterate over all diagram elements.
8958 *
8959 * @param {Function} fn
8960 */
8961 ElementRegistry.prototype.forEach = function(fn) {
8962
8963 var map = this._elements;
8964
8965 Object.keys(map).forEach(function(id) {
8966 var container = map[id],
8967 element = container.element,
8968 gfx = container.gfx;
8969
8970 return fn(element, gfx);
8971 });
8972 };
8973
8974 /**
8975 * Return the graphical representation of an element or its id.
8976 *
8977 * @example
8978 * elementRegistry.getGraphics('SomeElementId_1');
8979 * elementRegistry.getGraphics(rootElement); // <g ...>
8980 *
8981 * elementRegistry.getGraphics(rootElement, true); // <svg ...>
8982 *
8983 *
8984 * @param {string|djs.model.Base} filter
8985 * @param {boolean} [secondary=false] whether to return the secondary connected element
8986 *
8987 * @return {SVGElement}
8988 */
8989 ElementRegistry.prototype.getGraphics = function(filter, secondary) {
8990 var id = filter.id || filter;
8991
8992 var container = this._elements[id];
8993 return container && (secondary ? container.secondaryGfx : container.gfx);
8994 };
8995
8996 /**
8997 * Validate the suitability of the given id and signals a problem
8998 * with an exception.
8999 *
9000 * @param {string} id
9001 *
9002 * @throws {Error} if id is empty or already assigned
9003 */
9004 ElementRegistry.prototype._validateId = function(id) {
9005 if (!id) {
9006 throw new Error('element must have an id');
9007 }
9008
9009 if (this._elements[id]) {
9010 throw new Error('element with id ' + id + ' already added');
9011 }
9012 };
9013
9014 /**
9015 * An empty collection stub. Use {@link RefsCollection.extend} to extend a
9016 * collection with ref semantics.
9017 *
9018 * @class RefsCollection
9019 */
9020
9021 /**
9022 * Extends a collection with {@link Refs} aware methods
9023 *
9024 * @memberof RefsCollection
9025 * @static
9026 *
9027 * @param {Array<Object>} collection
9028 * @param {Refs} refs instance
9029 * @param {Object} property represented by the collection
9030 * @param {Object} target object the collection is attached to
9031 *
9032 * @return {RefsCollection<Object>} the extended array
9033 */
9034 function extend$1(collection, refs, property, target) {
9035
9036 var inverseProperty = property.inverse;
9037
9038 /**
9039 * Removes the given element from the array and returns it.
9040 *
9041 * @method RefsCollection#remove
9042 *
9043 * @param {Object} element the element to remove
9044 */
9045 Object.defineProperty(collection, 'remove', {
9046 value: function(element) {
9047 var idx = this.indexOf(element);
9048 if (idx !== -1) {
9049 this.splice(idx, 1);
9050
9051 // unset inverse
9052 refs.unset(element, inverseProperty, target);
9053 }
9054
9055 return element;
9056 }
9057 });
9058
9059 /**
9060 * Returns true if the collection contains the given element
9061 *
9062 * @method RefsCollection#contains
9063 *
9064 * @param {Object} element the element to check for
9065 */
9066 Object.defineProperty(collection, 'contains', {
9067 value: function(element) {
9068 return this.indexOf(element) !== -1;
9069 }
9070 });
9071
9072 /**
9073 * Adds an element to the array, unless it exists already (set semantics).
9074 *
9075 * @method RefsCollection#add
9076 *
9077 * @param {Object} element the element to add
9078 * @param {Number} optional index to add element to
9079 * (possibly moving other elements around)
9080 */
9081 Object.defineProperty(collection, 'add', {
9082 value: function(element, idx) {
9083
9084 var currentIdx = this.indexOf(element);
9085
9086 if (typeof idx === 'undefined') {
9087
9088 if (currentIdx !== -1) {
9089 // element already in collection (!)
9090 return;
9091 }
9092
9093 // add to end of array, as no idx is specified
9094 idx = this.length;
9095 }
9096
9097 // handle already in collection
9098 if (currentIdx !== -1) {
9099
9100 // remove element from currentIdx
9101 this.splice(currentIdx, 1);
9102 }
9103
9104 // add element at idx
9105 this.splice(idx, 0, element);
9106
9107 if (currentIdx === -1) {
9108 // set inverse, unless element was
9109 // in collection already
9110 refs.set(element, inverseProperty, target);
9111 }
9112 }
9113 });
9114
9115 // a simple marker, identifying this element
9116 // as being a refs collection
9117 Object.defineProperty(collection, '__refs_collection', {
9118 value: true
9119 });
9120
9121 return collection;
9122 }
9123
9124
9125 function isExtended(collection) {
9126 return collection.__refs_collection === true;
9127 }
9128
9129 var extend_1 = extend$1;
9130
9131 var isExtended_1 = isExtended;
9132
9133 var collection = {
9134 extend: extend_1,
9135 isExtended: isExtended_1
9136 };
9137
9138 function hasOwnProperty(e, property) {
9139 return Object.prototype.hasOwnProperty.call(e, property.name || property);
9140 }
9141
9142 function defineCollectionProperty(ref, property, target) {
9143
9144 var collection$1 = collection.extend(target[property.name] || [], ref, property, target);
9145
9146 Object.defineProperty(target, property.name, {
9147 enumerable: property.enumerable,
9148 value: collection$1
9149 });
9150
9151 if (collection$1.length) {
9152
9153 collection$1.forEach(function(o) {
9154 ref.set(o, property.inverse, target);
9155 });
9156 }
9157 }
9158
9159
9160 function defineProperty(ref, property, target) {
9161
9162 var inverseProperty = property.inverse;
9163
9164 var _value = target[property.name];
9165
9166 Object.defineProperty(target, property.name, {
9167 configurable: property.configurable,
9168 enumerable: property.enumerable,
9169
9170 get: function() {
9171 return _value;
9172 },
9173
9174 set: function(value) {
9175
9176 // return if we already performed all changes
9177 if (value === _value) {
9178 return;
9179 }
9180
9181 var old = _value;
9182
9183 // temporary set null
9184 _value = null;
9185
9186 if (old) {
9187 ref.unset(old, inverseProperty, target);
9188 }
9189
9190 // set new value
9191 _value = value;
9192
9193 // set inverse value
9194 ref.set(_value, inverseProperty, target);
9195 }
9196 });
9197
9198 }
9199
9200 /**
9201 * Creates a new references object defining two inversly related
9202 * attribute descriptors a and b.
9203 *
9204 * <p>
9205 * When bound to an object using {@link Refs#bind} the references
9206 * get activated and ensure that add and remove operations are applied
9207 * reversely, too.
9208 * </p>
9209 *
9210 * <p>
9211 * For attributes represented as collections {@link Refs} provides the
9212 * {@link RefsCollection#add}, {@link RefsCollection#remove} and {@link RefsCollection#contains} extensions
9213 * that must be used to properly hook into the inverse change mechanism.
9214 * </p>
9215 *
9216 * @class Refs
9217 *
9218 * @classdesc A bi-directional reference between two attributes.
9219 *
9220 * @param {Refs.AttributeDescriptor} a property descriptor
9221 * @param {Refs.AttributeDescriptor} b property descriptor
9222 *
9223 * @example
9224 *
9225 * var refs = Refs({ name: 'wheels', collection: true, enumerable: true }, { name: 'car' });
9226 *
9227 * var car = { name: 'toyota' };
9228 * var wheels = [{ pos: 'front-left' }, { pos: 'front-right' }];
9229 *
9230 * refs.bind(car, 'wheels');
9231 *
9232 * car.wheels // []
9233 * car.wheels.add(wheels[0]);
9234 * car.wheels.add(wheels[1]);
9235 *
9236 * car.wheels // [{ pos: 'front-left' }, { pos: 'front-right' }]
9237 *
9238 * wheels[0].car // { name: 'toyota' };
9239 * car.wheels.remove(wheels[0]);
9240 *
9241 * wheels[0].car // undefined
9242 */
9243 function Refs(a, b) {
9244
9245 if (!(this instanceof Refs)) {
9246 return new Refs(a, b);
9247 }
9248
9249 // link
9250 a.inverse = b;
9251 b.inverse = a;
9252
9253 this.props = {};
9254 this.props[a.name] = a;
9255 this.props[b.name] = b;
9256 }
9257
9258 /**
9259 * Binds one side of a bi-directional reference to a
9260 * target object.
9261 *
9262 * @memberOf Refs
9263 *
9264 * @param {Object} target
9265 * @param {String} property
9266 */
9267 Refs.prototype.bind = function(target, property) {
9268 if (typeof property === 'string') {
9269 if (!this.props[property]) {
9270 throw new Error('no property <' + property + '> in ref');
9271 }
9272 property = this.props[property];
9273 }
9274
9275 if (property.collection) {
9276 defineCollectionProperty(this, property, target);
9277 } else {
9278 defineProperty(this, property, target);
9279 }
9280 };
9281
9282 Refs.prototype.ensureRefsCollection = function(target, property) {
9283
9284 var collection$1 = target[property.name];
9285
9286 if (!collection.isExtended(collection$1)) {
9287 defineCollectionProperty(this, property, target);
9288 }
9289
9290 return collection$1;
9291 };
9292
9293 Refs.prototype.ensureBound = function(target, property) {
9294 if (!hasOwnProperty(target, property)) {
9295 this.bind(target, property);
9296 }
9297 };
9298
9299 Refs.prototype.unset = function(target, property, value) {
9300
9301 if (target) {
9302 this.ensureBound(target, property);
9303
9304 if (property.collection) {
9305 this.ensureRefsCollection(target, property).remove(value);
9306 } else {
9307 target[property.name] = undefined;
9308 }
9309 }
9310 };
9311
9312 Refs.prototype.set = function(target, property, value) {
9313
9314 if (target) {
9315 this.ensureBound(target, property);
9316
9317 if (property.collection) {
9318 this.ensureRefsCollection(target, property).add(value);
9319 } else {
9320 target[property.name] = value;
9321 }
9322 }
9323 };
9324
9325 var refs = Refs;
9326
9327 var objectRefs = refs;
9328
9329 var Collection = collection;
9330 objectRefs.Collection = Collection;
9331
9332 var parentRefs = new objectRefs({ name: 'children', enumerable: true, collection: true }, { name: 'parent' }),
9333 labelRefs = new objectRefs({ name: 'labels', enumerable: true, collection: true }, { name: 'labelTarget' }),
9334 attacherRefs = new objectRefs({ name: 'attachers', collection: true }, { name: 'host' }),
9335 outgoingRefs = new objectRefs({ name: 'outgoing', collection: true }, { name: 'source' }),
9336 incomingRefs = new objectRefs({ name: 'incoming', collection: true }, { name: 'target' });
9337
9338 /**
9339 * @namespace djs.model
9340 */
9341
9342 /**
9343 * @memberOf djs.model
9344 */
9345
9346 /**
9347 * The basic graphical representation
9348 *
9349 * @class
9350 *
9351 * @abstract
9352 */
9353 function Base() {
9354
9355 /**
9356 * The object that backs up the shape
9357 *
9358 * @name Base#businessObject
9359 * @type Object
9360 */
9361 Object.defineProperty(this, 'businessObject', {
9362 writable: true
9363 });
9364
9365
9366 /**
9367 * Single label support, will mapped to multi label array
9368 *
9369 * @name Base#label
9370 * @type Object
9371 */
9372 Object.defineProperty(this, 'label', {
9373 get: function() {
9374 return this.labels[0];
9375 },
9376 set: function(newLabel) {
9377
9378 var label = this.label,
9379 labels = this.labels;
9380
9381 if (!newLabel && label) {
9382 labels.remove(label);
9383 } else {
9384 labels.add(newLabel, 0);
9385 }
9386 }
9387 });
9388
9389 /**
9390 * The parent shape
9391 *
9392 * @name Base#parent
9393 * @type Shape
9394 */
9395 parentRefs.bind(this, 'parent');
9396
9397 /**
9398 * The list of labels
9399 *
9400 * @name Base#labels
9401 * @type Label
9402 */
9403 labelRefs.bind(this, 'labels');
9404
9405 /**
9406 * The list of outgoing connections
9407 *
9408 * @name Base#outgoing
9409 * @type Array<Connection>
9410 */
9411 outgoingRefs.bind(this, 'outgoing');
9412
9413 /**
9414 * The list of incoming connections
9415 *
9416 * @name Base#incoming
9417 * @type Array<Connection>
9418 */
9419 incomingRefs.bind(this, 'incoming');
9420 }
9421
9422
9423 /**
9424 * A graphical object
9425 *
9426 * @class
9427 * @constructor
9428 *
9429 * @extends Base
9430 */
9431 function Shape() {
9432 Base.call(this);
9433
9434 /**
9435 * Indicates frame shapes
9436 *
9437 * @name Shape#isFrame
9438 * @type boolean
9439 */
9440
9441 /**
9442 * The list of children
9443 *
9444 * @name Shape#children
9445 * @type Array<Base>
9446 */
9447 parentRefs.bind(this, 'children');
9448
9449 /**
9450 * @name Shape#host
9451 * @type Shape
9452 */
9453 attacherRefs.bind(this, 'host');
9454
9455 /**
9456 * @name Shape#attachers
9457 * @type Shape
9458 */
9459 attacherRefs.bind(this, 'attachers');
9460 }
9461
9462 inherits_browser(Shape, Base);
9463
9464
9465 /**
9466 * A root graphical object
9467 *
9468 * @class
9469 * @constructor
9470 *
9471 * @extends Shape
9472 */
9473 function Root() {
9474 Shape.call(this);
9475 }
9476
9477 inherits_browser(Root, Shape);
9478
9479
9480 /**
9481 * A label for an element
9482 *
9483 * @class
9484 * @constructor
9485 *
9486 * @extends Shape
9487 */
9488 function Label() {
9489 Shape.call(this);
9490
9491 /**
9492 * The labeled element
9493 *
9494 * @name Label#labelTarget
9495 * @type Base
9496 */
9497 labelRefs.bind(this, 'labelTarget');
9498 }
9499
9500 inherits_browser(Label, Shape);
9501
9502
9503 /**
9504 * A connection between two elements
9505 *
9506 * @class
9507 * @constructor
9508 *
9509 * @extends Base
9510 */
9511 function Connection() {
9512 Base.call(this);
9513
9514 /**
9515 * The element this connection originates from
9516 *
9517 * @name Connection#source
9518 * @type Base
9519 */
9520 outgoingRefs.bind(this, 'source');
9521
9522 /**
9523 * The element this connection points to
9524 *
9525 * @name Connection#target
9526 * @type Base
9527 */
9528 incomingRefs.bind(this, 'target');
9529 }
9530
9531 inherits_browser(Connection, Base);
9532
9533
9534 var types = {
9535 connection: Connection,
9536 shape: Shape,
9537 label: Label,
9538 root: Root
9539 };
9540
9541 /**
9542 * Creates a new model element of the specified type
9543 *
9544 * @method create
9545 *
9546 * @example
9547 *
9548 * var shape1 = Model.create('shape', { x: 10, y: 10, width: 100, height: 100 });
9549 * var shape2 = Model.create('shape', { x: 210, y: 210, width: 100, height: 100 });
9550 *
9551 * var connection = Model.create('connection', { waypoints: [ { x: 110, y: 55 }, {x: 210, y: 55 } ] });
9552 *
9553 * @param {string} type lower-cased model name
9554 * @param {Object} attrs attributes to initialize the new model instance with
9555 *
9556 * @return {Base} the new model instance
9557 */
9558 function create$1(type, attrs) {
9559 var Type = types[type];
9560 if (!Type) {
9561 throw new Error('unknown type: <' + type + '>');
9562 }
9563 return assign(new Type(), attrs);
9564 }
9565
9566 /**
9567 * A factory for diagram-js shapes
9568 */
9569 function ElementFactory() {
9570 this._uid = 12;
9571 }
9572
9573
9574 ElementFactory.prototype.createRoot = function(attrs) {
9575 return this.create('root', attrs);
9576 };
9577
9578 ElementFactory.prototype.createLabel = function(attrs) {
9579 return this.create('label', attrs);
9580 };
9581
9582 ElementFactory.prototype.createShape = function(attrs) {
9583 return this.create('shape', attrs);
9584 };
9585
9586 ElementFactory.prototype.createConnection = function(attrs) {
9587 return this.create('connection', attrs);
9588 };
9589
9590 /**
9591 * Create a model element with the given type and
9592 * a number of pre-set attributes.
9593 *
9594 * @param {string} type
9595 * @param {Object} attrs
9596 * @return {djs.model.Base} the newly created model instance
9597 */
9598 ElementFactory.prototype.create = function(type, attrs) {
9599
9600 attrs = assign({}, attrs || {});
9601
9602 if (!attrs.id) {
9603 attrs.id = type + '_' + (this._uid++);
9604 }
9605
9606 return create$1(type, attrs);
9607 };
9608
9609 var FN_REF = '__fn';
9610
9611 var DEFAULT_PRIORITY = 1000;
9612
9613 var slice$1 = Array.prototype.slice;
9614
9615 /**
9616 * A general purpose event bus.
9617 *
9618 * This component is used to communicate across a diagram instance.
9619 * Other parts of a diagram can use it to listen to and broadcast events.
9620 *
9621 *
9622 * ## Registering for Events
9623 *
9624 * The event bus provides the {@link EventBus#on} and {@link EventBus#once}
9625 * methods to register for events. {@link EventBus#off} can be used to
9626 * remove event registrations. Listeners receive an instance of {@link Event}
9627 * as the first argument. It allows them to hook into the event execution.
9628 *
9629 * ```javascript
9630 *
9631 * // listen for event
9632 * eventBus.on('foo', function(event) {
9633 *
9634 * // access event type
9635 * event.type; // 'foo'
9636 *
9637 * // stop propagation to other listeners
9638 * event.stopPropagation();
9639 *
9640 * // prevent event default
9641 * event.preventDefault();
9642 * });
9643 *
9644 * // listen for event with custom payload
9645 * eventBus.on('bar', function(event, payload) {
9646 * console.log(payload);
9647 * });
9648 *
9649 * // listen for event returning value
9650 * eventBus.on('foobar', function(event) {
9651 *
9652 * // stop event propagation + prevent default
9653 * return false;
9654 *
9655 * // stop event propagation + return custom result
9656 * return {
9657 * complex: 'listening result'
9658 * };
9659 * });
9660 *
9661 *
9662 * // listen with custom priority (default=1000, higher is better)
9663 * eventBus.on('priorityfoo', 1500, function(event) {
9664 * console.log('invoked first!');
9665 * });
9666 *
9667 *
9668 * // listen for event and pass the context (`this`)
9669 * eventBus.on('foobar', function(event) {
9670 * this.foo();
9671 * }, this);
9672 * ```
9673 *
9674 *
9675 * ## Emitting Events
9676 *
9677 * Events can be emitted via the event bus using {@link EventBus#fire}.
9678 *
9679 * ```javascript
9680 *
9681 * // false indicates that the default action
9682 * // was prevented by listeners
9683 * if (eventBus.fire('foo') === false) {
9684 * console.log('default has been prevented!');
9685 * };
9686 *
9687 *
9688 * // custom args + return value listener
9689 * eventBus.on('sum', function(event, a, b) {
9690 * return a + b;
9691 * });
9692 *
9693 * // you can pass custom arguments + retrieve result values.
9694 * var sum = eventBus.fire('sum', 1, 2);
9695 * console.log(sum); // 3
9696 * ```
9697 */
9698 function EventBus() {
9699 this._listeners = {};
9700
9701 // cleanup on destroy on lowest priority to allow
9702 // message passing until the bitter end
9703 this.on('diagram.destroy', 1, this._destroy, this);
9704 }
9705
9706
9707 /**
9708 * Register an event listener for events with the given name.
9709 *
9710 * The callback will be invoked with `event, ...additionalArguments`
9711 * that have been passed to {@link EventBus#fire}.
9712 *
9713 * Returning false from a listener will prevent the events default action
9714 * (if any is specified). To stop an event from being processed further in
9715 * other listeners execute {@link Event#stopPropagation}.
9716 *
9717 * Returning anything but `undefined` from a listener will stop the listener propagation.
9718 *
9719 * @param {string|Array<string>} events
9720 * @param {number} [priority=1000] the priority in which this listener is called, larger is higher
9721 * @param {Function} callback
9722 * @param {Object} [that] Pass context (`this`) to the callback
9723 */
9724 EventBus.prototype.on = function(events, priority, callback, that) {
9725
9726 events = isArray(events) ? events : [ events ];
9727
9728 if (isFunction(priority)) {
9729 that = callback;
9730 callback = priority;
9731 priority = DEFAULT_PRIORITY;
9732 }
9733
9734 if (!isNumber(priority)) {
9735 throw new Error('priority must be a number');
9736 }
9737
9738 var actualCallback = callback;
9739
9740 if (that) {
9741 actualCallback = bind(callback, that);
9742
9743 // make sure we remember and are able to remove
9744 // bound callbacks via {@link #off} using the original
9745 // callback
9746 actualCallback[FN_REF] = callback[FN_REF] || callback;
9747 }
9748
9749 var self = this;
9750
9751 events.forEach(function(e) {
9752 self._addListener(e, {
9753 priority: priority,
9754 callback: actualCallback,
9755 next: null
9756 });
9757 });
9758 };
9759
9760
9761 /**
9762 * Register an event listener that is executed only once.
9763 *
9764 * @param {string} event the event name to register for
9765 * @param {number} [priority=1000] the priority in which this listener is called, larger is higher
9766 * @param {Function} callback the callback to execute
9767 * @param {Object} [that] Pass context (`this`) to the callback
9768 */
9769 EventBus.prototype.once = function(event, priority, callback, that) {
9770 var self = this;
9771
9772 if (isFunction(priority)) {
9773 that = callback;
9774 callback = priority;
9775 priority = DEFAULT_PRIORITY;
9776 }
9777
9778 if (!isNumber(priority)) {
9779 throw new Error('priority must be a number');
9780 }
9781
9782 function wrappedCallback() {
9783 var result = callback.apply(that, arguments);
9784
9785 self.off(event, wrappedCallback);
9786
9787 return result;
9788 }
9789
9790 // make sure we remember and are able to remove
9791 // bound callbacks via {@link #off} using the original
9792 // callback
9793 wrappedCallback[FN_REF] = callback;
9794
9795 this.on(event, priority, wrappedCallback);
9796 };
9797
9798
9799 /**
9800 * Removes event listeners by event and callback.
9801 *
9802 * If no callback is given, all listeners for a given event name are being removed.
9803 *
9804 * @param {string|Array<string>} events
9805 * @param {Function} [callback]
9806 */
9807 EventBus.prototype.off = function(events, callback) {
9808
9809 events = isArray(events) ? events : [ events ];
9810
9811 var self = this;
9812
9813 events.forEach(function(event) {
9814 self._removeListener(event, callback);
9815 });
9816
9817 };
9818
9819
9820 /**
9821 * Create an EventBus event.
9822 *
9823 * @param {Object} data
9824 *
9825 * @return {Object} event, recognized by the eventBus
9826 */
9827 EventBus.prototype.createEvent = function(data) {
9828 var event = new InternalEvent();
9829
9830 event.init(data);
9831
9832 return event;
9833 };
9834
9835
9836 /**
9837 * Fires a named event.
9838 *
9839 * @example
9840 *
9841 * // fire event by name
9842 * events.fire('foo');
9843 *
9844 * // fire event object with nested type
9845 * var event = { type: 'foo' };
9846 * events.fire(event);
9847 *
9848 * // fire event with explicit type
9849 * var event = { x: 10, y: 20 };
9850 * events.fire('element.moved', event);
9851 *
9852 * // pass additional arguments to the event
9853 * events.on('foo', function(event, bar) {
9854 * alert(bar);
9855 * });
9856 *
9857 * events.fire({ type: 'foo' }, 'I am bar!');
9858 *
9859 * @param {string} [name] the optional event name
9860 * @param {Object} [event] the event object
9861 * @param {...Object} additional arguments to be passed to the callback functions
9862 *
9863 * @return {boolean} the events return value, if specified or false if the
9864 * default action was prevented by listeners
9865 */
9866 EventBus.prototype.fire = function(type, data) {
9867 var event,
9868 firstListener,
9869 returnValue,
9870 args;
9871
9872 args = slice$1.call(arguments);
9873
9874 if (typeof type === 'object') {
9875 data = type;
9876 type = data.type;
9877 }
9878
9879 if (!type) {
9880 throw new Error('no event type specified');
9881 }
9882
9883 firstListener = this._listeners[type];
9884
9885 if (!firstListener) {
9886 return;
9887 }
9888
9889 // we make sure we fire instances of our home made
9890 // events here. We wrap them only once, though
9891 if (data instanceof InternalEvent) {
9892
9893 // we are fine, we alread have an event
9894 event = data;
9895 } else {
9896 event = this.createEvent(data);
9897 }
9898
9899 // ensure we pass the event as the first parameter
9900 args[0] = event;
9901
9902 // original event type (in case we delegate)
9903 var originalType = event.type;
9904
9905 // update event type before delegation
9906 if (type !== originalType) {
9907 event.type = type;
9908 }
9909
9910 try {
9911 returnValue = this._invokeListeners(event, args, firstListener);
9912 } finally {
9913
9914 // reset event type after delegation
9915 if (type !== originalType) {
9916 event.type = originalType;
9917 }
9918 }
9919
9920 // set the return value to false if the event default
9921 // got prevented and no other return value exists
9922 if (returnValue === undefined && event.defaultPrevented) {
9923 returnValue = false;
9924 }
9925
9926 return returnValue;
9927 };
9928
9929
9930 EventBus.prototype.handleError = function(error) {
9931 return this.fire('error', { error: error }) === false;
9932 };
9933
9934
9935 EventBus.prototype._destroy = function() {
9936 this._listeners = {};
9937 };
9938
9939 EventBus.prototype._invokeListeners = function(event, args, listener) {
9940
9941 var returnValue;
9942
9943 while (listener) {
9944
9945 // handle stopped propagation
9946 if (event.cancelBubble) {
9947 break;
9948 }
9949
9950 returnValue = this._invokeListener(event, args, listener);
9951
9952 listener = listener.next;
9953 }
9954
9955 return returnValue;
9956 };
9957
9958 EventBus.prototype._invokeListener = function(event, args, listener) {
9959
9960 var returnValue;
9961
9962 try {
9963
9964 // returning false prevents the default action
9965 returnValue = invokeFunction(listener.callback, args);
9966
9967 // stop propagation on return value
9968 if (returnValue !== undefined) {
9969 event.returnValue = returnValue;
9970 event.stopPropagation();
9971 }
9972
9973 // prevent default on return false
9974 if (returnValue === false) {
9975 event.preventDefault();
9976 }
9977 } catch (e) {
9978 if (!this.handleError(e)) {
9979 console.error('unhandled error in event listener');
9980 console.error(e.stack);
9981
9982 throw e;
9983 }
9984 }
9985
9986 return returnValue;
9987 };
9988
9989 /*
9990 * Add new listener with a certain priority to the list
9991 * of listeners (for the given event).
9992 *
9993 * The semantics of listener registration / listener execution are
9994 * first register, first serve: New listeners will always be inserted
9995 * after existing listeners with the same priority.
9996 *
9997 * Example: Inserting two listeners with priority 1000 and 1300
9998 *
9999 * * before: [ 1500, 1500, 1000, 1000 ]
10000 * * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ]
10001 *
10002 * @param {string} event
10003 * @param {Object} listener { priority, callback }
10004 */
10005 EventBus.prototype._addListener = function(event, newListener) {
10006
10007 var listener = this._getListeners(event),
10008 previousListener;
10009
10010 // no prior listeners
10011 if (!listener) {
10012 this._setListeners(event, newListener);
10013
10014 return;
10015 }
10016
10017 // ensure we order listeners by priority from
10018 // 0 (high) to n > 0 (low)
10019 while (listener) {
10020
10021 if (listener.priority < newListener.priority) {
10022
10023 newListener.next = listener;
10024
10025 if (previousListener) {
10026 previousListener.next = newListener;
10027 } else {
10028 this._setListeners(event, newListener);
10029 }
10030
10031 return;
10032 }
10033
10034 previousListener = listener;
10035 listener = listener.next;
10036 }
10037
10038 // add new listener to back
10039 previousListener.next = newListener;
10040 };
10041
10042
10043 EventBus.prototype._getListeners = function(name) {
10044 return this._listeners[name];
10045 };
10046
10047 EventBus.prototype._setListeners = function(name, listener) {
10048 this._listeners[name] = listener;
10049 };
10050
10051 EventBus.prototype._removeListener = function(event, callback) {
10052
10053 var listener = this._getListeners(event),
10054 nextListener,
10055 previousListener,
10056 listenerCallback;
10057
10058 if (!callback) {
10059
10060 // clear listeners
10061 this._setListeners(event, null);
10062
10063 return;
10064 }
10065
10066 while (listener) {
10067
10068 nextListener = listener.next;
10069
10070 listenerCallback = listener.callback;
10071
10072 if (listenerCallback === callback || listenerCallback[FN_REF] === callback) {
10073 if (previousListener) {
10074 previousListener.next = nextListener;
10075 } else {
10076
10077 // new first listener
10078 this._setListeners(event, nextListener);
10079 }
10080 }
10081
10082 previousListener = listener;
10083 listener = nextListener;
10084 }
10085 };
10086
10087 /**
10088 * A event that is emitted via the event bus.
10089 */
10090 function InternalEvent() { }
10091
10092 InternalEvent.prototype.stopPropagation = function() {
10093 this.cancelBubble = true;
10094 };
10095
10096 InternalEvent.prototype.preventDefault = function() {
10097 this.defaultPrevented = true;
10098 };
10099
10100 InternalEvent.prototype.init = function(data) {
10101 assign(this, data || {});
10102 };
10103
10104
10105 /**
10106 * Invoke function. Be fast...
10107 *
10108 * @param {Function} fn
10109 * @param {Array<Object>} args
10110 *
10111 * @return {Any}
10112 */
10113 function invokeFunction(fn, args) {
10114 return fn.apply(null, args);
10115 }
10116
10117 /**
10118 * SVGs for elements are generated by the {@link GraphicsFactory}.
10119 *
10120 * This utility gives quick access to the important semantic
10121 * parts of an element.
10122 */
10123
10124 /**
10125 * Returns the visual part of a diagram element
10126 *
10127 * @param {Snap<SVGElement>} gfx
10128 *
10129 * @return {Snap<SVGElement>}
10130 */
10131 function getVisual(gfx) {
10132 return gfx.childNodes[0];
10133 }
10134
10135 /**
10136 * Returns the children for a given diagram element.
10137 *
10138 * @param {Snap<SVGElement>} gfx
10139 * @return {Snap<SVGElement>}
10140 */
10141 function getChildren(gfx) {
10142 return gfx.parentNode.childNodes[1];
10143 }
10144
10145 /**
10146 * A factory that creates graphical elements
10147 *
10148 * @param {EventBus} eventBus
10149 * @param {ElementRegistry} elementRegistry
10150 */
10151 function GraphicsFactory(eventBus, elementRegistry) {
10152 this._eventBus = eventBus;
10153 this._elementRegistry = elementRegistry;
10154 }
10155
10156 GraphicsFactory.$inject = [ 'eventBus' , 'elementRegistry' ];
10157
10158
10159 GraphicsFactory.prototype._getChildrenContainer = function(element) {
10160
10161 var gfx = this._elementRegistry.getGraphics(element);
10162
10163 var childrenGfx;
10164
10165 // root element
10166 if (!element.parent) {
10167 childrenGfx = gfx;
10168 } else {
10169 childrenGfx = getChildren(gfx);
10170 if (!childrenGfx) {
10171 childrenGfx = create('g');
10172 classes(childrenGfx).add('djs-children');
10173
10174 append(gfx.parentNode, childrenGfx);
10175 }
10176 }
10177
10178 return childrenGfx;
10179 };
10180
10181 /**
10182 * Clears the graphical representation of the element and returns the
10183 * cleared visual (the <g class="djs-visual" /> element).
10184 */
10185 GraphicsFactory.prototype._clear = function(gfx) {
10186 var visual = getVisual(gfx);
10187
10188 clear$1(visual);
10189
10190 return visual;
10191 };
10192
10193 /**
10194 * Creates a gfx container for shapes and connections
10195 *
10196 * The layout is as follows:
10197 *
10198 * <g class="djs-group">
10199 *
10200 * <!-- the gfx -->
10201 * <g class="djs-element djs-(shape|connection|frame)">
10202 * <g class="djs-visual">
10203 * <!-- the renderer draws in here -->
10204 * </g>
10205 *
10206 * <!-- extensions (overlays, click box, ...) goes here
10207 * </g>
10208 *
10209 * <!-- the gfx child nodes -->
10210 * <g class="djs-children"></g>
10211 * </g>
10212 *
10213 * @param {string} type the type of the element, i.e. shape | connection
10214 * @param {SVGElement} [childrenGfx]
10215 * @param {number} [parentIndex] position to create container in parent
10216 * @param {boolean} [isFrame] is frame element
10217 *
10218 * @return {SVGElement}
10219 */
10220 GraphicsFactory.prototype._createContainer = function(
10221 type, childrenGfx, parentIndex, isFrame
10222 ) {
10223 var outerGfx = create('g');
10224 classes(outerGfx).add('djs-group');
10225
10226 // insert node at position
10227 if (typeof parentIndex !== 'undefined') {
10228 prependTo(outerGfx, childrenGfx, childrenGfx.childNodes[parentIndex]);
10229 } else {
10230 append(childrenGfx, outerGfx);
10231 }
10232
10233 var gfx = create('g');
10234 classes(gfx).add('djs-element');
10235 classes(gfx).add('djs-' + type);
10236
10237 if (isFrame) {
10238 classes(gfx).add('djs-frame');
10239 }
10240
10241 append(outerGfx, gfx);
10242
10243 // create visual
10244 var visual = create('g');
10245 classes(visual).add('djs-visual');
10246
10247 append(gfx, visual);
10248
10249 return gfx;
10250 };
10251
10252 GraphicsFactory.prototype.create = function(type, element, parentIndex) {
10253 var childrenGfx = this._getChildrenContainer(element.parent);
10254 return this._createContainer(type, childrenGfx, parentIndex, isFrameElement$1(element));
10255 };
10256
10257 GraphicsFactory.prototype.updateContainments = function(elements) {
10258
10259 var self = this,
10260 elementRegistry = this._elementRegistry,
10261 parents;
10262
10263 parents = reduce(elements, function(map, e) {
10264
10265 if (e.parent) {
10266 map[e.parent.id] = e.parent;
10267 }
10268
10269 return map;
10270 }, {});
10271
10272 // update all parents of changed and reorganized their children
10273 // in the correct order (as indicated in our model)
10274 forEach(parents, function(parent) {
10275
10276 var children = parent.children;
10277
10278 if (!children) {
10279 return;
10280 }
10281
10282 var childrenGfx = self._getChildrenContainer(parent);
10283
10284 forEach(children.slice().reverse(), function(child) {
10285 var childGfx = elementRegistry.getGraphics(child);
10286
10287 prependTo(childGfx.parentNode, childrenGfx);
10288 });
10289 });
10290 };
10291
10292 GraphicsFactory.prototype.drawShape = function(visual, element) {
10293 var eventBus = this._eventBus;
10294
10295 return eventBus.fire('render.shape', { gfx: visual, element: element });
10296 };
10297
10298 GraphicsFactory.prototype.getShapePath = function(element) {
10299 var eventBus = this._eventBus;
10300
10301 return eventBus.fire('render.getShapePath', element);
10302 };
10303
10304 GraphicsFactory.prototype.drawConnection = function(visual, element) {
10305 var eventBus = this._eventBus;
10306
10307 return eventBus.fire('render.connection', { gfx: visual, element: element });
10308 };
10309
10310 GraphicsFactory.prototype.getConnectionPath = function(waypoints) {
10311 var eventBus = this._eventBus;
10312
10313 return eventBus.fire('render.getConnectionPath', waypoints);
10314 };
10315
10316 GraphicsFactory.prototype.update = function(type, element, gfx) {
10317
10318 // do NOT update root element
10319 if (!element.parent) {
10320 return;
10321 }
10322
10323 var visual = this._clear(gfx);
10324
10325 // redraw
10326 if (type === 'shape') {
10327 this.drawShape(visual, element);
10328
10329 // update positioning
10330 translate(gfx, element.x, element.y);
10331 } else
10332 if (type === 'connection') {
10333 this.drawConnection(visual, element);
10334 } else {
10335 throw new Error('unknown type: ' + type);
10336 }
10337
10338 if (element.hidden) {
10339 attr(gfx, 'display', 'none');
10340 } else {
10341 attr(gfx, 'display', 'block');
10342 }
10343 };
10344
10345 GraphicsFactory.prototype.remove = function(element) {
10346 var gfx = this._elementRegistry.getGraphics(element);
10347
10348 // remove
10349 remove(gfx.parentNode);
10350 };
10351
10352
10353 // helpers //////////
10354
10355 function prependTo(newNode, parentNode, siblingNode) {
10356 var node = siblingNode || parentNode.firstChild;
10357
10358 // do not prepend node to itself to prevent IE from crashing
10359 // https://github.com/bpmn-io/bpmn-js/issues/746
10360 if (newNode === node) {
10361 return;
10362 }
10363
10364 parentNode.insertBefore(newNode, node);
10365 }
10366
10367 var CoreModule$1 = {
10368 __depends__: [ DrawModule$1 ],
10369 __init__: [ 'canvas' ],
10370 canvas: [ 'type', Canvas ],
10371 elementRegistry: [ 'type', ElementRegistry ],
10372 elementFactory: [ 'type', ElementFactory ],
10373 eventBus: [ 'type', EventBus ],
10374 graphicsFactory: [ 'type', GraphicsFactory ]
10375 };
10376
10377 /**
10378 * Bootstrap an injector from a list of modules, instantiating a number of default components
10379 *
10380 * @ignore
10381 * @param {Array<didi.Module>} bootstrapModules
10382 *
10383 * @return {didi.Injector} a injector to use to access the components
10384 */
10385 function bootstrap(bootstrapModules) {
10386
10387 var modules = [],
10388 components = [];
10389
10390 function hasModule(m) {
10391 return modules.indexOf(m) >= 0;
10392 }
10393
10394 function addModule(m) {
10395 modules.push(m);
10396 }
10397
10398 function visit(m) {
10399 if (hasModule(m)) {
10400 return;
10401 }
10402
10403 (m.__depends__ || []).forEach(visit);
10404
10405 if (hasModule(m)) {
10406 return;
10407 }
10408
10409 addModule(m);
10410
10411 (m.__init__ || []).forEach(function(c) {
10412 components.push(c);
10413 });
10414 }
10415
10416 bootstrapModules.forEach(visit);
10417
10418 var injector = new Injector(modules);
10419
10420 components.forEach(function(c) {
10421
10422 try {
10423
10424 // eagerly resolve component (fn or string)
10425 injector[typeof c === 'string' ? 'get' : 'invoke'](c);
10426 } catch (e) {
10427 console.error('Failed to instantiate component');
10428 console.error(e.stack);
10429
10430 throw e;
10431 }
10432 });
10433
10434 return injector;
10435 }
10436
10437 /**
10438 * Creates an injector from passed options.
10439 *
10440 * @ignore
10441 * @param {Object} options
10442 * @return {didi.Injector}
10443 */
10444 function createInjector(options) {
10445
10446 options = options || {};
10447
10448 var configModule = {
10449 'config': ['value', options]
10450 };
10451
10452 var modules = [ configModule, CoreModule$1 ].concat(options.modules || []);
10453
10454 return bootstrap(modules);
10455 }
10456
10457
10458 /**
10459 * The main diagram-js entry point that bootstraps the diagram with the given
10460 * configuration.
10461 *
10462 * To register extensions with the diagram, pass them as Array<didi.Module> to the constructor.
10463 *
10464 * @class djs.Diagram
10465 * @memberOf djs
10466 * @constructor
10467 *
10468 * @example
10469 *
10470 * <caption>Creating a plug-in that logs whenever a shape is added to the canvas.</caption>
10471 *
10472 * // plug-in implemenentation
10473 * function MyLoggingPlugin(eventBus) {
10474 * eventBus.on('shape.added', function(event) {
10475 * console.log('shape ', event.shape, ' was added to the diagram');
10476 * });
10477 * }
10478 *
10479 * // export as module
10480 * export default {
10481 * __init__: [ 'myLoggingPlugin' ],
10482 * myLoggingPlugin: [ 'type', MyLoggingPlugin ]
10483 * };
10484 *
10485 *
10486 * // instantiate the diagram with the new plug-in
10487 *
10488 * import MyLoggingModule from 'path-to-my-logging-plugin';
10489 *
10490 * var diagram = new Diagram({
10491 * modules: [
10492 * MyLoggingModule
10493 * ]
10494 * });
10495 *
10496 * diagram.invoke([ 'canvas', function(canvas) {
10497 * // add shape to drawing canvas
10498 * canvas.addShape({ x: 10, y: 10 });
10499 * });
10500 *
10501 * // 'shape ... was added to the diagram' logged to console
10502 *
10503 * @param {Object} options
10504 * @param {Array<didi.Module>} [options.modules] external modules to instantiate with the diagram
10505 * @param {didi.Injector} [injector] an (optional) injector to bootstrap the diagram with
10506 */
10507 function Diagram(options, injector) {
10508
10509 // create injector unless explicitly specified
10510 this.injector = injector = injector || createInjector(options);
10511
10512 // API
10513
10514 /**
10515 * Resolves a diagram service
10516 *
10517 * @method Diagram#get
10518 *
10519 * @param {string} name the name of the diagram service to be retrieved
10520 * @param {boolean} [strict=true] if false, resolve missing services to null
10521 */
10522 this.get = injector.get;
10523
10524 /**
10525 * Executes a function into which diagram services are injected
10526 *
10527 * @method Diagram#invoke
10528 *
10529 * @param {Function|Object[]} fn the function to resolve
10530 * @param {Object} locals a number of locals to use to resolve certain dependencies
10531 */
10532 this.invoke = injector.invoke;
10533
10534 // init
10535
10536 // indicate via event
10537
10538
10539 /**
10540 * An event indicating that all plug-ins are loaded.
10541 *
10542 * Use this event to fire other events to interested plug-ins
10543 *
10544 * @memberOf Diagram
10545 *
10546 * @event diagram.init
10547 *
10548 * @example
10549 *
10550 * eventBus.on('diagram.init', function() {
10551 * eventBus.fire('my-custom-event', { foo: 'BAR' });
10552 * });
10553 *
10554 * @type {Object}
10555 */
10556 this.get('eventBus').fire('diagram.init');
10557 }
10558
10559
10560 /**
10561 * Destroys the diagram
10562 *
10563 * @method Diagram#destroy
10564 */
10565 Diagram.prototype.destroy = function() {
10566 this.get('eventBus').fire('diagram.destroy');
10567 };
10568
10569 /**
10570 * Clear the diagram, removing all contents.
10571 */
10572 Diagram.prototype.clear = function() {
10573 this.get('eventBus').fire('diagram.clear');
10574 };
10575
10576 /**
10577 * Moddle base element.
10578 */
10579 function Base$1() { }
10580
10581 Base$1.prototype.get = function(name) {
10582 return this.$model.properties.get(this, name);
10583 };
10584
10585 Base$1.prototype.set = function(name, value) {
10586 this.$model.properties.set(this, name, value);
10587 };
10588
10589 /**
10590 * A model element factory.
10591 *
10592 * @param {Moddle} model
10593 * @param {Properties} properties
10594 */
10595 function Factory(model, properties) {
10596 this.model = model;
10597 this.properties = properties;
10598 }
10599
10600
10601 Factory.prototype.createType = function(descriptor) {
10602
10603 var model = this.model;
10604
10605 var props = this.properties,
10606 prototype = Object.create(Base$1.prototype);
10607
10608 // initialize default values
10609 forEach(descriptor.properties, function(p) {
10610 if (!p.isMany && p.default !== undefined) {
10611 prototype[p.name] = p.default;
10612 }
10613 });
10614
10615 props.defineModel(prototype, model);
10616 props.defineDescriptor(prototype, descriptor);
10617
10618 var name = descriptor.ns.name;
10619
10620 /**
10621 * The new type constructor
10622 */
10623 function ModdleElement(attrs) {
10624 props.define(this, '$type', { value: name, enumerable: true });
10625 props.define(this, '$attrs', { value: {} });
10626 props.define(this, '$parent', { writable: true });
10627
10628 forEach(attrs, bind(function(val, key) {
10629 this.set(key, val);
10630 }, this));
10631 }
10632
10633 ModdleElement.prototype = prototype;
10634
10635 ModdleElement.hasType = prototype.$instanceOf = this.model.hasType;
10636
10637 // static links
10638 props.defineModel(ModdleElement, model);
10639 props.defineDescriptor(ModdleElement, descriptor);
10640
10641 return ModdleElement;
10642 };
10643
10644 /**
10645 * Built-in moddle types
10646 */
10647 var BUILTINS = {
10648 String: true,
10649 Boolean: true,
10650 Integer: true,
10651 Real: true,
10652 Element: true
10653 };
10654
10655 /**
10656 * Converters for built in types from string representations
10657 */
10658 var TYPE_CONVERTERS = {
10659 String: function(s) { return s; },
10660 Boolean: function(s) { return s === 'true'; },
10661 Integer: function(s) { return parseInt(s, 10); },
10662 Real: function(s) { return parseFloat(s, 10); }
10663 };
10664
10665 /**
10666 * Convert a type to its real representation
10667 */
10668 function coerceType(type, value) {
10669
10670 var converter = TYPE_CONVERTERS[type];
10671
10672 if (converter) {
10673 return converter(value);
10674 } else {
10675 return value;
10676 }
10677 }
10678
10679 /**
10680 * Return whether the given type is built-in
10681 */
10682 function isBuiltIn(type) {
10683 return !!BUILTINS[type];
10684 }
10685
10686 /**
10687 * Return whether the given type is simple
10688 */
10689 function isSimple(type) {
10690 return !!TYPE_CONVERTERS[type];
10691 }
10692
10693 /**
10694 * Parses a namespaced attribute name of the form (ns:)localName to an object,
10695 * given a default prefix to assume in case no explicit namespace is given.
10696 *
10697 * @param {String} name
10698 * @param {String} [defaultPrefix] the default prefix to take, if none is present.
10699 *
10700 * @return {Object} the parsed name
10701 */
10702 function parseName(name, defaultPrefix) {
10703 var parts = name.split(/:/),
10704 localName, prefix;
10705
10706 // no prefix (i.e. only local name)
10707 if (parts.length === 1) {
10708 localName = name;
10709 prefix = defaultPrefix;
10710 } else
10711 // prefix + local name
10712 if (parts.length === 2) {
10713 localName = parts[1];
10714 prefix = parts[0];
10715 } else {
10716 throw new Error('expected <prefix:localName> or <localName>, got ' + name);
10717 }
10718
10719 name = (prefix ? prefix + ':' : '') + localName;
10720
10721 return {
10722 name: name,
10723 prefix: prefix,
10724 localName: localName
10725 };
10726 }
10727
10728 /**
10729 * A utility to build element descriptors.
10730 */
10731 function DescriptorBuilder(nameNs) {
10732 this.ns = nameNs;
10733 this.name = nameNs.name;
10734 this.allTypes = [];
10735 this.allTypesByName = {};
10736 this.properties = [];
10737 this.propertiesByName = {};
10738 }
10739
10740
10741 DescriptorBuilder.prototype.build = function() {
10742 return pick(this, [
10743 'ns',
10744 'name',
10745 'allTypes',
10746 'allTypesByName',
10747 'properties',
10748 'propertiesByName',
10749 'bodyProperty',
10750 'idProperty'
10751 ]);
10752 };
10753
10754 /**
10755 * Add property at given index.
10756 *
10757 * @param {Object} p
10758 * @param {Number} [idx]
10759 * @param {Boolean} [validate=true]
10760 */
10761 DescriptorBuilder.prototype.addProperty = function(p, idx, validate) {
10762
10763 if (typeof idx === 'boolean') {
10764 validate = idx;
10765 idx = undefined;
10766 }
10767
10768 this.addNamedProperty(p, validate !== false);
10769
10770 var properties = this.properties;
10771
10772 if (idx !== undefined) {
10773 properties.splice(idx, 0, p);
10774 } else {
10775 properties.push(p);
10776 }
10777 };
10778
10779
10780 DescriptorBuilder.prototype.replaceProperty = function(oldProperty, newProperty, replace) {
10781 var oldNameNs = oldProperty.ns;
10782
10783 var props = this.properties,
10784 propertiesByName = this.propertiesByName,
10785 rename = oldProperty.name !== newProperty.name;
10786
10787 if (oldProperty.isId) {
10788 if (!newProperty.isId) {
10789 throw new Error(
10790 'property <' + newProperty.ns.name + '> must be id property ' +
10791 'to refine <' + oldProperty.ns.name + '>');
10792 }
10793
10794 this.setIdProperty(newProperty, false);
10795 }
10796
10797 if (oldProperty.isBody) {
10798
10799 if (!newProperty.isBody) {
10800 throw new Error(
10801 'property <' + newProperty.ns.name + '> must be body property ' +
10802 'to refine <' + oldProperty.ns.name + '>');
10803 }
10804
10805 // TODO: Check compatibility
10806 this.setBodyProperty(newProperty, false);
10807 }
10808
10809 // validate existence and get location of old property
10810 var idx = props.indexOf(oldProperty);
10811 if (idx === -1) {
10812 throw new Error('property <' + oldNameNs.name + '> not found in property list');
10813 }
10814
10815 // remove old property
10816 props.splice(idx, 1);
10817
10818 // replacing the named property is intentional
10819 //
10820 // * validate only if this is a "rename" operation
10821 // * add at specific index unless we "replace"
10822 //
10823 this.addProperty(newProperty, replace ? undefined : idx, rename);
10824
10825 // make new property available under old name
10826 propertiesByName[oldNameNs.name] = propertiesByName[oldNameNs.localName] = newProperty;
10827 };
10828
10829
10830 DescriptorBuilder.prototype.redefineProperty = function(p, targetPropertyName, replace) {
10831
10832 var nsPrefix = p.ns.prefix;
10833 var parts = targetPropertyName.split('#');
10834
10835 var name = parseName(parts[0], nsPrefix);
10836 var attrName = parseName(parts[1], name.prefix).name;
10837
10838 var redefinedProperty = this.propertiesByName[attrName];
10839 if (!redefinedProperty) {
10840 throw new Error('refined property <' + attrName + '> not found');
10841 } else {
10842 this.replaceProperty(redefinedProperty, p, replace);
10843 }
10844
10845 delete p.redefines;
10846 };
10847
10848 DescriptorBuilder.prototype.addNamedProperty = function(p, validate) {
10849 var ns = p.ns,
10850 propsByName = this.propertiesByName;
10851
10852 if (validate) {
10853 this.assertNotDefined(p, ns.name);
10854 this.assertNotDefined(p, ns.localName);
10855 }
10856
10857 propsByName[ns.name] = propsByName[ns.localName] = p;
10858 };
10859
10860 DescriptorBuilder.prototype.removeNamedProperty = function(p) {
10861 var ns = p.ns,
10862 propsByName = this.propertiesByName;
10863
10864 delete propsByName[ns.name];
10865 delete propsByName[ns.localName];
10866 };
10867
10868 DescriptorBuilder.prototype.setBodyProperty = function(p, validate) {
10869
10870 if (validate && this.bodyProperty) {
10871 throw new Error(
10872 'body property defined multiple times ' +
10873 '(<' + this.bodyProperty.ns.name + '>, <' + p.ns.name + '>)');
10874 }
10875
10876 this.bodyProperty = p;
10877 };
10878
10879 DescriptorBuilder.prototype.setIdProperty = function(p, validate) {
10880
10881 if (validate && this.idProperty) {
10882 throw new Error(
10883 'id property defined multiple times ' +
10884 '(<' + this.idProperty.ns.name + '>, <' + p.ns.name + '>)');
10885 }
10886
10887 this.idProperty = p;
10888 };
10889
10890 DescriptorBuilder.prototype.assertNotDefined = function(p, name) {
10891 var propertyName = p.name,
10892 definedProperty = this.propertiesByName[propertyName];
10893
10894 if (definedProperty) {
10895 throw new Error(
10896 'property <' + propertyName + '> already defined; ' +
10897 'override of <' + definedProperty.definedBy.ns.name + '#' + definedProperty.ns.name + '> by ' +
10898 '<' + p.definedBy.ns.name + '#' + p.ns.name + '> not allowed without redefines');
10899 }
10900 };
10901
10902 DescriptorBuilder.prototype.hasProperty = function(name) {
10903 return this.propertiesByName[name];
10904 };
10905
10906 DescriptorBuilder.prototype.addTrait = function(t, inherited) {
10907
10908 var typesByName = this.allTypesByName,
10909 types = this.allTypes;
10910
10911 var typeName = t.name;
10912
10913 if (typeName in typesByName) {
10914 return;
10915 }
10916
10917 forEach(t.properties, bind(function(p) {
10918
10919 // clone property to allow extensions
10920 p = assign({}, p, {
10921 name: p.ns.localName,
10922 inherited: inherited
10923 });
10924
10925 Object.defineProperty(p, 'definedBy', {
10926 value: t
10927 });
10928
10929 var replaces = p.replaces,
10930 redefines = p.redefines;
10931
10932 // add replace/redefine support
10933 if (replaces || redefines) {
10934 this.redefineProperty(p, replaces || redefines, replaces);
10935 } else {
10936 if (p.isBody) {
10937 this.setBodyProperty(p);
10938 }
10939 if (p.isId) {
10940 this.setIdProperty(p);
10941 }
10942 this.addProperty(p);
10943 }
10944 }, this));
10945
10946 types.push(t);
10947 typesByName[typeName] = t;
10948 };
10949
10950 /**
10951 * A registry of Moddle packages.
10952 *
10953 * @param {Array<Package>} packages
10954 * @param {Properties} properties
10955 */
10956 function Registry(packages, properties) {
10957 this.packageMap = {};
10958 this.typeMap = {};
10959
10960 this.packages = [];
10961
10962 this.properties = properties;
10963
10964 forEach(packages, bind(this.registerPackage, this));
10965 }
10966
10967
10968 Registry.prototype.getPackage = function(uriOrPrefix) {
10969 return this.packageMap[uriOrPrefix];
10970 };
10971
10972 Registry.prototype.getPackages = function() {
10973 return this.packages;
10974 };
10975
10976
10977 Registry.prototype.registerPackage = function(pkg) {
10978
10979 // copy package
10980 pkg = assign({}, pkg);
10981
10982 var pkgMap = this.packageMap;
10983
10984 ensureAvailable(pkgMap, pkg, 'prefix');
10985 ensureAvailable(pkgMap, pkg, 'uri');
10986
10987 // register types
10988 forEach(pkg.types, bind(function(descriptor) {
10989 this.registerType(descriptor, pkg);
10990 }, this));
10991
10992 pkgMap[pkg.uri] = pkgMap[pkg.prefix] = pkg;
10993 this.packages.push(pkg);
10994 };
10995
10996
10997 /**
10998 * Register a type from a specific package with us
10999 */
11000 Registry.prototype.registerType = function(type, pkg) {
11001
11002 type = assign({}, type, {
11003 superClass: (type.superClass || []).slice(),
11004 extends: (type.extends || []).slice(),
11005 properties: (type.properties || []).slice(),
11006 meta: assign((type.meta || {}))
11007 });
11008
11009 var ns = parseName(type.name, pkg.prefix),
11010 name = ns.name,
11011 propertiesByName = {};
11012
11013 // parse properties
11014 forEach(type.properties, bind(function(p) {
11015
11016 // namespace property names
11017 var propertyNs = parseName(p.name, ns.prefix),
11018 propertyName = propertyNs.name;
11019
11020 // namespace property types
11021 if (!isBuiltIn(p.type)) {
11022 p.type = parseName(p.type, propertyNs.prefix).name;
11023 }
11024
11025 assign(p, {
11026 ns: propertyNs,
11027 name: propertyName
11028 });
11029
11030 propertiesByName[propertyName] = p;
11031 }, this));
11032
11033 // update ns + name
11034 assign(type, {
11035 ns: ns,
11036 name: name,
11037 propertiesByName: propertiesByName
11038 });
11039
11040 forEach(type.extends, bind(function(extendsName) {
11041 var extended = this.typeMap[extendsName];
11042
11043 extended.traits = extended.traits || [];
11044 extended.traits.push(name);
11045 }, this));
11046
11047 // link to package
11048 this.definePackage(type, pkg);
11049
11050 // register
11051 this.typeMap[name] = type;
11052 };
11053
11054
11055 /**
11056 * Traverse the type hierarchy from bottom to top,
11057 * calling iterator with (type, inherited) for all elements in
11058 * the inheritance chain.
11059 *
11060 * @param {Object} nsName
11061 * @param {Function} iterator
11062 * @param {Boolean} [trait=false]
11063 */
11064 Registry.prototype.mapTypes = function(nsName, iterator, trait) {
11065
11066 var type = isBuiltIn(nsName.name) ? { name: nsName.name } : this.typeMap[nsName.name];
11067
11068 var self = this;
11069
11070 /**
11071 * Traverse the selected trait.
11072 *
11073 * @param {String} cls
11074 */
11075 function traverseTrait(cls) {
11076 return traverseSuper(cls, true);
11077 }
11078
11079 /**
11080 * Traverse the selected super type or trait
11081 *
11082 * @param {String} cls
11083 * @param {Boolean} [trait=false]
11084 */
11085 function traverseSuper(cls, trait) {
11086 var parentNs = parseName(cls, isBuiltIn(cls) ? '' : nsName.prefix);
11087 self.mapTypes(parentNs, iterator, trait);
11088 }
11089
11090 if (!type) {
11091 throw new Error('unknown type <' + nsName.name + '>');
11092 }
11093
11094 forEach(type.superClass, trait ? traverseTrait : traverseSuper);
11095
11096 // call iterator with (type, inherited=!trait)
11097 iterator(type, !trait);
11098
11099 forEach(type.traits, traverseTrait);
11100 };
11101
11102
11103 /**
11104 * Returns the effective descriptor for a type.
11105 *
11106 * @param {String} type the namespaced name (ns:localName) of the type
11107 *
11108 * @return {Descriptor} the resulting effective descriptor
11109 */
11110 Registry.prototype.getEffectiveDescriptor = function(name) {
11111
11112 var nsName = parseName(name);
11113
11114 var builder = new DescriptorBuilder(nsName);
11115
11116 this.mapTypes(nsName, function(type, inherited) {
11117 builder.addTrait(type, inherited);
11118 });
11119
11120 var descriptor = builder.build();
11121
11122 // define package link
11123 this.definePackage(descriptor, descriptor.allTypes[descriptor.allTypes.length - 1].$pkg);
11124
11125 return descriptor;
11126 };
11127
11128
11129 Registry.prototype.definePackage = function(target, pkg) {
11130 this.properties.define(target, '$pkg', { value: pkg });
11131 };
11132
11133
11134
11135 ///////// helpers ////////////////////////////
11136
11137 function ensureAvailable(packageMap, pkg, identifierKey) {
11138
11139 var value = pkg[identifierKey];
11140
11141 if (value in packageMap) {
11142 throw new Error('package with ' + identifierKey + ' <' + value + '> already defined');
11143 }
11144 }
11145
11146 /**
11147 * A utility that gets and sets properties of model elements.
11148 *
11149 * @param {Model} model
11150 */
11151 function Properties(model) {
11152 this.model = model;
11153 }
11154
11155
11156 /**
11157 * Sets a named property on the target element.
11158 * If the value is undefined, the property gets deleted.
11159 *
11160 * @param {Object} target
11161 * @param {String} name
11162 * @param {Object} value
11163 */
11164 Properties.prototype.set = function(target, name, value) {
11165
11166 var property = this.model.getPropertyDescriptor(target, name);
11167
11168 var propertyName = property && property.name;
11169
11170 if (isUndefined$1(value)) {
11171 // unset the property, if the specified value is undefined;
11172 // delete from $attrs (for extensions) or the target itself
11173 if (property) {
11174 delete target[propertyName];
11175 } else {
11176 delete target.$attrs[name];
11177 }
11178 } else {
11179 // set the property, defining well defined properties on the fly
11180 // or simply updating them in target.$attrs (for extensions)
11181 if (property) {
11182 if (propertyName in target) {
11183 target[propertyName] = value;
11184 } else {
11185 defineProperty$1(target, property, value);
11186 }
11187 } else {
11188 target.$attrs[name] = value;
11189 }
11190 }
11191 };
11192
11193 /**
11194 * Returns the named property of the given element
11195 *
11196 * @param {Object} target
11197 * @param {String} name
11198 *
11199 * @return {Object}
11200 */
11201 Properties.prototype.get = function(target, name) {
11202
11203 var property = this.model.getPropertyDescriptor(target, name);
11204
11205 if (!property) {
11206 return target.$attrs[name];
11207 }
11208
11209 var propertyName = property.name;
11210
11211 // check if access to collection property and lazily initialize it
11212 if (!target[propertyName] && property.isMany) {
11213 defineProperty$1(target, property, []);
11214 }
11215
11216 return target[propertyName];
11217 };
11218
11219
11220 /**
11221 * Define a property on the target element
11222 *
11223 * @param {Object} target
11224 * @param {String} name
11225 * @param {Object} options
11226 */
11227 Properties.prototype.define = function(target, name, options) {
11228 Object.defineProperty(target, name, options);
11229 };
11230
11231
11232 /**
11233 * Define the descriptor for an element
11234 */
11235 Properties.prototype.defineDescriptor = function(target, descriptor) {
11236 this.define(target, '$descriptor', { value: descriptor });
11237 };
11238
11239 /**
11240 * Define the model for an element
11241 */
11242 Properties.prototype.defineModel = function(target, model) {
11243 this.define(target, '$model', { value: model });
11244 };
11245
11246
11247 function isUndefined$1(val) {
11248 return typeof val === 'undefined';
11249 }
11250
11251 function defineProperty$1(target, property, value) {
11252 Object.defineProperty(target, property.name, {
11253 enumerable: !property.isReference,
11254 writable: true,
11255 value: value,
11256 configurable: true
11257 });
11258 }
11259
11260 //// Moddle implementation /////////////////////////////////////////////////
11261
11262 /**
11263 * @class Moddle
11264 *
11265 * A model that can be used to create elements of a specific type.
11266 *
11267 * @example
11268 *
11269 * var Moddle = require('moddle');
11270 *
11271 * var pkg = {
11272 * name: 'mypackage',
11273 * prefix: 'my',
11274 * types: [
11275 * { name: 'Root' }
11276 * ]
11277 * };
11278 *
11279 * var moddle = new Moddle([pkg]);
11280 *
11281 * @param {Array<Package>} packages the packages to contain
11282 */
11283 function Moddle(packages) {
11284
11285 this.properties = new Properties(this);
11286
11287 this.factory = new Factory(this, this.properties);
11288 this.registry = new Registry(packages, this.properties);
11289
11290 this.typeCache = {};
11291 }
11292
11293
11294 /**
11295 * Create an instance of the specified type.
11296 *
11297 * @method Moddle#create
11298 *
11299 * @example
11300 *
11301 * var foo = moddle.create('my:Foo');
11302 * var bar = moddle.create('my:Bar', { id: 'BAR_1' });
11303 *
11304 * @param {String|Object} descriptor the type descriptor or name know to the model
11305 * @param {Object} attrs a number of attributes to initialize the model instance with
11306 * @return {Object} model instance
11307 */
11308 Moddle.prototype.create = function(descriptor, attrs) {
11309 var Type = this.getType(descriptor);
11310
11311 if (!Type) {
11312 throw new Error('unknown type <' + descriptor + '>');
11313 }
11314
11315 return new Type(attrs);
11316 };
11317
11318
11319 /**
11320 * Returns the type representing a given descriptor
11321 *
11322 * @method Moddle#getType
11323 *
11324 * @example
11325 *
11326 * var Foo = moddle.getType('my:Foo');
11327 * var foo = new Foo({ 'id' : 'FOO_1' });
11328 *
11329 * @param {String|Object} descriptor the type descriptor or name know to the model
11330 * @return {Object} the type representing the descriptor
11331 */
11332 Moddle.prototype.getType = function(descriptor) {
11333
11334 var cache = this.typeCache;
11335
11336 var name = isString(descriptor) ? descriptor : descriptor.ns.name;
11337
11338 var type = cache[name];
11339
11340 if (!type) {
11341 descriptor = this.registry.getEffectiveDescriptor(name);
11342 type = cache[name] = this.factory.createType(descriptor);
11343 }
11344
11345 return type;
11346 };
11347
11348
11349 /**
11350 * Creates an any-element type to be used within model instances.
11351 *
11352 * This can be used to create custom elements that lie outside the meta-model.
11353 * The created element contains all the meta-data required to serialize it
11354 * as part of meta-model elements.
11355 *
11356 * @method Moddle#createAny
11357 *
11358 * @example
11359 *
11360 * var foo = moddle.createAny('vendor:Foo', 'http://vendor', {
11361 * value: 'bar'
11362 * });
11363 *
11364 * var container = moddle.create('my:Container', 'http://my', {
11365 * any: [ foo ]
11366 * });
11367 *
11368 * // go ahead and serialize the stuff
11369 *
11370 *
11371 * @param {String} name the name of the element
11372 * @param {String} nsUri the namespace uri of the element
11373 * @param {Object} [properties] a map of properties to initialize the instance with
11374 * @return {Object} the any type instance
11375 */
11376 Moddle.prototype.createAny = function(name, nsUri, properties) {
11377
11378 var nameNs = parseName(name);
11379
11380 var element = {
11381 $type: name,
11382 $instanceOf: function(type) {
11383 return type === this.$type;
11384 }
11385 };
11386
11387 var descriptor = {
11388 name: name,
11389 isGeneric: true,
11390 ns: {
11391 prefix: nameNs.prefix,
11392 localName: nameNs.localName,
11393 uri: nsUri
11394 }
11395 };
11396
11397 this.properties.defineDescriptor(element, descriptor);
11398 this.properties.defineModel(element, this);
11399 this.properties.define(element, '$parent', { enumerable: false, writable: true });
11400
11401 forEach(properties, function(a, key) {
11402 if (isObject(a) && a.value !== undefined) {
11403 element[a.name] = a.value;
11404 } else {
11405 element[key] = a;
11406 }
11407 });
11408
11409 return element;
11410 };
11411
11412 /**
11413 * Returns a registered package by uri or prefix
11414 *
11415 * @return {Object} the package
11416 */
11417 Moddle.prototype.getPackage = function(uriOrPrefix) {
11418 return this.registry.getPackage(uriOrPrefix);
11419 };
11420
11421 /**
11422 * Returns a snapshot of all known packages
11423 *
11424 * @return {Object} the package
11425 */
11426 Moddle.prototype.getPackages = function() {
11427 return this.registry.getPackages();
11428 };
11429
11430 /**
11431 * Returns the descriptor for an element
11432 */
11433 Moddle.prototype.getElementDescriptor = function(element) {
11434 return element.$descriptor;
11435 };
11436
11437 /**
11438 * Returns true if the given descriptor or instance
11439 * represents the given type.
11440 *
11441 * May be applied to this, if element is omitted.
11442 */
11443 Moddle.prototype.hasType = function(element, type) {
11444 if (type === undefined) {
11445 type = element;
11446 element = this;
11447 }
11448
11449 var descriptor = element.$model.getElementDescriptor(element);
11450
11451 return (type in descriptor.allTypesByName);
11452 };
11453
11454 /**
11455 * Returns the descriptor of an elements named property
11456 */
11457 Moddle.prototype.getPropertyDescriptor = function(element, property) {
11458 return this.getElementDescriptor(element).propertiesByName[property];
11459 };
11460
11461 /**
11462 * Returns a mapped type's descriptor
11463 */
11464 Moddle.prototype.getTypeDescriptor = function(type) {
11465 return this.registry.typeMap[type];
11466 };
11467
11468 var fromCharCode = String.fromCharCode;
11469
11470 var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
11471
11472 var ENTITY_PATTERN = /&#(\d+);|&#x([0-9a-f]+);|&(\w+);/ig;
11473
11474 var ENTITY_MAPPING = {
11475 'amp': '&',
11476 'apos': '\'',
11477 'gt': '>',
11478 'lt': '<',
11479 'quot': '"'
11480 };
11481
11482 // map UPPERCASE variants of supported special chars
11483 Object.keys(ENTITY_MAPPING).forEach(function(k) {
11484 ENTITY_MAPPING[k.toUpperCase()] = ENTITY_MAPPING[k];
11485 });
11486
11487
11488 function replaceEntities(_, d, x, z) {
11489
11490 // reserved names, i.e. &nbsp;
11491 if (z) {
11492 if (hasOwnProperty$1.call(ENTITY_MAPPING, z)) {
11493 return ENTITY_MAPPING[z];
11494 } else {
11495
11496 // fall back to original value
11497 return '&' + z + ';';
11498 }
11499 }
11500
11501 // decimal encoded char
11502 if (d) {
11503 return fromCharCode(d);
11504 }
11505
11506 // hex encoded char
11507 return fromCharCode(parseInt(x, 16));
11508 }
11509
11510
11511 /**
11512 * A basic entity decoder that can decode a minimal
11513 * sub-set of reserved names (&amp;) as well as
11514 * hex (&#xaaf;) and decimal (&#1231;) encoded characters.
11515 *
11516 * @param {string} str
11517 *
11518 * @return {string} decoded string
11519 */
11520 function decodeEntities(s) {
11521 if (s.length > 3 && s.indexOf('&') !== -1) {
11522 return s.replace(ENTITY_PATTERN, replaceEntities);
11523 }
11524
11525 return s;
11526 }
11527
11528 var XSI_URI = 'http://www.w3.org/2001/XMLSchema-instance';
11529 var XSI_PREFIX = 'xsi';
11530 var XSI_TYPE = 'xsi:type';
11531
11532 var NON_WHITESPACE_OUTSIDE_ROOT_NODE = 'non-whitespace outside of root node';
11533
11534 function error(msg) {
11535 return new Error(msg);
11536 }
11537
11538 function missingNamespaceForPrefix(prefix) {
11539 return 'missing namespace for prefix <' + prefix + '>';
11540 }
11541
11542 function getter(getFn) {
11543 return {
11544 'get': getFn,
11545 'enumerable': true
11546 };
11547 }
11548
11549 function cloneNsMatrix(nsMatrix) {
11550 var clone = {}, key;
11551 for (key in nsMatrix) {
11552 clone[key] = nsMatrix[key];
11553 }
11554 return clone;
11555 }
11556
11557 function uriPrefix(prefix) {
11558 return prefix + '$uri';
11559 }
11560
11561 function buildNsMatrix(nsUriToPrefix) {
11562 var nsMatrix = {},
11563 uri,
11564 prefix;
11565
11566 for (uri in nsUriToPrefix) {
11567 prefix = nsUriToPrefix[uri];
11568 nsMatrix[prefix] = prefix;
11569 nsMatrix[uriPrefix(prefix)] = uri;
11570 }
11571
11572 return nsMatrix;
11573 }
11574
11575 function noopGetContext() {
11576 return { 'line': 0, 'column': 0 };
11577 }
11578
11579 function throwFunc(err) {
11580 throw err;
11581 }
11582
11583 /**
11584 * Creates a new parser with the given options.
11585 *
11586 * @constructor
11587 *
11588 * @param {!Object<string, ?>=} options
11589 */
11590 function Parser(options) {
11591
11592 if (!this) {
11593 return new Parser(options);
11594 }
11595
11596 var proxy = options && options['proxy'];
11597
11598 var onText,
11599 onOpenTag,
11600 onCloseTag,
11601 onCDATA,
11602 onError = throwFunc,
11603 onWarning,
11604 onComment,
11605 onQuestion,
11606 onAttention;
11607
11608 var getContext = noopGetContext;
11609
11610 /**
11611 * Do we need to parse the current elements attributes for namespaces?
11612 *
11613 * @type {boolean}
11614 */
11615 var maybeNS = false;
11616
11617 /**
11618 * Do we process namespaces at all?
11619 *
11620 * @type {boolean}
11621 */
11622 var isNamespace = false;
11623
11624 /**
11625 * The caught error returned on parse end
11626 *
11627 * @type {Error}
11628 */
11629 var returnError = null;
11630
11631 /**
11632 * Should we stop parsing?
11633 *
11634 * @type {boolean}
11635 */
11636 var parseStop = false;
11637
11638 /**
11639 * A map of { uri: prefix } used by the parser.
11640 *
11641 * This map will ensure we can normalize prefixes during processing;
11642 * for each uri, only one prefix will be exposed to the handlers.
11643 *
11644 * @type {!Object<string, string>}}
11645 */
11646 var nsUriToPrefix;
11647
11648 /**
11649 * Handle parse error.
11650 *
11651 * @param {string|Error} err
11652 */
11653 function handleError(err) {
11654 if (!(err instanceof Error)) {
11655 err = error(err);
11656 }
11657
11658 returnError = err;
11659
11660 onError(err, getContext);
11661 }
11662
11663 /**
11664 * Handle parse error.
11665 *
11666 * @param {string|Error} err
11667 */
11668 function handleWarning(err) {
11669
11670 if (!onWarning) {
11671 return;
11672 }
11673
11674 if (!(err instanceof Error)) {
11675 err = error(err);
11676 }
11677
11678 onWarning(err, getContext);
11679 }
11680
11681 /**
11682 * Register parse listener.
11683 *
11684 * @param {string} name
11685 * @param {Function} cb
11686 *
11687 * @return {Parser}
11688 */
11689 this['on'] = function(name, cb) {
11690
11691 if (typeof cb !== 'function') {
11692 throw error('required args <name, cb>');
11693 }
11694
11695 switch (name) {
11696 case 'openTag': onOpenTag = cb; break;
11697 case 'text': onText = cb; break;
11698 case 'closeTag': onCloseTag = cb; break;
11699 case 'error': onError = cb; break;
11700 case 'warn': onWarning = cb; break;
11701 case 'cdata': onCDATA = cb; break;
11702 case 'attention': onAttention = cb; break; // <!XXXXX zzzz="eeee">
11703 case 'question': onQuestion = cb; break; // <? .... ?>
11704 case 'comment': onComment = cb; break;
11705 default:
11706 throw error('unsupported event: ' + name);
11707 }
11708
11709 return this;
11710 };
11711
11712 /**
11713 * Set the namespace to prefix mapping.
11714 *
11715 * @example
11716 *
11717 * parser.ns({
11718 * 'http://foo': 'foo',
11719 * 'http://bar': 'bar'
11720 * });
11721 *
11722 * @param {!Object<string, string>} nsMap
11723 *
11724 * @return {Parser}
11725 */
11726 this['ns'] = function(nsMap) {
11727
11728 if (typeof nsMap === 'undefined') {
11729 nsMap = {};
11730 }
11731
11732 if (typeof nsMap !== 'object') {
11733 throw error('required args <nsMap={}>');
11734 }
11735
11736 var _nsUriToPrefix = {}, k;
11737
11738 for (k in nsMap) {
11739 _nsUriToPrefix[k] = nsMap[k];
11740 }
11741
11742 // FORCE default mapping for schema instance
11743 _nsUriToPrefix[XSI_URI] = XSI_PREFIX;
11744
11745 isNamespace = true;
11746 nsUriToPrefix = _nsUriToPrefix;
11747
11748 return this;
11749 };
11750
11751 /**
11752 * Parse xml string.
11753 *
11754 * @param {string} xml
11755 *
11756 * @return {Error} returnError, if not thrown
11757 */
11758 this['parse'] = function(xml) {
11759 if (typeof xml !== 'string') {
11760 throw error('required args <xml=string>');
11761 }
11762
11763 returnError = null;
11764
11765 parse(xml);
11766
11767 getContext = noopGetContext;
11768 parseStop = false;
11769
11770 return returnError;
11771 };
11772
11773 /**
11774 * Stop parsing.
11775 */
11776 this['stop'] = function() {
11777 parseStop = true;
11778 };
11779
11780 /**
11781 * Parse string, invoking configured listeners on element.
11782 *
11783 * @param {string} xml
11784 */
11785 function parse(xml) {
11786 var nsMatrixStack = isNamespace ? [] : null,
11787 nsMatrix = isNamespace ? buildNsMatrix(nsUriToPrefix) : null,
11788 _nsMatrix,
11789 nodeStack = [],
11790 anonymousNsCount = 0,
11791 tagStart = false,
11792 tagEnd = false,
11793 i = 0, j = 0,
11794 x, y, q, w, v,
11795 xmlns,
11796 elementName,
11797 _elementName,
11798 elementProxy
11799 ;
11800
11801 var attrsString = '',
11802 attrsStart = 0,
11803 cachedAttrs // false = parsed with errors, null = needs parsing
11804 ;
11805
11806 /**
11807 * Parse attributes on demand and returns the parsed attributes.
11808 *
11809 * Return semantics: (1) `false` on attribute parse error,
11810 * (2) object hash on extracted attrs.
11811 *
11812 * @return {boolean|Object}
11813 */
11814 function getAttrs() {
11815 if (cachedAttrs !== null) {
11816 return cachedAttrs;
11817 }
11818
11819 var nsUri,
11820 nsUriPrefix,
11821 nsName,
11822 defaultAlias = isNamespace && nsMatrix['xmlns'],
11823 attrList = isNamespace && maybeNS ? [] : null,
11824 i = attrsStart,
11825 s = attrsString,
11826 l = s.length,
11827 hasNewMatrix,
11828 newalias,
11829 value,
11830 alias,
11831 name,
11832 attrs = {},
11833 seenAttrs = {},
11834 skipAttr,
11835 w,
11836 j;
11837
11838 parseAttr:
11839 for (; i < l; i++) {
11840 skipAttr = false;
11841 w = s.charCodeAt(i);
11842
11843 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE={ \f\n\r\t\v}
11844 continue;
11845 }
11846
11847 // wait for non whitespace character
11848 if (w < 65 || w > 122 || (w > 90 && w < 97)) {
11849 if (w !== 95 && w !== 58) { // char 95"_" 58":"
11850 handleWarning('illegal first char attribute name');
11851 skipAttr = true;
11852 }
11853 }
11854
11855 // parse attribute name
11856 for (j = i + 1; j < l; j++) {
11857 w = s.charCodeAt(j);
11858
11859 if (
11860 w > 96 && w < 123 ||
11861 w > 64 && w < 91 ||
11862 w > 47 && w < 59 ||
11863 w === 46 || // '.'
11864 w === 45 || // '-'
11865 w === 95 // '_'
11866 ) {
11867 continue;
11868 }
11869
11870 // unexpected whitespace
11871 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
11872 handleWarning('missing attribute value');
11873 i = j;
11874
11875 continue parseAttr;
11876 }
11877
11878 // expected "="
11879 if (w === 61) { // "=" == 61
11880 break;
11881 }
11882
11883 handleWarning('illegal attribute name char');
11884 skipAttr = true;
11885 }
11886
11887 name = s.substring(i, j);
11888
11889 if (name === 'xmlns:xmlns') {
11890 handleWarning('illegal declaration of xmlns');
11891 skipAttr = true;
11892 }
11893
11894 w = s.charCodeAt(j + 1);
11895
11896 if (w === 34) { // '"'
11897 j = s.indexOf('"', i = j + 2);
11898
11899 if (j === -1) {
11900 j = s.indexOf('\'', i);
11901
11902 if (j !== -1) {
11903 handleWarning('attribute value quote missmatch');
11904 skipAttr = true;
11905 }
11906 }
11907
11908 } else if (w === 39) { // "'"
11909 j = s.indexOf('\'', i = j + 2);
11910
11911 if (j === -1) {
11912 j = s.indexOf('"', i);
11913
11914 if (j !== -1) {
11915 handleWarning('attribute value quote missmatch');
11916 skipAttr = true;
11917 }
11918 }
11919
11920 } else {
11921 handleWarning('missing attribute value quotes');
11922 skipAttr = true;
11923
11924 // skip to next space
11925 for (j = j + 1; j < l; j++) {
11926 w = s.charCodeAt(j + 1);
11927
11928 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
11929 break;
11930 }
11931 }
11932
11933 }
11934
11935 if (j === -1) {
11936 handleWarning('missing closing quotes');
11937
11938 j = l;
11939 skipAttr = true;
11940 }
11941
11942 if (!skipAttr) {
11943 value = s.substring(i, j);
11944 }
11945
11946 i = j;
11947
11948 // ensure SPACE follows attribute
11949 // skip illegal content otherwise
11950 // example a="b"c
11951 for (; j + 1 < l; j++) {
11952 w = s.charCodeAt(j + 1);
11953
11954 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
11955 break;
11956 }
11957
11958 // FIRST ILLEGAL CHAR
11959 if (i === j) {
11960 handleWarning('illegal character after attribute end');
11961 skipAttr = true;
11962 }
11963 }
11964
11965 // advance cursor to next attribute
11966 i = j + 1;
11967
11968 if (skipAttr) {
11969 continue parseAttr;
11970 }
11971
11972 // check attribute re-declaration
11973 if (name in seenAttrs) {
11974 handleWarning('attribute <' + name + '> already defined');
11975 continue;
11976 }
11977
11978 seenAttrs[name] = true;
11979
11980 if (!isNamespace) {
11981 attrs[name] = value;
11982 continue;
11983 }
11984
11985 // try to extract namespace information
11986 if (maybeNS) {
11987 newalias = (
11988 name === 'xmlns'
11989 ? 'xmlns'
11990 : (name.charCodeAt(0) === 120 && name.substr(0, 6) === 'xmlns:')
11991 ? name.substr(6)
11992 : null
11993 );
11994
11995 // handle xmlns(:alias) assignment
11996 if (newalias !== null) {
11997 nsUri = decodeEntities(value);
11998 nsUriPrefix = uriPrefix(newalias);
11999
12000 alias = nsUriToPrefix[nsUri];
12001
12002 if (!alias) {
12003
12004 // no prefix defined or prefix collision
12005 if (
12006 (newalias === 'xmlns') ||
12007 (nsUriPrefix in nsMatrix && nsMatrix[nsUriPrefix] !== nsUri)
12008 ) {
12009
12010 // alocate free ns prefix
12011 do {
12012 alias = 'ns' + (anonymousNsCount++);
12013 } while (typeof nsMatrix[alias] !== 'undefined');
12014 } else {
12015 alias = newalias;
12016 }
12017
12018 nsUriToPrefix[nsUri] = alias;
12019 }
12020
12021 if (nsMatrix[newalias] !== alias) {
12022 if (!hasNewMatrix) {
12023 nsMatrix = cloneNsMatrix(nsMatrix);
12024 hasNewMatrix = true;
12025 }
12026
12027 nsMatrix[newalias] = alias;
12028 if (newalias === 'xmlns') {
12029 nsMatrix[uriPrefix(alias)] = nsUri;
12030 defaultAlias = alias;
12031 }
12032
12033 nsMatrix[nsUriPrefix] = nsUri;
12034 }
12035
12036 // expose xmlns(:asd)="..." in attributes
12037 attrs[name] = value;
12038 continue;
12039 }
12040
12041 // collect attributes until all namespace
12042 // declarations are processed
12043 attrList.push(name, value);
12044 continue;
12045
12046 } /** end if (maybeNs) */
12047
12048 // handle attributes on element without
12049 // namespace declarations
12050 w = name.indexOf(':');
12051 if (w === -1) {
12052 attrs[name] = value;
12053 continue;
12054 }
12055
12056 // normalize ns attribute name
12057 if (!(nsName = nsMatrix[name.substring(0, w)])) {
12058 handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
12059 continue;
12060 }
12061
12062 name = defaultAlias === nsName
12063 ? name.substr(w + 1)
12064 : nsName + name.substr(w);
12065
12066 // end: normalize ns attribute name
12067
12068 // normalize xsi:type ns attribute value
12069 if (name === XSI_TYPE) {
12070 w = value.indexOf(':');
12071
12072 if (w !== -1) {
12073 nsName = value.substring(0, w);
12074
12075 // handle default prefixes, i.e. xs:String gracefully
12076 nsName = nsMatrix[nsName] || nsName;
12077 value = nsName + value.substring(w);
12078 } else {
12079 value = defaultAlias + ':' + value;
12080 }
12081 }
12082
12083 // end: normalize xsi:type ns attribute value
12084
12085 attrs[name] = value;
12086 }
12087
12088
12089 // handle deferred, possibly namespaced attributes
12090 if (maybeNS) {
12091
12092 // normalize captured attributes
12093 for (i = 0, l = attrList.length; i < l; i++) {
12094
12095 name = attrList[i++];
12096 value = attrList[i];
12097
12098 w = name.indexOf(':');
12099
12100 if (w !== -1) {
12101
12102 // normalize ns attribute name
12103 if (!(nsName = nsMatrix[name.substring(0, w)])) {
12104 handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
12105 continue;
12106 }
12107
12108 name = defaultAlias === nsName
12109 ? name.substr(w + 1)
12110 : nsName + name.substr(w);
12111
12112 // end: normalize ns attribute name
12113
12114 // normalize xsi:type ns attribute value
12115 if (name === XSI_TYPE) {
12116 w = value.indexOf(':');
12117
12118 if (w !== -1) {
12119 nsName = value.substring(0, w);
12120
12121 // handle default prefixes, i.e. xs:String gracefully
12122 nsName = nsMatrix[nsName] || nsName;
12123 value = nsName + value.substring(w);
12124 } else {
12125 value = defaultAlias + ':' + value;
12126 }
12127 }
12128
12129 // end: normalize xsi:type ns attribute value
12130 }
12131
12132 attrs[name] = value;
12133 }
12134
12135 // end: normalize captured attributes
12136 }
12137
12138 return cachedAttrs = attrs;
12139 }
12140
12141 /**
12142 * Extract the parse context { line, column, part }
12143 * from the current parser position.
12144 *
12145 * @return {Object} parse context
12146 */
12147 function getParseContext() {
12148 var splitsRe = /(\r\n|\r|\n)/g;
12149
12150 var line = 0;
12151 var column = 0;
12152 var startOfLine = 0;
12153 var endOfLine = j;
12154 var match;
12155 var data;
12156
12157 while (i >= startOfLine) {
12158
12159 match = splitsRe.exec(xml);
12160
12161 if (!match) {
12162 break;
12163 }
12164
12165 // end of line = (break idx + break chars)
12166 endOfLine = match[0].length + match.index;
12167
12168 if (endOfLine > i) {
12169 break;
12170 }
12171
12172 // advance to next line
12173 line += 1;
12174
12175 startOfLine = endOfLine;
12176 }
12177
12178 // EOF errors
12179 if (i == -1) {
12180 column = endOfLine;
12181 data = xml.substring(j);
12182 } else
12183
12184 // start errors
12185 if (j === 0) {
12186 data = xml.substring(j, i);
12187 }
12188
12189 // other errors
12190 else {
12191 column = i - startOfLine;
12192 data = (j == -1 ? xml.substring(i) : xml.substring(i, j + 1));
12193 }
12194
12195 return {
12196 'data': data,
12197 'line': line,
12198 'column': column
12199 };
12200 }
12201
12202 getContext = getParseContext;
12203
12204
12205 if (proxy) {
12206 elementProxy = Object.create({}, {
12207 'name': getter(function() {
12208 return elementName;
12209 }),
12210 'originalName': getter(function() {
12211 return _elementName;
12212 }),
12213 'attrs': getter(getAttrs),
12214 'ns': getter(function() {
12215 return nsMatrix;
12216 })
12217 });
12218 }
12219
12220 // actual parse logic
12221 while (j !== -1) {
12222
12223 if (xml.charCodeAt(j) === 60) { // "<"
12224 i = j;
12225 } else {
12226 i = xml.indexOf('<', j);
12227 }
12228
12229 // parse end
12230 if (i === -1) {
12231 if (nodeStack.length) {
12232 return handleError('unexpected end of file');
12233 }
12234
12235 if (j === 0) {
12236 return handleError('missing start tag');
12237 }
12238
12239 if (j < xml.length) {
12240 if (xml.substring(j).trim()) {
12241 handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
12242 }
12243 }
12244
12245 return;
12246 }
12247
12248 // parse text
12249 if (j !== i) {
12250
12251 if (nodeStack.length) {
12252 if (onText) {
12253 onText(xml.substring(j, i), decodeEntities, getContext);
12254
12255 if (parseStop) {
12256 return;
12257 }
12258 }
12259 } else {
12260 if (xml.substring(j, i).trim()) {
12261 handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
12262
12263 if (parseStop) {
12264 return;
12265 }
12266 }
12267 }
12268 }
12269
12270 w = xml.charCodeAt(i+1);
12271
12272 // parse comments + CDATA
12273 if (w === 33) { // "!"
12274 q = xml.charCodeAt(i+2);
12275
12276 // CDATA section
12277 if (q === 91 && xml.substr(i + 3, 6) === 'CDATA[') { // 91 == "["
12278 j = xml.indexOf(']]>', i);
12279 if (j === -1) {
12280 return handleError('unclosed cdata');
12281 }
12282
12283 if (onCDATA) {
12284 onCDATA(xml.substring(i + 9, j), getContext);
12285 if (parseStop) {
12286 return;
12287 }
12288 }
12289
12290 j += 3;
12291 continue;
12292 }
12293
12294 // comment
12295 if (q === 45 && xml.charCodeAt(i + 3) === 45) { // 45 == "-"
12296 j = xml.indexOf('-->', i);
12297 if (j === -1) {
12298 return handleError('unclosed comment');
12299 }
12300
12301
12302 if (onComment) {
12303 onComment(xml.substring(i + 4, j), decodeEntities, getContext);
12304 if (parseStop) {
12305 return;
12306 }
12307 }
12308
12309 j += 3;
12310 continue;
12311 }
12312 }
12313
12314 // parse question <? ... ?>
12315 if (w === 63) { // "?"
12316 j = xml.indexOf('?>', i);
12317 if (j === -1) {
12318 return handleError('unclosed question');
12319 }
12320
12321 if (onQuestion) {
12322 onQuestion(xml.substring(i, j + 2), getContext);
12323 if (parseStop) {
12324 return;
12325 }
12326 }
12327
12328 j += 2;
12329 continue;
12330 }
12331
12332 // find matching closing tag for attention or standard tags
12333 // for that we must skip through attribute values
12334 // (enclosed in single or double quotes)
12335 for (x = i + 1; ; x++) {
12336 v = xml.charCodeAt(x);
12337 if (isNaN(v)) {
12338 j = -1;
12339 return handleError('unclosed tag');
12340 }
12341
12342 // [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'"
12343 // skips the quoted string
12344 // (double quotes) does not appear in a literal enclosed by (double quotes)
12345 // (single quote) does not appear in a literal enclosed by (single quote)
12346 if (v === 34) { // '"'
12347 q = xml.indexOf('"', x + 1);
12348 x = q !== -1 ? q : x;
12349 } else if (v === 39) { // "'"
12350 q = xml.indexOf("'", x + 1);
12351 x = q !== -1 ? q : x;
12352 } else if (v === 62) { // '>'
12353 j = x;
12354 break;
12355 }
12356 }
12357
12358
12359 // parse attention <! ...>
12360 // previously comment and CDATA have already been parsed
12361 if (w === 33) { // "!"
12362
12363 if (onAttention) {
12364 onAttention(xml.substring(i, j + 1), decodeEntities, getContext);
12365 if (parseStop) {
12366 return;
12367 }
12368 }
12369
12370 j += 1;
12371 continue;
12372 }
12373
12374 // don't process attributes;
12375 // there are none
12376 cachedAttrs = {};
12377
12378 // if (xml.charCodeAt(i+1) === 47) { // </...
12379 if (w === 47) { // </...
12380 tagStart = false;
12381 tagEnd = true;
12382
12383 if (!nodeStack.length) {
12384 return handleError('missing open tag');
12385 }
12386
12387 // verify open <-> close tag match
12388 x = elementName = nodeStack.pop();
12389 q = i + 2 + x.length;
12390
12391 if (xml.substring(i + 2, q) !== x) {
12392 return handleError('closing tag mismatch');
12393 }
12394
12395 // verify chars in close tag
12396 for (; q < j; q++) {
12397 w = xml.charCodeAt(q);
12398
12399 if (w === 32 || (w > 8 && w < 14)) { // \f\n\r\t\v space
12400 continue;
12401 }
12402
12403 return handleError('close tag');
12404 }
12405
12406 } else {
12407 if (xml.charCodeAt(j - 1) === 47) { // .../>
12408 x = elementName = xml.substring(i + 1, j - 1);
12409
12410 tagStart = true;
12411 tagEnd = true;
12412
12413 } else {
12414 x = elementName = xml.substring(i + 1, j);
12415
12416 tagStart = true;
12417 tagEnd = false;
12418 }
12419
12420 if (!(w > 96 && w < 123 || w > 64 && w < 91 || w === 95 || w === 58)) { // char 95"_" 58":"
12421 return handleError('illegal first char nodeName');
12422 }
12423
12424 for (q = 1, y = x.length; q < y; q++) {
12425 w = x.charCodeAt(q);
12426
12427 if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w == 46) {
12428 continue;
12429 }
12430
12431 if (w === 32 || (w < 14 && w > 8)) { // \f\n\r\t\v space
12432 elementName = x.substring(0, q);
12433
12434 // maybe there are attributes
12435 cachedAttrs = null;
12436 break;
12437 }
12438
12439 return handleError('invalid nodeName');
12440 }
12441
12442 if (!tagEnd) {
12443 nodeStack.push(elementName);
12444 }
12445 }
12446
12447 if (isNamespace) {
12448
12449 _nsMatrix = nsMatrix;
12450
12451 if (tagStart) {
12452
12453 // remember old namespace
12454 // unless we're self-closing
12455 if (!tagEnd) {
12456 nsMatrixStack.push(_nsMatrix);
12457 }
12458
12459 if (cachedAttrs === null) {
12460
12461 // quick check, whether there may be namespace
12462 // declarations on the node; if that is the case
12463 // we need to eagerly parse the node attributes
12464 if ((maybeNS = x.indexOf('xmlns', q) !== -1)) {
12465 attrsStart = q;
12466 attrsString = x;
12467
12468 getAttrs();
12469
12470 maybeNS = false;
12471 }
12472 }
12473 }
12474
12475 _elementName = elementName;
12476
12477 w = elementName.indexOf(':');
12478 if (w !== -1) {
12479 xmlns = nsMatrix[elementName.substring(0, w)];
12480
12481 // prefix given; namespace must exist
12482 if (!xmlns) {
12483 return handleError('missing namespace on <' + _elementName + '>');
12484 }
12485
12486 elementName = elementName.substr(w + 1);
12487 } else {
12488 xmlns = nsMatrix['xmlns'];
12489
12490 // if no default namespace is defined,
12491 // we'll import the element as anonymous.
12492 //
12493 // it is up to users to correct that to the document defined
12494 // targetNamespace, or whatever their undersanding of the
12495 // XML spec mandates.
12496 }
12497
12498 // adjust namespace prefixs as configured
12499 if (xmlns) {
12500 elementName = xmlns + ':' + elementName;
12501 }
12502
12503 }
12504
12505 if (tagStart) {
12506 attrsStart = q;
12507 attrsString = x;
12508
12509 if (onOpenTag) {
12510 if (proxy) {
12511 onOpenTag(elementProxy, decodeEntities, tagEnd, getContext);
12512 } else {
12513 onOpenTag(elementName, getAttrs, decodeEntities, tagEnd, getContext);
12514 }
12515
12516 if (parseStop) {
12517 return;
12518 }
12519 }
12520
12521 }
12522
12523 if (tagEnd) {
12524
12525 if (onCloseTag) {
12526 onCloseTag(proxy ? elementProxy : elementName, decodeEntities, tagStart, getContext);
12527
12528 if (parseStop) {
12529 return;
12530 }
12531 }
12532
12533 // restore old namespace
12534 if (isNamespace) {
12535 if (!tagStart) {
12536 nsMatrix = nsMatrixStack.pop();
12537 } else {
12538 nsMatrix = _nsMatrix;
12539 }
12540 }
12541 }
12542
12543 j += 1;
12544 }
12545 } /** end parse */
12546
12547 }
12548
12549 function hasLowerCaseAlias(pkg) {
12550 return pkg.xml && pkg.xml.tagAlias === 'lowerCase';
12551 }
12552
12553 var DEFAULT_NS_MAP = {
12554 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
12555 'xml': 'http://www.w3.org/XML/1998/namespace'
12556 };
12557
12558 var XSI_TYPE$1 = 'xsi:type';
12559
12560 function serializeFormat(element) {
12561 return element.xml && element.xml.serialize;
12562 }
12563
12564 function serializeAsType(element) {
12565 return serializeFormat(element) === XSI_TYPE$1;
12566 }
12567
12568 function serializeAsProperty(element) {
12569 return serializeFormat(element) === 'property';
12570 }
12571
12572 function capitalize(str) {
12573 return str.charAt(0).toUpperCase() + str.slice(1);
12574 }
12575
12576 function aliasToName(aliasNs, pkg) {
12577
12578 if (!hasLowerCaseAlias(pkg)) {
12579 return aliasNs.name;
12580 }
12581
12582 return aliasNs.prefix + ':' + capitalize(aliasNs.localName);
12583 }
12584
12585 function prefixedToName(nameNs, pkg) {
12586
12587 var name = nameNs.name,
12588 localName = nameNs.localName;
12589
12590 var typePrefix = pkg.xml && pkg.xml.typePrefix;
12591
12592 if (typePrefix && localName.indexOf(typePrefix) === 0) {
12593 return nameNs.prefix + ':' + localName.slice(typePrefix.length);
12594 } else {
12595 return name;
12596 }
12597 }
12598
12599 function normalizeXsiTypeName(name, model) {
12600
12601 var nameNs = parseName(name);
12602 var pkg = model.getPackage(nameNs.prefix);
12603
12604 return prefixedToName(nameNs, pkg);
12605 }
12606
12607 function error$1(message) {
12608 return new Error(message);
12609 }
12610
12611 /**
12612 * Get the moddle descriptor for a given instance or type.
12613 *
12614 * @param {ModdleElement|Function} element
12615 *
12616 * @return {Object} the moddle descriptor
12617 */
12618 function getModdleDescriptor(element) {
12619 return element.$descriptor;
12620 }
12621
12622
12623 /**
12624 * A parse context.
12625 *
12626 * @class
12627 *
12628 * @param {Object} options
12629 * @param {ElementHandler} options.rootHandler the root handler for parsing a document
12630 * @param {boolean} [options.lax=false] whether or not to ignore invalid elements
12631 */
12632 function Context(options) {
12633
12634 /**
12635 * @property {ElementHandler} rootHandler
12636 */
12637
12638 /**
12639 * @property {Boolean} lax
12640 */
12641
12642 assign(this, options);
12643
12644 this.elementsById = {};
12645 this.references = [];
12646 this.warnings = [];
12647
12648 /**
12649 * Add an unresolved reference.
12650 *
12651 * @param {Object} reference
12652 */
12653 this.addReference = function(reference) {
12654 this.references.push(reference);
12655 };
12656
12657 /**
12658 * Add a processed element.
12659 *
12660 * @param {ModdleElement} element
12661 */
12662 this.addElement = function(element) {
12663
12664 if (!element) {
12665 throw error$1('expected element');
12666 }
12667
12668 var elementsById = this.elementsById;
12669
12670 var descriptor = getModdleDescriptor(element);
12671
12672 var idProperty = descriptor.idProperty,
12673 id;
12674
12675 if (idProperty) {
12676 id = element.get(idProperty.name);
12677
12678 if (id) {
12679 // for QName validation as per http://www.w3.org/TR/REC-xml/#NT-NameChar
12680 if (!/^([a-z][\w-.]*:)?[a-z_][\w-.]*$/i.test(id)) {
12681 throw new Error('illegal ID <' + id + '>');
12682 }
12683
12684 if (elementsById[id]) {
12685 throw error$1('duplicate ID <' + id + '>');
12686 }
12687
12688 elementsById[id] = element;
12689 }
12690 }
12691 };
12692
12693 /**
12694 * Add an import warning.
12695 *
12696 * @param {Object} warning
12697 * @param {String} warning.message
12698 * @param {Error} [warning.error]
12699 */
12700 this.addWarning = function(warning) {
12701 this.warnings.push(warning);
12702 };
12703 }
12704
12705 function BaseHandler() {}
12706
12707 BaseHandler.prototype.handleEnd = function() {};
12708 BaseHandler.prototype.handleText = function() {};
12709 BaseHandler.prototype.handleNode = function() {};
12710
12711
12712 /**
12713 * A simple pass through handler that does nothing except for
12714 * ignoring all input it receives.
12715 *
12716 * This is used to ignore unknown elements and
12717 * attributes.
12718 */
12719 function NoopHandler() { }
12720
12721 NoopHandler.prototype = Object.create(BaseHandler.prototype);
12722
12723 NoopHandler.prototype.handleNode = function() {
12724 return this;
12725 };
12726
12727 function BodyHandler() {}
12728
12729 BodyHandler.prototype = Object.create(BaseHandler.prototype);
12730
12731 BodyHandler.prototype.handleText = function(text) {
12732 this.body = (this.body || '') + text;
12733 };
12734
12735 function ReferenceHandler(property, context) {
12736 this.property = property;
12737 this.context = context;
12738 }
12739
12740 ReferenceHandler.prototype = Object.create(BodyHandler.prototype);
12741
12742 ReferenceHandler.prototype.handleNode = function(node) {
12743
12744 if (this.element) {
12745 throw error$1('expected no sub nodes');
12746 } else {
12747 this.element = this.createReference(node);
12748 }
12749
12750 return this;
12751 };
12752
12753 ReferenceHandler.prototype.handleEnd = function() {
12754 this.element.id = this.body;
12755 };
12756
12757 ReferenceHandler.prototype.createReference = function(node) {
12758 return {
12759 property: this.property.ns.name,
12760 id: ''
12761 };
12762 };
12763
12764 function ValueHandler(propertyDesc, element) {
12765 this.element = element;
12766 this.propertyDesc = propertyDesc;
12767 }
12768
12769 ValueHandler.prototype = Object.create(BodyHandler.prototype);
12770
12771 ValueHandler.prototype.handleEnd = function() {
12772
12773 var value = this.body || '',
12774 element = this.element,
12775 propertyDesc = this.propertyDesc;
12776
12777 value = coerceType(propertyDesc.type, value);
12778
12779 if (propertyDesc.isMany) {
12780 element.get(propertyDesc.name).push(value);
12781 } else {
12782 element.set(propertyDesc.name, value);
12783 }
12784 };
12785
12786
12787 function BaseElementHandler() {}
12788
12789 BaseElementHandler.prototype = Object.create(BodyHandler.prototype);
12790
12791 BaseElementHandler.prototype.handleNode = function(node) {
12792 var parser = this,
12793 element = this.element;
12794
12795 if (!element) {
12796 element = this.element = this.createElement(node);
12797
12798 this.context.addElement(element);
12799 } else {
12800 parser = this.handleChild(node);
12801 }
12802
12803 return parser;
12804 };
12805
12806 /**
12807 * @class Reader.ElementHandler
12808 *
12809 */
12810 function ElementHandler(model, typeName, context) {
12811 this.model = model;
12812 this.type = model.getType(typeName);
12813 this.context = context;
12814 }
12815
12816 ElementHandler.prototype = Object.create(BaseElementHandler.prototype);
12817
12818 ElementHandler.prototype.addReference = function(reference) {
12819 this.context.addReference(reference);
12820 };
12821
12822 ElementHandler.prototype.handleText = function(text) {
12823
12824 var element = this.element,
12825 descriptor = getModdleDescriptor(element),
12826 bodyProperty = descriptor.bodyProperty;
12827
12828 if (!bodyProperty) {
12829 throw error$1('unexpected body text <' + text + '>');
12830 }
12831
12832 BodyHandler.prototype.handleText.call(this, text);
12833 };
12834
12835 ElementHandler.prototype.handleEnd = function() {
12836
12837 var value = this.body,
12838 element = this.element,
12839 descriptor = getModdleDescriptor(element),
12840 bodyProperty = descriptor.bodyProperty;
12841
12842 if (bodyProperty && value !== undefined) {
12843 value = coerceType(bodyProperty.type, value);
12844 element.set(bodyProperty.name, value);
12845 }
12846 };
12847
12848 /**
12849 * Create an instance of the model from the given node.
12850 *
12851 * @param {Element} node the xml node
12852 */
12853 ElementHandler.prototype.createElement = function(node) {
12854 var attributes = node.attributes,
12855 Type = this.type,
12856 descriptor = getModdleDescriptor(Type),
12857 context = this.context,
12858 instance = new Type({}),
12859 model = this.model,
12860 propNameNs;
12861
12862 forEach(attributes, function(value, name) {
12863
12864 var prop = descriptor.propertiesByName[name],
12865 values;
12866
12867 if (prop && prop.isReference) {
12868
12869 if (!prop.isMany) {
12870 context.addReference({
12871 element: instance,
12872 property: prop.ns.name,
12873 id: value
12874 });
12875 } else {
12876 // IDREFS: parse references as whitespace-separated list
12877 values = value.split(' ');
12878
12879 forEach(values, function(v) {
12880 context.addReference({
12881 element: instance,
12882 property: prop.ns.name,
12883 id: v
12884 });
12885 });
12886 }
12887
12888 } else {
12889 if (prop) {
12890 value = coerceType(prop.type, value);
12891 } else
12892 if (name !== 'xmlns') {
12893 propNameNs = parseName(name, descriptor.ns.prefix);
12894
12895 // check whether attribute is defined in a well-known namespace
12896 // if that is the case we emit a warning to indicate potential misuse
12897 if (model.getPackage(propNameNs.prefix)) {
12898
12899 context.addWarning({
12900 message: 'unknown attribute <' + name + '>',
12901 element: instance,
12902 property: name,
12903 value: value
12904 });
12905 }
12906 }
12907
12908 instance.set(name, value);
12909 }
12910 });
12911
12912 return instance;
12913 };
12914
12915 ElementHandler.prototype.getPropertyForNode = function(node) {
12916
12917 var name = node.name;
12918 var nameNs = parseName(name);
12919
12920 var type = this.type,
12921 model = this.model,
12922 descriptor = getModdleDescriptor(type);
12923
12924 var propertyName = nameNs.name,
12925 property = descriptor.propertiesByName[propertyName],
12926 elementTypeName,
12927 elementType;
12928
12929 // search for properties by name first
12930
12931 if (property && !property.isAttr) {
12932
12933 if (serializeAsType(property)) {
12934 elementTypeName = node.attributes[XSI_TYPE$1];
12935
12936 // xsi type is optional, if it does not exists the
12937 // default type is assumed
12938 if (elementTypeName) {
12939
12940 // take possible type prefixes from XML
12941 // into account, i.e.: xsi:type="t{ActualType}"
12942 elementTypeName = normalizeXsiTypeName(elementTypeName, model);
12943
12944 elementType = model.getType(elementTypeName);
12945
12946 return assign({}, property, {
12947 effectiveType: getModdleDescriptor(elementType).name
12948 });
12949 }
12950 }
12951
12952 // search for properties by name first
12953 return property;
12954 }
12955
12956 var pkg = model.getPackage(nameNs.prefix);
12957
12958 if (pkg) {
12959 elementTypeName = aliasToName(nameNs, pkg);
12960 elementType = model.getType(elementTypeName);
12961
12962 // search for collection members later
12963 property = find(descriptor.properties, function(p) {
12964 return !p.isVirtual && !p.isReference && !p.isAttribute && elementType.hasType(p.type);
12965 });
12966
12967 if (property) {
12968 return assign({}, property, {
12969 effectiveType: getModdleDescriptor(elementType).name
12970 });
12971 }
12972 } else {
12973 // parse unknown element (maybe extension)
12974 property = find(descriptor.properties, function(p) {
12975 return !p.isReference && !p.isAttribute && p.type === 'Element';
12976 });
12977
12978 if (property) {
12979 return property;
12980 }
12981 }
12982
12983 throw error$1('unrecognized element <' + nameNs.name + '>');
12984 };
12985
12986 ElementHandler.prototype.toString = function() {
12987 return 'ElementDescriptor[' + getModdleDescriptor(this.type).name + ']';
12988 };
12989
12990 ElementHandler.prototype.valueHandler = function(propertyDesc, element) {
12991 return new ValueHandler(propertyDesc, element);
12992 };
12993
12994 ElementHandler.prototype.referenceHandler = function(propertyDesc) {
12995 return new ReferenceHandler(propertyDesc, this.context);
12996 };
12997
12998 ElementHandler.prototype.handler = function(type) {
12999 if (type === 'Element') {
13000 return new GenericElementHandler(this.model, type, this.context);
13001 } else {
13002 return new ElementHandler(this.model, type, this.context);
13003 }
13004 };
13005
13006 /**
13007 * Handle the child element parsing
13008 *
13009 * @param {Element} node the xml node
13010 */
13011 ElementHandler.prototype.handleChild = function(node) {
13012 var propertyDesc, type, element, childHandler;
13013
13014 propertyDesc = this.getPropertyForNode(node);
13015 element = this.element;
13016
13017 type = propertyDesc.effectiveType || propertyDesc.type;
13018
13019 if (isSimple(type)) {
13020 return this.valueHandler(propertyDesc, element);
13021 }
13022
13023 if (propertyDesc.isReference) {
13024 childHandler = this.referenceHandler(propertyDesc).handleNode(node);
13025 } else {
13026 childHandler = this.handler(type).handleNode(node);
13027 }
13028
13029 var newElement = childHandler.element;
13030
13031 // child handles may decide to skip elements
13032 // by not returning anything
13033 if (newElement !== undefined) {
13034
13035 if (propertyDesc.isMany) {
13036 element.get(propertyDesc.name).push(newElement);
13037 } else {
13038 element.set(propertyDesc.name, newElement);
13039 }
13040
13041 if (propertyDesc.isReference) {
13042 assign(newElement, {
13043 element: element
13044 });
13045
13046 this.context.addReference(newElement);
13047 } else {
13048 // establish child -> parent relationship
13049 newElement.$parent = element;
13050 }
13051 }
13052
13053 return childHandler;
13054 };
13055
13056 /**
13057 * An element handler that performs special validation
13058 * to ensure the node it gets initialized with matches
13059 * the handlers type (namespace wise).
13060 *
13061 * @param {Moddle} model
13062 * @param {String} typeName
13063 * @param {Context} context
13064 */
13065 function RootElementHandler(model, typeName, context) {
13066 ElementHandler.call(this, model, typeName, context);
13067 }
13068
13069 RootElementHandler.prototype = Object.create(ElementHandler.prototype);
13070
13071 RootElementHandler.prototype.createElement = function(node) {
13072
13073 var name = node.name,
13074 nameNs = parseName(name),
13075 model = this.model,
13076 type = this.type,
13077 pkg = model.getPackage(nameNs.prefix),
13078 typeName = pkg && aliasToName(nameNs, pkg) || name;
13079
13080 // verify the correct namespace if we parse
13081 // the first element in the handler tree
13082 //
13083 // this ensures we don't mistakenly import wrong namespace elements
13084 if (!type.hasType(typeName)) {
13085 throw error$1('unexpected element <' + node.originalName + '>');
13086 }
13087
13088 return ElementHandler.prototype.createElement.call(this, node);
13089 };
13090
13091
13092 function GenericElementHandler(model, typeName, context) {
13093 this.model = model;
13094 this.context = context;
13095 }
13096
13097 GenericElementHandler.prototype = Object.create(BaseElementHandler.prototype);
13098
13099 GenericElementHandler.prototype.createElement = function(node) {
13100
13101 var name = node.name,
13102 ns = parseName(name),
13103 prefix = ns.prefix,
13104 uri = node.ns[prefix + '$uri'],
13105 attributes = node.attributes;
13106
13107 return this.model.createAny(name, uri, attributes);
13108 };
13109
13110 GenericElementHandler.prototype.handleChild = function(node) {
13111
13112 var handler = new GenericElementHandler(this.model, 'Element', this.context).handleNode(node),
13113 element = this.element;
13114
13115 var newElement = handler.element,
13116 children;
13117
13118 if (newElement !== undefined) {
13119 children = element.$children = element.$children || [];
13120 children.push(newElement);
13121
13122 // establish child -> parent relationship
13123 newElement.$parent = element;
13124 }
13125
13126 return handler;
13127 };
13128
13129 GenericElementHandler.prototype.handleEnd = function() {
13130 if (this.body) {
13131 this.element.$body = this.body;
13132 }
13133 };
13134
13135 /**
13136 * A reader for a meta-model
13137 *
13138 * @param {Object} options
13139 * @param {Model} options.model used to read xml files
13140 * @param {Boolean} options.lax whether to make parse errors warnings
13141 */
13142 function Reader(options) {
13143
13144 if (options instanceof Moddle) {
13145 options = {
13146 model: options
13147 };
13148 }
13149
13150 assign(this, { lax: false }, options);
13151 }
13152
13153 /**
13154 * The fromXML result.
13155 *
13156 * @typedef {Object} ParseResult
13157 *
13158 * @property {ModdleElement} rootElement
13159 * @property {Array<Object>} references
13160 * @property {Array<Error>} warnings
13161 * @property {Object} elementsById - a mapping containing each ID -> ModdleElement
13162 */
13163
13164 /**
13165 * The fromXML result.
13166 *
13167 * @typedef {Error} ParseError
13168 *
13169 * @property {Array<Error>} warnings
13170 */
13171
13172 /**
13173 * Parse the given XML into a moddle document tree.
13174 *
13175 * @param {String} xml
13176 * @param {ElementHandler|Object} options or rootHandler
13177 *
13178 * @returns {Promise<ParseResult, ParseError>}
13179 */
13180 Reader.prototype.fromXML = function(xml, options, done) {
13181
13182 var rootHandler = options.rootHandler;
13183
13184 if (options instanceof ElementHandler) {
13185 // root handler passed via (xml, { rootHandler: ElementHandler }, ...)
13186 rootHandler = options;
13187 options = {};
13188 } else {
13189 if (typeof options === 'string') {
13190 // rootHandler passed via (xml, 'someString', ...)
13191 rootHandler = this.handler(options);
13192 options = {};
13193 } else if (typeof rootHandler === 'string') {
13194 // rootHandler passed via (xml, { rootHandler: 'someString' }, ...)
13195 rootHandler = this.handler(rootHandler);
13196 }
13197 }
13198
13199 var model = this.model,
13200 lax = this.lax;
13201
13202 var context = new Context(assign({}, options, { rootHandler: rootHandler })),
13203 parser = new Parser({ proxy: true }),
13204 stack = createStack();
13205
13206 rootHandler.context = context;
13207
13208 // push root handler
13209 stack.push(rootHandler);
13210
13211
13212 /**
13213 * Handle error.
13214 *
13215 * @param {Error} err
13216 * @param {Function} getContext
13217 * @param {boolean} lax
13218 *
13219 * @return {boolean} true if handled
13220 */
13221 function handleError(err, getContext, lax) {
13222
13223 var ctx = getContext();
13224
13225 var line = ctx.line,
13226 column = ctx.column,
13227 data = ctx.data;
13228
13229 // we receive the full context data here,
13230 // for elements trim down the information
13231 // to the tag name, only
13232 if (data.charAt(0) === '<' && data.indexOf(' ') !== -1) {
13233 data = data.slice(0, data.indexOf(' ')) + '>';
13234 }
13235
13236 var message =
13237 'unparsable content ' + (data ? data + ' ' : '') + 'detected\n\t' +
13238 'line: ' + line + '\n\t' +
13239 'column: ' + column + '\n\t' +
13240 'nested error: ' + err.message;
13241
13242 if (lax) {
13243 context.addWarning({
13244 message: message,
13245 error: err
13246 });
13247
13248 return true;
13249 } else {
13250 throw error$1(message);
13251 }
13252 }
13253
13254 function handleWarning(err, getContext) {
13255 // just like handling errors in <lax=true> mode
13256 return handleError(err, getContext, true);
13257 }
13258
13259 /**
13260 * Resolve collected references on parse end.
13261 */
13262 function resolveReferences() {
13263
13264 var elementsById = context.elementsById;
13265 var references = context.references;
13266
13267 var i, r;
13268
13269 for (i = 0; (r = references[i]); i++) {
13270 var element = r.element;
13271 var reference = elementsById[r.id];
13272 var property = getModdleDescriptor(element).propertiesByName[r.property];
13273
13274 if (!reference) {
13275 context.addWarning({
13276 message: 'unresolved reference <' + r.id + '>',
13277 element: r.element,
13278 property: r.property,
13279 value: r.id
13280 });
13281 }
13282
13283 if (property.isMany) {
13284 var collection = element.get(property.name),
13285 idx = collection.indexOf(r);
13286
13287 // we replace an existing place holder (idx != -1) or
13288 // append to the collection instead
13289 if (idx === -1) {
13290 idx = collection.length;
13291 }
13292
13293 if (!reference) {
13294 // remove unresolvable reference
13295 collection.splice(idx, 1);
13296 } else {
13297 // add or update reference in collection
13298 collection[idx] = reference;
13299 }
13300 } else {
13301 element.set(property.name, reference);
13302 }
13303 }
13304 }
13305
13306 function handleClose() {
13307 stack.pop().handleEnd();
13308 }
13309
13310 var PREAMBLE_START_PATTERN = /^<\?xml /i;
13311
13312 var ENCODING_PATTERN = / encoding="([^"]+)"/i;
13313
13314 var UTF_8_PATTERN = /^utf-8$/i;
13315
13316 function handleQuestion(question) {
13317
13318 if (!PREAMBLE_START_PATTERN.test(question)) {
13319 return;
13320 }
13321
13322 var match = ENCODING_PATTERN.exec(question);
13323 var encoding = match && match[1];
13324
13325 if (!encoding || UTF_8_PATTERN.test(encoding)) {
13326 return;
13327 }
13328
13329 context.addWarning({
13330 message:
13331 'unsupported document encoding <' + encoding + '>, ' +
13332 'falling back to UTF-8'
13333 });
13334 }
13335
13336 function handleOpen(node, getContext) {
13337 var handler = stack.peek();
13338
13339 try {
13340 stack.push(handler.handleNode(node));
13341 } catch (err) {
13342
13343 if (handleError(err, getContext, lax)) {
13344 stack.push(new NoopHandler());
13345 }
13346 }
13347 }
13348
13349 function handleCData(text, getContext) {
13350
13351 try {
13352 stack.peek().handleText(text);
13353 } catch (err) {
13354 handleWarning(err, getContext);
13355 }
13356 }
13357
13358 function handleText(text, getContext) {
13359 // strip whitespace only nodes, i.e. before
13360 // <!CDATA[ ... ]> sections and in between tags
13361 text = text.trim();
13362
13363 if (!text) {
13364 return;
13365 }
13366
13367 handleCData(text, getContext);
13368 }
13369
13370 var uriMap = model.getPackages().reduce(function(uriMap, p) {
13371 uriMap[p.uri] = p.prefix;
13372
13373 return uriMap;
13374 }, {
13375 'http://www.w3.org/XML/1998/namespace': 'xml' // add default xml ns
13376 });
13377 parser
13378 .ns(uriMap)
13379 .on('openTag', function(obj, decodeStr, selfClosing, getContext) {
13380
13381 // gracefully handle unparsable attributes (attrs=false)
13382 var attrs = obj.attrs || {};
13383
13384 var decodedAttrs = Object.keys(attrs).reduce(function(d, key) {
13385 var value = decodeStr(attrs[key]);
13386
13387 d[key] = value;
13388
13389 return d;
13390 }, {});
13391
13392 var node = {
13393 name: obj.name,
13394 originalName: obj.originalName,
13395 attributes: decodedAttrs,
13396 ns: obj.ns
13397 };
13398
13399 handleOpen(node, getContext);
13400 })
13401 .on('question', handleQuestion)
13402 .on('closeTag', handleClose)
13403 .on('cdata', handleCData)
13404 .on('text', function(text, decodeEntities, getContext) {
13405 handleText(decodeEntities(text), getContext);
13406 })
13407 .on('error', handleError)
13408 .on('warn', handleWarning);
13409
13410 // async XML parsing to make sure the execution environment
13411 // (node or brower) is kept responsive and that certain optimization
13412 // strategies can kick in.
13413 return new Promise(function(resolve, reject) {
13414
13415 var err;
13416
13417 try {
13418 parser.parse(xml);
13419
13420 resolveReferences();
13421 } catch (e) {
13422 err = e;
13423 }
13424
13425 var rootElement = rootHandler.element;
13426
13427 if (!err && !rootElement) {
13428 err = error$1('failed to parse document as <' + rootHandler.type.$descriptor.name + '>');
13429 }
13430
13431 var warnings = context.warnings;
13432 var references = context.references;
13433 var elementsById = context.elementsById;
13434
13435 if (err) {
13436 err.warnings = warnings;
13437
13438 return reject(err);
13439 } else {
13440 return resolve({
13441 rootElement: rootElement,
13442 elementsById: elementsById,
13443 references: references,
13444 warnings: warnings
13445 });
13446 }
13447 });
13448 };
13449
13450 Reader.prototype.handler = function(name) {
13451 return new RootElementHandler(this.model, name);
13452 };
13453
13454
13455 // helpers //////////////////////////
13456
13457 function createStack() {
13458 var stack = [];
13459
13460 Object.defineProperty(stack, 'peek', {
13461 value: function() {
13462 return this[this.length - 1];
13463 }
13464 });
13465
13466 return stack;
13467 }
13468
13469 var XML_PREAMBLE = '<?xml version="1.0" encoding="UTF-8"?>\n';
13470
13471 var ESCAPE_ATTR_CHARS = /<|>|'|"|&|\n\r|\n/g;
13472 var ESCAPE_CHARS = /<|>|&/g;
13473
13474
13475 function Namespaces(parent) {
13476
13477 var prefixMap = {};
13478 var uriMap = {};
13479 var used = {};
13480
13481 var wellknown = [];
13482 var custom = [];
13483
13484 // API
13485
13486 this.byUri = function(uri) {
13487 return uriMap[uri] || (
13488 parent && parent.byUri(uri)
13489 );
13490 };
13491
13492 this.add = function(ns, isWellknown) {
13493
13494 uriMap[ns.uri] = ns;
13495
13496 if (isWellknown) {
13497 wellknown.push(ns);
13498 } else {
13499 custom.push(ns);
13500 }
13501
13502 this.mapPrefix(ns.prefix, ns.uri);
13503 };
13504
13505 this.uriByPrefix = function(prefix) {
13506 return prefixMap[prefix || 'xmlns'];
13507 };
13508
13509 this.mapPrefix = function(prefix, uri) {
13510 prefixMap[prefix || 'xmlns'] = uri;
13511 };
13512
13513 this.getNSKey = function(ns) {
13514 return (ns.prefix !== undefined) ? (ns.uri + '|' + ns.prefix) : ns.uri;
13515 };
13516
13517 this.logUsed = function(ns) {
13518
13519 var uri = ns.uri;
13520 var nsKey = this.getNSKey(ns);
13521
13522 used[nsKey] = this.byUri(uri);
13523
13524 // Inform parent recursively about the usage of this NS
13525 if (parent) {
13526 parent.logUsed(ns);
13527 }
13528 };
13529
13530 this.getUsed = function(ns) {
13531
13532 function isUsed(ns) {
13533 var nsKey = self.getNSKey(ns);
13534
13535 return used[nsKey];
13536 }
13537
13538 var self = this;
13539
13540 var allNs = [].concat(wellknown, custom);
13541
13542 return allNs.filter(isUsed);
13543 };
13544
13545 }
13546
13547 function lower(string) {
13548 return string.charAt(0).toLowerCase() + string.slice(1);
13549 }
13550
13551 function nameToAlias(name, pkg) {
13552 if (hasLowerCaseAlias(pkg)) {
13553 return lower(name);
13554 } else {
13555 return name;
13556 }
13557 }
13558
13559 function inherits(ctor, superCtor) {
13560 ctor.super_ = superCtor;
13561 ctor.prototype = Object.create(superCtor.prototype, {
13562 constructor: {
13563 value: ctor,
13564 enumerable: false,
13565 writable: true,
13566 configurable: true
13567 }
13568 });
13569 }
13570
13571 function nsName(ns) {
13572 if (isString(ns)) {
13573 return ns;
13574 } else {
13575 return (ns.prefix ? ns.prefix + ':' : '') + ns.localName;
13576 }
13577 }
13578
13579 function getNsAttrs(namespaces) {
13580
13581 return map(namespaces.getUsed(), function(ns) {
13582 var name = 'xmlns' + (ns.prefix ? ':' + ns.prefix : '');
13583 return { name: name, value: ns.uri };
13584 });
13585
13586 }
13587
13588 function getElementNs(ns, descriptor) {
13589 if (descriptor.isGeneric) {
13590 return assign({ localName: descriptor.ns.localName }, ns);
13591 } else {
13592 return assign({ localName: nameToAlias(descriptor.ns.localName, descriptor.$pkg) }, ns);
13593 }
13594 }
13595
13596 function getPropertyNs(ns, descriptor) {
13597 return assign({ localName: descriptor.ns.localName }, ns);
13598 }
13599
13600 function getSerializableProperties(element) {
13601 var descriptor = element.$descriptor;
13602
13603 return filter(descriptor.properties, function(p) {
13604 var name = p.name;
13605
13606 if (p.isVirtual) {
13607 return false;
13608 }
13609
13610 // do not serialize defaults
13611 if (!element.hasOwnProperty(name)) {
13612 return false;
13613 }
13614
13615 var value = element[name];
13616
13617 // do not serialize default equals
13618 if (value === p.default) {
13619 return false;
13620 }
13621
13622 // do not serialize null properties
13623 if (value === null) {
13624 return false;
13625 }
13626
13627 return p.isMany ? value.length : true;
13628 });
13629 }
13630
13631 var ESCAPE_ATTR_MAP = {
13632 '\n': '#10',
13633 '\n\r': '#10',
13634 '"': '#34',
13635 '\'': '#39',
13636 '<': '#60',
13637 '>': '#62',
13638 '&': '#38'
13639 };
13640
13641 var ESCAPE_MAP = {
13642 '<': 'lt',
13643 '>': 'gt',
13644 '&': 'amp'
13645 };
13646
13647 function escape$1(str, charPattern, replaceMap) {
13648
13649 // ensure we are handling strings here
13650 str = isString(str) ? str : '' + str;
13651
13652 return str.replace(charPattern, function(s) {
13653 return '&' + replaceMap[s] + ';';
13654 });
13655 }
13656
13657 /**
13658 * Escape a string attribute to not contain any bad values (line breaks, '"', ...)
13659 *
13660 * @param {String} str the string to escape
13661 * @return {String} the escaped string
13662 */
13663 function escapeAttr(str) {
13664 return escape$1(str, ESCAPE_ATTR_CHARS, ESCAPE_ATTR_MAP);
13665 }
13666
13667 function escapeBody(str) {
13668 return escape$1(str, ESCAPE_CHARS, ESCAPE_MAP);
13669 }
13670
13671 function filterAttributes(props) {
13672 return filter(props, function(p) { return p.isAttr; });
13673 }
13674
13675 function filterContained(props) {
13676 return filter(props, function(p) { return !p.isAttr; });
13677 }
13678
13679
13680 function ReferenceSerializer(tagName) {
13681 this.tagName = tagName;
13682 }
13683
13684 ReferenceSerializer.prototype.build = function(element) {
13685 this.element = element;
13686 return this;
13687 };
13688
13689 ReferenceSerializer.prototype.serializeTo = function(writer) {
13690 writer
13691 .appendIndent()
13692 .append('<' + this.tagName + '>' + this.element.id + '</' + this.tagName + '>')
13693 .appendNewLine();
13694 };
13695
13696 function BodySerializer() {}
13697
13698 BodySerializer.prototype.serializeValue =
13699 BodySerializer.prototype.serializeTo = function(writer) {
13700 writer.append(
13701 this.escape
13702 ? escapeBody(this.value)
13703 : this.value
13704 );
13705 };
13706
13707 BodySerializer.prototype.build = function(prop, value) {
13708 this.value = value;
13709
13710 if (prop.type === 'String' && value.search(ESCAPE_CHARS) !== -1) {
13711 this.escape = true;
13712 }
13713
13714 return this;
13715 };
13716
13717 function ValueSerializer(tagName) {
13718 this.tagName = tagName;
13719 }
13720
13721 inherits(ValueSerializer, BodySerializer);
13722
13723 ValueSerializer.prototype.serializeTo = function(writer) {
13724
13725 writer
13726 .appendIndent()
13727 .append('<' + this.tagName + '>');
13728
13729 this.serializeValue(writer);
13730
13731 writer
13732 .append('</' + this.tagName + '>')
13733 .appendNewLine();
13734 };
13735
13736 function ElementSerializer(parent, propertyDescriptor) {
13737 this.body = [];
13738 this.attrs = [];
13739
13740 this.parent = parent;
13741 this.propertyDescriptor = propertyDescriptor;
13742 }
13743
13744 ElementSerializer.prototype.build = function(element) {
13745 this.element = element;
13746
13747 var elementDescriptor = element.$descriptor,
13748 propertyDescriptor = this.propertyDescriptor;
13749
13750 var otherAttrs,
13751 properties;
13752
13753 var isGeneric = elementDescriptor.isGeneric;
13754
13755 if (isGeneric) {
13756 otherAttrs = this.parseGeneric(element);
13757 } else {
13758 otherAttrs = this.parseNsAttributes(element);
13759 }
13760
13761 if (propertyDescriptor) {
13762 this.ns = this.nsPropertyTagName(propertyDescriptor);
13763 } else {
13764 this.ns = this.nsTagName(elementDescriptor);
13765 }
13766
13767 // compute tag name
13768 this.tagName = this.addTagName(this.ns);
13769
13770 if (!isGeneric) {
13771 properties = getSerializableProperties(element);
13772
13773 this.parseAttributes(filterAttributes(properties));
13774 this.parseContainments(filterContained(properties));
13775 }
13776
13777 this.parseGenericAttributes(element, otherAttrs);
13778
13779 return this;
13780 };
13781
13782 ElementSerializer.prototype.nsTagName = function(descriptor) {
13783 var effectiveNs = this.logNamespaceUsed(descriptor.ns);
13784 return getElementNs(effectiveNs, descriptor);
13785 };
13786
13787 ElementSerializer.prototype.nsPropertyTagName = function(descriptor) {
13788 var effectiveNs = this.logNamespaceUsed(descriptor.ns);
13789 return getPropertyNs(effectiveNs, descriptor);
13790 };
13791
13792 ElementSerializer.prototype.isLocalNs = function(ns) {
13793 return ns.uri === this.ns.uri;
13794 };
13795
13796 /**
13797 * Get the actual ns attribute name for the given element.
13798 *
13799 * @param {Object} element
13800 * @param {Boolean} [element.inherited=false]
13801 *
13802 * @return {Object} nsName
13803 */
13804 ElementSerializer.prototype.nsAttributeName = function(element) {
13805
13806 var ns;
13807
13808 if (isString(element)) {
13809 ns = parseName(element);
13810 } else {
13811 ns = element.ns;
13812 }
13813
13814 // return just local name for inherited attributes
13815 if (element.inherited) {
13816 return { localName: ns.localName };
13817 }
13818
13819 // parse + log effective ns
13820 var effectiveNs = this.logNamespaceUsed(ns);
13821
13822 // LOG ACTUAL namespace use
13823 this.getNamespaces().logUsed(effectiveNs);
13824
13825 // strip prefix if same namespace like parent
13826 if (this.isLocalNs(effectiveNs)) {
13827 return { localName: ns.localName };
13828 } else {
13829 return assign({ localName: ns.localName }, effectiveNs);
13830 }
13831 };
13832
13833 ElementSerializer.prototype.parseGeneric = function(element) {
13834
13835 var self = this,
13836 body = this.body;
13837
13838 var attributes = [];
13839
13840 forEach(element, function(val, key) {
13841
13842 var nonNsAttr;
13843
13844 if (key === '$body') {
13845 body.push(new BodySerializer().build({ type: 'String' }, val));
13846 } else
13847 if (key === '$children') {
13848 forEach(val, function(child) {
13849 body.push(new ElementSerializer(self).build(child));
13850 });
13851 } else
13852 if (key.indexOf('$') !== 0) {
13853 nonNsAttr = self.parseNsAttribute(element, key, val);
13854
13855 if (nonNsAttr) {
13856 attributes.push({ name: key, value: val });
13857 }
13858 }
13859 });
13860
13861 return attributes;
13862 };
13863
13864 ElementSerializer.prototype.parseNsAttribute = function(element, name, value) {
13865 var model = element.$model;
13866
13867 var nameNs = parseName(name);
13868
13869 var ns;
13870
13871 // parse xmlns:foo="http://foo.bar"
13872 if (nameNs.prefix === 'xmlns') {
13873 ns = { prefix: nameNs.localName, uri: value };
13874 }
13875
13876 // parse xmlns="http://foo.bar"
13877 if (!nameNs.prefix && nameNs.localName === 'xmlns') {
13878 ns = { uri: value };
13879 }
13880
13881 if (!ns) {
13882 return {
13883 name: name,
13884 value: value
13885 };
13886 }
13887
13888 if (model && model.getPackage(value)) {
13889 // register well known namespace
13890 this.logNamespace(ns, true, true);
13891 } else {
13892 // log custom namespace directly as used
13893 var actualNs = this.logNamespaceUsed(ns, true);
13894
13895 this.getNamespaces().logUsed(actualNs);
13896 }
13897 };
13898
13899
13900 /**
13901 * Parse namespaces and return a list of left over generic attributes
13902 *
13903 * @param {Object} element
13904 * @return {Array<Object>}
13905 */
13906 ElementSerializer.prototype.parseNsAttributes = function(element, attrs) {
13907 var self = this;
13908
13909 var genericAttrs = element.$attrs;
13910
13911 var attributes = [];
13912
13913 // parse namespace attributes first
13914 // and log them. push non namespace attributes to a list
13915 // and process them later
13916 forEach(genericAttrs, function(value, name) {
13917
13918 var nonNsAttr = self.parseNsAttribute(element, name, value);
13919
13920 if (nonNsAttr) {
13921 attributes.push(nonNsAttr);
13922 }
13923 });
13924
13925 return attributes;
13926 };
13927
13928 ElementSerializer.prototype.parseGenericAttributes = function(element, attributes) {
13929
13930 var self = this;
13931
13932 forEach(attributes, function(attr) {
13933
13934 // do not serialize xsi:type attribute
13935 // it is set manually based on the actual implementation type
13936 if (attr.name === XSI_TYPE$1) {
13937 return;
13938 }
13939
13940 try {
13941 self.addAttribute(self.nsAttributeName(attr.name), attr.value);
13942 } catch (e) {
13943 console.warn(
13944 'missing namespace information for ',
13945 attr.name, '=', attr.value, 'on', element,
13946 e);
13947 }
13948 });
13949 };
13950
13951 ElementSerializer.prototype.parseContainments = function(properties) {
13952
13953 var self = this,
13954 body = this.body,
13955 element = this.element;
13956
13957 forEach(properties, function(p) {
13958 var value = element.get(p.name),
13959 isReference = p.isReference,
13960 isMany = p.isMany;
13961
13962 if (!isMany) {
13963 value = [ value ];
13964 }
13965
13966 if (p.isBody) {
13967 body.push(new BodySerializer().build(p, value[0]));
13968 } else
13969 if (isSimple(p.type)) {
13970 forEach(value, function(v) {
13971 body.push(new ValueSerializer(self.addTagName(self.nsPropertyTagName(p))).build(p, v));
13972 });
13973 } else
13974 if (isReference) {
13975 forEach(value, function(v) {
13976 body.push(new ReferenceSerializer(self.addTagName(self.nsPropertyTagName(p))).build(v));
13977 });
13978 } else {
13979 // allow serialization via type
13980 // rather than element name
13981 var asType = serializeAsType(p),
13982 asProperty = serializeAsProperty(p);
13983
13984 forEach(value, function(v) {
13985 var serializer;
13986
13987 if (asType) {
13988 serializer = new TypeSerializer(self, p);
13989 } else
13990 if (asProperty) {
13991 serializer = new ElementSerializer(self, p);
13992 } else {
13993 serializer = new ElementSerializer(self);
13994 }
13995
13996 body.push(serializer.build(v));
13997 });
13998 }
13999 });
14000 };
14001
14002 ElementSerializer.prototype.getNamespaces = function(local) {
14003
14004 var namespaces = this.namespaces,
14005 parent = this.parent,
14006 parentNamespaces;
14007
14008 if (!namespaces) {
14009 parentNamespaces = parent && parent.getNamespaces();
14010
14011 if (local || !parentNamespaces) {
14012 this.namespaces = namespaces = new Namespaces(parentNamespaces);
14013 } else {
14014 namespaces = parentNamespaces;
14015 }
14016 }
14017
14018 return namespaces;
14019 };
14020
14021 ElementSerializer.prototype.logNamespace = function(ns, wellknown, local) {
14022 var namespaces = this.getNamespaces(local);
14023
14024 var nsUri = ns.uri,
14025 nsPrefix = ns.prefix;
14026
14027 var existing = namespaces.byUri(nsUri);
14028
14029 if (nsPrefix !== 'xml' && (!existing || local)) {
14030 namespaces.add(ns, wellknown);
14031 }
14032
14033 namespaces.mapPrefix(nsPrefix, nsUri);
14034
14035 return ns;
14036 };
14037
14038 ElementSerializer.prototype.logNamespaceUsed = function(ns, local) {
14039 var element = this.element,
14040 model = element.$model,
14041 namespaces = this.getNamespaces(local);
14042
14043 // ns may be
14044 //
14045 // * prefix only
14046 // * prefix:uri
14047 // * localName only
14048
14049 var prefix = ns.prefix,
14050 uri = ns.uri,
14051 newPrefix, idx,
14052 wellknownUri;
14053
14054 // handle anonymous namespaces (elementForm=unqualified), cf. #23
14055 if (!prefix && !uri) {
14056 return { localName: ns.localName };
14057 }
14058
14059 wellknownUri = DEFAULT_NS_MAP[prefix] || model && (model.getPackage(prefix) || {}).uri;
14060
14061 uri = uri || wellknownUri || namespaces.uriByPrefix(prefix);
14062
14063 if (!uri) {
14064 throw new Error('no namespace uri given for prefix <' + prefix + '>');
14065 }
14066
14067 ns = namespaces.byUri(uri);
14068
14069 if (!ns) {
14070 newPrefix = prefix;
14071 idx = 1;
14072
14073 // find a prefix that is not mapped yet
14074 while (namespaces.uriByPrefix(newPrefix)) {
14075 newPrefix = prefix + '_' + idx++;
14076 }
14077
14078 ns = this.logNamespace({ prefix: newPrefix, uri: uri }, wellknownUri === uri);
14079 }
14080
14081 if (prefix) {
14082 namespaces.mapPrefix(prefix, uri);
14083 }
14084
14085 return ns;
14086 };
14087
14088 ElementSerializer.prototype.parseAttributes = function(properties) {
14089 var self = this,
14090 element = this.element;
14091
14092 forEach(properties, function(p) {
14093
14094 var value = element.get(p.name);
14095
14096 if (p.isReference) {
14097
14098 if (!p.isMany) {
14099 value = value.id;
14100 }
14101 else {
14102 var values = [];
14103 forEach(value, function(v) {
14104 values.push(v.id);
14105 });
14106 // IDREFS is a whitespace-separated list of references.
14107 value = values.join(' ');
14108 }
14109
14110 }
14111
14112 self.addAttribute(self.nsAttributeName(p), value);
14113 });
14114 };
14115
14116 ElementSerializer.prototype.addTagName = function(nsTagName) {
14117 var actualNs = this.logNamespaceUsed(nsTagName);
14118
14119 this.getNamespaces().logUsed(actualNs);
14120
14121 return nsName(nsTagName);
14122 };
14123
14124 ElementSerializer.prototype.addAttribute = function(name, value) {
14125 var attrs = this.attrs;
14126
14127 if (isString(value)) {
14128 value = escapeAttr(value);
14129 }
14130
14131 attrs.push({ name: name, value: value });
14132 };
14133
14134 ElementSerializer.prototype.serializeAttributes = function(writer) {
14135 var attrs = this.attrs,
14136 namespaces = this.namespaces;
14137
14138 if (namespaces) {
14139 attrs = getNsAttrs(namespaces).concat(attrs);
14140 }
14141
14142 forEach(attrs, function(a) {
14143 writer
14144 .append(' ')
14145 .append(nsName(a.name)).append('="').append(a.value).append('"');
14146 });
14147 };
14148
14149 ElementSerializer.prototype.serializeTo = function(writer) {
14150 var firstBody = this.body[0],
14151 indent = firstBody && firstBody.constructor !== BodySerializer;
14152
14153 writer
14154 .appendIndent()
14155 .append('<' + this.tagName);
14156
14157 this.serializeAttributes(writer);
14158
14159 writer.append(firstBody ? '>' : ' />');
14160
14161 if (firstBody) {
14162
14163 if (indent) {
14164 writer
14165 .appendNewLine()
14166 .indent();
14167 }
14168
14169 forEach(this.body, function(b) {
14170 b.serializeTo(writer);
14171 });
14172
14173 if (indent) {
14174 writer
14175 .unindent()
14176 .appendIndent();
14177 }
14178
14179 writer.append('</' + this.tagName + '>');
14180 }
14181
14182 writer.appendNewLine();
14183 };
14184
14185 /**
14186 * A serializer for types that handles serialization of data types
14187 */
14188 function TypeSerializer(parent, propertyDescriptor) {
14189 ElementSerializer.call(this, parent, propertyDescriptor);
14190 }
14191
14192 inherits(TypeSerializer, ElementSerializer);
14193
14194 TypeSerializer.prototype.parseNsAttributes = function(element) {
14195
14196 // extracted attributes
14197 var attributes = ElementSerializer.prototype.parseNsAttributes.call(this, element);
14198
14199 var descriptor = element.$descriptor;
14200
14201 // only serialize xsi:type if necessary
14202 if (descriptor.name === this.propertyDescriptor.type) {
14203 return attributes;
14204 }
14205
14206 var typeNs = this.typeNs = this.nsTagName(descriptor);
14207 this.getNamespaces().logUsed(this.typeNs);
14208
14209 // add xsi:type attribute to represent the elements
14210 // actual type
14211
14212 var pkg = element.$model.getPackage(typeNs.uri),
14213 typePrefix = (pkg.xml && pkg.xml.typePrefix) || '';
14214
14215 this.addAttribute(
14216 this.nsAttributeName(XSI_TYPE$1),
14217 (typeNs.prefix ? typeNs.prefix + ':' : '') + typePrefix + descriptor.ns.localName
14218 );
14219
14220 return attributes;
14221 };
14222
14223 TypeSerializer.prototype.isLocalNs = function(ns) {
14224 return ns.uri === (this.typeNs || this.ns).uri;
14225 };
14226
14227 function SavingWriter() {
14228 this.value = '';
14229
14230 this.write = function(str) {
14231 this.value += str;
14232 };
14233 }
14234
14235 function FormatingWriter(out, format) {
14236
14237 var indent = [''];
14238
14239 this.append = function(str) {
14240 out.write(str);
14241
14242 return this;
14243 };
14244
14245 this.appendNewLine = function() {
14246 if (format) {
14247 out.write('\n');
14248 }
14249
14250 return this;
14251 };
14252
14253 this.appendIndent = function() {
14254 if (format) {
14255 out.write(indent.join(' '));
14256 }
14257
14258 return this;
14259 };
14260
14261 this.indent = function() {
14262 indent.push('');
14263 return this;
14264 };
14265
14266 this.unindent = function() {
14267 indent.pop();
14268 return this;
14269 };
14270 }
14271
14272 /**
14273 * A writer for meta-model backed document trees
14274 *
14275 * @param {Object} options output options to pass into the writer
14276 */
14277 function Writer(options) {
14278
14279 options = assign({ format: false, preamble: true }, options || {});
14280
14281 function toXML(tree, writer) {
14282 var internalWriter = writer || new SavingWriter();
14283 var formatingWriter = new FormatingWriter(internalWriter, options.format);
14284
14285 if (options.preamble) {
14286 formatingWriter.append(XML_PREAMBLE);
14287 }
14288
14289 new ElementSerializer().build(tree).serializeTo(formatingWriter);
14290
14291 if (!writer) {
14292 return internalWriter.value;
14293 }
14294 }
14295
14296 return {
14297 toXML: toXML
14298 };
14299 }
14300
14301 /**
14302 * A sub class of {@link Moddle} with support for import and export of BPMN 2.0 xml files.
14303 *
14304 * @class BpmnModdle
14305 * @extends Moddle
14306 *
14307 * @param {Object|Array} packages to use for instantiating the model
14308 * @param {Object} [options] additional options to pass over
14309 */
14310 function BpmnModdle(packages, options) {
14311 Moddle.call(this, packages, options);
14312 }
14313
14314 BpmnModdle.prototype = Object.create(Moddle.prototype);
14315
14316 /**
14317 * The fromXML result.
14318 *
14319 * @typedef {Object} ParseResult
14320 *
14321 * @property {ModdleElement} rootElement
14322 * @property {Array<Object>} references
14323 * @property {Array<Error>} warnings
14324 * @property {Object} elementsById - a mapping containing each ID -> ModdleElement
14325 */
14326
14327 /**
14328 * The fromXML error.
14329 *
14330 * @typedef {Error} ParseError
14331 *
14332 * @property {Array<Error>} warnings
14333 */
14334
14335 /**
14336 * Instantiates a BPMN model tree from a given xml string.
14337 *
14338 * @param {String} xmlStr
14339 * @param {String} [typeName='bpmn:Definitions'] name of the root element
14340 * @param {Object} [options] options to pass to the underlying reader
14341 *
14342 * @returns {Promise<ParseResult, ParseError>}
14343 */
14344 BpmnModdle.prototype.fromXML = function(xmlStr, typeName, options) {
14345
14346 if (!isString(typeName)) {
14347 options = typeName;
14348 typeName = 'bpmn:Definitions';
14349 }
14350
14351 var reader = new Reader(assign({ model: this, lax: true }, options));
14352 var rootHandler = reader.handler(typeName);
14353
14354 return reader.fromXML(xmlStr, rootHandler);
14355 };
14356
14357
14358 /**
14359 * The toXML result.
14360 *
14361 * @typedef {Object} SerializationResult
14362 *
14363 * @property {String} xml
14364 */
14365
14366 /**
14367 * Serializes a BPMN 2.0 object tree to XML.
14368 *
14369 * @param {String} element the root element, typically an instance of `bpmn:Definitions`
14370 * @param {Object} [options] to pass to the underlying writer
14371 *
14372 * @returns {Promise<SerializationResult, Error>}
14373 */
14374 BpmnModdle.prototype.toXML = function(element, options) {
14375
14376 var writer = new Writer(options);
14377
14378 return new Promise(function(resolve, reject) {
14379 try {
14380 var result = writer.toXML(element);
14381
14382 return resolve({
14383 xml: result
14384 });
14385 } catch (err) {
14386 return reject(err);
14387 }
14388 });
14389 };
14390
14391 var name = "BPMN20";
14392 var uri = "http://www.omg.org/spec/BPMN/20100524/MODEL";
14393 var prefix$1 = "bpmn";
14394 var associations = [
14395 ];
14396 var types$1 = [
14397 {
14398 name: "Interface",
14399 superClass: [
14400 "RootElement"
14401 ],
14402 properties: [
14403 {
14404 name: "name",
14405 isAttr: true,
14406 type: "String"
14407 },
14408 {
14409 name: "operations",
14410 type: "Operation",
14411 isMany: true
14412 },
14413 {
14414 name: "implementationRef",
14415 isAttr: true,
14416 type: "String"
14417 }
14418 ]
14419 },
14420 {
14421 name: "Operation",
14422 superClass: [
14423 "BaseElement"
14424 ],
14425 properties: [
14426 {
14427 name: "name",
14428 isAttr: true,
14429 type: "String"
14430 },
14431 {
14432 name: "inMessageRef",
14433 type: "Message",
14434 isReference: true
14435 },
14436 {
14437 name: "outMessageRef",
14438 type: "Message",
14439 isReference: true
14440 },
14441 {
14442 name: "errorRef",
14443 type: "Error",
14444 isMany: true,
14445 isReference: true
14446 },
14447 {
14448 name: "implementationRef",
14449 isAttr: true,
14450 type: "String"
14451 }
14452 ]
14453 },
14454 {
14455 name: "EndPoint",
14456 superClass: [
14457 "RootElement"
14458 ]
14459 },
14460 {
14461 name: "Auditing",
14462 superClass: [
14463 "BaseElement"
14464 ]
14465 },
14466 {
14467 name: "GlobalTask",
14468 superClass: [
14469 "CallableElement"
14470 ],
14471 properties: [
14472 {
14473 name: "resources",
14474 type: "ResourceRole",
14475 isMany: true
14476 }
14477 ]
14478 },
14479 {
14480 name: "Monitoring",
14481 superClass: [
14482 "BaseElement"
14483 ]
14484 },
14485 {
14486 name: "Performer",
14487 superClass: [
14488 "ResourceRole"
14489 ]
14490 },
14491 {
14492 name: "Process",
14493 superClass: [
14494 "FlowElementsContainer",
14495 "CallableElement"
14496 ],
14497 properties: [
14498 {
14499 name: "processType",
14500 type: "ProcessType",
14501 isAttr: true
14502 },
14503 {
14504 name: "isClosed",
14505 isAttr: true,
14506 type: "Boolean"
14507 },
14508 {
14509 name: "auditing",
14510 type: "Auditing"
14511 },
14512 {
14513 name: "monitoring",
14514 type: "Monitoring"
14515 },
14516 {
14517 name: "properties",
14518 type: "Property",
14519 isMany: true
14520 },
14521 {
14522 name: "laneSets",
14523 isMany: true,
14524 replaces: "FlowElementsContainer#laneSets",
14525 type: "LaneSet"
14526 },
14527 {
14528 name: "flowElements",
14529 isMany: true,
14530 replaces: "FlowElementsContainer#flowElements",
14531 type: "FlowElement"
14532 },
14533 {
14534 name: "artifacts",
14535 type: "Artifact",
14536 isMany: true
14537 },
14538 {
14539 name: "resources",
14540 type: "ResourceRole",
14541 isMany: true
14542 },
14543 {
14544 name: "correlationSubscriptions",
14545 type: "CorrelationSubscription",
14546 isMany: true
14547 },
14548 {
14549 name: "supports",
14550 type: "Process",
14551 isMany: true,
14552 isReference: true
14553 },
14554 {
14555 name: "definitionalCollaborationRef",
14556 type: "Collaboration",
14557 isAttr: true,
14558 isReference: true
14559 },
14560 {
14561 name: "isExecutable",
14562 isAttr: true,
14563 type: "Boolean"
14564 }
14565 ]
14566 },
14567 {
14568 name: "LaneSet",
14569 superClass: [
14570 "BaseElement"
14571 ],
14572 properties: [
14573 {
14574 name: "lanes",
14575 type: "Lane",
14576 isMany: true
14577 },
14578 {
14579 name: "name",
14580 isAttr: true,
14581 type: "String"
14582 }
14583 ]
14584 },
14585 {
14586 name: "Lane",
14587 superClass: [
14588 "BaseElement"
14589 ],
14590 properties: [
14591 {
14592 name: "name",
14593 isAttr: true,
14594 type: "String"
14595 },
14596 {
14597 name: "partitionElementRef",
14598 type: "BaseElement",
14599 isAttr: true,
14600 isReference: true
14601 },
14602 {
14603 name: "partitionElement",
14604 type: "BaseElement"
14605 },
14606 {
14607 name: "flowNodeRef",
14608 type: "FlowNode",
14609 isMany: true,
14610 isReference: true
14611 },
14612 {
14613 name: "childLaneSet",
14614 type: "LaneSet",
14615 xml: {
14616 serialize: "xsi:type"
14617 }
14618 }
14619 ]
14620 },
14621 {
14622 name: "GlobalManualTask",
14623 superClass: [
14624 "GlobalTask"
14625 ]
14626 },
14627 {
14628 name: "ManualTask",
14629 superClass: [
14630 "Task"
14631 ]
14632 },
14633 {
14634 name: "UserTask",
14635 superClass: [
14636 "Task"
14637 ],
14638 properties: [
14639 {
14640 name: "renderings",
14641 type: "Rendering",
14642 isMany: true
14643 },
14644 {
14645 name: "implementation",
14646 isAttr: true,
14647 type: "String"
14648 }
14649 ]
14650 },
14651 {
14652 name: "Rendering",
14653 superClass: [
14654 "BaseElement"
14655 ]
14656 },
14657 {
14658 name: "HumanPerformer",
14659 superClass: [
14660 "Performer"
14661 ]
14662 },
14663 {
14664 name: "PotentialOwner",
14665 superClass: [
14666 "HumanPerformer"
14667 ]
14668 },
14669 {
14670 name: "GlobalUserTask",
14671 superClass: [
14672 "GlobalTask"
14673 ],
14674 properties: [
14675 {
14676 name: "implementation",
14677 isAttr: true,
14678 type: "String"
14679 },
14680 {
14681 name: "renderings",
14682 type: "Rendering",
14683 isMany: true
14684 }
14685 ]
14686 },
14687 {
14688 name: "Gateway",
14689 isAbstract: true,
14690 superClass: [
14691 "FlowNode"
14692 ],
14693 properties: [
14694 {
14695 name: "gatewayDirection",
14696 type: "GatewayDirection",
14697 "default": "Unspecified",
14698 isAttr: true
14699 }
14700 ]
14701 },
14702 {
14703 name: "EventBasedGateway",
14704 superClass: [
14705 "Gateway"
14706 ],
14707 properties: [
14708 {
14709 name: "instantiate",
14710 "default": false,
14711 isAttr: true,
14712 type: "Boolean"
14713 },
14714 {
14715 name: "eventGatewayType",
14716 type: "EventBasedGatewayType",
14717 isAttr: true,
14718 "default": "Exclusive"
14719 }
14720 ]
14721 },
14722 {
14723 name: "ComplexGateway",
14724 superClass: [
14725 "Gateway"
14726 ],
14727 properties: [
14728 {
14729 name: "activationCondition",
14730 type: "Expression",
14731 xml: {
14732 serialize: "xsi:type"
14733 }
14734 },
14735 {
14736 name: "default",
14737 type: "SequenceFlow",
14738 isAttr: true,
14739 isReference: true
14740 }
14741 ]
14742 },
14743 {
14744 name: "ExclusiveGateway",
14745 superClass: [
14746 "Gateway"
14747 ],
14748 properties: [
14749 {
14750 name: "default",
14751 type: "SequenceFlow",
14752 isAttr: true,
14753 isReference: true
14754 }
14755 ]
14756 },
14757 {
14758 name: "InclusiveGateway",
14759 superClass: [
14760 "Gateway"
14761 ],
14762 properties: [
14763 {
14764 name: "default",
14765 type: "SequenceFlow",
14766 isAttr: true,
14767 isReference: true
14768 }
14769 ]
14770 },
14771 {
14772 name: "ParallelGateway",
14773 superClass: [
14774 "Gateway"
14775 ]
14776 },
14777 {
14778 name: "RootElement",
14779 isAbstract: true,
14780 superClass: [
14781 "BaseElement"
14782 ]
14783 },
14784 {
14785 name: "Relationship",
14786 superClass: [
14787 "BaseElement"
14788 ],
14789 properties: [
14790 {
14791 name: "type",
14792 isAttr: true,
14793 type: "String"
14794 },
14795 {
14796 name: "direction",
14797 type: "RelationshipDirection",
14798 isAttr: true
14799 },
14800 {
14801 name: "source",
14802 isMany: true,
14803 isReference: true,
14804 type: "Element"
14805 },
14806 {
14807 name: "target",
14808 isMany: true,
14809 isReference: true,
14810 type: "Element"
14811 }
14812 ]
14813 },
14814 {
14815 name: "BaseElement",
14816 isAbstract: true,
14817 properties: [
14818 {
14819 name: "id",
14820 isAttr: true,
14821 type: "String",
14822 isId: true
14823 },
14824 {
14825 name: "documentation",
14826 type: "Documentation",
14827 isMany: true
14828 },
14829 {
14830 name: "extensionDefinitions",
14831 type: "ExtensionDefinition",
14832 isMany: true,
14833 isReference: true
14834 },
14835 {
14836 name: "extensionElements",
14837 type: "ExtensionElements"
14838 }
14839 ]
14840 },
14841 {
14842 name: "Extension",
14843 properties: [
14844 {
14845 name: "mustUnderstand",
14846 "default": false,
14847 isAttr: true,
14848 type: "Boolean"
14849 },
14850 {
14851 name: "definition",
14852 type: "ExtensionDefinition",
14853 isAttr: true,
14854 isReference: true
14855 }
14856 ]
14857 },
14858 {
14859 name: "ExtensionDefinition",
14860 properties: [
14861 {
14862 name: "name",
14863 isAttr: true,
14864 type: "String"
14865 },
14866 {
14867 name: "extensionAttributeDefinitions",
14868 type: "ExtensionAttributeDefinition",
14869 isMany: true
14870 }
14871 ]
14872 },
14873 {
14874 name: "ExtensionAttributeDefinition",
14875 properties: [
14876 {
14877 name: "name",
14878 isAttr: true,
14879 type: "String"
14880 },
14881 {
14882 name: "type",
14883 isAttr: true,
14884 type: "String"
14885 },
14886 {
14887 name: "isReference",
14888 "default": false,
14889 isAttr: true,
14890 type: "Boolean"
14891 },
14892 {
14893 name: "extensionDefinition",
14894 type: "ExtensionDefinition",
14895 isAttr: true,
14896 isReference: true
14897 }
14898 ]
14899 },
14900 {
14901 name: "ExtensionElements",
14902 properties: [
14903 {
14904 name: "valueRef",
14905 isAttr: true,
14906 isReference: true,
14907 type: "Element"
14908 },
14909 {
14910 name: "values",
14911 type: "Element",
14912 isMany: true
14913 },
14914 {
14915 name: "extensionAttributeDefinition",
14916 type: "ExtensionAttributeDefinition",
14917 isAttr: true,
14918 isReference: true
14919 }
14920 ]
14921 },
14922 {
14923 name: "Documentation",
14924 superClass: [
14925 "BaseElement"
14926 ],
14927 properties: [
14928 {
14929 name: "text",
14930 type: "String",
14931 isBody: true
14932 },
14933 {
14934 name: "textFormat",
14935 "default": "text/plain",
14936 isAttr: true,
14937 type: "String"
14938 }
14939 ]
14940 },
14941 {
14942 name: "Event",
14943 isAbstract: true,
14944 superClass: [
14945 "FlowNode",
14946 "InteractionNode"
14947 ],
14948 properties: [
14949 {
14950 name: "properties",
14951 type: "Property",
14952 isMany: true
14953 }
14954 ]
14955 },
14956 {
14957 name: "IntermediateCatchEvent",
14958 superClass: [
14959 "CatchEvent"
14960 ]
14961 },
14962 {
14963 name: "IntermediateThrowEvent",
14964 superClass: [
14965 "ThrowEvent"
14966 ]
14967 },
14968 {
14969 name: "EndEvent",
14970 superClass: [
14971 "ThrowEvent"
14972 ]
14973 },
14974 {
14975 name: "StartEvent",
14976 superClass: [
14977 "CatchEvent"
14978 ],
14979 properties: [
14980 {
14981 name: "isInterrupting",
14982 "default": true,
14983 isAttr: true,
14984 type: "Boolean"
14985 }
14986 ]
14987 },
14988 {
14989 name: "ThrowEvent",
14990 isAbstract: true,
14991 superClass: [
14992 "Event"
14993 ],
14994 properties: [
14995 {
14996 name: "dataInputs",
14997 type: "DataInput",
14998 isMany: true
14999 },
15000 {
15001 name: "dataInputAssociations",
15002 type: "DataInputAssociation",
15003 isMany: true
15004 },
15005 {
15006 name: "inputSet",
15007 type: "InputSet"
15008 },
15009 {
15010 name: "eventDefinitions",
15011 type: "EventDefinition",
15012 isMany: true
15013 },
15014 {
15015 name: "eventDefinitionRef",
15016 type: "EventDefinition",
15017 isMany: true,
15018 isReference: true
15019 }
15020 ]
15021 },
15022 {
15023 name: "CatchEvent",
15024 isAbstract: true,
15025 superClass: [
15026 "Event"
15027 ],
15028 properties: [
15029 {
15030 name: "parallelMultiple",
15031 isAttr: true,
15032 type: "Boolean",
15033 "default": false
15034 },
15035 {
15036 name: "dataOutputs",
15037 type: "DataOutput",
15038 isMany: true
15039 },
15040 {
15041 name: "dataOutputAssociations",
15042 type: "DataOutputAssociation",
15043 isMany: true
15044 },
15045 {
15046 name: "outputSet",
15047 type: "OutputSet"
15048 },
15049 {
15050 name: "eventDefinitions",
15051 type: "EventDefinition",
15052 isMany: true
15053 },
15054 {
15055 name: "eventDefinitionRef",
15056 type: "EventDefinition",
15057 isMany: true,
15058 isReference: true
15059 }
15060 ]
15061 },
15062 {
15063 name: "BoundaryEvent",
15064 superClass: [
15065 "CatchEvent"
15066 ],
15067 properties: [
15068 {
15069 name: "cancelActivity",
15070 "default": true,
15071 isAttr: true,
15072 type: "Boolean"
15073 },
15074 {
15075 name: "attachedToRef",
15076 type: "Activity",
15077 isAttr: true,
15078 isReference: true
15079 }
15080 ]
15081 },
15082 {
15083 name: "EventDefinition",
15084 isAbstract: true,
15085 superClass: [
15086 "RootElement"
15087 ]
15088 },
15089 {
15090 name: "CancelEventDefinition",
15091 superClass: [
15092 "EventDefinition"
15093 ]
15094 },
15095 {
15096 name: "ErrorEventDefinition",
15097 superClass: [
15098 "EventDefinition"
15099 ],
15100 properties: [
15101 {
15102 name: "errorRef",
15103 type: "Error",
15104 isAttr: true,
15105 isReference: true
15106 }
15107 ]
15108 },
15109 {
15110 name: "TerminateEventDefinition",
15111 superClass: [
15112 "EventDefinition"
15113 ]
15114 },
15115 {
15116 name: "EscalationEventDefinition",
15117 superClass: [
15118 "EventDefinition"
15119 ],
15120 properties: [
15121 {
15122 name: "escalationRef",
15123 type: "Escalation",
15124 isAttr: true,
15125 isReference: true
15126 }
15127 ]
15128 },
15129 {
15130 name: "Escalation",
15131 properties: [
15132 {
15133 name: "structureRef",
15134 type: "ItemDefinition",
15135 isAttr: true,
15136 isReference: true
15137 },
15138 {
15139 name: "name",
15140 isAttr: true,
15141 type: "String"
15142 },
15143 {
15144 name: "escalationCode",
15145 isAttr: true,
15146 type: "String"
15147 }
15148 ],
15149 superClass: [
15150 "RootElement"
15151 ]
15152 },
15153 {
15154 name: "CompensateEventDefinition",
15155 superClass: [
15156 "EventDefinition"
15157 ],
15158 properties: [
15159 {
15160 name: "waitForCompletion",
15161 isAttr: true,
15162 type: "Boolean",
15163 "default": true
15164 },
15165 {
15166 name: "activityRef",
15167 type: "Activity",
15168 isAttr: true,
15169 isReference: true
15170 }
15171 ]
15172 },
15173 {
15174 name: "TimerEventDefinition",
15175 superClass: [
15176 "EventDefinition"
15177 ],
15178 properties: [
15179 {
15180 name: "timeDate",
15181 type: "Expression",
15182 xml: {
15183 serialize: "xsi:type"
15184 }
15185 },
15186 {
15187 name: "timeCycle",
15188 type: "Expression",
15189 xml: {
15190 serialize: "xsi:type"
15191 }
15192 },
15193 {
15194 name: "timeDuration",
15195 type: "Expression",
15196 xml: {
15197 serialize: "xsi:type"
15198 }
15199 }
15200 ]
15201 },
15202 {
15203 name: "LinkEventDefinition",
15204 superClass: [
15205 "EventDefinition"
15206 ],
15207 properties: [
15208 {
15209 name: "name",
15210 isAttr: true,
15211 type: "String"
15212 },
15213 {
15214 name: "target",
15215 type: "LinkEventDefinition",
15216 isAttr: true,
15217 isReference: true
15218 },
15219 {
15220 name: "source",
15221 type: "LinkEventDefinition",
15222 isMany: true,
15223 isReference: true
15224 }
15225 ]
15226 },
15227 {
15228 name: "MessageEventDefinition",
15229 superClass: [
15230 "EventDefinition"
15231 ],
15232 properties: [
15233 {
15234 name: "messageRef",
15235 type: "Message",
15236 isAttr: true,
15237 isReference: true
15238 },
15239 {
15240 name: "operationRef",
15241 type: "Operation",
15242 isAttr: true,
15243 isReference: true
15244 }
15245 ]
15246 },
15247 {
15248 name: "ConditionalEventDefinition",
15249 superClass: [
15250 "EventDefinition"
15251 ],
15252 properties: [
15253 {
15254 name: "condition",
15255 type: "Expression",
15256 xml: {
15257 serialize: "xsi:type"
15258 }
15259 }
15260 ]
15261 },
15262 {
15263 name: "SignalEventDefinition",
15264 superClass: [
15265 "EventDefinition"
15266 ],
15267 properties: [
15268 {
15269 name: "signalRef",
15270 type: "Signal",
15271 isAttr: true,
15272 isReference: true
15273 }
15274 ]
15275 },
15276 {
15277 name: "Signal",
15278 superClass: [
15279 "RootElement"
15280 ],
15281 properties: [
15282 {
15283 name: "structureRef",
15284 type: "ItemDefinition",
15285 isAttr: true,
15286 isReference: true
15287 },
15288 {
15289 name: "name",
15290 isAttr: true,
15291 type: "String"
15292 }
15293 ]
15294 },
15295 {
15296 name: "ImplicitThrowEvent",
15297 superClass: [
15298 "ThrowEvent"
15299 ]
15300 },
15301 {
15302 name: "DataState",
15303 superClass: [
15304 "BaseElement"
15305 ],
15306 properties: [
15307 {
15308 name: "name",
15309 isAttr: true,
15310 type: "String"
15311 }
15312 ]
15313 },
15314 {
15315 name: "ItemAwareElement",
15316 superClass: [
15317 "BaseElement"
15318 ],
15319 properties: [
15320 {
15321 name: "itemSubjectRef",
15322 type: "ItemDefinition",
15323 isAttr: true,
15324 isReference: true
15325 },
15326 {
15327 name: "dataState",
15328 type: "DataState"
15329 }
15330 ]
15331 },
15332 {
15333 name: "DataAssociation",
15334 superClass: [
15335 "BaseElement"
15336 ],
15337 properties: [
15338 {
15339 name: "sourceRef",
15340 type: "ItemAwareElement",
15341 isMany: true,
15342 isReference: true
15343 },
15344 {
15345 name: "targetRef",
15346 type: "ItemAwareElement",
15347 isReference: true
15348 },
15349 {
15350 name: "transformation",
15351 type: "FormalExpression",
15352 xml: {
15353 serialize: "property"
15354 }
15355 },
15356 {
15357 name: "assignment",
15358 type: "Assignment",
15359 isMany: true
15360 }
15361 ]
15362 },
15363 {
15364 name: "DataInput",
15365 superClass: [
15366 "ItemAwareElement"
15367 ],
15368 properties: [
15369 {
15370 name: "name",
15371 isAttr: true,
15372 type: "String"
15373 },
15374 {
15375 name: "isCollection",
15376 "default": false,
15377 isAttr: true,
15378 type: "Boolean"
15379 },
15380 {
15381 name: "inputSetRef",
15382 type: "InputSet",
15383 isMany: true,
15384 isVirtual: true,
15385 isReference: true
15386 },
15387 {
15388 name: "inputSetWithOptional",
15389 type: "InputSet",
15390 isMany: true,
15391 isVirtual: true,
15392 isReference: true
15393 },
15394 {
15395 name: "inputSetWithWhileExecuting",
15396 type: "InputSet",
15397 isMany: true,
15398 isVirtual: true,
15399 isReference: true
15400 }
15401 ]
15402 },
15403 {
15404 name: "DataOutput",
15405 superClass: [
15406 "ItemAwareElement"
15407 ],
15408 properties: [
15409 {
15410 name: "name",
15411 isAttr: true,
15412 type: "String"
15413 },
15414 {
15415 name: "isCollection",
15416 "default": false,
15417 isAttr: true,
15418 type: "Boolean"
15419 },
15420 {
15421 name: "outputSetRef",
15422 type: "OutputSet",
15423 isMany: true,
15424 isVirtual: true,
15425 isReference: true
15426 },
15427 {
15428 name: "outputSetWithOptional",
15429 type: "OutputSet",
15430 isMany: true,
15431 isVirtual: true,
15432 isReference: true
15433 },
15434 {
15435 name: "outputSetWithWhileExecuting",
15436 type: "OutputSet",
15437 isMany: true,
15438 isVirtual: true,
15439 isReference: true
15440 }
15441 ]
15442 },
15443 {
15444 name: "InputSet",
15445 superClass: [
15446 "BaseElement"
15447 ],
15448 properties: [
15449 {
15450 name: "name",
15451 isAttr: true,
15452 type: "String"
15453 },
15454 {
15455 name: "dataInputRefs",
15456 type: "DataInput",
15457 isMany: true,
15458 isReference: true
15459 },
15460 {
15461 name: "optionalInputRefs",
15462 type: "DataInput",
15463 isMany: true,
15464 isReference: true
15465 },
15466 {
15467 name: "whileExecutingInputRefs",
15468 type: "DataInput",
15469 isMany: true,
15470 isReference: true
15471 },
15472 {
15473 name: "outputSetRefs",
15474 type: "OutputSet",
15475 isMany: true,
15476 isReference: true
15477 }
15478 ]
15479 },
15480 {
15481 name: "OutputSet",
15482 superClass: [
15483 "BaseElement"
15484 ],
15485 properties: [
15486 {
15487 name: "dataOutputRefs",
15488 type: "DataOutput",
15489 isMany: true,
15490 isReference: true
15491 },
15492 {
15493 name: "name",
15494 isAttr: true,
15495 type: "String"
15496 },
15497 {
15498 name: "inputSetRefs",
15499 type: "InputSet",
15500 isMany: true,
15501 isReference: true
15502 },
15503 {
15504 name: "optionalOutputRefs",
15505 type: "DataOutput",
15506 isMany: true,
15507 isReference: true
15508 },
15509 {
15510 name: "whileExecutingOutputRefs",
15511 type: "DataOutput",
15512 isMany: true,
15513 isReference: true
15514 }
15515 ]
15516 },
15517 {
15518 name: "Property",
15519 superClass: [
15520 "ItemAwareElement"
15521 ],
15522 properties: [
15523 {
15524 name: "name",
15525 isAttr: true,
15526 type: "String"
15527 }
15528 ]
15529 },
15530 {
15531 name: "DataInputAssociation",
15532 superClass: [
15533 "DataAssociation"
15534 ]
15535 },
15536 {
15537 name: "DataOutputAssociation",
15538 superClass: [
15539 "DataAssociation"
15540 ]
15541 },
15542 {
15543 name: "InputOutputSpecification",
15544 superClass: [
15545 "BaseElement"
15546 ],
15547 properties: [
15548 {
15549 name: "dataInputs",
15550 type: "DataInput",
15551 isMany: true
15552 },
15553 {
15554 name: "dataOutputs",
15555 type: "DataOutput",
15556 isMany: true
15557 },
15558 {
15559 name: "inputSets",
15560 type: "InputSet",
15561 isMany: true
15562 },
15563 {
15564 name: "outputSets",
15565 type: "OutputSet",
15566 isMany: true
15567 }
15568 ]
15569 },
15570 {
15571 name: "DataObject",
15572 superClass: [
15573 "FlowElement",
15574 "ItemAwareElement"
15575 ],
15576 properties: [
15577 {
15578 name: "isCollection",
15579 "default": false,
15580 isAttr: true,
15581 type: "Boolean"
15582 }
15583 ]
15584 },
15585 {
15586 name: "InputOutputBinding",
15587 properties: [
15588 {
15589 name: "inputDataRef",
15590 type: "InputSet",
15591 isAttr: true,
15592 isReference: true
15593 },
15594 {
15595 name: "outputDataRef",
15596 type: "OutputSet",
15597 isAttr: true,
15598 isReference: true
15599 },
15600 {
15601 name: "operationRef",
15602 type: "Operation",
15603 isAttr: true,
15604 isReference: true
15605 }
15606 ]
15607 },
15608 {
15609 name: "Assignment",
15610 superClass: [
15611 "BaseElement"
15612 ],
15613 properties: [
15614 {
15615 name: "from",
15616 type: "Expression",
15617 xml: {
15618 serialize: "xsi:type"
15619 }
15620 },
15621 {
15622 name: "to",
15623 type: "Expression",
15624 xml: {
15625 serialize: "xsi:type"
15626 }
15627 }
15628 ]
15629 },
15630 {
15631 name: "DataStore",
15632 superClass: [
15633 "RootElement",
15634 "ItemAwareElement"
15635 ],
15636 properties: [
15637 {
15638 name: "name",
15639 isAttr: true,
15640 type: "String"
15641 },
15642 {
15643 name: "capacity",
15644 isAttr: true,
15645 type: "Integer"
15646 },
15647 {
15648 name: "isUnlimited",
15649 "default": true,
15650 isAttr: true,
15651 type: "Boolean"
15652 }
15653 ]
15654 },
15655 {
15656 name: "DataStoreReference",
15657 superClass: [
15658 "ItemAwareElement",
15659 "FlowElement"
15660 ],
15661 properties: [
15662 {
15663 name: "dataStoreRef",
15664 type: "DataStore",
15665 isAttr: true,
15666 isReference: true
15667 }
15668 ]
15669 },
15670 {
15671 name: "DataObjectReference",
15672 superClass: [
15673 "ItemAwareElement",
15674 "FlowElement"
15675 ],
15676 properties: [
15677 {
15678 name: "dataObjectRef",
15679 type: "DataObject",
15680 isAttr: true,
15681 isReference: true
15682 }
15683 ]
15684 },
15685 {
15686 name: "ConversationLink",
15687 superClass: [
15688 "BaseElement"
15689 ],
15690 properties: [
15691 {
15692 name: "sourceRef",
15693 type: "InteractionNode",
15694 isAttr: true,
15695 isReference: true
15696 },
15697 {
15698 name: "targetRef",
15699 type: "InteractionNode",
15700 isAttr: true,
15701 isReference: true
15702 },
15703 {
15704 name: "name",
15705 isAttr: true,
15706 type: "String"
15707 }
15708 ]
15709 },
15710 {
15711 name: "ConversationAssociation",
15712 superClass: [
15713 "BaseElement"
15714 ],
15715 properties: [
15716 {
15717 name: "innerConversationNodeRef",
15718 type: "ConversationNode",
15719 isAttr: true,
15720 isReference: true
15721 },
15722 {
15723 name: "outerConversationNodeRef",
15724 type: "ConversationNode",
15725 isAttr: true,
15726 isReference: true
15727 }
15728 ]
15729 },
15730 {
15731 name: "CallConversation",
15732 superClass: [
15733 "ConversationNode"
15734 ],
15735 properties: [
15736 {
15737 name: "calledCollaborationRef",
15738 type: "Collaboration",
15739 isAttr: true,
15740 isReference: true
15741 },
15742 {
15743 name: "participantAssociations",
15744 type: "ParticipantAssociation",
15745 isMany: true
15746 }
15747 ]
15748 },
15749 {
15750 name: "Conversation",
15751 superClass: [
15752 "ConversationNode"
15753 ]
15754 },
15755 {
15756 name: "SubConversation",
15757 superClass: [
15758 "ConversationNode"
15759 ],
15760 properties: [
15761 {
15762 name: "conversationNodes",
15763 type: "ConversationNode",
15764 isMany: true
15765 }
15766 ]
15767 },
15768 {
15769 name: "ConversationNode",
15770 isAbstract: true,
15771 superClass: [
15772 "InteractionNode",
15773 "BaseElement"
15774 ],
15775 properties: [
15776 {
15777 name: "name",
15778 isAttr: true,
15779 type: "String"
15780 },
15781 {
15782 name: "participantRef",
15783 type: "Participant",
15784 isMany: true,
15785 isReference: true
15786 },
15787 {
15788 name: "messageFlowRefs",
15789 type: "MessageFlow",
15790 isMany: true,
15791 isReference: true
15792 },
15793 {
15794 name: "correlationKeys",
15795 type: "CorrelationKey",
15796 isMany: true
15797 }
15798 ]
15799 },
15800 {
15801 name: "GlobalConversation",
15802 superClass: [
15803 "Collaboration"
15804 ]
15805 },
15806 {
15807 name: "PartnerEntity",
15808 superClass: [
15809 "RootElement"
15810 ],
15811 properties: [
15812 {
15813 name: "name",
15814 isAttr: true,
15815 type: "String"
15816 },
15817 {
15818 name: "participantRef",
15819 type: "Participant",
15820 isMany: true,
15821 isReference: true
15822 }
15823 ]
15824 },
15825 {
15826 name: "PartnerRole",
15827 superClass: [
15828 "RootElement"
15829 ],
15830 properties: [
15831 {
15832 name: "name",
15833 isAttr: true,
15834 type: "String"
15835 },
15836 {
15837 name: "participantRef",
15838 type: "Participant",
15839 isMany: true,
15840 isReference: true
15841 }
15842 ]
15843 },
15844 {
15845 name: "CorrelationProperty",
15846 superClass: [
15847 "RootElement"
15848 ],
15849 properties: [
15850 {
15851 name: "correlationPropertyRetrievalExpression",
15852 type: "CorrelationPropertyRetrievalExpression",
15853 isMany: true
15854 },
15855 {
15856 name: "name",
15857 isAttr: true,
15858 type: "String"
15859 },
15860 {
15861 name: "type",
15862 type: "ItemDefinition",
15863 isAttr: true,
15864 isReference: true
15865 }
15866 ]
15867 },
15868 {
15869 name: "Error",
15870 superClass: [
15871 "RootElement"
15872 ],
15873 properties: [
15874 {
15875 name: "structureRef",
15876 type: "ItemDefinition",
15877 isAttr: true,
15878 isReference: true
15879 },
15880 {
15881 name: "name",
15882 isAttr: true,
15883 type: "String"
15884 },
15885 {
15886 name: "errorCode",
15887 isAttr: true,
15888 type: "String"
15889 }
15890 ]
15891 },
15892 {
15893 name: "CorrelationKey",
15894 superClass: [
15895 "BaseElement"
15896 ],
15897 properties: [
15898 {
15899 name: "correlationPropertyRef",
15900 type: "CorrelationProperty",
15901 isMany: true,
15902 isReference: true
15903 },
15904 {
15905 name: "name",
15906 isAttr: true,
15907 type: "String"
15908 }
15909 ]
15910 },
15911 {
15912 name: "Expression",
15913 superClass: [
15914 "BaseElement"
15915 ],
15916 isAbstract: false,
15917 properties: [
15918 {
15919 name: "body",
15920 isBody: true,
15921 type: "String"
15922 }
15923 ]
15924 },
15925 {
15926 name: "FormalExpression",
15927 superClass: [
15928 "Expression"
15929 ],
15930 properties: [
15931 {
15932 name: "language",
15933 isAttr: true,
15934 type: "String"
15935 },
15936 {
15937 name: "evaluatesToTypeRef",
15938 type: "ItemDefinition",
15939 isAttr: true,
15940 isReference: true
15941 }
15942 ]
15943 },
15944 {
15945 name: "Message",
15946 superClass: [
15947 "RootElement"
15948 ],
15949 properties: [
15950 {
15951 name: "name",
15952 isAttr: true,
15953 type: "String"
15954 },
15955 {
15956 name: "itemRef",
15957 type: "ItemDefinition",
15958 isAttr: true,
15959 isReference: true
15960 }
15961 ]
15962 },
15963 {
15964 name: "ItemDefinition",
15965 superClass: [
15966 "RootElement"
15967 ],
15968 properties: [
15969 {
15970 name: "itemKind",
15971 type: "ItemKind",
15972 isAttr: true
15973 },
15974 {
15975 name: "structureRef",
15976 isAttr: true,
15977 type: "String"
15978 },
15979 {
15980 name: "isCollection",
15981 "default": false,
15982 isAttr: true,
15983 type: "Boolean"
15984 },
15985 {
15986 name: "import",
15987 type: "Import",
15988 isAttr: true,
15989 isReference: true
15990 }
15991 ]
15992 },
15993 {
15994 name: "FlowElement",
15995 isAbstract: true,
15996 superClass: [
15997 "BaseElement"
15998 ],
15999 properties: [
16000 {
16001 name: "name",
16002 isAttr: true,
16003 type: "String"
16004 },
16005 {
16006 name: "auditing",
16007 type: "Auditing"
16008 },
16009 {
16010 name: "monitoring",
16011 type: "Monitoring"
16012 },
16013 {
16014 name: "categoryValueRef",
16015 type: "CategoryValue",
16016 isMany: true,
16017 isReference: true
16018 }
16019 ]
16020 },
16021 {
16022 name: "SequenceFlow",
16023 superClass: [
16024 "FlowElement"
16025 ],
16026 properties: [
16027 {
16028 name: "isImmediate",
16029 isAttr: true,
16030 type: "Boolean"
16031 },
16032 {
16033 name: "conditionExpression",
16034 type: "Expression",
16035 xml: {
16036 serialize: "xsi:type"
16037 }
16038 },
16039 {
16040 name: "sourceRef",
16041 type: "FlowNode",
16042 isAttr: true,
16043 isReference: true
16044 },
16045 {
16046 name: "targetRef",
16047 type: "FlowNode",
16048 isAttr: true,
16049 isReference: true
16050 }
16051 ]
16052 },
16053 {
16054 name: "FlowElementsContainer",
16055 isAbstract: true,
16056 superClass: [
16057 "BaseElement"
16058 ],
16059 properties: [
16060 {
16061 name: "laneSets",
16062 type: "LaneSet",
16063 isMany: true
16064 },
16065 {
16066 name: "flowElements",
16067 type: "FlowElement",
16068 isMany: true
16069 }
16070 ]
16071 },
16072 {
16073 name: "CallableElement",
16074 isAbstract: true,
16075 superClass: [
16076 "RootElement"
16077 ],
16078 properties: [
16079 {
16080 name: "name",
16081 isAttr: true,
16082 type: "String"
16083 },
16084 {
16085 name: "ioSpecification",
16086 type: "InputOutputSpecification",
16087 xml: {
16088 serialize: "property"
16089 }
16090 },
16091 {
16092 name: "supportedInterfaceRef",
16093 type: "Interface",
16094 isMany: true,
16095 isReference: true
16096 },
16097 {
16098 name: "ioBinding",
16099 type: "InputOutputBinding",
16100 isMany: true,
16101 xml: {
16102 serialize: "property"
16103 }
16104 }
16105 ]
16106 },
16107 {
16108 name: "FlowNode",
16109 isAbstract: true,
16110 superClass: [
16111 "FlowElement"
16112 ],
16113 properties: [
16114 {
16115 name: "incoming",
16116 type: "SequenceFlow",
16117 isMany: true,
16118 isReference: true
16119 },
16120 {
16121 name: "outgoing",
16122 type: "SequenceFlow",
16123 isMany: true,
16124 isReference: true
16125 },
16126 {
16127 name: "lanes",
16128 type: "Lane",
16129 isMany: true,
16130 isVirtual: true,
16131 isReference: true
16132 }
16133 ]
16134 },
16135 {
16136 name: "CorrelationPropertyRetrievalExpression",
16137 superClass: [
16138 "BaseElement"
16139 ],
16140 properties: [
16141 {
16142 name: "messagePath",
16143 type: "FormalExpression"
16144 },
16145 {
16146 name: "messageRef",
16147 type: "Message",
16148 isAttr: true,
16149 isReference: true
16150 }
16151 ]
16152 },
16153 {
16154 name: "CorrelationPropertyBinding",
16155 superClass: [
16156 "BaseElement"
16157 ],
16158 properties: [
16159 {
16160 name: "dataPath",
16161 type: "FormalExpression"
16162 },
16163 {
16164 name: "correlationPropertyRef",
16165 type: "CorrelationProperty",
16166 isAttr: true,
16167 isReference: true
16168 }
16169 ]
16170 },
16171 {
16172 name: "Resource",
16173 superClass: [
16174 "RootElement"
16175 ],
16176 properties: [
16177 {
16178 name: "name",
16179 isAttr: true,
16180 type: "String"
16181 },
16182 {
16183 name: "resourceParameters",
16184 type: "ResourceParameter",
16185 isMany: true
16186 }
16187 ]
16188 },
16189 {
16190 name: "ResourceParameter",
16191 superClass: [
16192 "BaseElement"
16193 ],
16194 properties: [
16195 {
16196 name: "name",
16197 isAttr: true,
16198 type: "String"
16199 },
16200 {
16201 name: "isRequired",
16202 isAttr: true,
16203 type: "Boolean"
16204 },
16205 {
16206 name: "type",
16207 type: "ItemDefinition",
16208 isAttr: true,
16209 isReference: true
16210 }
16211 ]
16212 },
16213 {
16214 name: "CorrelationSubscription",
16215 superClass: [
16216 "BaseElement"
16217 ],
16218 properties: [
16219 {
16220 name: "correlationKeyRef",
16221 type: "CorrelationKey",
16222 isAttr: true,
16223 isReference: true
16224 },
16225 {
16226 name: "correlationPropertyBinding",
16227 type: "CorrelationPropertyBinding",
16228 isMany: true
16229 }
16230 ]
16231 },
16232 {
16233 name: "MessageFlow",
16234 superClass: [
16235 "BaseElement"
16236 ],
16237 properties: [
16238 {
16239 name: "name",
16240 isAttr: true,
16241 type: "String"
16242 },
16243 {
16244 name: "sourceRef",
16245 type: "InteractionNode",
16246 isAttr: true,
16247 isReference: true
16248 },
16249 {
16250 name: "targetRef",
16251 type: "InteractionNode",
16252 isAttr: true,
16253 isReference: true
16254 },
16255 {
16256 name: "messageRef",
16257 type: "Message",
16258 isAttr: true,
16259 isReference: true
16260 }
16261 ]
16262 },
16263 {
16264 name: "MessageFlowAssociation",
16265 superClass: [
16266 "BaseElement"
16267 ],
16268 properties: [
16269 {
16270 name: "innerMessageFlowRef",
16271 type: "MessageFlow",
16272 isAttr: true,
16273 isReference: true
16274 },
16275 {
16276 name: "outerMessageFlowRef",
16277 type: "MessageFlow",
16278 isAttr: true,
16279 isReference: true
16280 }
16281 ]
16282 },
16283 {
16284 name: "InteractionNode",
16285 isAbstract: true,
16286 properties: [
16287 {
16288 name: "incomingConversationLinks",
16289 type: "ConversationLink",
16290 isMany: true,
16291 isVirtual: true,
16292 isReference: true
16293 },
16294 {
16295 name: "outgoingConversationLinks",
16296 type: "ConversationLink",
16297 isMany: true,
16298 isVirtual: true,
16299 isReference: true
16300 }
16301 ]
16302 },
16303 {
16304 name: "Participant",
16305 superClass: [
16306 "InteractionNode",
16307 "BaseElement"
16308 ],
16309 properties: [
16310 {
16311 name: "name",
16312 isAttr: true,
16313 type: "String"
16314 },
16315 {
16316 name: "interfaceRef",
16317 type: "Interface",
16318 isMany: true,
16319 isReference: true
16320 },
16321 {
16322 name: "participantMultiplicity",
16323 type: "ParticipantMultiplicity"
16324 },
16325 {
16326 name: "endPointRefs",
16327 type: "EndPoint",
16328 isMany: true,
16329 isReference: true
16330 },
16331 {
16332 name: "processRef",
16333 type: "Process",
16334 isAttr: true,
16335 isReference: true
16336 }
16337 ]
16338 },
16339 {
16340 name: "ParticipantAssociation",
16341 superClass: [
16342 "BaseElement"
16343 ],
16344 properties: [
16345 {
16346 name: "innerParticipantRef",
16347 type: "Participant",
16348 isAttr: true,
16349 isReference: true
16350 },
16351 {
16352 name: "outerParticipantRef",
16353 type: "Participant",
16354 isAttr: true,
16355 isReference: true
16356 }
16357 ]
16358 },
16359 {
16360 name: "ParticipantMultiplicity",
16361 properties: [
16362 {
16363 name: "minimum",
16364 "default": 0,
16365 isAttr: true,
16366 type: "Integer"
16367 },
16368 {
16369 name: "maximum",
16370 "default": 1,
16371 isAttr: true,
16372 type: "Integer"
16373 }
16374 ],
16375 superClass: [
16376 "BaseElement"
16377 ]
16378 },
16379 {
16380 name: "Collaboration",
16381 superClass: [
16382 "RootElement"
16383 ],
16384 properties: [
16385 {
16386 name: "name",
16387 isAttr: true,
16388 type: "String"
16389 },
16390 {
16391 name: "isClosed",
16392 isAttr: true,
16393 type: "Boolean"
16394 },
16395 {
16396 name: "participants",
16397 type: "Participant",
16398 isMany: true
16399 },
16400 {
16401 name: "messageFlows",
16402 type: "MessageFlow",
16403 isMany: true
16404 },
16405 {
16406 name: "artifacts",
16407 type: "Artifact",
16408 isMany: true
16409 },
16410 {
16411 name: "conversations",
16412 type: "ConversationNode",
16413 isMany: true
16414 },
16415 {
16416 name: "conversationAssociations",
16417 type: "ConversationAssociation"
16418 },
16419 {
16420 name: "participantAssociations",
16421 type: "ParticipantAssociation",
16422 isMany: true
16423 },
16424 {
16425 name: "messageFlowAssociations",
16426 type: "MessageFlowAssociation",
16427 isMany: true
16428 },
16429 {
16430 name: "correlationKeys",
16431 type: "CorrelationKey",
16432 isMany: true
16433 },
16434 {
16435 name: "choreographyRef",
16436 type: "Choreography",
16437 isMany: true,
16438 isReference: true
16439 },
16440 {
16441 name: "conversationLinks",
16442 type: "ConversationLink",
16443 isMany: true
16444 }
16445 ]
16446 },
16447 {
16448 name: "ChoreographyActivity",
16449 isAbstract: true,
16450 superClass: [
16451 "FlowNode"
16452 ],
16453 properties: [
16454 {
16455 name: "participantRef",
16456 type: "Participant",
16457 isMany: true,
16458 isReference: true
16459 },
16460 {
16461 name: "initiatingParticipantRef",
16462 type: "Participant",
16463 isAttr: true,
16464 isReference: true
16465 },
16466 {
16467 name: "correlationKeys",
16468 type: "CorrelationKey",
16469 isMany: true
16470 },
16471 {
16472 name: "loopType",
16473 type: "ChoreographyLoopType",
16474 "default": "None",
16475 isAttr: true
16476 }
16477 ]
16478 },
16479 {
16480 name: "CallChoreography",
16481 superClass: [
16482 "ChoreographyActivity"
16483 ],
16484 properties: [
16485 {
16486 name: "calledChoreographyRef",
16487 type: "Choreography",
16488 isAttr: true,
16489 isReference: true
16490 },
16491 {
16492 name: "participantAssociations",
16493 type: "ParticipantAssociation",
16494 isMany: true
16495 }
16496 ]
16497 },
16498 {
16499 name: "SubChoreography",
16500 superClass: [
16501 "ChoreographyActivity",
16502 "FlowElementsContainer"
16503 ],
16504 properties: [
16505 {
16506 name: "artifacts",
16507 type: "Artifact",
16508 isMany: true
16509 }
16510 ]
16511 },
16512 {
16513 name: "ChoreographyTask",
16514 superClass: [
16515 "ChoreographyActivity"
16516 ],
16517 properties: [
16518 {
16519 name: "messageFlowRef",
16520 type: "MessageFlow",
16521 isMany: true,
16522 isReference: true
16523 }
16524 ]
16525 },
16526 {
16527 name: "Choreography",
16528 superClass: [
16529 "Collaboration",
16530 "FlowElementsContainer"
16531 ]
16532 },
16533 {
16534 name: "GlobalChoreographyTask",
16535 superClass: [
16536 "Choreography"
16537 ],
16538 properties: [
16539 {
16540 name: "initiatingParticipantRef",
16541 type: "Participant",
16542 isAttr: true,
16543 isReference: true
16544 }
16545 ]
16546 },
16547 {
16548 name: "TextAnnotation",
16549 superClass: [
16550 "Artifact"
16551 ],
16552 properties: [
16553 {
16554 name: "text",
16555 type: "String"
16556 },
16557 {
16558 name: "textFormat",
16559 "default": "text/plain",
16560 isAttr: true,
16561 type: "String"
16562 }
16563 ]
16564 },
16565 {
16566 name: "Group",
16567 superClass: [
16568 "Artifact"
16569 ],
16570 properties: [
16571 {
16572 name: "categoryValueRef",
16573 type: "CategoryValue",
16574 isAttr: true,
16575 isReference: true
16576 }
16577 ]
16578 },
16579 {
16580 name: "Association",
16581 superClass: [
16582 "Artifact"
16583 ],
16584 properties: [
16585 {
16586 name: "associationDirection",
16587 type: "AssociationDirection",
16588 isAttr: true
16589 },
16590 {
16591 name: "sourceRef",
16592 type: "BaseElement",
16593 isAttr: true,
16594 isReference: true
16595 },
16596 {
16597 name: "targetRef",
16598 type: "BaseElement",
16599 isAttr: true,
16600 isReference: true
16601 }
16602 ]
16603 },
16604 {
16605 name: "Category",
16606 superClass: [
16607 "RootElement"
16608 ],
16609 properties: [
16610 {
16611 name: "categoryValue",
16612 type: "CategoryValue",
16613 isMany: true
16614 },
16615 {
16616 name: "name",
16617 isAttr: true,
16618 type: "String"
16619 }
16620 ]
16621 },
16622 {
16623 name: "Artifact",
16624 isAbstract: true,
16625 superClass: [
16626 "BaseElement"
16627 ]
16628 },
16629 {
16630 name: "CategoryValue",
16631 superClass: [
16632 "BaseElement"
16633 ],
16634 properties: [
16635 {
16636 name: "categorizedFlowElements",
16637 type: "FlowElement",
16638 isMany: true,
16639 isVirtual: true,
16640 isReference: true
16641 },
16642 {
16643 name: "value",
16644 isAttr: true,
16645 type: "String"
16646 }
16647 ]
16648 },
16649 {
16650 name: "Activity",
16651 isAbstract: true,
16652 superClass: [
16653 "FlowNode"
16654 ],
16655 properties: [
16656 {
16657 name: "isForCompensation",
16658 "default": false,
16659 isAttr: true,
16660 type: "Boolean"
16661 },
16662 {
16663 name: "default",
16664 type: "SequenceFlow",
16665 isAttr: true,
16666 isReference: true
16667 },
16668 {
16669 name: "ioSpecification",
16670 type: "InputOutputSpecification",
16671 xml: {
16672 serialize: "property"
16673 }
16674 },
16675 {
16676 name: "boundaryEventRefs",
16677 type: "BoundaryEvent",
16678 isMany: true,
16679 isReference: true
16680 },
16681 {
16682 name: "properties",
16683 type: "Property",
16684 isMany: true
16685 },
16686 {
16687 name: "dataInputAssociations",
16688 type: "DataInputAssociation",
16689 isMany: true
16690 },
16691 {
16692 name: "dataOutputAssociations",
16693 type: "DataOutputAssociation",
16694 isMany: true
16695 },
16696 {
16697 name: "startQuantity",
16698 "default": 1,
16699 isAttr: true,
16700 type: "Integer"
16701 },
16702 {
16703 name: "resources",
16704 type: "ResourceRole",
16705 isMany: true
16706 },
16707 {
16708 name: "completionQuantity",
16709 "default": 1,
16710 isAttr: true,
16711 type: "Integer"
16712 },
16713 {
16714 name: "loopCharacteristics",
16715 type: "LoopCharacteristics"
16716 }
16717 ]
16718 },
16719 {
16720 name: "ServiceTask",
16721 superClass: [
16722 "Task"
16723 ],
16724 properties: [
16725 {
16726 name: "implementation",
16727 isAttr: true,
16728 type: "String"
16729 },
16730 {
16731 name: "operationRef",
16732 type: "Operation",
16733 isAttr: true,
16734 isReference: true
16735 }
16736 ]
16737 },
16738 {
16739 name: "SubProcess",
16740 superClass: [
16741 "Activity",
16742 "FlowElementsContainer",
16743 "InteractionNode"
16744 ],
16745 properties: [
16746 {
16747 name: "triggeredByEvent",
16748 "default": false,
16749 isAttr: true,
16750 type: "Boolean"
16751 },
16752 {
16753 name: "artifacts",
16754 type: "Artifact",
16755 isMany: true
16756 }
16757 ]
16758 },
16759 {
16760 name: "LoopCharacteristics",
16761 isAbstract: true,
16762 superClass: [
16763 "BaseElement"
16764 ]
16765 },
16766 {
16767 name: "MultiInstanceLoopCharacteristics",
16768 superClass: [
16769 "LoopCharacteristics"
16770 ],
16771 properties: [
16772 {
16773 name: "isSequential",
16774 "default": false,
16775 isAttr: true,
16776 type: "Boolean"
16777 },
16778 {
16779 name: "behavior",
16780 type: "MultiInstanceBehavior",
16781 "default": "All",
16782 isAttr: true
16783 },
16784 {
16785 name: "loopCardinality",
16786 type: "Expression",
16787 xml: {
16788 serialize: "xsi:type"
16789 }
16790 },
16791 {
16792 name: "loopDataInputRef",
16793 type: "ItemAwareElement",
16794 isReference: true
16795 },
16796 {
16797 name: "loopDataOutputRef",
16798 type: "ItemAwareElement",
16799 isReference: true
16800 },
16801 {
16802 name: "inputDataItem",
16803 type: "DataInput",
16804 xml: {
16805 serialize: "property"
16806 }
16807 },
16808 {
16809 name: "outputDataItem",
16810 type: "DataOutput",
16811 xml: {
16812 serialize: "property"
16813 }
16814 },
16815 {
16816 name: "complexBehaviorDefinition",
16817 type: "ComplexBehaviorDefinition",
16818 isMany: true
16819 },
16820 {
16821 name: "completionCondition",
16822 type: "Expression",
16823 xml: {
16824 serialize: "xsi:type"
16825 }
16826 },
16827 {
16828 name: "oneBehaviorEventRef",
16829 type: "EventDefinition",
16830 isAttr: true,
16831 isReference: true
16832 },
16833 {
16834 name: "noneBehaviorEventRef",
16835 type: "EventDefinition",
16836 isAttr: true,
16837 isReference: true
16838 }
16839 ]
16840 },
16841 {
16842 name: "StandardLoopCharacteristics",
16843 superClass: [
16844 "LoopCharacteristics"
16845 ],
16846 properties: [
16847 {
16848 name: "testBefore",
16849 "default": false,
16850 isAttr: true,
16851 type: "Boolean"
16852 },
16853 {
16854 name: "loopCondition",
16855 type: "Expression",
16856 xml: {
16857 serialize: "xsi:type"
16858 }
16859 },
16860 {
16861 name: "loopMaximum",
16862 type: "Integer",
16863 isAttr: true
16864 }
16865 ]
16866 },
16867 {
16868 name: "CallActivity",
16869 superClass: [
16870 "Activity"
16871 ],
16872 properties: [
16873 {
16874 name: "calledElement",
16875 type: "String",
16876 isAttr: true
16877 }
16878 ]
16879 },
16880 {
16881 name: "Task",
16882 superClass: [
16883 "Activity",
16884 "InteractionNode"
16885 ]
16886 },
16887 {
16888 name: "SendTask",
16889 superClass: [
16890 "Task"
16891 ],
16892 properties: [
16893 {
16894 name: "implementation",
16895 isAttr: true,
16896 type: "String"
16897 },
16898 {
16899 name: "operationRef",
16900 type: "Operation",
16901 isAttr: true,
16902 isReference: true
16903 },
16904 {
16905 name: "messageRef",
16906 type: "Message",
16907 isAttr: true,
16908 isReference: true
16909 }
16910 ]
16911 },
16912 {
16913 name: "ReceiveTask",
16914 superClass: [
16915 "Task"
16916 ],
16917 properties: [
16918 {
16919 name: "implementation",
16920 isAttr: true,
16921 type: "String"
16922 },
16923 {
16924 name: "instantiate",
16925 "default": false,
16926 isAttr: true,
16927 type: "Boolean"
16928 },
16929 {
16930 name: "operationRef",
16931 type: "Operation",
16932 isAttr: true,
16933 isReference: true
16934 },
16935 {
16936 name: "messageRef",
16937 type: "Message",
16938 isAttr: true,
16939 isReference: true
16940 }
16941 ]
16942 },
16943 {
16944 name: "ScriptTask",
16945 superClass: [
16946 "Task"
16947 ],
16948 properties: [
16949 {
16950 name: "scriptFormat",
16951 isAttr: true,
16952 type: "String"
16953 },
16954 {
16955 name: "script",
16956 type: "String"
16957 }
16958 ]
16959 },
16960 {
16961 name: "BusinessRuleTask",
16962 superClass: [
16963 "Task"
16964 ],
16965 properties: [
16966 {
16967 name: "implementation",
16968 isAttr: true,
16969 type: "String"
16970 }
16971 ]
16972 },
16973 {
16974 name: "AdHocSubProcess",
16975 superClass: [
16976 "SubProcess"
16977 ],
16978 properties: [
16979 {
16980 name: "completionCondition",
16981 type: "Expression",
16982 xml: {
16983 serialize: "xsi:type"
16984 }
16985 },
16986 {
16987 name: "ordering",
16988 type: "AdHocOrdering",
16989 isAttr: true
16990 },
16991 {
16992 name: "cancelRemainingInstances",
16993 "default": true,
16994 isAttr: true,
16995 type: "Boolean"
16996 }
16997 ]
16998 },
16999 {
17000 name: "Transaction",
17001 superClass: [
17002 "SubProcess"
17003 ],
17004 properties: [
17005 {
17006 name: "protocol",
17007 isAttr: true,
17008 type: "String"
17009 },
17010 {
17011 name: "method",
17012 isAttr: true,
17013 type: "String"
17014 }
17015 ]
17016 },
17017 {
17018 name: "GlobalScriptTask",
17019 superClass: [
17020 "GlobalTask"
17021 ],
17022 properties: [
17023 {
17024 name: "scriptLanguage",
17025 isAttr: true,
17026 type: "String"
17027 },
17028 {
17029 name: "script",
17030 isAttr: true,
17031 type: "String"
17032 }
17033 ]
17034 },
17035 {
17036 name: "GlobalBusinessRuleTask",
17037 superClass: [
17038 "GlobalTask"
17039 ],
17040 properties: [
17041 {
17042 name: "implementation",
17043 isAttr: true,
17044 type: "String"
17045 }
17046 ]
17047 },
17048 {
17049 name: "ComplexBehaviorDefinition",
17050 superClass: [
17051 "BaseElement"
17052 ],
17053 properties: [
17054 {
17055 name: "condition",
17056 type: "FormalExpression"
17057 },
17058 {
17059 name: "event",
17060 type: "ImplicitThrowEvent"
17061 }
17062 ]
17063 },
17064 {
17065 name: "ResourceRole",
17066 superClass: [
17067 "BaseElement"
17068 ],
17069 properties: [
17070 {
17071 name: "resourceRef",
17072 type: "Resource",
17073 isReference: true
17074 },
17075 {
17076 name: "resourceParameterBindings",
17077 type: "ResourceParameterBinding",
17078 isMany: true
17079 },
17080 {
17081 name: "resourceAssignmentExpression",
17082 type: "ResourceAssignmentExpression"
17083 },
17084 {
17085 name: "name",
17086 isAttr: true,
17087 type: "String"
17088 }
17089 ]
17090 },
17091 {
17092 name: "ResourceParameterBinding",
17093 properties: [
17094 {
17095 name: "expression",
17096 type: "Expression",
17097 xml: {
17098 serialize: "xsi:type"
17099 }
17100 },
17101 {
17102 name: "parameterRef",
17103 type: "ResourceParameter",
17104 isAttr: true,
17105 isReference: true
17106 }
17107 ],
17108 superClass: [
17109 "BaseElement"
17110 ]
17111 },
17112 {
17113 name: "ResourceAssignmentExpression",
17114 properties: [
17115 {
17116 name: "expression",
17117 type: "Expression",
17118 xml: {
17119 serialize: "xsi:type"
17120 }
17121 }
17122 ],
17123 superClass: [
17124 "BaseElement"
17125 ]
17126 },
17127 {
17128 name: "Import",
17129 properties: [
17130 {
17131 name: "importType",
17132 isAttr: true,
17133 type: "String"
17134 },
17135 {
17136 name: "location",
17137 isAttr: true,
17138 type: "String"
17139 },
17140 {
17141 name: "namespace",
17142 isAttr: true,
17143 type: "String"
17144 }
17145 ]
17146 },
17147 {
17148 name: "Definitions",
17149 superClass: [
17150 "BaseElement"
17151 ],
17152 properties: [
17153 {
17154 name: "name",
17155 isAttr: true,
17156 type: "String"
17157 },
17158 {
17159 name: "targetNamespace",
17160 isAttr: true,
17161 type: "String"
17162 },
17163 {
17164 name: "expressionLanguage",
17165 "default": "http://www.w3.org/1999/XPath",
17166 isAttr: true,
17167 type: "String"
17168 },
17169 {
17170 name: "typeLanguage",
17171 "default": "http://www.w3.org/2001/XMLSchema",
17172 isAttr: true,
17173 type: "String"
17174 },
17175 {
17176 name: "imports",
17177 type: "Import",
17178 isMany: true
17179 },
17180 {
17181 name: "extensions",
17182 type: "Extension",
17183 isMany: true
17184 },
17185 {
17186 name: "rootElements",
17187 type: "RootElement",
17188 isMany: true
17189 },
17190 {
17191 name: "diagrams",
17192 isMany: true,
17193 type: "bpmndi:BPMNDiagram"
17194 },
17195 {
17196 name: "exporter",
17197 isAttr: true,
17198 type: "String"
17199 },
17200 {
17201 name: "relationships",
17202 type: "Relationship",
17203 isMany: true
17204 },
17205 {
17206 name: "exporterVersion",
17207 isAttr: true,
17208 type: "String"
17209 }
17210 ]
17211 }
17212 ];
17213 var enumerations = [
17214 {
17215 name: "ProcessType",
17216 literalValues: [
17217 {
17218 name: "None"
17219 },
17220 {
17221 name: "Public"
17222 },
17223 {
17224 name: "Private"
17225 }
17226 ]
17227 },
17228 {
17229 name: "GatewayDirection",
17230 literalValues: [
17231 {
17232 name: "Unspecified"
17233 },
17234 {
17235 name: "Converging"
17236 },
17237 {
17238 name: "Diverging"
17239 },
17240 {
17241 name: "Mixed"
17242 }
17243 ]
17244 },
17245 {
17246 name: "EventBasedGatewayType",
17247 literalValues: [
17248 {
17249 name: "Parallel"
17250 },
17251 {
17252 name: "Exclusive"
17253 }
17254 ]
17255 },
17256 {
17257 name: "RelationshipDirection",
17258 literalValues: [
17259 {
17260 name: "None"
17261 },
17262 {
17263 name: "Forward"
17264 },
17265 {
17266 name: "Backward"
17267 },
17268 {
17269 name: "Both"
17270 }
17271 ]
17272 },
17273 {
17274 name: "ItemKind",
17275 literalValues: [
17276 {
17277 name: "Physical"
17278 },
17279 {
17280 name: "Information"
17281 }
17282 ]
17283 },
17284 {
17285 name: "ChoreographyLoopType",
17286 literalValues: [
17287 {
17288 name: "None"
17289 },
17290 {
17291 name: "Standard"
17292 },
17293 {
17294 name: "MultiInstanceSequential"
17295 },
17296 {
17297 name: "MultiInstanceParallel"
17298 }
17299 ]
17300 },
17301 {
17302 name: "AssociationDirection",
17303 literalValues: [
17304 {
17305 name: "None"
17306 },
17307 {
17308 name: "One"
17309 },
17310 {
17311 name: "Both"
17312 }
17313 ]
17314 },
17315 {
17316 name: "MultiInstanceBehavior",
17317 literalValues: [
17318 {
17319 name: "None"
17320 },
17321 {
17322 name: "One"
17323 },
17324 {
17325 name: "All"
17326 },
17327 {
17328 name: "Complex"
17329 }
17330 ]
17331 },
17332 {
17333 name: "AdHocOrdering",
17334 literalValues: [
17335 {
17336 name: "Parallel"
17337 },
17338 {
17339 name: "Sequential"
17340 }
17341 ]
17342 }
17343 ];
17344 var xml = {
17345 tagAlias: "lowerCase",
17346 typePrefix: "t"
17347 };
17348 var BpmnPackage = {
17349 name: name,
17350 uri: uri,
17351 prefix: prefix$1,
17352 associations: associations,
17353 types: types$1,
17354 enumerations: enumerations,
17355 xml: xml
17356 };
17357
17358 var name$1 = "BPMNDI";
17359 var uri$1 = "http://www.omg.org/spec/BPMN/20100524/DI";
17360 var prefix$1$1 = "bpmndi";
17361 var types$1$1 = [
17362 {
17363 name: "BPMNDiagram",
17364 properties: [
17365 {
17366 name: "plane",
17367 type: "BPMNPlane",
17368 redefines: "di:Diagram#rootElement"
17369 },
17370 {
17371 name: "labelStyle",
17372 type: "BPMNLabelStyle",
17373 isMany: true
17374 }
17375 ],
17376 superClass: [
17377 "di:Diagram"
17378 ]
17379 },
17380 {
17381 name: "BPMNPlane",
17382 properties: [
17383 {
17384 name: "bpmnElement",
17385 isAttr: true,
17386 isReference: true,
17387 type: "bpmn:BaseElement",
17388 redefines: "di:DiagramElement#modelElement"
17389 }
17390 ],
17391 superClass: [
17392 "di:Plane"
17393 ]
17394 },
17395 {
17396 name: "BPMNShape",
17397 properties: [
17398 {
17399 name: "bpmnElement",
17400 isAttr: true,
17401 isReference: true,
17402 type: "bpmn:BaseElement",
17403 redefines: "di:DiagramElement#modelElement"
17404 },
17405 {
17406 name: "isHorizontal",
17407 isAttr: true,
17408 type: "Boolean"
17409 },
17410 {
17411 name: "isExpanded",
17412 isAttr: true,
17413 type: "Boolean"
17414 },
17415 {
17416 name: "isMarkerVisible",
17417 isAttr: true,
17418 type: "Boolean"
17419 },
17420 {
17421 name: "label",
17422 type: "BPMNLabel"
17423 },
17424 {
17425 name: "isMessageVisible",
17426 isAttr: true,
17427 type: "Boolean"
17428 },
17429 {
17430 name: "participantBandKind",
17431 type: "ParticipantBandKind",
17432 isAttr: true
17433 },
17434 {
17435 name: "choreographyActivityShape",
17436 type: "BPMNShape",
17437 isAttr: true,
17438 isReference: true
17439 }
17440 ],
17441 superClass: [
17442 "di:LabeledShape"
17443 ]
17444 },
17445 {
17446 name: "BPMNEdge",
17447 properties: [
17448 {
17449 name: "label",
17450 type: "BPMNLabel"
17451 },
17452 {
17453 name: "bpmnElement",
17454 isAttr: true,
17455 isReference: true,
17456 type: "bpmn:BaseElement",
17457 redefines: "di:DiagramElement#modelElement"
17458 },
17459 {
17460 name: "sourceElement",
17461 isAttr: true,
17462 isReference: true,
17463 type: "di:DiagramElement",
17464 redefines: "di:Edge#source"
17465 },
17466 {
17467 name: "targetElement",
17468 isAttr: true,
17469 isReference: true,
17470 type: "di:DiagramElement",
17471 redefines: "di:Edge#target"
17472 },
17473 {
17474 name: "messageVisibleKind",
17475 type: "MessageVisibleKind",
17476 isAttr: true,
17477 "default": "initiating"
17478 }
17479 ],
17480 superClass: [
17481 "di:LabeledEdge"
17482 ]
17483 },
17484 {
17485 name: "BPMNLabel",
17486 properties: [
17487 {
17488 name: "labelStyle",
17489 type: "BPMNLabelStyle",
17490 isAttr: true,
17491 isReference: true,
17492 redefines: "di:DiagramElement#style"
17493 }
17494 ],
17495 superClass: [
17496 "di:Label"
17497 ]
17498 },
17499 {
17500 name: "BPMNLabelStyle",
17501 properties: [
17502 {
17503 name: "font",
17504 type: "dc:Font"
17505 }
17506 ],
17507 superClass: [
17508 "di:Style"
17509 ]
17510 }
17511 ];
17512 var enumerations$1 = [
17513 {
17514 name: "ParticipantBandKind",
17515 literalValues: [
17516 {
17517 name: "top_initiating"
17518 },
17519 {
17520 name: "middle_initiating"
17521 },
17522 {
17523 name: "bottom_initiating"
17524 },
17525 {
17526 name: "top_non_initiating"
17527 },
17528 {
17529 name: "middle_non_initiating"
17530 },
17531 {
17532 name: "bottom_non_initiating"
17533 }
17534 ]
17535 },
17536 {
17537 name: "MessageVisibleKind",
17538 literalValues: [
17539 {
17540 name: "initiating"
17541 },
17542 {
17543 name: "non_initiating"
17544 }
17545 ]
17546 }
17547 ];
17548 var associations$1 = [
17549 ];
17550 var BpmnDiPackage = {
17551 name: name$1,
17552 uri: uri$1,
17553 prefix: prefix$1$1,
17554 types: types$1$1,
17555 enumerations: enumerations$1,
17556 associations: associations$1
17557 };
17558
17559 var name$2 = "DC";
17560 var uri$2 = "http://www.omg.org/spec/DD/20100524/DC";
17561 var prefix$2 = "dc";
17562 var types$2 = [
17563 {
17564 name: "Boolean"
17565 },
17566 {
17567 name: "Integer"
17568 },
17569 {
17570 name: "Real"
17571 },
17572 {
17573 name: "String"
17574 },
17575 {
17576 name: "Font",
17577 properties: [
17578 {
17579 name: "name",
17580 type: "String",
17581 isAttr: true
17582 },
17583 {
17584 name: "size",
17585 type: "Real",
17586 isAttr: true
17587 },
17588 {
17589 name: "isBold",
17590 type: "Boolean",
17591 isAttr: true
17592 },
17593 {
17594 name: "isItalic",
17595 type: "Boolean",
17596 isAttr: true
17597 },
17598 {
17599 name: "isUnderline",
17600 type: "Boolean",
17601 isAttr: true
17602 },
17603 {
17604 name: "isStrikeThrough",
17605 type: "Boolean",
17606 isAttr: true
17607 }
17608 ]
17609 },
17610 {
17611 name: "Point",
17612 properties: [
17613 {
17614 name: "x",
17615 type: "Real",
17616 "default": "0",
17617 isAttr: true
17618 },
17619 {
17620 name: "y",
17621 type: "Real",
17622 "default": "0",
17623 isAttr: true
17624 }
17625 ]
17626 },
17627 {
17628 name: "Bounds",
17629 properties: [
17630 {
17631 name: "x",
17632 type: "Real",
17633 "default": "0",
17634 isAttr: true
17635 },
17636 {
17637 name: "y",
17638 type: "Real",
17639 "default": "0",
17640 isAttr: true
17641 },
17642 {
17643 name: "width",
17644 type: "Real",
17645 isAttr: true
17646 },
17647 {
17648 name: "height",
17649 type: "Real",
17650 isAttr: true
17651 }
17652 ]
17653 }
17654 ];
17655 var associations$2 = [
17656 ];
17657 var DcPackage = {
17658 name: name$2,
17659 uri: uri$2,
17660 prefix: prefix$2,
17661 types: types$2,
17662 associations: associations$2
17663 };
17664
17665 var name$3 = "DI";
17666 var uri$3 = "http://www.omg.org/spec/DD/20100524/DI";
17667 var prefix$3 = "di";
17668 var types$3 = [
17669 {
17670 name: "DiagramElement",
17671 isAbstract: true,
17672 properties: [
17673 {
17674 name: "id",
17675 isAttr: true,
17676 isId: true,
17677 type: "String"
17678 },
17679 {
17680 name: "extension",
17681 type: "Extension"
17682 },
17683 {
17684 name: "owningDiagram",
17685 type: "Diagram",
17686 isReadOnly: true,
17687 isVirtual: true,
17688 isReference: true
17689 },
17690 {
17691 name: "owningElement",
17692 type: "DiagramElement",
17693 isReadOnly: true,
17694 isVirtual: true,
17695 isReference: true
17696 },
17697 {
17698 name: "modelElement",
17699 isReadOnly: true,
17700 isVirtual: true,
17701 isReference: true,
17702 type: "Element"
17703 },
17704 {
17705 name: "style",
17706 type: "Style",
17707 isReadOnly: true,
17708 isVirtual: true,
17709 isReference: true
17710 },
17711 {
17712 name: "ownedElement",
17713 type: "DiagramElement",
17714 isReadOnly: true,
17715 isMany: true,
17716 isVirtual: true
17717 }
17718 ]
17719 },
17720 {
17721 name: "Node",
17722 isAbstract: true,
17723 superClass: [
17724 "DiagramElement"
17725 ]
17726 },
17727 {
17728 name: "Edge",
17729 isAbstract: true,
17730 superClass: [
17731 "DiagramElement"
17732 ],
17733 properties: [
17734 {
17735 name: "source",
17736 type: "DiagramElement",
17737 isReadOnly: true,
17738 isVirtual: true,
17739 isReference: true
17740 },
17741 {
17742 name: "target",
17743 type: "DiagramElement",
17744 isReadOnly: true,
17745 isVirtual: true,
17746 isReference: true
17747 },
17748 {
17749 name: "waypoint",
17750 isUnique: false,
17751 isMany: true,
17752 type: "dc:Point",
17753 xml: {
17754 serialize: "xsi:type"
17755 }
17756 }
17757 ]
17758 },
17759 {
17760 name: "Diagram",
17761 isAbstract: true,
17762 properties: [
17763 {
17764 name: "id",
17765 isAttr: true,
17766 isId: true,
17767 type: "String"
17768 },
17769 {
17770 name: "rootElement",
17771 type: "DiagramElement",
17772 isReadOnly: true,
17773 isVirtual: true
17774 },
17775 {
17776 name: "name",
17777 isAttr: true,
17778 type: "String"
17779 },
17780 {
17781 name: "documentation",
17782 isAttr: true,
17783 type: "String"
17784 },
17785 {
17786 name: "resolution",
17787 isAttr: true,
17788 type: "Real"
17789 },
17790 {
17791 name: "ownedStyle",
17792 type: "Style",
17793 isReadOnly: true,
17794 isMany: true,
17795 isVirtual: true
17796 }
17797 ]
17798 },
17799 {
17800 name: "Shape",
17801 isAbstract: true,
17802 superClass: [
17803 "Node"
17804 ],
17805 properties: [
17806 {
17807 name: "bounds",
17808 type: "dc:Bounds"
17809 }
17810 ]
17811 },
17812 {
17813 name: "Plane",
17814 isAbstract: true,
17815 superClass: [
17816 "Node"
17817 ],
17818 properties: [
17819 {
17820 name: "planeElement",
17821 type: "DiagramElement",
17822 subsettedProperty: "DiagramElement-ownedElement",
17823 isMany: true
17824 }
17825 ]
17826 },
17827 {
17828 name: "LabeledEdge",
17829 isAbstract: true,
17830 superClass: [
17831 "Edge"
17832 ],
17833 properties: [
17834 {
17835 name: "ownedLabel",
17836 type: "Label",
17837 isReadOnly: true,
17838 subsettedProperty: "DiagramElement-ownedElement",
17839 isMany: true,
17840 isVirtual: true
17841 }
17842 ]
17843 },
17844 {
17845 name: "LabeledShape",
17846 isAbstract: true,
17847 superClass: [
17848 "Shape"
17849 ],
17850 properties: [
17851 {
17852 name: "ownedLabel",
17853 type: "Label",
17854 isReadOnly: true,
17855 subsettedProperty: "DiagramElement-ownedElement",
17856 isMany: true,
17857 isVirtual: true
17858 }
17859 ]
17860 },
17861 {
17862 name: "Label",
17863 isAbstract: true,
17864 superClass: [
17865 "Node"
17866 ],
17867 properties: [
17868 {
17869 name: "bounds",
17870 type: "dc:Bounds"
17871 }
17872 ]
17873 },
17874 {
17875 name: "Style",
17876 isAbstract: true,
17877 properties: [
17878 {
17879 name: "id",
17880 isAttr: true,
17881 isId: true,
17882 type: "String"
17883 }
17884 ]
17885 },
17886 {
17887 name: "Extension",
17888 properties: [
17889 {
17890 name: "values",
17891 isMany: true,
17892 type: "Element"
17893 }
17894 ]
17895 }
17896 ];
17897 var associations$3 = [
17898 ];
17899 var xml$1 = {
17900 tagAlias: "lowerCase"
17901 };
17902 var DiPackage = {
17903 name: name$3,
17904 uri: uri$3,
17905 prefix: prefix$3,
17906 types: types$3,
17907 associations: associations$3,
17908 xml: xml$1
17909 };
17910
17911 var name$4 = "bpmn.io colors for BPMN";
17912 var uri$4 = "http://bpmn.io/schema/bpmn/biocolor/1.0";
17913 var prefix$4 = "bioc";
17914 var types$4 = [
17915 {
17916 name: "ColoredShape",
17917 "extends": [
17918 "bpmndi:BPMNShape"
17919 ],
17920 properties: [
17921 {
17922 name: "stroke",
17923 isAttr: true,
17924 type: "String"
17925 },
17926 {
17927 name: "fill",
17928 isAttr: true,
17929 type: "String"
17930 }
17931 ]
17932 },
17933 {
17934 name: "ColoredEdge",
17935 "extends": [
17936 "bpmndi:BPMNEdge"
17937 ],
17938 properties: [
17939 {
17940 name: "stroke",
17941 isAttr: true,
17942 type: "String"
17943 },
17944 {
17945 name: "fill",
17946 isAttr: true,
17947 type: "String"
17948 }
17949 ]
17950 }
17951 ];
17952 var enumerations$2 = [
17953 ];
17954 var associations$4 = [
17955 ];
17956 var BiocPackage = {
17957 name: name$4,
17958 uri: uri$4,
17959 prefix: prefix$4,
17960 types: types$4,
17961 enumerations: enumerations$2,
17962 associations: associations$4
17963 };
17964
17965 var packages = {
17966 bpmn: BpmnPackage,
17967 bpmndi: BpmnDiPackage,
17968 dc: DcPackage,
17969 di: DiPackage,
17970 bioc: BiocPackage
17971 };
17972
17973 function simple(additionalPackages, options) {
17974 var pks = assign({}, packages, additionalPackages);
17975
17976 return new BpmnModdle(pks, options);
17977 }
17978
17979 var diRefs = new objectRefs(
17980 { name: 'bpmnElement', enumerable: true },
17981 { name: 'di', configurable: true }
17982 );
17983
17984 /**
17985 * Returns true if an element has the given meta-model type
17986 *
17987 * @param {ModdleElement} element
17988 * @param {string} type
17989 *
17990 * @return {boolean}
17991 */
17992 function is$1(element, type) {
17993 return element.$instanceOf(type);
17994 }
17995
17996
17997 /**
17998 * Find a suitable display candidate for definitions where the DI does not
17999 * correctly specify one.
18000 */
18001 function findDisplayCandidate(definitions) {
18002 return find(definitions.rootElements, function(e) {
18003 return is$1(e, 'bpmn:Process') || is$1(e, 'bpmn:Collaboration');
18004 });
18005 }
18006
18007
18008 function BpmnTreeWalker(handler, translate) {
18009
18010 // list of containers already walked
18011 var handledElements = {};
18012
18013 // list of elements to handle deferred to ensure
18014 // prerequisites are drawn
18015 var deferred = [];
18016
18017 // Helpers //////////////////////
18018
18019 function contextual(fn, ctx) {
18020 return function(e) {
18021 fn(e, ctx);
18022 };
18023 }
18024
18025 function handled(element) {
18026 handledElements[element.id] = element;
18027 }
18028
18029 function isHandled(element) {
18030 return handledElements[element.id];
18031 }
18032
18033 function visit(element, ctx) {
18034
18035 var gfx = element.gfx;
18036
18037 // avoid multiple rendering of elements
18038 if (gfx) {
18039 throw new Error(
18040 translate('already rendered {element}', { element: elementToString(element) })
18041 );
18042 }
18043
18044 // call handler
18045 return handler.element(element, ctx);
18046 }
18047
18048 function visitRoot(element, diagram) {
18049 return handler.root(element, diagram);
18050 }
18051
18052 function visitIfDi(element, ctx) {
18053
18054 try {
18055 var gfx = element.di && visit(element, ctx);
18056
18057 handled(element);
18058
18059 return gfx;
18060 } catch (e) {
18061 logError(e.message, { element: element, error: e });
18062
18063 console.error(translate('failed to import {element}', { element: elementToString(element) }));
18064 console.error(e);
18065 }
18066 }
18067
18068 function logError(message, context) {
18069 handler.error(message, context);
18070 }
18071
18072 // DI handling //////////////////////
18073
18074 function registerDi(di) {
18075 var bpmnElement = di.bpmnElement;
18076
18077 if (bpmnElement) {
18078 if (bpmnElement.di) {
18079 logError(
18080 translate('multiple DI elements defined for {element}', {
18081 element: elementToString(bpmnElement)
18082 }),
18083 { element: bpmnElement }
18084 );
18085 } else {
18086 diRefs.bind(bpmnElement, 'di');
18087 bpmnElement.di = di;
18088 }
18089 } else {
18090 logError(
18091 translate('no bpmnElement referenced in {element}', {
18092 element: elementToString(di)
18093 }),
18094 { element: di }
18095 );
18096 }
18097 }
18098
18099 function handleDiagram(diagram) {
18100 handlePlane(diagram.plane);
18101 }
18102
18103 function handlePlane(plane) {
18104 registerDi(plane);
18105
18106 forEach(plane.planeElement, handlePlaneElement);
18107 }
18108
18109 function handlePlaneElement(planeElement) {
18110 registerDi(planeElement);
18111 }
18112
18113
18114 // Semantic handling //////////////////////
18115
18116 /**
18117 * Handle definitions and return the rendered diagram (if any)
18118 *
18119 * @param {ModdleElement} definitions to walk and import
18120 * @param {ModdleElement} [diagram] specific diagram to import and display
18121 *
18122 * @throws {Error} if no diagram to display could be found
18123 */
18124 function handleDefinitions(definitions, diagram) {
18125
18126 // make sure we walk the correct bpmnElement
18127
18128 var diagrams = definitions.diagrams;
18129
18130 if (diagram && diagrams.indexOf(diagram) === -1) {
18131 throw new Error(translate('diagram not part of bpmn:Definitions'));
18132 }
18133
18134 if (!diagram && diagrams && diagrams.length) {
18135 diagram = diagrams[0];
18136 }
18137
18138 // no diagram -> nothing to import
18139 if (!diagram) {
18140 throw new Error(translate('no diagram to display'));
18141 }
18142
18143 // load DI from selected diagram only
18144 handleDiagram(diagram);
18145
18146
18147 var plane = diagram.plane;
18148
18149 if (!plane) {
18150 throw new Error(translate(
18151 'no plane for {element}',
18152 { element: elementToString(diagram) }
18153 ));
18154 }
18155
18156 var rootElement = plane.bpmnElement;
18157
18158 // ensure we default to a suitable display candidate (process or collaboration),
18159 // even if non is specified in DI
18160 if (!rootElement) {
18161 rootElement = findDisplayCandidate(definitions);
18162
18163 if (!rootElement) {
18164 throw new Error(translate('no process or collaboration to display'));
18165 } else {
18166
18167 logError(
18168 translate('correcting missing bpmnElement on {plane} to {rootElement}', {
18169 plane: elementToString(plane),
18170 rootElement: elementToString(rootElement)
18171 })
18172 );
18173
18174 // correct DI on the fly
18175 plane.bpmnElement = rootElement;
18176 registerDi(plane);
18177 }
18178 }
18179
18180
18181 var ctx = visitRoot(rootElement, plane);
18182
18183 if (is$1(rootElement, 'bpmn:Process')) {
18184 handleProcess(rootElement, ctx);
18185 } else if (is$1(rootElement, 'bpmn:Collaboration')) {
18186 handleCollaboration(rootElement);
18187
18188 // force drawing of everything not yet drawn that is part of the target DI
18189 handleUnhandledProcesses(definitions.rootElements, ctx);
18190 } else {
18191 throw new Error(
18192 translate('unsupported bpmnElement for {plane}: {rootElement}', {
18193 plane: elementToString(plane),
18194 rootElement: elementToString(rootElement)
18195 })
18196 );
18197 }
18198
18199 // handle all deferred elements
18200 handleDeferred();
18201 }
18202
18203 function handleDeferred() {
18204
18205 var fn;
18206
18207 // drain deferred until empty
18208 while (deferred.length) {
18209 fn = deferred.shift();
18210
18211 fn();
18212 }
18213 }
18214
18215 function handleProcess(process, context) {
18216 handleFlowElementsContainer(process, context);
18217 handleIoSpecification(process.ioSpecification, context);
18218
18219 handleArtifacts(process.artifacts, context);
18220
18221 // log process handled
18222 handled(process);
18223 }
18224
18225 function handleUnhandledProcesses(rootElements, ctx) {
18226
18227 // walk through all processes that have not yet been drawn and draw them
18228 // if they contain lanes with DI information.
18229 // we do this to pass the free-floating lane test cases in the MIWG test suite
18230 var processes = filter(rootElements, function(e) {
18231 return !isHandled(e) && is$1(e, 'bpmn:Process') && e.laneSets;
18232 });
18233
18234 processes.forEach(contextual(handleProcess, ctx));
18235 }
18236
18237 function handleMessageFlow(messageFlow, context) {
18238 visitIfDi(messageFlow, context);
18239 }
18240
18241 function handleMessageFlows(messageFlows, context) {
18242 forEach(messageFlows, contextual(handleMessageFlow, context));
18243 }
18244
18245 function handleDataAssociation(association, context) {
18246 visitIfDi(association, context);
18247 }
18248
18249 function handleDataInput(dataInput, context) {
18250 visitIfDi(dataInput, context);
18251 }
18252
18253 function handleDataOutput(dataOutput, context) {
18254 visitIfDi(dataOutput, context);
18255 }
18256
18257 function handleArtifact(artifact, context) {
18258
18259 // bpmn:TextAnnotation
18260 // bpmn:Group
18261 // bpmn:Association
18262
18263 visitIfDi(artifact, context);
18264 }
18265
18266 function handleArtifacts(artifacts, context) {
18267
18268 forEach(artifacts, function(e) {
18269 if (is$1(e, 'bpmn:Association')) {
18270 deferred.push(function() {
18271 handleArtifact(e, context);
18272 });
18273 } else {
18274 handleArtifact(e, context);
18275 }
18276 });
18277 }
18278
18279 function handleIoSpecification(ioSpecification, context) {
18280
18281 if (!ioSpecification) {
18282 return;
18283 }
18284
18285 forEach(ioSpecification.dataInputs, contextual(handleDataInput, context));
18286 forEach(ioSpecification.dataOutputs, contextual(handleDataOutput, context));
18287 }
18288
18289 function handleSubProcess(subProcess, context) {
18290 handleFlowElementsContainer(subProcess, context);
18291 handleArtifacts(subProcess.artifacts, context);
18292 }
18293
18294 function handleFlowNode(flowNode, context) {
18295 var childCtx = visitIfDi(flowNode, context);
18296
18297 if (is$1(flowNode, 'bpmn:SubProcess')) {
18298 handleSubProcess(flowNode, childCtx || context);
18299 }
18300
18301 if (is$1(flowNode, 'bpmn:Activity')) {
18302 handleIoSpecification(flowNode.ioSpecification, context);
18303 }
18304
18305 // defer handling of associations
18306 // affected types:
18307 //
18308 // * bpmn:Activity
18309 // * bpmn:ThrowEvent
18310 // * bpmn:CatchEvent
18311 //
18312 deferred.push(function() {
18313 forEach(flowNode.dataInputAssociations, contextual(handleDataAssociation, context));
18314 forEach(flowNode.dataOutputAssociations, contextual(handleDataAssociation, context));
18315 });
18316 }
18317
18318 function handleSequenceFlow(sequenceFlow, context) {
18319 visitIfDi(sequenceFlow, context);
18320 }
18321
18322 function handleDataElement(dataObject, context) {
18323 visitIfDi(dataObject, context);
18324 }
18325
18326 function handleLane(lane, context) {
18327
18328 deferred.push(function() {
18329
18330 var newContext = visitIfDi(lane, context);
18331
18332 if (lane.childLaneSet) {
18333 handleLaneSet(lane.childLaneSet, newContext || context);
18334 }
18335
18336 wireFlowNodeRefs(lane);
18337 });
18338 }
18339
18340 function handleLaneSet(laneSet, context) {
18341 forEach(laneSet.lanes, contextual(handleLane, context));
18342 }
18343
18344 function handleLaneSets(laneSets, context) {
18345 forEach(laneSets, contextual(handleLaneSet, context));
18346 }
18347
18348 function handleFlowElementsContainer(container, context) {
18349 handleFlowElements(container.flowElements, context);
18350
18351 if (container.laneSets) {
18352 handleLaneSets(container.laneSets, context);
18353 }
18354 }
18355
18356 function handleFlowElements(flowElements, context) {
18357 forEach(flowElements, function(e) {
18358 if (is$1(e, 'bpmn:SequenceFlow')) {
18359 deferred.push(function() {
18360 handleSequenceFlow(e, context);
18361 });
18362 } else if (is$1(e, 'bpmn:BoundaryEvent')) {
18363 deferred.unshift(function() {
18364 handleFlowNode(e, context);
18365 });
18366 } else if (is$1(e, 'bpmn:FlowNode')) {
18367 handleFlowNode(e, context);
18368 } else if (is$1(e, 'bpmn:DataObject')) ; else if (is$1(e, 'bpmn:DataStoreReference')) {
18369 handleDataElement(e, context);
18370 } else if (is$1(e, 'bpmn:DataObjectReference')) {
18371 handleDataElement(e, context);
18372 } else {
18373 logError(
18374 translate('unrecognized flowElement {element} in context {context}', {
18375 element: elementToString(e),
18376 context: (context ? elementToString(context.businessObject) : 'null')
18377 }),
18378 { element: e, context: context }
18379 );
18380 }
18381 });
18382 }
18383
18384 function handleParticipant(participant, context) {
18385 var newCtx = visitIfDi(participant, context);
18386
18387 var process = participant.processRef;
18388 if (process) {
18389 handleProcess(process, newCtx || context);
18390 }
18391 }
18392
18393 function handleCollaboration(collaboration) {
18394
18395 forEach(collaboration.participants, contextual(handleParticipant));
18396
18397 handleArtifacts(collaboration.artifacts);
18398
18399 // handle message flows latest in the process
18400 deferred.push(function() {
18401 handleMessageFlows(collaboration.messageFlows);
18402 });
18403 }
18404
18405
18406 function wireFlowNodeRefs(lane) {
18407
18408 // wire the virtual flowNodeRefs <-> relationship
18409 forEach(lane.flowNodeRef, function(flowNode) {
18410 var lanes = flowNode.get('lanes');
18411
18412 if (lanes) {
18413 lanes.push(lane);
18414 }
18415 });
18416 }
18417
18418 // API //////////////////////
18419
18420 return {
18421 handleDeferred: handleDeferred,
18422 handleDefinitions: handleDefinitions,
18423 handleSubProcess: handleSubProcess,
18424 registerDi: registerDi
18425 };
18426 }
18427
18428 /**
18429 * The importBpmnDiagram result.
18430 *
18431 * @typedef {Object} ImportBPMNDiagramResult
18432 *
18433 * @property {Array<string>} warnings
18434 */
18435
18436 /**
18437 * The importBpmnDiagram error.
18438 *
18439 * @typedef {Error} ImportBPMNDiagramError
18440 *
18441 * @property {Array<string>} warnings
18442 */
18443
18444 /**
18445 * Import the definitions into a diagram.
18446 *
18447 * Errors and warnings are reported through the specified callback.
18448 *
18449 * @param {djs.Diagram} diagram
18450 * @param {ModdleElement<Definitions>} definitions
18451 * @param {ModdleElement<BPMNDiagram>} [bpmnDiagram] the diagram to be rendered
18452 * (if not provided, the first one will be rendered)
18453 *
18454 * Returns {Promise<ImportBPMNDiagramResult, ImportBPMNDiagramError>}
18455 */
18456 function importBpmnDiagram(diagram, definitions, bpmnDiagram) {
18457
18458 var importer,
18459 eventBus,
18460 translate;
18461
18462 var error,
18463 warnings = [];
18464
18465 /**
18466 * Walk the diagram semantically, importing (=drawing)
18467 * all elements you encounter.
18468 *
18469 * @param {ModdleElement<Definitions>} definitions
18470 * @param {ModdleElement<BPMNDiagram>} bpmnDiagram
18471 */
18472 function render(definitions, bpmnDiagram) {
18473
18474 var visitor = {
18475
18476 root: function(element) {
18477 return importer.add(element);
18478 },
18479
18480 element: function(element, parentShape) {
18481 return importer.add(element, parentShape);
18482 },
18483
18484 error: function(message, context) {
18485 warnings.push({ message: message, context: context });
18486 }
18487 };
18488
18489 var walker = new BpmnTreeWalker(visitor, translate);
18490
18491 // traverse BPMN 2.0 document model,
18492 // starting at definitions
18493 walker.handleDefinitions(definitions, bpmnDiagram);
18494 }
18495
18496 return new Promise(function(resolve, reject) {
18497 try {
18498 importer = diagram.get('bpmnImporter');
18499 eventBus = diagram.get('eventBus');
18500 translate = diagram.get('translate');
18501
18502 eventBus.fire('import.render.start', { definitions: definitions });
18503
18504 render(definitions, bpmnDiagram);
18505
18506 eventBus.fire('import.render.complete', {
18507 error: error,
18508 warnings: warnings
18509 });
18510
18511 return resolve({ warnings: warnings });
18512 } catch (e) {
18513
18514 e.warnings = warnings;
18515 return reject(e);
18516 }
18517 });
18518 }
18519
18520 // TODO(nikku): remove with future bpmn-js version
18521
18522 /**
18523 * Wraps APIs to check:
18524 *
18525 * 1) If a callback is passed -> Warn users about callback deprecation.
18526 * 2) If Promise class is implemented in current environment.
18527 *
18528 * @private
18529 */
18530 function wrapForCompatibility(api) {
18531
18532 return function() {
18533
18534 if (!window.Promise) {
18535 throw new Error('Promises is not supported in this environment. Please polyfill Promise.');
18536 }
18537
18538 var argLen = arguments.length;
18539 if (argLen >= 1 && isFunction(arguments[argLen - 1])) {
18540
18541 var callback = arguments[argLen - 1];
18542
18543 console.warn(new Error(
18544 'Passing callbacks to ' + api.name + ' is deprecated and will be removed in a future major release. ' +
18545 'Please switch to promises: https://bpmn.io/l/moving-to-promises.html'
18546 ));
18547
18548 var argsWithoutCallback = Array.prototype.slice.call(arguments, 0, -1);
18549
18550 api.apply(this, argsWithoutCallback).then(function(result) {
18551
18552 var firstKey = Object.keys(result)[0];
18553
18554 // The APIs we are wrapping all resolve a single item depending on the API.
18555 // For instance, importXML resolves { warnings } and saveXML returns { xml }.
18556 // That's why we can call the callback with the first item of result.
18557 return callback(null, result[firstKey]);
18558
18559 // Passing a second paramter instead of catch because we don't want to
18560 // catch errors thrown by callback().
18561 }, function(err) {
18562
18563 return callback(err, err.warnings);
18564 });
18565 } else {
18566
18567 return api.apply(this, arguments);
18568 }
18569 };
18570 }
18571
18572 /**
18573 * This file must not be changed or exchanged.
18574 *
18575 * @see http://bpmn.io/license for more information.
18576 */
18577
18578
18579 // inlined ../../resources/logo.svg
18580 var BPMNIO_LOGO_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14.02 5.57" width="53" height="21" style="vertical-align:middle"><path fill="currentColor" d="M1.88.92v.14c0 .41-.13.68-.4.8.33.14.46.44.46.86v.33c0 .61-.33.95-.95.95H0V0h.95c.65 0 .93.3.93.92zM.63.57v1.06h.24c.24 0 .38-.1.38-.43V.98c0-.28-.1-.4-.32-.4zm0 1.63v1.22h.36c.2 0 .32-.1.32-.39v-.35c0-.37-.12-.48-.4-.48H.63zM4.18.99v.52c0 .64-.31.98-.94.98h-.3V4h-.62V0h.92c.63 0 .94.35.94.99zM2.94.57v1.35h.3c.2 0 .3-.09.3-.37v-.6c0-.29-.1-.38-.3-.38h-.3zm2.89 2.27L6.25 0h.88v4h-.6V1.12L6.1 3.99h-.6l-.46-2.82v2.82h-.55V0h.87zM8.14 1.1V4h-.56V0h.79L9 2.4V0h.56v4h-.64zm2.49 2.29v.6h-.6v-.6zM12.12 1c0-.63.33-1 .95-1 .61 0 .95.37.95 1v2.04c0 .64-.34 1-.95 1-.62 0-.95-.37-.95-1zm.62 2.08c0 .28.13.39.33.39s.32-.1.32-.4V.98c0-.29-.12-.4-.32-.4s-.33.11-.33.4z"/><path fill="currentColor" d="M0 4.53h14.02v1.04H0zM11.08 0h.63v.62h-.63zm.63 4V1h-.63v2.98z"/></svg>';
18581
18582 var BPMNIO_IMG = BPMNIO_LOGO_SVG;
18583
18584 function css(attrs) {
18585 return attrs.join(';');
18586 }
18587
18588 var LINK_STYLES = css([
18589 'color: #404040'
18590 ]);
18591
18592 var LIGHTBOX_STYLES = css([
18593 'z-index: 1001',
18594 'position: fixed',
18595 'top: 0',
18596 'left: 0',
18597 'right: 0',
18598 'bottom: 0'
18599 ]);
18600
18601 var BACKDROP_STYLES = css([
18602 'width: 100%',
18603 'height: 100%',
18604 'background: rgba(40,40,40,0.2)'
18605 ]);
18606
18607 var NOTICE_STYLES = css([
18608 'position: absolute',
18609 'left: 50%',
18610 'top: 40%',
18611 'transform: translate(-50%)',
18612 'width: 260px',
18613 'padding: 10px',
18614 'background: white',
18615 'box-shadow: 0 1px 4px rgba(0,0,0,0.3)',
18616 'font-family: Helvetica, Arial, sans-serif',
18617 'font-size: 14px',
18618 'display: flex',
18619 'line-height: 1.3'
18620 ]);
18621
18622 var LIGHTBOX_MARKUP =
18623 '<div class="bjs-powered-by-lightbox" style="' + LIGHTBOX_STYLES + '">' +
18624 '<div class="backdrop" style="' + BACKDROP_STYLES + '"></div>' +
18625 '<div class="notice" style="' + NOTICE_STYLES + '">' +
18626 '<a href="https://bpmn.io" target="_blank" rel="noopener" style="margin: 15px 20px 15px 10px; align-self: center;' + LINK_STYLES + '">' +
18627 BPMNIO_IMG +
18628 '</a>' +
18629 '<span>' +
18630 'Web-based tooling for BPMN, DMN and CMMN diagrams ' +
18631 'powered by <a href="https://bpmn.io" target="_blank" rel="noopener">bpmn.io</a>.' +
18632 '</span>' +
18633 '</div>' +
18634 '</div>';
18635
18636
18637 var lightbox;
18638
18639 function open() {
18640
18641 if (!lightbox) {
18642 lightbox = domify(LIGHTBOX_MARKUP);
18643
18644 delegateEvents.bind(lightbox, '.backdrop', 'click', function(event) {
18645 document.body.removeChild(lightbox);
18646 });
18647 }
18648
18649 document.body.appendChild(lightbox);
18650 }
18651
18652 /**
18653 * The code in the <project-logo></project-logo> area
18654 * must not be changed.
18655 *
18656 * @see http://bpmn.io/license for more information.
18657 */
18658
18659 /**
18660 * A base viewer for BPMN 2.0 diagrams.
18661 *
18662 * Have a look at {@link Viewer}, {@link NavigatedViewer} or {@link Modeler} for
18663 * bundles that include actual features.
18664 *
18665 * @param {Object} [options] configuration options to pass to the viewer
18666 * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
18667 * @param {string|number} [options.width] the width of the viewer
18668 * @param {string|number} [options.height] the height of the viewer
18669 * @param {Object} [options.moddleExtensions] extension packages to provide
18670 * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
18671 * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
18672 */
18673 function BaseViewer(options) {
18674
18675 options = assign({}, DEFAULT_OPTIONS, options);
18676
18677 this._moddle = this._createModdle(options);
18678
18679 this._container = this._createContainer(options);
18680
18681 /* <project-logo> */
18682
18683 addProjectLogo(this._container);
18684
18685 /* </project-logo> */
18686
18687 this._init(this._container, this._moddle, options);
18688 }
18689
18690 inherits_browser(BaseViewer, Diagram);
18691
18692 /**
18693 * The importXML result.
18694 *
18695 * @typedef {Object} ImportXMLResult
18696 *
18697 * @property {Array<string>} warnings
18698 */
18699
18700 /**
18701 * The importXML error.
18702 *
18703 * @typedef {Error} ImportXMLError
18704 *
18705 * @property {Array<string>} warnings
18706 */
18707
18708 /**
18709 * Parse and render a BPMN 2.0 diagram.
18710 *
18711 * Once finished the viewer reports back the result to the
18712 * provided callback function with (err, warnings).
18713 *
18714 * ## Life-Cycle Events
18715 *
18716 * During import the viewer will fire life-cycle events:
18717 *
18718 * * import.parse.start (about to read model from xml)
18719 * * import.parse.complete (model read; may have worked or not)
18720 * * import.render.start (graphical import start)
18721 * * import.render.complete (graphical import finished)
18722 * * import.done (everything done)
18723 *
18724 * You can use these events to hook into the life-cycle.
18725 *
18726 * @param {string} xml the BPMN 2.0 xml
18727 * @param {ModdleElement<BPMNDiagram>|string} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
18728 *
18729 * Returns {Promise<ImportXMLResult, ImportXMLError>}
18730 */
18731 BaseViewer.prototype.importXML = wrapForCompatibility(function importXML(xml, bpmnDiagram) {
18732
18733 var self = this;
18734
18735 function ParseCompleteEvent(data) {
18736
18737 var event = self.get('eventBus').createEvent(data);
18738
18739 // TODO(nikku): remove with future bpmn-js version
18740 Object.defineProperty(event, 'context', {
18741 enumerable: true,
18742 get: function() {
18743
18744 console.warn(new Error(
18745 'import.parse.complete <context> is deprecated ' +
18746 'and will be removed in future library versions'
18747 ));
18748
18749 return {
18750 warnings: data.warnings,
18751 references: data.references,
18752 elementsById: data.elementsById
18753 };
18754 }
18755 });
18756
18757 return event;
18758 }
18759
18760 return new Promise(function(resolve, reject) {
18761
18762 // hook in pre-parse listeners +
18763 // allow xml manipulation
18764 xml = self._emit('import.parse.start', { xml: xml }) || xml;
18765
18766 self._moddle.fromXML(xml, 'bpmn:Definitions').then(function(result) {
18767 var definitions = result.rootElement;
18768 var references = result.references;
18769 var parseWarnings = result.warnings;
18770 var elementsById = result.elementsById;
18771
18772 // hook in post parse listeners +
18773 // allow definitions manipulation
18774 definitions = self._emit('import.parse.complete', ParseCompleteEvent({
18775 error: null,
18776 definitions: definitions,
18777 elementsById: elementsById,
18778 references: references,
18779 warnings: parseWarnings
18780 })) || definitions;
18781
18782 self.importDefinitions(definitions, bpmnDiagram).then(function(result) {
18783 var allWarnings = [].concat(parseWarnings, result.warnings || []);
18784
18785 self._emit('import.done', { error: null, warnings: allWarnings });
18786
18787 return resolve({ warnings: allWarnings });
18788 }).catch(function(err) {
18789 var allWarnings = [].concat(parseWarnings, err.warnings || []);
18790
18791 self._emit('import.done', { error: err, warnings: allWarnings });
18792
18793 return reject(addWarningsToError(err, allWarnings));
18794 });
18795 }).catch(function(err) {
18796
18797 self._emit('import.parse.complete', {
18798 error: err
18799 });
18800
18801 err = checkValidationError(err);
18802
18803 self._emit('import.done', { error: err, warnings: err.warnings });
18804
18805 return reject(err);
18806 });
18807 });
18808 });
18809
18810 /**
18811 * The importDefinitions result.
18812 *
18813 * @typedef {Object} ImportDefinitionsResult
18814 *
18815 * @property {Array<string>} warnings
18816 */
18817
18818 /**
18819 * The importDefinitions error.
18820 *
18821 * @typedef {Error} ImportDefinitionsError
18822 *
18823 * @property {Array<string>} warnings
18824 */
18825
18826 /**
18827 * Import parsed definitions and render a BPMN 2.0 diagram.
18828 *
18829 * Once finished the viewer reports back the result to the
18830 * provided callback function with (err, warnings).
18831 *
18832 * ## Life-Cycle Events
18833 *
18834 * During import the viewer will fire life-cycle events:
18835 *
18836 * * import.render.start (graphical import start)
18837 * * import.render.complete (graphical import finished)
18838 *
18839 * You can use these events to hook into the life-cycle.
18840 *
18841 * @param {ModdleElement<Definitions>} definitions parsed BPMN 2.0 definitions
18842 * @param {ModdleElement<BPMNDiagram>|string} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
18843 *
18844 * Returns {Promise<ImportDefinitionsResult, ImportDefinitionsError>}
18845 */
18846 BaseViewer.prototype.importDefinitions = wrapForCompatibility(function importDefinitions(definitions, bpmnDiagram) {
18847
18848 var self = this;
18849
18850 return new Promise(function(resolve, reject) {
18851
18852 self._setDefinitions(definitions);
18853
18854 self.open(bpmnDiagram).then(function(result) {
18855
18856 var warnings = result.warnings;
18857
18858 return resolve({ warnings: warnings });
18859 }).catch(function(err) {
18860
18861 return reject(err);
18862 });
18863 });
18864 });
18865
18866 /**
18867 * The open result.
18868 *
18869 * @typedef {Object} OpenResult
18870 *
18871 * @property {Array<string>} warnings
18872 */
18873
18874 /**
18875 * The open error.
18876 *
18877 * @typedef {Error} OpenError
18878 *
18879 * @property {Array<string>} warnings
18880 */
18881
18882 /**
18883 * Open diagram of previously imported XML.
18884 *
18885 * Once finished the viewer reports back the result to the
18886 * provided callback function with (err, warnings).
18887 *
18888 * ## Life-Cycle Events
18889 *
18890 * During switch the viewer will fire life-cycle events:
18891 *
18892 * * import.render.start (graphical import start)
18893 * * import.render.complete (graphical import finished)
18894 *
18895 * You can use these events to hook into the life-cycle.
18896 *
18897 * @param {string|ModdleElement<BPMNDiagram>} [bpmnDiagramOrId] id or the diagram to open
18898 *
18899 * Returns {Promise<OpenResult, OpenError>}
18900 */
18901 BaseViewer.prototype.open = wrapForCompatibility(function open(bpmnDiagramOrId) {
18902
18903 var definitions = this._definitions;
18904 var bpmnDiagram = bpmnDiagramOrId;
18905
18906 var self = this;
18907
18908 return new Promise(function(resolve, reject) {
18909 if (!definitions) {
18910 var err1 = new Error('no XML imported');
18911
18912 return reject(addWarningsToError(err1, []));
18913 }
18914
18915 if (typeof bpmnDiagramOrId === 'string') {
18916 bpmnDiagram = findBPMNDiagram(definitions, bpmnDiagramOrId);
18917
18918 if (!bpmnDiagram) {
18919 var err2 = new Error('BPMNDiagram <' + bpmnDiagramOrId + '> not found');
18920
18921 return reject(addWarningsToError(err2, []));
18922 }
18923 }
18924
18925 // clear existing rendered diagram
18926 // catch synchronous exceptions during #clear()
18927 try {
18928 self.clear();
18929 } catch (error) {
18930
18931 return reject(addWarningsToError(error, []));
18932 }
18933
18934 // perform graphical import
18935 importBpmnDiagram(self, definitions, bpmnDiagram).then(function(result) {
18936
18937 var warnings = result.warnings;
18938
18939 return resolve({ warnings: warnings });
18940 }).catch(function(err) {
18941
18942 return reject(err);
18943 });
18944 });
18945 });
18946
18947 /**
18948 * The saveXML result.
18949 *
18950 * @typedef {Object} SaveXMLResult
18951 *
18952 * @property {string} xml
18953 */
18954
18955 /**
18956 * Export the currently displayed BPMN 2.0 diagram as
18957 * a BPMN 2.0 XML document.
18958 *
18959 * ## Life-Cycle Events
18960 *
18961 * During XML saving the viewer will fire life-cycle events:
18962 *
18963 * * saveXML.start (before serialization)
18964 * * saveXML.serialized (after xml generation)
18965 * * saveXML.done (everything done)
18966 *
18967 * You can use these events to hook into the life-cycle.
18968 *
18969 * @param {Object} [options] export options
18970 * @param {boolean} [options.format=false] output formatted XML
18971 * @param {boolean} [options.preamble=true] output preamble
18972 *
18973 * Returns {Promise<SaveXMLResult, Error>}
18974 */
18975 BaseViewer.prototype.saveXML = wrapForCompatibility(function saveXML(options) {
18976
18977 options = options || {};
18978
18979 var self = this;
18980
18981 var definitions = this._definitions;
18982
18983 return new Promise(function(resolve, reject) {
18984
18985 if (!definitions) {
18986 var err = new Error('no definitions loaded');
18987
18988 return reject(err);
18989 }
18990
18991 // allow to fiddle around with definitions
18992 definitions = self._emit('saveXML.start', {
18993 definitions: definitions
18994 }) || definitions;
18995
18996 self._moddle.toXML(definitions, options).then(function(result) {
18997
18998 var xml = result.xml;
18999
19000 try {
19001 xml = self._emit('saveXML.serialized', {
19002 error: null,
19003 xml: xml
19004 }) || xml;
19005
19006 self._emit('saveXML.done', {
19007 error: null,
19008 xml: xml
19009 });
19010 } catch (e) {
19011 console.error('error in saveXML life-cycle listener', e);
19012 }
19013
19014 return resolve({ xml: xml });
19015 }).catch(function(err) {
19016
19017 return reject(err);
19018 });
19019 });
19020 });
19021
19022 /**
19023 * The saveSVG result.
19024 *
19025 * @typedef {Object} SaveSVGResult
19026 *
19027 * @property {string} svg
19028 */
19029
19030 /**
19031 * Export the currently displayed BPMN 2.0 diagram as
19032 * an SVG image.
19033 *
19034 * ## Life-Cycle Events
19035 *
19036 * During SVG saving the viewer will fire life-cycle events:
19037 *
19038 * * saveSVG.start (before serialization)
19039 * * saveSVG.done (everything done)
19040 *
19041 * You can use these events to hook into the life-cycle.
19042 *
19043 * @param {Object} [options]
19044 *
19045 * Returns {Promise<SaveSVGResult, Error>}
19046 */
19047 BaseViewer.prototype.saveSVG = wrapForCompatibility(function saveSVG(options) {
19048
19049 var self = this;
19050
19051 return new Promise(function(resolve, reject) {
19052
19053 self._emit('saveSVG.start');
19054
19055 var svg, err;
19056
19057 try {
19058 var canvas = self.get('canvas');
19059
19060 var contentNode = canvas.getDefaultLayer(),
19061 defsNode = query('defs', canvas._svg);
19062
19063 var contents = innerSVG(contentNode),
19064 defs = defsNode ? '<defs>' + innerSVG(defsNode) + '</defs>' : '';
19065
19066 var bbox = contentNode.getBBox();
19067
19068 svg =
19069 '<?xml version="1.0" encoding="utf-8"?>\n' +
19070 '<!-- created with bpmn-js / http://bpmn.io -->\n' +
19071 '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
19072 '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
19073 'width="' + bbox.width + '" height="' + bbox.height + '" ' +
19074 'viewBox="' + bbox.x + ' ' + bbox.y + ' ' + bbox.width + ' ' + bbox.height + '" version="1.1">' +
19075 defs + contents +
19076 '</svg>';
19077 } catch (e) {
19078 err = e;
19079 }
19080
19081 self._emit('saveSVG.done', {
19082 error: err,
19083 svg: svg
19084 });
19085
19086 if (!err) {
19087 return resolve({ svg: svg });
19088 }
19089
19090 return reject(err);
19091 });
19092 });
19093
19094 /**
19095 * Get a named diagram service.
19096 *
19097 * @example
19098 *
19099 * var elementRegistry = viewer.get('elementRegistry');
19100 * var startEventShape = elementRegistry.get('StartEvent_1');
19101 *
19102 * @param {string} name
19103 *
19104 * @return {Object} diagram service instance
19105 *
19106 * @method BaseViewer#get
19107 */
19108
19109 /**
19110 * Invoke a function in the context of this viewer.
19111 *
19112 * @example
19113 *
19114 * viewer.invoke(function(elementRegistry) {
19115 * var startEventShape = elementRegistry.get('StartEvent_1');
19116 * });
19117 *
19118 * @param {Function} fn to be invoked
19119 *
19120 * @return {Object} the functions return value
19121 *
19122 * @method BaseViewer#invoke
19123 */
19124
19125
19126 BaseViewer.prototype._setDefinitions = function(definitions) {
19127 this._definitions = definitions;
19128 };
19129
19130 BaseViewer.prototype.getModules = function() {
19131 return this._modules;
19132 };
19133
19134 /**
19135 * Remove all drawn elements from the viewer.
19136 *
19137 * After calling this method the viewer can still
19138 * be reused for opening another diagram.
19139 *
19140 * @method BaseViewer#clear
19141 */
19142 BaseViewer.prototype.clear = function() {
19143 if (!this.getDefinitions()) {
19144
19145 // no diagram to clear
19146 return;
19147 }
19148
19149 // remove businessObject#di binding
19150 //
19151 // this is necessary, as we establish the bindings
19152 // in the BpmnTreeWalker (and assume none are given
19153 // on reimport)
19154 this.get('elementRegistry').forEach(function(element) {
19155 var bo = element.businessObject;
19156
19157 if (bo && bo.di) {
19158 delete bo.di;
19159 }
19160 });
19161
19162 // remove drawn elements
19163 Diagram.prototype.clear.call(this);
19164 };
19165
19166 /**
19167 * Destroy the viewer instance and remove all its
19168 * remainders from the document tree.
19169 */
19170 BaseViewer.prototype.destroy = function() {
19171
19172 // diagram destroy
19173 Diagram.prototype.destroy.call(this);
19174
19175 // dom detach
19176 remove$1(this._container);
19177 };
19178
19179 /**
19180 * Register an event listener
19181 *
19182 * Remove a previously added listener via {@link #off(event, callback)}.
19183 *
19184 * @param {string} event
19185 * @param {number} [priority]
19186 * @param {Function} callback
19187 * @param {Object} [that]
19188 */
19189 BaseViewer.prototype.on = function(event, priority, callback, target) {
19190 return this.get('eventBus').on(event, priority, callback, target);
19191 };
19192
19193 /**
19194 * De-register an event listener
19195 *
19196 * @param {string} event
19197 * @param {Function} callback
19198 */
19199 BaseViewer.prototype.off = function(event, callback) {
19200 this.get('eventBus').off(event, callback);
19201 };
19202
19203 BaseViewer.prototype.attachTo = function(parentNode) {
19204
19205 if (!parentNode) {
19206 throw new Error('parentNode required');
19207 }
19208
19209 // ensure we detach from the
19210 // previous, old parent
19211 this.detach();
19212
19213 // unwrap jQuery if provided
19214 if (parentNode.get && parentNode.constructor.prototype.jquery) {
19215 parentNode = parentNode.get(0);
19216 }
19217
19218 if (typeof parentNode === 'string') {
19219 parentNode = query(parentNode);
19220 }
19221
19222 parentNode.appendChild(this._container);
19223
19224 this._emit('attach', {});
19225
19226 this.get('canvas').resized();
19227 };
19228
19229 BaseViewer.prototype.getDefinitions = function() {
19230 return this._definitions;
19231 };
19232
19233 BaseViewer.prototype.detach = function() {
19234
19235 var container = this._container,
19236 parentNode = container.parentNode;
19237
19238 if (!parentNode) {
19239 return;
19240 }
19241
19242 this._emit('detach', {});
19243
19244 parentNode.removeChild(container);
19245 };
19246
19247 BaseViewer.prototype._init = function(container, moddle, options) {
19248
19249 var baseModules = options.modules || this.getModules(),
19250 additionalModules = options.additionalModules || [],
19251 staticModules = [
19252 {
19253 bpmnjs: [ 'value', this ],
19254 moddle: [ 'value', moddle ]
19255 }
19256 ];
19257
19258 var diagramModules = [].concat(staticModules, baseModules, additionalModules);
19259
19260 var diagramOptions = assign(omit(options, [ 'additionalModules' ]), {
19261 canvas: assign({}, options.canvas, { container: container }),
19262 modules: diagramModules
19263 });
19264
19265 // invoke diagram constructor
19266 Diagram.call(this, diagramOptions);
19267
19268 if (options && options.container) {
19269 this.attachTo(options.container);
19270 }
19271 };
19272
19273 /**
19274 * Emit an event on the underlying {@link EventBus}
19275 *
19276 * @param {string} type
19277 * @param {Object} event
19278 *
19279 * @return {Object} event processing result (if any)
19280 */
19281 BaseViewer.prototype._emit = function(type, event) {
19282 return this.get('eventBus').fire(type, event);
19283 };
19284
19285 BaseViewer.prototype._createContainer = function(options) {
19286
19287 var container = domify('<div class="bjs-container"></div>');
19288
19289 assign(container.style, {
19290 width: ensureUnit(options.width),
19291 height: ensureUnit(options.height),
19292 position: options.position
19293 });
19294
19295 return container;
19296 };
19297
19298 BaseViewer.prototype._createModdle = function(options) {
19299 var moddleOptions = assign({}, this._moddleExtensions, options.moddleExtensions);
19300
19301 return new simple(moddleOptions);
19302 };
19303
19304 BaseViewer.prototype._modules = [];
19305
19306 // helpers ///////////////
19307
19308 function addWarningsToError(err, warningsAry) {
19309 err.warnings = warningsAry;
19310 return err;
19311 }
19312
19313 function checkValidationError(err) {
19314
19315 // check if we can help the user by indicating wrong BPMN 2.0 xml
19316 // (in case he or the exporting tool did not get that right)
19317
19318 var pattern = /unparsable content <([^>]+)> detected([\s\S]*)$/;
19319 var match = pattern.exec(err.message);
19320
19321 if (match) {
19322 err.message =
19323 'unparsable content <' + match[1] + '> detected; ' +
19324 'this may indicate an invalid BPMN 2.0 diagram file' + match[2];
19325 }
19326
19327 return err;
19328 }
19329
19330 var DEFAULT_OPTIONS = {
19331 width: '100%',
19332 height: '100%',
19333 position: 'relative'
19334 };
19335
19336
19337 /**
19338 * Ensure the passed argument is a proper unit (defaulting to px)
19339 */
19340 function ensureUnit(val) {
19341 return val + (isNumber(val) ? 'px' : '');
19342 }
19343
19344
19345 /**
19346 * Find BPMNDiagram in definitions by ID
19347 *
19348 * @param {ModdleElement<Definitions>} definitions
19349 * @param {string} diagramId
19350 *
19351 * @return {ModdleElement<BPMNDiagram>|null}
19352 */
19353 function findBPMNDiagram(definitions, diagramId) {
19354 if (!diagramId) {
19355 return null;
19356 }
19357
19358 return find(definitions.diagrams, function(element) {
19359 return element.id === diagramId;
19360 }) || null;
19361 }
19362
19363 /**
19364 * Adds the project logo to the diagram container as
19365 * required by the bpmn.io license.
19366 *
19367 * @see http://bpmn.io/license
19368 *
19369 * @param {Element} container
19370 */
19371 function addProjectLogo(container) {
19372 var img = BPMNIO_IMG;
19373
19374 var linkMarkup =
19375 '<a href="http://bpmn.io" ' +
19376 'target="_blank" ' +
19377 'class="bjs-powered-by" ' +
19378 'title="Powered by bpmn.io" ' +
19379 'style="position: absolute; bottom: 15px; right: 15px; z-index: 100; ' + LINK_STYLES + '">' +
19380 img +
19381 '</a>';
19382
19383 var linkElement = domify(linkMarkup);
19384
19385 container.appendChild(linkElement);
19386
19387 componentEvent.bind(linkElement, 'click', function(event) {
19388 open();
19389
19390 event.preventDefault();
19391 });
19392 }
19393
19394 /* </project-logo> */
19395
19396 /**
19397 * A viewer for BPMN 2.0 diagrams.
19398 *
19399 * Have a look at {@link NavigatedViewer} or {@link Modeler} for bundles that include
19400 * additional features.
19401 *
19402 *
19403 * ## Extending the Viewer
19404 *
19405 * In order to extend the viewer pass extension modules to bootstrap via the
19406 * `additionalModules` option. An extension module is an object that exposes
19407 * named services.
19408 *
19409 * The following example depicts the integration of a simple
19410 * logging component that integrates with interaction events:
19411 *
19412 *
19413 * ```javascript
19414 *
19415 * // logging component
19416 * function InteractionLogger(eventBus) {
19417 * eventBus.on('element.hover', function(event) {
19418 * console.log()
19419 * })
19420 * }
19421 *
19422 * InteractionLogger.$inject = [ 'eventBus' ]; // minification save
19423 *
19424 * // extension module
19425 * var extensionModule = {
19426 * __init__: [ 'interactionLogger' ],
19427 * interactionLogger: [ 'type', InteractionLogger ]
19428 * };
19429 *
19430 * // extend the viewer
19431 * var bpmnViewer = new Viewer({ additionalModules: [ extensionModule ] });
19432 * bpmnViewer.importXML(...);
19433 * ```
19434 *
19435 * @param {Object} [options] configuration options to pass to the viewer
19436 * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
19437 * @param {string|number} [options.width] the width of the viewer
19438 * @param {string|number} [options.height] the height of the viewer
19439 * @param {Object} [options.moddleExtensions] extension packages to provide
19440 * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
19441 * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
19442 */
19443 function Viewer(options) {
19444 BaseViewer.call(this, options);
19445 }
19446
19447 inherits_browser(Viewer, BaseViewer);
19448
19449 // modules the viewer is composed of
19450 Viewer.prototype._modules = [
19451 CoreModule,
19452 TranslateModule,
19453 SelectionModule,
19454 OverlaysModule
19455 ];
19456
19457 // default moddle extensions the viewer is composed of
19458 Viewer.prototype._moddleExtensions = {};
19459
19460 /**
19461 * Returns true if event was triggered with any modifier
19462 * @param {KeyboardEvent} event
19463 */
19464 function hasModifier(event) {
19465 return (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey);
19466 }
19467
19468 /**
19469 * @param {KeyboardEvent} event
19470 */
19471 function isCmd(event) {
19472
19473 // ensure we don't react to AltGr
19474 // (mapped to CTRL + ALT)
19475 if (event.altKey) {
19476 return false;
19477 }
19478
19479 return event.ctrlKey || event.metaKey;
19480 }
19481
19482 /**
19483 * Checks if key pressed is one of provided keys.
19484 *
19485 * @param {string|Array<string>} keys
19486 * @param {KeyboardEvent} event
19487 */
19488 function isKey(keys, event) {
19489 keys = isArray(keys) ? keys : [ keys ];
19490
19491 return keys.indexOf(event.key) !== -1 || keys.indexOf(event.keyCode) !== -1;
19492 }
19493
19494 /**
19495 * @param {KeyboardEvent} event
19496 */
19497 function isShift(event) {
19498 return event.shiftKey;
19499 }
19500
19501 var KEYDOWN_EVENT = 'keyboard.keydown',
19502 KEYUP_EVENT = 'keyboard.keyup';
19503
19504 var DEFAULT_PRIORITY$1 = 1000;
19505
19506
19507 /**
19508 * A keyboard abstraction that may be activated and
19509 * deactivated by users at will, consuming key events
19510 * and triggering diagram actions.
19511 *
19512 * For keys pressed down, keyboard fires `keyboard.keydown` event.
19513 * The event context contains one field which is `KeyboardEvent` event.
19514 *
19515 * The implementation fires the following key events that allow
19516 * other components to hook into key handling:
19517 *
19518 * - keyboard.bind
19519 * - keyboard.unbind
19520 * - keyboard.init
19521 * - keyboard.destroy
19522 *
19523 * All events contain one field which is node.
19524 *
19525 * A default binding for the keyboard may be specified via the
19526 * `keyboard.bindTo` configuration option.
19527 *
19528 * @param {Config} config
19529 * @param {EventBus} eventBus
19530 */
19531 function Keyboard(config, eventBus) {
19532 var self = this;
19533
19534 this._config = config || {};
19535 this._eventBus = eventBus;
19536
19537 this._keydownHandler = this._keydownHandler.bind(this);
19538 this._keyupHandler = this._keyupHandler.bind(this);
19539
19540 // properly clean dom registrations
19541 eventBus.on('diagram.destroy', function() {
19542 self._fire('destroy');
19543
19544 self.unbind();
19545 });
19546
19547 eventBus.on('diagram.init', function() {
19548 self._fire('init');
19549 });
19550
19551 eventBus.on('attach', function() {
19552 if (config && config.bindTo) {
19553 self.bind(config.bindTo);
19554 }
19555 });
19556
19557 eventBus.on('detach', function() {
19558 self.unbind();
19559 });
19560 }
19561
19562 Keyboard.$inject = [
19563 'config.keyboard',
19564 'eventBus'
19565 ];
19566
19567 Keyboard.prototype._keydownHandler = function(event) {
19568 this._keyHandler(event, KEYDOWN_EVENT);
19569 };
19570
19571 Keyboard.prototype._keyupHandler = function(event) {
19572 this._keyHandler(event, KEYUP_EVENT);
19573 };
19574
19575 Keyboard.prototype._keyHandler = function(event, type) {
19576 var target = event.target,
19577 eventBusResult;
19578
19579 if (isInput(target)) {
19580 return;
19581 }
19582
19583 var context = {
19584 keyEvent: event
19585 };
19586
19587 eventBusResult = this._eventBus.fire(type || KEYDOWN_EVENT, context);
19588
19589 if (eventBusResult) {
19590 event.preventDefault();
19591 }
19592 };
19593
19594 Keyboard.prototype.bind = function(node) {
19595
19596 // make sure that the keyboard is only bound once to the DOM
19597 this.unbind();
19598
19599 this._node = node;
19600
19601 // bind key events
19602 componentEvent.bind(node, 'keydown', this._keydownHandler, true);
19603 componentEvent.bind(node, 'keyup', this._keyupHandler, true);
19604
19605 this._fire('bind');
19606 };
19607
19608 Keyboard.prototype.getBinding = function() {
19609 return this._node;
19610 };
19611
19612 Keyboard.prototype.unbind = function() {
19613 var node = this._node;
19614
19615 if (node) {
19616 this._fire('unbind');
19617
19618 // unbind key events
19619 componentEvent.unbind(node, 'keydown', this._keydownHandler, true);
19620 componentEvent.unbind(node, 'keyup', this._keyupHandler, true);
19621 }
19622
19623 this._node = null;
19624 };
19625
19626 Keyboard.prototype._fire = function(event) {
19627 this._eventBus.fire('keyboard.' + event, { node: this._node });
19628 };
19629
19630 /**
19631 * Add a listener function that is notified with `KeyboardEvent` whenever
19632 * the keyboard is bound and the user presses a key. If no priority is
19633 * provided, the default value of 1000 is used.
19634 *
19635 * @param {number} [priority]
19636 * @param {Function} listener
19637 * @param {string} type
19638 */
19639 Keyboard.prototype.addListener = function(priority, listener, type) {
19640 if (isFunction(priority)) {
19641 type = listener;
19642 listener = priority;
19643 priority = DEFAULT_PRIORITY$1;
19644 }
19645
19646 this._eventBus.on(type || KEYDOWN_EVENT, priority, listener);
19647 };
19648
19649 Keyboard.prototype.removeListener = function(listener, type) {
19650 this._eventBus.off(type || KEYDOWN_EVENT, listener);
19651 };
19652
19653 Keyboard.prototype.hasModifier = hasModifier;
19654 Keyboard.prototype.isCmd = isCmd;
19655 Keyboard.prototype.isShift = isShift;
19656 Keyboard.prototype.isKey = isKey;
19657
19658
19659
19660 // helpers ///////
19661
19662 function isInput(target) {
19663 return target && (matchesSelector(target, 'input, textarea') || target.contentEditable === 'true');
19664 }
19665
19666 var LOW_PRIORITY$3 = 500;
19667
19668 var KEYCODE_C = 67;
19669 var KEYCODE_V = 86;
19670 var KEYCODE_Y = 89;
19671 var KEYCODE_Z = 90;
19672
19673 var KEYS_COPY = ['c', 'C', KEYCODE_C ];
19674 var KEYS_PASTE = [ 'v', 'V', KEYCODE_V ];
19675 var KEYS_REDO = [ 'y', 'Y', KEYCODE_Y ];
19676 var KEYS_UNDO = [ 'z', 'Z', KEYCODE_Z ];
19677
19678
19679 /**
19680 * Adds default keyboard bindings.
19681 *
19682 * This does not pull in any features will bind only actions that
19683 * have previously been registered against the editorActions component.
19684 *
19685 * @param {EventBus} eventBus
19686 * @param {Keyboard} keyboard
19687 */
19688 function KeyboardBindings(eventBus, keyboard) {
19689
19690 var self = this;
19691
19692 eventBus.on('editorActions.init', LOW_PRIORITY$3, function(event) {
19693
19694 var editorActions = event.editorActions;
19695
19696 self.registerBindings(keyboard, editorActions);
19697 });
19698 }
19699
19700 KeyboardBindings.$inject = [
19701 'eventBus',
19702 'keyboard'
19703 ];
19704
19705
19706 /**
19707 * Register available keyboard bindings.
19708 *
19709 * @param {Keyboard} keyboard
19710 * @param {EditorActions} editorActions
19711 */
19712 KeyboardBindings.prototype.registerBindings = function(keyboard, editorActions) {
19713
19714 /**
19715 * Add keyboard binding if respective editor action
19716 * is registered.
19717 *
19718 * @param {string} action name
19719 * @param {Function} fn that implements the key binding
19720 */
19721 function addListener(action, fn) {
19722
19723 if (editorActions.isRegistered(action)) {
19724 keyboard.addListener(fn);
19725 }
19726 }
19727
19728
19729 // undo
19730 // (CTRL|CMD) + Z
19731 addListener('undo', function(context) {
19732
19733 var event = context.keyEvent;
19734
19735 if (isCmd(event) && !isShift(event) && isKey(KEYS_UNDO, event)) {
19736 editorActions.trigger('undo');
19737
19738 return true;
19739 }
19740 });
19741
19742 // redo
19743 // CTRL + Y
19744 // CMD + SHIFT + Z
19745 addListener('redo', function(context) {
19746
19747 var event = context.keyEvent;
19748
19749 if (isCmd(event) && (isKey(KEYS_REDO, event) || (isKey(KEYS_UNDO, event) && isShift(event)))) {
19750 editorActions.trigger('redo');
19751
19752 return true;
19753 }
19754 });
19755
19756 // copy
19757 // CTRL/CMD + C
19758 addListener('copy', function(context) {
19759
19760 var event = context.keyEvent;
19761
19762 if (isCmd(event) && isKey(KEYS_COPY, event)) {
19763 editorActions.trigger('copy');
19764
19765 return true;
19766 }
19767 });
19768
19769 // paste
19770 // CTRL/CMD + V
19771 addListener('paste', function(context) {
19772
19773 var event = context.keyEvent;
19774
19775 if (isCmd(event) && isKey(KEYS_PASTE, event)) {
19776 editorActions.trigger('paste');
19777
19778 return true;
19779 }
19780 });
19781
19782 // zoom in one step
19783 // CTRL/CMD + +
19784 addListener('stepZoom', function(context) {
19785
19786 var event = context.keyEvent;
19787
19788 if (isKey([ '+', 'Add' ], event) && isCmd(event)) {
19789 editorActions.trigger('stepZoom', { value: 1 });
19790
19791 return true;
19792 }
19793 });
19794
19795 // zoom out one step
19796 // CTRL + -
19797 addListener('stepZoom', function(context) {
19798
19799 var event = context.keyEvent;
19800
19801 if (isKey([ '-', 'Subtract' ], event) && isCmd(event)) {
19802 editorActions.trigger('stepZoom', { value: -1 });
19803
19804 return true;
19805 }
19806 });
19807
19808 // zoom to the default level
19809 // CTRL + 0
19810 addListener('zoom', function(context) {
19811
19812 var event = context.keyEvent;
19813
19814 if (isKey('0', event) && isCmd(event)) {
19815 editorActions.trigger('zoom', { value: 1 });
19816
19817 return true;
19818 }
19819 });
19820
19821 // delete selected element
19822 // DEL
19823 addListener('removeSelection', function(context) {
19824
19825 var event = context.keyEvent;
19826
19827 if (isKey([ 'Delete', 'Del' ], event)) {
19828 editorActions.trigger('removeSelection');
19829
19830 return true;
19831 }
19832 });
19833 };
19834
19835 var KeyboardModule = {
19836 __init__: [ 'keyboard', 'keyboardBindings' ],
19837 keyboard: [ 'type', Keyboard ],
19838 keyboardBindings: [ 'type', KeyboardBindings ]
19839 };
19840
19841 var DEFAULT_CONFIG = {
19842 moveSpeed: 50,
19843 moveSpeedAccelerated: 200
19844 };
19845
19846
19847 /**
19848 * A feature that allows users to move the canvas using the keyboard.
19849 *
19850 * @param {Object} config
19851 * @param {number} [config.moveSpeed=50]
19852 * @param {number} [config.moveSpeedAccelerated=200]
19853 * @param {Keyboard} keyboard
19854 * @param {Canvas} canvas
19855 */
19856 function KeyboardMove(
19857 config,
19858 keyboard,
19859 canvas
19860 ) {
19861
19862 var self = this;
19863
19864 this._config = assign({}, DEFAULT_CONFIG, config || {});
19865
19866 keyboard.addListener(arrowsListener);
19867
19868
19869 function arrowsListener(context) {
19870
19871 var event = context.keyEvent,
19872 config = self._config;
19873
19874 if (!keyboard.isCmd(event)) {
19875 return;
19876 }
19877
19878 if (keyboard.isKey([
19879 'ArrowLeft', 'Left',
19880 'ArrowUp', 'Up',
19881 'ArrowDown', 'Down',
19882 'ArrowRight', 'Right'
19883 ], event)) {
19884
19885 var speed = (
19886 keyboard.isShift(event) ?
19887 config.moveSpeedAccelerated :
19888 config.moveSpeed
19889 );
19890
19891 var direction;
19892
19893 switch (event.key) {
19894 case 'ArrowLeft':
19895 case 'Left':
19896 direction = 'left';
19897 break;
19898 case 'ArrowUp':
19899 case 'Up':
19900 direction = 'up';
19901 break;
19902 case 'ArrowRight':
19903 case 'Right':
19904 direction = 'right';
19905 break;
19906 case 'ArrowDown':
19907 case 'Down':
19908 direction = 'down';
19909 break;
19910 }
19911
19912 self.moveCanvas({
19913 speed: speed,
19914 direction: direction
19915 });
19916
19917 return true;
19918 }
19919 }
19920
19921 this.moveCanvas = function(opts) {
19922
19923 var dx = 0,
19924 dy = 0,
19925 speed = opts.speed;
19926
19927 var actualSpeed = speed / Math.min(Math.sqrt(canvas.viewbox().scale), 1);
19928
19929 switch (opts.direction) {
19930 case 'left': // Left
19931 dx = actualSpeed;
19932 break;
19933 case 'up': // Up
19934 dy = actualSpeed;
19935 break;
19936 case 'right': // Right
19937 dx = -actualSpeed;
19938 break;
19939 case 'down': // Down
19940 dy = -actualSpeed;
19941 break;
19942 }
19943
19944 canvas.scroll({
19945 dx: dx,
19946 dy: dy
19947 });
19948 };
19949
19950 }
19951
19952
19953 KeyboardMove.$inject = [
19954 'config.keyboardMove',
19955 'keyboard',
19956 'canvas'
19957 ];
19958
19959 var KeyboardMoveModule = {
19960 __depends__: [
19961 KeyboardModule
19962 ],
19963 __init__: [ 'keyboardMove' ],
19964 keyboardMove: [ 'type', KeyboardMove ]
19965 };
19966
19967 var CURSOR_CLS_PATTERN = /^djs-cursor-.*$/;
19968
19969
19970 function set$1(mode) {
19971 var classes = classes$1(document.body);
19972
19973 classes.removeMatching(CURSOR_CLS_PATTERN);
19974
19975 if (mode) {
19976 classes.add('djs-cursor-' + mode);
19977 }
19978 }
19979
19980 function unset() {
19981 set$1(null);
19982 }
19983
19984 var TRAP_PRIORITY = 5000;
19985
19986 /**
19987 * Installs a click trap that prevents a ghost click following a dragging operation.
19988 *
19989 * @return {Function} a function to immediately remove the installed trap.
19990 */
19991 function install(eventBus, eventName) {
19992
19993 eventName = eventName || 'element.click';
19994
19995 function trap() {
19996 return false;
19997 }
19998
19999 eventBus.once(eventName, TRAP_PRIORITY, trap);
20000
20001 return function() {
20002 eventBus.off(eventName, trap);
20003 };
20004 }
20005
20006 function delta(a, b) {
20007 return {
20008 x: a.x - b.x,
20009 y: a.y - b.y
20010 };
20011 }
20012
20013 var THRESHOLD = 15;
20014
20015
20016 /**
20017 * Move the canvas via mouse.
20018 *
20019 * @param {EventBus} eventBus
20020 * @param {Canvas} canvas
20021 */
20022 function MoveCanvas(eventBus, canvas) {
20023
20024 var context;
20025
20026
20027 // listen for move on element mouse down;
20028 // allow others to hook into the event before us though
20029 // (dragging / element moving will do this)
20030 eventBus.on('element.mousedown', 500, function(e) {
20031 return handleStart(e.originalEvent);
20032 });
20033
20034
20035 function handleMove(event) {
20036
20037 var start = context.start,
20038 position = toPoint(event),
20039 delta$1 = delta(position, start);
20040
20041 if (!context.dragging && length(delta$1) > THRESHOLD) {
20042 context.dragging = true;
20043
20044 install(eventBus);
20045
20046 set$1('grab');
20047 }
20048
20049 if (context.dragging) {
20050
20051 var lastPosition = context.last || context.start;
20052
20053 delta$1 = delta(position, lastPosition);
20054
20055 canvas.scroll({
20056 dx: delta$1.x,
20057 dy: delta$1.y
20058 });
20059
20060 context.last = position;
20061 }
20062
20063 // prevent select
20064 event.preventDefault();
20065 }
20066
20067
20068 function handleEnd(event) {
20069 componentEvent.unbind(document, 'mousemove', handleMove);
20070 componentEvent.unbind(document, 'mouseup', handleEnd);
20071
20072 context = null;
20073
20074 unset();
20075 }
20076
20077 function handleStart(event) {
20078
20079 // event is already handled by '.djs-draggable'
20080 if (closest(event.target, '.djs-draggable')) {
20081 return;
20082 }
20083
20084
20085 // reject non-left left mouse button or modifier key
20086 if (event.button || event.ctrlKey || event.shiftKey || event.altKey) {
20087 return;
20088 }
20089
20090 context = {
20091 start: toPoint(event)
20092 };
20093
20094 componentEvent.bind(document, 'mousemove', handleMove);
20095 componentEvent.bind(document, 'mouseup', handleEnd);
20096
20097 // we've handled the event
20098 return true;
20099 }
20100 }
20101
20102
20103 MoveCanvas.$inject = [
20104 'eventBus',
20105 'canvas'
20106 ];
20107
20108
20109
20110 // helpers ///////
20111
20112 function length(point) {
20113 return Math.sqrt(Math.pow(point.x, 2) + Math.pow(point.y, 2));
20114 }
20115
20116 var MoveCanvasModule = {
20117 __init__: [ 'moveCanvas' ],
20118 moveCanvas: [ 'type', MoveCanvas ]
20119 };
20120
20121 /**
20122 * Get the logarithm of x with base 10
20123 * @param {Integer} value
20124 */
20125 function log10(x) {
20126 return Math.log(x) / Math.log(10);
20127 }
20128
20129 /**
20130 * Get step size for given range and number of steps.
20131 *
20132 * @param {Object} range
20133 * @param {number} range.min
20134 * @param {number} range.max
20135 */
20136 function getStepSize(range, steps) {
20137
20138 var minLinearRange = log10(range.min),
20139 maxLinearRange = log10(range.max);
20140
20141 var absoluteLinearRange = Math.abs(minLinearRange) + Math.abs(maxLinearRange);
20142
20143 return absoluteLinearRange / steps;
20144 }
20145
20146 function cap(range, scale) {
20147 return Math.max(range.min, Math.min(range.max, scale));
20148 }
20149
20150 var sign = Math.sign || function(n) {
20151 return n >= 0 ? 1 : -1;
20152 };
20153
20154 var RANGE = { min: 0.2, max: 4 },
20155 NUM_STEPS = 10;
20156
20157 var DELTA_THRESHOLD = 0.1;
20158
20159 var DEFAULT_SCALE = 0.75;
20160
20161 /**
20162 * An implementation of zooming and scrolling within the
20163 * {@link Canvas} via the mouse wheel.
20164 *
20165 * Mouse wheel zooming / scrolling may be disabled using
20166 * the {@link toggle(enabled)} method.
20167 *
20168 * @param {Object} [config]
20169 * @param {boolean} [config.enabled=true] default enabled state
20170 * @param {number} [config.scale=.75] scroll sensivity
20171 * @param {EventBus} eventBus
20172 * @param {Canvas} canvas
20173 */
20174 function ZoomScroll(config, eventBus, canvas) {
20175
20176 config = config || {};
20177
20178 this._enabled = false;
20179
20180 this._canvas = canvas;
20181 this._container = canvas._container;
20182
20183 this._handleWheel = bind(this._handleWheel, this);
20184
20185 this._totalDelta = 0;
20186 this._scale = config.scale || DEFAULT_SCALE;
20187
20188 var self = this;
20189
20190 eventBus.on('canvas.init', function(e) {
20191 self._init(config.enabled !== false);
20192 });
20193 }
20194
20195 ZoomScroll.$inject = [
20196 'config.zoomScroll',
20197 'eventBus',
20198 'canvas'
20199 ];
20200
20201 ZoomScroll.prototype.scroll = function scroll(delta) {
20202 this._canvas.scroll(delta);
20203 };
20204
20205
20206 ZoomScroll.prototype.reset = function reset() {
20207 this._canvas.zoom('fit-viewport');
20208 };
20209
20210 /**
20211 * Zoom depending on delta.
20212 *
20213 * @param {number} delta
20214 * @param {Object} position
20215 */
20216 ZoomScroll.prototype.zoom = function zoom(delta, position) {
20217
20218 // zoom with half the step size of stepZoom
20219 var stepSize = getStepSize(RANGE, NUM_STEPS * 2);
20220
20221 // add until threshold reached
20222 this._totalDelta += delta;
20223
20224 if (Math.abs(this._totalDelta) > DELTA_THRESHOLD) {
20225 this._zoom(delta, position, stepSize);
20226
20227 // reset
20228 this._totalDelta = 0;
20229 }
20230 };
20231
20232
20233 ZoomScroll.prototype._handleWheel = function handleWheel(event) {
20234
20235 // event is already handled by '.djs-scrollable'
20236 if (closest(event.target, '.djs-scrollable', true)) {
20237 return;
20238 }
20239
20240 var element = this._container;
20241
20242 event.preventDefault();
20243
20244 // pinch to zoom is mapped to wheel + ctrlKey = true
20245 // in modern browsers (!)
20246
20247 var isZoom = event.ctrlKey;
20248
20249 var isHorizontalScroll = event.shiftKey;
20250
20251 var factor = -1 * this._scale,
20252 delta;
20253
20254 if (isZoom) {
20255 factor *= event.deltaMode === 0 ? 0.020 : 0.32;
20256 } else {
20257 factor *= event.deltaMode === 0 ? 1.0 : 16.0;
20258 }
20259
20260 if (isZoom) {
20261 var elementRect = element.getBoundingClientRect();
20262
20263 var offset = {
20264 x: event.clientX - elementRect.left,
20265 y: event.clientY - elementRect.top
20266 };
20267
20268 delta = (
20269 Math.sqrt(
20270 Math.pow(event.deltaY, 2) +
20271 Math.pow(event.deltaX, 2)
20272 ) * sign(event.deltaY) * factor
20273 );
20274
20275 // zoom in relative to diagram {x,y} coordinates
20276 this.zoom(delta, offset);
20277 } else {
20278
20279 if (isHorizontalScroll) {
20280 delta = {
20281 dx: factor * event.deltaY,
20282 dy: 0
20283 };
20284 } else {
20285 delta = {
20286 dx: factor * event.deltaX,
20287 dy: factor * event.deltaY
20288 };
20289 }
20290
20291 this.scroll(delta);
20292 }
20293 };
20294
20295 /**
20296 * Zoom with fixed step size.
20297 *
20298 * @param {number} delta - Zoom delta (1 for zooming in, -1 for out).
20299 * @param {Object} position
20300 */
20301 ZoomScroll.prototype.stepZoom = function stepZoom(delta, position) {
20302
20303 var stepSize = getStepSize(RANGE, NUM_STEPS);
20304
20305 this._zoom(delta, position, stepSize);
20306 };
20307
20308
20309 /**
20310 * Zoom in/out given a step size.
20311 *
20312 * @param {number} delta
20313 * @param {Object} position
20314 * @param {number} stepSize
20315 */
20316 ZoomScroll.prototype._zoom = function(delta, position, stepSize) {
20317 var canvas = this._canvas;
20318
20319 var direction = delta > 0 ? 1 : -1;
20320
20321 var currentLinearZoomLevel = log10(canvas.zoom());
20322
20323 // snap to a proximate zoom step
20324 var newLinearZoomLevel = Math.round(currentLinearZoomLevel / stepSize) * stepSize;
20325
20326 // increase or decrease one zoom step in the given direction
20327 newLinearZoomLevel += stepSize * direction;
20328
20329 // calculate the absolute logarithmic zoom level based on the linear zoom level
20330 // (e.g. 2 for an absolute x2 zoom)
20331 var newLogZoomLevel = Math.pow(10, newLinearZoomLevel);
20332
20333 canvas.zoom(cap(RANGE, newLogZoomLevel), position);
20334 };
20335
20336
20337 /**
20338 * Toggle the zoom scroll ability via mouse wheel.
20339 *
20340 * @param {boolean} [newEnabled] new enabled state
20341 */
20342 ZoomScroll.prototype.toggle = function toggle(newEnabled) {
20343
20344 var element = this._container;
20345 var handleWheel = this._handleWheel;
20346
20347 var oldEnabled = this._enabled;
20348
20349 if (typeof newEnabled === 'undefined') {
20350 newEnabled = !oldEnabled;
20351 }
20352
20353 // only react on actual changes
20354 if (oldEnabled !== newEnabled) {
20355
20356 // add or remove wheel listener based on
20357 // changed enabled state
20358 componentEvent[newEnabled ? 'bind' : 'unbind'](element, 'wheel', handleWheel, false);
20359 }
20360
20361 this._enabled = newEnabled;
20362
20363 return newEnabled;
20364 };
20365
20366
20367 ZoomScroll.prototype._init = function(newEnabled) {
20368 this.toggle(newEnabled);
20369 };
20370
20371 var ZoomScrollModule = {
20372 __init__: [ 'zoomScroll' ],
20373 zoomScroll: [ 'type', ZoomScroll ]
20374 };
20375
20376 /**
20377 * A viewer that includes mouse navigation facilities
20378 *
20379 * @param {Object} options
20380 */
20381 function NavigatedViewer(options) {
20382 Viewer.call(this, options);
20383 }
20384
20385 inherits_browser(NavigatedViewer, Viewer);
20386
20387
20388 NavigatedViewer.prototype._navigationModules = [
20389 KeyboardMoveModule,
20390 MoveCanvasModule,
20391 ZoomScrollModule
20392 ];
20393
20394 NavigatedViewer.prototype._modules = [].concat(
20395 Viewer.prototype._modules,
20396 NavigatedViewer.prototype._navigationModules
20397 );
20398
20399 return NavigatedViewer;
20400
20401}));