UNPKG

469 kBJavaScriptView Raw
1/*!
2 * bpmn-js - bpmn-viewer v8.8.2
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: 2021-10-20
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 = typeof globalThis !== 'undefined' ? globalThis : global || self, global.BpmnJS = factory());
17}(this, (function () { 'use strict';
18
19 var inherits_browser = {exports: {}};
20
21 if (typeof Object.create === 'function') {
22 // implementation from standard node.js 'util' module
23 inherits_browser.exports = function inherits(ctor, superCtor) {
24 if (superCtor) {
25 ctor.super_ = superCtor;
26 ctor.prototype = Object.create(superCtor.prototype, {
27 constructor: {
28 value: ctor,
29 enumerable: false,
30 writable: true,
31 configurable: true
32 }
33 });
34 }
35 };
36 } else {
37 // old school shim for old browsers
38 inherits_browser.exports = function inherits(ctor, superCtor) {
39 if (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 var inherits$1 = inherits_browser.exports;
50
51 /**
52 * Flatten array, one level deep.
53 *
54 * @param {Array<?>} arr
55 *
56 * @return {Array<?>}
57 */
58
59 var nativeToString = Object.prototype.toString;
60 var nativeHasOwnProperty = Object.prototype.hasOwnProperty;
61 function isUndefined$1(obj) {
62 return obj === undefined;
63 }
64 function isDefined(obj) {
65 return obj !== undefined;
66 }
67 function isArray$1(obj) {
68 return nativeToString.call(obj) === '[object Array]';
69 }
70 function isObject(obj) {
71 return nativeToString.call(obj) === '[object Object]';
72 }
73 function isNumber(obj) {
74 return nativeToString.call(obj) === '[object Number]';
75 }
76 function isFunction(obj) {
77 var tag = nativeToString.call(obj);
78 return tag === '[object Function]' || tag === '[object AsyncFunction]' || tag === '[object GeneratorFunction]' || tag === '[object AsyncGeneratorFunction]' || tag === '[object Proxy]';
79 }
80 function isString(obj) {
81 return nativeToString.call(obj) === '[object String]';
82 }
83 /**
84 * Return true, if target owns a property with the given key.
85 *
86 * @param {Object} target
87 * @param {String} key
88 *
89 * @return {Boolean}
90 */
91
92 function has(target, key) {
93 return nativeHasOwnProperty.call(target, key);
94 }
95
96 /**
97 * Find element in collection.
98 *
99 * @param {Array|Object} collection
100 * @param {Function|Object} matcher
101 *
102 * @return {Object}
103 */
104
105 function find(collection, matcher) {
106 matcher = toMatcher(matcher);
107 var match;
108 forEach(collection, function (val, key) {
109 if (matcher(val, key)) {
110 match = val;
111 return false;
112 }
113 });
114 return match;
115 }
116 /**
117 * Find element in collection.
118 *
119 * @param {Array|Object} collection
120 * @param {Function} matcher
121 *
122 * @return {Array} result
123 */
124
125 function filter(collection, matcher) {
126 var result = [];
127 forEach(collection, function (val, key) {
128 if (matcher(val, key)) {
129 result.push(val);
130 }
131 });
132 return result;
133 }
134 /**
135 * Iterate over collection; returning something
136 * (non-undefined) will stop iteration.
137 *
138 * @param {Array|Object} collection
139 * @param {Function} iterator
140 *
141 * @return {Object} return result that stopped the iteration
142 */
143
144 function forEach(collection, iterator) {
145 var val, result;
146
147 if (isUndefined$1(collection)) {
148 return;
149 }
150
151 var convertKey = isArray$1(collection) ? toNum : identity;
152
153 for (var key in collection) {
154 if (has(collection, key)) {
155 val = collection[key];
156 result = iterator(val, convertKey(key));
157
158 if (result === false) {
159 return val;
160 }
161 }
162 }
163 }
164 /**
165 * Reduce collection, returning a single result.
166 *
167 * @param {Object|Array} collection
168 * @param {Function} iterator
169 * @param {Any} result
170 *
171 * @return {Any} result returned from last iterator
172 */
173
174 function reduce(collection, iterator, result) {
175 forEach(collection, function (value, idx) {
176 result = iterator(result, value, idx);
177 });
178 return result;
179 }
180 /**
181 * Return true if every element in the collection
182 * matches the criteria.
183 *
184 * @param {Object|Array} collection
185 * @param {Function} matcher
186 *
187 * @return {Boolean}
188 */
189
190 function every(collection, matcher) {
191 return !!reduce(collection, function (matches, val, key) {
192 return matches && matcher(val, key);
193 }, true);
194 }
195 /**
196 * Return true if some elements in the collection
197 * match the criteria.
198 *
199 * @param {Object|Array} collection
200 * @param {Function} matcher
201 *
202 * @return {Boolean}
203 */
204
205 function some(collection, matcher) {
206 return !!find(collection, matcher);
207 }
208 /**
209 * Create an object pattern matcher.
210 *
211 * @example
212 *
213 * const matcher = matchPattern({ id: 1 });
214 *
215 * var element = find(elements, matcher);
216 *
217 * @param {Object} pattern
218 *
219 * @return {Function} matcherFn
220 */
221
222 function matchPattern(pattern) {
223 return function (el) {
224 return every(pattern, function (val, key) {
225 return el[key] === val;
226 });
227 };
228 }
229
230 function toMatcher(matcher) {
231 return isFunction(matcher) ? matcher : function (e) {
232 return e === matcher;
233 };
234 }
235
236 function identity(arg) {
237 return arg;
238 }
239
240 function toNum(arg) {
241 return Number(arg);
242 }
243
244 /**
245 * Debounce fn, calling it only once if
246 * the given time elapsed between calls.
247 *
248 * @param {Function} fn
249 * @param {Number} timeout
250 *
251 * @return {Function} debounced function
252 */
253 function debounce(fn, timeout) {
254 var timer;
255 var lastArgs;
256 var lastThis;
257 var lastNow;
258
259 function fire() {
260 var now = Date.now();
261 var scheduledDiff = lastNow + timeout - now;
262
263 if (scheduledDiff > 0) {
264 return schedule(scheduledDiff);
265 }
266
267 fn.apply(lastThis, lastArgs);
268 timer = lastNow = lastArgs = lastThis = undefined;
269 }
270
271 function schedule(timeout) {
272 timer = setTimeout(fire, timeout);
273 }
274
275 return function () {
276 lastNow = Date.now();
277
278 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
279 args[_key] = arguments[_key];
280 }
281
282 lastArgs = args;
283 lastThis = this; // ensure an execution is scheduled
284
285 if (!timer) {
286 schedule(timeout);
287 }
288 };
289 }
290 /**
291 * Bind function against target <this>.
292 *
293 * @param {Function} fn
294 * @param {Object} target
295 *
296 * @return {Function} bound function
297 */
298
299 function bind$2(fn, target) {
300 return fn.bind(target);
301 }
302
303 function _extends() {
304 _extends = Object.assign || function (target) {
305 for (var i = 1; i < arguments.length; i++) {
306 var source = arguments[i];
307
308 for (var key in source) {
309 if (Object.prototype.hasOwnProperty.call(source, key)) {
310 target[key] = source[key];
311 }
312 }
313 }
314
315 return target;
316 };
317
318 return _extends.apply(this, arguments);
319 }
320
321 /**
322 * Convenience wrapper for `Object.assign`.
323 *
324 * @param {Object} target
325 * @param {...Object} others
326 *
327 * @return {Object} the target
328 */
329
330 function assign(target) {
331 for (var _len = arguments.length, others = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
332 others[_key - 1] = arguments[_key];
333 }
334
335 return _extends.apply(void 0, [target].concat(others));
336 }
337 /**
338 * Pick given properties from the target object.
339 *
340 * @param {Object} target
341 * @param {Array} properties
342 *
343 * @return {Object} target
344 */
345
346 function pick(target, properties) {
347 var result = {};
348 var obj = Object(target);
349 forEach(properties, function (prop) {
350 if (prop in obj) {
351 result[prop] = target[prop];
352 }
353 });
354 return result;
355 }
356 /**
357 * Pick all target properties, excluding the given ones.
358 *
359 * @param {Object} target
360 * @param {Array} properties
361 *
362 * @return {Object} target
363 */
364
365 function omit(target, properties) {
366 var result = {};
367 var obj = Object(target);
368 forEach(obj, function (prop, key) {
369 if (properties.indexOf(key) === -1) {
370 result[key] = prop;
371 }
372 });
373 return result;
374 }
375
376 var DEFAULT_RENDER_PRIORITY$1 = 1000;
377
378 /**
379 * The base implementation of shape and connection renderers.
380 *
381 * @param {EventBus} eventBus
382 * @param {number} [renderPriority=1000]
383 */
384 function BaseRenderer(eventBus, renderPriority) {
385 var self = this;
386
387 renderPriority = renderPriority || DEFAULT_RENDER_PRIORITY$1;
388
389 eventBus.on([ 'render.shape', 'render.connection' ], renderPriority, function(evt, context) {
390 var type = evt.type,
391 element = context.element,
392 visuals = context.gfx;
393
394 if (self.canRender(element)) {
395 if (type === 'render.shape') {
396 return self.drawShape(visuals, element);
397 } else {
398 return self.drawConnection(visuals, element);
399 }
400 }
401 });
402
403 eventBus.on([ 'render.getShapePath', 'render.getConnectionPath'], renderPriority, function(evt, element) {
404 if (self.canRender(element)) {
405 if (evt.type === 'render.getShapePath') {
406 return self.getShapePath(element);
407 } else {
408 return self.getConnectionPath(element);
409 }
410 }
411 });
412 }
413
414 /**
415 * Should check whether *this* renderer can render
416 * the element/connection.
417 *
418 * @param {element} element
419 *
420 * @returns {boolean}
421 */
422 BaseRenderer.prototype.canRender = function() {};
423
424 /**
425 * Provides the shape's snap svg element to be drawn on the `canvas`.
426 *
427 * @param {djs.Graphics} visuals
428 * @param {Shape} shape
429 *
430 * @returns {Snap.svg} [returns a Snap.svg paper element ]
431 */
432 BaseRenderer.prototype.drawShape = function() {};
433
434 /**
435 * Provides the shape's snap svg element to be drawn on the `canvas`.
436 *
437 * @param {djs.Graphics} visuals
438 * @param {Connection} connection
439 *
440 * @returns {Snap.svg} [returns a Snap.svg paper element ]
441 */
442 BaseRenderer.prototype.drawConnection = function() {};
443
444 /**
445 * Gets the SVG path of a shape that represents it's visual bounds.
446 *
447 * @param {Shape} shape
448 *
449 * @return {string} svg path
450 */
451 BaseRenderer.prototype.getShapePath = function() {};
452
453 /**
454 * Gets the SVG path of a connection that represents it's visual bounds.
455 *
456 * @param {Connection} connection
457 *
458 * @return {string} svg path
459 */
460 BaseRenderer.prototype.getConnectionPath = function() {};
461
462 /**
463 * Is an element of the given BPMN type?
464 *
465 * @param {djs.model.Base|ModdleElement} element
466 * @param {string} type
467 *
468 * @return {boolean}
469 */
470 function is$1(element, type) {
471 var bo = getBusinessObject(element);
472
473 return bo && (typeof bo.$instanceOf === 'function') && bo.$instanceOf(type);
474 }
475
476
477 /**
478 * Return the business object for a given element.
479 *
480 * @param {djs.model.Base|ModdleElement} element
481 *
482 * @return {ModdleElement}
483 */
484 function getBusinessObject(element) {
485 return (element && element.businessObject) || element;
486 }
487
488 function isExpanded(element) {
489
490 if (is$1(element, 'bpmn:CallActivity')) {
491 return false;
492 }
493
494 if (is$1(element, 'bpmn:SubProcess')) {
495 return getBusinessObject(element).di && !!getBusinessObject(element).di.isExpanded;
496 }
497
498 if (is$1(element, 'bpmn:Participant')) {
499 return !!getBusinessObject(element).processRef;
500 }
501
502 return true;
503 }
504
505 function isEventSubProcess(element) {
506 return element && !!getBusinessObject(element).triggeredByEvent;
507 }
508
509 function getLabelAttr(semantic) {
510 if (
511 is$1(semantic, 'bpmn:FlowElement') ||
512 is$1(semantic, 'bpmn:Participant') ||
513 is$1(semantic, 'bpmn:Lane') ||
514 is$1(semantic, 'bpmn:SequenceFlow') ||
515 is$1(semantic, 'bpmn:MessageFlow') ||
516 is$1(semantic, 'bpmn:DataInput') ||
517 is$1(semantic, 'bpmn:DataOutput')
518 ) {
519 return 'name';
520 }
521
522 if (is$1(semantic, 'bpmn:TextAnnotation')) {
523 return 'text';
524 }
525
526 if (is$1(semantic, 'bpmn:Group')) {
527 return 'categoryValueRef';
528 }
529 }
530
531 function getCategoryValue(semantic) {
532 var categoryValueRef = semantic['categoryValueRef'];
533
534 if (!categoryValueRef) {
535 return '';
536 }
537
538
539 return categoryValueRef.value || '';
540 }
541
542 function getLabel(element) {
543 var semantic = element.businessObject,
544 attr = getLabelAttr(semantic);
545
546 if (attr) {
547
548 if (attr === 'categoryValueRef') {
549
550 return getCategoryValue(semantic);
551 }
552
553 return semantic[attr] || '';
554 }
555 }
556
557 function ensureImported(element, target) {
558
559 if (element.ownerDocument !== target.ownerDocument) {
560 try {
561 // may fail on webkit
562 return target.ownerDocument.importNode(element, true);
563 } catch (e) {
564 // ignore
565 }
566 }
567
568 return element;
569 }
570
571 /**
572 * appendTo utility
573 */
574
575 /**
576 * Append a node to a target element and return the appended node.
577 *
578 * @param {SVGElement} element
579 * @param {SVGElement} target
580 *
581 * @return {SVGElement} the appended node
582 */
583 function appendTo(element, target) {
584 return target.appendChild(ensureImported(element, target));
585 }
586
587 /**
588 * append utility
589 */
590
591 /**
592 * Append a node to an element
593 *
594 * @param {SVGElement} element
595 * @param {SVGElement} node
596 *
597 * @return {SVGElement} the element
598 */
599 function append(target, node) {
600 appendTo(node, target);
601 return target;
602 }
603
604 /**
605 * attribute accessor utility
606 */
607
608 var LENGTH_ATTR = 2;
609
610 var CSS_PROPERTIES = {
611 'alignment-baseline': 1,
612 'baseline-shift': 1,
613 'clip': 1,
614 'clip-path': 1,
615 'clip-rule': 1,
616 'color': 1,
617 'color-interpolation': 1,
618 'color-interpolation-filters': 1,
619 'color-profile': 1,
620 'color-rendering': 1,
621 'cursor': 1,
622 'direction': 1,
623 'display': 1,
624 'dominant-baseline': 1,
625 'enable-background': 1,
626 'fill': 1,
627 'fill-opacity': 1,
628 'fill-rule': 1,
629 'filter': 1,
630 'flood-color': 1,
631 'flood-opacity': 1,
632 'font': 1,
633 'font-family': 1,
634 'font-size': LENGTH_ATTR,
635 'font-size-adjust': 1,
636 'font-stretch': 1,
637 'font-style': 1,
638 'font-variant': 1,
639 'font-weight': 1,
640 'glyph-orientation-horizontal': 1,
641 'glyph-orientation-vertical': 1,
642 'image-rendering': 1,
643 'kerning': 1,
644 'letter-spacing': 1,
645 'lighting-color': 1,
646 'marker': 1,
647 'marker-end': 1,
648 'marker-mid': 1,
649 'marker-start': 1,
650 'mask': 1,
651 'opacity': 1,
652 'overflow': 1,
653 'pointer-events': 1,
654 'shape-rendering': 1,
655 'stop-color': 1,
656 'stop-opacity': 1,
657 'stroke': 1,
658 'stroke-dasharray': 1,
659 'stroke-dashoffset': 1,
660 'stroke-linecap': 1,
661 'stroke-linejoin': 1,
662 'stroke-miterlimit': 1,
663 'stroke-opacity': 1,
664 'stroke-width': LENGTH_ATTR,
665 'text-anchor': 1,
666 'text-decoration': 1,
667 'text-rendering': 1,
668 'unicode-bidi': 1,
669 'visibility': 1,
670 'word-spacing': 1,
671 'writing-mode': 1
672 };
673
674
675 function getAttribute(node, name) {
676 if (CSS_PROPERTIES[name]) {
677 return node.style[name];
678 } else {
679 return node.getAttributeNS(null, name);
680 }
681 }
682
683 function setAttribute(node, name, value) {
684 var hyphenated = name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
685
686 var type = CSS_PROPERTIES[hyphenated];
687
688 if (type) {
689 // append pixel unit, unless present
690 if (type === LENGTH_ATTR && typeof value === 'number') {
691 value = String(value) + 'px';
692 }
693
694 node.style[hyphenated] = value;
695 } else {
696 node.setAttributeNS(null, name, value);
697 }
698 }
699
700 function setAttributes(node, attrs) {
701
702 var names = Object.keys(attrs), i, name;
703
704 for (i = 0, name; (name = names[i]); i++) {
705 setAttribute(node, name, attrs[name]);
706 }
707 }
708
709 /**
710 * Gets or sets raw attributes on a node.
711 *
712 * @param {SVGElement} node
713 * @param {Object} [attrs]
714 * @param {String} [name]
715 * @param {String} [value]
716 *
717 * @return {String}
718 */
719 function attr$1(node, name, value) {
720 if (typeof name === 'string') {
721 if (value !== undefined) {
722 setAttribute(node, name, value);
723 } else {
724 return getAttribute(node, name);
725 }
726 } else {
727 setAttributes(node, name);
728 }
729
730 return node;
731 }
732
733 /**
734 * Clear utility
735 */
736 function index(arr, obj) {
737 if (arr.indexOf) {
738 return arr.indexOf(obj);
739 }
740
741
742 for (var i = 0; i < arr.length; ++i) {
743 if (arr[i] === obj) {
744 return i;
745 }
746 }
747
748 return -1;
749 }
750
751 var re$1 = /\s+/;
752
753 var toString$1 = Object.prototype.toString;
754
755 function defined(o) {
756 return typeof o !== 'undefined';
757 }
758
759 /**
760 * Wrap `el` in a `ClassList`.
761 *
762 * @param {Element} el
763 * @return {ClassList}
764 * @api public
765 */
766
767 function classes$1(el) {
768 return new ClassList$1(el);
769 }
770
771 function ClassList$1(el) {
772 if (!el || !el.nodeType) {
773 throw new Error('A DOM element reference is required');
774 }
775 this.el = el;
776 this.list = el.classList;
777 }
778
779 /**
780 * Add class `name` if not already present.
781 *
782 * @param {String} name
783 * @return {ClassList}
784 * @api public
785 */
786
787 ClassList$1.prototype.add = function(name) {
788
789 // classList
790 if (this.list) {
791 this.list.add(name);
792 return this;
793 }
794
795 // fallback
796 var arr = this.array();
797 var i = index(arr, name);
798 if (!~i) {
799 arr.push(name);
800 }
801
802 if (defined(this.el.className.baseVal)) {
803 this.el.className.baseVal = arr.join(' ');
804 } else {
805 this.el.className = arr.join(' ');
806 }
807
808 return this;
809 };
810
811 /**
812 * Remove class `name` when present, or
813 * pass a regular expression to remove
814 * any which match.
815 *
816 * @param {String|RegExp} name
817 * @return {ClassList}
818 * @api public
819 */
820
821 ClassList$1.prototype.remove = function(name) {
822 if ('[object RegExp]' === toString$1.call(name)) {
823 return this.removeMatching(name);
824 }
825
826 // classList
827 if (this.list) {
828 this.list.remove(name);
829 return this;
830 }
831
832 // fallback
833 var arr = this.array();
834 var i = index(arr, name);
835 if (~i) {
836 arr.splice(i, 1);
837 }
838 this.el.className.baseVal = arr.join(' ');
839 return this;
840 };
841
842 /**
843 * Remove all classes matching `re`.
844 *
845 * @param {RegExp} re
846 * @return {ClassList}
847 * @api private
848 */
849
850 ClassList$1.prototype.removeMatching = function(re) {
851 var arr = this.array();
852 for (var i = 0; i < arr.length; i++) {
853 if (re.test(arr[i])) {
854 this.remove(arr[i]);
855 }
856 }
857 return this;
858 };
859
860 /**
861 * Toggle class `name`, can force state via `force`.
862 *
863 * For browsers that support classList, but do not support `force` yet,
864 * the mistake will be detected and corrected.
865 *
866 * @param {String} name
867 * @param {Boolean} force
868 * @return {ClassList}
869 * @api public
870 */
871
872 ClassList$1.prototype.toggle = function(name, force) {
873 // classList
874 if (this.list) {
875 if (defined(force)) {
876 if (force !== this.list.toggle(name, force)) {
877 this.list.toggle(name); // toggle again to correct
878 }
879 } else {
880 this.list.toggle(name);
881 }
882 return this;
883 }
884
885 // fallback
886 if (defined(force)) {
887 if (!force) {
888 this.remove(name);
889 } else {
890 this.add(name);
891 }
892 } else {
893 if (this.has(name)) {
894 this.remove(name);
895 } else {
896 this.add(name);
897 }
898 }
899
900 return this;
901 };
902
903 /**
904 * Return an array of classes.
905 *
906 * @return {Array}
907 * @api public
908 */
909
910 ClassList$1.prototype.array = function() {
911 var className = this.el.getAttribute('class') || '';
912 var str = className.replace(/^\s+|\s+$/g, '');
913 var arr = str.split(re$1);
914 if ('' === arr[0]) {
915 arr.shift();
916 }
917 return arr;
918 };
919
920 /**
921 * Check if class `name` is present.
922 *
923 * @param {String} name
924 * @return {ClassList}
925 * @api public
926 */
927
928 ClassList$1.prototype.has =
929 ClassList$1.prototype.contains = function(name) {
930 return (
931 this.list ?
932 this.list.contains(name) :
933 !! ~index(this.array(), name)
934 );
935 };
936
937 function remove$2(element) {
938 var parent = element.parentNode;
939
940 if (parent) {
941 parent.removeChild(element);
942 }
943
944 return element;
945 }
946
947 /**
948 * Clear utility
949 */
950
951 /**
952 * Removes all children from the given element
953 *
954 * @param {DOMElement} element
955 * @return {DOMElement} the element (for chaining)
956 */
957 function clear$1(element) {
958 var child;
959
960 while ((child = element.firstChild)) {
961 remove$2(child);
962 }
963
964 return element;
965 }
966
967 var ns = {
968 svg: 'http://www.w3.org/2000/svg'
969 };
970
971 /**
972 * DOM parsing utility
973 */
974
975 var SVG_START = '<svg xmlns="' + ns.svg + '"';
976
977 function parse$1(svg) {
978
979 var unwrap = false;
980
981 // ensure we import a valid svg document
982 if (svg.substring(0, 4) === '<svg') {
983 if (svg.indexOf(ns.svg) === -1) {
984 svg = SVG_START + svg.substring(4);
985 }
986 } else {
987 // namespace svg
988 svg = SVG_START + '>' + svg + '</svg>';
989 unwrap = true;
990 }
991
992 var parsed = parseDocument(svg);
993
994 if (!unwrap) {
995 return parsed;
996 }
997
998 var fragment = document.createDocumentFragment();
999
1000 var parent = parsed.firstChild;
1001
1002 while (parent.firstChild) {
1003 fragment.appendChild(parent.firstChild);
1004 }
1005
1006 return fragment;
1007 }
1008
1009 function parseDocument(svg) {
1010
1011 var parser;
1012
1013 // parse
1014 parser = new DOMParser();
1015 parser.async = false;
1016
1017 return parser.parseFromString(svg, 'text/xml');
1018 }
1019
1020 /**
1021 * Create utility for SVG elements
1022 */
1023
1024
1025 /**
1026 * Create a specific type from name or SVG markup.
1027 *
1028 * @param {String} name the name or markup of the element
1029 * @param {Object} [attrs] attributes to set on the element
1030 *
1031 * @returns {SVGElement}
1032 */
1033 function create$1(name, attrs) {
1034 var element;
1035
1036 if (name.charAt(0) === '<') {
1037 element = parse$1(name).firstChild;
1038 element = document.importNode(element, true);
1039 } else {
1040 element = document.createElementNS(ns.svg, name);
1041 }
1042
1043 if (attrs) {
1044 attr$1(element, attrs);
1045 }
1046
1047 return element;
1048 }
1049
1050 /**
1051 * Geometry helpers
1052 */
1053
1054 // fake node used to instantiate svg geometry elements
1055 var node = create$1('svg');
1056
1057 function extend$1(object, props) {
1058 var i, k, keys = Object.keys(props);
1059
1060 for (i = 0; (k = keys[i]); i++) {
1061 object[k] = props[k];
1062 }
1063
1064 return object;
1065 }
1066
1067 /**
1068 * Create matrix via args.
1069 *
1070 * @example
1071 *
1072 * createMatrix({ a: 1, b: 1 });
1073 * createMatrix();
1074 * createMatrix(1, 2, 0, 0, 30, 20);
1075 *
1076 * @return {SVGMatrix}
1077 */
1078 function createMatrix(a, b, c, d, e, f) {
1079 var matrix = node.createSVGMatrix();
1080
1081 switch (arguments.length) {
1082 case 0:
1083 return matrix;
1084 case 1:
1085 return extend$1(matrix, a);
1086 case 6:
1087 return extend$1(matrix, {
1088 a: a,
1089 b: b,
1090 c: c,
1091 d: d,
1092 e: e,
1093 f: f
1094 });
1095 }
1096 }
1097
1098 function createTransform(matrix) {
1099 if (matrix) {
1100 return node.createSVGTransformFromMatrix(matrix);
1101 } else {
1102 return node.createSVGTransform();
1103 }
1104 }
1105
1106 /**
1107 * Serialization util
1108 */
1109
1110 var TEXT_ENTITIES = /([&<>]{1})/g;
1111 var ATTR_ENTITIES = /([\n\r"]{1})/g;
1112
1113 var ENTITY_REPLACEMENT = {
1114 '&': '&amp;',
1115 '<': '&lt;',
1116 '>': '&gt;',
1117 '"': '\''
1118 };
1119
1120 function escape$1(str, pattern) {
1121
1122 function replaceFn(match, entity) {
1123 return ENTITY_REPLACEMENT[entity] || entity;
1124 }
1125
1126 return str.replace(pattern, replaceFn);
1127 }
1128
1129 function serialize(node, output) {
1130
1131 var i, len, attrMap, attrNode, childNodes;
1132
1133 switch (node.nodeType) {
1134 // TEXT
1135 case 3:
1136 // replace special XML characters
1137 output.push(escape$1(node.textContent, TEXT_ENTITIES));
1138 break;
1139
1140 // ELEMENT
1141 case 1:
1142 output.push('<', node.tagName);
1143
1144 if (node.hasAttributes()) {
1145 attrMap = node.attributes;
1146 for (i = 0, len = attrMap.length; i < len; ++i) {
1147 attrNode = attrMap.item(i);
1148 output.push(' ', attrNode.name, '="', escape$1(attrNode.value, ATTR_ENTITIES), '"');
1149 }
1150 }
1151
1152 if (node.hasChildNodes()) {
1153 output.push('>');
1154 childNodes = node.childNodes;
1155 for (i = 0, len = childNodes.length; i < len; ++i) {
1156 serialize(childNodes.item(i), output);
1157 }
1158 output.push('</', node.tagName, '>');
1159 } else {
1160 output.push('/>');
1161 }
1162 break;
1163
1164 // COMMENT
1165 case 8:
1166 output.push('<!--', escape$1(node.nodeValue, TEXT_ENTITIES), '-->');
1167 break;
1168
1169 // CDATA
1170 case 4:
1171 output.push('<![CDATA[', node.nodeValue, ']]>');
1172 break;
1173
1174 default:
1175 throw new Error('unable to handle node ' + node.nodeType);
1176 }
1177
1178 return output;
1179 }
1180
1181 /**
1182 * innerHTML like functionality for SVG elements.
1183 * based on innerSVG (https://code.google.com/p/innersvg)
1184 */
1185
1186
1187 function set(element, svg) {
1188
1189 var parsed = parse$1(svg);
1190
1191 // clear element contents
1192 clear$1(element);
1193
1194 if (!svg) {
1195 return;
1196 }
1197
1198 if (!isFragment(parsed)) {
1199 // extract <svg> from parsed document
1200 parsed = parsed.documentElement;
1201 }
1202
1203 var nodes = slice$1(parsed.childNodes);
1204
1205 // import + append each node
1206 for (var i = 0; i < nodes.length; i++) {
1207 appendTo(nodes[i], element);
1208 }
1209
1210 }
1211
1212 function get(element) {
1213 var child = element.firstChild,
1214 output = [];
1215
1216 while (child) {
1217 serialize(child, output);
1218 child = child.nextSibling;
1219 }
1220
1221 return output.join('');
1222 }
1223
1224 function isFragment(node) {
1225 return node.nodeName === '#document-fragment';
1226 }
1227
1228 function innerSVG(element, svg) {
1229
1230 if (svg !== undefined) {
1231
1232 try {
1233 set(element, svg);
1234 } catch (e) {
1235 throw new Error('error parsing SVG: ' + e.message);
1236 }
1237
1238 return element;
1239 } else {
1240 return get(element);
1241 }
1242 }
1243
1244
1245 function slice$1(arr) {
1246 return Array.prototype.slice.call(arr);
1247 }
1248
1249 /**
1250 * transform accessor utility
1251 */
1252
1253 function wrapMatrix(transformList, transform) {
1254 if (transform instanceof SVGMatrix) {
1255 return transformList.createSVGTransformFromMatrix(transform);
1256 }
1257
1258 return transform;
1259 }
1260
1261
1262 function setTransforms(transformList, transforms) {
1263 var i, t;
1264
1265 transformList.clear();
1266
1267 for (i = 0; (t = transforms[i]); i++) {
1268 transformList.appendItem(wrapMatrix(transformList, t));
1269 }
1270 }
1271
1272 /**
1273 * Get or set the transforms on the given node.
1274 *
1275 * @param {SVGElement} node
1276 * @param {SVGTransform|SVGMatrix|Array<SVGTransform|SVGMatrix>} [transforms]
1277 *
1278 * @return {SVGTransform} the consolidated transform
1279 */
1280 function transform$1(node, transforms) {
1281 var transformList = node.transform.baseVal;
1282
1283 if (transforms) {
1284
1285 if (!Array.isArray(transforms)) {
1286 transforms = [ transforms ];
1287 }
1288
1289 setTransforms(transformList, transforms);
1290 }
1291
1292 return transformList.consolidate();
1293 }
1294
1295 function componentsToPath(elements) {
1296 return elements.join(',').replace(/,?([A-z]),?/g, '$1');
1297 }
1298
1299 function toSVGPoints(points) {
1300 var result = '';
1301
1302 for (var i = 0, p; (p = points[i]); i++) {
1303 result += p.x + ',' + p.y + ' ';
1304 }
1305
1306 return result;
1307 }
1308
1309 function createLine(points, attrs) {
1310
1311 var line = create$1('polyline');
1312 attr$1(line, { points: toSVGPoints(points) });
1313
1314 if (attrs) {
1315 attr$1(line, attrs);
1316 }
1317
1318 return line;
1319 }
1320
1321 function updateLine(gfx, points) {
1322 attr$1(gfx, { points: toSVGPoints(points) });
1323
1324 return gfx;
1325 }
1326
1327 // element utils //////////////////////
1328
1329 /**
1330 * Checks if eventDefinition of the given element matches with semantic type.
1331 *
1332 * @return {boolean} true if element is of the given semantic type
1333 */
1334 function isTypedEvent(event, eventDefinitionType, filter) {
1335
1336 function matches(definition, filter) {
1337 return every(filter, function(val, key) {
1338
1339 // we want a == conversion here, to be able to catch
1340 // undefined == false and friends
1341 /* jshint -W116 */
1342 return definition[key] == val;
1343 });
1344 }
1345
1346 return some(event.eventDefinitions, function(definition) {
1347 return definition.$type === eventDefinitionType && matches(event, filter);
1348 });
1349 }
1350
1351 function isThrowEvent(event) {
1352 return (event.$type === 'bpmn:IntermediateThrowEvent') || (event.$type === 'bpmn:EndEvent');
1353 }
1354
1355 function isCollection(element) {
1356 var dataObject = element.dataObjectRef;
1357
1358 return element.isCollection || (dataObject && dataObject.isCollection);
1359 }
1360
1361 function getDi(element) {
1362 return element.businessObject.di;
1363 }
1364
1365 function getSemantic(element) {
1366 return element.businessObject;
1367 }
1368
1369
1370 // color access //////////////////////
1371
1372 function getFillColor(element, defaultColor) {
1373 var di = getDi(element);
1374
1375 return di.get('color:background-color') || di.get('bioc:fill') || defaultColor || 'white';
1376 }
1377
1378 function getStrokeColor(element, defaultColor) {
1379 var di = getDi(element);
1380
1381 return di.get('color:border-color') || di.get('bioc:stroke') || defaultColor || 'black';
1382 }
1383
1384 function getLabelColor(element, defaultColor, defaultStrokeColor) {
1385 var di = getDi(element),
1386 label = di.get('label');
1387
1388 return label && label.get('color:color') || defaultColor ||
1389 getStrokeColor(element, defaultStrokeColor);
1390 }
1391
1392 // cropping path customizations //////////////////////
1393
1394 function getCirclePath(shape) {
1395
1396 var cx = shape.x + shape.width / 2,
1397 cy = shape.y + shape.height / 2,
1398 radius = shape.width / 2;
1399
1400 var circlePath = [
1401 ['M', cx, cy],
1402 ['m', 0, -radius],
1403 ['a', radius, radius, 0, 1, 1, 0, 2 * radius],
1404 ['a', radius, radius, 0, 1, 1, 0, -2 * radius],
1405 ['z']
1406 ];
1407
1408 return componentsToPath(circlePath);
1409 }
1410
1411 function getRoundRectPath(shape, borderRadius) {
1412
1413 var x = shape.x,
1414 y = shape.y,
1415 width = shape.width,
1416 height = shape.height;
1417
1418 var roundRectPath = [
1419 ['M', x + borderRadius, y],
1420 ['l', width - borderRadius * 2, 0],
1421 ['a', borderRadius, borderRadius, 0, 0, 1, borderRadius, borderRadius],
1422 ['l', 0, height - borderRadius * 2],
1423 ['a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, borderRadius],
1424 ['l', borderRadius * 2 - width, 0],
1425 ['a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, -borderRadius],
1426 ['l', 0, borderRadius * 2 - height],
1427 ['a', borderRadius, borderRadius, 0, 0, 1, borderRadius, -borderRadius],
1428 ['z']
1429 ];
1430
1431 return componentsToPath(roundRectPath);
1432 }
1433
1434 function getDiamondPath(shape) {
1435
1436 var width = shape.width,
1437 height = shape.height,
1438 x = shape.x,
1439 y = shape.y,
1440 halfWidth = width / 2,
1441 halfHeight = height / 2;
1442
1443 var diamondPath = [
1444 ['M', x + halfWidth, y],
1445 ['l', halfWidth, halfHeight],
1446 ['l', -halfWidth, halfHeight],
1447 ['l', -halfWidth, -halfHeight],
1448 ['z']
1449 ];
1450
1451 return componentsToPath(diamondPath);
1452 }
1453
1454 function getRectPath(shape) {
1455 var x = shape.x,
1456 y = shape.y,
1457 width = shape.width,
1458 height = shape.height;
1459
1460 var rectPath = [
1461 ['M', x, y],
1462 ['l', width, 0],
1463 ['l', 0, height],
1464 ['l', -width, 0],
1465 ['z']
1466 ];
1467
1468 return componentsToPath(rectPath);
1469 }
1470
1471 /**
1472 * Set attribute `name` to `val`, or get attr `name`.
1473 *
1474 * @param {Element} el
1475 * @param {String} name
1476 * @param {String} [val]
1477 * @api public
1478 */
1479 function attr(el, name, val) {
1480 // get
1481 if (arguments.length == 2) {
1482 return el.getAttribute(name);
1483 }
1484
1485 // remove
1486 if (val === null) {
1487 return el.removeAttribute(name);
1488 }
1489
1490 // set
1491 el.setAttribute(name, val);
1492
1493 return el;
1494 }
1495
1496 var indexOf = [].indexOf;
1497
1498 var indexof = function(arr, obj){
1499 if (indexOf) return arr.indexOf(obj);
1500 for (var i = 0; i < arr.length; ++i) {
1501 if (arr[i] === obj) return i;
1502 }
1503 return -1;
1504 };
1505
1506 /**
1507 * Taken from https://github.com/component/classes
1508 *
1509 * Without the component bits.
1510 */
1511
1512 /**
1513 * Whitespace regexp.
1514 */
1515
1516 var re = /\s+/;
1517
1518 /**
1519 * toString reference.
1520 */
1521
1522 var toString = Object.prototype.toString;
1523
1524 /**
1525 * Wrap `el` in a `ClassList`.
1526 *
1527 * @param {Element} el
1528 * @return {ClassList}
1529 * @api public
1530 */
1531
1532 function classes(el) {
1533 return new ClassList(el);
1534 }
1535
1536 /**
1537 * Initialize a new ClassList for `el`.
1538 *
1539 * @param {Element} el
1540 * @api private
1541 */
1542
1543 function ClassList(el) {
1544 if (!el || !el.nodeType) {
1545 throw new Error('A DOM element reference is required');
1546 }
1547 this.el = el;
1548 this.list = el.classList;
1549 }
1550
1551 /**
1552 * Add class `name` if not already present.
1553 *
1554 * @param {String} name
1555 * @return {ClassList}
1556 * @api public
1557 */
1558
1559 ClassList.prototype.add = function (name) {
1560 // classList
1561 if (this.list) {
1562 this.list.add(name);
1563 return this;
1564 }
1565
1566 // fallback
1567 var arr = this.array();
1568 var i = indexof(arr, name);
1569 if (!~i) arr.push(name);
1570 this.el.className = arr.join(' ');
1571 return this;
1572 };
1573
1574 /**
1575 * Remove class `name` when present, or
1576 * pass a regular expression to remove
1577 * any which match.
1578 *
1579 * @param {String|RegExp} name
1580 * @return {ClassList}
1581 * @api public
1582 */
1583
1584 ClassList.prototype.remove = function (name) {
1585 if ('[object RegExp]' == toString.call(name)) {
1586 return this.removeMatching(name);
1587 }
1588
1589 // classList
1590 if (this.list) {
1591 this.list.remove(name);
1592 return this;
1593 }
1594
1595 // fallback
1596 var arr = this.array();
1597 var i = indexof(arr, name);
1598 if (~i) arr.splice(i, 1);
1599 this.el.className = arr.join(' ');
1600 return this;
1601 };
1602
1603 /**
1604 * Remove all classes matching `re`.
1605 *
1606 * @param {RegExp} re
1607 * @return {ClassList}
1608 * @api private
1609 */
1610
1611 ClassList.prototype.removeMatching = function (re) {
1612 var arr = this.array();
1613 for (var i = 0; i < arr.length; i++) {
1614 if (re.test(arr[i])) {
1615 this.remove(arr[i]);
1616 }
1617 }
1618 return this;
1619 };
1620
1621 /**
1622 * Toggle class `name`, can force state via `force`.
1623 *
1624 * For browsers that support classList, but do not support `force` yet,
1625 * the mistake will be detected and corrected.
1626 *
1627 * @param {String} name
1628 * @param {Boolean} force
1629 * @return {ClassList}
1630 * @api public
1631 */
1632
1633 ClassList.prototype.toggle = function (name, force) {
1634 // classList
1635 if (this.list) {
1636 if ('undefined' !== typeof force) {
1637 if (force !== this.list.toggle(name, force)) {
1638 this.list.toggle(name); // toggle again to correct
1639 }
1640 } else {
1641 this.list.toggle(name);
1642 }
1643 return this;
1644 }
1645
1646 // fallback
1647 if ('undefined' !== typeof force) {
1648 if (!force) {
1649 this.remove(name);
1650 } else {
1651 this.add(name);
1652 }
1653 } else {
1654 if (this.has(name)) {
1655 this.remove(name);
1656 } else {
1657 this.add(name);
1658 }
1659 }
1660
1661 return this;
1662 };
1663
1664 /**
1665 * Return an array of classes.
1666 *
1667 * @return {Array}
1668 * @api public
1669 */
1670
1671 ClassList.prototype.array = function () {
1672 var className = this.el.getAttribute('class') || '';
1673 var str = className.replace(/^\s+|\s+$/g, '');
1674 var arr = str.split(re);
1675 if ('' === arr[0]) arr.shift();
1676 return arr;
1677 };
1678
1679 /**
1680 * Check if class `name` is present.
1681 *
1682 * @param {String} name
1683 * @return {ClassList}
1684 * @api public
1685 */
1686
1687 ClassList.prototype.has = ClassList.prototype.contains = function (name) {
1688 return this.list ? this.list.contains(name) : !!~indexof(this.array(), name);
1689 };
1690
1691 /**
1692 * Remove all children from the given element.
1693 */
1694 function clear(el) {
1695
1696 var c;
1697
1698 while (el.childNodes.length) {
1699 c = el.childNodes[0];
1700 el.removeChild(c);
1701 }
1702
1703 return el;
1704 }
1705
1706 var proto = typeof Element !== 'undefined' ? Element.prototype : {};
1707 var vendor = proto.matches
1708 || proto.matchesSelector
1709 || proto.webkitMatchesSelector
1710 || proto.mozMatchesSelector
1711 || proto.msMatchesSelector
1712 || proto.oMatchesSelector;
1713
1714 var matchesSelector = match;
1715
1716 /**
1717 * Match `el` to `selector`.
1718 *
1719 * @param {Element} el
1720 * @param {String} selector
1721 * @return {Boolean}
1722 * @api public
1723 */
1724
1725 function match(el, selector) {
1726 if (!el || el.nodeType !== 1) return false;
1727 if (vendor) return vendor.call(el, selector);
1728 var nodes = el.parentNode.querySelectorAll(selector);
1729 for (var i = 0; i < nodes.length; i++) {
1730 if (nodes[i] == el) return true;
1731 }
1732 return false;
1733 }
1734
1735 /**
1736 * Closest
1737 *
1738 * @param {Element} el
1739 * @param {String} selector
1740 * @param {Boolean} checkYourSelf (optional)
1741 */
1742 function closest (element, selector, checkYourSelf) {
1743 var currentElem = checkYourSelf ? element : element.parentNode;
1744
1745 while (currentElem && currentElem.nodeType !== document.DOCUMENT_NODE && currentElem.nodeType !== document.DOCUMENT_FRAGMENT_NODE) {
1746
1747 if (matchesSelector(currentElem, selector)) {
1748 return currentElem;
1749 }
1750
1751 currentElem = currentElem.parentNode;
1752 }
1753
1754 return matchesSelector(currentElem, selector) ? currentElem : null;
1755 }
1756
1757 var bind = window.addEventListener ? 'addEventListener' : 'attachEvent',
1758 unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
1759 prefix$6 = bind !== 'addEventListener' ? 'on' : '';
1760
1761 /**
1762 * Bind `el` event `type` to `fn`.
1763 *
1764 * @param {Element} el
1765 * @param {String} type
1766 * @param {Function} fn
1767 * @param {Boolean} capture
1768 * @return {Function}
1769 * @api public
1770 */
1771
1772 var bind_1 = function(el, type, fn, capture){
1773 el[bind](prefix$6 + type, fn, capture || false);
1774 return fn;
1775 };
1776
1777 /**
1778 * Unbind `el` event `type`'s callback `fn`.
1779 *
1780 * @param {Element} el
1781 * @param {String} type
1782 * @param {Function} fn
1783 * @param {Boolean} capture
1784 * @return {Function}
1785 * @api public
1786 */
1787
1788 var unbind_1 = function(el, type, fn, capture){
1789 el[unbind](prefix$6 + type, fn, capture || false);
1790 return fn;
1791 };
1792
1793 var componentEvent = {
1794 bind: bind_1,
1795 unbind: unbind_1
1796 };
1797
1798 /**
1799 * Module dependencies.
1800 */
1801
1802 /**
1803 * Delegate event `type` to `selector`
1804 * and invoke `fn(e)`. A callback function
1805 * is returned which may be passed to `.unbind()`.
1806 *
1807 * @param {Element} el
1808 * @param {String} selector
1809 * @param {String} type
1810 * @param {Function} fn
1811 * @param {Boolean} capture
1812 * @return {Function}
1813 * @api public
1814 */
1815
1816 // Some events don't bubble, so we want to bind to the capture phase instead
1817 // when delegating.
1818 var forceCaptureEvents = ['focus', 'blur'];
1819
1820 function bind$1(el, selector, type, fn, capture) {
1821 if (forceCaptureEvents.indexOf(type) !== -1) {
1822 capture = true;
1823 }
1824
1825 return componentEvent.bind(el, type, function (e) {
1826 var target = e.target || e.srcElement;
1827 e.delegateTarget = closest(target, selector, true);
1828 if (e.delegateTarget) {
1829 fn.call(el, e);
1830 }
1831 }, capture);
1832 }
1833
1834 /**
1835 * Unbind event `type`'s callback `fn`.
1836 *
1837 * @param {Element} el
1838 * @param {String} type
1839 * @param {Function} fn
1840 * @param {Boolean} capture
1841 * @api public
1842 */
1843 function unbind$1(el, type, fn, capture) {
1844 if (forceCaptureEvents.indexOf(type) !== -1) {
1845 capture = true;
1846 }
1847
1848 return componentEvent.unbind(el, type, fn, capture);
1849 }
1850
1851 var delegate = {
1852 bind: bind$1,
1853 unbind: unbind$1
1854 };
1855
1856 /**
1857 * Expose `parse`.
1858 */
1859
1860 var domify = parse;
1861
1862 /**
1863 * Tests for browser support.
1864 */
1865
1866 var innerHTMLBug = false;
1867 var bugTestDiv;
1868 if (typeof document !== 'undefined') {
1869 bugTestDiv = document.createElement('div');
1870 // Setup
1871 bugTestDiv.innerHTML = ' <link/><table></table><a href="/a">a</a><input type="checkbox"/>';
1872 // Make sure that link elements get serialized correctly by innerHTML
1873 // This requires a wrapper element in IE
1874 innerHTMLBug = !bugTestDiv.getElementsByTagName('link').length;
1875 bugTestDiv = undefined;
1876 }
1877
1878 /**
1879 * Wrap map from jquery.
1880 */
1881
1882 var map = {
1883 legend: [1, '<fieldset>', '</fieldset>'],
1884 tr: [2, '<table><tbody>', '</tbody></table>'],
1885 col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
1886 // for script/link/style tags to work in IE6-8, you have to wrap
1887 // in a div with a non-whitespace character in front, ha!
1888 _default: innerHTMLBug ? [1, 'X<div>', '</div>'] : [0, '', '']
1889 };
1890
1891 map.td =
1892 map.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
1893
1894 map.option =
1895 map.optgroup = [1, '<select multiple="multiple">', '</select>'];
1896
1897 map.thead =
1898 map.tbody =
1899 map.colgroup =
1900 map.caption =
1901 map.tfoot = [1, '<table>', '</table>'];
1902
1903 map.polyline =
1904 map.ellipse =
1905 map.polygon =
1906 map.circle =
1907 map.text =
1908 map.line =
1909 map.path =
1910 map.rect =
1911 map.g = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>'];
1912
1913 /**
1914 * Parse `html` and return a DOM Node instance, which could be a TextNode,
1915 * HTML DOM Node of some kind (<div> for example), or a DocumentFragment
1916 * instance, depending on the contents of the `html` string.
1917 *
1918 * @param {String} html - HTML string to "domify"
1919 * @param {Document} doc - The `document` instance to create the Node for
1920 * @return {DOMNode} the TextNode, DOM Node, or DocumentFragment instance
1921 * @api private
1922 */
1923
1924 function parse(html, doc) {
1925 if ('string' != typeof html) throw new TypeError('String expected');
1926
1927 // default to the global `document` object
1928 if (!doc) doc = document;
1929
1930 // tag name
1931 var m = /<([\w:]+)/.exec(html);
1932 if (!m) return doc.createTextNode(html);
1933
1934 html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace
1935
1936 var tag = m[1];
1937
1938 // body support
1939 if (tag == 'body') {
1940 var el = doc.createElement('html');
1941 el.innerHTML = html;
1942 return el.removeChild(el.lastChild);
1943 }
1944
1945 // wrap map
1946 var wrap = map[tag] || map._default;
1947 var depth = wrap[0];
1948 var prefix = wrap[1];
1949 var suffix = wrap[2];
1950 var el = doc.createElement('div');
1951 el.innerHTML = prefix + html + suffix;
1952 while (depth--) el = el.lastChild;
1953
1954 // one element
1955 if (el.firstChild == el.lastChild) {
1956 return el.removeChild(el.firstChild);
1957 }
1958
1959 // several elements
1960 var fragment = doc.createDocumentFragment();
1961 while (el.firstChild) {
1962 fragment.appendChild(el.removeChild(el.firstChild));
1963 }
1964
1965 return fragment;
1966 }
1967
1968 function query(selector, el) {
1969 el = el || document;
1970
1971 return el.querySelector(selector);
1972 }
1973
1974 function all(selector, el) {
1975 el = el || document;
1976
1977 return el.querySelectorAll(selector);
1978 }
1979
1980 function remove$1(el) {
1981 el.parentNode && el.parentNode.removeChild(el);
1982 }
1983
1984 /**
1985 * @param {<SVGElement>} element
1986 * @param {number} x
1987 * @param {number} y
1988 * @param {number} angle
1989 * @param {number} amount
1990 */
1991 function transform(gfx, x, y, angle, amount) {
1992 var translate = createTransform();
1993 translate.setTranslate(x, y);
1994
1995 var rotate = createTransform();
1996 rotate.setRotate(angle || 0, 0, 0);
1997
1998 var scale = createTransform();
1999 scale.setScale(amount || 1, amount || 1);
2000
2001 transform$1(gfx, [ translate, rotate, scale ]);
2002 }
2003
2004
2005 /**
2006 * @param {SVGElement} element
2007 * @param {number} x
2008 * @param {number} y
2009 */
2010 function translate$1(gfx, x, y) {
2011 var translate = createTransform();
2012 translate.setTranslate(x, y);
2013
2014 transform$1(gfx, translate);
2015 }
2016
2017
2018 /**
2019 * @param {SVGElement} element
2020 * @param {number} angle
2021 */
2022 function rotate(gfx, angle) {
2023 var rotate = createTransform();
2024 rotate.setRotate(angle, 0, 0);
2025
2026 transform$1(gfx, rotate);
2027 }
2028
2029 function createCommonjsModule(fn, module) {
2030 return module = { exports: {} }, fn(module, module.exports), module.exports;
2031 }
2032
2033 var hat_1 = createCommonjsModule(function (module) {
2034 var hat = module.exports = function (bits, base) {
2035 if (!base) base = 16;
2036 if (bits === undefined) bits = 128;
2037 if (bits <= 0) return '0';
2038
2039 var digits = Math.log(Math.pow(2, bits)) / Math.log(base);
2040 for (var i = 2; digits === Infinity; i *= 2) {
2041 digits = Math.log(Math.pow(2, bits / i)) / Math.log(base) * i;
2042 }
2043
2044 var rem = digits - Math.floor(digits);
2045
2046 var res = '';
2047
2048 for (var i = 0; i < Math.floor(digits); i++) {
2049 var x = Math.floor(Math.random() * base).toString(base);
2050 res = x + res;
2051 }
2052
2053 if (rem) {
2054 var b = Math.pow(base, rem);
2055 var x = Math.floor(Math.random() * b).toString(base);
2056 res = x + res;
2057 }
2058
2059 var parsed = parseInt(res, base);
2060 if (parsed !== Infinity && parsed >= Math.pow(2, bits)) {
2061 return hat(bits, base)
2062 }
2063 else return res;
2064 };
2065
2066 hat.rack = function (bits, base, expandBy) {
2067 var fn = function (data) {
2068 var iters = 0;
2069 do {
2070 if (iters ++ > 10) {
2071 if (expandBy) bits += expandBy;
2072 else throw new Error('too many ID collisions, use more bits')
2073 }
2074
2075 var id = hat(bits, base);
2076 } while (Object.hasOwnProperty.call(hats, id));
2077
2078 hats[id] = data;
2079 return id;
2080 };
2081 var hats = fn.hats = {};
2082
2083 fn.get = function (id) {
2084 return fn.hats[id];
2085 };
2086
2087 fn.set = function (id, value) {
2088 fn.hats[id] = value;
2089 return fn;
2090 };
2091
2092 fn.bits = bits || 128;
2093 fn.base = base || 16;
2094 return fn;
2095 };
2096 });
2097
2098 /**
2099 * Create a new id generator / cache instance.
2100 *
2101 * You may optionally provide a seed that is used internally.
2102 *
2103 * @param {Seed} seed
2104 */
2105
2106 function Ids(seed) {
2107 if (!(this instanceof Ids)) {
2108 return new Ids(seed);
2109 }
2110
2111 seed = seed || [128, 36, 1];
2112 this._seed = seed.length ? hat_1.rack(seed[0], seed[1], seed[2]) : seed;
2113 }
2114 /**
2115 * Generate a next id.
2116 *
2117 * @param {Object} [element] element to bind the id to
2118 *
2119 * @return {String} id
2120 */
2121
2122 Ids.prototype.next = function (element) {
2123 return this._seed(element || true);
2124 };
2125 /**
2126 * Generate a next id with a given prefix.
2127 *
2128 * @param {Object} [element] element to bind the id to
2129 *
2130 * @return {String} id
2131 */
2132
2133
2134 Ids.prototype.nextPrefixed = function (prefix, element) {
2135 var id;
2136
2137 do {
2138 id = prefix + this.next(true);
2139 } while (this.assigned(id)); // claim {prefix}{random}
2140
2141
2142 this.claim(id, element); // return
2143
2144 return id;
2145 };
2146 /**
2147 * Manually claim an existing id.
2148 *
2149 * @param {String} id
2150 * @param {String} [element] element the id is claimed by
2151 */
2152
2153
2154 Ids.prototype.claim = function (id, element) {
2155 this._seed.set(id, element || true);
2156 };
2157 /**
2158 * Returns true if the given id has already been assigned.
2159 *
2160 * @param {String} id
2161 * @return {Boolean}
2162 */
2163
2164
2165 Ids.prototype.assigned = function (id) {
2166 return this._seed.get(id) || false;
2167 };
2168 /**
2169 * Unclaim an id.
2170 *
2171 * @param {String} id the id to unclaim
2172 */
2173
2174
2175 Ids.prototype.unclaim = function (id) {
2176 delete this._seed.hats[id];
2177 };
2178 /**
2179 * Clear all claimed ids.
2180 */
2181
2182
2183 Ids.prototype.clear = function () {
2184 var hats = this._seed.hats,
2185 id;
2186
2187 for (id in hats) {
2188 this.unclaim(id);
2189 }
2190 };
2191
2192 var RENDERER_IDS = new Ids();
2193
2194 var TASK_BORDER_RADIUS = 10;
2195 var INNER_OUTER_DIST = 3;
2196
2197 var DEFAULT_FILL_OPACITY = .95,
2198 HIGH_FILL_OPACITY = .35;
2199
2200 var ELEMENT_LABEL_DISTANCE = 10;
2201
2202 function BpmnRenderer(
2203 config, eventBus, styles, pathMap,
2204 canvas, textRenderer, priority) {
2205
2206 BaseRenderer.call(this, eventBus, priority);
2207
2208 var defaultFillColor = config && config.defaultFillColor,
2209 defaultStrokeColor = config && config.defaultStrokeColor,
2210 defaultLabelColor = config && config.defaultLabelColor;
2211
2212 var rendererId = RENDERER_IDS.next();
2213
2214 var markers = {};
2215
2216 var computeStyle = styles.computeStyle;
2217
2218 function addMarker(id, options) {
2219 var attrs = assign({
2220 fill: 'black',
2221 strokeWidth: 1,
2222 strokeLinecap: 'round',
2223 strokeDasharray: 'none'
2224 }, options.attrs);
2225
2226 var ref = options.ref || { x: 0, y: 0 };
2227
2228 var scale = options.scale || 1;
2229
2230 // fix for safari / chrome / firefox bug not correctly
2231 // resetting stroke dash array
2232 if (attrs.strokeDasharray === 'none') {
2233 attrs.strokeDasharray = [10000, 1];
2234 }
2235
2236 var marker = create$1('marker');
2237
2238 attr$1(options.element, attrs);
2239
2240 append(marker, options.element);
2241
2242 attr$1(marker, {
2243 id: id,
2244 viewBox: '0 0 20 20',
2245 refX: ref.x,
2246 refY: ref.y,
2247 markerWidth: 20 * scale,
2248 markerHeight: 20 * scale,
2249 orient: 'auto'
2250 });
2251
2252 var defs = query('defs', canvas._svg);
2253
2254 if (!defs) {
2255 defs = create$1('defs');
2256
2257 append(canvas._svg, defs);
2258 }
2259
2260 append(defs, marker);
2261
2262 markers[id] = marker;
2263 }
2264
2265 function colorEscape(str) {
2266
2267 // only allow characters and numbers
2268 return str.replace(/[^0-9a-zA-z]+/g, '_');
2269 }
2270
2271 function marker(type, fill, stroke) {
2272 var id = type + '-' + colorEscape(fill) + '-' + colorEscape(stroke) + '-' + rendererId;
2273
2274 if (!markers[id]) {
2275 createMarker(id, type, fill, stroke);
2276 }
2277
2278 return 'url(#' + id + ')';
2279 }
2280
2281 function createMarker(id, type, fill, stroke) {
2282
2283 if (type === 'sequenceflow-end') {
2284 var sequenceflowEnd = create$1('path');
2285 attr$1(sequenceflowEnd, { d: 'M 1 5 L 11 10 L 1 15 Z' });
2286
2287 addMarker(id, {
2288 element: sequenceflowEnd,
2289 ref: { x: 11, y: 10 },
2290 scale: 0.5,
2291 attrs: {
2292 fill: stroke,
2293 stroke: stroke
2294 }
2295 });
2296 }
2297
2298 if (type === 'messageflow-start') {
2299 var messageflowStart = create$1('circle');
2300 attr$1(messageflowStart, { cx: 6, cy: 6, r: 3.5 });
2301
2302 addMarker(id, {
2303 element: messageflowStart,
2304 attrs: {
2305 fill: fill,
2306 stroke: stroke
2307 },
2308 ref: { x: 6, y: 6 }
2309 });
2310 }
2311
2312 if (type === 'messageflow-end') {
2313 var messageflowEnd = create$1('path');
2314 attr$1(messageflowEnd, { d: 'm 1 5 l 0 -3 l 7 3 l -7 3 z' });
2315
2316 addMarker(id, {
2317 element: messageflowEnd,
2318 attrs: {
2319 fill: fill,
2320 stroke: stroke,
2321 strokeLinecap: 'butt'
2322 },
2323 ref: { x: 8.5, y: 5 }
2324 });
2325 }
2326
2327 if (type === 'association-start') {
2328 var associationStart = create$1('path');
2329 attr$1(associationStart, { d: 'M 11 5 L 1 10 L 11 15' });
2330
2331 addMarker(id, {
2332 element: associationStart,
2333 attrs: {
2334 fill: 'none',
2335 stroke: stroke,
2336 strokeWidth: 1.5
2337 },
2338 ref: { x: 1, y: 10 },
2339 scale: 0.5
2340 });
2341 }
2342
2343 if (type === 'association-end') {
2344 var associationEnd = create$1('path');
2345 attr$1(associationEnd, { d: 'M 1 5 L 11 10 L 1 15' });
2346
2347 addMarker(id, {
2348 element: associationEnd,
2349 attrs: {
2350 fill: 'none',
2351 stroke: stroke,
2352 strokeWidth: 1.5
2353 },
2354 ref: { x: 12, y: 10 },
2355 scale: 0.5
2356 });
2357 }
2358
2359 if (type === 'conditional-flow-marker') {
2360 var conditionalflowMarker = create$1('path');
2361 attr$1(conditionalflowMarker, { d: 'M 0 10 L 8 6 L 16 10 L 8 14 Z' });
2362
2363 addMarker(id, {
2364 element: conditionalflowMarker,
2365 attrs: {
2366 fill: fill,
2367 stroke: stroke
2368 },
2369 ref: { x: -1, y: 10 },
2370 scale: 0.5
2371 });
2372 }
2373
2374 if (type === 'conditional-default-flow-marker') {
2375 var conditionaldefaultflowMarker = create$1('path');
2376 attr$1(conditionaldefaultflowMarker, { d: 'M 6 4 L 10 16' });
2377
2378 addMarker(id, {
2379 element: conditionaldefaultflowMarker,
2380 attrs: {
2381 stroke: stroke
2382 },
2383 ref: { x: 0, y: 10 },
2384 scale: 0.5
2385 });
2386 }
2387 }
2388
2389 function drawCircle(parentGfx, width, height, offset, attrs) {
2390
2391 if (isObject(offset)) {
2392 attrs = offset;
2393 offset = 0;
2394 }
2395
2396 offset = offset || 0;
2397
2398 attrs = computeStyle(attrs, {
2399 stroke: 'black',
2400 strokeWidth: 2,
2401 fill: 'white'
2402 });
2403
2404 if (attrs.fill === 'none') {
2405 delete attrs.fillOpacity;
2406 }
2407
2408 var cx = width / 2,
2409 cy = height / 2;
2410
2411 var circle = create$1('circle');
2412 attr$1(circle, {
2413 cx: cx,
2414 cy: cy,
2415 r: Math.round((width + height) / 4 - offset)
2416 });
2417 attr$1(circle, attrs);
2418
2419 append(parentGfx, circle);
2420
2421 return circle;
2422 }
2423
2424 function drawRect(parentGfx, width, height, r, offset, attrs) {
2425
2426 if (isObject(offset)) {
2427 attrs = offset;
2428 offset = 0;
2429 }
2430
2431 offset = offset || 0;
2432
2433 attrs = computeStyle(attrs, {
2434 stroke: 'black',
2435 strokeWidth: 2,
2436 fill: 'white'
2437 });
2438
2439 var rect = create$1('rect');
2440 attr$1(rect, {
2441 x: offset,
2442 y: offset,
2443 width: width - offset * 2,
2444 height: height - offset * 2,
2445 rx: r,
2446 ry: r
2447 });
2448 attr$1(rect, attrs);
2449
2450 append(parentGfx, rect);
2451
2452 return rect;
2453 }
2454
2455 function drawDiamond(parentGfx, width, height, attrs) {
2456
2457 var x_2 = width / 2;
2458 var y_2 = height / 2;
2459
2460 var points = [{ x: x_2, y: 0 }, { x: width, y: y_2 }, { x: x_2, y: height }, { x: 0, y: y_2 }];
2461
2462 var pointsString = points.map(function(point) {
2463 return point.x + ',' + point.y;
2464 }).join(' ');
2465
2466 attrs = computeStyle(attrs, {
2467 stroke: 'black',
2468 strokeWidth: 2,
2469 fill: 'white'
2470 });
2471
2472 var polygon = create$1('polygon');
2473 attr$1(polygon, {
2474 points: pointsString
2475 });
2476 attr$1(polygon, attrs);
2477
2478 append(parentGfx, polygon);
2479
2480 return polygon;
2481 }
2482
2483 function drawLine(parentGfx, waypoints, attrs) {
2484 attrs = computeStyle(attrs, [ 'no-fill' ], {
2485 stroke: 'black',
2486 strokeWidth: 2,
2487 fill: 'none'
2488 });
2489
2490 var line = createLine(waypoints, attrs);
2491
2492 append(parentGfx, line);
2493
2494 return line;
2495 }
2496
2497 function drawPath(parentGfx, d, attrs) {
2498
2499 attrs = computeStyle(attrs, [ 'no-fill' ], {
2500 strokeWidth: 2,
2501 stroke: 'black'
2502 });
2503
2504 var path = create$1('path');
2505 attr$1(path, { d: d });
2506 attr$1(path, attrs);
2507
2508 append(parentGfx, path);
2509
2510 return path;
2511 }
2512
2513 function drawMarker(type, parentGfx, path, attrs) {
2514 return drawPath(parentGfx, path, assign({ 'data-marker': type }, attrs));
2515 }
2516
2517 function as(type) {
2518 return function(parentGfx, element) {
2519 return handlers[type](parentGfx, element);
2520 };
2521 }
2522
2523 function renderer(type) {
2524 return handlers[type];
2525 }
2526
2527 function renderEventContent(element, parentGfx) {
2528
2529 var event = getSemantic(element);
2530 var isThrowing = isThrowEvent(event);
2531
2532 if (event.eventDefinitions && event.eventDefinitions.length>1) {
2533 if (event.parallelMultiple) {
2534 return renderer('bpmn:ParallelMultipleEventDefinition')(parentGfx, element, isThrowing);
2535 }
2536 else {
2537 return renderer('bpmn:MultipleEventDefinition')(parentGfx, element, isThrowing);
2538 }
2539 }
2540
2541 if (isTypedEvent(event, 'bpmn:MessageEventDefinition')) {
2542 return renderer('bpmn:MessageEventDefinition')(parentGfx, element, isThrowing);
2543 }
2544
2545 if (isTypedEvent(event, 'bpmn:TimerEventDefinition')) {
2546 return renderer('bpmn:TimerEventDefinition')(parentGfx, element, isThrowing);
2547 }
2548
2549 if (isTypedEvent(event, 'bpmn:ConditionalEventDefinition')) {
2550 return renderer('bpmn:ConditionalEventDefinition')(parentGfx, element);
2551 }
2552
2553 if (isTypedEvent(event, 'bpmn:SignalEventDefinition')) {
2554 return renderer('bpmn:SignalEventDefinition')(parentGfx, element, isThrowing);
2555 }
2556
2557 if (isTypedEvent(event, 'bpmn:EscalationEventDefinition')) {
2558 return renderer('bpmn:EscalationEventDefinition')(parentGfx, element, isThrowing);
2559 }
2560
2561 if (isTypedEvent(event, 'bpmn:LinkEventDefinition')) {
2562 return renderer('bpmn:LinkEventDefinition')(parentGfx, element, isThrowing);
2563 }
2564
2565 if (isTypedEvent(event, 'bpmn:ErrorEventDefinition')) {
2566 return renderer('bpmn:ErrorEventDefinition')(parentGfx, element, isThrowing);
2567 }
2568
2569 if (isTypedEvent(event, 'bpmn:CancelEventDefinition')) {
2570 return renderer('bpmn:CancelEventDefinition')(parentGfx, element, isThrowing);
2571 }
2572
2573 if (isTypedEvent(event, 'bpmn:CompensateEventDefinition')) {
2574 return renderer('bpmn:CompensateEventDefinition')(parentGfx, element, isThrowing);
2575 }
2576
2577 if (isTypedEvent(event, 'bpmn:TerminateEventDefinition')) {
2578 return renderer('bpmn:TerminateEventDefinition')(parentGfx, element, isThrowing);
2579 }
2580
2581 return null;
2582 }
2583
2584 function renderLabel(parentGfx, label, options) {
2585
2586 options = assign({
2587 size: {
2588 width: 100
2589 }
2590 }, options);
2591
2592 var text = textRenderer.createText(label || '', options);
2593
2594 classes$1(text).add('djs-label');
2595
2596 append(parentGfx, text);
2597
2598 return text;
2599 }
2600
2601 function renderEmbeddedLabel(parentGfx, element, align) {
2602 var semantic = getSemantic(element);
2603
2604 return renderLabel(parentGfx, semantic.name, {
2605 box: element,
2606 align: align,
2607 padding: 5,
2608 style: {
2609 fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
2610 }
2611 });
2612 }
2613
2614 function renderExternalLabel(parentGfx, element) {
2615
2616 var box = {
2617 width: 90,
2618 height: 30,
2619 x: element.width / 2 + element.x,
2620 y: element.height / 2 + element.y
2621 };
2622
2623 return renderLabel(parentGfx, getLabel(element), {
2624 box: box,
2625 fitBox: true,
2626 style: assign(
2627 {},
2628 textRenderer.getExternalStyle(),
2629 {
2630 fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
2631 }
2632 )
2633 });
2634 }
2635
2636 function renderLaneLabel(parentGfx, text, element) {
2637 var textBox = renderLabel(parentGfx, text, {
2638 box: {
2639 height: 30,
2640 width: element.height
2641 },
2642 align: 'center-middle',
2643 style: {
2644 fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
2645 }
2646 });
2647
2648 var top = -1 * element.height;
2649
2650 transform(textBox, 0, -top, 270);
2651 }
2652
2653 function createPathFromConnection(connection) {
2654 var waypoints = connection.waypoints;
2655
2656 var pathData = 'm ' + waypoints[0].x + ',' + waypoints[0].y;
2657 for (var i = 1; i < waypoints.length; i++) {
2658 pathData += 'L' + waypoints[i].x + ',' + waypoints[i].y + ' ';
2659 }
2660 return pathData;
2661 }
2662
2663 var handlers = this.handlers = {
2664 'bpmn:Event': function(parentGfx, element, attrs) {
2665
2666 if (!('fillOpacity' in attrs)) {
2667 attrs.fillOpacity = DEFAULT_FILL_OPACITY;
2668 }
2669
2670 return drawCircle(parentGfx, element.width, element.height, attrs);
2671 },
2672 'bpmn:StartEvent': function(parentGfx, element) {
2673 var attrs = {
2674 fill: getFillColor(element, defaultFillColor),
2675 stroke: getStrokeColor(element, defaultStrokeColor)
2676 };
2677
2678 var semantic = getSemantic(element);
2679
2680 if (!semantic.isInterrupting) {
2681 attrs = {
2682 strokeDasharray: '6',
2683 strokeLinecap: 'round',
2684 fill: getFillColor(element, defaultFillColor),
2685 stroke: getStrokeColor(element, defaultStrokeColor)
2686 };
2687 }
2688
2689 var circle = renderer('bpmn:Event')(parentGfx, element, attrs);
2690
2691 renderEventContent(element, parentGfx);
2692
2693 return circle;
2694 },
2695 'bpmn:MessageEventDefinition': function(parentGfx, element, isThrowing) {
2696 var pathData = pathMap.getScaledPath('EVENT_MESSAGE', {
2697 xScaleFactor: 0.9,
2698 yScaleFactor: 0.9,
2699 containerWidth: element.width,
2700 containerHeight: element.height,
2701 position: {
2702 mx: 0.235,
2703 my: 0.315
2704 }
2705 });
2706
2707 var fill = isThrowing ? getStrokeColor(element, defaultStrokeColor) : getFillColor(element, defaultFillColor);
2708 var stroke = isThrowing ? getFillColor(element, defaultFillColor) : getStrokeColor(element, defaultStrokeColor);
2709
2710 var messagePath = drawPath(parentGfx, pathData, {
2711 strokeWidth: 1,
2712 fill: fill,
2713 stroke: stroke
2714 });
2715
2716 return messagePath;
2717 },
2718 'bpmn:TimerEventDefinition': function(parentGfx, element) {
2719 var circle = drawCircle(parentGfx, element.width, element.height, 0.2 * element.height, {
2720 strokeWidth: 2,
2721 fill: getFillColor(element, defaultFillColor),
2722 stroke: getStrokeColor(element, defaultStrokeColor)
2723 });
2724
2725 var pathData = pathMap.getScaledPath('EVENT_TIMER_WH', {
2726 xScaleFactor: 0.75,
2727 yScaleFactor: 0.75,
2728 containerWidth: element.width,
2729 containerHeight: element.height,
2730 position: {
2731 mx: 0.5,
2732 my: 0.5
2733 }
2734 });
2735
2736 drawPath(parentGfx, pathData, {
2737 strokeWidth: 2,
2738 strokeLinecap: 'square',
2739 stroke: getStrokeColor(element, defaultStrokeColor)
2740 });
2741
2742 for (var i = 0;i < 12; i++) {
2743
2744 var linePathData = pathMap.getScaledPath('EVENT_TIMER_LINE', {
2745 xScaleFactor: 0.75,
2746 yScaleFactor: 0.75,
2747 containerWidth: element.width,
2748 containerHeight: element.height,
2749 position: {
2750 mx: 0.5,
2751 my: 0.5
2752 }
2753 });
2754
2755 var width = element.width / 2;
2756 var height = element.height / 2;
2757
2758 drawPath(parentGfx, linePathData, {
2759 strokeWidth: 1,
2760 strokeLinecap: 'square',
2761 transform: 'rotate(' + (i * 30) + ',' + height + ',' + width + ')',
2762 stroke: getStrokeColor(element, defaultStrokeColor)
2763 });
2764 }
2765
2766 return circle;
2767 },
2768 'bpmn:EscalationEventDefinition': function(parentGfx, event, isThrowing) {
2769 var pathData = pathMap.getScaledPath('EVENT_ESCALATION', {
2770 xScaleFactor: 1,
2771 yScaleFactor: 1,
2772 containerWidth: event.width,
2773 containerHeight: event.height,
2774 position: {
2775 mx: 0.5,
2776 my: 0.2
2777 }
2778 });
2779
2780 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2781
2782 return drawPath(parentGfx, pathData, {
2783 strokeWidth: 1,
2784 fill: fill,
2785 stroke: getStrokeColor(event, defaultStrokeColor)
2786 });
2787 },
2788 'bpmn:ConditionalEventDefinition': function(parentGfx, event) {
2789 var pathData = pathMap.getScaledPath('EVENT_CONDITIONAL', {
2790 xScaleFactor: 1,
2791 yScaleFactor: 1,
2792 containerWidth: event.width,
2793 containerHeight: event.height,
2794 position: {
2795 mx: 0.5,
2796 my: 0.222
2797 }
2798 });
2799
2800 return drawPath(parentGfx, pathData, {
2801 strokeWidth: 1,
2802 stroke: getStrokeColor(event, defaultStrokeColor)
2803 });
2804 },
2805 'bpmn:LinkEventDefinition': function(parentGfx, event, isThrowing) {
2806 var pathData = pathMap.getScaledPath('EVENT_LINK', {
2807 xScaleFactor: 1,
2808 yScaleFactor: 1,
2809 containerWidth: event.width,
2810 containerHeight: event.height,
2811 position: {
2812 mx: 0.57,
2813 my: 0.263
2814 }
2815 });
2816
2817 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2818
2819 return drawPath(parentGfx, pathData, {
2820 strokeWidth: 1,
2821 fill: fill,
2822 stroke: getStrokeColor(event, defaultStrokeColor)
2823 });
2824 },
2825 'bpmn:ErrorEventDefinition': function(parentGfx, event, isThrowing) {
2826 var pathData = pathMap.getScaledPath('EVENT_ERROR', {
2827 xScaleFactor: 1.1,
2828 yScaleFactor: 1.1,
2829 containerWidth: event.width,
2830 containerHeight: event.height,
2831 position: {
2832 mx: 0.2,
2833 my: 0.722
2834 }
2835 });
2836
2837 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2838
2839 return drawPath(parentGfx, pathData, {
2840 strokeWidth: 1,
2841 fill: fill,
2842 stroke: getStrokeColor(event, defaultStrokeColor)
2843 });
2844 },
2845 'bpmn:CancelEventDefinition': function(parentGfx, event, isThrowing) {
2846 var pathData = pathMap.getScaledPath('EVENT_CANCEL_45', {
2847 xScaleFactor: 1.0,
2848 yScaleFactor: 1.0,
2849 containerWidth: event.width,
2850 containerHeight: event.height,
2851 position: {
2852 mx: 0.638,
2853 my: -0.055
2854 }
2855 });
2856
2857 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2858
2859 var path = drawPath(parentGfx, pathData, {
2860 strokeWidth: 1,
2861 fill: fill,
2862 stroke: getStrokeColor(event, defaultStrokeColor)
2863 });
2864
2865 rotate(path, 45);
2866
2867 return path;
2868 },
2869 'bpmn:CompensateEventDefinition': function(parentGfx, event, isThrowing) {
2870 var pathData = pathMap.getScaledPath('EVENT_COMPENSATION', {
2871 xScaleFactor: 1,
2872 yScaleFactor: 1,
2873 containerWidth: event.width,
2874 containerHeight: event.height,
2875 position: {
2876 mx: 0.22,
2877 my: 0.5
2878 }
2879 });
2880
2881 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2882
2883 return drawPath(parentGfx, pathData, {
2884 strokeWidth: 1,
2885 fill: fill,
2886 stroke: getStrokeColor(event, defaultStrokeColor)
2887 });
2888 },
2889 'bpmn:SignalEventDefinition': function(parentGfx, event, isThrowing) {
2890 var pathData = pathMap.getScaledPath('EVENT_SIGNAL', {
2891 xScaleFactor: 0.9,
2892 yScaleFactor: 0.9,
2893 containerWidth: event.width,
2894 containerHeight: event.height,
2895 position: {
2896 mx: 0.5,
2897 my: 0.2
2898 }
2899 });
2900
2901 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2902
2903 return drawPath(parentGfx, pathData, {
2904 strokeWidth: 1,
2905 fill: fill,
2906 stroke: getStrokeColor(event, defaultStrokeColor)
2907 });
2908 },
2909 'bpmn:MultipleEventDefinition': function(parentGfx, event, isThrowing) {
2910 var pathData = pathMap.getScaledPath('EVENT_MULTIPLE', {
2911 xScaleFactor: 1.1,
2912 yScaleFactor: 1.1,
2913 containerWidth: event.width,
2914 containerHeight: event.height,
2915 position: {
2916 mx: 0.222,
2917 my: 0.36
2918 }
2919 });
2920
2921 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2922
2923 return drawPath(parentGfx, pathData, {
2924 strokeWidth: 1,
2925 fill: fill
2926 });
2927 },
2928 'bpmn:ParallelMultipleEventDefinition': function(parentGfx, event) {
2929 var pathData = pathMap.getScaledPath('EVENT_PARALLEL_MULTIPLE', {
2930 xScaleFactor: 1.2,
2931 yScaleFactor: 1.2,
2932 containerWidth: event.width,
2933 containerHeight: event.height,
2934 position: {
2935 mx: 0.458,
2936 my: 0.194
2937 }
2938 });
2939
2940 return drawPath(parentGfx, pathData, {
2941 strokeWidth: 1,
2942 fill: getStrokeColor(event, defaultStrokeColor),
2943 stroke: getStrokeColor(event, defaultStrokeColor)
2944 });
2945 },
2946 'bpmn:EndEvent': function(parentGfx, element) {
2947 var circle = renderer('bpmn:Event')(parentGfx, element, {
2948 strokeWidth: 4,
2949 fill: getFillColor(element, defaultFillColor),
2950 stroke: getStrokeColor(element, defaultStrokeColor)
2951 });
2952
2953 renderEventContent(element, parentGfx);
2954
2955 return circle;
2956 },
2957 'bpmn:TerminateEventDefinition': function(parentGfx, element) {
2958 var circle = drawCircle(parentGfx, element.width, element.height, 8, {
2959 strokeWidth: 4,
2960 fill: getStrokeColor(element, defaultStrokeColor),
2961 stroke: getStrokeColor(element, defaultStrokeColor)
2962 });
2963
2964 return circle;
2965 },
2966 'bpmn:IntermediateEvent': function(parentGfx, element) {
2967 var outer = renderer('bpmn:Event')(parentGfx, element, {
2968 strokeWidth: 1,
2969 fill: getFillColor(element, defaultFillColor),
2970 stroke: getStrokeColor(element, defaultStrokeColor)
2971 });
2972
2973 /* inner */
2974 drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, {
2975 strokeWidth: 1,
2976 fill: getFillColor(element, 'none'),
2977 stroke: getStrokeColor(element, defaultStrokeColor)
2978 });
2979
2980 renderEventContent(element, parentGfx);
2981
2982 return outer;
2983 },
2984 'bpmn:IntermediateCatchEvent': as('bpmn:IntermediateEvent'),
2985 'bpmn:IntermediateThrowEvent': as('bpmn:IntermediateEvent'),
2986
2987 'bpmn:Activity': function(parentGfx, element, attrs) {
2988
2989 attrs = attrs || {};
2990
2991 if (!('fillOpacity' in attrs)) {
2992 attrs.fillOpacity = DEFAULT_FILL_OPACITY;
2993 }
2994
2995 return drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, attrs);
2996 },
2997
2998 'bpmn:Task': function(parentGfx, element) {
2999 var attrs = {
3000 fill: getFillColor(element, defaultFillColor),
3001 stroke: getStrokeColor(element, defaultStrokeColor)
3002 };
3003
3004 var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
3005
3006 renderEmbeddedLabel(parentGfx, element, 'center-middle');
3007 attachTaskMarkers(parentGfx, element);
3008
3009 return rect;
3010 },
3011 'bpmn:ServiceTask': function(parentGfx, element) {
3012 var task = renderer('bpmn:Task')(parentGfx, element);
3013
3014 var pathDataBG = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
3015 abspos: {
3016 x: 12,
3017 y: 18
3018 }
3019 });
3020
3021 /* service bg */ drawPath(parentGfx, pathDataBG, {
3022 strokeWidth: 1,
3023 fill: getFillColor(element, defaultFillColor),
3024 stroke: getStrokeColor(element, defaultStrokeColor)
3025 });
3026
3027 var fillPathData = pathMap.getScaledPath('TASK_TYPE_SERVICE_FILL', {
3028 abspos: {
3029 x: 17.2,
3030 y: 18
3031 }
3032 });
3033
3034 /* service fill */ drawPath(parentGfx, fillPathData, {
3035 strokeWidth: 0,
3036 fill: getFillColor(element, defaultFillColor)
3037 });
3038
3039 var pathData = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
3040 abspos: {
3041 x: 17,
3042 y: 22
3043 }
3044 });
3045
3046 /* service */ drawPath(parentGfx, pathData, {
3047 strokeWidth: 1,
3048 fill: getFillColor(element, defaultFillColor),
3049 stroke: getStrokeColor(element, defaultStrokeColor)
3050 });
3051
3052 return task;
3053 },
3054 'bpmn:UserTask': function(parentGfx, element) {
3055 var task = renderer('bpmn:Task')(parentGfx, element);
3056
3057 var x = 15;
3058 var y = 12;
3059
3060 var pathData = pathMap.getScaledPath('TASK_TYPE_USER_1', {
3061 abspos: {
3062 x: x,
3063 y: y
3064 }
3065 });
3066
3067 /* user path */ drawPath(parentGfx, pathData, {
3068 strokeWidth: 0.5,
3069 fill: getFillColor(element, defaultFillColor),
3070 stroke: getStrokeColor(element, defaultStrokeColor)
3071 });
3072
3073 var pathData2 = pathMap.getScaledPath('TASK_TYPE_USER_2', {
3074 abspos: {
3075 x: x,
3076 y: y
3077 }
3078 });
3079
3080 /* user2 path */ drawPath(parentGfx, pathData2, {
3081 strokeWidth: 0.5,
3082 fill: getFillColor(element, defaultFillColor),
3083 stroke: getStrokeColor(element, defaultStrokeColor)
3084 });
3085
3086 var pathData3 = pathMap.getScaledPath('TASK_TYPE_USER_3', {
3087 abspos: {
3088 x: x,
3089 y: y
3090 }
3091 });
3092
3093 /* user3 path */ drawPath(parentGfx, pathData3, {
3094 strokeWidth: 0.5,
3095 fill: getStrokeColor(element, defaultStrokeColor),
3096 stroke: getStrokeColor(element, defaultStrokeColor)
3097 });
3098
3099 return task;
3100 },
3101 'bpmn:ManualTask': function(parentGfx, element) {
3102 var task = renderer('bpmn:Task')(parentGfx, element);
3103
3104 var pathData = pathMap.getScaledPath('TASK_TYPE_MANUAL', {
3105 abspos: {
3106 x: 17,
3107 y: 15
3108 }
3109 });
3110
3111 /* manual path */ drawPath(parentGfx, pathData, {
3112 strokeWidth: 0.5, // 0.25,
3113 fill: getFillColor(element, defaultFillColor),
3114 stroke: getStrokeColor(element, defaultStrokeColor)
3115 });
3116
3117 return task;
3118 },
3119 'bpmn:SendTask': function(parentGfx, element) {
3120 var task = renderer('bpmn:Task')(parentGfx, element);
3121
3122 var pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
3123 xScaleFactor: 1,
3124 yScaleFactor: 1,
3125 containerWidth: 21,
3126 containerHeight: 14,
3127 position: {
3128 mx: 0.285,
3129 my: 0.357
3130 }
3131 });
3132
3133 /* send path */ drawPath(parentGfx, pathData, {
3134 strokeWidth: 1,
3135 fill: getStrokeColor(element, defaultStrokeColor),
3136 stroke: getFillColor(element, defaultFillColor)
3137 });
3138
3139 return task;
3140 },
3141 'bpmn:ReceiveTask' : function(parentGfx, element) {
3142 var semantic = getSemantic(element);
3143
3144 var task = renderer('bpmn:Task')(parentGfx, element);
3145 var pathData;
3146
3147 if (semantic.instantiate) {
3148 drawCircle(parentGfx, 28, 28, 20 * 0.22, { strokeWidth: 1 });
3149
3150 pathData = pathMap.getScaledPath('TASK_TYPE_INSTANTIATING_SEND', {
3151 abspos: {
3152 x: 7.77,
3153 y: 9.52
3154 }
3155 });
3156 } else {
3157
3158 pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
3159 xScaleFactor: 0.9,
3160 yScaleFactor: 0.9,
3161 containerWidth: 21,
3162 containerHeight: 14,
3163 position: {
3164 mx: 0.3,
3165 my: 0.4
3166 }
3167 });
3168 }
3169
3170 /* receive path */ drawPath(parentGfx, pathData, {
3171 strokeWidth: 1,
3172 fill: getFillColor(element, defaultFillColor),
3173 stroke: getStrokeColor(element, defaultStrokeColor)
3174 });
3175
3176 return task;
3177 },
3178 'bpmn:ScriptTask': function(parentGfx, element) {
3179 var task = renderer('bpmn:Task')(parentGfx, element);
3180
3181 var pathData = pathMap.getScaledPath('TASK_TYPE_SCRIPT', {
3182 abspos: {
3183 x: 15,
3184 y: 20
3185 }
3186 });
3187
3188 /* script path */ drawPath(parentGfx, pathData, {
3189 strokeWidth: 1,
3190 stroke: getStrokeColor(element, defaultStrokeColor)
3191 });
3192
3193 return task;
3194 },
3195 'bpmn:BusinessRuleTask': function(parentGfx, element) {
3196 var task = renderer('bpmn:Task')(parentGfx, element);
3197
3198 var headerPathData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_HEADER', {
3199 abspos: {
3200 x: 8,
3201 y: 8
3202 }
3203 });
3204
3205 var businessHeaderPath = drawPath(parentGfx, headerPathData);
3206 attr$1(businessHeaderPath, {
3207 strokeWidth: 1,
3208 fill: getFillColor(element, '#aaaaaa'),
3209 stroke: getStrokeColor(element, defaultStrokeColor)
3210 });
3211
3212 var headerData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_MAIN', {
3213 abspos: {
3214 x: 8,
3215 y: 8
3216 }
3217 });
3218
3219 var businessPath = drawPath(parentGfx, headerData);
3220 attr$1(businessPath, {
3221 strokeWidth: 1,
3222 stroke: getStrokeColor(element, defaultStrokeColor)
3223 });
3224
3225 return task;
3226 },
3227 'bpmn:SubProcess': function(parentGfx, element, attrs) {
3228 attrs = assign({
3229 fill: getFillColor(element, defaultFillColor),
3230 stroke: getStrokeColor(element, defaultStrokeColor)
3231 }, attrs);
3232
3233 var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
3234
3235 var expanded = isExpanded(element);
3236
3237 if (isEventSubProcess(element)) {
3238 attr$1(rect, {
3239 strokeDasharray: '1,2'
3240 });
3241 }
3242
3243 renderEmbeddedLabel(parentGfx, element, expanded ? 'center-top' : 'center-middle');
3244
3245 if (expanded) {
3246 attachTaskMarkers(parentGfx, element);
3247 } else {
3248 attachTaskMarkers(parentGfx, element, ['SubProcessMarker']);
3249 }
3250
3251 return rect;
3252 },
3253 'bpmn:AdHocSubProcess': function(parentGfx, element) {
3254 return renderer('bpmn:SubProcess')(parentGfx, element);
3255 },
3256 'bpmn:Transaction': function(parentGfx, element) {
3257 var outer = renderer('bpmn:SubProcess')(parentGfx, element);
3258
3259 var innerAttrs = styles.style([ 'no-fill', 'no-events' ], {
3260 stroke: getStrokeColor(element, defaultStrokeColor)
3261 });
3262
3263 /* inner path */ drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS - 2, INNER_OUTER_DIST, innerAttrs);
3264
3265 return outer;
3266 },
3267 'bpmn:CallActivity': function(parentGfx, element) {
3268 return renderer('bpmn:SubProcess')(parentGfx, element, {
3269 strokeWidth: 5
3270 });
3271 },
3272 'bpmn:Participant': function(parentGfx, element) {
3273
3274 var attrs = {
3275 fillOpacity: DEFAULT_FILL_OPACITY,
3276 fill: getFillColor(element, defaultFillColor),
3277 stroke: getStrokeColor(element, defaultStrokeColor)
3278 };
3279
3280 var lane = renderer('bpmn:Lane')(parentGfx, element, attrs);
3281
3282 var expandedPool = isExpanded(element);
3283
3284 if (expandedPool) {
3285 drawLine(parentGfx, [
3286 { x: 30, y: 0 },
3287 { x: 30, y: element.height }
3288 ], {
3289 stroke: getStrokeColor(element, defaultStrokeColor)
3290 });
3291 var text = getSemantic(element).name;
3292 renderLaneLabel(parentGfx, text, element);
3293 } else {
3294
3295 // Collapsed pool draw text inline
3296 var text2 = getSemantic(element).name;
3297 renderLabel(parentGfx, text2, {
3298 box: element, align: 'center-middle',
3299 style: {
3300 fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
3301 }
3302 });
3303 }
3304
3305 var participantMultiplicity = !!(getSemantic(element).participantMultiplicity);
3306
3307 if (participantMultiplicity) {
3308 renderer('ParticipantMultiplicityMarker')(parentGfx, element);
3309 }
3310
3311 return lane;
3312 },
3313 'bpmn:Lane': function(parentGfx, element, attrs) {
3314 var rect = drawRect(parentGfx, element.width, element.height, 0, assign({
3315 fill: getFillColor(element, defaultFillColor),
3316 fillOpacity: HIGH_FILL_OPACITY,
3317 stroke: getStrokeColor(element, defaultStrokeColor)
3318 }, attrs));
3319
3320 var semantic = getSemantic(element);
3321
3322 if (semantic.$type === 'bpmn:Lane') {
3323 var text = semantic.name;
3324 renderLaneLabel(parentGfx, text, element);
3325 }
3326
3327 return rect;
3328 },
3329 'bpmn:InclusiveGateway': function(parentGfx, element) {
3330 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3331
3332 /* circle path */
3333 drawCircle(parentGfx, element.width, element.height, element.height * 0.24, {
3334 strokeWidth: 2.5,
3335 fill: getFillColor(element, defaultFillColor),
3336 stroke: getStrokeColor(element, defaultStrokeColor)
3337 });
3338
3339 return diamond;
3340 },
3341 'bpmn:ExclusiveGateway': function(parentGfx, element) {
3342 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3343
3344 var pathData = pathMap.getScaledPath('GATEWAY_EXCLUSIVE', {
3345 xScaleFactor: 0.4,
3346 yScaleFactor: 0.4,
3347 containerWidth: element.width,
3348 containerHeight: element.height,
3349 position: {
3350 mx: 0.32,
3351 my: 0.3
3352 }
3353 });
3354
3355 if ((getDi(element).isMarkerVisible)) {
3356 drawPath(parentGfx, pathData, {
3357 strokeWidth: 1,
3358 fill: getStrokeColor(element, defaultStrokeColor),
3359 stroke: getStrokeColor(element, defaultStrokeColor)
3360 });
3361 }
3362
3363 return diamond;
3364 },
3365 'bpmn:ComplexGateway': function(parentGfx, element) {
3366 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3367
3368 var pathData = pathMap.getScaledPath('GATEWAY_COMPLEX', {
3369 xScaleFactor: 0.5,
3370 yScaleFactor:0.5,
3371 containerWidth: element.width,
3372 containerHeight: element.height,
3373 position: {
3374 mx: 0.46,
3375 my: 0.26
3376 }
3377 });
3378
3379 /* complex path */ drawPath(parentGfx, pathData, {
3380 strokeWidth: 1,
3381 fill: getStrokeColor(element, defaultStrokeColor),
3382 stroke: getStrokeColor(element, defaultStrokeColor)
3383 });
3384
3385 return diamond;
3386 },
3387 'bpmn:ParallelGateway': function(parentGfx, element) {
3388 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3389
3390 var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
3391 xScaleFactor: 0.6,
3392 yScaleFactor:0.6,
3393 containerWidth: element.width,
3394 containerHeight: element.height,
3395 position: {
3396 mx: 0.46,
3397 my: 0.2
3398 }
3399 });
3400
3401 /* parallel path */ drawPath(parentGfx, pathData, {
3402 strokeWidth: 1,
3403 fill: getStrokeColor(element, defaultStrokeColor),
3404 stroke: getStrokeColor(element, defaultStrokeColor)
3405 });
3406
3407 return diamond;
3408 },
3409 'bpmn:EventBasedGateway': function(parentGfx, element) {
3410
3411 var semantic = getSemantic(element);
3412
3413 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3414
3415 /* outer circle path */ drawCircle(parentGfx, element.width, element.height, element.height * 0.20, {
3416 strokeWidth: 1,
3417 fill: 'none',
3418 stroke: getStrokeColor(element, defaultStrokeColor)
3419 });
3420
3421 var type = semantic.eventGatewayType;
3422 var instantiate = !!semantic.instantiate;
3423
3424 function drawEvent() {
3425
3426 var pathData = pathMap.getScaledPath('GATEWAY_EVENT_BASED', {
3427 xScaleFactor: 0.18,
3428 yScaleFactor: 0.18,
3429 containerWidth: element.width,
3430 containerHeight: element.height,
3431 position: {
3432 mx: 0.36,
3433 my: 0.44
3434 }
3435 });
3436
3437 var attrs = {
3438 strokeWidth: 2,
3439 fill: getFillColor(element, 'none'),
3440 stroke: getStrokeColor(element, defaultStrokeColor)
3441 };
3442
3443 /* event path */ drawPath(parentGfx, pathData, attrs);
3444 }
3445
3446 if (type === 'Parallel') {
3447
3448 var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
3449 xScaleFactor: 0.4,
3450 yScaleFactor:0.4,
3451 containerWidth: element.width,
3452 containerHeight: element.height,
3453 position: {
3454 mx: 0.474,
3455 my: 0.296
3456 }
3457 });
3458
3459 var parallelPath = drawPath(parentGfx, pathData);
3460 attr$1(parallelPath, {
3461 strokeWidth: 1,
3462 fill: 'none'
3463 });
3464 } else if (type === 'Exclusive') {
3465
3466 if (!instantiate) {
3467 var innerCircle = drawCircle(parentGfx, element.width, element.height, element.height * 0.26);
3468 attr$1(innerCircle, {
3469 strokeWidth: 1,
3470 fill: 'none',
3471 stroke: getStrokeColor(element, defaultStrokeColor)
3472 });
3473 }
3474
3475 drawEvent();
3476 }
3477
3478
3479 return diamond;
3480 },
3481 'bpmn:Gateway': function(parentGfx, element) {
3482 var attrs = {
3483 fill: getFillColor(element, defaultFillColor),
3484 fillOpacity: DEFAULT_FILL_OPACITY,
3485 stroke: getStrokeColor(element, defaultStrokeColor)
3486 };
3487
3488 return drawDiamond(parentGfx, element.width, element.height, attrs);
3489 },
3490 'bpmn:SequenceFlow': function(parentGfx, element) {
3491 var pathData = createPathFromConnection(element);
3492
3493 var fill = getFillColor(element, defaultFillColor),
3494 stroke = getStrokeColor(element, defaultStrokeColor);
3495
3496 var attrs = {
3497 strokeLinejoin: 'round',
3498 markerEnd: marker('sequenceflow-end', fill, stroke),
3499 stroke: getStrokeColor(element, defaultStrokeColor)
3500 };
3501
3502 var path = drawPath(parentGfx, pathData, attrs);
3503
3504 var sequenceFlow = getSemantic(element);
3505
3506 var source;
3507
3508 if (element.source) {
3509 source = element.source.businessObject;
3510
3511 // conditional flow marker
3512 if (sequenceFlow.conditionExpression && source.$instanceOf('bpmn:Activity')) {
3513 attr$1(path, {
3514 markerStart: marker('conditional-flow-marker', fill, stroke)
3515 });
3516 }
3517
3518 // default marker
3519 if (source.default && (source.$instanceOf('bpmn:Gateway') || source.$instanceOf('bpmn:Activity')) &&
3520 source.default === sequenceFlow) {
3521 attr$1(path, {
3522 markerStart: marker('conditional-default-flow-marker', fill, stroke)
3523 });
3524 }
3525 }
3526
3527 return path;
3528 },
3529 'bpmn:Association': function(parentGfx, element, attrs) {
3530
3531 var semantic = getSemantic(element);
3532
3533 var fill = getFillColor(element, defaultFillColor),
3534 stroke = getStrokeColor(element, defaultStrokeColor);
3535
3536 attrs = assign({
3537 strokeDasharray: '0.5, 5',
3538 strokeLinecap: 'round',
3539 strokeLinejoin: 'round',
3540 stroke: getStrokeColor(element, defaultStrokeColor)
3541 }, attrs || {});
3542
3543 if (semantic.associationDirection === 'One' ||
3544 semantic.associationDirection === 'Both') {
3545 attrs.markerEnd = marker('association-end', fill, stroke);
3546 }
3547
3548 if (semantic.associationDirection === 'Both') {
3549 attrs.markerStart = marker('association-start', fill, stroke);
3550 }
3551
3552 return drawLine(parentGfx, element.waypoints, attrs);
3553 },
3554 'bpmn:DataInputAssociation': function(parentGfx, element) {
3555 var fill = getFillColor(element, defaultFillColor),
3556 stroke = getStrokeColor(element, defaultStrokeColor);
3557
3558 return renderer('bpmn:Association')(parentGfx, element, {
3559 markerEnd: marker('association-end', fill, stroke)
3560 });
3561 },
3562 'bpmn:DataOutputAssociation': function(parentGfx, element) {
3563 var fill = getFillColor(element, defaultFillColor),
3564 stroke = getStrokeColor(element, defaultStrokeColor);
3565
3566 return renderer('bpmn:Association')(parentGfx, element, {
3567 markerEnd: marker('association-end', fill, stroke)
3568 });
3569 },
3570 'bpmn:MessageFlow': function(parentGfx, element) {
3571
3572 var semantic = getSemantic(element),
3573 di = getDi(element);
3574
3575 var fill = getFillColor(element, defaultFillColor),
3576 stroke = getStrokeColor(element, defaultStrokeColor);
3577
3578 var pathData = createPathFromConnection(element);
3579
3580 var attrs = {
3581 markerEnd: marker('messageflow-end', fill, stroke),
3582 markerStart: marker('messageflow-start', fill, stroke),
3583 strokeDasharray: '10, 12',
3584 strokeLinecap: 'round',
3585 strokeLinejoin: 'round',
3586 strokeWidth: '1.5px',
3587 stroke: getStrokeColor(element, defaultStrokeColor)
3588 };
3589
3590 var path = drawPath(parentGfx, pathData, attrs);
3591
3592 if (semantic.messageRef) {
3593 var midPoint = path.getPointAtLength(path.getTotalLength() / 2);
3594
3595 var markerPathData = pathMap.getScaledPath('MESSAGE_FLOW_MARKER', {
3596 abspos: {
3597 x: midPoint.x,
3598 y: midPoint.y
3599 }
3600 });
3601
3602 var messageAttrs = { strokeWidth: 1 };
3603
3604 if (di.messageVisibleKind === 'initiating') {
3605 messageAttrs.fill = 'white';
3606 messageAttrs.stroke = 'black';
3607 } else {
3608 messageAttrs.fill = '#888';
3609 messageAttrs.stroke = 'white';
3610 }
3611
3612 var message = drawPath(parentGfx, markerPathData, messageAttrs);
3613
3614 var labelText = semantic.messageRef.name;
3615 var label = renderLabel(parentGfx, labelText, {
3616 align: 'center-top',
3617 fitBox: true,
3618 style: {
3619 fill: getStrokeColor(element, defaultLabelColor)
3620 }
3621 });
3622
3623 var messageBounds = message.getBBox(),
3624 labelBounds = label.getBBox();
3625
3626 var translateX = midPoint.x - labelBounds.width / 2,
3627 translateY = midPoint.y + messageBounds.height / 2 + ELEMENT_LABEL_DISTANCE;
3628
3629 transform(label, translateX, translateY, 0);
3630
3631 }
3632
3633 return path;
3634 },
3635 'bpmn:DataObject': function(parentGfx, element) {
3636 var pathData = pathMap.getScaledPath('DATA_OBJECT_PATH', {
3637 xScaleFactor: 1,
3638 yScaleFactor: 1,
3639 containerWidth: element.width,
3640 containerHeight: element.height,
3641 position: {
3642 mx: 0.474,
3643 my: 0.296
3644 }
3645 });
3646
3647 var elementObject = drawPath(parentGfx, pathData, {
3648 fill: getFillColor(element, defaultFillColor),
3649 fillOpacity: DEFAULT_FILL_OPACITY,
3650 stroke: getStrokeColor(element, defaultStrokeColor)
3651 });
3652
3653 var semantic = getSemantic(element);
3654
3655 if (isCollection(semantic)) {
3656 renderDataItemCollection(parentGfx, element);
3657 }
3658
3659 return elementObject;
3660 },
3661 'bpmn:DataObjectReference': as('bpmn:DataObject'),
3662 'bpmn:DataInput': function(parentGfx, element) {
3663
3664 var arrowPathData = pathMap.getRawPath('DATA_ARROW');
3665
3666 // page
3667 var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
3668
3669 /* input arrow path */ drawPath(parentGfx, arrowPathData, { strokeWidth: 1 });
3670
3671 return elementObject;
3672 },
3673 'bpmn:DataOutput': function(parentGfx, element) {
3674 var arrowPathData = pathMap.getRawPath('DATA_ARROW');
3675
3676 // page
3677 var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
3678
3679 /* output arrow path */ drawPath(parentGfx, arrowPathData, {
3680 strokeWidth: 1,
3681 fill: 'black'
3682 });
3683
3684 return elementObject;
3685 },
3686 'bpmn:DataStoreReference': function(parentGfx, element) {
3687 var DATA_STORE_PATH = pathMap.getScaledPath('DATA_STORE', {
3688 xScaleFactor: 1,
3689 yScaleFactor: 1,
3690 containerWidth: element.width,
3691 containerHeight: element.height,
3692 position: {
3693 mx: 0,
3694 my: 0.133
3695 }
3696 });
3697
3698 var elementStore = drawPath(parentGfx, DATA_STORE_PATH, {
3699 strokeWidth: 2,
3700 fill: getFillColor(element, defaultFillColor),
3701 fillOpacity: DEFAULT_FILL_OPACITY,
3702 stroke: getStrokeColor(element, defaultStrokeColor)
3703 });
3704
3705 return elementStore;
3706 },
3707 'bpmn:BoundaryEvent': function(parentGfx, element) {
3708
3709 var semantic = getSemantic(element),
3710 cancel = semantic.cancelActivity;
3711
3712 var attrs = {
3713 strokeWidth: 1,
3714 fill: getFillColor(element, defaultFillColor),
3715 stroke: getStrokeColor(element, defaultStrokeColor)
3716 };
3717
3718 if (!cancel) {
3719 attrs.strokeDasharray = '6';
3720 attrs.strokeLinecap = 'round';
3721 }
3722
3723 // apply fillOpacity
3724 var outerAttrs = assign({}, attrs, {
3725 fillOpacity: 1
3726 });
3727
3728 // apply no-fill
3729 var innerAttrs = assign({}, attrs, {
3730 fill: 'none'
3731 });
3732
3733 var outer = renderer('bpmn:Event')(parentGfx, element, outerAttrs);
3734
3735 /* inner path */ drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, innerAttrs);
3736
3737 renderEventContent(element, parentGfx);
3738
3739 return outer;
3740 },
3741 'bpmn:Group': function(parentGfx, element) {
3742
3743 var group = drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, {
3744 stroke: getStrokeColor(element, defaultStrokeColor),
3745 strokeWidth: 1,
3746 strokeDasharray: '8,3,1,3',
3747 fill: 'none',
3748 pointerEvents: 'none'
3749 });
3750
3751 return group;
3752 },
3753 'label': function(parentGfx, element) {
3754 return renderExternalLabel(parentGfx, element);
3755 },
3756 'bpmn:TextAnnotation': function(parentGfx, element) {
3757 var style = {
3758 'fill': 'none',
3759 'stroke': 'none'
3760 };
3761
3762 var textElement = drawRect(parentGfx, element.width, element.height, 0, 0, style);
3763
3764 var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', {
3765 xScaleFactor: 1,
3766 yScaleFactor: 1,
3767 containerWidth: element.width,
3768 containerHeight: element.height,
3769 position: {
3770 mx: 0.0,
3771 my: 0.0
3772 }
3773 });
3774
3775 drawPath(parentGfx, textPathData, {
3776 stroke: getStrokeColor(element, defaultStrokeColor)
3777 });
3778
3779 var text = getSemantic(element).text || '';
3780 renderLabel(parentGfx, text, {
3781 box: element,
3782 align: 'left-top',
3783 padding: 5,
3784 style: {
3785 fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
3786 }
3787 });
3788
3789 return textElement;
3790 },
3791 'ParticipantMultiplicityMarker': function(parentGfx, element) {
3792 var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
3793 xScaleFactor: 1,
3794 yScaleFactor: 1,
3795 containerWidth: element.width,
3796 containerHeight: element.height,
3797 position: {
3798 mx: ((element.width / 2) / element.width),
3799 my: (element.height - 15) / element.height
3800 }
3801 });
3802
3803 drawMarker('participant-multiplicity', parentGfx, markerPath, {
3804 strokeWidth: 2,
3805 fill: getFillColor(element, defaultFillColor),
3806 stroke: getStrokeColor(element, defaultStrokeColor)
3807 });
3808 },
3809 'SubProcessMarker': function(parentGfx, element) {
3810 var markerRect = drawRect(parentGfx, 14, 14, 0, {
3811 strokeWidth: 1,
3812 fill: getFillColor(element, defaultFillColor),
3813 stroke: getStrokeColor(element, defaultStrokeColor)
3814 });
3815
3816 // Process marker is placed in the middle of the box
3817 // therefore fixed values can be used here
3818 translate$1(markerRect, element.width / 2 - 7.5, element.height - 20);
3819
3820 var markerPath = pathMap.getScaledPath('MARKER_SUB_PROCESS', {
3821 xScaleFactor: 1.5,
3822 yScaleFactor: 1.5,
3823 containerWidth: element.width,
3824 containerHeight: element.height,
3825 position: {
3826 mx: (element.width / 2 - 7.5) / element.width,
3827 my: (element.height - 20) / element.height
3828 }
3829 });
3830
3831 drawMarker('sub-process', parentGfx, markerPath, {
3832 fill: getFillColor(element, defaultFillColor),
3833 stroke: getStrokeColor(element, defaultStrokeColor)
3834 });
3835 },
3836 'ParallelMarker': function(parentGfx, element, position) {
3837 var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
3838 xScaleFactor: 1,
3839 yScaleFactor: 1,
3840 containerWidth: element.width,
3841 containerHeight: element.height,
3842 position: {
3843 mx: ((element.width / 2 + position.parallel) / element.width),
3844 my: (element.height - 20) / element.height
3845 }
3846 });
3847
3848 drawMarker('parallel', parentGfx, markerPath, {
3849 fill: getFillColor(element, defaultFillColor),
3850 stroke: getStrokeColor(element, defaultStrokeColor)
3851 });
3852 },
3853 'SequentialMarker': function(parentGfx, element, position) {
3854 var markerPath = pathMap.getScaledPath('MARKER_SEQUENTIAL', {
3855 xScaleFactor: 1,
3856 yScaleFactor: 1,
3857 containerWidth: element.width,
3858 containerHeight: element.height,
3859 position: {
3860 mx: ((element.width / 2 + position.seq) / element.width),
3861 my: (element.height - 19) / element.height
3862 }
3863 });
3864
3865 drawMarker('sequential', parentGfx, markerPath, {
3866 fill: getFillColor(element, defaultFillColor),
3867 stroke: getStrokeColor(element, defaultStrokeColor)
3868 });
3869 },
3870 'CompensationMarker': function(parentGfx, element, position) {
3871 var markerMath = pathMap.getScaledPath('MARKER_COMPENSATION', {
3872 xScaleFactor: 1,
3873 yScaleFactor: 1,
3874 containerWidth: element.width,
3875 containerHeight: element.height,
3876 position: {
3877 mx: ((element.width / 2 + position.compensation) / element.width),
3878 my: (element.height - 13) / element.height
3879 }
3880 });
3881
3882 drawMarker('compensation', parentGfx, markerMath, {
3883 strokeWidth: 1,
3884 fill: getFillColor(element, defaultFillColor),
3885 stroke: getStrokeColor(element, defaultStrokeColor)
3886 });
3887 },
3888 'LoopMarker': function(parentGfx, element, position) {
3889 var markerPath = pathMap.getScaledPath('MARKER_LOOP', {
3890 xScaleFactor: 1,
3891 yScaleFactor: 1,
3892 containerWidth: element.width,
3893 containerHeight: element.height,
3894 position: {
3895 mx: ((element.width / 2 + position.loop) / element.width),
3896 my: (element.height - 7) / element.height
3897 }
3898 });
3899
3900 drawMarker('loop', parentGfx, markerPath, {
3901 strokeWidth: 1,
3902 fill: getFillColor(element, defaultFillColor),
3903 stroke: getStrokeColor(element, defaultStrokeColor),
3904 strokeLinecap: 'round',
3905 strokeMiterlimit: 0.5
3906 });
3907 },
3908 'AdhocMarker': function(parentGfx, element, position) {
3909 var markerPath = pathMap.getScaledPath('MARKER_ADHOC', {
3910 xScaleFactor: 1,
3911 yScaleFactor: 1,
3912 containerWidth: element.width,
3913 containerHeight: element.height,
3914 position: {
3915 mx: ((element.width / 2 + position.adhoc) / element.width),
3916 my: (element.height - 15) / element.height
3917 }
3918 });
3919
3920 drawMarker('adhoc', parentGfx, markerPath, {
3921 strokeWidth: 1,
3922 fill: getStrokeColor(element, defaultStrokeColor),
3923 stroke: getStrokeColor(element, defaultStrokeColor)
3924 });
3925 }
3926 };
3927
3928 function attachTaskMarkers(parentGfx, element, taskMarkers) {
3929 var obj = getSemantic(element);
3930
3931 var subprocess = taskMarkers && taskMarkers.indexOf('SubProcessMarker') !== -1;
3932 var position;
3933
3934 if (subprocess) {
3935 position = {
3936 seq: -21,
3937 parallel: -22,
3938 compensation: -42,
3939 loop: -18,
3940 adhoc: 10
3941 };
3942 } else {
3943 position = {
3944 seq: -3,
3945 parallel: -6,
3946 compensation: -27,
3947 loop: 0,
3948 adhoc: 10
3949 };
3950 }
3951
3952 forEach(taskMarkers, function(marker) {
3953 renderer(marker)(parentGfx, element, position);
3954 });
3955
3956 if (obj.isForCompensation) {
3957 renderer('CompensationMarker')(parentGfx, element, position);
3958 }
3959
3960 if (obj.$type === 'bpmn:AdHocSubProcess') {
3961 renderer('AdhocMarker')(parentGfx, element, position);
3962 }
3963
3964 var loopCharacteristics = obj.loopCharacteristics,
3965 isSequential = loopCharacteristics && loopCharacteristics.isSequential;
3966
3967 if (loopCharacteristics) {
3968
3969 if (isSequential === undefined) {
3970 renderer('LoopMarker')(parentGfx, element, position);
3971 }
3972
3973 if (isSequential === false) {
3974 renderer('ParallelMarker')(parentGfx, element, position);
3975 }
3976
3977 if (isSequential === true) {
3978 renderer('SequentialMarker')(parentGfx, element, position);
3979 }
3980 }
3981 }
3982
3983 function renderDataItemCollection(parentGfx, element) {
3984
3985 var yPosition = (element.height - 18) / element.height;
3986
3987 var pathData = pathMap.getScaledPath('DATA_OBJECT_COLLECTION_PATH', {
3988 xScaleFactor: 1,
3989 yScaleFactor: 1,
3990 containerWidth: element.width,
3991 containerHeight: element.height,
3992 position: {
3993 mx: 0.33,
3994 my: yPosition
3995 }
3996 });
3997
3998 /* collection path */ drawPath(parentGfx, pathData, {
3999 strokeWidth: 2
4000 });
4001 }
4002
4003
4004 // extension API, use at your own risk
4005 this._drawPath = drawPath;
4006
4007 }
4008
4009
4010 inherits$1(BpmnRenderer, BaseRenderer);
4011
4012 BpmnRenderer.$inject = [
4013 'config.bpmnRenderer',
4014 'eventBus',
4015 'styles',
4016 'pathMap',
4017 'canvas',
4018 'textRenderer'
4019 ];
4020
4021
4022 BpmnRenderer.prototype.canRender = function(element) {
4023 return is$1(element, 'bpmn:BaseElement');
4024 };
4025
4026 BpmnRenderer.prototype.drawShape = function(parentGfx, element) {
4027 var type = element.type;
4028 var h = this.handlers[type];
4029
4030 /* jshint -W040 */
4031 return h(parentGfx, element);
4032 };
4033
4034 BpmnRenderer.prototype.drawConnection = function(parentGfx, element) {
4035 var type = element.type;
4036 var h = this.handlers[type];
4037
4038 /* jshint -W040 */
4039 return h(parentGfx, element);
4040 };
4041
4042 BpmnRenderer.prototype.getShapePath = function(element) {
4043
4044 if (is$1(element, 'bpmn:Event')) {
4045 return getCirclePath(element);
4046 }
4047
4048 if (is$1(element, 'bpmn:Activity')) {
4049 return getRoundRectPath(element, TASK_BORDER_RADIUS);
4050 }
4051
4052 if (is$1(element, 'bpmn:Gateway')) {
4053 return getDiamondPath(element);
4054 }
4055
4056 return getRectPath(element);
4057 };
4058
4059 var DEFAULT_BOX_PADDING = 0;
4060
4061 var DEFAULT_LABEL_SIZE$1 = {
4062 width: 150,
4063 height: 50
4064 };
4065
4066
4067 function parseAlign(align) {
4068
4069 var parts = align.split('-');
4070
4071 return {
4072 horizontal: parts[0] || 'center',
4073 vertical: parts[1] || 'top'
4074 };
4075 }
4076
4077 function parsePadding(padding) {
4078
4079 if (isObject(padding)) {
4080 return assign({ top: 0, left: 0, right: 0, bottom: 0 }, padding);
4081 } else {
4082 return {
4083 top: padding,
4084 left: padding,
4085 right: padding,
4086 bottom: padding
4087 };
4088 }
4089 }
4090
4091 function getTextBBox(text, fakeText) {
4092
4093 fakeText.textContent = text;
4094
4095 var textBBox;
4096
4097 try {
4098 var bbox,
4099 emptyLine = text === '';
4100
4101 // add dummy text, when line is empty to
4102 // determine correct height
4103 fakeText.textContent = emptyLine ? 'dummy' : text;
4104
4105 textBBox = fakeText.getBBox();
4106
4107 // take text rendering related horizontal
4108 // padding into account
4109 bbox = {
4110 width: textBBox.width + textBBox.x * 2,
4111 height: textBBox.height
4112 };
4113
4114 if (emptyLine) {
4115
4116 // correct width
4117 bbox.width = 0;
4118 }
4119
4120 return bbox;
4121 } catch (e) {
4122 return { width: 0, height: 0 };
4123 }
4124 }
4125
4126
4127 /**
4128 * Layout the next line and return the layouted element.
4129 *
4130 * Alters the lines passed.
4131 *
4132 * @param {Array<string>} lines
4133 * @return {Object} the line descriptor, an object { width, height, text }
4134 */
4135 function layoutNext(lines, maxWidth, fakeText) {
4136
4137 var originalLine = lines.shift(),
4138 fitLine = originalLine;
4139
4140 var textBBox;
4141
4142 for (;;) {
4143 textBBox = getTextBBox(fitLine, fakeText);
4144
4145 textBBox.width = fitLine ? textBBox.width : 0;
4146
4147 // try to fit
4148 if (fitLine === ' ' || fitLine === '' || textBBox.width < Math.round(maxWidth) || fitLine.length < 2) {
4149 return fit(lines, fitLine, originalLine, textBBox);
4150 }
4151
4152 fitLine = shortenLine(fitLine, textBBox.width, maxWidth);
4153 }
4154 }
4155
4156 function fit(lines, fitLine, originalLine, textBBox) {
4157 if (fitLine.length < originalLine.length) {
4158 var remainder = originalLine.slice(fitLine.length).trim();
4159
4160 lines.unshift(remainder);
4161 }
4162
4163 return {
4164 width: textBBox.width,
4165 height: textBBox.height,
4166 text: fitLine
4167 };
4168 }
4169
4170 var SOFT_BREAK = '\u00AD';
4171
4172
4173 /**
4174 * Shortens a line based on spacing and hyphens.
4175 * Returns the shortened result on success.
4176 *
4177 * @param {string} line
4178 * @param {number} maxLength the maximum characters of the string
4179 * @return {string} the shortened string
4180 */
4181 function semanticShorten(line, maxLength) {
4182
4183 var parts = line.split(/(\s|-|\u00AD)/g),
4184 part,
4185 shortenedParts = [],
4186 length = 0;
4187
4188 // try to shorten via break chars
4189 if (parts.length > 1) {
4190
4191 while ((part = parts.shift())) {
4192 if (part.length + length < maxLength) {
4193 shortenedParts.push(part);
4194 length += part.length;
4195 } else {
4196
4197 // remove previous part, too if hyphen does not fit anymore
4198 if (part === '-' || part === SOFT_BREAK) {
4199 shortenedParts.pop();
4200 }
4201
4202 break;
4203 }
4204 }
4205 }
4206
4207 var last = shortenedParts[shortenedParts.length - 1];
4208
4209 // translate trailing soft break to actual hyphen
4210 if (last && last === SOFT_BREAK) {
4211 shortenedParts[shortenedParts.length - 1] = '-';
4212 }
4213
4214 return shortenedParts.join('');
4215 }
4216
4217
4218 function shortenLine(line, width, maxWidth) {
4219 var length = Math.max(line.length * (maxWidth / width), 1);
4220
4221 // try to shorten semantically (i.e. based on spaces and hyphens)
4222 var shortenedLine = semanticShorten(line, length);
4223
4224 if (!shortenedLine) {
4225
4226 // force shorten by cutting the long word
4227 shortenedLine = line.slice(0, Math.max(Math.round(length - 1), 1));
4228 }
4229
4230 return shortenedLine;
4231 }
4232
4233
4234 function getHelperSvg() {
4235 var helperSvg = document.getElementById('helper-svg');
4236
4237 if (!helperSvg) {
4238 helperSvg = create$1('svg');
4239
4240 attr$1(helperSvg, {
4241 id: 'helper-svg',
4242 width: 0,
4243 height: 0,
4244 style: 'visibility: hidden; position: fixed'
4245 });
4246
4247 document.body.appendChild(helperSvg);
4248 }
4249
4250 return helperSvg;
4251 }
4252
4253
4254 /**
4255 * Creates a new label utility
4256 *
4257 * @param {Object} config
4258 * @param {Dimensions} config.size
4259 * @param {number} config.padding
4260 * @param {Object} config.style
4261 * @param {string} config.align
4262 */
4263 function Text(config) {
4264
4265 this._config = assign({}, {
4266 size: DEFAULT_LABEL_SIZE$1,
4267 padding: DEFAULT_BOX_PADDING,
4268 style: {},
4269 align: 'center-top'
4270 }, config || {});
4271 }
4272
4273 /**
4274 * Returns the layouted text as an SVG element.
4275 *
4276 * @param {string} text
4277 * @param {Object} options
4278 *
4279 * @return {SVGElement}
4280 */
4281 Text.prototype.createText = function(text, options) {
4282 return this.layoutText(text, options).element;
4283 };
4284
4285 /**
4286 * Returns a labels layouted dimensions.
4287 *
4288 * @param {string} text to layout
4289 * @param {Object} options
4290 *
4291 * @return {Dimensions}
4292 */
4293 Text.prototype.getDimensions = function(text, options) {
4294 return this.layoutText(text, options).dimensions;
4295 };
4296
4297 /**
4298 * Creates and returns a label and its bounding box.
4299 *
4300 * @method Text#createText
4301 *
4302 * @param {string} text the text to render on the label
4303 * @param {Object} options
4304 * @param {string} options.align how to align in the bounding box.
4305 * Any of { 'center-middle', 'center-top' },
4306 * defaults to 'center-top'.
4307 * @param {string} options.style style to be applied to the text
4308 * @param {boolean} options.fitBox indicates if box will be recalculated to
4309 * fit text
4310 *
4311 * @return {Object} { element, dimensions }
4312 */
4313 Text.prototype.layoutText = function(text, options) {
4314 var box = assign({}, this._config.size, options.box),
4315 style = assign({}, this._config.style, options.style),
4316 align = parseAlign(options.align || this._config.align),
4317 padding = parsePadding(options.padding !== undefined ? options.padding : this._config.padding),
4318 fitBox = options.fitBox || false;
4319
4320 var lineHeight = getLineHeight(style);
4321
4322 // we split text by lines and normalize
4323 // {soft break} + {line break} => { line break }
4324 var lines = text.split(/\u00AD?\r?\n/),
4325 layouted = [];
4326
4327 var maxWidth = box.width - padding.left - padding.right;
4328
4329 // ensure correct rendering by attaching helper text node to invisible SVG
4330 var helperText = create$1('text');
4331 attr$1(helperText, { x: 0, y: 0 });
4332 attr$1(helperText, style);
4333
4334 var helperSvg = getHelperSvg();
4335
4336 append(helperSvg, helperText);
4337
4338 while (lines.length) {
4339 layouted.push(layoutNext(lines, maxWidth, helperText));
4340 }
4341
4342 if (align.vertical === 'middle') {
4343 padding.top = padding.bottom = 0;
4344 }
4345
4346 var totalHeight = reduce(layouted, function(sum, line, idx) {
4347 return sum + (lineHeight || line.height);
4348 }, 0) + padding.top + padding.bottom;
4349
4350 var maxLineWidth = reduce(layouted, function(sum, line, idx) {
4351 return line.width > sum ? line.width : sum;
4352 }, 0);
4353
4354 // the y position of the next line
4355 var y = padding.top;
4356
4357 if (align.vertical === 'middle') {
4358 y += (box.height - totalHeight) / 2;
4359 }
4360
4361 // magic number initial offset
4362 y -= (lineHeight || layouted[0].height) / 4;
4363
4364
4365 var textElement = create$1('text');
4366
4367 attr$1(textElement, style);
4368
4369 // layout each line taking into account that parent
4370 // shape might resize to fit text size
4371 forEach(layouted, function(line) {
4372
4373 var x;
4374
4375 y += (lineHeight || line.height);
4376
4377 switch (align.horizontal) {
4378 case 'left':
4379 x = padding.left;
4380 break;
4381
4382 case 'right':
4383 x = ((fitBox ? maxLineWidth : maxWidth)
4384 - padding.right - line.width);
4385 break;
4386
4387 default:
4388
4389 // aka center
4390 x = Math.max((((fitBox ? maxLineWidth : maxWidth)
4391 - line.width) / 2 + padding.left), 0);
4392 }
4393
4394 var tspan = create$1('tspan');
4395 attr$1(tspan, { x: x, y: y });
4396
4397 tspan.textContent = line.text;
4398
4399 append(textElement, tspan);
4400 });
4401
4402 remove$2(helperText);
4403
4404 var dimensions = {
4405 width: maxLineWidth,
4406 height: totalHeight
4407 };
4408
4409 return {
4410 dimensions: dimensions,
4411 element: textElement
4412 };
4413 };
4414
4415
4416 function getLineHeight(style) {
4417 if ('fontSize' in style && 'lineHeight' in style) {
4418 return style.lineHeight * parseInt(style.fontSize, 10);
4419 }
4420 }
4421
4422 var DEFAULT_FONT_SIZE = 12;
4423 var LINE_HEIGHT_RATIO = 1.2;
4424
4425 var MIN_TEXT_ANNOTATION_HEIGHT = 30;
4426
4427
4428 function TextRenderer(config) {
4429
4430 var defaultStyle = assign({
4431 fontFamily: 'Arial, sans-serif',
4432 fontSize: DEFAULT_FONT_SIZE,
4433 fontWeight: 'normal',
4434 lineHeight: LINE_HEIGHT_RATIO
4435 }, config && config.defaultStyle || {});
4436
4437 var fontSize = parseInt(defaultStyle.fontSize, 10) - 1;
4438
4439 var externalStyle = assign({}, defaultStyle, {
4440 fontSize: fontSize
4441 }, config && config.externalStyle || {});
4442
4443 var textUtil = new Text({
4444 style: defaultStyle
4445 });
4446
4447 /**
4448 * Get the new bounds of an externally rendered,
4449 * layouted label.
4450 *
4451 * @param {Bounds} bounds
4452 * @param {string} text
4453 *
4454 * @return {Bounds}
4455 */
4456 this.getExternalLabelBounds = function(bounds, text) {
4457
4458 var layoutedDimensions = textUtil.getDimensions(text, {
4459 box: {
4460 width: 90,
4461 height: 30,
4462 x: bounds.width / 2 + bounds.x,
4463 y: bounds.height / 2 + bounds.y
4464 },
4465 style: externalStyle
4466 });
4467
4468 // resize label shape to fit label text
4469 return {
4470 x: Math.round(bounds.x + bounds.width / 2 - layoutedDimensions.width / 2),
4471 y: Math.round(bounds.y),
4472 width: Math.ceil(layoutedDimensions.width),
4473 height: Math.ceil(layoutedDimensions.height)
4474 };
4475
4476 };
4477
4478 /**
4479 * Get the new bounds of text annotation.
4480 *
4481 * @param {Bounds} bounds
4482 * @param {string} text
4483 *
4484 * @return {Bounds}
4485 */
4486 this.getTextAnnotationBounds = function(bounds, text) {
4487
4488 var layoutedDimensions = textUtil.getDimensions(text, {
4489 box: bounds,
4490 style: defaultStyle,
4491 align: 'left-top',
4492 padding: 5
4493 });
4494
4495 return {
4496 x: bounds.x,
4497 y: bounds.y,
4498 width: bounds.width,
4499 height: Math.max(MIN_TEXT_ANNOTATION_HEIGHT, Math.round(layoutedDimensions.height))
4500 };
4501 };
4502
4503 /**
4504 * Create a layouted text element.
4505 *
4506 * @param {string} text
4507 * @param {Object} [options]
4508 *
4509 * @return {SVGElement} rendered text
4510 */
4511 this.createText = function(text, options) {
4512 return textUtil.createText(text, options || {});
4513 };
4514
4515 /**
4516 * Get default text style.
4517 */
4518 this.getDefaultStyle = function() {
4519 return defaultStyle;
4520 };
4521
4522 /**
4523 * Get the external text style.
4524 */
4525 this.getExternalStyle = function() {
4526 return externalStyle;
4527 };
4528
4529 }
4530
4531 TextRenderer.$inject = [
4532 'config.textRenderer'
4533 ];
4534
4535 /**
4536 * Map containing SVG paths needed by BpmnRenderer.
4537 */
4538
4539 function PathMap() {
4540
4541 /**
4542 * Contains a map of path elements
4543 *
4544 * <h1>Path definition</h1>
4545 * A parameterized path is defined like this:
4546 * <pre>
4547 * 'GATEWAY_PARALLEL': {
4548 * d: 'm {mx},{my} {e.x0},0 0,{e.x1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
4549 '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
4550 * height: 17.5,
4551 * width: 17.5,
4552 * heightElements: [2.5, 7.5],
4553 * widthElements: [2.5, 7.5]
4554 * }
4555 * </pre>
4556 * <p>It's important to specify a correct <b>height and width</b> for the path as the scaling
4557 * is based on the ratio between the specified height and width in this object and the
4558 * height and width that is set as scale target (Note x,y coordinates will be scaled with
4559 * individual ratios).</p>
4560 * <p>The '<b>heightElements</b>' and '<b>widthElements</b>' array must contain the values that will be scaled.
4561 * The scaling is based on the computed ratios.
4562 * Coordinates on the y axis should be in the <b>heightElement</b>'s array, they will be scaled using
4563 * the computed ratio coefficient.
4564 * In the parameterized path the scaled values can be accessed through the 'e' object in {} brackets.
4565 * <ul>
4566 * <li>The values for the y axis can be accessed in the path string using {e.y0}, {e.y1}, ....</li>
4567 * <li>The values for the x axis can be accessed in the path string using {e.x0}, {e.x1}, ....</li>
4568 * </ul>
4569 * The numbers x0, x1 respectively y0, y1, ... map to the corresponding array index.
4570 * </p>
4571 */
4572 this.pathMap = {
4573 'EVENT_MESSAGE': {
4574 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}',
4575 height: 36,
4576 width: 36,
4577 heightElements: [6, 14],
4578 widthElements: [10.5, 21]
4579 },
4580 'EVENT_SIGNAL': {
4581 d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x1},0 Z',
4582 height: 36,
4583 width: 36,
4584 heightElements: [18],
4585 widthElements: [10, 20]
4586 },
4587 'EVENT_ESCALATION': {
4588 d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x0},-{e.y1} l -{e.x0},{e.y1} Z',
4589 height: 36,
4590 width: 36,
4591 heightElements: [20, 7],
4592 widthElements: [8]
4593 },
4594 'EVENT_CONDITIONAL': {
4595 d: 'M {e.x0},{e.y0} l {e.x1},0 l 0,{e.y2} l -{e.x1},0 Z ' +
4596 'M {e.x2},{e.y3} l {e.x0},0 ' +
4597 'M {e.x2},{e.y4} l {e.x0},0 ' +
4598 'M {e.x2},{e.y5} l {e.x0},0 ' +
4599 'M {e.x2},{e.y6} l {e.x0},0 ' +
4600 'M {e.x2},{e.y7} l {e.x0},0 ' +
4601 'M {e.x2},{e.y8} l {e.x0},0 ',
4602 height: 36,
4603 width: 36,
4604 heightElements: [8.5, 14.5, 18, 11.5, 14.5, 17.5, 20.5, 23.5, 26.5],
4605 widthElements: [10.5, 14.5, 12.5]
4606 },
4607 'EVENT_LINK': {
4608 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',
4609 height: 36,
4610 width: 36,
4611 heightElements: [4.4375, 6.75, 7.8125],
4612 widthElements: [9.84375, 13.5]
4613 },
4614 'EVENT_ERROR': {
4615 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',
4616 height: 36,
4617 width: 36,
4618 heightElements: [0.023, 8.737, 8.151, 16.564, 10.591, 8.714],
4619 widthElements: [0.085, 6.672, 6.97, 4.273, 5.337, 6.636]
4620 },
4621 'EVENT_CANCEL_45': {
4622 d: 'm {mx},{my} -{e.x1},0 0,{e.x0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
4623 '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
4624 height: 36,
4625 width: 36,
4626 heightElements: [4.75, 8.5],
4627 widthElements: [4.75, 8.5]
4628 },
4629 'EVENT_COMPENSATION': {
4630 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',
4631 height: 36,
4632 width: 36,
4633 heightElements: [6.5, 13, 0.4, 6.1],
4634 widthElements: [9, 9.3, 8.7]
4635 },
4636 'EVENT_TIMER_WH': {
4637 d: 'M {mx},{my} l {e.x0},-{e.y0} m -{e.x0},{e.y0} l {e.x1},{e.y1} ',
4638 height: 36,
4639 width: 36,
4640 heightElements: [10, 2],
4641 widthElements: [3, 7]
4642 },
4643 'EVENT_TIMER_LINE': {
4644 d: 'M {mx},{my} ' +
4645 'm {e.x0},{e.y0} l -{e.x1},{e.y1} ',
4646 height: 36,
4647 width: 36,
4648 heightElements: [10, 3],
4649 widthElements: [0, 0]
4650 },
4651 'EVENT_MULTIPLE': {
4652 d:'m {mx},{my} {e.x1},-{e.y0} {e.x1},{e.y0} -{e.x0},{e.y1} -{e.x2},0 z',
4653 height: 36,
4654 width: 36,
4655 heightElements: [6.28099, 12.56199],
4656 widthElements: [3.1405, 9.42149, 12.56198]
4657 },
4658 'EVENT_PARALLEL_MULTIPLE': {
4659 d:'m {mx},{my} {e.x0},0 0,{e.y1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
4660 '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
4661 height: 36,
4662 width: 36,
4663 heightElements: [2.56228, 7.68683],
4664 widthElements: [2.56228, 7.68683]
4665 },
4666 'GATEWAY_EXCLUSIVE': {
4667 d:'m {mx},{my} {e.x0},{e.y0} {e.x1},{e.y0} {e.x2},0 {e.x4},{e.y2} ' +
4668 '{e.x4},{e.y1} {e.x2},0 {e.x1},{e.y3} {e.x0},{e.y3} ' +
4669 '{e.x3},0 {e.x5},{e.y1} {e.x5},{e.y2} {e.x3},0 z',
4670 height: 17.5,
4671 width: 17.5,
4672 heightElements: [8.5, 6.5312, -6.5312, -8.5],
4673 widthElements: [6.5, -6.5, 3, -3, 5, -5]
4674 },
4675 'GATEWAY_PARALLEL': {
4676 d:'m {mx},{my} 0,{e.y1} -{e.x1},0 0,{e.y0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
4677 '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
4678 height: 30,
4679 width: 30,
4680 heightElements: [5, 12.5],
4681 widthElements: [5, 12.5]
4682 },
4683 'GATEWAY_EVENT_BASED': {
4684 d:'m {mx},{my} {e.x0},{e.y0} {e.x0},{e.y1} {e.x1},{e.y2} {e.x2},0 z',
4685 height: 11,
4686 width: 11,
4687 heightElements: [-6, 6, 12, -12],
4688 widthElements: [9, -3, -12]
4689 },
4690 'GATEWAY_COMPLEX': {
4691 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} ' +
4692 '{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} ' +
4693 '{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} ' +
4694 '-{e.x0},{e.y1} 0,-{e.y0} -{e.x3},0 z',
4695 height: 17.125,
4696 width: 17.125,
4697 heightElements: [4.875, 3.4375, 2.125, 3],
4698 widthElements: [3.4375, 2.125, 4.875, 3]
4699 },
4700 'DATA_OBJECT_PATH': {
4701 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',
4702 height: 61,
4703 width: 51,
4704 heightElements: [10, 50, 60],
4705 widthElements: [10, 40, 50, 60]
4706 },
4707 'DATA_OBJECT_COLLECTION_PATH': {
4708 d: 'm{mx},{my} m 3,2 l 0,10 m 3,-10 l 0,10 m 3,-10 l 0,10',
4709 height: 10,
4710 width: 10,
4711 heightElements: [],
4712 widthElements: []
4713 },
4714 'DATA_ARROW': {
4715 d:'m 5,9 9,0 0,-3 5,5 -5,5 0,-3 -9,0 z',
4716 height: 61,
4717 width: 51,
4718 heightElements: [],
4719 widthElements: []
4720 },
4721 'DATA_STORE': {
4722 d:'m {mx},{my} ' +
4723 'l 0,{e.y2} ' +
4724 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' +
4725 'l 0,-{e.y2} ' +
4726 'c -{e.x0},-{e.y1} -{e.x1},-{e.y1} -{e.x2},0' +
4727 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' +
4728 'm -{e.x2},{e.y0}' +
4729 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0' +
4730 'm -{e.x2},{e.y0}' +
4731 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0',
4732 height: 61,
4733 width: 61,
4734 heightElements: [7, 10, 45],
4735 widthElements: [2, 58, 60]
4736 },
4737 'TEXT_ANNOTATION': {
4738 d: 'm {mx}, {my} m 10,0 l -10,0 l 0,{e.y0} l 10,0',
4739 height: 30,
4740 width: 10,
4741 heightElements: [30],
4742 widthElements: [10]
4743 },
4744 'MARKER_SUB_PROCESS': {
4745 d: 'm{mx},{my} m 7,2 l 0,10 m -5,-5 l 10,0',
4746 height: 10,
4747 width: 10,
4748 heightElements: [],
4749 widthElements: []
4750 },
4751 'MARKER_PARALLEL': {
4752 d: 'm{mx},{my} m 3,2 l 0,10 m 3,-10 l 0,10 m 3,-10 l 0,10',
4753 height: 10,
4754 width: 10,
4755 heightElements: [],
4756 widthElements: []
4757 },
4758 'MARKER_SEQUENTIAL': {
4759 d: 'm{mx},{my} m 0,3 l 10,0 m -10,3 l 10,0 m -10,3 l 10,0',
4760 height: 10,
4761 width: 10,
4762 heightElements: [],
4763 widthElements: []
4764 },
4765 'MARKER_COMPENSATION': {
4766 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',
4767 height: 10,
4768 width: 21,
4769 heightElements: [],
4770 widthElements: []
4771 },
4772 'MARKER_LOOP': {
4773 d: 'm {mx},{my} c 3.526979,0 6.386161,-2.829858 6.386161,-6.320661 0,-3.490806 -2.859182,-6.320661 ' +
4774 '-6.386161,-6.320661 -3.526978,0 -6.38616,2.829855 -6.38616,6.320661 0,1.745402 ' +
4775 '0.714797,3.325567 1.870463,4.469381 0.577834,0.571908 1.265885,1.034728 2.029916,1.35457 ' +
4776 'l -0.718163,-3.909793 m 0.718163,3.909793 -3.885211,0.802902',
4777 height: 13.9,
4778 width: 13.7,
4779 heightElements: [],
4780 widthElements: []
4781 },
4782 'MARKER_ADHOC': {
4783 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 ' +
4784 '3.85579,1.15803 5.76082,1.79107 1.06385,0.34139996 2.24454,0.1438 3.18759,-0.43767 0.61743,-0.33642 ' +
4785 '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 ' +
4786 '-3.6918,1.66181996 -1.24459,0.0927 -2.46671,-0.2491 -3.59505,-0.74812 -1.35789,-0.55965 ' +
4787 '-2.75133,-1.33436996 -4.27027,-1.18121996 -1.37741,0.14601 -2.41842,1.13685996 -3.44288,1.96782996 z',
4788 height: 4,
4789 width: 15,
4790 heightElements: [],
4791 widthElements: []
4792 },
4793 'TASK_TYPE_SEND': {
4794 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}',
4795 height: 14,
4796 width: 21,
4797 heightElements: [6, 14],
4798 widthElements: [10.5, 21]
4799 },
4800 'TASK_TYPE_SCRIPT': {
4801 d: 'm {mx},{my} c 9.966553,-6.27276 -8.000926,-7.91932 2.968968,-14.938 l -8.802728,0 ' +
4802 'c -10.969894,7.01868 6.997585,8.66524 -2.968967,14.938 z ' +
4803 'm -7,-12 l 5,0 ' +
4804 'm -4.5,3 l 4.5,0 ' +
4805 'm -3,3 l 5,0' +
4806 'm -4,3 l 5,0',
4807 height: 15,
4808 width: 12.6,
4809 heightElements: [6, 14],
4810 widthElements: [10.5, 21]
4811 },
4812 'TASK_TYPE_USER_1': {
4813 d: 'm {mx},{my} c 0.909,-0.845 1.594,-2.049 1.594,-3.385 0,-2.554 -1.805,-4.62199999 ' +
4814 '-4.357,-4.62199999 -2.55199998,0 -4.28799998,2.06799999 -4.28799998,4.62199999 0,1.348 ' +
4815 '0.974,2.562 1.89599998,3.405 -0.52899998,0.187 -5.669,2.097 -5.794,4.7560005 v 6.718 ' +
4816 'h 17 v -6.718 c 0,-2.2980005 -5.5279996,-4.5950005 -6.0509996,-4.7760005 z' +
4817 'm -8,6 l 0,5.5 m 11,0 l 0,-5'
4818 },
4819 'TASK_TYPE_USER_2': {
4820 d: 'm {mx},{my} m 2.162,1.009 c 0,2.4470005 -2.158,4.4310005 -4.821,4.4310005 ' +
4821 '-2.66499998,0 -4.822,-1.981 -4.822,-4.4310005 '
4822 },
4823 'TASK_TYPE_USER_3': {
4824 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 ' +
4825 '4.124,0.965 -0.098,-0.57 -0.117,-3.79099999 -4.191,-4.13599999 -3.57499998,0.001 ' +
4826 '-4.20799998,3.36699999 -4.20699998,4.34799999 z'
4827 },
4828 'TASK_TYPE_MANUAL': {
4829 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 ' +
4830 '-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 ' +
4831 '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 ' +
4832 '-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 ' +
4833 '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 ' +
4834 '-10.86,-0.003 -11.0829995,-0.003 -0.022,-0.047 -0.045,-0.094 -0.069,-0.139 0.3939995,-0.319 ' +
4835 '2.0409995,-1.626 2.4149995,-2.017 0.469,-0.4870005 0.519,-1.1650005 0.162,-1.6040005 -0.414,-0.511 ' +
4836 '-0.973,-0.5 -1.48,-0.236 -1.4609995,0.764 -6.5999995,3.6430005 -7.7329995,4.2710005 -0.9,0.499 ' +
4837 '-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 ' +
4838 '-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 ' +
4839 '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 ' +
4840 '-5.824,-0.004 -6.04,-0.004 10e-4,-0.084 0.003,-0.586 10e-4,-0.67 z'
4841 },
4842 'TASK_TYPE_INSTANTIATING_SEND': {
4843 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'
4844 },
4845 'TASK_TYPE_SERVICE': {
4846 d: 'm {mx},{my} v -1.71335 c 0.352326,-0.0705 0.703932,-0.17838 1.047628,-0.32133 ' +
4847 '0.344416,-0.14465 0.665822,-0.32133 0.966377,-0.52145 l 1.19431,1.18005 1.567487,-1.57688 ' +
4848 '-1.195028,-1.18014 c 0.403376,-0.61394 0.683079,-1.29908 0.825447,-2.01824 l 1.622133,-0.01 ' +
4849 'v -2.2196 l -1.636514,0.01 c -0.07333,-0.35153 -0.178319,-0.70024 -0.323564,-1.04372 ' +
4850 '-0.145244,-0.34406 -0.321407,-0.6644 -0.522735,-0.96217 l 1.131035,-1.13631 -1.583305,-1.56293 ' +
4851 '-1.129598,1.13589 c -0.614052,-0.40108 -1.302883,-0.68093 -2.022633,-0.82247 l 0.0093,-1.61852 ' +
4852 '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 ' +
4853 '-0.665102,0.32092 -0.9635006,0.52046 l -1.1698628,-1.15823 -1.5667691,1.5792 1.1684265,1.15669 ' +
4854 'c -0.4026573,0.61283 -0.68308,1.29797 -0.8247287,2.01713 l -1.6588041,0.003 v 2.22174 ' +
4855 'l 1.6724648,-0.006 c 0.073327,0.35077 0.1797598,0.70243 0.3242851,1.04472 0.1452428,0.34448 ' +
4856 '0.3214064,0.6644 0.5227339,0.96066 l -1.1993431,1.19723 1.5840256,1.56011 1.1964668,-1.19348 ' +
4857 'c 0.6140517,0.40346 1.3028827,0.68232 2.0233517,0.82331 l 7.19e-4,1.69892 h 2.226848 z ' +
4858 'm 0.221462,-3.9957 c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
4859 '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
4860 '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
4861 },
4862 'TASK_TYPE_SERVICE_FILL': {
4863 d: 'm {mx},{my} c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
4864 '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
4865 '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
4866 },
4867 'TASK_TYPE_BUSINESS_RULE_HEADER': {
4868 d: 'm {mx},{my} 0,4 20,0 0,-4 z'
4869 },
4870 'TASK_TYPE_BUSINESS_RULE_MAIN': {
4871 d: 'm {mx},{my} 0,12 20,0 0,-12 z' +
4872 'm 0,8 l 20,0 ' +
4873 'm -13,-4 l 0,8'
4874 },
4875 'MESSAGE_FLOW_MARKER': {
4876 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'
4877 }
4878 };
4879
4880 this.getRawPath = function getRawPath(pathId) {
4881 return this.pathMap[pathId].d;
4882 };
4883
4884 /**
4885 * Scales the path to the given height and width.
4886 * <h1>Use case</h1>
4887 * <p>Use case is to scale the content of elements (event, gateways) based
4888 * on the element bounding box's size.
4889 * </p>
4890 * <h1>Why not transform</h1>
4891 * <p>Scaling a path with transform() will also scale the stroke and IE does not support
4892 * the option 'non-scaling-stroke' to prevent this.
4893 * Also there are use cases where only some parts of a path should be
4894 * scaled.</p>
4895 *
4896 * @param {string} pathId The ID of the path.
4897 * @param {Object} param <p>
4898 * Example param object scales the path to 60% size of the container (data.width, data.height).
4899 * <pre>
4900 * {
4901 * xScaleFactor: 0.6,
4902 * yScaleFactor:0.6,
4903 * containerWidth: data.width,
4904 * containerHeight: data.height,
4905 * position: {
4906 * mx: 0.46,
4907 * my: 0.2,
4908 * }
4909 * }
4910 * </pre>
4911 * <ul>
4912 * <li>targetpathwidth = xScaleFactor * containerWidth</li>
4913 * <li>targetpathheight = yScaleFactor * containerHeight</li>
4914 * <li>Position is used to set the starting coordinate of the path. M is computed:
4915 * <ul>
4916 * <li>position.x * containerWidth</li>
4917 * <li>position.y * containerHeight</li>
4918 * </ul>
4919 * Center of the container <pre> position: {
4920 * mx: 0.5,
4921 * my: 0.5,
4922 * }</pre>
4923 * Upper left corner of the container
4924 * <pre> position: {
4925 * mx: 0.0,
4926 * my: 0.0,
4927 * }</pre>
4928 * </li>
4929 * </ul>
4930 * </p>
4931 *
4932 */
4933 this.getScaledPath = function getScaledPath(pathId, param) {
4934 var rawPath = this.pathMap[pathId];
4935
4936 // positioning
4937 // compute the start point of the path
4938 var mx, my;
4939
4940 if (param.abspos) {
4941 mx = param.abspos.x;
4942 my = param.abspos.y;
4943 } else {
4944 mx = param.containerWidth * param.position.mx;
4945 my = param.containerHeight * param.position.my;
4946 }
4947
4948 var coordinates = {}; // map for the scaled coordinates
4949 if (param.position) {
4950
4951 // path
4952 var heightRatio = (param.containerHeight / rawPath.height) * param.yScaleFactor;
4953 var widthRatio = (param.containerWidth / rawPath.width) * param.xScaleFactor;
4954
4955
4956 // Apply height ratio
4957 for (var heightIndex = 0; heightIndex < rawPath.heightElements.length; heightIndex++) {
4958 coordinates['y' + heightIndex] = rawPath.heightElements[heightIndex] * heightRatio;
4959 }
4960
4961 // Apply width ratio
4962 for (var widthIndex = 0; widthIndex < rawPath.widthElements.length; widthIndex++) {
4963 coordinates['x' + widthIndex] = rawPath.widthElements[widthIndex] * widthRatio;
4964 }
4965 }
4966
4967 // Apply value to raw path
4968 var path = format(
4969 rawPath.d, {
4970 mx: mx,
4971 my: my,
4972 e: coordinates
4973 }
4974 );
4975 return path;
4976 };
4977 }
4978
4979 // helpers //////////////////////
4980
4981 // copied and adjusted from https://github.com/adobe-webplatform/Snap.svg/blob/master/src/svg.js
4982 var tokenRegex = /\{([^{}]+)\}/g,
4983 objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g; // matches .xxxxx or ["xxxxx"] to run over object properties
4984
4985 function replacer(all, key, obj) {
4986 var res = obj;
4987 key.replace(objNotationRegex, function(all, name, quote, quotedName, isFunc) {
4988 name = name || quotedName;
4989 if (res) {
4990 if (name in res) {
4991 res = res[name];
4992 }
4993 typeof res == 'function' && isFunc && (res = res());
4994 }
4995 });
4996 res = (res == null || res == obj ? all : res) + '';
4997
4998 return res;
4999 }
5000
5001 function format(str, obj) {
5002 return String(str).replace(tokenRegex, function(all, key) {
5003 return replacer(all, key, obj);
5004 });
5005 }
5006
5007 var DrawModule$1 = {
5008 __init__: [ 'bpmnRenderer' ],
5009 bpmnRenderer: [ 'type', BpmnRenderer ],
5010 textRenderer: [ 'type', TextRenderer ],
5011 pathMap: [ 'type', PathMap ]
5012 };
5013
5014 /**
5015 * A simple translation stub to be used for multi-language support
5016 * in diagrams. Can be easily replaced with a more sophisticated
5017 * solution.
5018 *
5019 * @example
5020 *
5021 * // use it inside any diagram component by injecting `translate`.
5022 *
5023 * function MyService(translate) {
5024 * alert(translate('HELLO {you}', { you: 'You!' }));
5025 * }
5026 *
5027 * @param {string} template to interpolate
5028 * @param {Object} [replacements] a map with substitutes
5029 *
5030 * @return {string} the translated string
5031 */
5032 function translate(template, replacements) {
5033
5034 replacements = replacements || {};
5035
5036 return template.replace(/{([^}]+)}/g, function(_, key) {
5037 return replacements[key] || '{' + key + '}';
5038 });
5039 }
5040
5041 var TranslateModule = {
5042 translate: [ 'value', translate ]
5043 };
5044
5045 var DEFAULT_LABEL_SIZE = {
5046 width: 90,
5047 height: 20
5048 };
5049
5050 var FLOW_LABEL_INDENT = 15;
5051
5052
5053 /**
5054 * Returns true if the given semantic has an external label
5055 *
5056 * @param {BpmnElement} semantic
5057 * @return {boolean} true if has label
5058 */
5059 function isLabelExternal(semantic) {
5060 return is$1(semantic, 'bpmn:Event') ||
5061 is$1(semantic, 'bpmn:Gateway') ||
5062 is$1(semantic, 'bpmn:DataStoreReference') ||
5063 is$1(semantic, 'bpmn:DataObjectReference') ||
5064 is$1(semantic, 'bpmn:DataInput') ||
5065 is$1(semantic, 'bpmn:DataOutput') ||
5066 is$1(semantic, 'bpmn:SequenceFlow') ||
5067 is$1(semantic, 'bpmn:MessageFlow') ||
5068 is$1(semantic, 'bpmn:Group');
5069 }
5070
5071 /**
5072 * Get the position for sequence flow labels
5073 *
5074 * @param {Array<Point>} waypoints
5075 * @return {Point} the label position
5076 */
5077 function getFlowLabelPosition(waypoints) {
5078
5079 // get the waypoints mid
5080 var mid = waypoints.length / 2 - 1;
5081
5082 var first = waypoints[Math.floor(mid)];
5083 var second = waypoints[Math.ceil(mid + 0.01)];
5084
5085 // get position
5086 var position = getWaypointsMid(waypoints);
5087
5088 // calculate angle
5089 var angle = Math.atan((second.y - first.y) / (second.x - first.x));
5090
5091 var x = position.x,
5092 y = position.y;
5093
5094 if (Math.abs(angle) < Math.PI / 2) {
5095 y -= FLOW_LABEL_INDENT;
5096 } else {
5097 x += FLOW_LABEL_INDENT;
5098 }
5099
5100 return { x: x, y: y };
5101 }
5102
5103
5104 /**
5105 * Get the middle of a number of waypoints
5106 *
5107 * @param {Array<Point>} waypoints
5108 * @return {Point} the mid point
5109 */
5110 function getWaypointsMid(waypoints) {
5111
5112 var mid = waypoints.length / 2 - 1;
5113
5114 var first = waypoints[Math.floor(mid)];
5115 var second = waypoints[Math.ceil(mid + 0.01)];
5116
5117 return {
5118 x: first.x + (second.x - first.x) / 2,
5119 y: first.y + (second.y - first.y) / 2
5120 };
5121 }
5122
5123
5124 function getExternalLabelMid(element) {
5125
5126 if (element.waypoints) {
5127 return getFlowLabelPosition(element.waypoints);
5128 } else if (is$1(element, 'bpmn:Group')) {
5129 return {
5130 x: element.x + element.width / 2,
5131 y: element.y + DEFAULT_LABEL_SIZE.height / 2
5132 };
5133 } else {
5134 return {
5135 x: element.x + element.width / 2,
5136 y: element.y + element.height + DEFAULT_LABEL_SIZE.height / 2
5137 };
5138 }
5139 }
5140
5141
5142 /**
5143 * Returns the bounds of an elements label, parsed from the elements DI or
5144 * generated from its bounds.
5145 *
5146 * @param {BpmnElement} semantic
5147 * @param {djs.model.Base} element
5148 */
5149 function getExternalLabelBounds(semantic, element) {
5150
5151 var mid,
5152 size,
5153 bounds,
5154 di = semantic.di,
5155 label = di.label;
5156
5157 if (label && label.bounds) {
5158 bounds = label.bounds;
5159
5160 size = {
5161 width: Math.max(DEFAULT_LABEL_SIZE.width, bounds.width),
5162 height: bounds.height
5163 };
5164
5165 mid = {
5166 x: bounds.x + bounds.width / 2,
5167 y: bounds.y + bounds.height / 2
5168 };
5169 } else {
5170
5171 mid = getExternalLabelMid(element);
5172
5173 size = DEFAULT_LABEL_SIZE;
5174 }
5175
5176 return assign({
5177 x: mid.x - size.width / 2,
5178 y: mid.y - size.height / 2
5179 }, size);
5180 }
5181
5182 function roundPoint(point) {
5183
5184 return {
5185 x: Math.round(point.x),
5186 y: Math.round(point.y)
5187 };
5188 }
5189
5190
5191 /**
5192 * Convert the given bounds to a { top, left, bottom, right } descriptor.
5193 *
5194 * @param {Bounds|Point} bounds
5195 *
5196 * @return {Object}
5197 */
5198 function asTRBL(bounds) {
5199 return {
5200 top: bounds.y,
5201 right: bounds.x + (bounds.width || 0),
5202 bottom: bounds.y + (bounds.height || 0),
5203 left: bounds.x
5204 };
5205 }
5206
5207
5208 /**
5209 * Get the mid of the given bounds or point.
5210 *
5211 * @param {Bounds|Point} bounds
5212 *
5213 * @return {Point}
5214 */
5215 function getMid(bounds) {
5216 return roundPoint({
5217 x: bounds.x + (bounds.width || 0) / 2,
5218 y: bounds.y + (bounds.height || 0) / 2
5219 });
5220 }
5221
5222 function elementToString(e) {
5223 if (!e) {
5224 return '<null>';
5225 }
5226
5227 return '<' + e.$type + (e.id ? ' id="' + e.id : '') + '" />';
5228 }
5229
5230 function elementData(semantic, attrs) {
5231 return assign({
5232 id: semantic.id,
5233 type: semantic.$type,
5234 businessObject: semantic
5235 }, attrs);
5236 }
5237
5238 function getWaypoints(bo, source, target) {
5239
5240 var waypoints = bo.di.waypoint;
5241
5242 if (!waypoints || waypoints.length < 2) {
5243 return [ getMid(source), getMid(target) ];
5244 }
5245
5246 return waypoints.map(function(p) {
5247 return { x: p.x, y: p.y };
5248 });
5249 }
5250
5251 function notYetDrawn(translate, semantic, refSemantic, property) {
5252 return new Error(translate('element {element} referenced by {referenced}#{property} not yet drawn', {
5253 element: elementToString(refSemantic),
5254 referenced: elementToString(semantic),
5255 property: property
5256 }));
5257 }
5258
5259
5260 /**
5261 * An importer that adds bpmn elements to the canvas
5262 *
5263 * @param {EventBus} eventBus
5264 * @param {Canvas} canvas
5265 * @param {ElementFactory} elementFactory
5266 * @param {ElementRegistry} elementRegistry
5267 * @param {Function} translate
5268 * @param {TextRenderer} textRenderer
5269 */
5270 function BpmnImporter(
5271 eventBus, canvas, elementFactory,
5272 elementRegistry, translate, textRenderer) {
5273
5274 this._eventBus = eventBus;
5275 this._canvas = canvas;
5276 this._elementFactory = elementFactory;
5277 this._elementRegistry = elementRegistry;
5278 this._translate = translate;
5279 this._textRenderer = textRenderer;
5280 }
5281
5282 BpmnImporter.$inject = [
5283 'eventBus',
5284 'canvas',
5285 'elementFactory',
5286 'elementRegistry',
5287 'translate',
5288 'textRenderer'
5289 ];
5290
5291
5292 /**
5293 * Add bpmn element (semantic) to the canvas onto the
5294 * specified parent shape.
5295 */
5296 BpmnImporter.prototype.add = function(semantic, parentElement) {
5297
5298 var di = semantic.di,
5299 element,
5300 translate = this._translate,
5301 hidden;
5302
5303 var parentIndex;
5304
5305 // ROOT ELEMENT
5306 // handle the special case that we deal with a
5307 // invisible root element (process or collaboration)
5308 if (is$1(di, 'bpmndi:BPMNPlane')) {
5309
5310 // add a virtual element (not being drawn)
5311 element = this._elementFactory.createRoot(elementData(semantic));
5312
5313 this._canvas.setRootElement(element);
5314 }
5315
5316 // SHAPE
5317 else if (is$1(di, 'bpmndi:BPMNShape')) {
5318
5319 var collapsed = !isExpanded(semantic),
5320 isFrame = isFrameElement$1(semantic);
5321 hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
5322
5323 var bounds = semantic.di.bounds;
5324
5325 element = this._elementFactory.createShape(elementData(semantic, {
5326 collapsed: collapsed,
5327 hidden: hidden,
5328 x: Math.round(bounds.x),
5329 y: Math.round(bounds.y),
5330 width: Math.round(bounds.width),
5331 height: Math.round(bounds.height),
5332 isFrame: isFrame
5333 }));
5334
5335 if (is$1(semantic, 'bpmn:BoundaryEvent')) {
5336 this._attachBoundary(semantic, element);
5337 }
5338
5339 // insert lanes behind other flow nodes (cf. #727)
5340 if (is$1(semantic, 'bpmn:Lane')) {
5341 parentIndex = 0;
5342 }
5343
5344 if (is$1(semantic, 'bpmn:DataStoreReference')) {
5345
5346 // check whether data store is inside our outside of its semantic parent
5347 if (!isPointInsideBBox(parentElement, getMid(bounds))) {
5348 parentElement = this._canvas.getRootElement();
5349 }
5350 }
5351
5352 this._canvas.addShape(element, parentElement, parentIndex);
5353 }
5354
5355 // CONNECTION
5356 else if (is$1(di, 'bpmndi:BPMNEdge')) {
5357
5358 var source = this._getSource(semantic),
5359 target = this._getTarget(semantic);
5360
5361 hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
5362
5363 element = this._elementFactory.createConnection(elementData(semantic, {
5364 hidden: hidden,
5365 source: source,
5366 target: target,
5367 waypoints: getWaypoints(semantic, source, target)
5368 }));
5369
5370 if (is$1(semantic, 'bpmn:DataAssociation')) {
5371
5372 // render always on top; this ensures DataAssociations
5373 // are rendered correctly across different "hacks" people
5374 // love to model such as cross participant / sub process
5375 // associations
5376 parentElement = null;
5377 }
5378
5379 // insert sequence flows behind other flow nodes (cf. #727)
5380 if (is$1(semantic, 'bpmn:SequenceFlow')) {
5381 parentIndex = 0;
5382 }
5383
5384 this._canvas.addConnection(element, parentElement, parentIndex);
5385 } else {
5386 throw new Error(translate('unknown di {di} for element {semantic}', {
5387 di: elementToString(di),
5388 semantic: elementToString(semantic)
5389 }));
5390 }
5391
5392 // (optional) LABEL
5393 if (isLabelExternal(semantic) && getLabel(element)) {
5394 this.addLabel(semantic, element);
5395 }
5396
5397
5398 this._eventBus.fire('bpmnElement.added', { element: element });
5399
5400 return element;
5401 };
5402
5403
5404 /**
5405 * Attach the boundary element to the given host
5406 *
5407 * @param {ModdleElement} boundarySemantic
5408 * @param {djs.model.Base} boundaryElement
5409 */
5410 BpmnImporter.prototype._attachBoundary = function(boundarySemantic, boundaryElement) {
5411 var translate = this._translate;
5412 var hostSemantic = boundarySemantic.attachedToRef;
5413
5414 if (!hostSemantic) {
5415 throw new Error(translate('missing {semantic}#attachedToRef', {
5416 semantic: elementToString(boundarySemantic)
5417 }));
5418 }
5419
5420 var host = this._elementRegistry.get(hostSemantic.id),
5421 attachers = host && host.attachers;
5422
5423 if (!host) {
5424 throw notYetDrawn(translate, boundarySemantic, hostSemantic, 'attachedToRef');
5425 }
5426
5427 // wire element.host <> host.attachers
5428 boundaryElement.host = host;
5429
5430 if (!attachers) {
5431 host.attachers = attachers = [];
5432 }
5433
5434 if (attachers.indexOf(boundaryElement) === -1) {
5435 attachers.push(boundaryElement);
5436 }
5437 };
5438
5439
5440 /**
5441 * add label for an element
5442 */
5443 BpmnImporter.prototype.addLabel = function(semantic, element) {
5444 var bounds,
5445 text,
5446 label;
5447
5448 bounds = getExternalLabelBounds(semantic, element);
5449
5450 text = getLabel(element);
5451
5452 if (text) {
5453
5454 // get corrected bounds from actual layouted text
5455 bounds = this._textRenderer.getExternalLabelBounds(bounds, text);
5456 }
5457
5458 label = this._elementFactory.createLabel(elementData(semantic, {
5459 id: semantic.id + '_label',
5460 labelTarget: element,
5461 type: 'label',
5462 hidden: element.hidden || !getLabel(element),
5463 x: Math.round(bounds.x),
5464 y: Math.round(bounds.y),
5465 width: Math.round(bounds.width),
5466 height: Math.round(bounds.height)
5467 }));
5468
5469 return this._canvas.addShape(label, element.parent);
5470 };
5471
5472 /**
5473 * Return the drawn connection end based on the given side.
5474 *
5475 * @throws {Error} if the end is not yet drawn
5476 */
5477 BpmnImporter.prototype._getEnd = function(semantic, side) {
5478
5479 var element,
5480 refSemantic,
5481 type = semantic.$type,
5482 translate = this._translate;
5483
5484 refSemantic = semantic[side + 'Ref'];
5485
5486 // handle mysterious isMany DataAssociation#sourceRef
5487 if (side === 'source' && type === 'bpmn:DataInputAssociation') {
5488 refSemantic = refSemantic && refSemantic[0];
5489 }
5490
5491 // fix source / target for DataInputAssociation / DataOutputAssociation
5492 if (side === 'source' && type === 'bpmn:DataOutputAssociation' ||
5493 side === 'target' && type === 'bpmn:DataInputAssociation') {
5494
5495 refSemantic = semantic.$parent;
5496 }
5497
5498 element = refSemantic && this._getElement(refSemantic);
5499
5500 if (element) {
5501 return element;
5502 }
5503
5504 if (refSemantic) {
5505 throw notYetDrawn(translate, semantic, refSemantic, side + 'Ref');
5506 } else {
5507 throw new Error(translate('{semantic}#{side} Ref not specified', {
5508 semantic: elementToString(semantic),
5509 side: side
5510 }));
5511 }
5512 };
5513
5514 BpmnImporter.prototype._getSource = function(semantic) {
5515 return this._getEnd(semantic, 'source');
5516 };
5517
5518 BpmnImporter.prototype._getTarget = function(semantic) {
5519 return this._getEnd(semantic, 'target');
5520 };
5521
5522
5523 BpmnImporter.prototype._getElement = function(semantic) {
5524 return this._elementRegistry.get(semantic.id);
5525 };
5526
5527
5528 // helpers ////////////////////
5529
5530 function isPointInsideBBox(bbox, point) {
5531 var x = point.x,
5532 y = point.y;
5533
5534 return x >= bbox.x &&
5535 x <= bbox.x + bbox.width &&
5536 y >= bbox.y &&
5537 y <= bbox.y + bbox.height;
5538 }
5539
5540 function isFrameElement$1(semantic) {
5541 return is$1(semantic, 'bpmn:Group');
5542 }
5543
5544 var ImportModule = {
5545 __depends__: [
5546 TranslateModule
5547 ],
5548 bpmnImporter: [ 'type', BpmnImporter ]
5549 };
5550
5551 var CoreModule$1 = {
5552 __depends__: [
5553 DrawModule$1,
5554 ImportModule
5555 ]
5556 };
5557
5558 function getOriginal(event) {
5559 return event.originalEvent || event.srcEvent;
5560 }
5561
5562 function isMac() {
5563 return (/mac/i).test(navigator.platform);
5564 }
5565
5566 function isButton(event, button) {
5567 return (getOriginal(event) || event).button === button;
5568 }
5569
5570 function isPrimaryButton(event) {
5571
5572 // button === 0 -> left áka primary mouse button
5573 return isButton(event, 0);
5574 }
5575
5576 function isAuxiliaryButton(event) {
5577
5578 // button === 1 -> auxiliary áka wheel button
5579 return isButton(event, 1);
5580 }
5581
5582 function hasPrimaryModifier(event) {
5583 var originalEvent = getOriginal(event) || event;
5584
5585 if (!isPrimaryButton(event)) {
5586 return false;
5587 }
5588
5589 // Use cmd as primary modifier key for mac OS
5590 if (isMac()) {
5591 return originalEvent.metaKey;
5592 } else {
5593 return originalEvent.ctrlKey;
5594 }
5595 }
5596
5597
5598 function hasSecondaryModifier(event) {
5599 var originalEvent = getOriginal(event) || event;
5600
5601 return isPrimaryButton(event) && originalEvent.shiftKey;
5602 }
5603
5604 function allowAll(event) { return true; }
5605
5606 function allowPrimaryAndAuxiliary(event) {
5607 return isPrimaryButton(event) || isAuxiliaryButton(event);
5608 }
5609
5610 var LOW_PRIORITY$2 = 500;
5611
5612
5613 /**
5614 * A plugin that provides interaction events for diagram elements.
5615 *
5616 * It emits the following events:
5617 *
5618 * * element.click
5619 * * element.contextmenu
5620 * * element.dblclick
5621 * * element.hover
5622 * * element.mousedown
5623 * * element.mousemove
5624 * * element.mouseup
5625 * * element.out
5626 *
5627 * Each event is a tuple { element, gfx, originalEvent }.
5628 *
5629 * Canceling the event via Event#preventDefault()
5630 * prevents the original DOM operation.
5631 *
5632 * @param {EventBus} eventBus
5633 */
5634 function InteractionEvents(eventBus, elementRegistry, styles) {
5635
5636 var self = this;
5637
5638 /**
5639 * Fire an interaction event.
5640 *
5641 * @param {string} type local event name, e.g. element.click.
5642 * @param {DOMEvent} event native event
5643 * @param {djs.model.Base} [element] the diagram element to emit the event on;
5644 * defaults to the event target
5645 */
5646 function fire(type, event, element) {
5647
5648 if (isIgnored(type, event)) {
5649 return;
5650 }
5651
5652 var target, gfx, returnValue;
5653
5654 if (!element) {
5655 target = event.delegateTarget || event.target;
5656
5657 if (target) {
5658 gfx = target;
5659 element = elementRegistry.get(gfx);
5660 }
5661 } else {
5662 gfx = elementRegistry.getGraphics(element);
5663 }
5664
5665 if (!gfx || !element) {
5666 return;
5667 }
5668
5669 returnValue = eventBus.fire(type, {
5670 element: element,
5671 gfx: gfx,
5672 originalEvent: event
5673 });
5674
5675 if (returnValue === false) {
5676 event.stopPropagation();
5677 event.preventDefault();
5678 }
5679 }
5680
5681 // TODO(nikku): document this
5682 var handlers = {};
5683
5684 function mouseHandler(localEventName) {
5685 return handlers[localEventName];
5686 }
5687
5688 function isIgnored(localEventName, event) {
5689
5690 var filter = ignoredFilters[localEventName] || isPrimaryButton;
5691
5692 // only react on left mouse button interactions
5693 // except for interaction events that are enabled
5694 // for secundary mouse button
5695 return !filter(event);
5696 }
5697
5698 var bindings = {
5699 click: 'element.click',
5700 contextmenu: 'element.contextmenu',
5701 dblclick: 'element.dblclick',
5702 mousedown: 'element.mousedown',
5703 mousemove: 'element.mousemove',
5704 mouseover: 'element.hover',
5705 mouseout: 'element.out',
5706 mouseup: 'element.mouseup',
5707 };
5708
5709 var ignoredFilters = {
5710 'element.contextmenu': allowAll,
5711 'element.mousedown': allowPrimaryAndAuxiliary,
5712 'element.mouseup': allowPrimaryAndAuxiliary,
5713 'element.click': allowPrimaryAndAuxiliary,
5714 'element.dblclick': allowPrimaryAndAuxiliary
5715 };
5716
5717
5718 // manual event trigger //////////
5719
5720 /**
5721 * Trigger an interaction event (based on a native dom event)
5722 * on the target shape or connection.
5723 *
5724 * @param {string} eventName the name of the triggered DOM event
5725 * @param {MouseEvent} event
5726 * @param {djs.model.Base} targetElement
5727 */
5728 function triggerMouseEvent(eventName, event, targetElement) {
5729
5730 // i.e. element.mousedown...
5731 var localEventName = bindings[eventName];
5732
5733 if (!localEventName) {
5734 throw new Error('unmapped DOM event name <' + eventName + '>');
5735 }
5736
5737 return fire(localEventName, event, targetElement);
5738 }
5739
5740
5741 var ELEMENT_SELECTOR = 'svg, .djs-element';
5742
5743 // event handling ///////
5744
5745 function registerEvent(node, event, localEvent, ignoredFilter) {
5746
5747 var handler = handlers[localEvent] = function(event) {
5748 fire(localEvent, event);
5749 };
5750
5751 if (ignoredFilter) {
5752 ignoredFilters[localEvent] = ignoredFilter;
5753 }
5754
5755 handler.$delegate = delegate.bind(node, ELEMENT_SELECTOR, event, handler);
5756 }
5757
5758 function unregisterEvent(node, event, localEvent) {
5759
5760 var handler = mouseHandler(localEvent);
5761
5762 if (!handler) {
5763 return;
5764 }
5765
5766 delegate.unbind(node, event, handler.$delegate);
5767 }
5768
5769 function registerEvents(svg) {
5770 forEach(bindings, function(val, key) {
5771 registerEvent(svg, key, val);
5772 });
5773 }
5774
5775 function unregisterEvents(svg) {
5776 forEach(bindings, function(val, key) {
5777 unregisterEvent(svg, key, val);
5778 });
5779 }
5780
5781 eventBus.on('canvas.destroy', function(event) {
5782 unregisterEvents(event.svg);
5783 });
5784
5785 eventBus.on('canvas.init', function(event) {
5786 registerEvents(event.svg);
5787 });
5788
5789
5790 // hit box updating ////////////////
5791
5792 eventBus.on([ 'shape.added', 'connection.added' ], function(event) {
5793 var element = event.element,
5794 gfx = event.gfx;
5795
5796 eventBus.fire('interactionEvents.createHit', { element: element, gfx: gfx });
5797 });
5798
5799 // Update djs-hit on change.
5800 // A low priortity is necessary, because djs-hit of labels has to be updated
5801 // after the label bounds have been updated in the renderer.
5802 eventBus.on([
5803 'shape.changed',
5804 'connection.changed'
5805 ], LOW_PRIORITY$2, function(event) {
5806
5807 var element = event.element,
5808 gfx = event.gfx;
5809
5810 eventBus.fire('interactionEvents.updateHit', { element: element, gfx: gfx });
5811 });
5812
5813 eventBus.on('interactionEvents.createHit', LOW_PRIORITY$2, function(event) {
5814 var element = event.element,
5815 gfx = event.gfx;
5816
5817 self.createDefaultHit(element, gfx);
5818 });
5819
5820 eventBus.on('interactionEvents.updateHit', function(event) {
5821 var element = event.element,
5822 gfx = event.gfx;
5823
5824 self.updateDefaultHit(element, gfx);
5825 });
5826
5827
5828 // hit styles ////////////
5829
5830 var STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-stroke');
5831
5832 var CLICK_STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-click-stroke');
5833
5834 var ALL_HIT_STYLE = createHitStyle('djs-hit djs-hit-all');
5835
5836 var HIT_TYPES = {
5837 'all': ALL_HIT_STYLE,
5838 'click-stroke': CLICK_STROKE_HIT_STYLE,
5839 'stroke': STROKE_HIT_STYLE
5840 };
5841
5842 function createHitStyle(classNames, attrs) {
5843
5844 attrs = assign({
5845 stroke: 'white',
5846 strokeWidth: 15
5847 }, attrs || {});
5848
5849 return styles.cls(classNames, [ 'no-fill', 'no-border' ], attrs);
5850 }
5851
5852
5853 // style helpers ///////////////
5854
5855 function applyStyle(hit, type) {
5856
5857 var attrs = HIT_TYPES[type];
5858
5859 if (!attrs) {
5860 throw new Error('invalid hit type <' + type + '>');
5861 }
5862
5863 attr$1(hit, attrs);
5864
5865 return hit;
5866 }
5867
5868 function appendHit(gfx, hit) {
5869 append(gfx, hit);
5870 }
5871
5872
5873 // API
5874
5875 /**
5876 * Remove hints on the given graphics.
5877 *
5878 * @param {SVGElement} gfx
5879 */
5880 this.removeHits = function(gfx) {
5881 var hits = all('.djs-hit', gfx);
5882
5883 forEach(hits, remove$2);
5884 };
5885
5886 /**
5887 * Create default hit for the given element.
5888 *
5889 * @param {djs.model.Base} element
5890 * @param {SVGElement} gfx
5891 *
5892 * @return {SVGElement} created hit
5893 */
5894 this.createDefaultHit = function(element, gfx) {
5895 var waypoints = element.waypoints,
5896 isFrame = element.isFrame,
5897 boxType;
5898
5899 if (waypoints) {
5900 return this.createWaypointsHit(gfx, waypoints);
5901 } else {
5902
5903 boxType = isFrame ? 'stroke' : 'all';
5904
5905 return this.createBoxHit(gfx, boxType, {
5906 width: element.width,
5907 height: element.height
5908 });
5909 }
5910 };
5911
5912 /**
5913 * Create hits for the given waypoints.
5914 *
5915 * @param {SVGElement} gfx
5916 * @param {Array<Point>} waypoints
5917 *
5918 * @return {SVGElement}
5919 */
5920 this.createWaypointsHit = function(gfx, waypoints) {
5921
5922 var hit = createLine(waypoints);
5923
5924 applyStyle(hit, 'stroke');
5925
5926 appendHit(gfx, hit);
5927
5928 return hit;
5929 };
5930
5931 /**
5932 * Create hits for a box.
5933 *
5934 * @param {SVGElement} gfx
5935 * @param {string} hitType
5936 * @param {Object} attrs
5937 *
5938 * @return {SVGElement}
5939 */
5940 this.createBoxHit = function(gfx, type, attrs) {
5941
5942 attrs = assign({
5943 x: 0,
5944 y: 0
5945 }, attrs);
5946
5947 var hit = create$1('rect');
5948
5949 applyStyle(hit, type);
5950
5951 attr$1(hit, attrs);
5952
5953 appendHit(gfx, hit);
5954
5955 return hit;
5956 };
5957
5958 /**
5959 * Update default hit of the element.
5960 *
5961 * @param {djs.model.Base} element
5962 * @param {SVGElement} gfx
5963 *
5964 * @return {SVGElement} updated hit
5965 */
5966 this.updateDefaultHit = function(element, gfx) {
5967
5968 var hit = query('.djs-hit', gfx);
5969
5970 if (!hit) {
5971 return;
5972 }
5973
5974 if (element.waypoints) {
5975 updateLine(hit, element.waypoints);
5976 } else {
5977 attr$1(hit, {
5978 width: element.width,
5979 height: element.height
5980 });
5981 }
5982
5983 return hit;
5984 };
5985
5986 this.fire = fire;
5987
5988 this.triggerMouseEvent = triggerMouseEvent;
5989
5990 this.mouseHandler = mouseHandler;
5991
5992 this.registerEvent = registerEvent;
5993 this.unregisterEvent = unregisterEvent;
5994 }
5995
5996
5997 InteractionEvents.$inject = [
5998 'eventBus',
5999 'elementRegistry',
6000 'styles'
6001 ];
6002
6003
6004 /**
6005 * An event indicating that the mouse hovered over an element
6006 *
6007 * @event element.hover
6008 *
6009 * @type {Object}
6010 * @property {djs.model.Base} element
6011 * @property {SVGElement} gfx
6012 * @property {Event} originalEvent
6013 */
6014
6015 /**
6016 * An event indicating that the mouse has left an element
6017 *
6018 * @event element.out
6019 *
6020 * @type {Object}
6021 * @property {djs.model.Base} element
6022 * @property {SVGElement} gfx
6023 * @property {Event} originalEvent
6024 */
6025
6026 /**
6027 * An event indicating that the mouse has clicked an element
6028 *
6029 * @event element.click
6030 *
6031 * @type {Object}
6032 * @property {djs.model.Base} element
6033 * @property {SVGElement} gfx
6034 * @property {Event} originalEvent
6035 */
6036
6037 /**
6038 * An event indicating that the mouse has double clicked an element
6039 *
6040 * @event element.dblclick
6041 *
6042 * @type {Object}
6043 * @property {djs.model.Base} element
6044 * @property {SVGElement} gfx
6045 * @property {Event} originalEvent
6046 */
6047
6048 /**
6049 * An event indicating that the mouse has gone down on an element.
6050 *
6051 * @event element.mousedown
6052 *
6053 * @type {Object}
6054 * @property {djs.model.Base} element
6055 * @property {SVGElement} gfx
6056 * @property {Event} originalEvent
6057 */
6058
6059 /**
6060 * An event indicating that the mouse has gone up on an element.
6061 *
6062 * @event element.mouseup
6063 *
6064 * @type {Object}
6065 * @property {djs.model.Base} element
6066 * @property {SVGElement} gfx
6067 * @property {Event} originalEvent
6068 */
6069
6070 /**
6071 * An event indicating that the context menu action is triggered
6072 * via mouse or touch controls.
6073 *
6074 * @event element.contextmenu
6075 *
6076 * @type {Object}
6077 * @property {djs.model.Base} element
6078 * @property {SVGElement} gfx
6079 * @property {Event} originalEvent
6080 */
6081
6082 var InteractionEventsModule = {
6083 __init__: [ 'interactionEvents' ],
6084 interactionEvents: [ 'type', InteractionEvents ]
6085 };
6086
6087 /**
6088 * Returns the surrounding bbox for all elements in
6089 * the array or the element primitive.
6090 *
6091 * @param {Array<djs.model.Shape>|djs.model.Shape} elements
6092 * @param {boolean} stopRecursion
6093 */
6094 function getBBox(elements, stopRecursion) {
6095
6096 stopRecursion = !!stopRecursion;
6097 if (!isArray$1(elements)) {
6098 elements = [elements];
6099 }
6100
6101 var minX,
6102 minY,
6103 maxX,
6104 maxY;
6105
6106 forEach(elements, function(element) {
6107
6108 // If element is a connection the bbox must be computed first
6109 var bbox = element;
6110 if (element.waypoints && !stopRecursion) {
6111 bbox = getBBox(element.waypoints, true);
6112 }
6113
6114 var x = bbox.x,
6115 y = bbox.y,
6116 height = bbox.height || 0,
6117 width = bbox.width || 0;
6118
6119 if (x < minX || minX === undefined) {
6120 minX = x;
6121 }
6122 if (y < minY || minY === undefined) {
6123 minY = y;
6124 }
6125
6126 if ((x + width) > maxX || maxX === undefined) {
6127 maxX = x + width;
6128 }
6129 if ((y + height) > maxY || maxY === undefined) {
6130 maxY = y + height;
6131 }
6132 });
6133
6134 return {
6135 x: minX,
6136 y: minY,
6137 height: maxY - minY,
6138 width: maxX - minX
6139 };
6140 }
6141
6142
6143 function getType(element) {
6144
6145 if ('waypoints' in element) {
6146 return 'connection';
6147 }
6148
6149 if ('x' in element) {
6150 return 'shape';
6151 }
6152
6153 return 'root';
6154 }
6155
6156 function isFrameElement(element) {
6157
6158 return !!(element && element.isFrame);
6159 }
6160
6161 var LOW_PRIORITY$1 = 500;
6162
6163
6164 /**
6165 * @class
6166 *
6167 * A plugin that adds an outline to shapes and connections that may be activated and styled
6168 * via CSS classes.
6169 *
6170 * @param {EventBus} eventBus
6171 * @param {Styles} styles
6172 * @param {ElementRegistry} elementRegistry
6173 */
6174 function Outline(eventBus, styles, elementRegistry) {
6175
6176 this.offset = 6;
6177
6178 var OUTLINE_STYLE = styles.cls('djs-outline', [ 'no-fill' ]);
6179
6180 var self = this;
6181
6182 function createOutline(gfx, bounds) {
6183 var outline = create$1('rect');
6184
6185 attr$1(outline, assign({
6186 x: 10,
6187 y: 10,
6188 width: 100,
6189 height: 100
6190 }, OUTLINE_STYLE));
6191
6192 append(gfx, outline);
6193
6194 return outline;
6195 }
6196
6197 // A low priortity is necessary, because outlines of labels have to be updated
6198 // after the label bounds have been updated in the renderer.
6199 eventBus.on([ 'shape.added', 'shape.changed' ], LOW_PRIORITY$1, function(event) {
6200 var element = event.element,
6201 gfx = event.gfx;
6202
6203 var outline = query('.djs-outline', gfx);
6204
6205 if (!outline) {
6206 outline = createOutline(gfx);
6207 }
6208
6209 self.updateShapeOutline(outline, element);
6210 });
6211
6212 eventBus.on([ 'connection.added', 'connection.changed' ], function(event) {
6213 var element = event.element,
6214 gfx = event.gfx;
6215
6216 var outline = query('.djs-outline', gfx);
6217
6218 if (!outline) {
6219 outline = createOutline(gfx);
6220 }
6221
6222 self.updateConnectionOutline(outline, element);
6223 });
6224 }
6225
6226
6227 /**
6228 * Updates the outline of a shape respecting the dimension of the
6229 * element and an outline offset.
6230 *
6231 * @param {SVGElement} outline
6232 * @param {djs.model.Base} element
6233 */
6234 Outline.prototype.updateShapeOutline = function(outline, element) {
6235
6236 attr$1(outline, {
6237 x: -this.offset,
6238 y: -this.offset,
6239 width: element.width + this.offset * 2,
6240 height: element.height + this.offset * 2
6241 });
6242
6243 };
6244
6245
6246 /**
6247 * Updates the outline of a connection respecting the bounding box of
6248 * the connection and an outline offset.
6249 *
6250 * @param {SVGElement} outline
6251 * @param {djs.model.Base} element
6252 */
6253 Outline.prototype.updateConnectionOutline = function(outline, connection) {
6254
6255 var bbox = getBBox(connection);
6256
6257 attr$1(outline, {
6258 x: bbox.x - this.offset,
6259 y: bbox.y - this.offset,
6260 width: bbox.width + this.offset * 2,
6261 height: bbox.height + this.offset * 2
6262 });
6263
6264 };
6265
6266
6267 Outline.$inject = ['eventBus', 'styles', 'elementRegistry'];
6268
6269 var OutlineModule = {
6270 __init__: [ 'outline' ],
6271 outline: [ 'type', Outline ]
6272 };
6273
6274 /**
6275 * A service that offers the current selection in a diagram.
6276 * Offers the api to control the selection, too.
6277 *
6278 * @class
6279 *
6280 * @param {EventBus} eventBus the event bus
6281 */
6282 function Selection(eventBus, canvas) {
6283
6284 this._eventBus = eventBus;
6285 this._canvas = canvas;
6286
6287 this._selectedElements = [];
6288
6289 var self = this;
6290
6291 eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
6292 var element = e.element;
6293 self.deselect(element);
6294 });
6295
6296 eventBus.on([ 'diagram.clear', 'plane.set' ], function(e) {
6297 self.select(null);
6298 });
6299 }
6300
6301 Selection.$inject = [ 'eventBus', 'canvas' ];
6302
6303
6304 Selection.prototype.deselect = function(element) {
6305 var selectedElements = this._selectedElements;
6306
6307 var idx = selectedElements.indexOf(element);
6308
6309 if (idx !== -1) {
6310 var oldSelection = selectedElements.slice();
6311
6312 selectedElements.splice(idx, 1);
6313
6314 this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
6315 }
6316 };
6317
6318
6319 Selection.prototype.get = function() {
6320 return this._selectedElements;
6321 };
6322
6323 Selection.prototype.isSelected = function(element) {
6324 return this._selectedElements.indexOf(element) !== -1;
6325 };
6326
6327
6328 /**
6329 * This method selects one or more elements on the diagram.
6330 *
6331 * By passing an additional add parameter you can decide whether or not the element(s)
6332 * should be added to the already existing selection or not.
6333 *
6334 * @method Selection#select
6335 *
6336 * @param {Object|Object[]} elements element or array of elements to be selected
6337 * @param {boolean} [add] whether the element(s) should be appended to the current selection, defaults to false
6338 */
6339 Selection.prototype.select = function(elements, add) {
6340 var selectedElements = this._selectedElements,
6341 oldSelection = selectedElements.slice();
6342
6343 if (!isArray$1(elements)) {
6344 elements = elements ? [ elements ] : [];
6345 }
6346
6347 var canvas = this._canvas;
6348
6349 elements = elements.filter(function(element) {
6350 var plane = canvas.findPlane(element);
6351
6352 return plane === canvas.getActivePlane();
6353 });
6354
6355 // selection may be cleared by passing an empty array or null
6356 // to the method
6357 if (add) {
6358 forEach(elements, function(element) {
6359 if (selectedElements.indexOf(element) !== -1) {
6360
6361 // already selected
6362 return;
6363 } else {
6364 selectedElements.push(element);
6365 }
6366 });
6367 } else {
6368 this._selectedElements = selectedElements = elements.slice();
6369 }
6370
6371 this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
6372 };
6373
6374 var MARKER_HOVER = 'hover',
6375 MARKER_SELECTED = 'selected';
6376
6377
6378 /**
6379 * A plugin that adds a visible selection UI to shapes and connections
6380 * by appending the <code>hover</code> and <code>selected</code> classes to them.
6381 *
6382 * @class
6383 *
6384 * Makes elements selectable, too.
6385 *
6386 * @param {EventBus} events
6387 * @param {SelectionService} selection
6388 * @param {Canvas} canvas
6389 */
6390 function SelectionVisuals(events, canvas, selection, styles) {
6391
6392 this._multiSelectionBox = null;
6393
6394 function addMarker(e, cls) {
6395 canvas.addMarker(e, cls);
6396 }
6397
6398 function removeMarker(e, cls) {
6399 canvas.removeMarker(e, cls);
6400 }
6401
6402 events.on('element.hover', function(event) {
6403 addMarker(event.element, MARKER_HOVER);
6404 });
6405
6406 events.on('element.out', function(event) {
6407 removeMarker(event.element, MARKER_HOVER);
6408 });
6409
6410 events.on('selection.changed', function(event) {
6411
6412 function deselect(s) {
6413 removeMarker(s, MARKER_SELECTED);
6414 }
6415
6416 function select(s) {
6417 addMarker(s, MARKER_SELECTED);
6418 }
6419
6420 var oldSelection = event.oldSelection,
6421 newSelection = event.newSelection;
6422
6423 forEach(oldSelection, function(e) {
6424 if (newSelection.indexOf(e) === -1) {
6425 deselect(e);
6426 }
6427 });
6428
6429 forEach(newSelection, function(e) {
6430 if (oldSelection.indexOf(e) === -1) {
6431 select(e);
6432 }
6433 });
6434 });
6435 }
6436
6437 SelectionVisuals.$inject = [
6438 'eventBus',
6439 'canvas',
6440 'selection',
6441 'styles'
6442 ];
6443
6444 function SelectionBehavior(eventBus, selection, canvas, elementRegistry) {
6445
6446 // Select elements on create
6447 eventBus.on('create.end', 500, function(event) {
6448 var context = event.context,
6449 canExecute = context.canExecute,
6450 elements = context.elements,
6451 hints = context.hints || {},
6452 autoSelect = hints.autoSelect;
6453
6454 if (canExecute) {
6455 if (autoSelect === false) {
6456
6457 // Select no elements
6458 return;
6459 }
6460
6461 if (isArray$1(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 // Select connection targets on connect
6472 eventBus.on('connect.end', 500, function(event) {
6473 var context = event.context,
6474 canExecute = context.canExecute,
6475 hover = context.hover;
6476
6477 if (canExecute && hover) {
6478 selection.select(hover);
6479 }
6480 });
6481
6482 // Select shapes on move
6483 eventBus.on('shape.move.end', 500, function(event) {
6484 var previousSelection = event.previousSelection || [];
6485
6486 var shape = elementRegistry.get(event.context.shape.id);
6487
6488 // Always select main shape on move
6489 var isSelected = find(previousSelection, function(selectedShape) {
6490 return shape.id === selectedShape.id;
6491 });
6492
6493 if (!isSelected) {
6494 selection.select(shape);
6495 }
6496 });
6497
6498 // Select elements on click
6499 eventBus.on('element.click', function(event) {
6500
6501 if (!isPrimaryButton(event)) {
6502 return;
6503 }
6504
6505 var element = event.element;
6506
6507 if (element === canvas.getRootElement()) {
6508 element = null;
6509 }
6510
6511 var isSelected = selection.isSelected(element),
6512 isMultiSelect = selection.get().length > 1;
6513
6514 // Add to selection if CTRL or SHIFT pressed
6515 var add = hasPrimaryModifier(event) || hasSecondaryModifier(event);
6516
6517 if (isSelected && isMultiSelect) {
6518 if (add) {
6519
6520 // Deselect element
6521 return selection.deselect(element);
6522 } else {
6523
6524 // Select element only
6525 return selection.select(element);
6526 }
6527 } else if (!isSelected) {
6528
6529 // Select element
6530 selection.select(element, add);
6531 } else {
6532
6533 // Deselect element
6534 selection.deselect(element);
6535 }
6536 });
6537 }
6538
6539 SelectionBehavior.$inject = [
6540 'eventBus',
6541 'selection',
6542 'canvas',
6543 'elementRegistry'
6544 ];
6545
6546
6547 function isShown(element) {
6548 return !element.hidden;
6549 }
6550
6551 var SelectionModule = {
6552 __init__: [ 'selectionVisuals', 'selectionBehavior' ],
6553 __depends__: [
6554 InteractionEventsModule,
6555 OutlineModule
6556 ],
6557 selection: [ 'type', Selection ],
6558 selectionVisuals: [ 'type', SelectionVisuals ],
6559 selectionBehavior: [ 'type', SelectionBehavior ]
6560 };
6561
6562 /**
6563 * Util that provides unique IDs.
6564 *
6565 * @class djs.util.IdGenerator
6566 * @constructor
6567 * @memberOf djs.util
6568 *
6569 * The ids can be customized via a given prefix and contain a random value to avoid collisions.
6570 *
6571 * @param {string} prefix a prefix to prepend to generated ids (for better readability)
6572 */
6573 function IdGenerator(prefix) {
6574
6575 this._counter = 0;
6576 this._prefix = (prefix ? prefix + '-' : '') + Math.floor(Math.random() * 1000000000) + '-';
6577 }
6578
6579 /**
6580 * Returns a next unique ID.
6581 *
6582 * @method djs.util.IdGenerator#next
6583 *
6584 * @returns {string} the id
6585 */
6586 IdGenerator.prototype.next = function() {
6587 return this._prefix + (++this._counter);
6588 };
6589
6590 // document wide unique overlay ids
6591 var ids = new IdGenerator('ov');
6592
6593 var LOW_PRIORITY = 500;
6594
6595
6596 /**
6597 * A service that allows users to attach overlays to diagram elements.
6598 *
6599 * The overlay service will take care of overlay positioning during updates.
6600 *
6601 * @example
6602 *
6603 * // add a pink badge on the top left of the shape
6604 * overlays.add(someShape, {
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 via shape id
6613 *
6614 * overlays.add('some-element-id', {
6615 * position: {
6616 * top: -5,
6617 * left: -5
6618 * }
6619 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
6620 * });
6621 *
6622 * // or add with optional type
6623 *
6624 * overlays.add(someShape, 'badge', {
6625 * position: {
6626 * top: -5,
6627 * left: -5
6628 * }
6629 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
6630 * });
6631 *
6632 *
6633 * // remove an overlay
6634 *
6635 * var id = overlays.add(...);
6636 * overlays.remove(id);
6637 *
6638 *
6639 * You may configure overlay defaults during tool by providing a `config` module
6640 * with `overlays.defaults` as an entry:
6641 *
6642 * {
6643 * overlays: {
6644 * defaults: {
6645 * show: {
6646 * minZoom: 0.7,
6647 * maxZoom: 5.0
6648 * },
6649 * scale: {
6650 * min: 1
6651 * }
6652 * }
6653 * }
6654 *
6655 * @param {Object} config
6656 * @param {EventBus} eventBus
6657 * @param {Canvas} canvas
6658 * @param {ElementRegistry} elementRegistry
6659 */
6660 function Overlays(config, eventBus, canvas, elementRegistry) {
6661
6662 this._eventBus = eventBus;
6663 this._canvas = canvas;
6664 this._elementRegistry = elementRegistry;
6665
6666 this._ids = ids;
6667
6668 this._overlayDefaults = assign({
6669
6670 // no show constraints
6671 show: null,
6672
6673 // always scale
6674 scale: true
6675 }, config && config.defaults);
6676
6677 /**
6678 * Mapping overlayId -> overlay
6679 */
6680 this._overlays = {};
6681
6682 /**
6683 * Mapping elementId -> overlay container
6684 */
6685 this._overlayContainers = [];
6686
6687 // root html element for all overlays
6688 this._overlayRoot = createRoot(canvas.getContainer());
6689
6690 this._init();
6691 }
6692
6693
6694 Overlays.$inject = [
6695 'config.overlays',
6696 'eventBus',
6697 'canvas',
6698 'elementRegistry'
6699 ];
6700
6701
6702 /**
6703 * Returns the overlay with the specified id or a list of overlays
6704 * for an element with a given type.
6705 *
6706 * @example
6707 *
6708 * // return the single overlay with the given id
6709 * overlays.get('some-id');
6710 *
6711 * // return all overlays for the shape
6712 * overlays.get({ element: someShape });
6713 *
6714 * // return all overlays on shape with type 'badge'
6715 * overlays.get({ element: someShape, type: 'badge' });
6716 *
6717 * // shape can also be specified as id
6718 * overlays.get({ element: 'element-id', type: 'badge' });
6719 *
6720 *
6721 * @param {Object} search
6722 * @param {string} [search.id]
6723 * @param {string|djs.model.Base} [search.element]
6724 * @param {string} [search.type]
6725 *
6726 * @return {Object|Array<Object>} the overlay(s)
6727 */
6728 Overlays.prototype.get = function(search) {
6729
6730 if (isString(search)) {
6731 search = { id: search };
6732 }
6733
6734 if (isString(search.element)) {
6735 search.element = this._elementRegistry.get(search.element);
6736 }
6737
6738 if (search.element) {
6739 var container = this._getOverlayContainer(search.element, true);
6740
6741 // return a list of overlays when searching by element (+type)
6742 if (container) {
6743 return search.type ? filter(container.overlays, matchPattern({ type: search.type })) : container.overlays.slice();
6744 } else {
6745 return [];
6746 }
6747 } else
6748 if (search.type) {
6749 return filter(this._overlays, matchPattern({ type: search.type }));
6750 } else {
6751
6752 // return single element when searching by id
6753 return search.id ? this._overlays[search.id] : null;
6754 }
6755 };
6756
6757 /**
6758 * Adds a HTML overlay to an element.
6759 *
6760 * @param {string|djs.model.Base} element attach overlay to this shape
6761 * @param {string} [type] optional type to assign to the overlay
6762 * @param {Object} overlay the overlay configuration
6763 *
6764 * @param {string|DOMElement} overlay.html html element to use as an overlay
6765 * @param {Object} [overlay.show] show configuration
6766 * @param {number} [overlay.show.minZoom] minimal zoom level to show the overlay
6767 * @param {number} [overlay.show.maxZoom] maximum zoom level to show the overlay
6768 * @param {Object} overlay.position where to attach the overlay
6769 * @param {number} [overlay.position.left] relative to element bbox left attachment
6770 * @param {number} [overlay.position.top] relative to element bbox top attachment
6771 * @param {number} [overlay.position.bottom] relative to element bbox bottom attachment
6772 * @param {number} [overlay.position.right] relative to element bbox right attachment
6773 * @param {boolean|Object} [overlay.scale=true] false to preserve the same size regardless of
6774 * diagram zoom
6775 * @param {number} [overlay.scale.min]
6776 * @param {number} [overlay.scale.max]
6777 *
6778 * @return {string} id that may be used to reference the overlay for update or removal
6779 */
6780 Overlays.prototype.add = function(element, type, overlay) {
6781
6782 if (isObject(type)) {
6783 overlay = type;
6784 type = null;
6785 }
6786
6787 if (!element.id) {
6788 element = this._elementRegistry.get(element);
6789 }
6790
6791 if (!overlay.position) {
6792 throw new Error('must specifiy overlay position');
6793 }
6794
6795 if (!overlay.html) {
6796 throw new Error('must specifiy overlay html');
6797 }
6798
6799 if (!element) {
6800 throw new Error('invalid element specified');
6801 }
6802
6803 var id = this._ids.next();
6804
6805 overlay = assign({}, this._overlayDefaults, overlay, {
6806 id: id,
6807 type: type,
6808 element: element,
6809 html: overlay.html
6810 });
6811
6812 this._addOverlay(overlay);
6813
6814 return id;
6815 };
6816
6817
6818 /**
6819 * Remove an overlay with the given id or all overlays matching the given filter.
6820 *
6821 * @see Overlays#get for filter options.
6822 *
6823 * @param {string} [id]
6824 * @param {Object} [filter]
6825 */
6826 Overlays.prototype.remove = function(filter) {
6827
6828 var overlays = this.get(filter) || [];
6829
6830 if (!isArray$1(overlays)) {
6831 overlays = [ overlays ];
6832 }
6833
6834 var self = this;
6835
6836 forEach(overlays, function(overlay) {
6837
6838 var container = self._getOverlayContainer(overlay.element, true);
6839
6840 if (overlay) {
6841 remove$1(overlay.html);
6842 remove$1(overlay.htmlContainer);
6843
6844 delete overlay.htmlContainer;
6845 delete overlay.element;
6846
6847 delete self._overlays[overlay.id];
6848 }
6849
6850 if (container) {
6851 var idx = container.overlays.indexOf(overlay);
6852 if (idx !== -1) {
6853 container.overlays.splice(idx, 1);
6854 }
6855 }
6856 });
6857
6858 };
6859
6860
6861 Overlays.prototype.show = function() {
6862 setVisible(this._overlayRoot);
6863 };
6864
6865
6866 Overlays.prototype.hide = function() {
6867 setVisible(this._overlayRoot, false);
6868 };
6869
6870 Overlays.prototype.clear = function() {
6871 this._overlays = {};
6872
6873 this._overlayContainers = [];
6874
6875 clear(this._overlayRoot);
6876 };
6877
6878 Overlays.prototype._updateOverlayContainer = function(container) {
6879 var element = container.element,
6880 html = container.html;
6881
6882 // update container left,top according to the elements x,y coordinates
6883 // this ensures we can attach child elements relative to this container
6884
6885 var x = element.x,
6886 y = element.y;
6887
6888 if (element.waypoints) {
6889 var bbox = getBBox(element);
6890 x = bbox.x;
6891 y = bbox.y;
6892 }
6893
6894 setPosition(html, x, y);
6895
6896 attr(container.html, 'data-container-id', element.id);
6897 };
6898
6899
6900 Overlays.prototype._updateOverlay = function(overlay) {
6901
6902 var position = overlay.position,
6903 htmlContainer = overlay.htmlContainer,
6904 element = overlay.element;
6905
6906 // update overlay html relative to shape because
6907 // it is already positioned on the element
6908
6909 // update relative
6910 var left = position.left,
6911 top = position.top;
6912
6913 if (position.right !== undefined) {
6914
6915 var width;
6916
6917 if (element.waypoints) {
6918 width = getBBox(element).width;
6919 } else {
6920 width = element.width;
6921 }
6922
6923 left = position.right * -1 + width;
6924 }
6925
6926 if (position.bottom !== undefined) {
6927
6928 var height;
6929
6930 if (element.waypoints) {
6931 height = getBBox(element).height;
6932 } else {
6933 height = element.height;
6934 }
6935
6936 top = position.bottom * -1 + height;
6937 }
6938
6939 setPosition(htmlContainer, left || 0, top || 0);
6940 };
6941
6942
6943 Overlays.prototype._createOverlayContainer = function(element) {
6944 var html = domify('<div class="djs-overlays" style="position: absolute" />');
6945
6946 this._overlayRoot.appendChild(html);
6947
6948 var container = {
6949 html: html,
6950 element: element,
6951 overlays: []
6952 };
6953
6954 this._updateOverlayContainer(container);
6955
6956 this._overlayContainers.push(container);
6957
6958 return container;
6959 };
6960
6961
6962 Overlays.prototype._updateRoot = function(viewbox) {
6963 var scale = viewbox.scale || 1;
6964
6965 var matrix = 'matrix(' +
6966 [
6967 scale,
6968 0,
6969 0,
6970 scale,
6971 -1 * viewbox.x * scale,
6972 -1 * viewbox.y * scale
6973 ].join(',') +
6974 ')';
6975
6976 setTransform(this._overlayRoot, matrix);
6977 };
6978
6979
6980 Overlays.prototype._getOverlayContainer = function(element, raw) {
6981 var container = find(this._overlayContainers, function(c) {
6982 return c.element === element;
6983 });
6984
6985
6986 if (!container && !raw) {
6987 return this._createOverlayContainer(element);
6988 }
6989
6990 return container;
6991 };
6992
6993
6994 Overlays.prototype._addOverlay = function(overlay) {
6995
6996 var id = overlay.id,
6997 element = overlay.element,
6998 html = overlay.html,
6999 htmlContainer,
7000 overlayContainer;
7001
7002 // unwrap jquery (for those who need it)
7003 if (html.get && html.constructor.prototype.jquery) {
7004 html = html.get(0);
7005 }
7006
7007 // create proper html elements from
7008 // overlay HTML strings
7009 if (isString(html)) {
7010 html = domify(html);
7011 }
7012
7013 overlayContainer = this._getOverlayContainer(element);
7014
7015 htmlContainer = domify('<div class="djs-overlay" data-overlay-id="' + id + '" style="position: absolute">');
7016
7017 htmlContainer.appendChild(html);
7018
7019 if (overlay.type) {
7020 classes(htmlContainer).add('djs-overlay-' + overlay.type);
7021 }
7022
7023 var plane = this._canvas.findPlane(element);
7024 var activePlane = this._canvas.getActivePlane();
7025 overlay.plane = plane;
7026 if (plane !== activePlane) {
7027 setVisible(htmlContainer, false);
7028 }
7029
7030 overlay.htmlContainer = htmlContainer;
7031
7032 overlayContainer.overlays.push(overlay);
7033 overlayContainer.html.appendChild(htmlContainer);
7034
7035 this._overlays[id] = overlay;
7036
7037 this._updateOverlay(overlay);
7038 this._updateOverlayVisibilty(overlay, this._canvas.viewbox());
7039 };
7040
7041
7042 Overlays.prototype._updateOverlayVisibilty = function(overlay, viewbox) {
7043 var show = overlay.show,
7044 minZoom = show && show.minZoom,
7045 maxZoom = show && show.maxZoom,
7046 htmlContainer = overlay.htmlContainer,
7047 visible = true;
7048
7049 if (show) {
7050 if (
7051 (isDefined(minZoom) && minZoom > viewbox.scale) ||
7052 (isDefined(maxZoom) && maxZoom < viewbox.scale)
7053 ) {
7054 visible = false;
7055 }
7056
7057 setVisible(htmlContainer, visible);
7058 }
7059
7060 this._updateOverlayScale(overlay, viewbox);
7061 };
7062
7063
7064 Overlays.prototype._updateOverlayScale = function(overlay, viewbox) {
7065 var shouldScale = overlay.scale,
7066 minScale,
7067 maxScale,
7068 htmlContainer = overlay.htmlContainer;
7069
7070 var scale, transform = '';
7071
7072 if (shouldScale !== true) {
7073
7074 if (shouldScale === false) {
7075 minScale = 1;
7076 maxScale = 1;
7077 } else {
7078 minScale = shouldScale.min;
7079 maxScale = shouldScale.max;
7080 }
7081
7082 if (isDefined(minScale) && viewbox.scale < minScale) {
7083 scale = (1 / viewbox.scale || 1) * minScale;
7084 }
7085
7086 if (isDefined(maxScale) && viewbox.scale > maxScale) {
7087 scale = (1 / viewbox.scale || 1) * maxScale;
7088 }
7089 }
7090
7091 if (isDefined(scale)) {
7092 transform = 'scale(' + scale + ',' + scale + ')';
7093 }
7094
7095 setTransform(htmlContainer, transform);
7096 };
7097
7098
7099 Overlays.prototype._updateOverlaysVisibilty = function(viewbox) {
7100
7101 var self = this;
7102
7103 forEach(this._overlays, function(overlay) {
7104 self._updateOverlayVisibilty(overlay, viewbox);
7105 });
7106 };
7107
7108
7109 Overlays.prototype._init = function() {
7110
7111 var eventBus = this._eventBus;
7112
7113 var self = this;
7114
7115
7116 // scroll/zoom integration
7117
7118 function updateViewbox(viewbox) {
7119 self._updateRoot(viewbox);
7120 self._updateOverlaysVisibilty(viewbox);
7121
7122 self.show();
7123 }
7124
7125 eventBus.on('canvas.viewbox.changing', function(event) {
7126 self.hide();
7127 });
7128
7129 eventBus.on('canvas.viewbox.changed', function(event) {
7130 updateViewbox(event.viewbox);
7131 });
7132
7133
7134 // remove integration
7135
7136 eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
7137 var element = e.element;
7138 var overlays = self.get({ element: element });
7139
7140 forEach(overlays, function(o) {
7141 self.remove(o.id);
7142 });
7143
7144 var container = self._getOverlayContainer(element);
7145
7146 if (container) {
7147 remove$1(container.html);
7148 var i = self._overlayContainers.indexOf(container);
7149 if (i !== -1) {
7150 self._overlayContainers.splice(i, 1);
7151 }
7152 }
7153 });
7154
7155
7156 // move integration
7157
7158 eventBus.on('element.changed', LOW_PRIORITY, function(e) {
7159 var element = e.element;
7160
7161 var container = self._getOverlayContainer(element, true);
7162
7163 if (container) {
7164 forEach(container.overlays, function(overlay) {
7165 self._updateOverlay(overlay);
7166 });
7167
7168 self._updateOverlayContainer(container);
7169 }
7170 });
7171
7172
7173 // marker integration, simply add them on the overlays as classes, too.
7174
7175 eventBus.on('element.marker.update', function(e) {
7176 var container = self._getOverlayContainer(e.element, true);
7177 if (container) {
7178 classes(container.html)[e.add ? 'add' : 'remove'](e.marker);
7179 }
7180 });
7181
7182
7183 eventBus.on('plane.set', function(e) {
7184 forEach(self._overlays, function(el) {
7185 setVisible(el.htmlContainer, el.plane === e.plane);
7186 });
7187 });
7188
7189 // clear overlays with diagram
7190
7191 eventBus.on('diagram.clear', this.clear, this);
7192 };
7193
7194
7195
7196 // helpers /////////////////////////////
7197
7198 function createRoot(parentNode) {
7199 var root = domify(
7200 '<div class="djs-overlay-container" style="position: absolute; width: 0; height: 0;" />'
7201 );
7202
7203 parentNode.insertBefore(root, parentNode.firstChild);
7204
7205 return root;
7206 }
7207
7208 function setPosition(el, x, y) {
7209 assign(el.style, { left: x + 'px', top: y + 'px' });
7210 }
7211
7212 function setVisible(el, visible) {
7213 el.style.display = visible === false ? 'none' : '';
7214 }
7215
7216 function setTransform(el, transform) {
7217
7218 el.style['transform-origin'] = 'top left';
7219
7220 [ '', '-ms-', '-webkit-' ].forEach(function(prefix) {
7221 el.style[prefix + 'transform'] = transform;
7222 });
7223 }
7224
7225 var OverlaysModule = {
7226 __init__: [ 'overlays' ],
7227 overlays: [ 'type', Overlays ]
7228 };
7229
7230 var CLASS_PATTERN = /^class /;
7231
7232 function isClass(fn) {
7233 return CLASS_PATTERN.test(fn.toString());
7234 }
7235
7236 function isArray(obj) {
7237 return Object.prototype.toString.call(obj) === '[object Array]';
7238 }
7239
7240 function hasOwnProp(obj, prop) {
7241 return Object.prototype.hasOwnProperty.call(obj, prop);
7242 }
7243
7244 function annotate() {
7245 var args = Array.prototype.slice.call(arguments);
7246
7247 if (args.length === 1 && isArray(args[0])) {
7248 args = args[0];
7249 }
7250
7251 var fn = args.pop();
7252
7253 fn.$inject = args;
7254
7255 return fn;
7256 }
7257
7258
7259 // Current limitations:
7260 // - can't put into "function arg" comments
7261 // function /* (no parenthesis like this) */ (){}
7262 // function abc( /* xx (no parenthesis like this) */ a, b) {}
7263 //
7264 // Just put the comment before function or inside:
7265 // /* (((this is fine))) */ function(a, b) {}
7266 // function abc(a) { /* (((this is fine))) */}
7267 //
7268 // - can't reliably auto-annotate constructor; we'll match the
7269 // first constructor(...) pattern found which may be the one
7270 // of a nested class, too.
7271
7272 var CONSTRUCTOR_ARGS = /constructor\s*[^(]*\(\s*([^)]*)\)/m;
7273 var FN_ARGS = /^(?:async )?(?:function\s*)?[^(]*\(\s*([^)]*)\)/m;
7274 var FN_ARG = /\/\*([^*]*)\*\//m;
7275
7276 function parseAnnotations(fn) {
7277
7278 if (typeof fn !== 'function') {
7279 throw new Error('Cannot annotate "' + fn + '". Expected a function!');
7280 }
7281
7282 var match = fn.toString().match(isClass(fn) ? CONSTRUCTOR_ARGS : FN_ARGS);
7283
7284 // may parse class without constructor
7285 if (!match) {
7286 return [];
7287 }
7288
7289 return match[1] && match[1].split(',').map(function(arg) {
7290 match = arg.match(FN_ARG);
7291 return match ? match[1].trim() : arg.trim();
7292 }) || [];
7293 }
7294
7295 function Module() {
7296 var providers = [];
7297
7298 this.factory = function(name, factory) {
7299 providers.push([name, 'factory', factory]);
7300 return this;
7301 };
7302
7303 this.value = function(name, value) {
7304 providers.push([name, 'value', value]);
7305 return this;
7306 };
7307
7308 this.type = function(name, type) {
7309 providers.push([name, 'type', type]);
7310 return this;
7311 };
7312
7313 this.forEach = function(iterator) {
7314 providers.forEach(iterator);
7315 };
7316
7317 }
7318
7319 function Injector(modules, parent) {
7320 parent = parent || {
7321 get: function(name, strict) {
7322 currentlyResolving.push(name);
7323
7324 if (strict === false) {
7325 return null;
7326 } else {
7327 throw error('No provider for "' + name + '"!');
7328 }
7329 }
7330 };
7331
7332 var currentlyResolving = [];
7333 var providers = this._providers = Object.create(parent._providers || null);
7334 var instances = this._instances = Object.create(null);
7335
7336 var self = instances.injector = this;
7337
7338 var error = function(msg) {
7339 var stack = currentlyResolving.join(' -> ');
7340 currentlyResolving.length = 0;
7341 return new Error(stack ? msg + ' (Resolving: ' + stack + ')' : msg);
7342 };
7343
7344 /**
7345 * Return a named service.
7346 *
7347 * @param {String} name
7348 * @param {Boolean} [strict=true] if false, resolve missing services to null
7349 *
7350 * @return {Object}
7351 */
7352 var get = function(name, strict) {
7353 if (!providers[name] && name.indexOf('.') !== -1) {
7354 var parts = name.split('.');
7355 var pivot = get(parts.shift());
7356
7357 while (parts.length) {
7358 pivot = pivot[parts.shift()];
7359 }
7360
7361 return pivot;
7362 }
7363
7364 if (hasOwnProp(instances, name)) {
7365 return instances[name];
7366 }
7367
7368 if (hasOwnProp(providers, name)) {
7369 if (currentlyResolving.indexOf(name) !== -1) {
7370 currentlyResolving.push(name);
7371 throw error('Cannot resolve circular dependency!');
7372 }
7373
7374 currentlyResolving.push(name);
7375 instances[name] = providers[name][0](providers[name][1]);
7376 currentlyResolving.pop();
7377
7378 return instances[name];
7379 }
7380
7381 return parent.get(name, strict);
7382 };
7383
7384 var fnDef = function(fn, locals) {
7385
7386 if (typeof locals === 'undefined') {
7387 locals = {};
7388 }
7389
7390 if (typeof fn !== 'function') {
7391 if (isArray(fn)) {
7392 fn = annotate(fn.slice());
7393 } else {
7394 throw new Error('Cannot invoke "' + fn + '". Expected a function!');
7395 }
7396 }
7397
7398 var inject = fn.$inject || parseAnnotations(fn);
7399 var dependencies = inject.map(function(dep) {
7400 if (hasOwnProp(locals, dep)) {
7401 return locals[dep];
7402 } else {
7403 return get(dep);
7404 }
7405 });
7406
7407 return {
7408 fn: fn,
7409 dependencies: dependencies
7410 };
7411 };
7412
7413 var instantiate = function(Type) {
7414 var def = fnDef(Type);
7415
7416 var fn = def.fn,
7417 dependencies = def.dependencies;
7418
7419 // instantiate var args constructor
7420 var Constructor = Function.prototype.bind.apply(fn, [ null ].concat(dependencies));
7421
7422 return new Constructor();
7423 };
7424
7425 var invoke = function(func, context, locals) {
7426 var def = fnDef(func, locals);
7427
7428 var fn = def.fn,
7429 dependencies = def.dependencies;
7430
7431 return fn.apply(context, dependencies);
7432 };
7433
7434
7435 var createPrivateInjectorFactory = function(privateChildInjector) {
7436 return annotate(function(key) {
7437 return privateChildInjector.get(key);
7438 });
7439 };
7440
7441 var createChild = function(modules, forceNewInstances) {
7442 if (forceNewInstances && forceNewInstances.length) {
7443 var fromParentModule = Object.create(null);
7444 var matchedScopes = Object.create(null);
7445
7446 var privateInjectorsCache = [];
7447 var privateChildInjectors = [];
7448 var privateChildFactories = [];
7449
7450 var provider;
7451 var cacheIdx;
7452 var privateChildInjector;
7453 var privateChildInjectorFactory;
7454 for (var name in providers) {
7455 provider = providers[name];
7456
7457 if (forceNewInstances.indexOf(name) !== -1) {
7458 if (provider[2] === 'private') {
7459 cacheIdx = privateInjectorsCache.indexOf(provider[3]);
7460 if (cacheIdx === -1) {
7461 privateChildInjector = provider[3].createChild([], forceNewInstances);
7462 privateChildInjectorFactory = createPrivateInjectorFactory(privateChildInjector);
7463 privateInjectorsCache.push(provider[3]);
7464 privateChildInjectors.push(privateChildInjector);
7465 privateChildFactories.push(privateChildInjectorFactory);
7466 fromParentModule[name] = [privateChildInjectorFactory, name, 'private', privateChildInjector];
7467 } else {
7468 fromParentModule[name] = [privateChildFactories[cacheIdx], name, 'private', privateChildInjectors[cacheIdx]];
7469 }
7470 } else {
7471 fromParentModule[name] = [provider[2], provider[1]];
7472 }
7473 matchedScopes[name] = true;
7474 }
7475
7476 if ((provider[2] === 'factory' || provider[2] === 'type') && provider[1].$scope) {
7477 /* jshint -W083 */
7478 forceNewInstances.forEach(function(scope) {
7479 if (provider[1].$scope.indexOf(scope) !== -1) {
7480 fromParentModule[name] = [provider[2], provider[1]];
7481 matchedScopes[scope] = true;
7482 }
7483 });
7484 }
7485 }
7486
7487 forceNewInstances.forEach(function(scope) {
7488 if (!matchedScopes[scope]) {
7489 throw new Error('No provider for "' + scope + '". Cannot use provider from the parent!');
7490 }
7491 });
7492
7493 modules.unshift(fromParentModule);
7494 }
7495
7496 return new Injector(modules, self);
7497 };
7498
7499 var factoryMap = {
7500 factory: invoke,
7501 type: instantiate,
7502 value: function(value) {
7503 return value;
7504 }
7505 };
7506
7507 modules.forEach(function(module) {
7508
7509 function arrayUnwrap(type, value) {
7510 if (type !== 'value' && isArray(value)) {
7511 value = annotate(value.slice());
7512 }
7513
7514 return value;
7515 }
7516
7517 // TODO(vojta): handle wrong inputs (modules)
7518 if (module instanceof Module) {
7519 module.forEach(function(provider) {
7520 var name = provider[0];
7521 var type = provider[1];
7522 var value = provider[2];
7523
7524 providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
7525 });
7526 } else if (typeof module === 'object') {
7527 if (module.__exports__) {
7528 var clonedModule = Object.keys(module).reduce(function(m, key) {
7529 if (key.substring(0, 2) !== '__') {
7530 m[key] = module[key];
7531 }
7532 return m;
7533 }, Object.create(null));
7534
7535 var privateInjector = new Injector((module.__modules__ || []).concat([clonedModule]), self);
7536 var getFromPrivateInjector = annotate(function(key) {
7537 return privateInjector.get(key);
7538 });
7539 module.__exports__.forEach(function(key) {
7540 providers[key] = [getFromPrivateInjector, key, 'private', privateInjector];
7541 });
7542 } else {
7543 Object.keys(module).forEach(function(name) {
7544 if (module[name][2] === 'private') {
7545 providers[name] = module[name];
7546 return;
7547 }
7548
7549 var type = module[name][0];
7550 var value = module[name][1];
7551
7552 providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
7553 });
7554 }
7555 }
7556 });
7557
7558 // public API
7559 this.get = get;
7560 this.invoke = invoke;
7561 this.instantiate = instantiate;
7562 this.createChild = createChild;
7563 }
7564
7565 // apply default renderer with lowest possible priority
7566 // so that it only kicks in if noone else could render
7567 var DEFAULT_RENDER_PRIORITY = 1;
7568
7569 /**
7570 * The default renderer used for shapes and connections.
7571 *
7572 * @param {EventBus} eventBus
7573 * @param {Styles} styles
7574 */
7575 function DefaultRenderer(eventBus, styles) {
7576
7577 //
7578 BaseRenderer.call(this, eventBus, DEFAULT_RENDER_PRIORITY);
7579
7580 this.CONNECTION_STYLE = styles.style([ 'no-fill' ], { strokeWidth: 5, stroke: 'fuchsia' });
7581 this.SHAPE_STYLE = styles.style({ fill: 'white', stroke: 'fuchsia', strokeWidth: 2 });
7582 this.FRAME_STYLE = styles.style([ 'no-fill' ], { stroke: 'fuchsia', strokeDasharray: 4, strokeWidth: 2 });
7583 }
7584
7585 inherits$1(DefaultRenderer, BaseRenderer);
7586
7587
7588 DefaultRenderer.prototype.canRender = function() {
7589 return true;
7590 };
7591
7592 DefaultRenderer.prototype.drawShape = function drawShape(visuals, element) {
7593 var rect = create$1('rect');
7594
7595 attr$1(rect, {
7596 x: 0,
7597 y: 0,
7598 width: element.width || 0,
7599 height: element.height || 0
7600 });
7601
7602 if (isFrameElement(element)) {
7603 attr$1(rect, this.FRAME_STYLE);
7604 } else {
7605 attr$1(rect, this.SHAPE_STYLE);
7606 }
7607
7608 append(visuals, rect);
7609
7610 return rect;
7611 };
7612
7613 DefaultRenderer.prototype.drawConnection = function drawConnection(visuals, connection) {
7614
7615 var line = createLine(connection.waypoints, this.CONNECTION_STYLE);
7616 append(visuals, line);
7617
7618 return line;
7619 };
7620
7621 DefaultRenderer.prototype.getShapePath = function getShapePath(shape) {
7622
7623 var x = shape.x,
7624 y = shape.y,
7625 width = shape.width,
7626 height = shape.height;
7627
7628 var shapePath = [
7629 ['M', x, y],
7630 ['l', width, 0],
7631 ['l', 0, height],
7632 ['l', -width, 0],
7633 ['z']
7634 ];
7635
7636 return componentsToPath(shapePath);
7637 };
7638
7639 DefaultRenderer.prototype.getConnectionPath = function getConnectionPath(connection) {
7640 var waypoints = connection.waypoints;
7641
7642 var idx, point, connectionPath = [];
7643
7644 for (idx = 0; (point = waypoints[idx]); idx++) {
7645
7646 // take invisible docking into account
7647 // when creating the path
7648 point = point.original || point;
7649
7650 connectionPath.push([ idx === 0 ? 'M' : 'L', point.x, point.y ]);
7651 }
7652
7653 return componentsToPath(connectionPath);
7654 };
7655
7656
7657 DefaultRenderer.$inject = [ 'eventBus', 'styles' ];
7658
7659 /**
7660 * A component that manages shape styles
7661 */
7662 function Styles() {
7663
7664 var defaultTraits = {
7665
7666 'no-fill': {
7667 fill: 'none'
7668 },
7669 'no-border': {
7670 strokeOpacity: 0.0
7671 },
7672 'no-events': {
7673 pointerEvents: 'none'
7674 }
7675 };
7676
7677 var self = this;
7678
7679 /**
7680 * Builds a style definition from a className, a list of traits and an object of additional attributes.
7681 *
7682 * @param {string} className
7683 * @param {Array<string>} traits
7684 * @param {Object} additionalAttrs
7685 *
7686 * @return {Object} the style defintion
7687 */
7688 this.cls = function(className, traits, additionalAttrs) {
7689 var attrs = this.style(traits, additionalAttrs);
7690
7691 return assign(attrs, { 'class': className });
7692 };
7693
7694 /**
7695 * Builds a style definition from a list of traits and an object of additional attributes.
7696 *
7697 * @param {Array<string>} traits
7698 * @param {Object} additionalAttrs
7699 *
7700 * @return {Object} the style defintion
7701 */
7702 this.style = function(traits, additionalAttrs) {
7703
7704 if (!isArray$1(traits) && !additionalAttrs) {
7705 additionalAttrs = traits;
7706 traits = [];
7707 }
7708
7709 var attrs = reduce(traits, function(attrs, t) {
7710 return assign(attrs, defaultTraits[t] || {});
7711 }, {});
7712
7713 return additionalAttrs ? assign(attrs, additionalAttrs) : attrs;
7714 };
7715
7716 this.computeStyle = function(custom, traits, defaultStyles) {
7717 if (!isArray$1(traits)) {
7718 defaultStyles = traits;
7719 traits = [];
7720 }
7721
7722 return self.style(traits || [], assign({}, defaultStyles, custom || {}));
7723 };
7724 }
7725
7726 var DrawModule = {
7727 __init__: [ 'defaultRenderer' ],
7728 defaultRenderer: [ 'type', DefaultRenderer ],
7729 styles: [ 'type', Styles ]
7730 };
7731
7732 /**
7733 * Failsafe remove an element from a collection
7734 *
7735 * @param {Array<Object>} [collection]
7736 * @param {Object} [element]
7737 *
7738 * @return {number} the previous index of the element
7739 */
7740 function remove(collection, element) {
7741
7742 if (!collection || !element) {
7743 return -1;
7744 }
7745
7746 var idx = collection.indexOf(element);
7747
7748 if (idx !== -1) {
7749 collection.splice(idx, 1);
7750 }
7751
7752 return idx;
7753 }
7754
7755 /**
7756 * Fail save add an element to the given connection, ensuring
7757 * it does not yet exist.
7758 *
7759 * @param {Array<Object>} collection
7760 * @param {Object} element
7761 * @param {number} idx
7762 */
7763 function add(collection, element, idx) {
7764
7765 if (!collection || !element) {
7766 return;
7767 }
7768
7769 if (typeof idx !== 'number') {
7770 idx = -1;
7771 }
7772
7773 var currentIdx = collection.indexOf(element);
7774
7775 if (currentIdx !== -1) {
7776
7777 if (currentIdx === idx) {
7778
7779 // nothing to do, position has not changed
7780 return;
7781 } else {
7782
7783 if (idx !== -1) {
7784
7785 // remove from current position
7786 collection.splice(currentIdx, 1);
7787 } else {
7788
7789 // already exists in collection
7790 return;
7791 }
7792 }
7793 }
7794
7795 if (idx !== -1) {
7796
7797 // insert at specified position
7798 collection.splice(idx, 0, element);
7799 } else {
7800
7801 // push to end
7802 collection.push(element);
7803 }
7804 }
7805
7806 function round(number, resolution) {
7807 return Math.round(number * resolution) / resolution;
7808 }
7809
7810 function ensurePx(number) {
7811 return isNumber(number) ? number + 'px' : number;
7812 }
7813
7814 function findRoot(element) {
7815 while (element.parent) {
7816 element = element.parent;
7817 }
7818
7819 return element;
7820 }
7821
7822 /**
7823 * Creates a HTML container element for a SVG element with
7824 * the given configuration
7825 *
7826 * @param {Object} options
7827 * @return {HTMLElement} the container element
7828 */
7829 function createContainer(options) {
7830
7831 options = assign({}, { width: '100%', height: '100%' }, options);
7832
7833 var container = options.container || document.body;
7834
7835 // create a <div> around the svg element with the respective size
7836 // this way we can always get the correct container size
7837 // (this is impossible for <svg> elements at the moment)
7838 var parent = document.createElement('div');
7839 parent.setAttribute('class', 'djs-container');
7840
7841 assign(parent.style, {
7842 position: 'relative',
7843 overflow: 'hidden',
7844 width: ensurePx(options.width),
7845 height: ensurePx(options.height)
7846 });
7847
7848 container.appendChild(parent);
7849
7850 return parent;
7851 }
7852
7853 function createGroup(parent, cls, childIndex) {
7854 var group = create$1('g');
7855 classes$1(group).add(cls);
7856
7857 var index = childIndex !== undefined ? childIndex : parent.childNodes.length - 1;
7858
7859 // must ensure second argument is node or _null_
7860 // cf. https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore
7861 parent.insertBefore(group, parent.childNodes[index] || null);
7862
7863 return group;
7864 }
7865
7866 var BASE_LAYER = 'base';
7867 var HIDDEN_MARKER = 'djs-element-hidden';
7868
7869
7870 var REQUIRED_MODEL_ATTRS = {
7871 shape: [ 'x', 'y', 'width', 'height' ],
7872 connection: [ 'waypoints' ]
7873 };
7874
7875 /**
7876 * The main drawing canvas.
7877 *
7878 * @class
7879 * @constructor
7880 *
7881 * @emits Canvas#canvas.init
7882 *
7883 * @param {Object} config
7884 * @param {EventBus} eventBus
7885 * @param {GraphicsFactory} graphicsFactory
7886 * @param {ElementRegistry} elementRegistry
7887 */
7888 function Canvas(config, eventBus, graphicsFactory, elementRegistry) {
7889
7890 this._eventBus = eventBus;
7891 this._elementRegistry = elementRegistry;
7892 this._graphicsFactory = graphicsFactory;
7893
7894 this._init(config || {});
7895 }
7896
7897 Canvas.$inject = [
7898 'config.canvas',
7899 'eventBus',
7900 'graphicsFactory',
7901 'elementRegistry'
7902 ];
7903
7904 /**
7905 * Creates a <svg> element that is wrapped into a <div>.
7906 * This way we are always able to correctly figure out the size of the svg element
7907 * by querying the parent node.
7908
7909 * (It is not possible to get the size of a svg element cross browser @ 2014-04-01)
7910
7911 * <div class="djs-container" style="width: {desired-width}, height: {desired-height}">
7912 * <svg width="100%" height="100%">
7913 * ...
7914 * </svg>
7915 * </div>
7916 */
7917 Canvas.prototype._init = function(config) {
7918
7919 var eventBus = this._eventBus;
7920
7921 // html container
7922 var container = this._container = createContainer(config);
7923
7924 var svg = this._svg = create$1('svg');
7925 attr$1(svg, { width: '100%', height: '100%' });
7926
7927 append(container, svg);
7928
7929 var viewport = this._viewport = createGroup(svg, 'viewport');
7930
7931 this._layers = {};
7932 this._planes = {};
7933
7934 // debounce canvas.viewbox.changed events
7935 // for smoother diagram interaction
7936 if (config.deferUpdate !== false) {
7937 this._viewboxChanged = debounce(bind$2(this._viewboxChanged, this), 300);
7938 }
7939
7940 eventBus.on('diagram.init', function() {
7941
7942 /**
7943 * An event indicating that the canvas is ready to be drawn on.
7944 *
7945 * @memberOf Canvas
7946 *
7947 * @event canvas.init
7948 *
7949 * @type {Object}
7950 * @property {SVGElement} svg the created svg element
7951 * @property {SVGElement} viewport the direct parent of diagram elements and shapes
7952 */
7953 eventBus.fire('canvas.init', {
7954 svg: svg,
7955 viewport: viewport
7956 });
7957
7958 }, this);
7959
7960 // reset viewbox on shape changes to
7961 // recompute the viewbox
7962 eventBus.on([
7963 'shape.added',
7964 'connection.added',
7965 'shape.removed',
7966 'connection.removed',
7967 'elements.changed'
7968 ], function() {
7969 delete this._cachedViewbox;
7970 }, this);
7971
7972 eventBus.on('diagram.destroy', 500, this._destroy, this);
7973 eventBus.on('diagram.clear', 500, this._clear, this);
7974 };
7975
7976 Canvas.prototype._destroy = function(emit) {
7977 this._eventBus.fire('canvas.destroy', {
7978 svg: this._svg,
7979 viewport: this._viewport
7980 });
7981
7982 var parent = this._container.parentNode;
7983
7984 if (parent) {
7985 parent.removeChild(this._container);
7986 }
7987
7988 delete this._svg;
7989 delete this._container;
7990 delete this._layers;
7991 delete this._planes;
7992 delete this._activePlane;
7993 delete this._viewport;
7994 };
7995
7996 Canvas.prototype._clear = function() {
7997
7998 var self = this;
7999
8000 var allElements = this._elementRegistry.getAll();
8001
8002 // remove all elements
8003 allElements.forEach(function(element) {
8004 var type = getType(element);
8005
8006 if (type === 'root') {
8007 self.setRootElementForPlane(null, self.findPlane(element), true);
8008 } else {
8009 self._removeElement(element, type);
8010 }
8011 });
8012
8013 // remove all planes
8014 this._activePlane = null;
8015 this._planes = {};
8016
8017 // force recomputation of view box
8018 delete this._cachedViewbox;
8019 };
8020
8021 /**
8022 * Returns the default layer on which
8023 * all elements are drawn.
8024 *
8025 * @returns {SVGElement}
8026 */
8027 Canvas.prototype.getDefaultLayer = function() {
8028 return this.getLayer(BASE_LAYER);
8029 };
8030
8031 /**
8032 * Returns a layer that is used to draw elements
8033 * or annotations on it.
8034 *
8035 * Non-existing layers retrieved through this method
8036 * will be created. During creation, the optional index
8037 * may be used to create layers below or above existing layers.
8038 * A layer with a certain index is always created above all
8039 * existing layers with the same index.
8040 *
8041 * @param {string} name
8042 * @param {number} index
8043 *
8044 * @returns {SVGElement}
8045 */
8046 Canvas.prototype.getLayer = function(name, index) {
8047
8048 if (!name) {
8049 throw new Error('must specify a name');
8050 }
8051
8052 var layer = this._layers[name];
8053
8054 if (!layer) {
8055 layer = this._layers[name] = this._createLayer(name, index);
8056 }
8057
8058 // throw an error if layer creation / retrival is
8059 // requested on different index
8060 if (typeof index !== 'undefined' && layer.index !== index) {
8061 throw new Error('layer <' + name + '> already created at index <' + index + '>');
8062 }
8063
8064 return layer.group;
8065 };
8066
8067 /**
8068 * Creates a given layer and returns it.
8069 *
8070 * @param {string} name
8071 * @param {number} [index=0]
8072 *
8073 * @return {Object} layer descriptor with { index, group: SVGGroup }
8074 */
8075 Canvas.prototype._createLayer = function(name, index) {
8076
8077 if (!index) {
8078 index = 0;
8079 }
8080
8081 var childIndex = reduce(this._layers, function(childIndex, layer) {
8082 if (index >= layer.index) {
8083 childIndex++;
8084 }
8085
8086 return childIndex;
8087 }, 0);
8088
8089 return {
8090 group: createGroup(this._viewport, 'layer-' + name, childIndex),
8091 index: index
8092 };
8093
8094 };
8095
8096 /**
8097 * Returns a plane that is used to draw elements on it.
8098 *
8099 * @param {string} name
8100 *
8101 * @return {Object} plane descriptor with { layer, rootElement, name }
8102 */
8103 Canvas.prototype.getPlane = function(name) {
8104 if (!name) {
8105 throw new Error('must specify a name');
8106 }
8107
8108 var plane = this._planes[name];
8109
8110 return plane;
8111 };
8112
8113 /**
8114 * Creates a plane that is used to draw elements on it. If no
8115 * root element is provided, an implicit root will be used.
8116 *
8117 * @param {string} name
8118 * @param {Object|djs.model.Root} [rootElement] optional root element
8119 *
8120 * @return {Object} plane descriptor with { layer, rootElement, name }
8121 */
8122 Canvas.prototype.createPlane = function(name, rootElement) {
8123 if (!name) {
8124 throw new Error('must specify a name');
8125 }
8126
8127 if (this._planes[name]) {
8128 throw new Error('plane ' + name + ' already exists');
8129 }
8130
8131 if (!rootElement) {
8132 rootElement = {
8133 id: '__implicitroot' + name,
8134 children: [],
8135 isImplicit: true
8136 };
8137 }
8138
8139 var svgLayer = this.getLayer(name);
8140 classes$1(svgLayer).add(HIDDEN_MARKER);
8141
8142 var plane = this._planes[name] = {
8143 layer: svgLayer,
8144 name: name,
8145 rootElement: null
8146 };
8147
8148 this.setRootElementForPlane(rootElement, plane);
8149
8150 return plane;
8151 };
8152
8153 /**
8154 * Sets the active plane and hides the previously active plane.
8155 *
8156 * @param {string|Object} plane
8157 *
8158 * @return {Object} plane descriptor with { layer, rootElement, name }
8159 */
8160 Canvas.prototype.setActivePlane = function(plane) {
8161 if (!plane) {
8162 throw new Error('must specify a plane');
8163 }
8164
8165 if (typeof plane === 'string') {
8166 plane = this.getPlane(plane);
8167 }
8168
8169 // hide previous Plane
8170 if (this._activePlane) {
8171 classes$1(this._activePlane.layer).add(HIDDEN_MARKER);
8172 }
8173
8174 this._activePlane = plane;
8175
8176 // show current Plane
8177 classes$1(plane.layer).remove(HIDDEN_MARKER);
8178
8179 if (plane.rootElement) {
8180 this._elementRegistry.updateGraphics(plane.rootElement, this._svg, true);
8181 }
8182
8183 this._eventBus.fire('plane.set', { plane: plane });
8184
8185 return plane;
8186 };
8187
8188 /**
8189 * Returns the currently active layer
8190 *
8191 * @returns {SVGElement}
8192 */
8193
8194 Canvas.prototype.getActiveLayer = function() {
8195 return this.getActivePlane().layer;
8196 };
8197
8198 /**
8199 * Returns the currently active plane.
8200 *
8201 * @return {Object} plane descriptor with { layer, rootElement, name }
8202 */
8203 Canvas.prototype.getActivePlane = function() {
8204 var plane = this._activePlane;
8205 if (!plane) {
8206 plane = this.createPlane(BASE_LAYER);
8207 this.setActivePlane(BASE_LAYER);
8208 }
8209
8210 return plane;
8211 };
8212
8213 /**
8214 * Returns the plane which contains the given element.
8215 *
8216 * @param {string|djs.model.Base} element
8217 *
8218 * @return {Object} plane descriptor with { layer, rootElement, name }
8219 */
8220 Canvas.prototype.findPlane = function(element) {
8221 if (typeof element === 'string') {
8222 element = this._elementRegistry.get(element);
8223 }
8224
8225 var root = findRoot(element);
8226
8227 return find(this._planes, function(plane) {
8228 return plane.rootElement === root;
8229 });
8230 };
8231
8232 /**
8233 * Returns the html element that encloses the
8234 * drawing canvas.
8235 *
8236 * @return {DOMNode}
8237 */
8238 Canvas.prototype.getContainer = function() {
8239 return this._container;
8240 };
8241
8242
8243 // markers //////////////////////
8244
8245 Canvas.prototype._updateMarker = function(element, marker, add) {
8246 var container;
8247
8248 if (!element.id) {
8249 element = this._elementRegistry.get(element);
8250 }
8251
8252 // we need to access all
8253 container = this._elementRegistry._elements[element.id];
8254
8255 if (!container) {
8256 return;
8257 }
8258
8259 forEach([ container.gfx, container.secondaryGfx ], function(gfx) {
8260 if (gfx) {
8261
8262 // invoke either addClass or removeClass based on mode
8263 if (add) {
8264 classes$1(gfx).add(marker);
8265 } else {
8266 classes$1(gfx).remove(marker);
8267 }
8268 }
8269 });
8270
8271 /**
8272 * An event indicating that a marker has been updated for an element
8273 *
8274 * @event element.marker.update
8275 * @type {Object}
8276 * @property {djs.model.Element} element the shape
8277 * @property {Object} gfx the graphical representation of the shape
8278 * @property {string} marker
8279 * @property {boolean} add true if the marker was added, false if it got removed
8280 */
8281 this._eventBus.fire('element.marker.update', { element: element, gfx: container.gfx, marker: marker, add: !!add });
8282 };
8283
8284
8285 /**
8286 * Adds a marker to an element (basically a css class).
8287 *
8288 * Fires the element.marker.update event, making it possible to
8289 * integrate extension into the marker life-cycle, too.
8290 *
8291 * @example
8292 * canvas.addMarker('foo', 'some-marker');
8293 *
8294 * var fooGfx = canvas.getGraphics('foo');
8295 *
8296 * fooGfx; // <g class="... some-marker"> ... </g>
8297 *
8298 * @param {string|djs.model.Base} element
8299 * @param {string} marker
8300 */
8301 Canvas.prototype.addMarker = function(element, marker) {
8302 this._updateMarker(element, marker, true);
8303 };
8304
8305
8306 /**
8307 * Remove a marker from an element.
8308 *
8309 * Fires the element.marker.update event, making it possible to
8310 * integrate extension into the marker life-cycle, too.
8311 *
8312 * @param {string|djs.model.Base} element
8313 * @param {string} marker
8314 */
8315 Canvas.prototype.removeMarker = function(element, marker) {
8316 this._updateMarker(element, marker, false);
8317 };
8318
8319 /**
8320 * Check the existence of a marker on element.
8321 *
8322 * @param {string|djs.model.Base} element
8323 * @param {string} marker
8324 */
8325 Canvas.prototype.hasMarker = function(element, marker) {
8326 if (!element.id) {
8327 element = this._elementRegistry.get(element);
8328 }
8329
8330 var gfx = this.getGraphics(element);
8331
8332 return classes$1(gfx).has(marker);
8333 };
8334
8335 /**
8336 * Toggles a marker on an element.
8337 *
8338 * Fires the element.marker.update event, making it possible to
8339 * integrate extension into the marker life-cycle, too.
8340 *
8341 * @param {string|djs.model.Base} element
8342 * @param {string} marker
8343 */
8344 Canvas.prototype.toggleMarker = function(element, marker) {
8345 if (this.hasMarker(element, marker)) {
8346 this.removeMarker(element, marker);
8347 } else {
8348 this.addMarker(element, marker);
8349 }
8350 };
8351
8352 Canvas.prototype.getRootElement = function() {
8353 var plane = this.getActivePlane();
8354
8355 return plane.rootElement;
8356 };
8357
8358
8359
8360 // root element handling //////////////////////
8361
8362 /**
8363 * Sets a given element as the new root element for the canvas
8364 * and returns the new root element.
8365 *
8366 * @param {Object|djs.model.Root} element
8367 * @param {boolean} [override] whether to override the current root element, if any
8368 *
8369 * @return {Object|djs.model.Root} new root element
8370 */
8371 Canvas.prototype.setRootElement = function(element, override) {
8372 var activePlane = this._activePlane;
8373
8374 if (activePlane) {
8375 return this.setRootElementForPlane(element, activePlane, override);
8376 } else {
8377 var basePlane = this.createPlane(BASE_LAYER, element);
8378
8379 this.setActivePlane(basePlane);
8380
8381 return basePlane.rootElement;
8382 }
8383 };
8384
8385
8386 /**
8387 * Sets a given element as the new root element for the canvas
8388 * and returns the new root element.
8389 *
8390 * @param {Object|djs.model.Root} element
8391 * @param {Object|djs.model.Root} plane
8392 * @param {boolean} [override] whether to override the current root element, if any
8393 *
8394 * @return {Object|djs.model.Root} new root element
8395 */
8396 Canvas.prototype.setRootElementForPlane = function(element, plane, override) {
8397
8398 if (typeof plane === 'string') {
8399 plane = this.getPlane(plane);
8400 }
8401
8402 if (element) {
8403 this._ensureValid('root', element);
8404 }
8405
8406 var currentRoot = plane.rootElement,
8407 elementRegistry = this._elementRegistry,
8408 eventBus = this._eventBus;
8409
8410 if (currentRoot) {
8411 if (!override) {
8412 throw new Error('rootElement already set, need to specify override');
8413 }
8414
8415 // simulate element remove event sequence
8416 eventBus.fire('root.remove', { element: currentRoot });
8417 eventBus.fire('root.removed', { element: currentRoot });
8418
8419 elementRegistry.remove(currentRoot);
8420 }
8421
8422 if (element) {
8423 var gfx = plane.layer;
8424
8425 // resemble element add event sequence
8426 eventBus.fire('root.add', { element: element });
8427
8428 elementRegistry.add(element, gfx);
8429
8430 eventBus.fire('root.added', { element: element, gfx: gfx });
8431
8432 // associate SVG with root element when active
8433 if (plane === this._activePlane) {
8434 this._elementRegistry.updateGraphics(element, this._svg, true);
8435 }
8436 }
8437
8438 plane.rootElement = element;
8439
8440 return element;
8441 };
8442
8443 // add functionality //////////////////////
8444
8445 Canvas.prototype._ensureValid = function(type, element) {
8446 if (!element.id) {
8447 throw new Error('element must have an id');
8448 }
8449
8450 if (this._elementRegistry.get(element.id)) {
8451 throw new Error('element with id ' + element.id + ' already exists');
8452 }
8453
8454 var requiredAttrs = REQUIRED_MODEL_ATTRS[type];
8455
8456 var valid = every(requiredAttrs, function(attr) {
8457 return typeof element[attr] !== 'undefined';
8458 });
8459
8460 if (!valid) {
8461 throw new Error(
8462 'must supply { ' + requiredAttrs.join(', ') + ' } with ' + type);
8463 }
8464 };
8465
8466 Canvas.prototype._setParent = function(element, parent, parentIndex) {
8467 add(parent.children, element, parentIndex);
8468 element.parent = parent;
8469 };
8470
8471 /**
8472 * Adds an element to the canvas.
8473 *
8474 * This wires the parent <-> child relationship between the element and
8475 * a explicitly specified parent or an implicit root element.
8476 *
8477 * During add it emits the events
8478 *
8479 * * <{type}.add> (element, parent)
8480 * * <{type}.added> (element, gfx)
8481 *
8482 * Extensions may hook into these events to perform their magic.
8483 *
8484 * @param {string} type
8485 * @param {Object|djs.model.Base} element
8486 * @param {Object|djs.model.Base} [parent]
8487 * @param {number} [parentIndex]
8488 *
8489 * @return {Object|djs.model.Base} the added element
8490 */
8491 Canvas.prototype._addElement = function(type, element, parent, parentIndex) {
8492
8493 parent = parent || this.getRootElement();
8494
8495 var eventBus = this._eventBus,
8496 graphicsFactory = this._graphicsFactory;
8497
8498 this._ensureValid(type, element);
8499
8500 eventBus.fire(type + '.add', { element: element, parent: parent });
8501
8502 this._setParent(element, parent, parentIndex);
8503
8504 // create graphics
8505 var gfx = graphicsFactory.create(type, element, parentIndex);
8506
8507 this._elementRegistry.add(element, gfx);
8508
8509 // update its visual
8510 graphicsFactory.update(type, element, gfx);
8511
8512 eventBus.fire(type + '.added', { element: element, gfx: gfx });
8513
8514 return element;
8515 };
8516
8517 /**
8518 * Adds a shape to the canvas
8519 *
8520 * @param {Object|djs.model.Shape} shape to add to the diagram
8521 * @param {djs.model.Base} [parent]
8522 * @param {number} [parentIndex]
8523 *
8524 * @return {djs.model.Shape} the added shape
8525 */
8526 Canvas.prototype.addShape = function(shape, parent, parentIndex) {
8527 return this._addElement('shape', shape, parent, parentIndex);
8528 };
8529
8530 /**
8531 * Adds a connection to the canvas
8532 *
8533 * @param {Object|djs.model.Connection} connection to add to the diagram
8534 * @param {djs.model.Base} [parent]
8535 * @param {number} [parentIndex]
8536 *
8537 * @return {djs.model.Connection} the added connection
8538 */
8539 Canvas.prototype.addConnection = function(connection, parent, parentIndex) {
8540 return this._addElement('connection', connection, parent, parentIndex);
8541 };
8542
8543
8544 /**
8545 * Internal remove element
8546 */
8547 Canvas.prototype._removeElement = function(element, type) {
8548
8549 var elementRegistry = this._elementRegistry,
8550 graphicsFactory = this._graphicsFactory,
8551 eventBus = this._eventBus;
8552
8553 element = elementRegistry.get(element.id || element);
8554
8555 if (!element) {
8556
8557 // element was removed already
8558 return;
8559 }
8560
8561 eventBus.fire(type + '.remove', { element: element });
8562
8563 graphicsFactory.remove(element);
8564
8565 // unset parent <-> child relationship
8566 remove(element.parent && element.parent.children, element);
8567 element.parent = null;
8568
8569 eventBus.fire(type + '.removed', { element: element });
8570
8571 elementRegistry.remove(element);
8572
8573 return element;
8574 };
8575
8576
8577 /**
8578 * Removes a shape from the canvas
8579 *
8580 * @param {string|djs.model.Shape} shape or shape id to be removed
8581 *
8582 * @return {djs.model.Shape} the removed shape
8583 */
8584 Canvas.prototype.removeShape = function(shape) {
8585
8586 /**
8587 * An event indicating that a shape is about to be removed from the canvas.
8588 *
8589 * @memberOf Canvas
8590 *
8591 * @event shape.remove
8592 * @type {Object}
8593 * @property {djs.model.Shape} element the shape descriptor
8594 * @property {Object} gfx the graphical representation of the shape
8595 */
8596
8597 /**
8598 * An event indicating that a shape has been removed from the canvas.
8599 *
8600 * @memberOf Canvas
8601 *
8602 * @event shape.removed
8603 * @type {Object}
8604 * @property {djs.model.Shape} element the shape descriptor
8605 * @property {Object} gfx the graphical representation of the shape
8606 */
8607 return this._removeElement(shape, 'shape');
8608 };
8609
8610
8611 /**
8612 * Removes a connection from the canvas
8613 *
8614 * @param {string|djs.model.Connection} connection or connection id to be removed
8615 *
8616 * @return {djs.model.Connection} the removed connection
8617 */
8618 Canvas.prototype.removeConnection = function(connection) {
8619
8620 /**
8621 * An event indicating that a connection is about to be removed from the canvas.
8622 *
8623 * @memberOf Canvas
8624 *
8625 * @event connection.remove
8626 * @type {Object}
8627 * @property {djs.model.Connection} element the connection descriptor
8628 * @property {Object} gfx the graphical representation of the connection
8629 */
8630
8631 /**
8632 * An event indicating that a connection has been removed from the canvas.
8633 *
8634 * @memberOf Canvas
8635 *
8636 * @event connection.removed
8637 * @type {Object}
8638 * @property {djs.model.Connection} element the connection descriptor
8639 * @property {Object} gfx the graphical representation of the connection
8640 */
8641 return this._removeElement(connection, 'connection');
8642 };
8643
8644
8645 /**
8646 * Return the graphical object underlaying a certain diagram element
8647 *
8648 * @param {string|djs.model.Base} element descriptor of the element
8649 * @param {boolean} [secondary=false] whether to return the secondary connected element
8650 *
8651 * @return {SVGElement}
8652 */
8653 Canvas.prototype.getGraphics = function(element, secondary) {
8654 return this._elementRegistry.getGraphics(element, secondary);
8655 };
8656
8657
8658 /**
8659 * Perform a viewbox update via a given change function.
8660 *
8661 * @param {Function} changeFn
8662 */
8663 Canvas.prototype._changeViewbox = function(changeFn) {
8664
8665 // notify others of the upcoming viewbox change
8666 this._eventBus.fire('canvas.viewbox.changing');
8667
8668 // perform actual change
8669 changeFn.apply(this);
8670
8671 // reset the cached viewbox so that
8672 // a new get operation on viewbox or zoom
8673 // triggers a viewbox re-computation
8674 this._cachedViewbox = null;
8675
8676 // notify others of the change; this step
8677 // may or may not be debounced
8678 this._viewboxChanged();
8679 };
8680
8681 Canvas.prototype._viewboxChanged = function() {
8682 this._eventBus.fire('canvas.viewbox.changed', { viewbox: this.viewbox() });
8683 };
8684
8685
8686 /**
8687 * Gets or sets the view box of the canvas, i.e. the
8688 * area that is currently displayed.
8689 *
8690 * The getter may return a cached viewbox (if it is currently
8691 * changing). To force a recomputation, pass `false` as the first argument.
8692 *
8693 * @example
8694 *
8695 * canvas.viewbox({ x: 100, y: 100, width: 500, height: 500 })
8696 *
8697 * // sets the visible area of the diagram to (100|100) -> (600|100)
8698 * // and and scales it according to the diagram width
8699 *
8700 * var viewbox = canvas.viewbox(); // pass `false` to force recomputing the box.
8701 *
8702 * console.log(viewbox);
8703 * // {
8704 * // inner: Dimensions,
8705 * // outer: Dimensions,
8706 * // scale,
8707 * // x, y,
8708 * // width, height
8709 * // }
8710 *
8711 * // if the current diagram is zoomed and scrolled, you may reset it to the
8712 * // default zoom via this method, too:
8713 *
8714 * var zoomedAndScrolledViewbox = canvas.viewbox();
8715 *
8716 * canvas.viewbox({
8717 * x: 0,
8718 * y: 0,
8719 * width: zoomedAndScrolledViewbox.outer.width,
8720 * height: zoomedAndScrolledViewbox.outer.height
8721 * });
8722 *
8723 * @param {Object} [box] the new view box to set
8724 * @param {number} box.x the top left X coordinate of the canvas visible in view box
8725 * @param {number} box.y the top left Y coordinate of the canvas visible in view box
8726 * @param {number} box.width the visible width
8727 * @param {number} box.height
8728 *
8729 * @return {Object} the current view box
8730 */
8731 Canvas.prototype.viewbox = function(box) {
8732
8733 if (box === undefined && this._cachedViewbox) {
8734 return this._cachedViewbox;
8735 }
8736
8737 var viewport = this._viewport,
8738 innerBox,
8739 outerBox = this.getSize(),
8740 matrix,
8741 transform,
8742 scale,
8743 x, y;
8744
8745 if (!box) {
8746
8747 // compute the inner box based on the
8748 // diagrams default layer. This allows us to exclude
8749 // external components, such as overlays
8750 innerBox = this.getDefaultLayer().getBBox();
8751
8752 transform = transform$1(viewport);
8753 matrix = transform ? transform.matrix : createMatrix();
8754 scale = round(matrix.a, 1000);
8755
8756 x = round(-matrix.e || 0, 1000);
8757 y = round(-matrix.f || 0, 1000);
8758
8759 box = this._cachedViewbox = {
8760 x: x ? x / scale : 0,
8761 y: y ? y / scale : 0,
8762 width: outerBox.width / scale,
8763 height: outerBox.height / scale,
8764 scale: scale,
8765 inner: {
8766 width: innerBox.width,
8767 height: innerBox.height,
8768 x: innerBox.x,
8769 y: innerBox.y
8770 },
8771 outer: outerBox
8772 };
8773
8774 return box;
8775 } else {
8776
8777 this._changeViewbox(function() {
8778 scale = Math.min(outerBox.width / box.width, outerBox.height / box.height);
8779
8780 var matrix = this._svg.createSVGMatrix()
8781 .scale(scale)
8782 .translate(-box.x, -box.y);
8783
8784 transform$1(viewport, matrix);
8785 });
8786 }
8787
8788 return box;
8789 };
8790
8791
8792 /**
8793 * Gets or sets the scroll of the canvas.
8794 *
8795 * @param {Object} [delta] the new scroll to apply.
8796 *
8797 * @param {number} [delta.dx]
8798 * @param {number} [delta.dy]
8799 */
8800 Canvas.prototype.scroll = function(delta) {
8801
8802 var node = this._viewport;
8803 var matrix = node.getCTM();
8804
8805 if (delta) {
8806 this._changeViewbox(function() {
8807 delta = assign({ dx: 0, dy: 0 }, delta || {});
8808
8809 matrix = this._svg.createSVGMatrix().translate(delta.dx, delta.dy).multiply(matrix);
8810
8811 setCTM(node, matrix);
8812 });
8813 }
8814
8815 return { x: matrix.e, y: matrix.f };
8816 };
8817
8818 /**
8819 * Scrolls the viewbox to contain the given element.
8820 * Optionally specify a padding to be applied to the edges.
8821 *
8822 * @param {Object} [element] the element to scroll to.
8823 * @param {Object|Number} [padding=100] the padding to be applied. Can also specify top, bottom, left and right.
8824 *
8825 */
8826 Canvas.prototype.scrollToElement = function(element, padding) {
8827 var defaultPadding = 100;
8828
8829 // switch to correct Plane
8830 var targetPlane = this.findPlane(element);
8831 if (targetPlane !== this._activePlane) {
8832 this.setActivePlane(targetPlane);
8833 }
8834
8835 if (!padding) {
8836 padding = {};
8837 }
8838 if (typeof padding === 'number') {
8839 defaultPadding = padding;
8840 }
8841
8842 padding = {
8843 top: padding.top || defaultPadding,
8844 right: padding.right || defaultPadding,
8845 bottom: padding.bottom || defaultPadding,
8846 left: padding.left || defaultPadding
8847 };
8848
8849 var elementBounds = getBBox(element),
8850 elementTrbl = asTRBL(elementBounds),
8851 viewboxBounds = this.viewbox(),
8852 zoom = this.zoom(),
8853 dx, dy;
8854
8855 // shrink viewboxBounds with padding
8856 viewboxBounds.y += padding.top / zoom;
8857 viewboxBounds.x += padding.left / zoom;
8858 viewboxBounds.width -= (padding.right + padding.left) / zoom;
8859 viewboxBounds.height -= (padding.bottom + padding.top) / zoom;
8860
8861 var viewboxTrbl = asTRBL(viewboxBounds);
8862
8863 var canFit = elementBounds.width < viewboxBounds.width && elementBounds.height < viewboxBounds.height;
8864
8865 if (!canFit) {
8866
8867 // top-left when element can't fit
8868 dx = elementBounds.x - viewboxBounds.x;
8869 dy = elementBounds.y - viewboxBounds.y;
8870
8871 } else {
8872
8873 var dRight = Math.max(0, elementTrbl.right - viewboxTrbl.right),
8874 dLeft = Math.min(0, elementTrbl.left - viewboxTrbl.left),
8875 dBottom = Math.max(0, elementTrbl.bottom - viewboxTrbl.bottom),
8876 dTop = Math.min(0, elementTrbl.top - viewboxTrbl.top);
8877
8878 dx = dRight || dLeft;
8879 dy = dBottom || dTop;
8880
8881 }
8882
8883 this.scroll({ dx: -dx * zoom, dy: -dy * zoom });
8884 };
8885
8886 /**
8887 * Gets or sets the current zoom of the canvas, optionally zooming
8888 * to the specified position.
8889 *
8890 * The getter may return a cached zoom level. Call it with `false` as
8891 * the first argument to force recomputation of the current level.
8892 *
8893 * @param {string|number} [newScale] the new zoom level, either a number, i.e. 0.9,
8894 * or `fit-viewport` to adjust the size to fit the current viewport
8895 * @param {string|Point} [center] the reference point { x: .., y: ..} to zoom to, 'auto' to zoom into mid or null
8896 *
8897 * @return {number} the current scale
8898 */
8899 Canvas.prototype.zoom = function(newScale, center) {
8900
8901 if (!newScale) {
8902 return this.viewbox(newScale).scale;
8903 }
8904
8905 if (newScale === 'fit-viewport') {
8906 return this._fitViewport(center);
8907 }
8908
8909 var outer,
8910 matrix;
8911
8912 this._changeViewbox(function() {
8913
8914 if (typeof center !== 'object') {
8915 outer = this.viewbox().outer;
8916
8917 center = {
8918 x: outer.width / 2,
8919 y: outer.height / 2
8920 };
8921 }
8922
8923 matrix = this._setZoom(newScale, center);
8924 });
8925
8926 return round(matrix.a, 1000);
8927 };
8928
8929 function setCTM(node, m) {
8930 var mstr = 'matrix(' + m.a + ',' + m.b + ',' + m.c + ',' + m.d + ',' + m.e + ',' + m.f + ')';
8931 node.setAttribute('transform', mstr);
8932 }
8933
8934 Canvas.prototype._fitViewport = function(center) {
8935
8936 var vbox = this.viewbox(),
8937 outer = vbox.outer,
8938 inner = vbox.inner,
8939 newScale,
8940 newViewbox;
8941
8942 // display the complete diagram without zooming in.
8943 // instead of relying on internal zoom, we perform a
8944 // hard reset on the canvas viewbox to realize this
8945 //
8946 // if diagram does not need to be zoomed in, we focus it around
8947 // the diagram origin instead
8948
8949 if (inner.x >= 0 &&
8950 inner.y >= 0 &&
8951 inner.x + inner.width <= outer.width &&
8952 inner.y + inner.height <= outer.height &&
8953 !center) {
8954
8955 newViewbox = {
8956 x: 0,
8957 y: 0,
8958 width: Math.max(inner.width + inner.x, outer.width),
8959 height: Math.max(inner.height + inner.y, outer.height)
8960 };
8961 } else {
8962
8963 newScale = Math.min(1, outer.width / inner.width, outer.height / inner.height);
8964 newViewbox = {
8965 x: inner.x + (center ? inner.width / 2 - outer.width / newScale / 2 : 0),
8966 y: inner.y + (center ? inner.height / 2 - outer.height / newScale / 2 : 0),
8967 width: outer.width / newScale,
8968 height: outer.height / newScale
8969 };
8970 }
8971
8972 this.viewbox(newViewbox);
8973
8974 return this.viewbox(false).scale;
8975 };
8976
8977
8978 Canvas.prototype._setZoom = function(scale, center) {
8979
8980 var svg = this._svg,
8981 viewport = this._viewport;
8982
8983 var matrix = svg.createSVGMatrix();
8984 var point = svg.createSVGPoint();
8985
8986 var centerPoint,
8987 originalPoint,
8988 currentMatrix,
8989 scaleMatrix,
8990 newMatrix;
8991
8992 currentMatrix = viewport.getCTM();
8993
8994 var currentScale = currentMatrix.a;
8995
8996 if (center) {
8997 centerPoint = assign(point, center);
8998
8999 // revert applied viewport transformations
9000 originalPoint = centerPoint.matrixTransform(currentMatrix.inverse());
9001
9002 // create scale matrix
9003 scaleMatrix = matrix
9004 .translate(originalPoint.x, originalPoint.y)
9005 .scale(1 / currentScale * scale)
9006 .translate(-originalPoint.x, -originalPoint.y);
9007
9008 newMatrix = currentMatrix.multiply(scaleMatrix);
9009 } else {
9010 newMatrix = matrix.scale(scale);
9011 }
9012
9013 setCTM(this._viewport, newMatrix);
9014
9015 return newMatrix;
9016 };
9017
9018
9019 /**
9020 * Returns the size of the canvas
9021 *
9022 * @return {Dimensions}
9023 */
9024 Canvas.prototype.getSize = function() {
9025 return {
9026 width: this._container.clientWidth,
9027 height: this._container.clientHeight
9028 };
9029 };
9030
9031
9032 /**
9033 * Return the absolute bounding box for the given element
9034 *
9035 * The absolute bounding box may be used to display overlays in the
9036 * callers (browser) coordinate system rather than the zoomed in/out
9037 * canvas coordinates.
9038 *
9039 * @param {ElementDescriptor} element
9040 * @return {Bounds} the absolute bounding box
9041 */
9042 Canvas.prototype.getAbsoluteBBox = function(element) {
9043 var vbox = this.viewbox();
9044 var bbox;
9045
9046 // connection
9047 // use svg bbox
9048 if (element.waypoints) {
9049 var gfx = this.getGraphics(element);
9050
9051 bbox = gfx.getBBox();
9052 }
9053
9054 // shapes
9055 // use data
9056 else {
9057 bbox = element;
9058 }
9059
9060 var x = bbox.x * vbox.scale - vbox.x * vbox.scale;
9061 var y = bbox.y * vbox.scale - vbox.y * vbox.scale;
9062
9063 var width = bbox.width * vbox.scale;
9064 var height = bbox.height * vbox.scale;
9065
9066 return {
9067 x: x,
9068 y: y,
9069 width: width,
9070 height: height
9071 };
9072 };
9073
9074 /**
9075 * Fires an event in order other modules can react to the
9076 * canvas resizing
9077 */
9078 Canvas.prototype.resized = function() {
9079
9080 // force recomputation of view box
9081 delete this._cachedViewbox;
9082
9083 this._eventBus.fire('canvas.resized');
9084 };
9085
9086 var ELEMENT_ID = 'data-element-id';
9087
9088
9089 /**
9090 * @class
9091 *
9092 * A registry that keeps track of all shapes in the diagram.
9093 */
9094 function ElementRegistry(eventBus) {
9095 this._elements = {};
9096
9097 this._eventBus = eventBus;
9098 }
9099
9100 ElementRegistry.$inject = [ 'eventBus' ];
9101
9102 /**
9103 * Register a pair of (element, gfx, (secondaryGfx)).
9104 *
9105 * @param {djs.model.Base} element
9106 * @param {SVGElement} gfx
9107 * @param {SVGElement} [secondaryGfx] optional other element to register, too
9108 */
9109 ElementRegistry.prototype.add = function(element, gfx, secondaryGfx) {
9110
9111 var id = element.id;
9112
9113 this._validateId(id);
9114
9115 // associate dom node with element
9116 attr$1(gfx, ELEMENT_ID, id);
9117
9118 if (secondaryGfx) {
9119 attr$1(secondaryGfx, ELEMENT_ID, id);
9120 }
9121
9122 this._elements[id] = { element: element, gfx: gfx, secondaryGfx: secondaryGfx };
9123 };
9124
9125 /**
9126 * Removes an element from the registry.
9127 *
9128 * @param {djs.model.Base} element
9129 */
9130 ElementRegistry.prototype.remove = function(element) {
9131 var elements = this._elements,
9132 id = element.id || element,
9133 container = id && elements[id];
9134
9135 if (container) {
9136
9137 // unset element id on gfx
9138 attr$1(container.gfx, ELEMENT_ID, '');
9139
9140 if (container.secondaryGfx) {
9141 attr$1(container.secondaryGfx, ELEMENT_ID, '');
9142 }
9143
9144 delete elements[id];
9145 }
9146 };
9147
9148 /**
9149 * Update the id of an element
9150 *
9151 * @param {djs.model.Base} element
9152 * @param {string} newId
9153 */
9154 ElementRegistry.prototype.updateId = function(element, newId) {
9155
9156 this._validateId(newId);
9157
9158 if (typeof element === 'string') {
9159 element = this.get(element);
9160 }
9161
9162 this._eventBus.fire('element.updateId', {
9163 element: element,
9164 newId: newId
9165 });
9166
9167 var gfx = this.getGraphics(element),
9168 secondaryGfx = this.getGraphics(element, true);
9169
9170 this.remove(element);
9171
9172 element.id = newId;
9173
9174 this.add(element, gfx, secondaryGfx);
9175 };
9176
9177 /**
9178 * Update the graphics of an element
9179 *
9180 * @param {djs.model.Base} element
9181 * @param {SVGElement} gfx
9182 * @param {boolean} [secondary=false] whether to update the secondary connected element
9183 */
9184 ElementRegistry.prototype.updateGraphics = function(filter, gfx, secondary) {
9185 var id = filter.id || filter;
9186
9187 var container = this._elements[id];
9188
9189 if (secondary) {
9190 container.secondaryGfx = gfx;
9191 } else {
9192 container.gfx = gfx;
9193 }
9194
9195 attr$1(gfx, ELEMENT_ID, id);
9196
9197 return gfx;
9198 };
9199
9200 /**
9201 * Return the model element for a given id or graphics.
9202 *
9203 * @example
9204 *
9205 * elementRegistry.get('SomeElementId_1');
9206 * elementRegistry.get(gfx);
9207 *
9208 *
9209 * @param {string|SVGElement} filter for selecting the element
9210 *
9211 * @return {djs.model.Base}
9212 */
9213 ElementRegistry.prototype.get = function(filter) {
9214 var id;
9215
9216 if (typeof filter === 'string') {
9217 id = filter;
9218 } else {
9219 id = filter && attr$1(filter, ELEMENT_ID);
9220 }
9221
9222 var container = this._elements[id];
9223 return container && container.element;
9224 };
9225
9226 /**
9227 * Return all elements that match a given filter function.
9228 *
9229 * @param {Function} fn
9230 *
9231 * @return {Array<djs.model.Base>}
9232 */
9233 ElementRegistry.prototype.filter = function(fn) {
9234
9235 var filtered = [];
9236
9237 this.forEach(function(element, gfx) {
9238 if (fn(element, gfx)) {
9239 filtered.push(element);
9240 }
9241 });
9242
9243 return filtered;
9244 };
9245
9246 /**
9247 * Return the first element that satisfies the provided testing function.
9248 *
9249 * @param {Function} fn
9250 *
9251 * @return {djs.model.Base}
9252 */
9253 ElementRegistry.prototype.find = function(fn) {
9254 var map = this._elements,
9255 keys = Object.keys(map);
9256
9257 for (var i = 0; i < keys.length; i++) {
9258 var id = keys[i],
9259 container = map[id],
9260 element = container.element,
9261 gfx = container.gfx;
9262
9263 if (fn(element, gfx)) {
9264 return element;
9265 }
9266 }
9267 };
9268
9269 /**
9270 * Return all rendered model elements.
9271 *
9272 * @return {Array<djs.model.Base>}
9273 */
9274 ElementRegistry.prototype.getAll = function() {
9275 return this.filter(function(e) { return e; });
9276 };
9277
9278 /**
9279 * Iterate over all diagram elements.
9280 *
9281 * @param {Function} fn
9282 */
9283 ElementRegistry.prototype.forEach = function(fn) {
9284
9285 var map = this._elements;
9286
9287 Object.keys(map).forEach(function(id) {
9288 var container = map[id],
9289 element = container.element,
9290 gfx = container.gfx;
9291
9292 return fn(element, gfx);
9293 });
9294 };
9295
9296 /**
9297 * Return the graphical representation of an element or its id.
9298 *
9299 * @example
9300 * elementRegistry.getGraphics('SomeElementId_1');
9301 * elementRegistry.getGraphics(rootElement); // <g ...>
9302 *
9303 * elementRegistry.getGraphics(rootElement, true); // <svg ...>
9304 *
9305 *
9306 * @param {string|djs.model.Base} filter
9307 * @param {boolean} [secondary=false] whether to return the secondary connected element
9308 *
9309 * @return {SVGElement}
9310 */
9311 ElementRegistry.prototype.getGraphics = function(filter, secondary) {
9312 var id = filter.id || filter;
9313
9314 var container = this._elements[id];
9315 return container && (secondary ? container.secondaryGfx : container.gfx);
9316 };
9317
9318 /**
9319 * Validate the suitability of the given id and signals a problem
9320 * with an exception.
9321 *
9322 * @param {string} id
9323 *
9324 * @throws {Error} if id is empty or already assigned
9325 */
9326 ElementRegistry.prototype._validateId = function(id) {
9327 if (!id) {
9328 throw new Error('element must have an id');
9329 }
9330
9331 if (this._elements[id]) {
9332 throw new Error('element with id ' + id + ' already added');
9333 }
9334 };
9335
9336 var objectRefs = {exports: {}};
9337
9338 var collection = {};
9339
9340 /**
9341 * An empty collection stub. Use {@link RefsCollection.extend} to extend a
9342 * collection with ref semantics.
9343 *
9344 * @class RefsCollection
9345 */
9346
9347 /**
9348 * Extends a collection with {@link Refs} aware methods
9349 *
9350 * @memberof RefsCollection
9351 * @static
9352 *
9353 * @param {Array<Object>} collection
9354 * @param {Refs} refs instance
9355 * @param {Object} property represented by the collection
9356 * @param {Object} target object the collection is attached to
9357 *
9358 * @return {RefsCollection<Object>} the extended array
9359 */
9360 function extend(collection, refs, property, target) {
9361
9362 var inverseProperty = property.inverse;
9363
9364 /**
9365 * Removes the given element from the array and returns it.
9366 *
9367 * @method RefsCollection#remove
9368 *
9369 * @param {Object} element the element to remove
9370 */
9371 Object.defineProperty(collection, 'remove', {
9372 value: function(element) {
9373 var idx = this.indexOf(element);
9374 if (idx !== -1) {
9375 this.splice(idx, 1);
9376
9377 // unset inverse
9378 refs.unset(element, inverseProperty, target);
9379 }
9380
9381 return element;
9382 }
9383 });
9384
9385 /**
9386 * Returns true if the collection contains the given element
9387 *
9388 * @method RefsCollection#contains
9389 *
9390 * @param {Object} element the element to check for
9391 */
9392 Object.defineProperty(collection, 'contains', {
9393 value: function(element) {
9394 return this.indexOf(element) !== -1;
9395 }
9396 });
9397
9398 /**
9399 * Adds an element to the array, unless it exists already (set semantics).
9400 *
9401 * @method RefsCollection#add
9402 *
9403 * @param {Object} element the element to add
9404 * @param {Number} optional index to add element to
9405 * (possibly moving other elements around)
9406 */
9407 Object.defineProperty(collection, 'add', {
9408 value: function(element, idx) {
9409
9410 var currentIdx = this.indexOf(element);
9411
9412 if (typeof idx === 'undefined') {
9413
9414 if (currentIdx !== -1) {
9415 // element already in collection (!)
9416 return;
9417 }
9418
9419 // add to end of array, as no idx is specified
9420 idx = this.length;
9421 }
9422
9423 // handle already in collection
9424 if (currentIdx !== -1) {
9425
9426 // remove element from currentIdx
9427 this.splice(currentIdx, 1);
9428 }
9429
9430 // add element at idx
9431 this.splice(idx, 0, element);
9432
9433 if (currentIdx === -1) {
9434 // set inverse, unless element was
9435 // in collection already
9436 refs.set(element, inverseProperty, target);
9437 }
9438 }
9439 });
9440
9441 // a simple marker, identifying this element
9442 // as being a refs collection
9443 Object.defineProperty(collection, '__refs_collection', {
9444 value: true
9445 });
9446
9447 return collection;
9448 }
9449
9450
9451 function isExtended(collection) {
9452 return collection.__refs_collection === true;
9453 }
9454
9455 collection.extend = extend;
9456
9457 collection.isExtended = isExtended;
9458
9459 var Collection = collection;
9460
9461 function hasOwnProperty$1(e, property) {
9462 return Object.prototype.hasOwnProperty.call(e, property.name || property);
9463 }
9464
9465 function defineCollectionProperty(ref, property, target) {
9466
9467 var collection = Collection.extend(target[property.name] || [], ref, property, target);
9468
9469 Object.defineProperty(target, property.name, {
9470 enumerable: property.enumerable,
9471 value: collection
9472 });
9473
9474 if (collection.length) {
9475
9476 collection.forEach(function(o) {
9477 ref.set(o, property.inverse, target);
9478 });
9479 }
9480 }
9481
9482
9483 function defineProperty$1(ref, property, target) {
9484
9485 var inverseProperty = property.inverse;
9486
9487 var _value = target[property.name];
9488
9489 Object.defineProperty(target, property.name, {
9490 configurable: property.configurable,
9491 enumerable: property.enumerable,
9492
9493 get: function() {
9494 return _value;
9495 },
9496
9497 set: function(value) {
9498
9499 // return if we already performed all changes
9500 if (value === _value) {
9501 return;
9502 }
9503
9504 var old = _value;
9505
9506 // temporary set null
9507 _value = null;
9508
9509 if (old) {
9510 ref.unset(old, inverseProperty, target);
9511 }
9512
9513 // set new value
9514 _value = value;
9515
9516 // set inverse value
9517 ref.set(_value, inverseProperty, target);
9518 }
9519 });
9520
9521 }
9522
9523 /**
9524 * Creates a new references object defining two inversly related
9525 * attribute descriptors a and b.
9526 *
9527 * <p>
9528 * When bound to an object using {@link Refs#bind} the references
9529 * get activated and ensure that add and remove operations are applied
9530 * reversely, too.
9531 * </p>
9532 *
9533 * <p>
9534 * For attributes represented as collections {@link Refs} provides the
9535 * {@link RefsCollection#add}, {@link RefsCollection#remove} and {@link RefsCollection#contains} extensions
9536 * that must be used to properly hook into the inverse change mechanism.
9537 * </p>
9538 *
9539 * @class Refs
9540 *
9541 * @classdesc A bi-directional reference between two attributes.
9542 *
9543 * @param {Refs.AttributeDescriptor} a property descriptor
9544 * @param {Refs.AttributeDescriptor} b property descriptor
9545 *
9546 * @example
9547 *
9548 * var refs = Refs({ name: 'wheels', collection: true, enumerable: true }, { name: 'car' });
9549 *
9550 * var car = { name: 'toyota' };
9551 * var wheels = [{ pos: 'front-left' }, { pos: 'front-right' }];
9552 *
9553 * refs.bind(car, 'wheels');
9554 *
9555 * car.wheels // []
9556 * car.wheels.add(wheels[0]);
9557 * car.wheels.add(wheels[1]);
9558 *
9559 * car.wheels // [{ pos: 'front-left' }, { pos: 'front-right' }]
9560 *
9561 * wheels[0].car // { name: 'toyota' };
9562 * car.wheels.remove(wheels[0]);
9563 *
9564 * wheels[0].car // undefined
9565 */
9566 function Refs$1(a, b) {
9567
9568 if (!(this instanceof Refs$1)) {
9569 return new Refs$1(a, b);
9570 }
9571
9572 // link
9573 a.inverse = b;
9574 b.inverse = a;
9575
9576 this.props = {};
9577 this.props[a.name] = a;
9578 this.props[b.name] = b;
9579 }
9580
9581 /**
9582 * Binds one side of a bi-directional reference to a
9583 * target object.
9584 *
9585 * @memberOf Refs
9586 *
9587 * @param {Object} target
9588 * @param {String} property
9589 */
9590 Refs$1.prototype.bind = function(target, property) {
9591 if (typeof property === 'string') {
9592 if (!this.props[property]) {
9593 throw new Error('no property <' + property + '> in ref');
9594 }
9595 property = this.props[property];
9596 }
9597
9598 if (property.collection) {
9599 defineCollectionProperty(this, property, target);
9600 } else {
9601 defineProperty$1(this, property, target);
9602 }
9603 };
9604
9605 Refs$1.prototype.ensureRefsCollection = function(target, property) {
9606
9607 var collection = target[property.name];
9608
9609 if (!Collection.isExtended(collection)) {
9610 defineCollectionProperty(this, property, target);
9611 }
9612
9613 return collection;
9614 };
9615
9616 Refs$1.prototype.ensureBound = function(target, property) {
9617 if (!hasOwnProperty$1(target, property)) {
9618 this.bind(target, property);
9619 }
9620 };
9621
9622 Refs$1.prototype.unset = function(target, property, value) {
9623
9624 if (target) {
9625 this.ensureBound(target, property);
9626
9627 if (property.collection) {
9628 this.ensureRefsCollection(target, property).remove(value);
9629 } else {
9630 target[property.name] = undefined;
9631 }
9632 }
9633 };
9634
9635 Refs$1.prototype.set = function(target, property, value) {
9636
9637 if (target) {
9638 this.ensureBound(target, property);
9639
9640 if (property.collection) {
9641 this.ensureRefsCollection(target, property).add(value);
9642 } else {
9643 target[property.name] = value;
9644 }
9645 }
9646 };
9647
9648 var refs = Refs$1;
9649
9650 objectRefs.exports = refs;
9651
9652 objectRefs.exports.Collection = collection;
9653
9654 var Refs = objectRefs.exports;
9655
9656 var parentRefs = new Refs({ name: 'children', enumerable: true, collection: true }, { name: 'parent' }),
9657 labelRefs = new Refs({ name: 'labels', enumerable: true, collection: true }, { name: 'labelTarget' }),
9658 attacherRefs = new Refs({ name: 'attachers', collection: true }, { name: 'host' }),
9659 outgoingRefs = new Refs({ name: 'outgoing', collection: true }, { name: 'source' }),
9660 incomingRefs = new Refs({ name: 'incoming', collection: true }, { name: 'target' });
9661
9662 /**
9663 * @namespace djs.model
9664 */
9665
9666 /**
9667 * @memberOf djs.model
9668 */
9669
9670 /**
9671 * The basic graphical representation
9672 *
9673 * @class
9674 *
9675 * @abstract
9676 */
9677 function Base$1() {
9678
9679 /**
9680 * The object that backs up the shape
9681 *
9682 * @name Base#businessObject
9683 * @type Object
9684 */
9685 Object.defineProperty(this, 'businessObject', {
9686 writable: true
9687 });
9688
9689
9690 /**
9691 * Single label support, will mapped to multi label array
9692 *
9693 * @name Base#label
9694 * @type Object
9695 */
9696 Object.defineProperty(this, 'label', {
9697 get: function() {
9698 return this.labels[0];
9699 },
9700 set: function(newLabel) {
9701
9702 var label = this.label,
9703 labels = this.labels;
9704
9705 if (!newLabel && label) {
9706 labels.remove(label);
9707 } else {
9708 labels.add(newLabel, 0);
9709 }
9710 }
9711 });
9712
9713 /**
9714 * The parent shape
9715 *
9716 * @name Base#parent
9717 * @type Shape
9718 */
9719 parentRefs.bind(this, 'parent');
9720
9721 /**
9722 * The list of labels
9723 *
9724 * @name Base#labels
9725 * @type Label
9726 */
9727 labelRefs.bind(this, 'labels');
9728
9729 /**
9730 * The list of outgoing connections
9731 *
9732 * @name Base#outgoing
9733 * @type Array<Connection>
9734 */
9735 outgoingRefs.bind(this, 'outgoing');
9736
9737 /**
9738 * The list of incoming connections
9739 *
9740 * @name Base#incoming
9741 * @type Array<Connection>
9742 */
9743 incomingRefs.bind(this, 'incoming');
9744 }
9745
9746
9747 /**
9748 * A graphical object
9749 *
9750 * @class
9751 * @constructor
9752 *
9753 * @extends Base
9754 */
9755 function Shape() {
9756 Base$1.call(this);
9757
9758 /**
9759 * Indicates frame shapes
9760 *
9761 * @name Shape#isFrame
9762 * @type boolean
9763 */
9764
9765 /**
9766 * The list of children
9767 *
9768 * @name Shape#children
9769 * @type Array<Base>
9770 */
9771 parentRefs.bind(this, 'children');
9772
9773 /**
9774 * @name Shape#host
9775 * @type Shape
9776 */
9777 attacherRefs.bind(this, 'host');
9778
9779 /**
9780 * @name Shape#attachers
9781 * @type Shape
9782 */
9783 attacherRefs.bind(this, 'attachers');
9784 }
9785
9786 inherits$1(Shape, Base$1);
9787
9788
9789 /**
9790 * A root graphical object
9791 *
9792 * @class
9793 * @constructor
9794 *
9795 * @extends Shape
9796 */
9797 function Root() {
9798 Shape.call(this);
9799 }
9800
9801 inherits$1(Root, Shape);
9802
9803
9804 /**
9805 * A label for an element
9806 *
9807 * @class
9808 * @constructor
9809 *
9810 * @extends Shape
9811 */
9812 function Label() {
9813 Shape.call(this);
9814
9815 /**
9816 * The labeled element
9817 *
9818 * @name Label#labelTarget
9819 * @type Base
9820 */
9821 labelRefs.bind(this, 'labelTarget');
9822 }
9823
9824 inherits$1(Label, Shape);
9825
9826
9827 /**
9828 * A connection between two elements
9829 *
9830 * @class
9831 * @constructor
9832 *
9833 * @extends Base
9834 */
9835 function Connection() {
9836 Base$1.call(this);
9837
9838 /**
9839 * The element this connection originates from
9840 *
9841 * @name Connection#source
9842 * @type Base
9843 */
9844 outgoingRefs.bind(this, 'source');
9845
9846 /**
9847 * The element this connection points to
9848 *
9849 * @name Connection#target
9850 * @type Base
9851 */
9852 incomingRefs.bind(this, 'target');
9853 }
9854
9855 inherits$1(Connection, Base$1);
9856
9857
9858 var types$6 = {
9859 connection: Connection,
9860 shape: Shape,
9861 label: Label,
9862 root: Root
9863 };
9864
9865 /**
9866 * Creates a new model element of the specified type
9867 *
9868 * @method create
9869 *
9870 * @example
9871 *
9872 * var shape1 = Model.create('shape', { x: 10, y: 10, width: 100, height: 100 });
9873 * var shape2 = Model.create('shape', { x: 210, y: 210, width: 100, height: 100 });
9874 *
9875 * var connection = Model.create('connection', { waypoints: [ { x: 110, y: 55 }, {x: 210, y: 55 } ] });
9876 *
9877 * @param {string} type lower-cased model name
9878 * @param {Object} attrs attributes to initialize the new model instance with
9879 *
9880 * @return {Base} the new model instance
9881 */
9882 function create(type, attrs) {
9883 var Type = types$6[type];
9884 if (!Type) {
9885 throw new Error('unknown type: <' + type + '>');
9886 }
9887 return assign(new Type(), attrs);
9888 }
9889
9890 /**
9891 * A factory for diagram-js shapes
9892 */
9893 function ElementFactory() {
9894 this._uid = 12;
9895 }
9896
9897
9898 ElementFactory.prototype.createRoot = function(attrs) {
9899 return this.create('root', attrs);
9900 };
9901
9902 ElementFactory.prototype.createLabel = function(attrs) {
9903 return this.create('label', attrs);
9904 };
9905
9906 ElementFactory.prototype.createShape = function(attrs) {
9907 return this.create('shape', attrs);
9908 };
9909
9910 ElementFactory.prototype.createConnection = function(attrs) {
9911 return this.create('connection', attrs);
9912 };
9913
9914 /**
9915 * Create a model element with the given type and
9916 * a number of pre-set attributes.
9917 *
9918 * @param {string} type
9919 * @param {Object} attrs
9920 * @return {djs.model.Base} the newly created model instance
9921 */
9922 ElementFactory.prototype.create = function(type, attrs) {
9923
9924 attrs = assign({}, attrs || {});
9925
9926 if (!attrs.id) {
9927 attrs.id = type + '_' + (this._uid++);
9928 }
9929
9930 return create(type, attrs);
9931 };
9932
9933 var FN_REF = '__fn';
9934
9935 var DEFAULT_PRIORITY = 1000;
9936
9937 var slice = Array.prototype.slice;
9938
9939 /**
9940 * A general purpose event bus.
9941 *
9942 * This component is used to communicate across a diagram instance.
9943 * Other parts of a diagram can use it to listen to and broadcast events.
9944 *
9945 *
9946 * ## Registering for Events
9947 *
9948 * The event bus provides the {@link EventBus#on} and {@link EventBus#once}
9949 * methods to register for events. {@link EventBus#off} can be used to
9950 * remove event registrations. Listeners receive an instance of {@link Event}
9951 * as the first argument. It allows them to hook into the event execution.
9952 *
9953 * ```javascript
9954 *
9955 * // listen for event
9956 * eventBus.on('foo', function(event) {
9957 *
9958 * // access event type
9959 * event.type; // 'foo'
9960 *
9961 * // stop propagation to other listeners
9962 * event.stopPropagation();
9963 *
9964 * // prevent event default
9965 * event.preventDefault();
9966 * });
9967 *
9968 * // listen for event with custom payload
9969 * eventBus.on('bar', function(event, payload) {
9970 * console.log(payload);
9971 * });
9972 *
9973 * // listen for event returning value
9974 * eventBus.on('foobar', function(event) {
9975 *
9976 * // stop event propagation + prevent default
9977 * return false;
9978 *
9979 * // stop event propagation + return custom result
9980 * return {
9981 * complex: 'listening result'
9982 * };
9983 * });
9984 *
9985 *
9986 * // listen with custom priority (default=1000, higher is better)
9987 * eventBus.on('priorityfoo', 1500, function(event) {
9988 * console.log('invoked first!');
9989 * });
9990 *
9991 *
9992 * // listen for event and pass the context (`this`)
9993 * eventBus.on('foobar', function(event) {
9994 * this.foo();
9995 * }, this);
9996 * ```
9997 *
9998 *
9999 * ## Emitting Events
10000 *
10001 * Events can be emitted via the event bus using {@link EventBus#fire}.
10002 *
10003 * ```javascript
10004 *
10005 * // false indicates that the default action
10006 * // was prevented by listeners
10007 * if (eventBus.fire('foo') === false) {
10008 * console.log('default has been prevented!');
10009 * };
10010 *
10011 *
10012 * // custom args + return value listener
10013 * eventBus.on('sum', function(event, a, b) {
10014 * return a + b;
10015 * });
10016 *
10017 * // you can pass custom arguments + retrieve result values.
10018 * var sum = eventBus.fire('sum', 1, 2);
10019 * console.log(sum); // 3
10020 * ```
10021 */
10022 function EventBus() {
10023 this._listeners = {};
10024
10025 // cleanup on destroy on lowest priority to allow
10026 // message passing until the bitter end
10027 this.on('diagram.destroy', 1, this._destroy, this);
10028 }
10029
10030
10031 /**
10032 * Register an event listener for events with the given name.
10033 *
10034 * The callback will be invoked with `event, ...additionalArguments`
10035 * that have been passed to {@link EventBus#fire}.
10036 *
10037 * Returning false from a listener will prevent the events default action
10038 * (if any is specified). To stop an event from being processed further in
10039 * other listeners execute {@link Event#stopPropagation}.
10040 *
10041 * Returning anything but `undefined` from a listener will stop the listener propagation.
10042 *
10043 * @param {string|Array<string>} events
10044 * @param {number} [priority=1000] the priority in which this listener is called, larger is higher
10045 * @param {Function} callback
10046 * @param {Object} [that] Pass context (`this`) to the callback
10047 */
10048 EventBus.prototype.on = function(events, priority, callback, that) {
10049
10050 events = isArray$1(events) ? events : [ events ];
10051
10052 if (isFunction(priority)) {
10053 that = callback;
10054 callback = priority;
10055 priority = DEFAULT_PRIORITY;
10056 }
10057
10058 if (!isNumber(priority)) {
10059 throw new Error('priority must be a number');
10060 }
10061
10062 var actualCallback = callback;
10063
10064 if (that) {
10065 actualCallback = bind$2(callback, that);
10066
10067 // make sure we remember and are able to remove
10068 // bound callbacks via {@link #off} using the original
10069 // callback
10070 actualCallback[FN_REF] = callback[FN_REF] || callback;
10071 }
10072
10073 var self = this;
10074
10075 events.forEach(function(e) {
10076 self._addListener(e, {
10077 priority: priority,
10078 callback: actualCallback,
10079 next: null
10080 });
10081 });
10082 };
10083
10084
10085 /**
10086 * Register an event listener that is executed only once.
10087 *
10088 * @param {string} event the event name to register for
10089 * @param {number} [priority=1000] the priority in which this listener is called, larger is higher
10090 * @param {Function} callback the callback to execute
10091 * @param {Object} [that] Pass context (`this`) to the callback
10092 */
10093 EventBus.prototype.once = function(event, priority, callback, that) {
10094 var self = this;
10095
10096 if (isFunction(priority)) {
10097 that = callback;
10098 callback = priority;
10099 priority = DEFAULT_PRIORITY;
10100 }
10101
10102 if (!isNumber(priority)) {
10103 throw new Error('priority must be a number');
10104 }
10105
10106 function wrappedCallback() {
10107 wrappedCallback.__isTomb = true;
10108
10109 var result = callback.apply(that, arguments);
10110
10111 self.off(event, wrappedCallback);
10112
10113 return result;
10114 }
10115
10116 // make sure we remember and are able to remove
10117 // bound callbacks via {@link #off} using the original
10118 // callback
10119 wrappedCallback[FN_REF] = callback;
10120
10121 this.on(event, priority, wrappedCallback);
10122 };
10123
10124
10125 /**
10126 * Removes event listeners by event and callback.
10127 *
10128 * If no callback is given, all listeners for a given event name are being removed.
10129 *
10130 * @param {string|Array<string>} events
10131 * @param {Function} [callback]
10132 */
10133 EventBus.prototype.off = function(events, callback) {
10134
10135 events = isArray$1(events) ? events : [ events ];
10136
10137 var self = this;
10138
10139 events.forEach(function(event) {
10140 self._removeListener(event, callback);
10141 });
10142
10143 };
10144
10145
10146 /**
10147 * Create an EventBus event.
10148 *
10149 * @param {Object} data
10150 *
10151 * @return {Object} event, recognized by the eventBus
10152 */
10153 EventBus.prototype.createEvent = function(data) {
10154 var event = new InternalEvent();
10155
10156 event.init(data);
10157
10158 return event;
10159 };
10160
10161
10162 /**
10163 * Fires a named event.
10164 *
10165 * @example
10166 *
10167 * // fire event by name
10168 * events.fire('foo');
10169 *
10170 * // fire event object with nested type
10171 * var event = { type: 'foo' };
10172 * events.fire(event);
10173 *
10174 * // fire event with explicit type
10175 * var event = { x: 10, y: 20 };
10176 * events.fire('element.moved', event);
10177 *
10178 * // pass additional arguments to the event
10179 * events.on('foo', function(event, bar) {
10180 * alert(bar);
10181 * });
10182 *
10183 * events.fire({ type: 'foo' }, 'I am bar!');
10184 *
10185 * @param {string} [name] the optional event name
10186 * @param {Object} [event] the event object
10187 * @param {...Object} additional arguments to be passed to the callback functions
10188 *
10189 * @return {boolean} the events return value, if specified or false if the
10190 * default action was prevented by listeners
10191 */
10192 EventBus.prototype.fire = function(type, data) {
10193 var event,
10194 firstListener,
10195 returnValue,
10196 args;
10197
10198 args = slice.call(arguments);
10199
10200 if (typeof type === 'object') {
10201 data = type;
10202 type = data.type;
10203 }
10204
10205 if (!type) {
10206 throw new Error('no event type specified');
10207 }
10208
10209 firstListener = this._listeners[type];
10210
10211 if (!firstListener) {
10212 return;
10213 }
10214
10215 // we make sure we fire instances of our home made
10216 // events here. We wrap them only once, though
10217 if (data instanceof InternalEvent) {
10218
10219 // we are fine, we alread have an event
10220 event = data;
10221 } else {
10222 event = this.createEvent(data);
10223 }
10224
10225 // ensure we pass the event as the first parameter
10226 args[0] = event;
10227
10228 // original event type (in case we delegate)
10229 var originalType = event.type;
10230
10231 // update event type before delegation
10232 if (type !== originalType) {
10233 event.type = type;
10234 }
10235
10236 try {
10237 returnValue = this._invokeListeners(event, args, firstListener);
10238 } finally {
10239
10240 // reset event type after delegation
10241 if (type !== originalType) {
10242 event.type = originalType;
10243 }
10244 }
10245
10246 // set the return value to false if the event default
10247 // got prevented and no other return value exists
10248 if (returnValue === undefined && event.defaultPrevented) {
10249 returnValue = false;
10250 }
10251
10252 return returnValue;
10253 };
10254
10255
10256 EventBus.prototype.handleError = function(error) {
10257 return this.fire('error', { error: error }) === false;
10258 };
10259
10260
10261 EventBus.prototype._destroy = function() {
10262 this._listeners = {};
10263 };
10264
10265 EventBus.prototype._invokeListeners = function(event, args, listener) {
10266
10267 var returnValue;
10268
10269 while (listener) {
10270
10271 // handle stopped propagation
10272 if (event.cancelBubble) {
10273 break;
10274 }
10275
10276 returnValue = this._invokeListener(event, args, listener);
10277
10278 listener = listener.next;
10279 }
10280
10281 return returnValue;
10282 };
10283
10284 EventBus.prototype._invokeListener = function(event, args, listener) {
10285
10286 var returnValue;
10287
10288 if (listener.callback.__isTomb) {
10289 return returnValue;
10290 }
10291
10292 try {
10293
10294 // returning false prevents the default action
10295 returnValue = invokeFunction(listener.callback, args);
10296
10297 // stop propagation on return value
10298 if (returnValue !== undefined) {
10299 event.returnValue = returnValue;
10300 event.stopPropagation();
10301 }
10302
10303 // prevent default on return false
10304 if (returnValue === false) {
10305 event.preventDefault();
10306 }
10307 } catch (error) {
10308 if (!this.handleError(error)) {
10309 console.error('unhandled error in event listener', error);
10310
10311 throw error;
10312 }
10313 }
10314
10315 return returnValue;
10316 };
10317
10318 /*
10319 * Add new listener with a certain priority to the list
10320 * of listeners (for the given event).
10321 *
10322 * The semantics of listener registration / listener execution are
10323 * first register, first serve: New listeners will always be inserted
10324 * after existing listeners with the same priority.
10325 *
10326 * Example: Inserting two listeners with priority 1000 and 1300
10327 *
10328 * * before: [ 1500, 1500, 1000, 1000 ]
10329 * * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ]
10330 *
10331 * @param {string} event
10332 * @param {Object} listener { priority, callback }
10333 */
10334 EventBus.prototype._addListener = function(event, newListener) {
10335
10336 var listener = this._getListeners(event),
10337 previousListener;
10338
10339 // no prior listeners
10340 if (!listener) {
10341 this._setListeners(event, newListener);
10342
10343 return;
10344 }
10345
10346 // ensure we order listeners by priority from
10347 // 0 (high) to n > 0 (low)
10348 while (listener) {
10349
10350 if (listener.priority < newListener.priority) {
10351
10352 newListener.next = listener;
10353
10354 if (previousListener) {
10355 previousListener.next = newListener;
10356 } else {
10357 this._setListeners(event, newListener);
10358 }
10359
10360 return;
10361 }
10362
10363 previousListener = listener;
10364 listener = listener.next;
10365 }
10366
10367 // add new listener to back
10368 previousListener.next = newListener;
10369 };
10370
10371
10372 EventBus.prototype._getListeners = function(name) {
10373 return this._listeners[name];
10374 };
10375
10376 EventBus.prototype._setListeners = function(name, listener) {
10377 this._listeners[name] = listener;
10378 };
10379
10380 EventBus.prototype._removeListener = function(event, callback) {
10381
10382 var listener = this._getListeners(event),
10383 nextListener,
10384 previousListener,
10385 listenerCallback;
10386
10387 if (!callback) {
10388
10389 // clear listeners
10390 this._setListeners(event, null);
10391
10392 return;
10393 }
10394
10395 while (listener) {
10396
10397 nextListener = listener.next;
10398
10399 listenerCallback = listener.callback;
10400
10401 if (listenerCallback === callback || listenerCallback[FN_REF] === callback) {
10402 if (previousListener) {
10403 previousListener.next = nextListener;
10404 } else {
10405
10406 // new first listener
10407 this._setListeners(event, nextListener);
10408 }
10409 }
10410
10411 previousListener = listener;
10412 listener = nextListener;
10413 }
10414 };
10415
10416 /**
10417 * A event that is emitted via the event bus.
10418 */
10419 function InternalEvent() { }
10420
10421 InternalEvent.prototype.stopPropagation = function() {
10422 this.cancelBubble = true;
10423 };
10424
10425 InternalEvent.prototype.preventDefault = function() {
10426 this.defaultPrevented = true;
10427 };
10428
10429 InternalEvent.prototype.init = function(data) {
10430 assign(this, data || {});
10431 };
10432
10433
10434 /**
10435 * Invoke function. Be fast...
10436 *
10437 * @param {Function} fn
10438 * @param {Array<Object>} args
10439 *
10440 * @return {Any}
10441 */
10442 function invokeFunction(fn, args) {
10443 return fn.apply(null, args);
10444 }
10445
10446 /**
10447 * SVGs for elements are generated by the {@link GraphicsFactory}.
10448 *
10449 * This utility gives quick access to the important semantic
10450 * parts of an element.
10451 */
10452
10453 /**
10454 * Returns the visual part of a diagram element
10455 *
10456 * @param {Snap<SVGElement>} gfx
10457 *
10458 * @return {Snap<SVGElement>}
10459 */
10460 function getVisual(gfx) {
10461 return gfx.childNodes[0];
10462 }
10463
10464 /**
10465 * Returns the children for a given diagram element.
10466 *
10467 * @param {Snap<SVGElement>} gfx
10468 * @return {Snap<SVGElement>}
10469 */
10470 function getChildren(gfx) {
10471 return gfx.parentNode.childNodes[1];
10472 }
10473
10474 /**
10475 * A factory that creates graphical elements
10476 *
10477 * @param {EventBus} eventBus
10478 * @param {ElementRegistry} elementRegistry
10479 */
10480 function GraphicsFactory(eventBus, elementRegistry) {
10481 this._eventBus = eventBus;
10482 this._elementRegistry = elementRegistry;
10483 }
10484
10485 GraphicsFactory.$inject = [ 'eventBus' , 'elementRegistry' ];
10486
10487
10488 GraphicsFactory.prototype._getChildrenContainer = function(element) {
10489
10490 var gfx = this._elementRegistry.getGraphics(element);
10491
10492 var childrenGfx;
10493
10494 // root element
10495 if (!element.parent) {
10496 childrenGfx = gfx;
10497 } else {
10498 childrenGfx = getChildren(gfx);
10499 if (!childrenGfx) {
10500 childrenGfx = create$1('g');
10501 classes$1(childrenGfx).add('djs-children');
10502
10503 append(gfx.parentNode, childrenGfx);
10504 }
10505 }
10506
10507 return childrenGfx;
10508 };
10509
10510 /**
10511 * Clears the graphical representation of the element and returns the
10512 * cleared visual (the <g class="djs-visual" /> element).
10513 */
10514 GraphicsFactory.prototype._clear = function(gfx) {
10515 var visual = getVisual(gfx);
10516
10517 clear(visual);
10518
10519 return visual;
10520 };
10521
10522 /**
10523 * Creates a gfx container for shapes and connections
10524 *
10525 * The layout is as follows:
10526 *
10527 * <g class="djs-group">
10528 *
10529 * <!-- the gfx -->
10530 * <g class="djs-element djs-(shape|connection|frame)">
10531 * <g class="djs-visual">
10532 * <!-- the renderer draws in here -->
10533 * </g>
10534 *
10535 * <!-- extensions (overlays, click box, ...) goes here
10536 * </g>
10537 *
10538 * <!-- the gfx child nodes -->
10539 * <g class="djs-children"></g>
10540 * </g>
10541 *
10542 * @param {string} type the type of the element, i.e. shape | connection
10543 * @param {SVGElement} [childrenGfx]
10544 * @param {number} [parentIndex] position to create container in parent
10545 * @param {boolean} [isFrame] is frame element
10546 *
10547 * @return {SVGElement}
10548 */
10549 GraphicsFactory.prototype._createContainer = function(
10550 type, childrenGfx, parentIndex, isFrame
10551 ) {
10552 var outerGfx = create$1('g');
10553 classes$1(outerGfx).add('djs-group');
10554
10555 // insert node at position
10556 if (typeof parentIndex !== 'undefined') {
10557 prependTo(outerGfx, childrenGfx, childrenGfx.childNodes[parentIndex]);
10558 } else {
10559 append(childrenGfx, outerGfx);
10560 }
10561
10562 var gfx = create$1('g');
10563 classes$1(gfx).add('djs-element');
10564 classes$1(gfx).add('djs-' + type);
10565
10566 if (isFrame) {
10567 classes$1(gfx).add('djs-frame');
10568 }
10569
10570 append(outerGfx, gfx);
10571
10572 // create visual
10573 var visual = create$1('g');
10574 classes$1(visual).add('djs-visual');
10575
10576 append(gfx, visual);
10577
10578 return gfx;
10579 };
10580
10581 GraphicsFactory.prototype.create = function(type, element, parentIndex) {
10582 var childrenGfx = this._getChildrenContainer(element.parent);
10583 return this._createContainer(type, childrenGfx, parentIndex, isFrameElement(element));
10584 };
10585
10586 GraphicsFactory.prototype.updateContainments = function(elements) {
10587
10588 var self = this,
10589 elementRegistry = this._elementRegistry,
10590 parents;
10591
10592 parents = reduce(elements, function(map, e) {
10593
10594 if (e.parent) {
10595 map[e.parent.id] = e.parent;
10596 }
10597
10598 return map;
10599 }, {});
10600
10601 // update all parents of changed and reorganized their children
10602 // in the correct order (as indicated in our model)
10603 forEach(parents, function(parent) {
10604
10605 var children = parent.children;
10606
10607 if (!children) {
10608 return;
10609 }
10610
10611 var childrenGfx = self._getChildrenContainer(parent);
10612
10613 forEach(children.slice().reverse(), function(child) {
10614 var childGfx = elementRegistry.getGraphics(child);
10615
10616 prependTo(childGfx.parentNode, childrenGfx);
10617 });
10618 });
10619 };
10620
10621 GraphicsFactory.prototype.drawShape = function(visual, element) {
10622 var eventBus = this._eventBus;
10623
10624 return eventBus.fire('render.shape', { gfx: visual, element: element });
10625 };
10626
10627 GraphicsFactory.prototype.getShapePath = function(element) {
10628 var eventBus = this._eventBus;
10629
10630 return eventBus.fire('render.getShapePath', element);
10631 };
10632
10633 GraphicsFactory.prototype.drawConnection = function(visual, element) {
10634 var eventBus = this._eventBus;
10635
10636 return eventBus.fire('render.connection', { gfx: visual, element: element });
10637 };
10638
10639 GraphicsFactory.prototype.getConnectionPath = function(waypoints) {
10640 var eventBus = this._eventBus;
10641
10642 return eventBus.fire('render.getConnectionPath', waypoints);
10643 };
10644
10645 GraphicsFactory.prototype.update = function(type, element, gfx) {
10646
10647 // do NOT update root element
10648 if (!element.parent) {
10649 return;
10650 }
10651
10652 var visual = this._clear(gfx);
10653
10654 // redraw
10655 if (type === 'shape') {
10656 this.drawShape(visual, element);
10657
10658 // update positioning
10659 translate$1(gfx, element.x, element.y);
10660 } else
10661 if (type === 'connection') {
10662 this.drawConnection(visual, element);
10663 } else {
10664 throw new Error('unknown type: ' + type);
10665 }
10666
10667 if (element.hidden) {
10668 attr$1(gfx, 'display', 'none');
10669 } else {
10670 attr$1(gfx, 'display', 'block');
10671 }
10672 };
10673
10674 GraphicsFactory.prototype.remove = function(element) {
10675 var gfx = this._elementRegistry.getGraphics(element);
10676
10677 // remove
10678 remove$2(gfx.parentNode);
10679 };
10680
10681
10682 // helpers //////////
10683
10684 function prependTo(newNode, parentNode, siblingNode) {
10685 var node = siblingNode || parentNode.firstChild;
10686
10687 // do not prepend node to itself to prevent IE from crashing
10688 // https://github.com/bpmn-io/bpmn-js/issues/746
10689 if (newNode === node) {
10690 return;
10691 }
10692
10693 parentNode.insertBefore(newNode, node);
10694 }
10695
10696 var CoreModule = {
10697 __depends__: [ DrawModule ],
10698 __init__: [ 'canvas' ],
10699 canvas: [ 'type', Canvas ],
10700 elementRegistry: [ 'type', ElementRegistry ],
10701 elementFactory: [ 'type', ElementFactory ],
10702 eventBus: [ 'type', EventBus ],
10703 graphicsFactory: [ 'type', GraphicsFactory ]
10704 };
10705
10706 /**
10707 * Bootstrap an injector from a list of modules, instantiating a number of default components
10708 *
10709 * @ignore
10710 * @param {Array<didi.Module>} bootstrapModules
10711 *
10712 * @return {didi.Injector} a injector to use to access the components
10713 */
10714 function bootstrap(bootstrapModules) {
10715
10716 var modules = [],
10717 components = [];
10718
10719 function hasModule(m) {
10720 return modules.indexOf(m) >= 0;
10721 }
10722
10723 function addModule(m) {
10724 modules.push(m);
10725 }
10726
10727 function visit(m) {
10728 if (hasModule(m)) {
10729 return;
10730 }
10731
10732 (m.__depends__ || []).forEach(visit);
10733
10734 if (hasModule(m)) {
10735 return;
10736 }
10737
10738 addModule(m);
10739
10740 (m.__init__ || []).forEach(function(c) {
10741 components.push(c);
10742 });
10743 }
10744
10745 bootstrapModules.forEach(visit);
10746
10747 var injector = new Injector(modules);
10748
10749 components.forEach(function(c) {
10750
10751 try {
10752
10753 // eagerly resolve component (fn or string)
10754 injector[typeof c === 'string' ? 'get' : 'invoke'](c);
10755 } catch (e) {
10756 console.error('Failed to instantiate component');
10757 console.error(e.stack);
10758
10759 throw e;
10760 }
10761 });
10762
10763 return injector;
10764 }
10765
10766 /**
10767 * Creates an injector from passed options.
10768 *
10769 * @ignore
10770 * @param {Object} options
10771 * @return {didi.Injector}
10772 */
10773 function createInjector(options) {
10774
10775 options = options || {};
10776
10777 var configModule = {
10778 'config': ['value', options]
10779 };
10780
10781 var modules = [ configModule, CoreModule ].concat(options.modules || []);
10782
10783 return bootstrap(modules);
10784 }
10785
10786
10787 /**
10788 * The main diagram-js entry point that bootstraps the diagram with the given
10789 * configuration.
10790 *
10791 * To register extensions with the diagram, pass them as Array<didi.Module> to the constructor.
10792 *
10793 * @class djs.Diagram
10794 * @memberOf djs
10795 * @constructor
10796 *
10797 * @example
10798 *
10799 * <caption>Creating a plug-in that logs whenever a shape is added to the canvas.</caption>
10800 *
10801 * // plug-in implemenentation
10802 * function MyLoggingPlugin(eventBus) {
10803 * eventBus.on('shape.added', function(event) {
10804 * console.log('shape ', event.shape, ' was added to the diagram');
10805 * });
10806 * }
10807 *
10808 * // export as module
10809 * export default {
10810 * __init__: [ 'myLoggingPlugin' ],
10811 * myLoggingPlugin: [ 'type', MyLoggingPlugin ]
10812 * };
10813 *
10814 *
10815 * // instantiate the diagram with the new plug-in
10816 *
10817 * import MyLoggingModule from 'path-to-my-logging-plugin';
10818 *
10819 * var diagram = new Diagram({
10820 * modules: [
10821 * MyLoggingModule
10822 * ]
10823 * });
10824 *
10825 * diagram.invoke([ 'canvas', function(canvas) {
10826 * // add shape to drawing canvas
10827 * canvas.addShape({ x: 10, y: 10 });
10828 * });
10829 *
10830 * // 'shape ... was added to the diagram' logged to console
10831 *
10832 * @param {Object} options
10833 * @param {Array<didi.Module>} [options.modules] external modules to instantiate with the diagram
10834 * @param {didi.Injector} [injector] an (optional) injector to bootstrap the diagram with
10835 */
10836 function Diagram(options, injector) {
10837
10838 // create injector unless explicitly specified
10839 this.injector = injector = injector || createInjector(options);
10840
10841 // API
10842
10843 /**
10844 * Resolves a diagram service
10845 *
10846 * @method Diagram#get
10847 *
10848 * @param {string} name the name of the diagram service to be retrieved
10849 * @param {boolean} [strict=true] if false, resolve missing services to null
10850 */
10851 this.get = injector.get;
10852
10853 /**
10854 * Executes a function into which diagram services are injected
10855 *
10856 * @method Diagram#invoke
10857 *
10858 * @param {Function|Object[]} fn the function to resolve
10859 * @param {Object} locals a number of locals to use to resolve certain dependencies
10860 */
10861 this.invoke = injector.invoke;
10862
10863 // init
10864
10865 // indicate via event
10866
10867
10868 /**
10869 * An event indicating that all plug-ins are loaded.
10870 *
10871 * Use this event to fire other events to interested plug-ins
10872 *
10873 * @memberOf Diagram
10874 *
10875 * @event diagram.init
10876 *
10877 * @example
10878 *
10879 * eventBus.on('diagram.init', function() {
10880 * eventBus.fire('my-custom-event', { foo: 'BAR' });
10881 * });
10882 *
10883 * @type {Object}
10884 */
10885 this.get('eventBus').fire('diagram.init');
10886 }
10887
10888
10889 /**
10890 * Destroys the diagram
10891 *
10892 * @method Diagram#destroy
10893 */
10894 Diagram.prototype.destroy = function() {
10895 this.get('eventBus').fire('diagram.destroy');
10896 };
10897
10898 /**
10899 * Clear the diagram, removing all contents.
10900 */
10901 Diagram.prototype.clear = function() {
10902 this.get('eventBus').fire('diagram.clear');
10903 };
10904
10905 /**
10906 * Moddle base element.
10907 */
10908 function Base() { }
10909
10910 Base.prototype.get = function(name) {
10911 return this.$model.properties.get(this, name);
10912 };
10913
10914 Base.prototype.set = function(name, value) {
10915 this.$model.properties.set(this, name, value);
10916 };
10917
10918 /**
10919 * A model element factory.
10920 *
10921 * @param {Moddle} model
10922 * @param {Properties} properties
10923 */
10924 function Factory(model, properties) {
10925 this.model = model;
10926 this.properties = properties;
10927 }
10928
10929
10930 Factory.prototype.createType = function(descriptor) {
10931
10932 var model = this.model;
10933
10934 var props = this.properties,
10935 prototype = Object.create(Base.prototype);
10936
10937 // initialize default values
10938 forEach(descriptor.properties, function(p) {
10939 if (!p.isMany && p.default !== undefined) {
10940 prototype[p.name] = p.default;
10941 }
10942 });
10943
10944 props.defineModel(prototype, model);
10945 props.defineDescriptor(prototype, descriptor);
10946
10947 var name = descriptor.ns.name;
10948
10949 /**
10950 * The new type constructor
10951 */
10952 function ModdleElement(attrs) {
10953 props.define(this, '$type', { value: name, enumerable: true });
10954 props.define(this, '$attrs', { value: {} });
10955 props.define(this, '$parent', { writable: true });
10956
10957 forEach(attrs, bind$2(function(val, key) {
10958 this.set(key, val);
10959 }, this));
10960 }
10961
10962 ModdleElement.prototype = prototype;
10963
10964 ModdleElement.hasType = prototype.$instanceOf = this.model.hasType;
10965
10966 // static links
10967 props.defineModel(ModdleElement, model);
10968 props.defineDescriptor(ModdleElement, descriptor);
10969
10970 return ModdleElement;
10971 };
10972
10973 /**
10974 * Built-in moddle types
10975 */
10976 var BUILTINS = {
10977 String: true,
10978 Boolean: true,
10979 Integer: true,
10980 Real: true,
10981 Element: true
10982 };
10983
10984 /**
10985 * Converters for built in types from string representations
10986 */
10987 var TYPE_CONVERTERS = {
10988 String: function(s) { return s; },
10989 Boolean: function(s) { return s === 'true'; },
10990 Integer: function(s) { return parseInt(s, 10); },
10991 Real: function(s) { return parseFloat(s); }
10992 };
10993
10994 /**
10995 * Convert a type to its real representation
10996 */
10997 function coerceType(type, value) {
10998
10999 var converter = TYPE_CONVERTERS[type];
11000
11001 if (converter) {
11002 return converter(value);
11003 } else {
11004 return value;
11005 }
11006 }
11007
11008 /**
11009 * Return whether the given type is built-in
11010 */
11011 function isBuiltIn(type) {
11012 return !!BUILTINS[type];
11013 }
11014
11015 /**
11016 * Return whether the given type is simple
11017 */
11018 function isSimple(type) {
11019 return !!TYPE_CONVERTERS[type];
11020 }
11021
11022 /**
11023 * Parses a namespaced attribute name of the form (ns:)localName to an object,
11024 * given a default prefix to assume in case no explicit namespace is given.
11025 *
11026 * @param {String} name
11027 * @param {String} [defaultPrefix] the default prefix to take, if none is present.
11028 *
11029 * @return {Object} the parsed name
11030 */
11031 function parseName(name, defaultPrefix) {
11032 var parts = name.split(/:/),
11033 localName, prefix;
11034
11035 // no prefix (i.e. only local name)
11036 if (parts.length === 1) {
11037 localName = name;
11038 prefix = defaultPrefix;
11039 } else
11040 // prefix + local name
11041 if (parts.length === 2) {
11042 localName = parts[1];
11043 prefix = parts[0];
11044 } else {
11045 throw new Error('expected <prefix:localName> or <localName>, got ' + name);
11046 }
11047
11048 name = (prefix ? prefix + ':' : '') + localName;
11049
11050 return {
11051 name: name,
11052 prefix: prefix,
11053 localName: localName
11054 };
11055 }
11056
11057 /**
11058 * A utility to build element descriptors.
11059 */
11060 function DescriptorBuilder(nameNs) {
11061 this.ns = nameNs;
11062 this.name = nameNs.name;
11063 this.allTypes = [];
11064 this.allTypesByName = {};
11065 this.properties = [];
11066 this.propertiesByName = {};
11067 }
11068
11069
11070 DescriptorBuilder.prototype.build = function() {
11071 return pick(this, [
11072 'ns',
11073 'name',
11074 'allTypes',
11075 'allTypesByName',
11076 'properties',
11077 'propertiesByName',
11078 'bodyProperty',
11079 'idProperty'
11080 ]);
11081 };
11082
11083 /**
11084 * Add property at given index.
11085 *
11086 * @param {Object} p
11087 * @param {Number} [idx]
11088 * @param {Boolean} [validate=true]
11089 */
11090 DescriptorBuilder.prototype.addProperty = function(p, idx, validate) {
11091
11092 if (typeof idx === 'boolean') {
11093 validate = idx;
11094 idx = undefined;
11095 }
11096
11097 this.addNamedProperty(p, validate !== false);
11098
11099 var properties = this.properties;
11100
11101 if (idx !== undefined) {
11102 properties.splice(idx, 0, p);
11103 } else {
11104 properties.push(p);
11105 }
11106 };
11107
11108
11109 DescriptorBuilder.prototype.replaceProperty = function(oldProperty, newProperty, replace) {
11110 var oldNameNs = oldProperty.ns;
11111
11112 var props = this.properties,
11113 propertiesByName = this.propertiesByName,
11114 rename = oldProperty.name !== newProperty.name;
11115
11116 if (oldProperty.isId) {
11117 if (!newProperty.isId) {
11118 throw new Error(
11119 'property <' + newProperty.ns.name + '> must be id property ' +
11120 'to refine <' + oldProperty.ns.name + '>');
11121 }
11122
11123 this.setIdProperty(newProperty, false);
11124 }
11125
11126 if (oldProperty.isBody) {
11127
11128 if (!newProperty.isBody) {
11129 throw new Error(
11130 'property <' + newProperty.ns.name + '> must be body property ' +
11131 'to refine <' + oldProperty.ns.name + '>');
11132 }
11133
11134 // TODO: Check compatibility
11135 this.setBodyProperty(newProperty, false);
11136 }
11137
11138 // validate existence and get location of old property
11139 var idx = props.indexOf(oldProperty);
11140 if (idx === -1) {
11141 throw new Error('property <' + oldNameNs.name + '> not found in property list');
11142 }
11143
11144 // remove old property
11145 props.splice(idx, 1);
11146
11147 // replacing the named property is intentional
11148 //
11149 // * validate only if this is a "rename" operation
11150 // * add at specific index unless we "replace"
11151 //
11152 this.addProperty(newProperty, replace ? undefined : idx, rename);
11153
11154 // make new property available under old name
11155 propertiesByName[oldNameNs.name] = propertiesByName[oldNameNs.localName] = newProperty;
11156 };
11157
11158
11159 DescriptorBuilder.prototype.redefineProperty = function(p, targetPropertyName, replace) {
11160
11161 var nsPrefix = p.ns.prefix;
11162 var parts = targetPropertyName.split('#');
11163
11164 var name = parseName(parts[0], nsPrefix);
11165 var attrName = parseName(parts[1], name.prefix).name;
11166
11167 var redefinedProperty = this.propertiesByName[attrName];
11168 if (!redefinedProperty) {
11169 throw new Error('refined property <' + attrName + '> not found');
11170 } else {
11171 this.replaceProperty(redefinedProperty, p, replace);
11172 }
11173
11174 delete p.redefines;
11175 };
11176
11177 DescriptorBuilder.prototype.addNamedProperty = function(p, validate) {
11178 var ns = p.ns,
11179 propsByName = this.propertiesByName;
11180
11181 if (validate) {
11182 this.assertNotDefined(p, ns.name);
11183 this.assertNotDefined(p, ns.localName);
11184 }
11185
11186 propsByName[ns.name] = propsByName[ns.localName] = p;
11187 };
11188
11189 DescriptorBuilder.prototype.removeNamedProperty = function(p) {
11190 var ns = p.ns,
11191 propsByName = this.propertiesByName;
11192
11193 delete propsByName[ns.name];
11194 delete propsByName[ns.localName];
11195 };
11196
11197 DescriptorBuilder.prototype.setBodyProperty = function(p, validate) {
11198
11199 if (validate && this.bodyProperty) {
11200 throw new Error(
11201 'body property defined multiple times ' +
11202 '(<' + this.bodyProperty.ns.name + '>, <' + p.ns.name + '>)');
11203 }
11204
11205 this.bodyProperty = p;
11206 };
11207
11208 DescriptorBuilder.prototype.setIdProperty = function(p, validate) {
11209
11210 if (validate && this.idProperty) {
11211 throw new Error(
11212 'id property defined multiple times ' +
11213 '(<' + this.idProperty.ns.name + '>, <' + p.ns.name + '>)');
11214 }
11215
11216 this.idProperty = p;
11217 };
11218
11219 DescriptorBuilder.prototype.assertNotDefined = function(p, name) {
11220 var propertyName = p.name,
11221 definedProperty = this.propertiesByName[propertyName];
11222
11223 if (definedProperty) {
11224 throw new Error(
11225 'property <' + propertyName + '> already defined; ' +
11226 'override of <' + definedProperty.definedBy.ns.name + '#' + definedProperty.ns.name + '> by ' +
11227 '<' + p.definedBy.ns.name + '#' + p.ns.name + '> not allowed without redefines');
11228 }
11229 };
11230
11231 DescriptorBuilder.prototype.hasProperty = function(name) {
11232 return this.propertiesByName[name];
11233 };
11234
11235 DescriptorBuilder.prototype.addTrait = function(t, inherited) {
11236
11237 var typesByName = this.allTypesByName,
11238 types = this.allTypes;
11239
11240 var typeName = t.name;
11241
11242 if (typeName in typesByName) {
11243 return;
11244 }
11245
11246 forEach(t.properties, bind$2(function(p) {
11247
11248 // clone property to allow extensions
11249 p = assign({}, p, {
11250 name: p.ns.localName,
11251 inherited: inherited
11252 });
11253
11254 Object.defineProperty(p, 'definedBy', {
11255 value: t
11256 });
11257
11258 var replaces = p.replaces,
11259 redefines = p.redefines;
11260
11261 // add replace/redefine support
11262 if (replaces || redefines) {
11263 this.redefineProperty(p, replaces || redefines, replaces);
11264 } else {
11265 if (p.isBody) {
11266 this.setBodyProperty(p);
11267 }
11268 if (p.isId) {
11269 this.setIdProperty(p);
11270 }
11271 this.addProperty(p);
11272 }
11273 }, this));
11274
11275 types.push(t);
11276 typesByName[typeName] = t;
11277 };
11278
11279 /**
11280 * A registry of Moddle packages.
11281 *
11282 * @param {Array<Package>} packages
11283 * @param {Properties} properties
11284 */
11285 function Registry(packages, properties) {
11286 this.packageMap = {};
11287 this.typeMap = {};
11288
11289 this.packages = [];
11290
11291 this.properties = properties;
11292
11293 forEach(packages, bind$2(this.registerPackage, this));
11294 }
11295
11296
11297 Registry.prototype.getPackage = function(uriOrPrefix) {
11298 return this.packageMap[uriOrPrefix];
11299 };
11300
11301 Registry.prototype.getPackages = function() {
11302 return this.packages;
11303 };
11304
11305
11306 Registry.prototype.registerPackage = function(pkg) {
11307
11308 // copy package
11309 pkg = assign({}, pkg);
11310
11311 var pkgMap = this.packageMap;
11312
11313 ensureAvailable(pkgMap, pkg, 'prefix');
11314 ensureAvailable(pkgMap, pkg, 'uri');
11315
11316 // register types
11317 forEach(pkg.types, bind$2(function(descriptor) {
11318 this.registerType(descriptor, pkg);
11319 }, this));
11320
11321 pkgMap[pkg.uri] = pkgMap[pkg.prefix] = pkg;
11322 this.packages.push(pkg);
11323 };
11324
11325
11326 /**
11327 * Register a type from a specific package with us
11328 */
11329 Registry.prototype.registerType = function(type, pkg) {
11330
11331 type = assign({}, type, {
11332 superClass: (type.superClass || []).slice(),
11333 extends: (type.extends || []).slice(),
11334 properties: (type.properties || []).slice(),
11335 meta: assign((type.meta || {}))
11336 });
11337
11338 var ns = parseName(type.name, pkg.prefix),
11339 name = ns.name,
11340 propertiesByName = {};
11341
11342 // parse properties
11343 forEach(type.properties, bind$2(function(p) {
11344
11345 // namespace property names
11346 var propertyNs = parseName(p.name, ns.prefix),
11347 propertyName = propertyNs.name;
11348
11349 // namespace property types
11350 if (!isBuiltIn(p.type)) {
11351 p.type = parseName(p.type, propertyNs.prefix).name;
11352 }
11353
11354 assign(p, {
11355 ns: propertyNs,
11356 name: propertyName
11357 });
11358
11359 propertiesByName[propertyName] = p;
11360 }, this));
11361
11362 // update ns + name
11363 assign(type, {
11364 ns: ns,
11365 name: name,
11366 propertiesByName: propertiesByName
11367 });
11368
11369 forEach(type.extends, bind$2(function(extendsName) {
11370 var extended = this.typeMap[extendsName];
11371
11372 extended.traits = extended.traits || [];
11373 extended.traits.push(name);
11374 }, this));
11375
11376 // link to package
11377 this.definePackage(type, pkg);
11378
11379 // register
11380 this.typeMap[name] = type;
11381 };
11382
11383
11384 /**
11385 * Traverse the type hierarchy from bottom to top,
11386 * calling iterator with (type, inherited) for all elements in
11387 * the inheritance chain.
11388 *
11389 * @param {Object} nsName
11390 * @param {Function} iterator
11391 * @param {Boolean} [trait=false]
11392 */
11393 Registry.prototype.mapTypes = function(nsName, iterator, trait) {
11394
11395 var type = isBuiltIn(nsName.name) ? { name: nsName.name } : this.typeMap[nsName.name];
11396
11397 var self = this;
11398
11399 /**
11400 * Traverse the selected trait.
11401 *
11402 * @param {String} cls
11403 */
11404 function traverseTrait(cls) {
11405 return traverseSuper(cls, true);
11406 }
11407
11408 /**
11409 * Traverse the selected super type or trait
11410 *
11411 * @param {String} cls
11412 * @param {Boolean} [trait=false]
11413 */
11414 function traverseSuper(cls, trait) {
11415 var parentNs = parseName(cls, isBuiltIn(cls) ? '' : nsName.prefix);
11416 self.mapTypes(parentNs, iterator, trait);
11417 }
11418
11419 if (!type) {
11420 throw new Error('unknown type <' + nsName.name + '>');
11421 }
11422
11423 forEach(type.superClass, trait ? traverseTrait : traverseSuper);
11424
11425 // call iterator with (type, inherited=!trait)
11426 iterator(type, !trait);
11427
11428 forEach(type.traits, traverseTrait);
11429 };
11430
11431
11432 /**
11433 * Returns the effective descriptor for a type.
11434 *
11435 * @param {String} type the namespaced name (ns:localName) of the type
11436 *
11437 * @return {Descriptor} the resulting effective descriptor
11438 */
11439 Registry.prototype.getEffectiveDescriptor = function(name) {
11440
11441 var nsName = parseName(name);
11442
11443 var builder = new DescriptorBuilder(nsName);
11444
11445 this.mapTypes(nsName, function(type, inherited) {
11446 builder.addTrait(type, inherited);
11447 });
11448
11449 var descriptor = builder.build();
11450
11451 // define package link
11452 this.definePackage(descriptor, descriptor.allTypes[descriptor.allTypes.length - 1].$pkg);
11453
11454 return descriptor;
11455 };
11456
11457
11458 Registry.prototype.definePackage = function(target, pkg) {
11459 this.properties.define(target, '$pkg', { value: pkg });
11460 };
11461
11462
11463
11464 ///////// helpers ////////////////////////////
11465
11466 function ensureAvailable(packageMap, pkg, identifierKey) {
11467
11468 var value = pkg[identifierKey];
11469
11470 if (value in packageMap) {
11471 throw new Error('package with ' + identifierKey + ' <' + value + '> already defined');
11472 }
11473 }
11474
11475 /**
11476 * A utility that gets and sets properties of model elements.
11477 *
11478 * @param {Model} model
11479 */
11480 function Properties(model) {
11481 this.model = model;
11482 }
11483
11484
11485 /**
11486 * Sets a named property on the target element.
11487 * If the value is undefined, the property gets deleted.
11488 *
11489 * @param {Object} target
11490 * @param {String} name
11491 * @param {Object} value
11492 */
11493 Properties.prototype.set = function(target, name, value) {
11494
11495 var property = this.model.getPropertyDescriptor(target, name);
11496
11497 var propertyName = property && property.name;
11498
11499 if (isUndefined(value)) {
11500 // unset the property, if the specified value is undefined;
11501 // delete from $attrs (for extensions) or the target itself
11502 if (property) {
11503 delete target[propertyName];
11504 } else {
11505 delete target.$attrs[name];
11506 }
11507 } else {
11508 // set the property, defining well defined properties on the fly
11509 // or simply updating them in target.$attrs (for extensions)
11510 if (property) {
11511 if (propertyName in target) {
11512 target[propertyName] = value;
11513 } else {
11514 defineProperty(target, property, value);
11515 }
11516 } else {
11517 target.$attrs[name] = value;
11518 }
11519 }
11520 };
11521
11522 /**
11523 * Returns the named property of the given element
11524 *
11525 * @param {Object} target
11526 * @param {String} name
11527 *
11528 * @return {Object}
11529 */
11530 Properties.prototype.get = function(target, name) {
11531
11532 var property = this.model.getPropertyDescriptor(target, name);
11533
11534 if (!property) {
11535 return target.$attrs[name];
11536 }
11537
11538 var propertyName = property.name;
11539
11540 // check if access to collection property and lazily initialize it
11541 if (!target[propertyName] && property.isMany) {
11542 defineProperty(target, property, []);
11543 }
11544
11545 return target[propertyName];
11546 };
11547
11548
11549 /**
11550 * Define a property on the target element
11551 *
11552 * @param {Object} target
11553 * @param {String} name
11554 * @param {Object} options
11555 */
11556 Properties.prototype.define = function(target, name, options) {
11557 Object.defineProperty(target, name, options);
11558 };
11559
11560
11561 /**
11562 * Define the descriptor for an element
11563 */
11564 Properties.prototype.defineDescriptor = function(target, descriptor) {
11565 this.define(target, '$descriptor', { value: descriptor });
11566 };
11567
11568 /**
11569 * Define the model for an element
11570 */
11571 Properties.prototype.defineModel = function(target, model) {
11572 this.define(target, '$model', { value: model });
11573 };
11574
11575
11576 function isUndefined(val) {
11577 return typeof val === 'undefined';
11578 }
11579
11580 function defineProperty(target, property, value) {
11581 Object.defineProperty(target, property.name, {
11582 enumerable: !property.isReference,
11583 writable: true,
11584 value: value,
11585 configurable: true
11586 });
11587 }
11588
11589 //// Moddle implementation /////////////////////////////////////////////////
11590
11591 /**
11592 * @class Moddle
11593 *
11594 * A model that can be used to create elements of a specific type.
11595 *
11596 * @example
11597 *
11598 * var Moddle = require('moddle');
11599 *
11600 * var pkg = {
11601 * name: 'mypackage',
11602 * prefix: 'my',
11603 * types: [
11604 * { name: 'Root' }
11605 * ]
11606 * };
11607 *
11608 * var moddle = new Moddle([pkg]);
11609 *
11610 * @param {Array<Package>} packages the packages to contain
11611 */
11612 function Moddle(packages) {
11613
11614 this.properties = new Properties(this);
11615
11616 this.factory = new Factory(this, this.properties);
11617 this.registry = new Registry(packages, this.properties);
11618
11619 this.typeCache = {};
11620 }
11621
11622
11623 /**
11624 * Create an instance of the specified type.
11625 *
11626 * @method Moddle#create
11627 *
11628 * @example
11629 *
11630 * var foo = moddle.create('my:Foo');
11631 * var bar = moddle.create('my:Bar', { id: 'BAR_1' });
11632 *
11633 * @param {String|Object} descriptor the type descriptor or name know to the model
11634 * @param {Object} attrs a number of attributes to initialize the model instance with
11635 * @return {Object} model instance
11636 */
11637 Moddle.prototype.create = function(descriptor, attrs) {
11638 var Type = this.getType(descriptor);
11639
11640 if (!Type) {
11641 throw new Error('unknown type <' + descriptor + '>');
11642 }
11643
11644 return new Type(attrs);
11645 };
11646
11647
11648 /**
11649 * Returns the type representing a given descriptor
11650 *
11651 * @method Moddle#getType
11652 *
11653 * @example
11654 *
11655 * var Foo = moddle.getType('my:Foo');
11656 * var foo = new Foo({ 'id' : 'FOO_1' });
11657 *
11658 * @param {String|Object} descriptor the type descriptor or name know to the model
11659 * @return {Object} the type representing the descriptor
11660 */
11661 Moddle.prototype.getType = function(descriptor) {
11662
11663 var cache = this.typeCache;
11664
11665 var name = isString(descriptor) ? descriptor : descriptor.ns.name;
11666
11667 var type = cache[name];
11668
11669 if (!type) {
11670 descriptor = this.registry.getEffectiveDescriptor(name);
11671 type = cache[name] = this.factory.createType(descriptor);
11672 }
11673
11674 return type;
11675 };
11676
11677
11678 /**
11679 * Creates an any-element type to be used within model instances.
11680 *
11681 * This can be used to create custom elements that lie outside the meta-model.
11682 * The created element contains all the meta-data required to serialize it
11683 * as part of meta-model elements.
11684 *
11685 * @method Moddle#createAny
11686 *
11687 * @example
11688 *
11689 * var foo = moddle.createAny('vendor:Foo', 'http://vendor', {
11690 * value: 'bar'
11691 * });
11692 *
11693 * var container = moddle.create('my:Container', 'http://my', {
11694 * any: [ foo ]
11695 * });
11696 *
11697 * // go ahead and serialize the stuff
11698 *
11699 *
11700 * @param {String} name the name of the element
11701 * @param {String} nsUri the namespace uri of the element
11702 * @param {Object} [properties] a map of properties to initialize the instance with
11703 * @return {Object} the any type instance
11704 */
11705 Moddle.prototype.createAny = function(name, nsUri, properties) {
11706
11707 var nameNs = parseName(name);
11708
11709 var element = {
11710 $type: name,
11711 $instanceOf: function(type) {
11712 return type === this.$type;
11713 }
11714 };
11715
11716 var descriptor = {
11717 name: name,
11718 isGeneric: true,
11719 ns: {
11720 prefix: nameNs.prefix,
11721 localName: nameNs.localName,
11722 uri: nsUri
11723 }
11724 };
11725
11726 this.properties.defineDescriptor(element, descriptor);
11727 this.properties.defineModel(element, this);
11728 this.properties.define(element, '$parent', { enumerable: false, writable: true });
11729 this.properties.define(element, '$instanceOf', { enumerable: false, writable: true });
11730
11731 forEach(properties, function(a, key) {
11732 if (isObject(a) && a.value !== undefined) {
11733 element[a.name] = a.value;
11734 } else {
11735 element[key] = a;
11736 }
11737 });
11738
11739 return element;
11740 };
11741
11742 /**
11743 * Returns a registered package by uri or prefix
11744 *
11745 * @return {Object} the package
11746 */
11747 Moddle.prototype.getPackage = function(uriOrPrefix) {
11748 return this.registry.getPackage(uriOrPrefix);
11749 };
11750
11751 /**
11752 * Returns a snapshot of all known packages
11753 *
11754 * @return {Object} the package
11755 */
11756 Moddle.prototype.getPackages = function() {
11757 return this.registry.getPackages();
11758 };
11759
11760 /**
11761 * Returns the descriptor for an element
11762 */
11763 Moddle.prototype.getElementDescriptor = function(element) {
11764 return element.$descriptor;
11765 };
11766
11767 /**
11768 * Returns true if the given descriptor or instance
11769 * represents the given type.
11770 *
11771 * May be applied to this, if element is omitted.
11772 */
11773 Moddle.prototype.hasType = function(element, type) {
11774 if (type === undefined) {
11775 type = element;
11776 element = this;
11777 }
11778
11779 var descriptor = element.$model.getElementDescriptor(element);
11780
11781 return (type in descriptor.allTypesByName);
11782 };
11783
11784 /**
11785 * Returns the descriptor of an elements named property
11786 */
11787 Moddle.prototype.getPropertyDescriptor = function(element, property) {
11788 return this.getElementDescriptor(element).propertiesByName[property];
11789 };
11790
11791 /**
11792 * Returns a mapped type's descriptor
11793 */
11794 Moddle.prototype.getTypeDescriptor = function(type) {
11795 return this.registry.typeMap[type];
11796 };
11797
11798 var fromCharCode = String.fromCharCode;
11799
11800 var hasOwnProperty = Object.prototype.hasOwnProperty;
11801
11802 var ENTITY_PATTERN = /&#(\d+);|&#x([0-9a-f]+);|&(\w+);/ig;
11803
11804 var ENTITY_MAPPING = {
11805 'amp': '&',
11806 'apos': '\'',
11807 'gt': '>',
11808 'lt': '<',
11809 'quot': '"'
11810 };
11811
11812 // map UPPERCASE variants of supported special chars
11813 Object.keys(ENTITY_MAPPING).forEach(function(k) {
11814 ENTITY_MAPPING[k.toUpperCase()] = ENTITY_MAPPING[k];
11815 });
11816
11817
11818 function replaceEntities(_, d, x, z) {
11819
11820 // reserved names, i.e. &nbsp;
11821 if (z) {
11822 if (hasOwnProperty.call(ENTITY_MAPPING, z)) {
11823 return ENTITY_MAPPING[z];
11824 } else {
11825
11826 // fall back to original value
11827 return '&' + z + ';';
11828 }
11829 }
11830
11831 // decimal encoded char
11832 if (d) {
11833 return fromCharCode(d);
11834 }
11835
11836 // hex encoded char
11837 return fromCharCode(parseInt(x, 16));
11838 }
11839
11840
11841 /**
11842 * A basic entity decoder that can decode a minimal
11843 * sub-set of reserved names (&amp;) as well as
11844 * hex (&#xaaf;) and decimal (&#1231;) encoded characters.
11845 *
11846 * @param {string} str
11847 *
11848 * @return {string} decoded string
11849 */
11850 function decodeEntities(s) {
11851 if (s.length > 3 && s.indexOf('&') !== -1) {
11852 return s.replace(ENTITY_PATTERN, replaceEntities);
11853 }
11854
11855 return s;
11856 }
11857
11858 var XSI_URI = 'http://www.w3.org/2001/XMLSchema-instance';
11859 var XSI_PREFIX = 'xsi';
11860 var XSI_TYPE$1 = 'xsi:type';
11861
11862 var NON_WHITESPACE_OUTSIDE_ROOT_NODE = 'non-whitespace outside of root node';
11863
11864 function error$1(msg) {
11865 return new Error(msg);
11866 }
11867
11868 function missingNamespaceForPrefix(prefix) {
11869 return 'missing namespace for prefix <' + prefix + '>';
11870 }
11871
11872 function getter(getFn) {
11873 return {
11874 'get': getFn,
11875 'enumerable': true
11876 };
11877 }
11878
11879 function cloneNsMatrix(nsMatrix) {
11880 var clone = {}, key;
11881 for (key in nsMatrix) {
11882 clone[key] = nsMatrix[key];
11883 }
11884 return clone;
11885 }
11886
11887 function uriPrefix(prefix) {
11888 return prefix + '$uri';
11889 }
11890
11891 function buildNsMatrix(nsUriToPrefix) {
11892 var nsMatrix = {},
11893 uri,
11894 prefix;
11895
11896 for (uri in nsUriToPrefix) {
11897 prefix = nsUriToPrefix[uri];
11898 nsMatrix[prefix] = prefix;
11899 nsMatrix[uriPrefix(prefix)] = uri;
11900 }
11901
11902 return nsMatrix;
11903 }
11904
11905 function noopGetContext() {
11906 return { 'line': 0, 'column': 0 };
11907 }
11908
11909 function throwFunc(err) {
11910 throw err;
11911 }
11912
11913 /**
11914 * Creates a new parser with the given options.
11915 *
11916 * @constructor
11917 *
11918 * @param {!Object<string, ?>=} options
11919 */
11920 function Parser(options) {
11921
11922 if (!this) {
11923 return new Parser(options);
11924 }
11925
11926 var proxy = options && options['proxy'];
11927
11928 var onText,
11929 onOpenTag,
11930 onCloseTag,
11931 onCDATA,
11932 onError = throwFunc,
11933 onWarning,
11934 onComment,
11935 onQuestion,
11936 onAttention;
11937
11938 var getContext = noopGetContext;
11939
11940 /**
11941 * Do we need to parse the current elements attributes for namespaces?
11942 *
11943 * @type {boolean}
11944 */
11945 var maybeNS = false;
11946
11947 /**
11948 * Do we process namespaces at all?
11949 *
11950 * @type {boolean}
11951 */
11952 var isNamespace = false;
11953
11954 /**
11955 * The caught error returned on parse end
11956 *
11957 * @type {Error}
11958 */
11959 var returnError = null;
11960
11961 /**
11962 * Should we stop parsing?
11963 *
11964 * @type {boolean}
11965 */
11966 var parseStop = false;
11967
11968 /**
11969 * A map of { uri: prefix } used by the parser.
11970 *
11971 * This map will ensure we can normalize prefixes during processing;
11972 * for each uri, only one prefix will be exposed to the handlers.
11973 *
11974 * @type {!Object<string, string>}}
11975 */
11976 var nsUriToPrefix;
11977
11978 /**
11979 * Handle parse error.
11980 *
11981 * @param {string|Error} err
11982 */
11983 function handleError(err) {
11984 if (!(err instanceof Error)) {
11985 err = error$1(err);
11986 }
11987
11988 returnError = err;
11989
11990 onError(err, getContext);
11991 }
11992
11993 /**
11994 * Handle parse error.
11995 *
11996 * @param {string|Error} err
11997 */
11998 function handleWarning(err) {
11999
12000 if (!onWarning) {
12001 return;
12002 }
12003
12004 if (!(err instanceof Error)) {
12005 err = error$1(err);
12006 }
12007
12008 onWarning(err, getContext);
12009 }
12010
12011 /**
12012 * Register parse listener.
12013 *
12014 * @param {string} name
12015 * @param {Function} cb
12016 *
12017 * @return {Parser}
12018 */
12019 this['on'] = function(name, cb) {
12020
12021 if (typeof cb !== 'function') {
12022 throw error$1('required args <name, cb>');
12023 }
12024
12025 switch (name) {
12026 case 'openTag': onOpenTag = cb; break;
12027 case 'text': onText = cb; break;
12028 case 'closeTag': onCloseTag = cb; break;
12029 case 'error': onError = cb; break;
12030 case 'warn': onWarning = cb; break;
12031 case 'cdata': onCDATA = cb; break;
12032 case 'attention': onAttention = cb; break; // <!XXXXX zzzz="eeee">
12033 case 'question': onQuestion = cb; break; // <? .... ?>
12034 case 'comment': onComment = cb; break;
12035 default:
12036 throw error$1('unsupported event: ' + name);
12037 }
12038
12039 return this;
12040 };
12041
12042 /**
12043 * Set the namespace to prefix mapping.
12044 *
12045 * @example
12046 *
12047 * parser.ns({
12048 * 'http://foo': 'foo',
12049 * 'http://bar': 'bar'
12050 * });
12051 *
12052 * @param {!Object<string, string>} nsMap
12053 *
12054 * @return {Parser}
12055 */
12056 this['ns'] = function(nsMap) {
12057
12058 if (typeof nsMap === 'undefined') {
12059 nsMap = {};
12060 }
12061
12062 if (typeof nsMap !== 'object') {
12063 throw error$1('required args <nsMap={}>');
12064 }
12065
12066 var _nsUriToPrefix = {}, k;
12067
12068 for (k in nsMap) {
12069 _nsUriToPrefix[k] = nsMap[k];
12070 }
12071
12072 // FORCE default mapping for schema instance
12073 _nsUriToPrefix[XSI_URI] = XSI_PREFIX;
12074
12075 isNamespace = true;
12076 nsUriToPrefix = _nsUriToPrefix;
12077
12078 return this;
12079 };
12080
12081 /**
12082 * Parse xml string.
12083 *
12084 * @param {string} xml
12085 *
12086 * @return {Error} returnError, if not thrown
12087 */
12088 this['parse'] = function(xml) {
12089 if (typeof xml !== 'string') {
12090 throw error$1('required args <xml=string>');
12091 }
12092
12093 returnError = null;
12094
12095 parse(xml);
12096
12097 getContext = noopGetContext;
12098 parseStop = false;
12099
12100 return returnError;
12101 };
12102
12103 /**
12104 * Stop parsing.
12105 */
12106 this['stop'] = function() {
12107 parseStop = true;
12108 };
12109
12110 /**
12111 * Parse string, invoking configured listeners on element.
12112 *
12113 * @param {string} xml
12114 */
12115 function parse(xml) {
12116 var nsMatrixStack = isNamespace ? [] : null,
12117 nsMatrix = isNamespace ? buildNsMatrix(nsUriToPrefix) : null,
12118 _nsMatrix,
12119 nodeStack = [],
12120 anonymousNsCount = 0,
12121 tagStart = false,
12122 tagEnd = false,
12123 i = 0, j = 0,
12124 x, y, q, w, v,
12125 xmlns,
12126 elementName,
12127 _elementName,
12128 elementProxy
12129 ;
12130
12131 var attrsString = '',
12132 attrsStart = 0,
12133 cachedAttrs // false = parsed with errors, null = needs parsing
12134 ;
12135
12136 /**
12137 * Parse attributes on demand and returns the parsed attributes.
12138 *
12139 * Return semantics: (1) `false` on attribute parse error,
12140 * (2) object hash on extracted attrs.
12141 *
12142 * @return {boolean|Object}
12143 */
12144 function getAttrs() {
12145 if (cachedAttrs !== null) {
12146 return cachedAttrs;
12147 }
12148
12149 var nsUri,
12150 nsUriPrefix,
12151 nsName,
12152 defaultAlias = isNamespace && nsMatrix['xmlns'],
12153 attrList = isNamespace && maybeNS ? [] : null,
12154 i = attrsStart,
12155 s = attrsString,
12156 l = s.length,
12157 hasNewMatrix,
12158 newalias,
12159 value,
12160 alias,
12161 name,
12162 attrs = {},
12163 seenAttrs = {},
12164 skipAttr,
12165 w,
12166 j;
12167
12168 parseAttr:
12169 for (; i < l; i++) {
12170 skipAttr = false;
12171 w = s.charCodeAt(i);
12172
12173 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE={ \f\n\r\t\v}
12174 continue;
12175 }
12176
12177 // wait for non whitespace character
12178 if (w < 65 || w > 122 || (w > 90 && w < 97)) {
12179 if (w !== 95 && w !== 58) { // char 95"_" 58":"
12180 handleWarning('illegal first char attribute name');
12181 skipAttr = true;
12182 }
12183 }
12184
12185 // parse attribute name
12186 for (j = i + 1; j < l; j++) {
12187 w = s.charCodeAt(j);
12188
12189 if (
12190 w > 96 && w < 123 ||
12191 w > 64 && w < 91 ||
12192 w > 47 && w < 59 ||
12193 w === 46 || // '.'
12194 w === 45 || // '-'
12195 w === 95 // '_'
12196 ) {
12197 continue;
12198 }
12199
12200 // unexpected whitespace
12201 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
12202 handleWarning('missing attribute value');
12203 i = j;
12204
12205 continue parseAttr;
12206 }
12207
12208 // expected "="
12209 if (w === 61) { // "=" == 61
12210 break;
12211 }
12212
12213 handleWarning('illegal attribute name char');
12214 skipAttr = true;
12215 }
12216
12217 name = s.substring(i, j);
12218
12219 if (name === 'xmlns:xmlns') {
12220 handleWarning('illegal declaration of xmlns');
12221 skipAttr = true;
12222 }
12223
12224 w = s.charCodeAt(j + 1);
12225
12226 if (w === 34) { // '"'
12227 j = s.indexOf('"', i = j + 2);
12228
12229 if (j === -1) {
12230 j = s.indexOf('\'', i);
12231
12232 if (j !== -1) {
12233 handleWarning('attribute value quote missmatch');
12234 skipAttr = true;
12235 }
12236 }
12237
12238 } else if (w === 39) { // "'"
12239 j = s.indexOf('\'', i = j + 2);
12240
12241 if (j === -1) {
12242 j = s.indexOf('"', i);
12243
12244 if (j !== -1) {
12245 handleWarning('attribute value quote missmatch');
12246 skipAttr = true;
12247 }
12248 }
12249
12250 } else {
12251 handleWarning('missing attribute value quotes');
12252 skipAttr = true;
12253
12254 // skip to next space
12255 for (j = j + 1; j < l; j++) {
12256 w = s.charCodeAt(j + 1);
12257
12258 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
12259 break;
12260 }
12261 }
12262
12263 }
12264
12265 if (j === -1) {
12266 handleWarning('missing closing quotes');
12267
12268 j = l;
12269 skipAttr = true;
12270 }
12271
12272 if (!skipAttr) {
12273 value = s.substring(i, j);
12274 }
12275
12276 i = j;
12277
12278 // ensure SPACE follows attribute
12279 // skip illegal content otherwise
12280 // example a="b"c
12281 for (; j + 1 < l; j++) {
12282 w = s.charCodeAt(j + 1);
12283
12284 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
12285 break;
12286 }
12287
12288 // FIRST ILLEGAL CHAR
12289 if (i === j) {
12290 handleWarning('illegal character after attribute end');
12291 skipAttr = true;
12292 }
12293 }
12294
12295 // advance cursor to next attribute
12296 i = j + 1;
12297
12298 if (skipAttr) {
12299 continue parseAttr;
12300 }
12301
12302 // check attribute re-declaration
12303 if (name in seenAttrs) {
12304 handleWarning('attribute <' + name + '> already defined');
12305 continue;
12306 }
12307
12308 seenAttrs[name] = true;
12309
12310 if (!isNamespace) {
12311 attrs[name] = value;
12312 continue;
12313 }
12314
12315 // try to extract namespace information
12316 if (maybeNS) {
12317 newalias = (
12318 name === 'xmlns'
12319 ? 'xmlns'
12320 : (name.charCodeAt(0) === 120 && name.substr(0, 6) === 'xmlns:')
12321 ? name.substr(6)
12322 : null
12323 );
12324
12325 // handle xmlns(:alias) assignment
12326 if (newalias !== null) {
12327 nsUri = decodeEntities(value);
12328 nsUriPrefix = uriPrefix(newalias);
12329
12330 alias = nsUriToPrefix[nsUri];
12331
12332 if (!alias) {
12333
12334 // no prefix defined or prefix collision
12335 if (
12336 (newalias === 'xmlns') ||
12337 (nsUriPrefix in nsMatrix && nsMatrix[nsUriPrefix] !== nsUri)
12338 ) {
12339
12340 // alocate free ns prefix
12341 do {
12342 alias = 'ns' + (anonymousNsCount++);
12343 } while (typeof nsMatrix[alias] !== 'undefined');
12344 } else {
12345 alias = newalias;
12346 }
12347
12348 nsUriToPrefix[nsUri] = alias;
12349 }
12350
12351 if (nsMatrix[newalias] !== alias) {
12352 if (!hasNewMatrix) {
12353 nsMatrix = cloneNsMatrix(nsMatrix);
12354 hasNewMatrix = true;
12355 }
12356
12357 nsMatrix[newalias] = alias;
12358 if (newalias === 'xmlns') {
12359 nsMatrix[uriPrefix(alias)] = nsUri;
12360 defaultAlias = alias;
12361 }
12362
12363 nsMatrix[nsUriPrefix] = nsUri;
12364 }
12365
12366 // expose xmlns(:asd)="..." in attributes
12367 attrs[name] = value;
12368 continue;
12369 }
12370
12371 // collect attributes until all namespace
12372 // declarations are processed
12373 attrList.push(name, value);
12374 continue;
12375
12376 } /** end if (maybeNs) */
12377
12378 // handle attributes on element without
12379 // namespace declarations
12380 w = name.indexOf(':');
12381 if (w === -1) {
12382 attrs[name] = value;
12383 continue;
12384 }
12385
12386 // normalize ns attribute name
12387 if (!(nsName = nsMatrix[name.substring(0, w)])) {
12388 handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
12389 continue;
12390 }
12391
12392 name = defaultAlias === nsName
12393 ? name.substr(w + 1)
12394 : nsName + name.substr(w);
12395
12396 // end: normalize ns attribute name
12397
12398 // normalize xsi:type ns attribute value
12399 if (name === XSI_TYPE$1) {
12400 w = value.indexOf(':');
12401
12402 if (w !== -1) {
12403 nsName = value.substring(0, w);
12404
12405 // handle default prefixes, i.e. xs:String gracefully
12406 nsName = nsMatrix[nsName] || nsName;
12407 value = nsName + value.substring(w);
12408 } else {
12409 value = defaultAlias + ':' + value;
12410 }
12411 }
12412
12413 // end: normalize xsi:type ns attribute value
12414
12415 attrs[name] = value;
12416 }
12417
12418
12419 // handle deferred, possibly namespaced attributes
12420 if (maybeNS) {
12421
12422 // normalize captured attributes
12423 for (i = 0, l = attrList.length; i < l; i++) {
12424
12425 name = attrList[i++];
12426 value = attrList[i];
12427
12428 w = name.indexOf(':');
12429
12430 if (w !== -1) {
12431
12432 // normalize ns attribute name
12433 if (!(nsName = nsMatrix[name.substring(0, w)])) {
12434 handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
12435 continue;
12436 }
12437
12438 name = defaultAlias === nsName
12439 ? name.substr(w + 1)
12440 : nsName + name.substr(w);
12441
12442 // end: normalize ns attribute name
12443
12444 // normalize xsi:type ns attribute value
12445 if (name === XSI_TYPE$1) {
12446 w = value.indexOf(':');
12447
12448 if (w !== -1) {
12449 nsName = value.substring(0, w);
12450
12451 // handle default prefixes, i.e. xs:String gracefully
12452 nsName = nsMatrix[nsName] || nsName;
12453 value = nsName + value.substring(w);
12454 } else {
12455 value = defaultAlias + ':' + value;
12456 }
12457 }
12458
12459 // end: normalize xsi:type ns attribute value
12460 }
12461
12462 attrs[name] = value;
12463 }
12464
12465 // end: normalize captured attributes
12466 }
12467
12468 return cachedAttrs = attrs;
12469 }
12470
12471 /**
12472 * Extract the parse context { line, column, part }
12473 * from the current parser position.
12474 *
12475 * @return {Object} parse context
12476 */
12477 function getParseContext() {
12478 var splitsRe = /(\r\n|\r|\n)/g;
12479
12480 var line = 0;
12481 var column = 0;
12482 var startOfLine = 0;
12483 var endOfLine = j;
12484 var match;
12485 var data;
12486
12487 while (i >= startOfLine) {
12488
12489 match = splitsRe.exec(xml);
12490
12491 if (!match) {
12492 break;
12493 }
12494
12495 // end of line = (break idx + break chars)
12496 endOfLine = match[0].length + match.index;
12497
12498 if (endOfLine > i) {
12499 break;
12500 }
12501
12502 // advance to next line
12503 line += 1;
12504
12505 startOfLine = endOfLine;
12506 }
12507
12508 // EOF errors
12509 if (i == -1) {
12510 column = endOfLine;
12511 data = xml.substring(j);
12512 } else
12513
12514 // start errors
12515 if (j === 0) {
12516 data = xml.substring(j, i);
12517 }
12518
12519 // other errors
12520 else {
12521 column = i - startOfLine;
12522 data = (j == -1 ? xml.substring(i) : xml.substring(i, j + 1));
12523 }
12524
12525 return {
12526 'data': data,
12527 'line': line,
12528 'column': column
12529 };
12530 }
12531
12532 getContext = getParseContext;
12533
12534
12535 if (proxy) {
12536 elementProxy = Object.create({}, {
12537 'name': getter(function() {
12538 return elementName;
12539 }),
12540 'originalName': getter(function() {
12541 return _elementName;
12542 }),
12543 'attrs': getter(getAttrs),
12544 'ns': getter(function() {
12545 return nsMatrix;
12546 })
12547 });
12548 }
12549
12550 // actual parse logic
12551 while (j !== -1) {
12552
12553 if (xml.charCodeAt(j) === 60) { // "<"
12554 i = j;
12555 } else {
12556 i = xml.indexOf('<', j);
12557 }
12558
12559 // parse end
12560 if (i === -1) {
12561 if (nodeStack.length) {
12562 return handleError('unexpected end of file');
12563 }
12564
12565 if (j === 0) {
12566 return handleError('missing start tag');
12567 }
12568
12569 if (j < xml.length) {
12570 if (xml.substring(j).trim()) {
12571 handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
12572 }
12573 }
12574
12575 return;
12576 }
12577
12578 // parse text
12579 if (j !== i) {
12580
12581 if (nodeStack.length) {
12582 if (onText) {
12583 onText(xml.substring(j, i), decodeEntities, getContext);
12584
12585 if (parseStop) {
12586 return;
12587 }
12588 }
12589 } else {
12590 if (xml.substring(j, i).trim()) {
12591 handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
12592
12593 if (parseStop) {
12594 return;
12595 }
12596 }
12597 }
12598 }
12599
12600 w = xml.charCodeAt(i+1);
12601
12602 // parse comments + CDATA
12603 if (w === 33) { // "!"
12604 q = xml.charCodeAt(i+2);
12605
12606 // CDATA section
12607 if (q === 91 && xml.substr(i + 3, 6) === 'CDATA[') { // 91 == "["
12608 j = xml.indexOf(']]>', i);
12609 if (j === -1) {
12610 return handleError('unclosed cdata');
12611 }
12612
12613 if (onCDATA) {
12614 onCDATA(xml.substring(i + 9, j), getContext);
12615 if (parseStop) {
12616 return;
12617 }
12618 }
12619
12620 j += 3;
12621 continue;
12622 }
12623
12624 // comment
12625 if (q === 45 && xml.charCodeAt(i + 3) === 45) { // 45 == "-"
12626 j = xml.indexOf('-->', i);
12627 if (j === -1) {
12628 return handleError('unclosed comment');
12629 }
12630
12631
12632 if (onComment) {
12633 onComment(xml.substring(i + 4, j), decodeEntities, getContext);
12634 if (parseStop) {
12635 return;
12636 }
12637 }
12638
12639 j += 3;
12640 continue;
12641 }
12642 }
12643
12644 // parse question <? ... ?>
12645 if (w === 63) { // "?"
12646 j = xml.indexOf('?>', i);
12647 if (j === -1) {
12648 return handleError('unclosed question');
12649 }
12650
12651 if (onQuestion) {
12652 onQuestion(xml.substring(i, j + 2), getContext);
12653 if (parseStop) {
12654 return;
12655 }
12656 }
12657
12658 j += 2;
12659 continue;
12660 }
12661
12662 // find matching closing tag for attention or standard tags
12663 // for that we must skip through attribute values
12664 // (enclosed in single or double quotes)
12665 for (x = i + 1; ; x++) {
12666 v = xml.charCodeAt(x);
12667 if (isNaN(v)) {
12668 j = -1;
12669 return handleError('unclosed tag');
12670 }
12671
12672 // [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'"
12673 // skips the quoted string
12674 // (double quotes) does not appear in a literal enclosed by (double quotes)
12675 // (single quote) does not appear in a literal enclosed by (single quote)
12676 if (v === 34) { // '"'
12677 q = xml.indexOf('"', x + 1);
12678 x = q !== -1 ? q : x;
12679 } else if (v === 39) { // "'"
12680 q = xml.indexOf("'", x + 1);
12681 x = q !== -1 ? q : x;
12682 } else if (v === 62) { // '>'
12683 j = x;
12684 break;
12685 }
12686 }
12687
12688
12689 // parse attention <! ...>
12690 // previously comment and CDATA have already been parsed
12691 if (w === 33) { // "!"
12692
12693 if (onAttention) {
12694 onAttention(xml.substring(i, j + 1), decodeEntities, getContext);
12695 if (parseStop) {
12696 return;
12697 }
12698 }
12699
12700 j += 1;
12701 continue;
12702 }
12703
12704 // don't process attributes;
12705 // there are none
12706 cachedAttrs = {};
12707
12708 // if (xml.charCodeAt(i+1) === 47) { // </...
12709 if (w === 47) { // </...
12710 tagStart = false;
12711 tagEnd = true;
12712
12713 if (!nodeStack.length) {
12714 return handleError('missing open tag');
12715 }
12716
12717 // verify open <-> close tag match
12718 x = elementName = nodeStack.pop();
12719 q = i + 2 + x.length;
12720
12721 if (xml.substring(i + 2, q) !== x) {
12722 return handleError('closing tag mismatch');
12723 }
12724
12725 // verify chars in close tag
12726 for (; q < j; q++) {
12727 w = xml.charCodeAt(q);
12728
12729 if (w === 32 || (w > 8 && w < 14)) { // \f\n\r\t\v space
12730 continue;
12731 }
12732
12733 return handleError('close tag');
12734 }
12735
12736 } else {
12737 if (xml.charCodeAt(j - 1) === 47) { // .../>
12738 x = elementName = xml.substring(i + 1, j - 1);
12739
12740 tagStart = true;
12741 tagEnd = true;
12742
12743 } else {
12744 x = elementName = xml.substring(i + 1, j);
12745
12746 tagStart = true;
12747 tagEnd = false;
12748 }
12749
12750 if (!(w > 96 && w < 123 || w > 64 && w < 91 || w === 95 || w === 58)) { // char 95"_" 58":"
12751 return handleError('illegal first char nodeName');
12752 }
12753
12754 for (q = 1, y = x.length; q < y; q++) {
12755 w = x.charCodeAt(q);
12756
12757 if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w == 46) {
12758 continue;
12759 }
12760
12761 if (w === 32 || (w < 14 && w > 8)) { // \f\n\r\t\v space
12762 elementName = x.substring(0, q);
12763
12764 // maybe there are attributes
12765 cachedAttrs = null;
12766 break;
12767 }
12768
12769 return handleError('invalid nodeName');
12770 }
12771
12772 if (!tagEnd) {
12773 nodeStack.push(elementName);
12774 }
12775 }
12776
12777 if (isNamespace) {
12778
12779 _nsMatrix = nsMatrix;
12780
12781 if (tagStart) {
12782
12783 // remember old namespace
12784 // unless we're self-closing
12785 if (!tagEnd) {
12786 nsMatrixStack.push(_nsMatrix);
12787 }
12788
12789 if (cachedAttrs === null) {
12790
12791 // quick check, whether there may be namespace
12792 // declarations on the node; if that is the case
12793 // we need to eagerly parse the node attributes
12794 if ((maybeNS = x.indexOf('xmlns', q) !== -1)) {
12795 attrsStart = q;
12796 attrsString = x;
12797
12798 getAttrs();
12799
12800 maybeNS = false;
12801 }
12802 }
12803 }
12804
12805 _elementName = elementName;
12806
12807 w = elementName.indexOf(':');
12808 if (w !== -1) {
12809 xmlns = nsMatrix[elementName.substring(0, w)];
12810
12811 // prefix given; namespace must exist
12812 if (!xmlns) {
12813 return handleError('missing namespace on <' + _elementName + '>');
12814 }
12815
12816 elementName = elementName.substr(w + 1);
12817 } else {
12818 xmlns = nsMatrix['xmlns'];
12819
12820 // if no default namespace is defined,
12821 // we'll import the element as anonymous.
12822 //
12823 // it is up to users to correct that to the document defined
12824 // targetNamespace, or whatever their undersanding of the
12825 // XML spec mandates.
12826 }
12827
12828 // adjust namespace prefixs as configured
12829 if (xmlns) {
12830 elementName = xmlns + ':' + elementName;
12831 }
12832
12833 }
12834
12835 if (tagStart) {
12836 attrsStart = q;
12837 attrsString = x;
12838
12839 if (onOpenTag) {
12840 if (proxy) {
12841 onOpenTag(elementProxy, decodeEntities, tagEnd, getContext);
12842 } else {
12843 onOpenTag(elementName, getAttrs, decodeEntities, tagEnd, getContext);
12844 }
12845
12846 if (parseStop) {
12847 return;
12848 }
12849 }
12850
12851 }
12852
12853 if (tagEnd) {
12854
12855 if (onCloseTag) {
12856 onCloseTag(proxy ? elementProxy : elementName, decodeEntities, tagStart, getContext);
12857
12858 if (parseStop) {
12859 return;
12860 }
12861 }
12862
12863 // restore old namespace
12864 if (isNamespace) {
12865 if (!tagStart) {
12866 nsMatrix = nsMatrixStack.pop();
12867 } else {
12868 nsMatrix = _nsMatrix;
12869 }
12870 }
12871 }
12872
12873 j += 1;
12874 }
12875 } /** end parse */
12876
12877 }
12878
12879 function hasLowerCaseAlias(pkg) {
12880 return pkg.xml && pkg.xml.tagAlias === 'lowerCase';
12881 }
12882
12883 var DEFAULT_NS_MAP = {
12884 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
12885 'xml': 'http://www.w3.org/XML/1998/namespace'
12886 };
12887
12888 var XSI_TYPE = 'xsi:type';
12889
12890 function serializeFormat(element) {
12891 return element.xml && element.xml.serialize;
12892 }
12893
12894 function serializeAsType(element) {
12895 return serializeFormat(element) === XSI_TYPE;
12896 }
12897
12898 function serializeAsProperty(element) {
12899 return serializeFormat(element) === 'property';
12900 }
12901
12902 function capitalize(str) {
12903 return str.charAt(0).toUpperCase() + str.slice(1);
12904 }
12905
12906 function aliasToName(aliasNs, pkg) {
12907
12908 if (!hasLowerCaseAlias(pkg)) {
12909 return aliasNs.name;
12910 }
12911
12912 return aliasNs.prefix + ':' + capitalize(aliasNs.localName);
12913 }
12914
12915 function prefixedToName(nameNs, pkg) {
12916
12917 var name = nameNs.name,
12918 localName = nameNs.localName;
12919
12920 var typePrefix = pkg.xml && pkg.xml.typePrefix;
12921
12922 if (typePrefix && localName.indexOf(typePrefix) === 0) {
12923 return nameNs.prefix + ':' + localName.slice(typePrefix.length);
12924 } else {
12925 return name;
12926 }
12927 }
12928
12929 function normalizeXsiTypeName(name, model) {
12930
12931 var nameNs = parseName(name);
12932 var pkg = model.getPackage(nameNs.prefix);
12933
12934 return prefixedToName(nameNs, pkg);
12935 }
12936
12937 function error(message) {
12938 return new Error(message);
12939 }
12940
12941 /**
12942 * Get the moddle descriptor for a given instance or type.
12943 *
12944 * @param {ModdleElement|Function} element
12945 *
12946 * @return {Object} the moddle descriptor
12947 */
12948 function getModdleDescriptor(element) {
12949 return element.$descriptor;
12950 }
12951
12952
12953 /**
12954 * A parse context.
12955 *
12956 * @class
12957 *
12958 * @param {Object} options
12959 * @param {ElementHandler} options.rootHandler the root handler for parsing a document
12960 * @param {boolean} [options.lax=false] whether or not to ignore invalid elements
12961 */
12962 function Context(options) {
12963
12964 /**
12965 * @property {ElementHandler} rootHandler
12966 */
12967
12968 /**
12969 * @property {Boolean} lax
12970 */
12971
12972 assign(this, options);
12973
12974 this.elementsById = {};
12975 this.references = [];
12976 this.warnings = [];
12977
12978 /**
12979 * Add an unresolved reference.
12980 *
12981 * @param {Object} reference
12982 */
12983 this.addReference = function(reference) {
12984 this.references.push(reference);
12985 };
12986
12987 /**
12988 * Add a processed element.
12989 *
12990 * @param {ModdleElement} element
12991 */
12992 this.addElement = function(element) {
12993
12994 if (!element) {
12995 throw error('expected element');
12996 }
12997
12998 var elementsById = this.elementsById;
12999
13000 var descriptor = getModdleDescriptor(element);
13001
13002 var idProperty = descriptor.idProperty,
13003 id;
13004
13005 if (idProperty) {
13006 id = element.get(idProperty.name);
13007
13008 if (id) {
13009
13010 // for QName validation as per http://www.w3.org/TR/REC-xml/#NT-NameChar
13011 if (!/^([a-z][\w-.]*:)?[a-z_][\w-.]*$/i.test(id)) {
13012 throw new Error('illegal ID <' + id + '>');
13013 }
13014
13015 if (elementsById[id]) {
13016 throw error('duplicate ID <' + id + '>');
13017 }
13018
13019 elementsById[id] = element;
13020 }
13021 }
13022 };
13023
13024 /**
13025 * Add an import warning.
13026 *
13027 * @param {Object} warning
13028 * @param {String} warning.message
13029 * @param {Error} [warning.error]
13030 */
13031 this.addWarning = function(warning) {
13032 this.warnings.push(warning);
13033 };
13034 }
13035
13036 function BaseHandler() {}
13037
13038 BaseHandler.prototype.handleEnd = function() {};
13039 BaseHandler.prototype.handleText = function() {};
13040 BaseHandler.prototype.handleNode = function() {};
13041
13042
13043 /**
13044 * A simple pass through handler that does nothing except for
13045 * ignoring all input it receives.
13046 *
13047 * This is used to ignore unknown elements and
13048 * attributes.
13049 */
13050 function NoopHandler() { }
13051
13052 NoopHandler.prototype = Object.create(BaseHandler.prototype);
13053
13054 NoopHandler.prototype.handleNode = function() {
13055 return this;
13056 };
13057
13058 function BodyHandler() {}
13059
13060 BodyHandler.prototype = Object.create(BaseHandler.prototype);
13061
13062 BodyHandler.prototype.handleText = function(text) {
13063 this.body = (this.body || '') + text;
13064 };
13065
13066 function ReferenceHandler(property, context) {
13067 this.property = property;
13068 this.context = context;
13069 }
13070
13071 ReferenceHandler.prototype = Object.create(BodyHandler.prototype);
13072
13073 ReferenceHandler.prototype.handleNode = function(node) {
13074
13075 if (this.element) {
13076 throw error('expected no sub nodes');
13077 } else {
13078 this.element = this.createReference(node);
13079 }
13080
13081 return this;
13082 };
13083
13084 ReferenceHandler.prototype.handleEnd = function() {
13085 this.element.id = this.body;
13086 };
13087
13088 ReferenceHandler.prototype.createReference = function(node) {
13089 return {
13090 property: this.property.ns.name,
13091 id: ''
13092 };
13093 };
13094
13095 function ValueHandler(propertyDesc, element) {
13096 this.element = element;
13097 this.propertyDesc = propertyDesc;
13098 }
13099
13100 ValueHandler.prototype = Object.create(BodyHandler.prototype);
13101
13102 ValueHandler.prototype.handleEnd = function() {
13103
13104 var value = this.body || '',
13105 element = this.element,
13106 propertyDesc = this.propertyDesc;
13107
13108 value = coerceType(propertyDesc.type, value);
13109
13110 if (propertyDesc.isMany) {
13111 element.get(propertyDesc.name).push(value);
13112 } else {
13113 element.set(propertyDesc.name, value);
13114 }
13115 };
13116
13117
13118 function BaseElementHandler() {}
13119
13120 BaseElementHandler.prototype = Object.create(BodyHandler.prototype);
13121
13122 BaseElementHandler.prototype.handleNode = function(node) {
13123 var parser = this,
13124 element = this.element;
13125
13126 if (!element) {
13127 element = this.element = this.createElement(node);
13128
13129 this.context.addElement(element);
13130 } else {
13131 parser = this.handleChild(node);
13132 }
13133
13134 return parser;
13135 };
13136
13137 /**
13138 * @class Reader.ElementHandler
13139 *
13140 */
13141 function ElementHandler(model, typeName, context) {
13142 this.model = model;
13143 this.type = model.getType(typeName);
13144 this.context = context;
13145 }
13146
13147 ElementHandler.prototype = Object.create(BaseElementHandler.prototype);
13148
13149 ElementHandler.prototype.addReference = function(reference) {
13150 this.context.addReference(reference);
13151 };
13152
13153 ElementHandler.prototype.handleText = function(text) {
13154
13155 var element = this.element,
13156 descriptor = getModdleDescriptor(element),
13157 bodyProperty = descriptor.bodyProperty;
13158
13159 if (!bodyProperty) {
13160 throw error('unexpected body text <' + text + '>');
13161 }
13162
13163 BodyHandler.prototype.handleText.call(this, text);
13164 };
13165
13166 ElementHandler.prototype.handleEnd = function() {
13167
13168 var value = this.body,
13169 element = this.element,
13170 descriptor = getModdleDescriptor(element),
13171 bodyProperty = descriptor.bodyProperty;
13172
13173 if (bodyProperty && value !== undefined) {
13174 value = coerceType(bodyProperty.type, value);
13175 element.set(bodyProperty.name, value);
13176 }
13177 };
13178
13179 /**
13180 * Create an instance of the model from the given node.
13181 *
13182 * @param {Element} node the xml node
13183 */
13184 ElementHandler.prototype.createElement = function(node) {
13185 var attributes = node.attributes,
13186 Type = this.type,
13187 descriptor = getModdleDescriptor(Type),
13188 context = this.context,
13189 instance = new Type({}),
13190 model = this.model,
13191 propNameNs;
13192
13193 forEach(attributes, function(value, name) {
13194
13195 var prop = descriptor.propertiesByName[name],
13196 values;
13197
13198 if (prop && prop.isReference) {
13199
13200 if (!prop.isMany) {
13201 context.addReference({
13202 element: instance,
13203 property: prop.ns.name,
13204 id: value
13205 });
13206 } else {
13207
13208 // IDREFS: parse references as whitespace-separated list
13209 values = value.split(' ');
13210
13211 forEach(values, function(v) {
13212 context.addReference({
13213 element: instance,
13214 property: prop.ns.name,
13215 id: v
13216 });
13217 });
13218 }
13219
13220 } else {
13221 if (prop) {
13222 value = coerceType(prop.type, value);
13223 } else
13224 if (name !== 'xmlns') {
13225 propNameNs = parseName(name, descriptor.ns.prefix);
13226
13227 // check whether attribute is defined in a well-known namespace
13228 // if that is the case we emit a warning to indicate potential misuse
13229 if (model.getPackage(propNameNs.prefix)) {
13230
13231 context.addWarning({
13232 message: 'unknown attribute <' + name + '>',
13233 element: instance,
13234 property: name,
13235 value: value
13236 });
13237 }
13238 }
13239
13240 instance.set(name, value);
13241 }
13242 });
13243
13244 return instance;
13245 };
13246
13247 ElementHandler.prototype.getPropertyForNode = function(node) {
13248
13249 var name = node.name;
13250 var nameNs = parseName(name);
13251
13252 var type = this.type,
13253 model = this.model,
13254 descriptor = getModdleDescriptor(type);
13255
13256 var propertyName = nameNs.name,
13257 property = descriptor.propertiesByName[propertyName],
13258 elementTypeName,
13259 elementType;
13260
13261 // search for properties by name first
13262
13263 if (property && !property.isAttr) {
13264
13265 if (serializeAsType(property)) {
13266 elementTypeName = node.attributes[XSI_TYPE];
13267
13268 // xsi type is optional, if it does not exists the
13269 // default type is assumed
13270 if (elementTypeName) {
13271
13272 // take possible type prefixes from XML
13273 // into account, i.e.: xsi:type="t{ActualType}"
13274 elementTypeName = normalizeXsiTypeName(elementTypeName, model);
13275
13276 elementType = model.getType(elementTypeName);
13277
13278 return assign({}, property, {
13279 effectiveType: getModdleDescriptor(elementType).name
13280 });
13281 }
13282 }
13283
13284 // search for properties by name first
13285 return property;
13286 }
13287
13288 var pkg = model.getPackage(nameNs.prefix);
13289
13290 if (pkg) {
13291 elementTypeName = aliasToName(nameNs, pkg);
13292 elementType = model.getType(elementTypeName);
13293
13294 // search for collection members later
13295 property = find(descriptor.properties, function(p) {
13296 return !p.isVirtual && !p.isReference && !p.isAttribute && elementType.hasType(p.type);
13297 });
13298
13299 if (property) {
13300 return assign({}, property, {
13301 effectiveType: getModdleDescriptor(elementType).name
13302 });
13303 }
13304 } else {
13305
13306 // parse unknown element (maybe extension)
13307 property = find(descriptor.properties, function(p) {
13308 return !p.isReference && !p.isAttribute && p.type === 'Element';
13309 });
13310
13311 if (property) {
13312 return property;
13313 }
13314 }
13315
13316 throw error('unrecognized element <' + nameNs.name + '>');
13317 };
13318
13319 ElementHandler.prototype.toString = function() {
13320 return 'ElementDescriptor[' + getModdleDescriptor(this.type).name + ']';
13321 };
13322
13323 ElementHandler.prototype.valueHandler = function(propertyDesc, element) {
13324 return new ValueHandler(propertyDesc, element);
13325 };
13326
13327 ElementHandler.prototype.referenceHandler = function(propertyDesc) {
13328 return new ReferenceHandler(propertyDesc, this.context);
13329 };
13330
13331 ElementHandler.prototype.handler = function(type) {
13332 if (type === 'Element') {
13333 return new GenericElementHandler(this.model, type, this.context);
13334 } else {
13335 return new ElementHandler(this.model, type, this.context);
13336 }
13337 };
13338
13339 /**
13340 * Handle the child element parsing
13341 *
13342 * @param {Element} node the xml node
13343 */
13344 ElementHandler.prototype.handleChild = function(node) {
13345 var propertyDesc, type, element, childHandler;
13346
13347 propertyDesc = this.getPropertyForNode(node);
13348 element = this.element;
13349
13350 type = propertyDesc.effectiveType || propertyDesc.type;
13351
13352 if (isSimple(type)) {
13353 return this.valueHandler(propertyDesc, element);
13354 }
13355
13356 if (propertyDesc.isReference) {
13357 childHandler = this.referenceHandler(propertyDesc).handleNode(node);
13358 } else {
13359 childHandler = this.handler(type).handleNode(node);
13360 }
13361
13362 var newElement = childHandler.element;
13363
13364 // child handles may decide to skip elements
13365 // by not returning anything
13366 if (newElement !== undefined) {
13367
13368 if (propertyDesc.isMany) {
13369 element.get(propertyDesc.name).push(newElement);
13370 } else {
13371 element.set(propertyDesc.name, newElement);
13372 }
13373
13374 if (propertyDesc.isReference) {
13375 assign(newElement, {
13376 element: element
13377 });
13378
13379 this.context.addReference(newElement);
13380 } else {
13381
13382 // establish child -> parent relationship
13383 newElement.$parent = element;
13384 }
13385 }
13386
13387 return childHandler;
13388 };
13389
13390 /**
13391 * An element handler that performs special validation
13392 * to ensure the node it gets initialized with matches
13393 * the handlers type (namespace wise).
13394 *
13395 * @param {Moddle} model
13396 * @param {String} typeName
13397 * @param {Context} context
13398 */
13399 function RootElementHandler(model, typeName, context) {
13400 ElementHandler.call(this, model, typeName, context);
13401 }
13402
13403 RootElementHandler.prototype = Object.create(ElementHandler.prototype);
13404
13405 RootElementHandler.prototype.createElement = function(node) {
13406
13407 var name = node.name,
13408 nameNs = parseName(name),
13409 model = this.model,
13410 type = this.type,
13411 pkg = model.getPackage(nameNs.prefix),
13412 typeName = pkg && aliasToName(nameNs, pkg) || name;
13413
13414 // verify the correct namespace if we parse
13415 // the first element in the handler tree
13416 //
13417 // this ensures we don't mistakenly import wrong namespace elements
13418 if (!type.hasType(typeName)) {
13419 throw error('unexpected element <' + node.originalName + '>');
13420 }
13421
13422 return ElementHandler.prototype.createElement.call(this, node);
13423 };
13424
13425
13426 function GenericElementHandler(model, typeName, context) {
13427 this.model = model;
13428 this.context = context;
13429 }
13430
13431 GenericElementHandler.prototype = Object.create(BaseElementHandler.prototype);
13432
13433 GenericElementHandler.prototype.createElement = function(node) {
13434
13435 var name = node.name,
13436 ns = parseName(name),
13437 prefix = ns.prefix,
13438 uri = node.ns[prefix + '$uri'],
13439 attributes = node.attributes;
13440
13441 return this.model.createAny(name, uri, attributes);
13442 };
13443
13444 GenericElementHandler.prototype.handleChild = function(node) {
13445
13446 var handler = new GenericElementHandler(this.model, 'Element', this.context).handleNode(node),
13447 element = this.element;
13448
13449 var newElement = handler.element,
13450 children;
13451
13452 if (newElement !== undefined) {
13453 children = element.$children = element.$children || [];
13454 children.push(newElement);
13455
13456 // establish child -> parent relationship
13457 newElement.$parent = element;
13458 }
13459
13460 return handler;
13461 };
13462
13463 GenericElementHandler.prototype.handleEnd = function() {
13464 if (this.body) {
13465 this.element.$body = this.body;
13466 }
13467 };
13468
13469 /**
13470 * A reader for a meta-model
13471 *
13472 * @param {Object} options
13473 * @param {Model} options.model used to read xml files
13474 * @param {Boolean} options.lax whether to make parse errors warnings
13475 */
13476 function Reader(options) {
13477
13478 if (options instanceof Moddle) {
13479 options = {
13480 model: options
13481 };
13482 }
13483
13484 assign(this, { lax: false }, options);
13485 }
13486
13487 /**
13488 * The fromXML result.
13489 *
13490 * @typedef {Object} ParseResult
13491 *
13492 * @property {ModdleElement} rootElement
13493 * @property {Array<Object>} references
13494 * @property {Array<Error>} warnings
13495 * @property {Object} elementsById - a mapping containing each ID -> ModdleElement
13496 */
13497
13498 /**
13499 * The fromXML result.
13500 *
13501 * @typedef {Error} ParseError
13502 *
13503 * @property {Array<Error>} warnings
13504 */
13505
13506 /**
13507 * Parse the given XML into a moddle document tree.
13508 *
13509 * @param {String} xml
13510 * @param {ElementHandler|Object} options or rootHandler
13511 *
13512 * @returns {Promise<ParseResult, ParseError>}
13513 */
13514 Reader.prototype.fromXML = function(xml, options, done) {
13515
13516 var rootHandler = options.rootHandler;
13517
13518 if (options instanceof ElementHandler) {
13519
13520 // root handler passed via (xml, { rootHandler: ElementHandler }, ...)
13521 rootHandler = options;
13522 options = {};
13523 } else {
13524 if (typeof options === 'string') {
13525
13526 // rootHandler passed via (xml, 'someString', ...)
13527 rootHandler = this.handler(options);
13528 options = {};
13529 } else if (typeof rootHandler === 'string') {
13530
13531 // rootHandler passed via (xml, { rootHandler: 'someString' }, ...)
13532 rootHandler = this.handler(rootHandler);
13533 }
13534 }
13535
13536 var model = this.model,
13537 lax = this.lax;
13538
13539 var context = new Context(assign({}, options, { rootHandler: rootHandler })),
13540 parser = new Parser({ proxy: true }),
13541 stack = createStack();
13542
13543 rootHandler.context = context;
13544
13545 // push root handler
13546 stack.push(rootHandler);
13547
13548
13549 /**
13550 * Handle error.
13551 *
13552 * @param {Error} err
13553 * @param {Function} getContext
13554 * @param {boolean} lax
13555 *
13556 * @return {boolean} true if handled
13557 */
13558 function handleError(err, getContext, lax) {
13559
13560 var ctx = getContext();
13561
13562 var line = ctx.line,
13563 column = ctx.column,
13564 data = ctx.data;
13565
13566 // we receive the full context data here,
13567 // for elements trim down the information
13568 // to the tag name, only
13569 if (data.charAt(0) === '<' && data.indexOf(' ') !== -1) {
13570 data = data.slice(0, data.indexOf(' ')) + '>';
13571 }
13572
13573 var message =
13574 'unparsable content ' + (data ? data + ' ' : '') + 'detected\n\t' +
13575 'line: ' + line + '\n\t' +
13576 'column: ' + column + '\n\t' +
13577 'nested error: ' + err.message;
13578
13579 if (lax) {
13580 context.addWarning({
13581 message: message,
13582 error: err
13583 });
13584
13585 return true;
13586 } else {
13587 throw error(message);
13588 }
13589 }
13590
13591 function handleWarning(err, getContext) {
13592
13593 // just like handling errors in <lax=true> mode
13594 return handleError(err, getContext, true);
13595 }
13596
13597 /**
13598 * Resolve collected references on parse end.
13599 */
13600 function resolveReferences() {
13601
13602 var elementsById = context.elementsById;
13603 var references = context.references;
13604
13605 var i, r;
13606
13607 for (i = 0; (r = references[i]); i++) {
13608 var element = r.element;
13609 var reference = elementsById[r.id];
13610 var property = getModdleDescriptor(element).propertiesByName[r.property];
13611
13612 if (!reference) {
13613 context.addWarning({
13614 message: 'unresolved reference <' + r.id + '>',
13615 element: r.element,
13616 property: r.property,
13617 value: r.id
13618 });
13619 }
13620
13621 if (property.isMany) {
13622 var collection = element.get(property.name),
13623 idx = collection.indexOf(r);
13624
13625 // we replace an existing place holder (idx != -1) or
13626 // append to the collection instead
13627 if (idx === -1) {
13628 idx = collection.length;
13629 }
13630
13631 if (!reference) {
13632
13633 // remove unresolvable reference
13634 collection.splice(idx, 1);
13635 } else {
13636
13637 // add or update reference in collection
13638 collection[idx] = reference;
13639 }
13640 } else {
13641 element.set(property.name, reference);
13642 }
13643 }
13644 }
13645
13646 function handleClose() {
13647 stack.pop().handleEnd();
13648 }
13649
13650 var PREAMBLE_START_PATTERN = /^<\?xml /i;
13651
13652 var ENCODING_PATTERN = / encoding="([^"]+)"/i;
13653
13654 var UTF_8_PATTERN = /^utf-8$/i;
13655
13656 function handleQuestion(question) {
13657
13658 if (!PREAMBLE_START_PATTERN.test(question)) {
13659 return;
13660 }
13661
13662 var match = ENCODING_PATTERN.exec(question);
13663 var encoding = match && match[1];
13664
13665 if (!encoding || UTF_8_PATTERN.test(encoding)) {
13666 return;
13667 }
13668
13669 context.addWarning({
13670 message:
13671 'unsupported document encoding <' + encoding + '>, ' +
13672 'falling back to UTF-8'
13673 });
13674 }
13675
13676 function handleOpen(node, getContext) {
13677 var handler = stack.peek();
13678
13679 try {
13680 stack.push(handler.handleNode(node));
13681 } catch (err) {
13682
13683 if (handleError(err, getContext, lax)) {
13684 stack.push(new NoopHandler());
13685 }
13686 }
13687 }
13688
13689 function handleCData(text, getContext) {
13690
13691 try {
13692 stack.peek().handleText(text);
13693 } catch (err) {
13694 handleWarning(err, getContext);
13695 }
13696 }
13697
13698 function handleText(text, getContext) {
13699
13700 // strip whitespace only nodes, i.e. before
13701 // <!CDATA[ ... ]> sections and in between tags
13702
13703 if (!text.trim()) {
13704 return;
13705 }
13706
13707 handleCData(text, getContext);
13708 }
13709
13710 var uriMap = model.getPackages().reduce(function(uriMap, p) {
13711 uriMap[p.uri] = p.prefix;
13712
13713 return uriMap;
13714 }, {
13715 'http://www.w3.org/XML/1998/namespace': 'xml' // add default xml ns
13716 });
13717 parser
13718 .ns(uriMap)
13719 .on('openTag', function(obj, decodeStr, selfClosing, getContext) {
13720
13721 // gracefully handle unparsable attributes (attrs=false)
13722 var attrs = obj.attrs || {};
13723
13724 var decodedAttrs = Object.keys(attrs).reduce(function(d, key) {
13725 var value = decodeStr(attrs[key]);
13726
13727 d[key] = value;
13728
13729 return d;
13730 }, {});
13731
13732 var node = {
13733 name: obj.name,
13734 originalName: obj.originalName,
13735 attributes: decodedAttrs,
13736 ns: obj.ns
13737 };
13738
13739 handleOpen(node, getContext);
13740 })
13741 .on('question', handleQuestion)
13742 .on('closeTag', handleClose)
13743 .on('cdata', handleCData)
13744 .on('text', function(text, decodeEntities, getContext) {
13745 handleText(decodeEntities(text), getContext);
13746 })
13747 .on('error', handleError)
13748 .on('warn', handleWarning);
13749
13750 // async XML parsing to make sure the execution environment
13751 // (node or brower) is kept responsive and that certain optimization
13752 // strategies can kick in.
13753 return new Promise(function(resolve, reject) {
13754
13755 var err;
13756
13757 try {
13758 parser.parse(xml);
13759
13760 resolveReferences();
13761 } catch (e) {
13762 err = e;
13763 }
13764
13765 var rootElement = rootHandler.element;
13766
13767 if (!err && !rootElement) {
13768 err = error('failed to parse document as <' + rootHandler.type.$descriptor.name + '>');
13769 }
13770
13771 var warnings = context.warnings;
13772 var references = context.references;
13773 var elementsById = context.elementsById;
13774
13775 if (err) {
13776 err.warnings = warnings;
13777
13778 return reject(err);
13779 } else {
13780 return resolve({
13781 rootElement: rootElement,
13782 elementsById: elementsById,
13783 references: references,
13784 warnings: warnings
13785 });
13786 }
13787 });
13788 };
13789
13790 Reader.prototype.handler = function(name) {
13791 return new RootElementHandler(this.model, name);
13792 };
13793
13794
13795 // helpers //////////////////////////
13796
13797 function createStack() {
13798 var stack = [];
13799
13800 Object.defineProperty(stack, 'peek', {
13801 value: function() {
13802 return this[this.length - 1];
13803 }
13804 });
13805
13806 return stack;
13807 }
13808
13809 var XML_PREAMBLE = '<?xml version="1.0" encoding="UTF-8"?>\n';
13810
13811 var ESCAPE_ATTR_CHARS = /<|>|'|"|&|\n\r|\n/g;
13812 var ESCAPE_CHARS = /<|>|&/g;
13813
13814
13815 function Namespaces(parent) {
13816
13817 var prefixMap = {};
13818 var uriMap = {};
13819 var used = {};
13820
13821 var wellknown = [];
13822 var custom = [];
13823
13824 // API
13825
13826 this.byUri = function(uri) {
13827 return uriMap[uri] || (
13828 parent && parent.byUri(uri)
13829 );
13830 };
13831
13832 this.add = function(ns, isWellknown) {
13833
13834 uriMap[ns.uri] = ns;
13835
13836 if (isWellknown) {
13837 wellknown.push(ns);
13838 } else {
13839 custom.push(ns);
13840 }
13841
13842 this.mapPrefix(ns.prefix, ns.uri);
13843 };
13844
13845 this.uriByPrefix = function(prefix) {
13846 return prefixMap[prefix || 'xmlns'];
13847 };
13848
13849 this.mapPrefix = function(prefix, uri) {
13850 prefixMap[prefix || 'xmlns'] = uri;
13851 };
13852
13853 this.getNSKey = function(ns) {
13854 return (ns.prefix !== undefined) ? (ns.uri + '|' + ns.prefix) : ns.uri;
13855 };
13856
13857 this.logUsed = function(ns) {
13858
13859 var uri = ns.uri;
13860 var nsKey = this.getNSKey(ns);
13861
13862 used[nsKey] = this.byUri(uri);
13863
13864 // Inform parent recursively about the usage of this NS
13865 if (parent) {
13866 parent.logUsed(ns);
13867 }
13868 };
13869
13870 this.getUsed = function(ns) {
13871
13872 function isUsed(ns) {
13873 var nsKey = self.getNSKey(ns);
13874
13875 return used[nsKey];
13876 }
13877
13878 var self = this;
13879
13880 var allNs = [].concat(wellknown, custom);
13881
13882 return allNs.filter(isUsed);
13883 };
13884
13885 }
13886
13887 function lower(string) {
13888 return string.charAt(0).toLowerCase() + string.slice(1);
13889 }
13890
13891 function nameToAlias(name, pkg) {
13892 if (hasLowerCaseAlias(pkg)) {
13893 return lower(name);
13894 } else {
13895 return name;
13896 }
13897 }
13898
13899 function inherits(ctor, superCtor) {
13900 ctor.super_ = superCtor;
13901 ctor.prototype = Object.create(superCtor.prototype, {
13902 constructor: {
13903 value: ctor,
13904 enumerable: false,
13905 writable: true,
13906 configurable: true
13907 }
13908 });
13909 }
13910
13911 function nsName(ns) {
13912 if (isString(ns)) {
13913 return ns;
13914 } else {
13915 return (ns.prefix ? ns.prefix + ':' : '') + ns.localName;
13916 }
13917 }
13918
13919 function getNsAttrs(namespaces) {
13920
13921 return namespaces.getUsed().filter(function(ns) {
13922
13923 // do not serialize built in <xml> namespace
13924 return ns.prefix !== 'xml';
13925 }).map(function(ns) {
13926 var name = 'xmlns' + (ns.prefix ? ':' + ns.prefix : '');
13927 return { name: name, value: ns.uri };
13928 });
13929
13930 }
13931
13932 function getElementNs(ns, descriptor) {
13933 if (descriptor.isGeneric) {
13934 return assign({ localName: descriptor.ns.localName }, ns);
13935 } else {
13936 return assign({ localName: nameToAlias(descriptor.ns.localName, descriptor.$pkg) }, ns);
13937 }
13938 }
13939
13940 function getPropertyNs(ns, descriptor) {
13941 return assign({ localName: descriptor.ns.localName }, ns);
13942 }
13943
13944 function getSerializableProperties(element) {
13945 var descriptor = element.$descriptor;
13946
13947 return filter(descriptor.properties, function(p) {
13948 var name = p.name;
13949
13950 if (p.isVirtual) {
13951 return false;
13952 }
13953
13954 // do not serialize defaults
13955 if (!has(element, name)) {
13956 return false;
13957 }
13958
13959 var value = element[name];
13960
13961 // do not serialize default equals
13962 if (value === p.default) {
13963 return false;
13964 }
13965
13966 // do not serialize null properties
13967 if (value === null) {
13968 return false;
13969 }
13970
13971 return p.isMany ? value.length : true;
13972 });
13973 }
13974
13975 var ESCAPE_ATTR_MAP = {
13976 '\n': '#10',
13977 '\n\r': '#10',
13978 '"': '#34',
13979 '\'': '#39',
13980 '<': '#60',
13981 '>': '#62',
13982 '&': '#38'
13983 };
13984
13985 var ESCAPE_MAP = {
13986 '<': 'lt',
13987 '>': 'gt',
13988 '&': 'amp'
13989 };
13990
13991 function escape(str, charPattern, replaceMap) {
13992
13993 // ensure we are handling strings here
13994 str = isString(str) ? str : '' + str;
13995
13996 return str.replace(charPattern, function(s) {
13997 return '&' + replaceMap[s] + ';';
13998 });
13999 }
14000
14001 /**
14002 * Escape a string attribute to not contain any bad values (line breaks, '"', ...)
14003 *
14004 * @param {String} str the string to escape
14005 * @return {String} the escaped string
14006 */
14007 function escapeAttr(str) {
14008 return escape(str, ESCAPE_ATTR_CHARS, ESCAPE_ATTR_MAP);
14009 }
14010
14011 function escapeBody(str) {
14012 return escape(str, ESCAPE_CHARS, ESCAPE_MAP);
14013 }
14014
14015 function filterAttributes(props) {
14016 return filter(props, function(p) { return p.isAttr; });
14017 }
14018
14019 function filterContained(props) {
14020 return filter(props, function(p) { return !p.isAttr; });
14021 }
14022
14023
14024 function ReferenceSerializer(tagName) {
14025 this.tagName = tagName;
14026 }
14027
14028 ReferenceSerializer.prototype.build = function(element) {
14029 this.element = element;
14030 return this;
14031 };
14032
14033 ReferenceSerializer.prototype.serializeTo = function(writer) {
14034 writer
14035 .appendIndent()
14036 .append('<' + this.tagName + '>' + this.element.id + '</' + this.tagName + '>')
14037 .appendNewLine();
14038 };
14039
14040 function BodySerializer() {}
14041
14042 BodySerializer.prototype.serializeValue =
14043 BodySerializer.prototype.serializeTo = function(writer) {
14044 writer.append(
14045 this.escape
14046 ? escapeBody(this.value)
14047 : this.value
14048 );
14049 };
14050
14051 BodySerializer.prototype.build = function(prop, value) {
14052 this.value = value;
14053
14054 if (prop.type === 'String' && value.search(ESCAPE_CHARS) !== -1) {
14055 this.escape = true;
14056 }
14057
14058 return this;
14059 };
14060
14061 function ValueSerializer(tagName) {
14062 this.tagName = tagName;
14063 }
14064
14065 inherits(ValueSerializer, BodySerializer);
14066
14067 ValueSerializer.prototype.serializeTo = function(writer) {
14068
14069 writer
14070 .appendIndent()
14071 .append('<' + this.tagName + '>');
14072
14073 this.serializeValue(writer);
14074
14075 writer
14076 .append('</' + this.tagName + '>')
14077 .appendNewLine();
14078 };
14079
14080 function ElementSerializer(parent, propertyDescriptor) {
14081 this.body = [];
14082 this.attrs = [];
14083
14084 this.parent = parent;
14085 this.propertyDescriptor = propertyDescriptor;
14086 }
14087
14088 ElementSerializer.prototype.build = function(element) {
14089 this.element = element;
14090
14091 var elementDescriptor = element.$descriptor,
14092 propertyDescriptor = this.propertyDescriptor;
14093
14094 var otherAttrs,
14095 properties;
14096
14097 var isGeneric = elementDescriptor.isGeneric;
14098
14099 if (isGeneric) {
14100 otherAttrs = this.parseGeneric(element);
14101 } else {
14102 otherAttrs = this.parseNsAttributes(element);
14103 }
14104
14105 if (propertyDescriptor) {
14106 this.ns = this.nsPropertyTagName(propertyDescriptor);
14107 } else {
14108 this.ns = this.nsTagName(elementDescriptor);
14109 }
14110
14111 // compute tag name
14112 this.tagName = this.addTagName(this.ns);
14113
14114 if (!isGeneric) {
14115 properties = getSerializableProperties(element);
14116
14117 this.parseAttributes(filterAttributes(properties));
14118 this.parseContainments(filterContained(properties));
14119 }
14120
14121 this.parseGenericAttributes(element, otherAttrs);
14122
14123 return this;
14124 };
14125
14126 ElementSerializer.prototype.nsTagName = function(descriptor) {
14127 var effectiveNs = this.logNamespaceUsed(descriptor.ns);
14128 return getElementNs(effectiveNs, descriptor);
14129 };
14130
14131 ElementSerializer.prototype.nsPropertyTagName = function(descriptor) {
14132 var effectiveNs = this.logNamespaceUsed(descriptor.ns);
14133 return getPropertyNs(effectiveNs, descriptor);
14134 };
14135
14136 ElementSerializer.prototype.isLocalNs = function(ns) {
14137 return ns.uri === this.ns.uri;
14138 };
14139
14140 /**
14141 * Get the actual ns attribute name for the given element.
14142 *
14143 * @param {Object} element
14144 * @param {Boolean} [element.inherited=false]
14145 *
14146 * @return {Object} nsName
14147 */
14148 ElementSerializer.prototype.nsAttributeName = function(element) {
14149
14150 var ns;
14151
14152 if (isString(element)) {
14153 ns = parseName(element);
14154 } else {
14155 ns = element.ns;
14156 }
14157
14158 // return just local name for inherited attributes
14159 if (element.inherited) {
14160 return { localName: ns.localName };
14161 }
14162
14163 // parse + log effective ns
14164 var effectiveNs = this.logNamespaceUsed(ns);
14165
14166 // LOG ACTUAL namespace use
14167 this.getNamespaces().logUsed(effectiveNs);
14168
14169 // strip prefix if same namespace like parent
14170 if (this.isLocalNs(effectiveNs)) {
14171 return { localName: ns.localName };
14172 } else {
14173 return assign({ localName: ns.localName }, effectiveNs);
14174 }
14175 };
14176
14177 ElementSerializer.prototype.parseGeneric = function(element) {
14178
14179 var self = this,
14180 body = this.body;
14181
14182 var attributes = [];
14183
14184 forEach(element, function(val, key) {
14185
14186 var nonNsAttr;
14187
14188 if (key === '$body') {
14189 body.push(new BodySerializer().build({ type: 'String' }, val));
14190 } else
14191 if (key === '$children') {
14192 forEach(val, function(child) {
14193 body.push(new ElementSerializer(self).build(child));
14194 });
14195 } else
14196 if (key.indexOf('$') !== 0) {
14197 nonNsAttr = self.parseNsAttribute(element, key, val);
14198
14199 if (nonNsAttr) {
14200 attributes.push({ name: key, value: val });
14201 }
14202 }
14203 });
14204
14205 return attributes;
14206 };
14207
14208 ElementSerializer.prototype.parseNsAttribute = function(element, name, value) {
14209 var model = element.$model;
14210
14211 var nameNs = parseName(name);
14212
14213 var ns;
14214
14215 // parse xmlns:foo="http://foo.bar"
14216 if (nameNs.prefix === 'xmlns') {
14217 ns = { prefix: nameNs.localName, uri: value };
14218 }
14219
14220 // parse xmlns="http://foo.bar"
14221 if (!nameNs.prefix && nameNs.localName === 'xmlns') {
14222 ns = { uri: value };
14223 }
14224
14225 if (!ns) {
14226 return {
14227 name: name,
14228 value: value
14229 };
14230 }
14231
14232 if (model && model.getPackage(value)) {
14233
14234 // register well known namespace
14235 this.logNamespace(ns, true, true);
14236 } else {
14237
14238 // log custom namespace directly as used
14239 var actualNs = this.logNamespaceUsed(ns, true);
14240
14241 this.getNamespaces().logUsed(actualNs);
14242 }
14243 };
14244
14245
14246 /**
14247 * Parse namespaces and return a list of left over generic attributes
14248 *
14249 * @param {Object} element
14250 * @return {Array<Object>}
14251 */
14252 ElementSerializer.prototype.parseNsAttributes = function(element, attrs) {
14253 var self = this;
14254
14255 var genericAttrs = element.$attrs;
14256
14257 var attributes = [];
14258
14259 // parse namespace attributes first
14260 // and log them. push non namespace attributes to a list
14261 // and process them later
14262 forEach(genericAttrs, function(value, name) {
14263
14264 var nonNsAttr = self.parseNsAttribute(element, name, value);
14265
14266 if (nonNsAttr) {
14267 attributes.push(nonNsAttr);
14268 }
14269 });
14270
14271 return attributes;
14272 };
14273
14274 ElementSerializer.prototype.parseGenericAttributes = function(element, attributes) {
14275
14276 var self = this;
14277
14278 forEach(attributes, function(attr) {
14279
14280 // do not serialize xsi:type attribute
14281 // it is set manually based on the actual implementation type
14282 if (attr.name === XSI_TYPE) {
14283 return;
14284 }
14285
14286 try {
14287 self.addAttribute(self.nsAttributeName(attr.name), attr.value);
14288 } catch (e) {
14289 console.warn(
14290 'missing namespace information for ',
14291 attr.name, '=', attr.value, 'on', element,
14292 e);
14293 }
14294 });
14295 };
14296
14297 ElementSerializer.prototype.parseContainments = function(properties) {
14298
14299 var self = this,
14300 body = this.body,
14301 element = this.element;
14302
14303 forEach(properties, function(p) {
14304 var value = element.get(p.name),
14305 isReference = p.isReference,
14306 isMany = p.isMany;
14307
14308 if (!isMany) {
14309 value = [ value ];
14310 }
14311
14312 if (p.isBody) {
14313 body.push(new BodySerializer().build(p, value[0]));
14314 } else
14315 if (isSimple(p.type)) {
14316 forEach(value, function(v) {
14317 body.push(new ValueSerializer(self.addTagName(self.nsPropertyTagName(p))).build(p, v));
14318 });
14319 } else
14320 if (isReference) {
14321 forEach(value, function(v) {
14322 body.push(new ReferenceSerializer(self.addTagName(self.nsPropertyTagName(p))).build(v));
14323 });
14324 } else {
14325
14326 // allow serialization via type
14327 // rather than element name
14328 var asType = serializeAsType(p),
14329 asProperty = serializeAsProperty(p);
14330
14331 forEach(value, function(v) {
14332 var serializer;
14333
14334 if (asType) {
14335 serializer = new TypeSerializer(self, p);
14336 } else
14337 if (asProperty) {
14338 serializer = new ElementSerializer(self, p);
14339 } else {
14340 serializer = new ElementSerializer(self);
14341 }
14342
14343 body.push(serializer.build(v));
14344 });
14345 }
14346 });
14347 };
14348
14349 ElementSerializer.prototype.getNamespaces = function(local) {
14350
14351 var namespaces = this.namespaces,
14352 parent = this.parent,
14353 parentNamespaces;
14354
14355 if (!namespaces) {
14356 parentNamespaces = parent && parent.getNamespaces();
14357
14358 if (local || !parentNamespaces) {
14359 this.namespaces = namespaces = new Namespaces(parentNamespaces);
14360 } else {
14361 namespaces = parentNamespaces;
14362 }
14363 }
14364
14365 return namespaces;
14366 };
14367
14368 ElementSerializer.prototype.logNamespace = function(ns, wellknown, local) {
14369 var namespaces = this.getNamespaces(local);
14370
14371 var nsUri = ns.uri,
14372 nsPrefix = ns.prefix;
14373
14374 var existing = namespaces.byUri(nsUri);
14375
14376 if (!existing || local) {
14377 namespaces.add(ns, wellknown);
14378 }
14379
14380 namespaces.mapPrefix(nsPrefix, nsUri);
14381
14382 return ns;
14383 };
14384
14385 ElementSerializer.prototype.logNamespaceUsed = function(ns, local) {
14386 var element = this.element,
14387 model = element.$model,
14388 namespaces = this.getNamespaces(local);
14389
14390 // ns may be
14391 //
14392 // * prefix only
14393 // * prefix:uri
14394 // * localName only
14395
14396 var prefix = ns.prefix,
14397 uri = ns.uri,
14398 newPrefix, idx,
14399 wellknownUri;
14400
14401 // handle anonymous namespaces (elementForm=unqualified), cf. #23
14402 if (!prefix && !uri) {
14403 return { localName: ns.localName };
14404 }
14405
14406 wellknownUri = DEFAULT_NS_MAP[prefix] || model && (model.getPackage(prefix) || {}).uri;
14407
14408 uri = uri || wellknownUri || namespaces.uriByPrefix(prefix);
14409
14410 if (!uri) {
14411 throw new Error('no namespace uri given for prefix <' + prefix + '>');
14412 }
14413
14414 ns = namespaces.byUri(uri);
14415
14416 if (!ns) {
14417 newPrefix = prefix;
14418 idx = 1;
14419
14420 // find a prefix that is not mapped yet
14421 while (namespaces.uriByPrefix(newPrefix)) {
14422 newPrefix = prefix + '_' + idx++;
14423 }
14424
14425 ns = this.logNamespace({ prefix: newPrefix, uri: uri }, wellknownUri === uri);
14426 }
14427
14428 if (prefix) {
14429 namespaces.mapPrefix(prefix, uri);
14430 }
14431
14432 return ns;
14433 };
14434
14435 ElementSerializer.prototype.parseAttributes = function(properties) {
14436 var self = this,
14437 element = this.element;
14438
14439 forEach(properties, function(p) {
14440
14441 var value = element.get(p.name);
14442
14443 if (p.isReference) {
14444
14445 if (!p.isMany) {
14446 value = value.id;
14447 }
14448 else {
14449 var values = [];
14450 forEach(value, function(v) {
14451 values.push(v.id);
14452 });
14453
14454 // IDREFS is a whitespace-separated list of references.
14455 value = values.join(' ');
14456 }
14457
14458 }
14459
14460 self.addAttribute(self.nsAttributeName(p), value);
14461 });
14462 };
14463
14464 ElementSerializer.prototype.addTagName = function(nsTagName) {
14465 var actualNs = this.logNamespaceUsed(nsTagName);
14466
14467 this.getNamespaces().logUsed(actualNs);
14468
14469 return nsName(nsTagName);
14470 };
14471
14472 ElementSerializer.prototype.addAttribute = function(name, value) {
14473 var attrs = this.attrs;
14474
14475 if (isString(value)) {
14476 value = escapeAttr(value);
14477 }
14478
14479 attrs.push({ name: name, value: value });
14480 };
14481
14482 ElementSerializer.prototype.serializeAttributes = function(writer) {
14483 var attrs = this.attrs,
14484 namespaces = this.namespaces;
14485
14486 if (namespaces) {
14487 attrs = getNsAttrs(namespaces).concat(attrs);
14488 }
14489
14490 forEach(attrs, function(a) {
14491 writer
14492 .append(' ')
14493 .append(nsName(a.name)).append('="').append(a.value).append('"');
14494 });
14495 };
14496
14497 ElementSerializer.prototype.serializeTo = function(writer) {
14498 var firstBody = this.body[0],
14499 indent = firstBody && firstBody.constructor !== BodySerializer;
14500
14501 writer
14502 .appendIndent()
14503 .append('<' + this.tagName);
14504
14505 this.serializeAttributes(writer);
14506
14507 writer.append(firstBody ? '>' : ' />');
14508
14509 if (firstBody) {
14510
14511 if (indent) {
14512 writer
14513 .appendNewLine()
14514 .indent();
14515 }
14516
14517 forEach(this.body, function(b) {
14518 b.serializeTo(writer);
14519 });
14520
14521 if (indent) {
14522 writer
14523 .unindent()
14524 .appendIndent();
14525 }
14526
14527 writer.append('</' + this.tagName + '>');
14528 }
14529
14530 writer.appendNewLine();
14531 };
14532
14533 /**
14534 * A serializer for types that handles serialization of data types
14535 */
14536 function TypeSerializer(parent, propertyDescriptor) {
14537 ElementSerializer.call(this, parent, propertyDescriptor);
14538 }
14539
14540 inherits(TypeSerializer, ElementSerializer);
14541
14542 TypeSerializer.prototype.parseNsAttributes = function(element) {
14543
14544 // extracted attributes
14545 var attributes = ElementSerializer.prototype.parseNsAttributes.call(this, element);
14546
14547 var descriptor = element.$descriptor;
14548
14549 // only serialize xsi:type if necessary
14550 if (descriptor.name === this.propertyDescriptor.type) {
14551 return attributes;
14552 }
14553
14554 var typeNs = this.typeNs = this.nsTagName(descriptor);
14555 this.getNamespaces().logUsed(this.typeNs);
14556
14557 // add xsi:type attribute to represent the elements
14558 // actual type
14559
14560 var pkg = element.$model.getPackage(typeNs.uri),
14561 typePrefix = (pkg.xml && pkg.xml.typePrefix) || '';
14562
14563 this.addAttribute(
14564 this.nsAttributeName(XSI_TYPE),
14565 (typeNs.prefix ? typeNs.prefix + ':' : '') + typePrefix + descriptor.ns.localName
14566 );
14567
14568 return attributes;
14569 };
14570
14571 TypeSerializer.prototype.isLocalNs = function(ns) {
14572 return ns.uri === (this.typeNs || this.ns).uri;
14573 };
14574
14575 function SavingWriter() {
14576 this.value = '';
14577
14578 this.write = function(str) {
14579 this.value += str;
14580 };
14581 }
14582
14583 function FormatingWriter(out, format) {
14584
14585 var indent = [''];
14586
14587 this.append = function(str) {
14588 out.write(str);
14589
14590 return this;
14591 };
14592
14593 this.appendNewLine = function() {
14594 if (format) {
14595 out.write('\n');
14596 }
14597
14598 return this;
14599 };
14600
14601 this.appendIndent = function() {
14602 if (format) {
14603 out.write(indent.join(' '));
14604 }
14605
14606 return this;
14607 };
14608
14609 this.indent = function() {
14610 indent.push('');
14611 return this;
14612 };
14613
14614 this.unindent = function() {
14615 indent.pop();
14616 return this;
14617 };
14618 }
14619
14620 /**
14621 * A writer for meta-model backed document trees
14622 *
14623 * @param {Object} options output options to pass into the writer
14624 */
14625 function Writer(options) {
14626
14627 options = assign({ format: false, preamble: true }, options || {});
14628
14629 function toXML(tree, writer) {
14630 var internalWriter = writer || new SavingWriter();
14631 var formatingWriter = new FormatingWriter(internalWriter, options.format);
14632
14633 if (options.preamble) {
14634 formatingWriter.append(XML_PREAMBLE);
14635 }
14636
14637 new ElementSerializer().build(tree).serializeTo(formatingWriter);
14638
14639 if (!writer) {
14640 return internalWriter.value;
14641 }
14642 }
14643
14644 return {
14645 toXML: toXML
14646 };
14647 }
14648
14649 /**
14650 * A sub class of {@link Moddle} with support for import and export of BPMN 2.0 xml files.
14651 *
14652 * @class BpmnModdle
14653 * @extends Moddle
14654 *
14655 * @param {Object|Array} packages to use for instantiating the model
14656 * @param {Object} [options] additional options to pass over
14657 */
14658 function BpmnModdle(packages, options) {
14659 Moddle.call(this, packages, options);
14660 }
14661
14662 BpmnModdle.prototype = Object.create(Moddle.prototype);
14663
14664 /**
14665 * The fromXML result.
14666 *
14667 * @typedef {Object} ParseResult
14668 *
14669 * @property {ModdleElement} rootElement
14670 * @property {Array<Object>} references
14671 * @property {Array<Error>} warnings
14672 * @property {Object} elementsById - a mapping containing each ID -> ModdleElement
14673 */
14674
14675 /**
14676 * The fromXML error.
14677 *
14678 * @typedef {Error} ParseError
14679 *
14680 * @property {Array<Error>} warnings
14681 */
14682
14683 /**
14684 * Instantiates a BPMN model tree from a given xml string.
14685 *
14686 * @param {String} xmlStr
14687 * @param {String} [typeName='bpmn:Definitions'] name of the root element
14688 * @param {Object} [options] options to pass to the underlying reader
14689 *
14690 * @returns {Promise<ParseResult, ParseError>}
14691 */
14692 BpmnModdle.prototype.fromXML = function(xmlStr, typeName, options) {
14693
14694 if (!isString(typeName)) {
14695 options = typeName;
14696 typeName = 'bpmn:Definitions';
14697 }
14698
14699 var reader = new Reader(assign({ model: this, lax: true }, options));
14700 var rootHandler = reader.handler(typeName);
14701
14702 return reader.fromXML(xmlStr, rootHandler);
14703 };
14704
14705
14706 /**
14707 * The toXML result.
14708 *
14709 * @typedef {Object} SerializationResult
14710 *
14711 * @property {String} xml
14712 */
14713
14714 /**
14715 * Serializes a BPMN 2.0 object tree to XML.
14716 *
14717 * @param {String} element the root element, typically an instance of `bpmn:Definitions`
14718 * @param {Object} [options] to pass to the underlying writer
14719 *
14720 * @returns {Promise<SerializationResult, Error>}
14721 */
14722 BpmnModdle.prototype.toXML = function(element, options) {
14723
14724 var writer = new Writer(options);
14725
14726 return new Promise(function(resolve, reject) {
14727 try {
14728 var result = writer.toXML(element);
14729
14730 return resolve({
14731 xml: result
14732 });
14733 } catch (err) {
14734 return reject(err);
14735 }
14736 });
14737 };
14738
14739 var name = "BPMN20";
14740 var uri = "http://www.omg.org/spec/BPMN/20100524/MODEL";
14741 var prefix = "bpmn";
14742 var associations = [
14743 ];
14744 var types = [
14745 {
14746 name: "Interface",
14747 superClass: [
14748 "RootElement"
14749 ],
14750 properties: [
14751 {
14752 name: "name",
14753 isAttr: true,
14754 type: "String"
14755 },
14756 {
14757 name: "operations",
14758 type: "Operation",
14759 isMany: true
14760 },
14761 {
14762 name: "implementationRef",
14763 isAttr: true,
14764 type: "String"
14765 }
14766 ]
14767 },
14768 {
14769 name: "Operation",
14770 superClass: [
14771 "BaseElement"
14772 ],
14773 properties: [
14774 {
14775 name: "name",
14776 isAttr: true,
14777 type: "String"
14778 },
14779 {
14780 name: "inMessageRef",
14781 type: "Message",
14782 isReference: true
14783 },
14784 {
14785 name: "outMessageRef",
14786 type: "Message",
14787 isReference: true
14788 },
14789 {
14790 name: "errorRef",
14791 type: "Error",
14792 isMany: true,
14793 isReference: true
14794 },
14795 {
14796 name: "implementationRef",
14797 isAttr: true,
14798 type: "String"
14799 }
14800 ]
14801 },
14802 {
14803 name: "EndPoint",
14804 superClass: [
14805 "RootElement"
14806 ]
14807 },
14808 {
14809 name: "Auditing",
14810 superClass: [
14811 "BaseElement"
14812 ]
14813 },
14814 {
14815 name: "GlobalTask",
14816 superClass: [
14817 "CallableElement"
14818 ],
14819 properties: [
14820 {
14821 name: "resources",
14822 type: "ResourceRole",
14823 isMany: true
14824 }
14825 ]
14826 },
14827 {
14828 name: "Monitoring",
14829 superClass: [
14830 "BaseElement"
14831 ]
14832 },
14833 {
14834 name: "Performer",
14835 superClass: [
14836 "ResourceRole"
14837 ]
14838 },
14839 {
14840 name: "Process",
14841 superClass: [
14842 "FlowElementsContainer",
14843 "CallableElement"
14844 ],
14845 properties: [
14846 {
14847 name: "processType",
14848 type: "ProcessType",
14849 isAttr: true
14850 },
14851 {
14852 name: "isClosed",
14853 isAttr: true,
14854 type: "Boolean"
14855 },
14856 {
14857 name: "auditing",
14858 type: "Auditing"
14859 },
14860 {
14861 name: "monitoring",
14862 type: "Monitoring"
14863 },
14864 {
14865 name: "properties",
14866 type: "Property",
14867 isMany: true
14868 },
14869 {
14870 name: "laneSets",
14871 isMany: true,
14872 replaces: "FlowElementsContainer#laneSets",
14873 type: "LaneSet"
14874 },
14875 {
14876 name: "flowElements",
14877 isMany: true,
14878 replaces: "FlowElementsContainer#flowElements",
14879 type: "FlowElement"
14880 },
14881 {
14882 name: "artifacts",
14883 type: "Artifact",
14884 isMany: true
14885 },
14886 {
14887 name: "resources",
14888 type: "ResourceRole",
14889 isMany: true
14890 },
14891 {
14892 name: "correlationSubscriptions",
14893 type: "CorrelationSubscription",
14894 isMany: true
14895 },
14896 {
14897 name: "supports",
14898 type: "Process",
14899 isMany: true,
14900 isReference: true
14901 },
14902 {
14903 name: "definitionalCollaborationRef",
14904 type: "Collaboration",
14905 isAttr: true,
14906 isReference: true
14907 },
14908 {
14909 name: "isExecutable",
14910 isAttr: true,
14911 type: "Boolean"
14912 }
14913 ]
14914 },
14915 {
14916 name: "LaneSet",
14917 superClass: [
14918 "BaseElement"
14919 ],
14920 properties: [
14921 {
14922 name: "lanes",
14923 type: "Lane",
14924 isMany: true
14925 },
14926 {
14927 name: "name",
14928 isAttr: true,
14929 type: "String"
14930 }
14931 ]
14932 },
14933 {
14934 name: "Lane",
14935 superClass: [
14936 "BaseElement"
14937 ],
14938 properties: [
14939 {
14940 name: "name",
14941 isAttr: true,
14942 type: "String"
14943 },
14944 {
14945 name: "partitionElementRef",
14946 type: "BaseElement",
14947 isAttr: true,
14948 isReference: true
14949 },
14950 {
14951 name: "partitionElement",
14952 type: "BaseElement"
14953 },
14954 {
14955 name: "flowNodeRef",
14956 type: "FlowNode",
14957 isMany: true,
14958 isReference: true
14959 },
14960 {
14961 name: "childLaneSet",
14962 type: "LaneSet",
14963 xml: {
14964 serialize: "xsi:type"
14965 }
14966 }
14967 ]
14968 },
14969 {
14970 name: "GlobalManualTask",
14971 superClass: [
14972 "GlobalTask"
14973 ]
14974 },
14975 {
14976 name: "ManualTask",
14977 superClass: [
14978 "Task"
14979 ]
14980 },
14981 {
14982 name: "UserTask",
14983 superClass: [
14984 "Task"
14985 ],
14986 properties: [
14987 {
14988 name: "renderings",
14989 type: "Rendering",
14990 isMany: true
14991 },
14992 {
14993 name: "implementation",
14994 isAttr: true,
14995 type: "String"
14996 }
14997 ]
14998 },
14999 {
15000 name: "Rendering",
15001 superClass: [
15002 "BaseElement"
15003 ]
15004 },
15005 {
15006 name: "HumanPerformer",
15007 superClass: [
15008 "Performer"
15009 ]
15010 },
15011 {
15012 name: "PotentialOwner",
15013 superClass: [
15014 "HumanPerformer"
15015 ]
15016 },
15017 {
15018 name: "GlobalUserTask",
15019 superClass: [
15020 "GlobalTask"
15021 ],
15022 properties: [
15023 {
15024 name: "implementation",
15025 isAttr: true,
15026 type: "String"
15027 },
15028 {
15029 name: "renderings",
15030 type: "Rendering",
15031 isMany: true
15032 }
15033 ]
15034 },
15035 {
15036 name: "Gateway",
15037 isAbstract: true,
15038 superClass: [
15039 "FlowNode"
15040 ],
15041 properties: [
15042 {
15043 name: "gatewayDirection",
15044 type: "GatewayDirection",
15045 "default": "Unspecified",
15046 isAttr: true
15047 }
15048 ]
15049 },
15050 {
15051 name: "EventBasedGateway",
15052 superClass: [
15053 "Gateway"
15054 ],
15055 properties: [
15056 {
15057 name: "instantiate",
15058 "default": false,
15059 isAttr: true,
15060 type: "Boolean"
15061 },
15062 {
15063 name: "eventGatewayType",
15064 type: "EventBasedGatewayType",
15065 isAttr: true,
15066 "default": "Exclusive"
15067 }
15068 ]
15069 },
15070 {
15071 name: "ComplexGateway",
15072 superClass: [
15073 "Gateway"
15074 ],
15075 properties: [
15076 {
15077 name: "activationCondition",
15078 type: "Expression",
15079 xml: {
15080 serialize: "xsi:type"
15081 }
15082 },
15083 {
15084 name: "default",
15085 type: "SequenceFlow",
15086 isAttr: true,
15087 isReference: true
15088 }
15089 ]
15090 },
15091 {
15092 name: "ExclusiveGateway",
15093 superClass: [
15094 "Gateway"
15095 ],
15096 properties: [
15097 {
15098 name: "default",
15099 type: "SequenceFlow",
15100 isAttr: true,
15101 isReference: true
15102 }
15103 ]
15104 },
15105 {
15106 name: "InclusiveGateway",
15107 superClass: [
15108 "Gateway"
15109 ],
15110 properties: [
15111 {
15112 name: "default",
15113 type: "SequenceFlow",
15114 isAttr: true,
15115 isReference: true
15116 }
15117 ]
15118 },
15119 {
15120 name: "ParallelGateway",
15121 superClass: [
15122 "Gateway"
15123 ]
15124 },
15125 {
15126 name: "RootElement",
15127 isAbstract: true,
15128 superClass: [
15129 "BaseElement"
15130 ]
15131 },
15132 {
15133 name: "Relationship",
15134 superClass: [
15135 "BaseElement"
15136 ],
15137 properties: [
15138 {
15139 name: "type",
15140 isAttr: true,
15141 type: "String"
15142 },
15143 {
15144 name: "direction",
15145 type: "RelationshipDirection",
15146 isAttr: true
15147 },
15148 {
15149 name: "source",
15150 isMany: true,
15151 isReference: true,
15152 type: "Element"
15153 },
15154 {
15155 name: "target",
15156 isMany: true,
15157 isReference: true,
15158 type: "Element"
15159 }
15160 ]
15161 },
15162 {
15163 name: "BaseElement",
15164 isAbstract: true,
15165 properties: [
15166 {
15167 name: "id",
15168 isAttr: true,
15169 type: "String",
15170 isId: true
15171 },
15172 {
15173 name: "documentation",
15174 type: "Documentation",
15175 isMany: true
15176 },
15177 {
15178 name: "extensionDefinitions",
15179 type: "ExtensionDefinition",
15180 isMany: true,
15181 isReference: true
15182 },
15183 {
15184 name: "extensionElements",
15185 type: "ExtensionElements"
15186 }
15187 ]
15188 },
15189 {
15190 name: "Extension",
15191 properties: [
15192 {
15193 name: "mustUnderstand",
15194 "default": false,
15195 isAttr: true,
15196 type: "Boolean"
15197 },
15198 {
15199 name: "definition",
15200 type: "ExtensionDefinition",
15201 isAttr: true,
15202 isReference: true
15203 }
15204 ]
15205 },
15206 {
15207 name: "ExtensionDefinition",
15208 properties: [
15209 {
15210 name: "name",
15211 isAttr: true,
15212 type: "String"
15213 },
15214 {
15215 name: "extensionAttributeDefinitions",
15216 type: "ExtensionAttributeDefinition",
15217 isMany: true
15218 }
15219 ]
15220 },
15221 {
15222 name: "ExtensionAttributeDefinition",
15223 properties: [
15224 {
15225 name: "name",
15226 isAttr: true,
15227 type: "String"
15228 },
15229 {
15230 name: "type",
15231 isAttr: true,
15232 type: "String"
15233 },
15234 {
15235 name: "isReference",
15236 "default": false,
15237 isAttr: true,
15238 type: "Boolean"
15239 },
15240 {
15241 name: "extensionDefinition",
15242 type: "ExtensionDefinition",
15243 isAttr: true,
15244 isReference: true
15245 }
15246 ]
15247 },
15248 {
15249 name: "ExtensionElements",
15250 properties: [
15251 {
15252 name: "valueRef",
15253 isAttr: true,
15254 isReference: true,
15255 type: "Element"
15256 },
15257 {
15258 name: "values",
15259 type: "Element",
15260 isMany: true
15261 },
15262 {
15263 name: "extensionAttributeDefinition",
15264 type: "ExtensionAttributeDefinition",
15265 isAttr: true,
15266 isReference: true
15267 }
15268 ]
15269 },
15270 {
15271 name: "Documentation",
15272 superClass: [
15273 "BaseElement"
15274 ],
15275 properties: [
15276 {
15277 name: "text",
15278 type: "String",
15279 isBody: true
15280 },
15281 {
15282 name: "textFormat",
15283 "default": "text/plain",
15284 isAttr: true,
15285 type: "String"
15286 }
15287 ]
15288 },
15289 {
15290 name: "Event",
15291 isAbstract: true,
15292 superClass: [
15293 "FlowNode",
15294 "InteractionNode"
15295 ],
15296 properties: [
15297 {
15298 name: "properties",
15299 type: "Property",
15300 isMany: true
15301 }
15302 ]
15303 },
15304 {
15305 name: "IntermediateCatchEvent",
15306 superClass: [
15307 "CatchEvent"
15308 ]
15309 },
15310 {
15311 name: "IntermediateThrowEvent",
15312 superClass: [
15313 "ThrowEvent"
15314 ]
15315 },
15316 {
15317 name: "EndEvent",
15318 superClass: [
15319 "ThrowEvent"
15320 ]
15321 },
15322 {
15323 name: "StartEvent",
15324 superClass: [
15325 "CatchEvent"
15326 ],
15327 properties: [
15328 {
15329 name: "isInterrupting",
15330 "default": true,
15331 isAttr: true,
15332 type: "Boolean"
15333 }
15334 ]
15335 },
15336 {
15337 name: "ThrowEvent",
15338 isAbstract: true,
15339 superClass: [
15340 "Event"
15341 ],
15342 properties: [
15343 {
15344 name: "dataInputs",
15345 type: "DataInput",
15346 isMany: true
15347 },
15348 {
15349 name: "dataInputAssociations",
15350 type: "DataInputAssociation",
15351 isMany: true
15352 },
15353 {
15354 name: "inputSet",
15355 type: "InputSet"
15356 },
15357 {
15358 name: "eventDefinitions",
15359 type: "EventDefinition",
15360 isMany: true
15361 },
15362 {
15363 name: "eventDefinitionRef",
15364 type: "EventDefinition",
15365 isMany: true,
15366 isReference: true
15367 }
15368 ]
15369 },
15370 {
15371 name: "CatchEvent",
15372 isAbstract: true,
15373 superClass: [
15374 "Event"
15375 ],
15376 properties: [
15377 {
15378 name: "parallelMultiple",
15379 isAttr: true,
15380 type: "Boolean",
15381 "default": false
15382 },
15383 {
15384 name: "dataOutputs",
15385 type: "DataOutput",
15386 isMany: true
15387 },
15388 {
15389 name: "dataOutputAssociations",
15390 type: "DataOutputAssociation",
15391 isMany: true
15392 },
15393 {
15394 name: "outputSet",
15395 type: "OutputSet"
15396 },
15397 {
15398 name: "eventDefinitions",
15399 type: "EventDefinition",
15400 isMany: true
15401 },
15402 {
15403 name: "eventDefinitionRef",
15404 type: "EventDefinition",
15405 isMany: true,
15406 isReference: true
15407 }
15408 ]
15409 },
15410 {
15411 name: "BoundaryEvent",
15412 superClass: [
15413 "CatchEvent"
15414 ],
15415 properties: [
15416 {
15417 name: "cancelActivity",
15418 "default": true,
15419 isAttr: true,
15420 type: "Boolean"
15421 },
15422 {
15423 name: "attachedToRef",
15424 type: "Activity",
15425 isAttr: true,
15426 isReference: true
15427 }
15428 ]
15429 },
15430 {
15431 name: "EventDefinition",
15432 isAbstract: true,
15433 superClass: [
15434 "RootElement"
15435 ]
15436 },
15437 {
15438 name: "CancelEventDefinition",
15439 superClass: [
15440 "EventDefinition"
15441 ]
15442 },
15443 {
15444 name: "ErrorEventDefinition",
15445 superClass: [
15446 "EventDefinition"
15447 ],
15448 properties: [
15449 {
15450 name: "errorRef",
15451 type: "Error",
15452 isAttr: true,
15453 isReference: true
15454 }
15455 ]
15456 },
15457 {
15458 name: "TerminateEventDefinition",
15459 superClass: [
15460 "EventDefinition"
15461 ]
15462 },
15463 {
15464 name: "EscalationEventDefinition",
15465 superClass: [
15466 "EventDefinition"
15467 ],
15468 properties: [
15469 {
15470 name: "escalationRef",
15471 type: "Escalation",
15472 isAttr: true,
15473 isReference: true
15474 }
15475 ]
15476 },
15477 {
15478 name: "Escalation",
15479 properties: [
15480 {
15481 name: "structureRef",
15482 type: "ItemDefinition",
15483 isAttr: true,
15484 isReference: true
15485 },
15486 {
15487 name: "name",
15488 isAttr: true,
15489 type: "String"
15490 },
15491 {
15492 name: "escalationCode",
15493 isAttr: true,
15494 type: "String"
15495 }
15496 ],
15497 superClass: [
15498 "RootElement"
15499 ]
15500 },
15501 {
15502 name: "CompensateEventDefinition",
15503 superClass: [
15504 "EventDefinition"
15505 ],
15506 properties: [
15507 {
15508 name: "waitForCompletion",
15509 isAttr: true,
15510 type: "Boolean",
15511 "default": true
15512 },
15513 {
15514 name: "activityRef",
15515 type: "Activity",
15516 isAttr: true,
15517 isReference: true
15518 }
15519 ]
15520 },
15521 {
15522 name: "TimerEventDefinition",
15523 superClass: [
15524 "EventDefinition"
15525 ],
15526 properties: [
15527 {
15528 name: "timeDate",
15529 type: "Expression",
15530 xml: {
15531 serialize: "xsi:type"
15532 }
15533 },
15534 {
15535 name: "timeCycle",
15536 type: "Expression",
15537 xml: {
15538 serialize: "xsi:type"
15539 }
15540 },
15541 {
15542 name: "timeDuration",
15543 type: "Expression",
15544 xml: {
15545 serialize: "xsi:type"
15546 }
15547 }
15548 ]
15549 },
15550 {
15551 name: "LinkEventDefinition",
15552 superClass: [
15553 "EventDefinition"
15554 ],
15555 properties: [
15556 {
15557 name: "name",
15558 isAttr: true,
15559 type: "String"
15560 },
15561 {
15562 name: "target",
15563 type: "LinkEventDefinition",
15564 isAttr: true,
15565 isReference: true
15566 },
15567 {
15568 name: "source",
15569 type: "LinkEventDefinition",
15570 isMany: true,
15571 isReference: true
15572 }
15573 ]
15574 },
15575 {
15576 name: "MessageEventDefinition",
15577 superClass: [
15578 "EventDefinition"
15579 ],
15580 properties: [
15581 {
15582 name: "messageRef",
15583 type: "Message",
15584 isAttr: true,
15585 isReference: true
15586 },
15587 {
15588 name: "operationRef",
15589 type: "Operation",
15590 isAttr: true,
15591 isReference: true
15592 }
15593 ]
15594 },
15595 {
15596 name: "ConditionalEventDefinition",
15597 superClass: [
15598 "EventDefinition"
15599 ],
15600 properties: [
15601 {
15602 name: "condition",
15603 type: "Expression",
15604 xml: {
15605 serialize: "xsi:type"
15606 }
15607 }
15608 ]
15609 },
15610 {
15611 name: "SignalEventDefinition",
15612 superClass: [
15613 "EventDefinition"
15614 ],
15615 properties: [
15616 {
15617 name: "signalRef",
15618 type: "Signal",
15619 isAttr: true,
15620 isReference: true
15621 }
15622 ]
15623 },
15624 {
15625 name: "Signal",
15626 superClass: [
15627 "RootElement"
15628 ],
15629 properties: [
15630 {
15631 name: "structureRef",
15632 type: "ItemDefinition",
15633 isAttr: true,
15634 isReference: true
15635 },
15636 {
15637 name: "name",
15638 isAttr: true,
15639 type: "String"
15640 }
15641 ]
15642 },
15643 {
15644 name: "ImplicitThrowEvent",
15645 superClass: [
15646 "ThrowEvent"
15647 ]
15648 },
15649 {
15650 name: "DataState",
15651 superClass: [
15652 "BaseElement"
15653 ],
15654 properties: [
15655 {
15656 name: "name",
15657 isAttr: true,
15658 type: "String"
15659 }
15660 ]
15661 },
15662 {
15663 name: "ItemAwareElement",
15664 superClass: [
15665 "BaseElement"
15666 ],
15667 properties: [
15668 {
15669 name: "itemSubjectRef",
15670 type: "ItemDefinition",
15671 isAttr: true,
15672 isReference: true
15673 },
15674 {
15675 name: "dataState",
15676 type: "DataState"
15677 }
15678 ]
15679 },
15680 {
15681 name: "DataAssociation",
15682 superClass: [
15683 "BaseElement"
15684 ],
15685 properties: [
15686 {
15687 name: "sourceRef",
15688 type: "ItemAwareElement",
15689 isMany: true,
15690 isReference: true
15691 },
15692 {
15693 name: "targetRef",
15694 type: "ItemAwareElement",
15695 isReference: true
15696 },
15697 {
15698 name: "transformation",
15699 type: "FormalExpression",
15700 xml: {
15701 serialize: "property"
15702 }
15703 },
15704 {
15705 name: "assignment",
15706 type: "Assignment",
15707 isMany: true
15708 }
15709 ]
15710 },
15711 {
15712 name: "DataInput",
15713 superClass: [
15714 "ItemAwareElement"
15715 ],
15716 properties: [
15717 {
15718 name: "name",
15719 isAttr: true,
15720 type: "String"
15721 },
15722 {
15723 name: "isCollection",
15724 "default": false,
15725 isAttr: true,
15726 type: "Boolean"
15727 },
15728 {
15729 name: "inputSetRef",
15730 type: "InputSet",
15731 isMany: true,
15732 isVirtual: true,
15733 isReference: true
15734 },
15735 {
15736 name: "inputSetWithOptional",
15737 type: "InputSet",
15738 isMany: true,
15739 isVirtual: true,
15740 isReference: true
15741 },
15742 {
15743 name: "inputSetWithWhileExecuting",
15744 type: "InputSet",
15745 isMany: true,
15746 isVirtual: true,
15747 isReference: true
15748 }
15749 ]
15750 },
15751 {
15752 name: "DataOutput",
15753 superClass: [
15754 "ItemAwareElement"
15755 ],
15756 properties: [
15757 {
15758 name: "name",
15759 isAttr: true,
15760 type: "String"
15761 },
15762 {
15763 name: "isCollection",
15764 "default": false,
15765 isAttr: true,
15766 type: "Boolean"
15767 },
15768 {
15769 name: "outputSetRef",
15770 type: "OutputSet",
15771 isMany: true,
15772 isVirtual: true,
15773 isReference: true
15774 },
15775 {
15776 name: "outputSetWithOptional",
15777 type: "OutputSet",
15778 isMany: true,
15779 isVirtual: true,
15780 isReference: true
15781 },
15782 {
15783 name: "outputSetWithWhileExecuting",
15784 type: "OutputSet",
15785 isMany: true,
15786 isVirtual: true,
15787 isReference: true
15788 }
15789 ]
15790 },
15791 {
15792 name: "InputSet",
15793 superClass: [
15794 "BaseElement"
15795 ],
15796 properties: [
15797 {
15798 name: "name",
15799 isAttr: true,
15800 type: "String"
15801 },
15802 {
15803 name: "dataInputRefs",
15804 type: "DataInput",
15805 isMany: true,
15806 isReference: true
15807 },
15808 {
15809 name: "optionalInputRefs",
15810 type: "DataInput",
15811 isMany: true,
15812 isReference: true
15813 },
15814 {
15815 name: "whileExecutingInputRefs",
15816 type: "DataInput",
15817 isMany: true,
15818 isReference: true
15819 },
15820 {
15821 name: "outputSetRefs",
15822 type: "OutputSet",
15823 isMany: true,
15824 isReference: true
15825 }
15826 ]
15827 },
15828 {
15829 name: "OutputSet",
15830 superClass: [
15831 "BaseElement"
15832 ],
15833 properties: [
15834 {
15835 name: "dataOutputRefs",
15836 type: "DataOutput",
15837 isMany: true,
15838 isReference: true
15839 },
15840 {
15841 name: "name",
15842 isAttr: true,
15843 type: "String"
15844 },
15845 {
15846 name: "inputSetRefs",
15847 type: "InputSet",
15848 isMany: true,
15849 isReference: true
15850 },
15851 {
15852 name: "optionalOutputRefs",
15853 type: "DataOutput",
15854 isMany: true,
15855 isReference: true
15856 },
15857 {
15858 name: "whileExecutingOutputRefs",
15859 type: "DataOutput",
15860 isMany: true,
15861 isReference: true
15862 }
15863 ]
15864 },
15865 {
15866 name: "Property",
15867 superClass: [
15868 "ItemAwareElement"
15869 ],
15870 properties: [
15871 {
15872 name: "name",
15873 isAttr: true,
15874 type: "String"
15875 }
15876 ]
15877 },
15878 {
15879 name: "DataInputAssociation",
15880 superClass: [
15881 "DataAssociation"
15882 ]
15883 },
15884 {
15885 name: "DataOutputAssociation",
15886 superClass: [
15887 "DataAssociation"
15888 ]
15889 },
15890 {
15891 name: "InputOutputSpecification",
15892 superClass: [
15893 "BaseElement"
15894 ],
15895 properties: [
15896 {
15897 name: "dataInputs",
15898 type: "DataInput",
15899 isMany: true
15900 },
15901 {
15902 name: "dataOutputs",
15903 type: "DataOutput",
15904 isMany: true
15905 },
15906 {
15907 name: "inputSets",
15908 type: "InputSet",
15909 isMany: true
15910 },
15911 {
15912 name: "outputSets",
15913 type: "OutputSet",
15914 isMany: true
15915 }
15916 ]
15917 },
15918 {
15919 name: "DataObject",
15920 superClass: [
15921 "FlowElement",
15922 "ItemAwareElement"
15923 ],
15924 properties: [
15925 {
15926 name: "isCollection",
15927 "default": false,
15928 isAttr: true,
15929 type: "Boolean"
15930 }
15931 ]
15932 },
15933 {
15934 name: "InputOutputBinding",
15935 properties: [
15936 {
15937 name: "inputDataRef",
15938 type: "InputSet",
15939 isAttr: true,
15940 isReference: true
15941 },
15942 {
15943 name: "outputDataRef",
15944 type: "OutputSet",
15945 isAttr: true,
15946 isReference: true
15947 },
15948 {
15949 name: "operationRef",
15950 type: "Operation",
15951 isAttr: true,
15952 isReference: true
15953 }
15954 ]
15955 },
15956 {
15957 name: "Assignment",
15958 superClass: [
15959 "BaseElement"
15960 ],
15961 properties: [
15962 {
15963 name: "from",
15964 type: "Expression",
15965 xml: {
15966 serialize: "xsi:type"
15967 }
15968 },
15969 {
15970 name: "to",
15971 type: "Expression",
15972 xml: {
15973 serialize: "xsi:type"
15974 }
15975 }
15976 ]
15977 },
15978 {
15979 name: "DataStore",
15980 superClass: [
15981 "RootElement",
15982 "ItemAwareElement"
15983 ],
15984 properties: [
15985 {
15986 name: "name",
15987 isAttr: true,
15988 type: "String"
15989 },
15990 {
15991 name: "capacity",
15992 isAttr: true,
15993 type: "Integer"
15994 },
15995 {
15996 name: "isUnlimited",
15997 "default": true,
15998 isAttr: true,
15999 type: "Boolean"
16000 }
16001 ]
16002 },
16003 {
16004 name: "DataStoreReference",
16005 superClass: [
16006 "ItemAwareElement",
16007 "FlowElement"
16008 ],
16009 properties: [
16010 {
16011 name: "dataStoreRef",
16012 type: "DataStore",
16013 isAttr: true,
16014 isReference: true
16015 }
16016 ]
16017 },
16018 {
16019 name: "DataObjectReference",
16020 superClass: [
16021 "ItemAwareElement",
16022 "FlowElement"
16023 ],
16024 properties: [
16025 {
16026 name: "dataObjectRef",
16027 type: "DataObject",
16028 isAttr: true,
16029 isReference: true
16030 }
16031 ]
16032 },
16033 {
16034 name: "ConversationLink",
16035 superClass: [
16036 "BaseElement"
16037 ],
16038 properties: [
16039 {
16040 name: "sourceRef",
16041 type: "InteractionNode",
16042 isAttr: true,
16043 isReference: true
16044 },
16045 {
16046 name: "targetRef",
16047 type: "InteractionNode",
16048 isAttr: true,
16049 isReference: true
16050 },
16051 {
16052 name: "name",
16053 isAttr: true,
16054 type: "String"
16055 }
16056 ]
16057 },
16058 {
16059 name: "ConversationAssociation",
16060 superClass: [
16061 "BaseElement"
16062 ],
16063 properties: [
16064 {
16065 name: "innerConversationNodeRef",
16066 type: "ConversationNode",
16067 isAttr: true,
16068 isReference: true
16069 },
16070 {
16071 name: "outerConversationNodeRef",
16072 type: "ConversationNode",
16073 isAttr: true,
16074 isReference: true
16075 }
16076 ]
16077 },
16078 {
16079 name: "CallConversation",
16080 superClass: [
16081 "ConversationNode"
16082 ],
16083 properties: [
16084 {
16085 name: "calledCollaborationRef",
16086 type: "Collaboration",
16087 isAttr: true,
16088 isReference: true
16089 },
16090 {
16091 name: "participantAssociations",
16092 type: "ParticipantAssociation",
16093 isMany: true
16094 }
16095 ]
16096 },
16097 {
16098 name: "Conversation",
16099 superClass: [
16100 "ConversationNode"
16101 ]
16102 },
16103 {
16104 name: "SubConversation",
16105 superClass: [
16106 "ConversationNode"
16107 ],
16108 properties: [
16109 {
16110 name: "conversationNodes",
16111 type: "ConversationNode",
16112 isMany: true
16113 }
16114 ]
16115 },
16116 {
16117 name: "ConversationNode",
16118 isAbstract: true,
16119 superClass: [
16120 "InteractionNode",
16121 "BaseElement"
16122 ],
16123 properties: [
16124 {
16125 name: "name",
16126 isAttr: true,
16127 type: "String"
16128 },
16129 {
16130 name: "participantRef",
16131 type: "Participant",
16132 isMany: true,
16133 isReference: true
16134 },
16135 {
16136 name: "messageFlowRefs",
16137 type: "MessageFlow",
16138 isMany: true,
16139 isReference: true
16140 },
16141 {
16142 name: "correlationKeys",
16143 type: "CorrelationKey",
16144 isMany: true
16145 }
16146 ]
16147 },
16148 {
16149 name: "GlobalConversation",
16150 superClass: [
16151 "Collaboration"
16152 ]
16153 },
16154 {
16155 name: "PartnerEntity",
16156 superClass: [
16157 "RootElement"
16158 ],
16159 properties: [
16160 {
16161 name: "name",
16162 isAttr: true,
16163 type: "String"
16164 },
16165 {
16166 name: "participantRef",
16167 type: "Participant",
16168 isMany: true,
16169 isReference: true
16170 }
16171 ]
16172 },
16173 {
16174 name: "PartnerRole",
16175 superClass: [
16176 "RootElement"
16177 ],
16178 properties: [
16179 {
16180 name: "name",
16181 isAttr: true,
16182 type: "String"
16183 },
16184 {
16185 name: "participantRef",
16186 type: "Participant",
16187 isMany: true,
16188 isReference: true
16189 }
16190 ]
16191 },
16192 {
16193 name: "CorrelationProperty",
16194 superClass: [
16195 "RootElement"
16196 ],
16197 properties: [
16198 {
16199 name: "correlationPropertyRetrievalExpression",
16200 type: "CorrelationPropertyRetrievalExpression",
16201 isMany: true
16202 },
16203 {
16204 name: "name",
16205 isAttr: true,
16206 type: "String"
16207 },
16208 {
16209 name: "type",
16210 type: "ItemDefinition",
16211 isAttr: true,
16212 isReference: true
16213 }
16214 ]
16215 },
16216 {
16217 name: "Error",
16218 superClass: [
16219 "RootElement"
16220 ],
16221 properties: [
16222 {
16223 name: "structureRef",
16224 type: "ItemDefinition",
16225 isAttr: true,
16226 isReference: true
16227 },
16228 {
16229 name: "name",
16230 isAttr: true,
16231 type: "String"
16232 },
16233 {
16234 name: "errorCode",
16235 isAttr: true,
16236 type: "String"
16237 }
16238 ]
16239 },
16240 {
16241 name: "CorrelationKey",
16242 superClass: [
16243 "BaseElement"
16244 ],
16245 properties: [
16246 {
16247 name: "correlationPropertyRef",
16248 type: "CorrelationProperty",
16249 isMany: true,
16250 isReference: true
16251 },
16252 {
16253 name: "name",
16254 isAttr: true,
16255 type: "String"
16256 }
16257 ]
16258 },
16259 {
16260 name: "Expression",
16261 superClass: [
16262 "BaseElement"
16263 ],
16264 isAbstract: false,
16265 properties: [
16266 {
16267 name: "body",
16268 isBody: true,
16269 type: "String"
16270 }
16271 ]
16272 },
16273 {
16274 name: "FormalExpression",
16275 superClass: [
16276 "Expression"
16277 ],
16278 properties: [
16279 {
16280 name: "language",
16281 isAttr: true,
16282 type: "String"
16283 },
16284 {
16285 name: "evaluatesToTypeRef",
16286 type: "ItemDefinition",
16287 isAttr: true,
16288 isReference: true
16289 }
16290 ]
16291 },
16292 {
16293 name: "Message",
16294 superClass: [
16295 "RootElement"
16296 ],
16297 properties: [
16298 {
16299 name: "name",
16300 isAttr: true,
16301 type: "String"
16302 },
16303 {
16304 name: "itemRef",
16305 type: "ItemDefinition",
16306 isAttr: true,
16307 isReference: true
16308 }
16309 ]
16310 },
16311 {
16312 name: "ItemDefinition",
16313 superClass: [
16314 "RootElement"
16315 ],
16316 properties: [
16317 {
16318 name: "itemKind",
16319 type: "ItemKind",
16320 isAttr: true
16321 },
16322 {
16323 name: "structureRef",
16324 isAttr: true,
16325 type: "String"
16326 },
16327 {
16328 name: "isCollection",
16329 "default": false,
16330 isAttr: true,
16331 type: "Boolean"
16332 },
16333 {
16334 name: "import",
16335 type: "Import",
16336 isAttr: true,
16337 isReference: true
16338 }
16339 ]
16340 },
16341 {
16342 name: "FlowElement",
16343 isAbstract: true,
16344 superClass: [
16345 "BaseElement"
16346 ],
16347 properties: [
16348 {
16349 name: "name",
16350 isAttr: true,
16351 type: "String"
16352 },
16353 {
16354 name: "auditing",
16355 type: "Auditing"
16356 },
16357 {
16358 name: "monitoring",
16359 type: "Monitoring"
16360 },
16361 {
16362 name: "categoryValueRef",
16363 type: "CategoryValue",
16364 isMany: true,
16365 isReference: true
16366 }
16367 ]
16368 },
16369 {
16370 name: "SequenceFlow",
16371 superClass: [
16372 "FlowElement"
16373 ],
16374 properties: [
16375 {
16376 name: "isImmediate",
16377 isAttr: true,
16378 type: "Boolean"
16379 },
16380 {
16381 name: "conditionExpression",
16382 type: "Expression",
16383 xml: {
16384 serialize: "xsi:type"
16385 }
16386 },
16387 {
16388 name: "sourceRef",
16389 type: "FlowNode",
16390 isAttr: true,
16391 isReference: true
16392 },
16393 {
16394 name: "targetRef",
16395 type: "FlowNode",
16396 isAttr: true,
16397 isReference: true
16398 }
16399 ]
16400 },
16401 {
16402 name: "FlowElementsContainer",
16403 isAbstract: true,
16404 superClass: [
16405 "BaseElement"
16406 ],
16407 properties: [
16408 {
16409 name: "laneSets",
16410 type: "LaneSet",
16411 isMany: true
16412 },
16413 {
16414 name: "flowElements",
16415 type: "FlowElement",
16416 isMany: true
16417 }
16418 ]
16419 },
16420 {
16421 name: "CallableElement",
16422 isAbstract: true,
16423 superClass: [
16424 "RootElement"
16425 ],
16426 properties: [
16427 {
16428 name: "name",
16429 isAttr: true,
16430 type: "String"
16431 },
16432 {
16433 name: "ioSpecification",
16434 type: "InputOutputSpecification",
16435 xml: {
16436 serialize: "property"
16437 }
16438 },
16439 {
16440 name: "supportedInterfaceRef",
16441 type: "Interface",
16442 isMany: true,
16443 isReference: true
16444 },
16445 {
16446 name: "ioBinding",
16447 type: "InputOutputBinding",
16448 isMany: true,
16449 xml: {
16450 serialize: "property"
16451 }
16452 }
16453 ]
16454 },
16455 {
16456 name: "FlowNode",
16457 isAbstract: true,
16458 superClass: [
16459 "FlowElement"
16460 ],
16461 properties: [
16462 {
16463 name: "incoming",
16464 type: "SequenceFlow",
16465 isMany: true,
16466 isReference: true
16467 },
16468 {
16469 name: "outgoing",
16470 type: "SequenceFlow",
16471 isMany: true,
16472 isReference: true
16473 },
16474 {
16475 name: "lanes",
16476 type: "Lane",
16477 isMany: true,
16478 isVirtual: true,
16479 isReference: true
16480 }
16481 ]
16482 },
16483 {
16484 name: "CorrelationPropertyRetrievalExpression",
16485 superClass: [
16486 "BaseElement"
16487 ],
16488 properties: [
16489 {
16490 name: "messagePath",
16491 type: "FormalExpression"
16492 },
16493 {
16494 name: "messageRef",
16495 type: "Message",
16496 isAttr: true,
16497 isReference: true
16498 }
16499 ]
16500 },
16501 {
16502 name: "CorrelationPropertyBinding",
16503 superClass: [
16504 "BaseElement"
16505 ],
16506 properties: [
16507 {
16508 name: "dataPath",
16509 type: "FormalExpression"
16510 },
16511 {
16512 name: "correlationPropertyRef",
16513 type: "CorrelationProperty",
16514 isAttr: true,
16515 isReference: true
16516 }
16517 ]
16518 },
16519 {
16520 name: "Resource",
16521 superClass: [
16522 "RootElement"
16523 ],
16524 properties: [
16525 {
16526 name: "name",
16527 isAttr: true,
16528 type: "String"
16529 },
16530 {
16531 name: "resourceParameters",
16532 type: "ResourceParameter",
16533 isMany: true
16534 }
16535 ]
16536 },
16537 {
16538 name: "ResourceParameter",
16539 superClass: [
16540 "BaseElement"
16541 ],
16542 properties: [
16543 {
16544 name: "name",
16545 isAttr: true,
16546 type: "String"
16547 },
16548 {
16549 name: "isRequired",
16550 isAttr: true,
16551 type: "Boolean"
16552 },
16553 {
16554 name: "type",
16555 type: "ItemDefinition",
16556 isAttr: true,
16557 isReference: true
16558 }
16559 ]
16560 },
16561 {
16562 name: "CorrelationSubscription",
16563 superClass: [
16564 "BaseElement"
16565 ],
16566 properties: [
16567 {
16568 name: "correlationKeyRef",
16569 type: "CorrelationKey",
16570 isAttr: true,
16571 isReference: true
16572 },
16573 {
16574 name: "correlationPropertyBinding",
16575 type: "CorrelationPropertyBinding",
16576 isMany: true
16577 }
16578 ]
16579 },
16580 {
16581 name: "MessageFlow",
16582 superClass: [
16583 "BaseElement"
16584 ],
16585 properties: [
16586 {
16587 name: "name",
16588 isAttr: true,
16589 type: "String"
16590 },
16591 {
16592 name: "sourceRef",
16593 type: "InteractionNode",
16594 isAttr: true,
16595 isReference: true
16596 },
16597 {
16598 name: "targetRef",
16599 type: "InteractionNode",
16600 isAttr: true,
16601 isReference: true
16602 },
16603 {
16604 name: "messageRef",
16605 type: "Message",
16606 isAttr: true,
16607 isReference: true
16608 }
16609 ]
16610 },
16611 {
16612 name: "MessageFlowAssociation",
16613 superClass: [
16614 "BaseElement"
16615 ],
16616 properties: [
16617 {
16618 name: "innerMessageFlowRef",
16619 type: "MessageFlow",
16620 isAttr: true,
16621 isReference: true
16622 },
16623 {
16624 name: "outerMessageFlowRef",
16625 type: "MessageFlow",
16626 isAttr: true,
16627 isReference: true
16628 }
16629 ]
16630 },
16631 {
16632 name: "InteractionNode",
16633 isAbstract: true,
16634 properties: [
16635 {
16636 name: "incomingConversationLinks",
16637 type: "ConversationLink",
16638 isMany: true,
16639 isVirtual: true,
16640 isReference: true
16641 },
16642 {
16643 name: "outgoingConversationLinks",
16644 type: "ConversationLink",
16645 isMany: true,
16646 isVirtual: true,
16647 isReference: true
16648 }
16649 ]
16650 },
16651 {
16652 name: "Participant",
16653 superClass: [
16654 "InteractionNode",
16655 "BaseElement"
16656 ],
16657 properties: [
16658 {
16659 name: "name",
16660 isAttr: true,
16661 type: "String"
16662 },
16663 {
16664 name: "interfaceRef",
16665 type: "Interface",
16666 isMany: true,
16667 isReference: true
16668 },
16669 {
16670 name: "participantMultiplicity",
16671 type: "ParticipantMultiplicity"
16672 },
16673 {
16674 name: "endPointRefs",
16675 type: "EndPoint",
16676 isMany: true,
16677 isReference: true
16678 },
16679 {
16680 name: "processRef",
16681 type: "Process",
16682 isAttr: true,
16683 isReference: true
16684 }
16685 ]
16686 },
16687 {
16688 name: "ParticipantAssociation",
16689 superClass: [
16690 "BaseElement"
16691 ],
16692 properties: [
16693 {
16694 name: "innerParticipantRef",
16695 type: "Participant",
16696 isAttr: true,
16697 isReference: true
16698 },
16699 {
16700 name: "outerParticipantRef",
16701 type: "Participant",
16702 isAttr: true,
16703 isReference: true
16704 }
16705 ]
16706 },
16707 {
16708 name: "ParticipantMultiplicity",
16709 properties: [
16710 {
16711 name: "minimum",
16712 "default": 0,
16713 isAttr: true,
16714 type: "Integer"
16715 },
16716 {
16717 name: "maximum",
16718 "default": 1,
16719 isAttr: true,
16720 type: "Integer"
16721 }
16722 ],
16723 superClass: [
16724 "BaseElement"
16725 ]
16726 },
16727 {
16728 name: "Collaboration",
16729 superClass: [
16730 "RootElement"
16731 ],
16732 properties: [
16733 {
16734 name: "name",
16735 isAttr: true,
16736 type: "String"
16737 },
16738 {
16739 name: "isClosed",
16740 isAttr: true,
16741 type: "Boolean"
16742 },
16743 {
16744 name: "participants",
16745 type: "Participant",
16746 isMany: true
16747 },
16748 {
16749 name: "messageFlows",
16750 type: "MessageFlow",
16751 isMany: true
16752 },
16753 {
16754 name: "artifacts",
16755 type: "Artifact",
16756 isMany: true
16757 },
16758 {
16759 name: "conversations",
16760 type: "ConversationNode",
16761 isMany: true
16762 },
16763 {
16764 name: "conversationAssociations",
16765 type: "ConversationAssociation"
16766 },
16767 {
16768 name: "participantAssociations",
16769 type: "ParticipantAssociation",
16770 isMany: true
16771 },
16772 {
16773 name: "messageFlowAssociations",
16774 type: "MessageFlowAssociation",
16775 isMany: true
16776 },
16777 {
16778 name: "correlationKeys",
16779 type: "CorrelationKey",
16780 isMany: true
16781 },
16782 {
16783 name: "choreographyRef",
16784 type: "Choreography",
16785 isMany: true,
16786 isReference: true
16787 },
16788 {
16789 name: "conversationLinks",
16790 type: "ConversationLink",
16791 isMany: true
16792 }
16793 ]
16794 },
16795 {
16796 name: "ChoreographyActivity",
16797 isAbstract: true,
16798 superClass: [
16799 "FlowNode"
16800 ],
16801 properties: [
16802 {
16803 name: "participantRef",
16804 type: "Participant",
16805 isMany: true,
16806 isReference: true
16807 },
16808 {
16809 name: "initiatingParticipantRef",
16810 type: "Participant",
16811 isAttr: true,
16812 isReference: true
16813 },
16814 {
16815 name: "correlationKeys",
16816 type: "CorrelationKey",
16817 isMany: true
16818 },
16819 {
16820 name: "loopType",
16821 type: "ChoreographyLoopType",
16822 "default": "None",
16823 isAttr: true
16824 }
16825 ]
16826 },
16827 {
16828 name: "CallChoreography",
16829 superClass: [
16830 "ChoreographyActivity"
16831 ],
16832 properties: [
16833 {
16834 name: "calledChoreographyRef",
16835 type: "Choreography",
16836 isAttr: true,
16837 isReference: true
16838 },
16839 {
16840 name: "participantAssociations",
16841 type: "ParticipantAssociation",
16842 isMany: true
16843 }
16844 ]
16845 },
16846 {
16847 name: "SubChoreography",
16848 superClass: [
16849 "ChoreographyActivity",
16850 "FlowElementsContainer"
16851 ],
16852 properties: [
16853 {
16854 name: "artifacts",
16855 type: "Artifact",
16856 isMany: true
16857 }
16858 ]
16859 },
16860 {
16861 name: "ChoreographyTask",
16862 superClass: [
16863 "ChoreographyActivity"
16864 ],
16865 properties: [
16866 {
16867 name: "messageFlowRef",
16868 type: "MessageFlow",
16869 isMany: true,
16870 isReference: true
16871 }
16872 ]
16873 },
16874 {
16875 name: "Choreography",
16876 superClass: [
16877 "Collaboration",
16878 "FlowElementsContainer"
16879 ]
16880 },
16881 {
16882 name: "GlobalChoreographyTask",
16883 superClass: [
16884 "Choreography"
16885 ],
16886 properties: [
16887 {
16888 name: "initiatingParticipantRef",
16889 type: "Participant",
16890 isAttr: true,
16891 isReference: true
16892 }
16893 ]
16894 },
16895 {
16896 name: "TextAnnotation",
16897 superClass: [
16898 "Artifact"
16899 ],
16900 properties: [
16901 {
16902 name: "text",
16903 type: "String"
16904 },
16905 {
16906 name: "textFormat",
16907 "default": "text/plain",
16908 isAttr: true,
16909 type: "String"
16910 }
16911 ]
16912 },
16913 {
16914 name: "Group",
16915 superClass: [
16916 "Artifact"
16917 ],
16918 properties: [
16919 {
16920 name: "categoryValueRef",
16921 type: "CategoryValue",
16922 isAttr: true,
16923 isReference: true
16924 }
16925 ]
16926 },
16927 {
16928 name: "Association",
16929 superClass: [
16930 "Artifact"
16931 ],
16932 properties: [
16933 {
16934 name: "associationDirection",
16935 type: "AssociationDirection",
16936 isAttr: true
16937 },
16938 {
16939 name: "sourceRef",
16940 type: "BaseElement",
16941 isAttr: true,
16942 isReference: true
16943 },
16944 {
16945 name: "targetRef",
16946 type: "BaseElement",
16947 isAttr: true,
16948 isReference: true
16949 }
16950 ]
16951 },
16952 {
16953 name: "Category",
16954 superClass: [
16955 "RootElement"
16956 ],
16957 properties: [
16958 {
16959 name: "categoryValue",
16960 type: "CategoryValue",
16961 isMany: true
16962 },
16963 {
16964 name: "name",
16965 isAttr: true,
16966 type: "String"
16967 }
16968 ]
16969 },
16970 {
16971 name: "Artifact",
16972 isAbstract: true,
16973 superClass: [
16974 "BaseElement"
16975 ]
16976 },
16977 {
16978 name: "CategoryValue",
16979 superClass: [
16980 "BaseElement"
16981 ],
16982 properties: [
16983 {
16984 name: "categorizedFlowElements",
16985 type: "FlowElement",
16986 isMany: true,
16987 isVirtual: true,
16988 isReference: true
16989 },
16990 {
16991 name: "value",
16992 isAttr: true,
16993 type: "String"
16994 }
16995 ]
16996 },
16997 {
16998 name: "Activity",
16999 isAbstract: true,
17000 superClass: [
17001 "FlowNode"
17002 ],
17003 properties: [
17004 {
17005 name: "isForCompensation",
17006 "default": false,
17007 isAttr: true,
17008 type: "Boolean"
17009 },
17010 {
17011 name: "default",
17012 type: "SequenceFlow",
17013 isAttr: true,
17014 isReference: true
17015 },
17016 {
17017 name: "ioSpecification",
17018 type: "InputOutputSpecification",
17019 xml: {
17020 serialize: "property"
17021 }
17022 },
17023 {
17024 name: "boundaryEventRefs",
17025 type: "BoundaryEvent",
17026 isMany: true,
17027 isReference: true
17028 },
17029 {
17030 name: "properties",
17031 type: "Property",
17032 isMany: true
17033 },
17034 {
17035 name: "dataInputAssociations",
17036 type: "DataInputAssociation",
17037 isMany: true
17038 },
17039 {
17040 name: "dataOutputAssociations",
17041 type: "DataOutputAssociation",
17042 isMany: true
17043 },
17044 {
17045 name: "startQuantity",
17046 "default": 1,
17047 isAttr: true,
17048 type: "Integer"
17049 },
17050 {
17051 name: "resources",
17052 type: "ResourceRole",
17053 isMany: true
17054 },
17055 {
17056 name: "completionQuantity",
17057 "default": 1,
17058 isAttr: true,
17059 type: "Integer"
17060 },
17061 {
17062 name: "loopCharacteristics",
17063 type: "LoopCharacteristics"
17064 }
17065 ]
17066 },
17067 {
17068 name: "ServiceTask",
17069 superClass: [
17070 "Task"
17071 ],
17072 properties: [
17073 {
17074 name: "implementation",
17075 isAttr: true,
17076 type: "String"
17077 },
17078 {
17079 name: "operationRef",
17080 type: "Operation",
17081 isAttr: true,
17082 isReference: true
17083 }
17084 ]
17085 },
17086 {
17087 name: "SubProcess",
17088 superClass: [
17089 "Activity",
17090 "FlowElementsContainer",
17091 "InteractionNode"
17092 ],
17093 properties: [
17094 {
17095 name: "triggeredByEvent",
17096 "default": false,
17097 isAttr: true,
17098 type: "Boolean"
17099 },
17100 {
17101 name: "artifacts",
17102 type: "Artifact",
17103 isMany: true
17104 }
17105 ]
17106 },
17107 {
17108 name: "LoopCharacteristics",
17109 isAbstract: true,
17110 superClass: [
17111 "BaseElement"
17112 ]
17113 },
17114 {
17115 name: "MultiInstanceLoopCharacteristics",
17116 superClass: [
17117 "LoopCharacteristics"
17118 ],
17119 properties: [
17120 {
17121 name: "isSequential",
17122 "default": false,
17123 isAttr: true,
17124 type: "Boolean"
17125 },
17126 {
17127 name: "behavior",
17128 type: "MultiInstanceBehavior",
17129 "default": "All",
17130 isAttr: true
17131 },
17132 {
17133 name: "loopCardinality",
17134 type: "Expression",
17135 xml: {
17136 serialize: "xsi:type"
17137 }
17138 },
17139 {
17140 name: "loopDataInputRef",
17141 type: "ItemAwareElement",
17142 isReference: true
17143 },
17144 {
17145 name: "loopDataOutputRef",
17146 type: "ItemAwareElement",
17147 isReference: true
17148 },
17149 {
17150 name: "inputDataItem",
17151 type: "DataInput",
17152 xml: {
17153 serialize: "property"
17154 }
17155 },
17156 {
17157 name: "outputDataItem",
17158 type: "DataOutput",
17159 xml: {
17160 serialize: "property"
17161 }
17162 },
17163 {
17164 name: "complexBehaviorDefinition",
17165 type: "ComplexBehaviorDefinition",
17166 isMany: true
17167 },
17168 {
17169 name: "completionCondition",
17170 type: "Expression",
17171 xml: {
17172 serialize: "xsi:type"
17173 }
17174 },
17175 {
17176 name: "oneBehaviorEventRef",
17177 type: "EventDefinition",
17178 isAttr: true,
17179 isReference: true
17180 },
17181 {
17182 name: "noneBehaviorEventRef",
17183 type: "EventDefinition",
17184 isAttr: true,
17185 isReference: true
17186 }
17187 ]
17188 },
17189 {
17190 name: "StandardLoopCharacteristics",
17191 superClass: [
17192 "LoopCharacteristics"
17193 ],
17194 properties: [
17195 {
17196 name: "testBefore",
17197 "default": false,
17198 isAttr: true,
17199 type: "Boolean"
17200 },
17201 {
17202 name: "loopCondition",
17203 type: "Expression",
17204 xml: {
17205 serialize: "xsi:type"
17206 }
17207 },
17208 {
17209 name: "loopMaximum",
17210 type: "Integer",
17211 isAttr: true
17212 }
17213 ]
17214 },
17215 {
17216 name: "CallActivity",
17217 superClass: [
17218 "Activity",
17219 "InteractionNode"
17220 ],
17221 properties: [
17222 {
17223 name: "calledElement",
17224 type: "String",
17225 isAttr: true
17226 }
17227 ]
17228 },
17229 {
17230 name: "Task",
17231 superClass: [
17232 "Activity",
17233 "InteractionNode"
17234 ]
17235 },
17236 {
17237 name: "SendTask",
17238 superClass: [
17239 "Task"
17240 ],
17241 properties: [
17242 {
17243 name: "implementation",
17244 isAttr: true,
17245 type: "String"
17246 },
17247 {
17248 name: "operationRef",
17249 type: "Operation",
17250 isAttr: true,
17251 isReference: true
17252 },
17253 {
17254 name: "messageRef",
17255 type: "Message",
17256 isAttr: true,
17257 isReference: true
17258 }
17259 ]
17260 },
17261 {
17262 name: "ReceiveTask",
17263 superClass: [
17264 "Task"
17265 ],
17266 properties: [
17267 {
17268 name: "implementation",
17269 isAttr: true,
17270 type: "String"
17271 },
17272 {
17273 name: "instantiate",
17274 "default": false,
17275 isAttr: true,
17276 type: "Boolean"
17277 },
17278 {
17279 name: "operationRef",
17280 type: "Operation",
17281 isAttr: true,
17282 isReference: true
17283 },
17284 {
17285 name: "messageRef",
17286 type: "Message",
17287 isAttr: true,
17288 isReference: true
17289 }
17290 ]
17291 },
17292 {
17293 name: "ScriptTask",
17294 superClass: [
17295 "Task"
17296 ],
17297 properties: [
17298 {
17299 name: "scriptFormat",
17300 isAttr: true,
17301 type: "String"
17302 },
17303 {
17304 name: "script",
17305 type: "String"
17306 }
17307 ]
17308 },
17309 {
17310 name: "BusinessRuleTask",
17311 superClass: [
17312 "Task"
17313 ],
17314 properties: [
17315 {
17316 name: "implementation",
17317 isAttr: true,
17318 type: "String"
17319 }
17320 ]
17321 },
17322 {
17323 name: "AdHocSubProcess",
17324 superClass: [
17325 "SubProcess"
17326 ],
17327 properties: [
17328 {
17329 name: "completionCondition",
17330 type: "Expression",
17331 xml: {
17332 serialize: "xsi:type"
17333 }
17334 },
17335 {
17336 name: "ordering",
17337 type: "AdHocOrdering",
17338 isAttr: true
17339 },
17340 {
17341 name: "cancelRemainingInstances",
17342 "default": true,
17343 isAttr: true,
17344 type: "Boolean"
17345 }
17346 ]
17347 },
17348 {
17349 name: "Transaction",
17350 superClass: [
17351 "SubProcess"
17352 ],
17353 properties: [
17354 {
17355 name: "protocol",
17356 isAttr: true,
17357 type: "String"
17358 },
17359 {
17360 name: "method",
17361 isAttr: true,
17362 type: "String"
17363 }
17364 ]
17365 },
17366 {
17367 name: "GlobalScriptTask",
17368 superClass: [
17369 "GlobalTask"
17370 ],
17371 properties: [
17372 {
17373 name: "scriptLanguage",
17374 isAttr: true,
17375 type: "String"
17376 },
17377 {
17378 name: "script",
17379 isAttr: true,
17380 type: "String"
17381 }
17382 ]
17383 },
17384 {
17385 name: "GlobalBusinessRuleTask",
17386 superClass: [
17387 "GlobalTask"
17388 ],
17389 properties: [
17390 {
17391 name: "implementation",
17392 isAttr: true,
17393 type: "String"
17394 }
17395 ]
17396 },
17397 {
17398 name: "ComplexBehaviorDefinition",
17399 superClass: [
17400 "BaseElement"
17401 ],
17402 properties: [
17403 {
17404 name: "condition",
17405 type: "FormalExpression"
17406 },
17407 {
17408 name: "event",
17409 type: "ImplicitThrowEvent"
17410 }
17411 ]
17412 },
17413 {
17414 name: "ResourceRole",
17415 superClass: [
17416 "BaseElement"
17417 ],
17418 properties: [
17419 {
17420 name: "resourceRef",
17421 type: "Resource",
17422 isReference: true
17423 },
17424 {
17425 name: "resourceParameterBindings",
17426 type: "ResourceParameterBinding",
17427 isMany: true
17428 },
17429 {
17430 name: "resourceAssignmentExpression",
17431 type: "ResourceAssignmentExpression"
17432 },
17433 {
17434 name: "name",
17435 isAttr: true,
17436 type: "String"
17437 }
17438 ]
17439 },
17440 {
17441 name: "ResourceParameterBinding",
17442 properties: [
17443 {
17444 name: "expression",
17445 type: "Expression",
17446 xml: {
17447 serialize: "xsi:type"
17448 }
17449 },
17450 {
17451 name: "parameterRef",
17452 type: "ResourceParameter",
17453 isAttr: true,
17454 isReference: true
17455 }
17456 ],
17457 superClass: [
17458 "BaseElement"
17459 ]
17460 },
17461 {
17462 name: "ResourceAssignmentExpression",
17463 properties: [
17464 {
17465 name: "expression",
17466 type: "Expression",
17467 xml: {
17468 serialize: "xsi:type"
17469 }
17470 }
17471 ],
17472 superClass: [
17473 "BaseElement"
17474 ]
17475 },
17476 {
17477 name: "Import",
17478 properties: [
17479 {
17480 name: "importType",
17481 isAttr: true,
17482 type: "String"
17483 },
17484 {
17485 name: "location",
17486 isAttr: true,
17487 type: "String"
17488 },
17489 {
17490 name: "namespace",
17491 isAttr: true,
17492 type: "String"
17493 }
17494 ]
17495 },
17496 {
17497 name: "Definitions",
17498 superClass: [
17499 "BaseElement"
17500 ],
17501 properties: [
17502 {
17503 name: "name",
17504 isAttr: true,
17505 type: "String"
17506 },
17507 {
17508 name: "targetNamespace",
17509 isAttr: true,
17510 type: "String"
17511 },
17512 {
17513 name: "expressionLanguage",
17514 "default": "http://www.w3.org/1999/XPath",
17515 isAttr: true,
17516 type: "String"
17517 },
17518 {
17519 name: "typeLanguage",
17520 "default": "http://www.w3.org/2001/XMLSchema",
17521 isAttr: true,
17522 type: "String"
17523 },
17524 {
17525 name: "imports",
17526 type: "Import",
17527 isMany: true
17528 },
17529 {
17530 name: "extensions",
17531 type: "Extension",
17532 isMany: true
17533 },
17534 {
17535 name: "rootElements",
17536 type: "RootElement",
17537 isMany: true
17538 },
17539 {
17540 name: "diagrams",
17541 isMany: true,
17542 type: "bpmndi:BPMNDiagram"
17543 },
17544 {
17545 name: "exporter",
17546 isAttr: true,
17547 type: "String"
17548 },
17549 {
17550 name: "relationships",
17551 type: "Relationship",
17552 isMany: true
17553 },
17554 {
17555 name: "exporterVersion",
17556 isAttr: true,
17557 type: "String"
17558 }
17559 ]
17560 }
17561 ];
17562 var enumerations = [
17563 {
17564 name: "ProcessType",
17565 literalValues: [
17566 {
17567 name: "None"
17568 },
17569 {
17570 name: "Public"
17571 },
17572 {
17573 name: "Private"
17574 }
17575 ]
17576 },
17577 {
17578 name: "GatewayDirection",
17579 literalValues: [
17580 {
17581 name: "Unspecified"
17582 },
17583 {
17584 name: "Converging"
17585 },
17586 {
17587 name: "Diverging"
17588 },
17589 {
17590 name: "Mixed"
17591 }
17592 ]
17593 },
17594 {
17595 name: "EventBasedGatewayType",
17596 literalValues: [
17597 {
17598 name: "Parallel"
17599 },
17600 {
17601 name: "Exclusive"
17602 }
17603 ]
17604 },
17605 {
17606 name: "RelationshipDirection",
17607 literalValues: [
17608 {
17609 name: "None"
17610 },
17611 {
17612 name: "Forward"
17613 },
17614 {
17615 name: "Backward"
17616 },
17617 {
17618 name: "Both"
17619 }
17620 ]
17621 },
17622 {
17623 name: "ItemKind",
17624 literalValues: [
17625 {
17626 name: "Physical"
17627 },
17628 {
17629 name: "Information"
17630 }
17631 ]
17632 },
17633 {
17634 name: "ChoreographyLoopType",
17635 literalValues: [
17636 {
17637 name: "None"
17638 },
17639 {
17640 name: "Standard"
17641 },
17642 {
17643 name: "MultiInstanceSequential"
17644 },
17645 {
17646 name: "MultiInstanceParallel"
17647 }
17648 ]
17649 },
17650 {
17651 name: "AssociationDirection",
17652 literalValues: [
17653 {
17654 name: "None"
17655 },
17656 {
17657 name: "One"
17658 },
17659 {
17660 name: "Both"
17661 }
17662 ]
17663 },
17664 {
17665 name: "MultiInstanceBehavior",
17666 literalValues: [
17667 {
17668 name: "None"
17669 },
17670 {
17671 name: "One"
17672 },
17673 {
17674 name: "All"
17675 },
17676 {
17677 name: "Complex"
17678 }
17679 ]
17680 },
17681 {
17682 name: "AdHocOrdering",
17683 literalValues: [
17684 {
17685 name: "Parallel"
17686 },
17687 {
17688 name: "Sequential"
17689 }
17690 ]
17691 }
17692 ];
17693 var xml = {
17694 tagAlias: "lowerCase",
17695 typePrefix: "t"
17696 };
17697 var BpmnPackage = {
17698 name: name,
17699 uri: uri,
17700 prefix: prefix,
17701 associations: associations,
17702 types: types,
17703 enumerations: enumerations,
17704 xml: xml
17705 };
17706
17707 var name$1 = "BPMNDI";
17708 var uri$1 = "http://www.omg.org/spec/BPMN/20100524/DI";
17709 var prefix$1 = "bpmndi";
17710 var types$1 = [
17711 {
17712 name: "BPMNDiagram",
17713 properties: [
17714 {
17715 name: "plane",
17716 type: "BPMNPlane",
17717 redefines: "di:Diagram#rootElement"
17718 },
17719 {
17720 name: "labelStyle",
17721 type: "BPMNLabelStyle",
17722 isMany: true
17723 }
17724 ],
17725 superClass: [
17726 "di:Diagram"
17727 ]
17728 },
17729 {
17730 name: "BPMNPlane",
17731 properties: [
17732 {
17733 name: "bpmnElement",
17734 isAttr: true,
17735 isReference: true,
17736 type: "bpmn:BaseElement",
17737 redefines: "di:DiagramElement#modelElement"
17738 }
17739 ],
17740 superClass: [
17741 "di:Plane"
17742 ]
17743 },
17744 {
17745 name: "BPMNShape",
17746 properties: [
17747 {
17748 name: "bpmnElement",
17749 isAttr: true,
17750 isReference: true,
17751 type: "bpmn:BaseElement",
17752 redefines: "di:DiagramElement#modelElement"
17753 },
17754 {
17755 name: "isHorizontal",
17756 isAttr: true,
17757 type: "Boolean"
17758 },
17759 {
17760 name: "isExpanded",
17761 isAttr: true,
17762 type: "Boolean"
17763 },
17764 {
17765 name: "isMarkerVisible",
17766 isAttr: true,
17767 type: "Boolean"
17768 },
17769 {
17770 name: "label",
17771 type: "BPMNLabel"
17772 },
17773 {
17774 name: "isMessageVisible",
17775 isAttr: true,
17776 type: "Boolean"
17777 },
17778 {
17779 name: "participantBandKind",
17780 type: "ParticipantBandKind",
17781 isAttr: true
17782 },
17783 {
17784 name: "choreographyActivityShape",
17785 type: "BPMNShape",
17786 isAttr: true,
17787 isReference: true
17788 }
17789 ],
17790 superClass: [
17791 "di:LabeledShape"
17792 ]
17793 },
17794 {
17795 name: "BPMNEdge",
17796 properties: [
17797 {
17798 name: "label",
17799 type: "BPMNLabel"
17800 },
17801 {
17802 name: "bpmnElement",
17803 isAttr: true,
17804 isReference: true,
17805 type: "bpmn:BaseElement",
17806 redefines: "di:DiagramElement#modelElement"
17807 },
17808 {
17809 name: "sourceElement",
17810 isAttr: true,
17811 isReference: true,
17812 type: "di:DiagramElement",
17813 redefines: "di:Edge#source"
17814 },
17815 {
17816 name: "targetElement",
17817 isAttr: true,
17818 isReference: true,
17819 type: "di:DiagramElement",
17820 redefines: "di:Edge#target"
17821 },
17822 {
17823 name: "messageVisibleKind",
17824 type: "MessageVisibleKind",
17825 isAttr: true,
17826 "default": "initiating"
17827 }
17828 ],
17829 superClass: [
17830 "di:LabeledEdge"
17831 ]
17832 },
17833 {
17834 name: "BPMNLabel",
17835 properties: [
17836 {
17837 name: "labelStyle",
17838 type: "BPMNLabelStyle",
17839 isAttr: true,
17840 isReference: true,
17841 redefines: "di:DiagramElement#style"
17842 }
17843 ],
17844 superClass: [
17845 "di:Label"
17846 ]
17847 },
17848 {
17849 name: "BPMNLabelStyle",
17850 properties: [
17851 {
17852 name: "font",
17853 type: "dc:Font"
17854 }
17855 ],
17856 superClass: [
17857 "di:Style"
17858 ]
17859 }
17860 ];
17861 var enumerations$1 = [
17862 {
17863 name: "ParticipantBandKind",
17864 literalValues: [
17865 {
17866 name: "top_initiating"
17867 },
17868 {
17869 name: "middle_initiating"
17870 },
17871 {
17872 name: "bottom_initiating"
17873 },
17874 {
17875 name: "top_non_initiating"
17876 },
17877 {
17878 name: "middle_non_initiating"
17879 },
17880 {
17881 name: "bottom_non_initiating"
17882 }
17883 ]
17884 },
17885 {
17886 name: "MessageVisibleKind",
17887 literalValues: [
17888 {
17889 name: "initiating"
17890 },
17891 {
17892 name: "non_initiating"
17893 }
17894 ]
17895 }
17896 ];
17897 var associations$1 = [
17898 ];
17899 var BpmnDiPackage = {
17900 name: name$1,
17901 uri: uri$1,
17902 prefix: prefix$1,
17903 types: types$1,
17904 enumerations: enumerations$1,
17905 associations: associations$1
17906 };
17907
17908 var name$2 = "DC";
17909 var uri$2 = "http://www.omg.org/spec/DD/20100524/DC";
17910 var prefix$2 = "dc";
17911 var types$2 = [
17912 {
17913 name: "Boolean"
17914 },
17915 {
17916 name: "Integer"
17917 },
17918 {
17919 name: "Real"
17920 },
17921 {
17922 name: "String"
17923 },
17924 {
17925 name: "Font",
17926 properties: [
17927 {
17928 name: "name",
17929 type: "String",
17930 isAttr: true
17931 },
17932 {
17933 name: "size",
17934 type: "Real",
17935 isAttr: true
17936 },
17937 {
17938 name: "isBold",
17939 type: "Boolean",
17940 isAttr: true
17941 },
17942 {
17943 name: "isItalic",
17944 type: "Boolean",
17945 isAttr: true
17946 },
17947 {
17948 name: "isUnderline",
17949 type: "Boolean",
17950 isAttr: true
17951 },
17952 {
17953 name: "isStrikeThrough",
17954 type: "Boolean",
17955 isAttr: true
17956 }
17957 ]
17958 },
17959 {
17960 name: "Point",
17961 properties: [
17962 {
17963 name: "x",
17964 type: "Real",
17965 "default": "0",
17966 isAttr: true
17967 },
17968 {
17969 name: "y",
17970 type: "Real",
17971 "default": "0",
17972 isAttr: true
17973 }
17974 ]
17975 },
17976 {
17977 name: "Bounds",
17978 properties: [
17979 {
17980 name: "x",
17981 type: "Real",
17982 "default": "0",
17983 isAttr: true
17984 },
17985 {
17986 name: "y",
17987 type: "Real",
17988 "default": "0",
17989 isAttr: true
17990 },
17991 {
17992 name: "width",
17993 type: "Real",
17994 isAttr: true
17995 },
17996 {
17997 name: "height",
17998 type: "Real",
17999 isAttr: true
18000 }
18001 ]
18002 }
18003 ];
18004 var associations$2 = [
18005 ];
18006 var DcPackage = {
18007 name: name$2,
18008 uri: uri$2,
18009 prefix: prefix$2,
18010 types: types$2,
18011 associations: associations$2
18012 };
18013
18014 var name$3 = "DI";
18015 var uri$3 = "http://www.omg.org/spec/DD/20100524/DI";
18016 var prefix$3 = "di";
18017 var types$3 = [
18018 {
18019 name: "DiagramElement",
18020 isAbstract: true,
18021 properties: [
18022 {
18023 name: "id",
18024 isAttr: true,
18025 isId: true,
18026 type: "String"
18027 },
18028 {
18029 name: "extension",
18030 type: "Extension"
18031 },
18032 {
18033 name: "owningDiagram",
18034 type: "Diagram",
18035 isReadOnly: true,
18036 isVirtual: true,
18037 isReference: true
18038 },
18039 {
18040 name: "owningElement",
18041 type: "DiagramElement",
18042 isReadOnly: true,
18043 isVirtual: true,
18044 isReference: true
18045 },
18046 {
18047 name: "modelElement",
18048 isReadOnly: true,
18049 isVirtual: true,
18050 isReference: true,
18051 type: "Element"
18052 },
18053 {
18054 name: "style",
18055 type: "Style",
18056 isReadOnly: true,
18057 isVirtual: true,
18058 isReference: true
18059 },
18060 {
18061 name: "ownedElement",
18062 type: "DiagramElement",
18063 isReadOnly: true,
18064 isMany: true,
18065 isVirtual: true
18066 }
18067 ]
18068 },
18069 {
18070 name: "Node",
18071 isAbstract: true,
18072 superClass: [
18073 "DiagramElement"
18074 ]
18075 },
18076 {
18077 name: "Edge",
18078 isAbstract: true,
18079 superClass: [
18080 "DiagramElement"
18081 ],
18082 properties: [
18083 {
18084 name: "source",
18085 type: "DiagramElement",
18086 isReadOnly: true,
18087 isVirtual: true,
18088 isReference: true
18089 },
18090 {
18091 name: "target",
18092 type: "DiagramElement",
18093 isReadOnly: true,
18094 isVirtual: true,
18095 isReference: true
18096 },
18097 {
18098 name: "waypoint",
18099 isUnique: false,
18100 isMany: true,
18101 type: "dc:Point",
18102 xml: {
18103 serialize: "xsi:type"
18104 }
18105 }
18106 ]
18107 },
18108 {
18109 name: "Diagram",
18110 isAbstract: true,
18111 properties: [
18112 {
18113 name: "id",
18114 isAttr: true,
18115 isId: true,
18116 type: "String"
18117 },
18118 {
18119 name: "rootElement",
18120 type: "DiagramElement",
18121 isReadOnly: true,
18122 isVirtual: true
18123 },
18124 {
18125 name: "name",
18126 isAttr: true,
18127 type: "String"
18128 },
18129 {
18130 name: "documentation",
18131 isAttr: true,
18132 type: "String"
18133 },
18134 {
18135 name: "resolution",
18136 isAttr: true,
18137 type: "Real"
18138 },
18139 {
18140 name: "ownedStyle",
18141 type: "Style",
18142 isReadOnly: true,
18143 isMany: true,
18144 isVirtual: true
18145 }
18146 ]
18147 },
18148 {
18149 name: "Shape",
18150 isAbstract: true,
18151 superClass: [
18152 "Node"
18153 ],
18154 properties: [
18155 {
18156 name: "bounds",
18157 type: "dc:Bounds"
18158 }
18159 ]
18160 },
18161 {
18162 name: "Plane",
18163 isAbstract: true,
18164 superClass: [
18165 "Node"
18166 ],
18167 properties: [
18168 {
18169 name: "planeElement",
18170 type: "DiagramElement",
18171 subsettedProperty: "DiagramElement-ownedElement",
18172 isMany: true
18173 }
18174 ]
18175 },
18176 {
18177 name: "LabeledEdge",
18178 isAbstract: true,
18179 superClass: [
18180 "Edge"
18181 ],
18182 properties: [
18183 {
18184 name: "ownedLabel",
18185 type: "Label",
18186 isReadOnly: true,
18187 subsettedProperty: "DiagramElement-ownedElement",
18188 isMany: true,
18189 isVirtual: true
18190 }
18191 ]
18192 },
18193 {
18194 name: "LabeledShape",
18195 isAbstract: true,
18196 superClass: [
18197 "Shape"
18198 ],
18199 properties: [
18200 {
18201 name: "ownedLabel",
18202 type: "Label",
18203 isReadOnly: true,
18204 subsettedProperty: "DiagramElement-ownedElement",
18205 isMany: true,
18206 isVirtual: true
18207 }
18208 ]
18209 },
18210 {
18211 name: "Label",
18212 isAbstract: true,
18213 superClass: [
18214 "Node"
18215 ],
18216 properties: [
18217 {
18218 name: "bounds",
18219 type: "dc:Bounds"
18220 }
18221 ]
18222 },
18223 {
18224 name: "Style",
18225 isAbstract: true,
18226 properties: [
18227 {
18228 name: "id",
18229 isAttr: true,
18230 isId: true,
18231 type: "String"
18232 }
18233 ]
18234 },
18235 {
18236 name: "Extension",
18237 properties: [
18238 {
18239 name: "values",
18240 isMany: true,
18241 type: "Element"
18242 }
18243 ]
18244 }
18245 ];
18246 var associations$3 = [
18247 ];
18248 var xml$1 = {
18249 tagAlias: "lowerCase"
18250 };
18251 var DiPackage = {
18252 name: name$3,
18253 uri: uri$3,
18254 prefix: prefix$3,
18255 types: types$3,
18256 associations: associations$3,
18257 xml: xml$1
18258 };
18259
18260 var name$4 = "bpmn.io colors for BPMN";
18261 var uri$4 = "http://bpmn.io/schema/bpmn/biocolor/1.0";
18262 var prefix$4 = "bioc";
18263 var types$4 = [
18264 {
18265 name: "ColoredShape",
18266 "extends": [
18267 "bpmndi:BPMNShape"
18268 ],
18269 properties: [
18270 {
18271 name: "stroke",
18272 isAttr: true,
18273 type: "String"
18274 },
18275 {
18276 name: "fill",
18277 isAttr: true,
18278 type: "String"
18279 }
18280 ]
18281 },
18282 {
18283 name: "ColoredEdge",
18284 "extends": [
18285 "bpmndi:BPMNEdge"
18286 ],
18287 properties: [
18288 {
18289 name: "stroke",
18290 isAttr: true,
18291 type: "String"
18292 },
18293 {
18294 name: "fill",
18295 isAttr: true,
18296 type: "String"
18297 }
18298 ]
18299 }
18300 ];
18301 var enumerations$2 = [
18302 ];
18303 var associations$4 = [
18304 ];
18305 var BiocPackage = {
18306 name: name$4,
18307 uri: uri$4,
18308 prefix: prefix$4,
18309 types: types$4,
18310 enumerations: enumerations$2,
18311 associations: associations$4
18312 };
18313
18314 var name$5 = "BPMN in Color";
18315 var uri$5 = "http://www.omg.org/spec/BPMN/non-normative/color/1.0";
18316 var prefix$5 = "color";
18317 var types$5 = [
18318 {
18319 name: "ColoredLabel",
18320 "extends": [
18321 "bpmndi:BPMNLabel"
18322 ],
18323 properties: [
18324 {
18325 name: "color",
18326 isAttr: true,
18327 type: "String"
18328 }
18329 ]
18330 },
18331 {
18332 name: "ColoredShape",
18333 "extends": [
18334 "bpmndi:BPMNShape"
18335 ],
18336 properties: [
18337 {
18338 name: "background-color",
18339 isAttr: true,
18340 type: "String"
18341 },
18342 {
18343 name: "border-color",
18344 isAttr: true,
18345 type: "String"
18346 }
18347 ]
18348 },
18349 {
18350 name: "ColoredEdge",
18351 "extends": [
18352 "bpmndi:BPMNEdge"
18353 ],
18354 properties: [
18355 {
18356 name: "border-color",
18357 isAttr: true,
18358 type: "String"
18359 }
18360 ]
18361 }
18362 ];
18363 var enumerations$3 = [
18364 ];
18365 var associations$5 = [
18366 ];
18367 var BpmnInColorPackage = {
18368 name: name$5,
18369 uri: uri$5,
18370 prefix: prefix$5,
18371 types: types$5,
18372 enumerations: enumerations$3,
18373 associations: associations$5
18374 };
18375
18376 var packages = {
18377 bpmn: BpmnPackage,
18378 bpmndi: BpmnDiPackage,
18379 dc: DcPackage,
18380 di: DiPackage,
18381 bioc: BiocPackage,
18382 color: BpmnInColorPackage
18383 };
18384
18385 function simple(additionalPackages, options) {
18386 var pks = assign({}, packages, additionalPackages);
18387
18388 return new BpmnModdle(pks, options);
18389 }
18390
18391 var diRefs = new Refs(
18392 { name: 'bpmnElement', enumerable: true },
18393 { name: 'di', configurable: true }
18394 );
18395
18396 /**
18397 * Returns true if an element has the given meta-model type
18398 *
18399 * @param {ModdleElement} element
18400 * @param {string} type
18401 *
18402 * @return {boolean}
18403 */
18404 function is(element, type) {
18405 return element.$instanceOf(type);
18406 }
18407
18408
18409 /**
18410 * Find a suitable display candidate for definitions where the DI does not
18411 * correctly specify one.
18412 */
18413 function findDisplayCandidate(definitions) {
18414 return find(definitions.rootElements, function(e) {
18415 return is(e, 'bpmn:Process') || is(e, 'bpmn:Collaboration');
18416 });
18417 }
18418
18419
18420 function BpmnTreeWalker(handler, translate) {
18421
18422 // list of containers already walked
18423 var handledElements = {};
18424
18425 // list of elements to handle deferred to ensure
18426 // prerequisites are drawn
18427 var deferred = [];
18428
18429 // Helpers //////////////////////
18430
18431 function contextual(fn, ctx) {
18432 return function(e) {
18433 fn(e, ctx);
18434 };
18435 }
18436
18437 function handled(element) {
18438 handledElements[element.id] = element;
18439 }
18440
18441 function isHandled(element) {
18442 return handledElements[element.id];
18443 }
18444
18445 function visit(element, ctx) {
18446
18447 var gfx = element.gfx;
18448
18449 // avoid multiple rendering of elements
18450 if (gfx) {
18451 throw new Error(
18452 translate('already rendered {element}', { element: elementToString(element) })
18453 );
18454 }
18455
18456 // call handler
18457 return handler.element(element, ctx);
18458 }
18459
18460 function visitRoot(element, diagram) {
18461 return handler.root(element, diagram);
18462 }
18463
18464 function visitIfDi(element, ctx) {
18465
18466 try {
18467 var gfx = element.di && visit(element, ctx);
18468
18469 handled(element);
18470
18471 return gfx;
18472 } catch (e) {
18473 logError(e.message, { element: element, error: e });
18474
18475 console.error(translate('failed to import {element}', { element: elementToString(element) }));
18476 console.error(e);
18477 }
18478 }
18479
18480 function logError(message, context) {
18481 handler.error(message, context);
18482 }
18483
18484 // DI handling //////////////////////
18485
18486 function registerDi(di) {
18487 var bpmnElement = di.bpmnElement;
18488
18489 if (bpmnElement) {
18490 if (bpmnElement.di) {
18491 logError(
18492 translate('multiple DI elements defined for {element}', {
18493 element: elementToString(bpmnElement)
18494 }),
18495 { element: bpmnElement }
18496 );
18497 } else {
18498 diRefs.bind(bpmnElement, 'di');
18499 bpmnElement.di = di;
18500 }
18501 } else {
18502 logError(
18503 translate('no bpmnElement referenced in {element}', {
18504 element: elementToString(di)
18505 }),
18506 { element: di }
18507 );
18508 }
18509 }
18510
18511 function handleDiagram(diagram) {
18512 handlePlane(diagram.plane);
18513 }
18514
18515 function handlePlane(plane) {
18516 registerDi(plane);
18517
18518 forEach(plane.planeElement, handlePlaneElement);
18519 }
18520
18521 function handlePlaneElement(planeElement) {
18522 registerDi(planeElement);
18523 }
18524
18525
18526 // Semantic handling //////////////////////
18527
18528 /**
18529 * Handle definitions and return the rendered diagram (if any)
18530 *
18531 * @param {ModdleElement} definitions to walk and import
18532 * @param {ModdleElement} [diagram] specific diagram to import and display
18533 *
18534 * @throws {Error} if no diagram to display could be found
18535 */
18536 function handleDefinitions(definitions, diagram) {
18537
18538 // make sure we walk the correct bpmnElement
18539
18540 var diagrams = definitions.diagrams;
18541
18542 if (diagram && diagrams.indexOf(diagram) === -1) {
18543 throw new Error(translate('diagram not part of bpmn:Definitions'));
18544 }
18545
18546 if (!diagram && diagrams && diagrams.length) {
18547 diagram = diagrams[0];
18548 }
18549
18550 // no diagram -> nothing to import
18551 if (!diagram) {
18552 throw new Error(translate('no diagram to display'));
18553 }
18554
18555 // load DI from selected diagram only
18556 handleDiagram(diagram);
18557
18558
18559 var plane = diagram.plane;
18560
18561 if (!plane) {
18562 throw new Error(translate(
18563 'no plane for {element}',
18564 { element: elementToString(diagram) }
18565 ));
18566 }
18567
18568 var rootElement = plane.bpmnElement;
18569
18570 // ensure we default to a suitable display candidate (process or collaboration),
18571 // even if non is specified in DI
18572 if (!rootElement) {
18573 rootElement = findDisplayCandidate(definitions);
18574
18575 if (!rootElement) {
18576 throw new Error(translate('no process or collaboration to display'));
18577 } else {
18578
18579 logError(
18580 translate('correcting missing bpmnElement on {plane} to {rootElement}', {
18581 plane: elementToString(plane),
18582 rootElement: elementToString(rootElement)
18583 })
18584 );
18585
18586 // correct DI on the fly
18587 plane.bpmnElement = rootElement;
18588 registerDi(plane);
18589 }
18590 }
18591
18592
18593 var ctx = visitRoot(rootElement, plane);
18594
18595 if (is(rootElement, 'bpmn:Process')) {
18596 handleProcess(rootElement, ctx);
18597 } else if (is(rootElement, 'bpmn:Collaboration')) {
18598 handleCollaboration(rootElement);
18599
18600 // force drawing of everything not yet drawn that is part of the target DI
18601 handleUnhandledProcesses(definitions.rootElements, ctx);
18602 } else {
18603 throw new Error(
18604 translate('unsupported bpmnElement for {plane}: {rootElement}', {
18605 plane: elementToString(plane),
18606 rootElement: elementToString(rootElement)
18607 })
18608 );
18609 }
18610
18611 // handle all deferred elements
18612 handleDeferred();
18613 }
18614
18615 function handleDeferred() {
18616
18617 var fn;
18618
18619 // drain deferred until empty
18620 while (deferred.length) {
18621 fn = deferred.shift();
18622
18623 fn();
18624 }
18625 }
18626
18627 function handleProcess(process, context) {
18628 handleFlowElementsContainer(process, context);
18629 handleIoSpecification(process.ioSpecification, context);
18630
18631 handleArtifacts(process.artifacts, context);
18632
18633 // log process handled
18634 handled(process);
18635 }
18636
18637 function handleUnhandledProcesses(rootElements, ctx) {
18638
18639 // walk through all processes that have not yet been drawn and draw them
18640 // if they contain lanes with DI information.
18641 // we do this to pass the free-floating lane test cases in the MIWG test suite
18642 var processes = filter(rootElements, function(e) {
18643 return !isHandled(e) && is(e, 'bpmn:Process') && e.laneSets;
18644 });
18645
18646 processes.forEach(contextual(handleProcess, ctx));
18647 }
18648
18649 function handleMessageFlow(messageFlow, context) {
18650 visitIfDi(messageFlow, context);
18651 }
18652
18653 function handleMessageFlows(messageFlows, context) {
18654 forEach(messageFlows, contextual(handleMessageFlow, context));
18655 }
18656
18657 function handleDataAssociation(association, context) {
18658 visitIfDi(association, context);
18659 }
18660
18661 function handleDataInput(dataInput, context) {
18662 visitIfDi(dataInput, context);
18663 }
18664
18665 function handleDataOutput(dataOutput, context) {
18666 visitIfDi(dataOutput, context);
18667 }
18668
18669 function handleArtifact(artifact, context) {
18670
18671 // bpmn:TextAnnotation
18672 // bpmn:Group
18673 // bpmn:Association
18674
18675 visitIfDi(artifact, context);
18676 }
18677
18678 function handleArtifacts(artifacts, context) {
18679
18680 forEach(artifacts, function(e) {
18681 if (is(e, 'bpmn:Association')) {
18682 deferred.push(function() {
18683 handleArtifact(e, context);
18684 });
18685 } else {
18686 handleArtifact(e, context);
18687 }
18688 });
18689 }
18690
18691 function handleIoSpecification(ioSpecification, context) {
18692
18693 if (!ioSpecification) {
18694 return;
18695 }
18696
18697 forEach(ioSpecification.dataInputs, contextual(handleDataInput, context));
18698 forEach(ioSpecification.dataOutputs, contextual(handleDataOutput, context));
18699 }
18700
18701 function handleSubProcess(subProcess, context) {
18702 handleFlowElementsContainer(subProcess, context);
18703 handleArtifacts(subProcess.artifacts, context);
18704 }
18705
18706 function handleFlowNode(flowNode, context) {
18707 var childCtx = visitIfDi(flowNode, context);
18708
18709 if (is(flowNode, 'bpmn:SubProcess')) {
18710 handleSubProcess(flowNode, childCtx || context);
18711 }
18712
18713 if (is(flowNode, 'bpmn:Activity')) {
18714 handleIoSpecification(flowNode.ioSpecification, context);
18715 }
18716
18717 // defer handling of associations
18718 // affected types:
18719 //
18720 // * bpmn:Activity
18721 // * bpmn:ThrowEvent
18722 // * bpmn:CatchEvent
18723 //
18724 deferred.push(function() {
18725 forEach(flowNode.dataInputAssociations, contextual(handleDataAssociation, context));
18726 forEach(flowNode.dataOutputAssociations, contextual(handleDataAssociation, context));
18727 });
18728 }
18729
18730 function handleSequenceFlow(sequenceFlow, context) {
18731 visitIfDi(sequenceFlow, context);
18732 }
18733
18734 function handleDataElement(dataObject, context) {
18735 visitIfDi(dataObject, context);
18736 }
18737
18738 function handleLane(lane, context) {
18739
18740 deferred.push(function() {
18741
18742 var newContext = visitIfDi(lane, context);
18743
18744 if (lane.childLaneSet) {
18745 handleLaneSet(lane.childLaneSet, newContext || context);
18746 }
18747
18748 wireFlowNodeRefs(lane);
18749 });
18750 }
18751
18752 function handleLaneSet(laneSet, context) {
18753 forEach(laneSet.lanes, contextual(handleLane, context));
18754 }
18755
18756 function handleLaneSets(laneSets, context) {
18757 forEach(laneSets, contextual(handleLaneSet, context));
18758 }
18759
18760 function handleFlowElementsContainer(container, context) {
18761 handleFlowElements(container.flowElements, context);
18762
18763 if (container.laneSets) {
18764 handleLaneSets(container.laneSets, context);
18765 }
18766 }
18767
18768 function handleFlowElements(flowElements, context) {
18769 forEach(flowElements, function(e) {
18770 if (is(e, 'bpmn:SequenceFlow')) {
18771 deferred.push(function() {
18772 handleSequenceFlow(e, context);
18773 });
18774 } else if (is(e, 'bpmn:BoundaryEvent')) {
18775 deferred.unshift(function() {
18776 handleFlowNode(e, context);
18777 });
18778 } else if (is(e, 'bpmn:FlowNode')) {
18779 handleFlowNode(e, context);
18780 } else if (is(e, 'bpmn:DataObject')) ; else if (is(e, 'bpmn:DataStoreReference')) {
18781 handleDataElement(e, context);
18782 } else if (is(e, 'bpmn:DataObjectReference')) {
18783 handleDataElement(e, context);
18784 } else {
18785 logError(
18786 translate('unrecognized flowElement {element} in context {context}', {
18787 element: elementToString(e),
18788 context: (context ? elementToString(context.businessObject) : 'null')
18789 }),
18790 { element: e, context: context }
18791 );
18792 }
18793 });
18794 }
18795
18796 function handleParticipant(participant, context) {
18797 var newCtx = visitIfDi(participant, context);
18798
18799 var process = participant.processRef;
18800 if (process) {
18801 handleProcess(process, newCtx || context);
18802 }
18803 }
18804
18805 function handleCollaboration(collaboration) {
18806
18807 forEach(collaboration.participants, contextual(handleParticipant));
18808
18809 handleArtifacts(collaboration.artifacts);
18810
18811 // handle message flows latest in the process
18812 deferred.push(function() {
18813 handleMessageFlows(collaboration.messageFlows);
18814 });
18815 }
18816
18817
18818 function wireFlowNodeRefs(lane) {
18819
18820 // wire the virtual flowNodeRefs <-> relationship
18821 forEach(lane.flowNodeRef, function(flowNode) {
18822 var lanes = flowNode.get('lanes');
18823
18824 if (lanes) {
18825 lanes.push(lane);
18826 }
18827 });
18828 }
18829
18830 // API //////////////////////
18831
18832 return {
18833 handleDeferred: handleDeferred,
18834 handleDefinitions: handleDefinitions,
18835 handleSubProcess: handleSubProcess,
18836 registerDi: registerDi
18837 };
18838 }
18839
18840 /**
18841 * The importBpmnDiagram result.
18842 *
18843 * @typedef {Object} ImportBPMNDiagramResult
18844 *
18845 * @property {Array<string>} warnings
18846 */
18847
18848 /**
18849 * The importBpmnDiagram error.
18850 *
18851 * @typedef {Error} ImportBPMNDiagramError
18852 *
18853 * @property {Array<string>} warnings
18854 */
18855
18856 /**
18857 * Import the definitions into a diagram.
18858 *
18859 * Errors and warnings are reported through the specified callback.
18860 *
18861 * @param {djs.Diagram} diagram
18862 * @param {ModdleElement<Definitions>} definitions
18863 * @param {ModdleElement<BPMNDiagram>} [bpmnDiagram] the diagram to be rendered
18864 * (if not provided, the first one will be rendered)
18865 *
18866 * Returns {Promise<ImportBPMNDiagramResult, ImportBPMNDiagramError>}
18867 */
18868 function importBpmnDiagram(diagram, definitions, bpmnDiagram) {
18869
18870 var importer,
18871 eventBus,
18872 translate;
18873
18874 var error,
18875 warnings = [];
18876
18877 /**
18878 * Walk the diagram semantically, importing (=drawing)
18879 * all elements you encounter.
18880 *
18881 * @param {ModdleElement<Definitions>} definitions
18882 * @param {ModdleElement<BPMNDiagram>} bpmnDiagram
18883 */
18884 function render(definitions, bpmnDiagram) {
18885
18886 var visitor = {
18887
18888 root: function(element) {
18889 return importer.add(element);
18890 },
18891
18892 element: function(element, parentShape) {
18893 return importer.add(element, parentShape);
18894 },
18895
18896 error: function(message, context) {
18897 warnings.push({ message: message, context: context });
18898 }
18899 };
18900
18901 var walker = new BpmnTreeWalker(visitor, translate);
18902
18903 // traverse BPMN 2.0 document model,
18904 // starting at definitions
18905 walker.handleDefinitions(definitions, bpmnDiagram);
18906 }
18907
18908 return new Promise(function(resolve, reject) {
18909 try {
18910 importer = diagram.get('bpmnImporter');
18911 eventBus = diagram.get('eventBus');
18912 translate = diagram.get('translate');
18913
18914 eventBus.fire('import.render.start', { definitions: definitions });
18915
18916 render(definitions, bpmnDiagram);
18917
18918 eventBus.fire('import.render.complete', {
18919 error: error,
18920 warnings: warnings
18921 });
18922
18923 return resolve({ warnings: warnings });
18924 } catch (e) {
18925
18926 e.warnings = warnings;
18927 return reject(e);
18928 }
18929 });
18930 }
18931
18932 // TODO(nikku): remove with future bpmn-js version
18933
18934 /**
18935 * Wraps APIs to check:
18936 *
18937 * 1) If a callback is passed -> Warn users about callback deprecation.
18938 * 2) If Promise class is implemented in current environment.
18939 *
18940 * @private
18941 */
18942 function wrapForCompatibility(api) {
18943
18944 return function() {
18945
18946 if (!window.Promise) {
18947 throw new Error('Promises is not supported in this environment. Please polyfill Promise.');
18948 }
18949
18950 var argLen = arguments.length;
18951 if (argLen >= 1 && isFunction(arguments[argLen - 1])) {
18952
18953 var callback = arguments[argLen - 1];
18954
18955 console.warn(new Error(
18956 'Passing callbacks to ' + api.name + ' is deprecated and will be removed in a future major release. ' +
18957 'Please switch to promises: https://bpmn.io/l/moving-to-promises.html'
18958 ));
18959
18960 var argsWithoutCallback = Array.prototype.slice.call(arguments, 0, -1);
18961
18962 api.apply(this, argsWithoutCallback).then(function(result) {
18963
18964 var firstKey = Object.keys(result)[0];
18965
18966 // The APIs we are wrapping all resolve a single item depending on the API.
18967 // For instance, importXML resolves { warnings } and saveXML returns { xml }.
18968 // That's why we can call the callback with the first item of result.
18969 return callback(null, result[firstKey]);
18970
18971 // Passing a second paramter instead of catch because we don't want to
18972 // catch errors thrown by callback().
18973 }, function(err) {
18974
18975 return callback(err, err.warnings);
18976 });
18977 } else {
18978
18979 return api.apply(this, arguments);
18980 }
18981 };
18982 }
18983
18984 /**
18985 * This file must not be changed or exchanged.
18986 *
18987 * @see http://bpmn.io/license for more information.
18988 */
18989
18990
18991 // inlined ../../resources/logo.svg
18992 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>';
18993
18994 var BPMNIO_IMG = BPMNIO_LOGO_SVG;
18995
18996 function css(attrs) {
18997 return attrs.join(';');
18998 }
18999
19000 var LINK_STYLES = css([
19001 'color: #404040'
19002 ]);
19003
19004 var LIGHTBOX_STYLES = css([
19005 'z-index: 1001',
19006 'position: fixed',
19007 'top: 0',
19008 'left: 0',
19009 'right: 0',
19010 'bottom: 0'
19011 ]);
19012
19013 var BACKDROP_STYLES = css([
19014 'width: 100%',
19015 'height: 100%',
19016 'background: rgba(40,40,40,0.2)'
19017 ]);
19018
19019 var NOTICE_STYLES = css([
19020 'position: absolute',
19021 'left: 50%',
19022 'top: 40%',
19023 'transform: translate(-50%)',
19024 'width: 260px',
19025 'padding: 10px',
19026 'background: white',
19027 'box-shadow: 0 1px 4px rgba(0,0,0,0.3)',
19028 'font-family: Helvetica, Arial, sans-serif',
19029 'font-size: 14px',
19030 'display: flex',
19031 'line-height: 1.3'
19032 ]);
19033
19034 var LIGHTBOX_MARKUP =
19035 '<div class="bjs-powered-by-lightbox" style="' + LIGHTBOX_STYLES + '">' +
19036 '<div class="backdrop" style="' + BACKDROP_STYLES + '"></div>' +
19037 '<div class="notice" style="' + NOTICE_STYLES + '">' +
19038 '<a href="https://bpmn.io" target="_blank" rel="noopener" style="margin: 15px 20px 15px 10px; align-self: center;' + LINK_STYLES + '">' +
19039 BPMNIO_IMG +
19040 '</a>' +
19041 '<span>' +
19042 'Web-based tooling for BPMN, DMN and CMMN diagrams ' +
19043 'powered by <a href="https://bpmn.io" target="_blank" rel="noopener">bpmn.io</a>.' +
19044 '</span>' +
19045 '</div>' +
19046 '</div>';
19047
19048
19049 var lightbox;
19050
19051 function open() {
19052
19053 if (!lightbox) {
19054 lightbox = domify(LIGHTBOX_MARKUP);
19055
19056 delegate.bind(lightbox, '.backdrop', 'click', function(event) {
19057 document.body.removeChild(lightbox);
19058 });
19059 }
19060
19061 document.body.appendChild(lightbox);
19062 }
19063
19064 /**
19065 * The code in the <project-logo></project-logo> area
19066 * must not be changed.
19067 *
19068 * @see http://bpmn.io/license for more information.
19069 */
19070
19071 /**
19072 * A base viewer for BPMN 2.0 diagrams.
19073 *
19074 * Have a look at {@link Viewer}, {@link NavigatedViewer} or {@link Modeler} for
19075 * bundles that include actual features.
19076 *
19077 * @param {Object} [options] configuration options to pass to the viewer
19078 * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
19079 * @param {string|number} [options.width] the width of the viewer
19080 * @param {string|number} [options.height] the height of the viewer
19081 * @param {Object} [options.moddleExtensions] extension packages to provide
19082 * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
19083 * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
19084 */
19085 function BaseViewer(options) {
19086
19087 options = assign({}, DEFAULT_OPTIONS, options);
19088
19089 this._moddle = this._createModdle(options);
19090
19091 this._container = this._createContainer(options);
19092
19093 /* <project-logo> */
19094
19095 addProjectLogo(this._container);
19096
19097 /* </project-logo> */
19098
19099 this._init(this._container, this._moddle, options);
19100 }
19101
19102 inherits$1(BaseViewer, Diagram);
19103
19104 /**
19105 * The importXML result.
19106 *
19107 * @typedef {Object} ImportXMLResult
19108 *
19109 * @property {Array<string>} warnings
19110 */
19111
19112 /**
19113 * The importXML error.
19114 *
19115 * @typedef {Error} ImportXMLError
19116 *
19117 * @property {Array<string>} warnings
19118 */
19119
19120 /**
19121 * Parse and render a BPMN 2.0 diagram.
19122 *
19123 * Once finished the viewer reports back the result to the
19124 * provided callback function with (err, warnings).
19125 *
19126 * ## Life-Cycle Events
19127 *
19128 * During import the viewer will fire life-cycle events:
19129 *
19130 * * import.parse.start (about to read model from xml)
19131 * * import.parse.complete (model read; may have worked or not)
19132 * * import.render.start (graphical import start)
19133 * * import.render.complete (graphical import finished)
19134 * * import.done (everything done)
19135 *
19136 * You can use these events to hook into the life-cycle.
19137 *
19138 * @param {string} xml the BPMN 2.0 xml
19139 * @param {ModdleElement<BPMNDiagram>|string} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
19140 *
19141 * Returns {Promise<ImportXMLResult, ImportXMLError>}
19142 */
19143 BaseViewer.prototype.importXML = wrapForCompatibility(function importXML(xml, bpmnDiagram) {
19144
19145 var self = this;
19146
19147 function ParseCompleteEvent(data) {
19148
19149 var event = self.get('eventBus').createEvent(data);
19150
19151 // TODO(nikku): remove with future bpmn-js version
19152 Object.defineProperty(event, 'context', {
19153 enumerable: true,
19154 get: function() {
19155
19156 console.warn(new Error(
19157 'import.parse.complete <context> is deprecated ' +
19158 'and will be removed in future library versions'
19159 ));
19160
19161 return {
19162 warnings: data.warnings,
19163 references: data.references,
19164 elementsById: data.elementsById
19165 };
19166 }
19167 });
19168
19169 return event;
19170 }
19171
19172 return new Promise(function(resolve, reject) {
19173
19174 // hook in pre-parse listeners +
19175 // allow xml manipulation
19176 xml = self._emit('import.parse.start', { xml: xml }) || xml;
19177
19178 self._moddle.fromXML(xml, 'bpmn:Definitions').then(function(result) {
19179 var definitions = result.rootElement;
19180 var references = result.references;
19181 var parseWarnings = result.warnings;
19182 var elementsById = result.elementsById;
19183
19184 // hook in post parse listeners +
19185 // allow definitions manipulation
19186 definitions = self._emit('import.parse.complete', ParseCompleteEvent({
19187 error: null,
19188 definitions: definitions,
19189 elementsById: elementsById,
19190 references: references,
19191 warnings: parseWarnings
19192 })) || definitions;
19193
19194 self.importDefinitions(definitions, bpmnDiagram).then(function(result) {
19195 var allWarnings = [].concat(parseWarnings, result.warnings || []);
19196
19197 self._emit('import.done', { error: null, warnings: allWarnings });
19198
19199 return resolve({ warnings: allWarnings });
19200 }).catch(function(err) {
19201 var allWarnings = [].concat(parseWarnings, err.warnings || []);
19202
19203 self._emit('import.done', { error: err, warnings: allWarnings });
19204
19205 return reject(addWarningsToError(err, allWarnings));
19206 });
19207 }).catch(function(err) {
19208
19209 self._emit('import.parse.complete', {
19210 error: err
19211 });
19212
19213 err = checkValidationError(err);
19214
19215 self._emit('import.done', { error: err, warnings: err.warnings });
19216
19217 return reject(err);
19218 });
19219 });
19220 });
19221
19222 /**
19223 * The importDefinitions result.
19224 *
19225 * @typedef {Object} ImportDefinitionsResult
19226 *
19227 * @property {Array<string>} warnings
19228 */
19229
19230 /**
19231 * The importDefinitions error.
19232 *
19233 * @typedef {Error} ImportDefinitionsError
19234 *
19235 * @property {Array<string>} warnings
19236 */
19237
19238 /**
19239 * Import parsed definitions and render a BPMN 2.0 diagram.
19240 *
19241 * Once finished the viewer reports back the result to the
19242 * provided callback function with (err, warnings).
19243 *
19244 * ## Life-Cycle Events
19245 *
19246 * During import the viewer will fire life-cycle events:
19247 *
19248 * * import.render.start (graphical import start)
19249 * * import.render.complete (graphical import finished)
19250 *
19251 * You can use these events to hook into the life-cycle.
19252 *
19253 * @param {ModdleElement<Definitions>} definitions parsed BPMN 2.0 definitions
19254 * @param {ModdleElement<BPMNDiagram>|string} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
19255 *
19256 * Returns {Promise<ImportDefinitionsResult, ImportDefinitionsError>}
19257 */
19258 BaseViewer.prototype.importDefinitions = wrapForCompatibility(function importDefinitions(definitions, bpmnDiagram) {
19259
19260 var self = this;
19261
19262 return new Promise(function(resolve, reject) {
19263
19264 self._setDefinitions(definitions);
19265
19266 self.open(bpmnDiagram).then(function(result) {
19267
19268 var warnings = result.warnings;
19269
19270 return resolve({ warnings: warnings });
19271 }).catch(function(err) {
19272
19273 return reject(err);
19274 });
19275 });
19276 });
19277
19278 /**
19279 * The open result.
19280 *
19281 * @typedef {Object} OpenResult
19282 *
19283 * @property {Array<string>} warnings
19284 */
19285
19286 /**
19287 * The open error.
19288 *
19289 * @typedef {Error} OpenError
19290 *
19291 * @property {Array<string>} warnings
19292 */
19293
19294 /**
19295 * Open diagram of previously imported XML.
19296 *
19297 * Once finished the viewer reports back the result to the
19298 * provided callback function with (err, warnings).
19299 *
19300 * ## Life-Cycle Events
19301 *
19302 * During switch the viewer will fire life-cycle events:
19303 *
19304 * * import.render.start (graphical import start)
19305 * * import.render.complete (graphical import finished)
19306 *
19307 * You can use these events to hook into the life-cycle.
19308 *
19309 * @param {string|ModdleElement<BPMNDiagram>} [bpmnDiagramOrId] id or the diagram to open
19310 *
19311 * Returns {Promise<OpenResult, OpenError>}
19312 */
19313 BaseViewer.prototype.open = wrapForCompatibility(function open(bpmnDiagramOrId) {
19314
19315 var definitions = this._definitions;
19316 var bpmnDiagram = bpmnDiagramOrId;
19317
19318 var self = this;
19319
19320 return new Promise(function(resolve, reject) {
19321 if (!definitions) {
19322 var err1 = new Error('no XML imported');
19323
19324 return reject(addWarningsToError(err1, []));
19325 }
19326
19327 if (typeof bpmnDiagramOrId === 'string') {
19328 bpmnDiagram = findBPMNDiagram(definitions, bpmnDiagramOrId);
19329
19330 if (!bpmnDiagram) {
19331 var err2 = new Error('BPMNDiagram <' + bpmnDiagramOrId + '> not found');
19332
19333 return reject(addWarningsToError(err2, []));
19334 }
19335 }
19336
19337 // clear existing rendered diagram
19338 // catch synchronous exceptions during #clear()
19339 try {
19340 self.clear();
19341 } catch (error) {
19342
19343 return reject(addWarningsToError(error, []));
19344 }
19345
19346 // perform graphical import
19347 importBpmnDiagram(self, definitions, bpmnDiagram).then(function(result) {
19348
19349 var warnings = result.warnings;
19350
19351 return resolve({ warnings: warnings });
19352 }).catch(function(err) {
19353
19354 return reject(err);
19355 });
19356 });
19357 });
19358
19359 /**
19360 * The saveXML result.
19361 *
19362 * @typedef {Object} SaveXMLResult
19363 *
19364 * @property {string} xml
19365 */
19366
19367 /**
19368 * Export the currently displayed BPMN 2.0 diagram as
19369 * a BPMN 2.0 XML document.
19370 *
19371 * ## Life-Cycle Events
19372 *
19373 * During XML saving the viewer will fire life-cycle events:
19374 *
19375 * * saveXML.start (before serialization)
19376 * * saveXML.serialized (after xml generation)
19377 * * saveXML.done (everything done)
19378 *
19379 * You can use these events to hook into the life-cycle.
19380 *
19381 * @param {Object} [options] export options
19382 * @param {boolean} [options.format=false] output formatted XML
19383 * @param {boolean} [options.preamble=true] output preamble
19384 *
19385 * Returns {Promise<SaveXMLResult, Error>}
19386 */
19387 BaseViewer.prototype.saveXML = wrapForCompatibility(function saveXML(options) {
19388
19389 options = options || {};
19390
19391 var self = this;
19392
19393 var definitions = this._definitions;
19394
19395 return new Promise(function(resolve) {
19396
19397 if (!definitions) {
19398 return resolve({
19399 error: new Error('no definitions loaded')
19400 });
19401 }
19402
19403 // allow to fiddle around with definitions
19404 definitions = self._emit('saveXML.start', {
19405 definitions: definitions
19406 }) || definitions;
19407
19408 self._moddle.toXML(definitions, options).then(function(result) {
19409
19410 var xml = result.xml;
19411
19412 xml = self._emit('saveXML.serialized', {
19413 xml: xml
19414 }) || xml;
19415
19416 return resolve({
19417 xml: xml
19418 });
19419 });
19420 }).catch(function(error) {
19421 return { error: error };
19422 }).then(function(result) {
19423
19424 self._emit('saveXML.done', result);
19425
19426 var error = result.error;
19427
19428 if (error) {
19429 return Promise.reject(error);
19430 }
19431
19432 return result;
19433 });
19434 });
19435
19436 /**
19437 * The saveSVG result.
19438 *
19439 * @typedef {Object} SaveSVGResult
19440 *
19441 * @property {string} svg
19442 */
19443
19444 /**
19445 * Export the currently displayed BPMN 2.0 diagram as
19446 * an SVG image.
19447 *
19448 * ## Life-Cycle Events
19449 *
19450 * During SVG saving the viewer will fire life-cycle events:
19451 *
19452 * * saveSVG.start (before serialization)
19453 * * saveSVG.done (everything done)
19454 *
19455 * You can use these events to hook into the life-cycle.
19456 *
19457 * @param {Object} [options]
19458 *
19459 * Returns {Promise<SaveSVGResult, Error>}
19460 */
19461 BaseViewer.prototype.saveSVG = wrapForCompatibility(function saveSVG(options) {
19462
19463 var self = this;
19464
19465 return new Promise(function(resolve, reject) {
19466
19467 self._emit('saveSVG.start');
19468
19469 var svg, err;
19470
19471 try {
19472 var canvas = self.get('canvas');
19473
19474 var contentNode = canvas.getDefaultLayer(),
19475 defsNode = query('defs', canvas._svg);
19476
19477 var contents = innerSVG(contentNode),
19478 defs = defsNode ? '<defs>' + innerSVG(defsNode) + '</defs>' : '';
19479
19480 var bbox = contentNode.getBBox();
19481
19482 svg =
19483 '<?xml version="1.0" encoding="utf-8"?>\n' +
19484 '<!-- created with bpmn-js / http://bpmn.io -->\n' +
19485 '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
19486 '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
19487 'width="' + bbox.width + '" height="' + bbox.height + '" ' +
19488 'viewBox="' + bbox.x + ' ' + bbox.y + ' ' + bbox.width + ' ' + bbox.height + '" version="1.1">' +
19489 defs + contents +
19490 '</svg>';
19491 } catch (e) {
19492 err = e;
19493 }
19494
19495 self._emit('saveSVG.done', {
19496 error: err,
19497 svg: svg
19498 });
19499
19500 if (!err) {
19501 return resolve({ svg: svg });
19502 }
19503
19504 return reject(err);
19505 });
19506 });
19507
19508 /**
19509 * Get a named diagram service.
19510 *
19511 * @example
19512 *
19513 * var elementRegistry = viewer.get('elementRegistry');
19514 * var startEventShape = elementRegistry.get('StartEvent_1');
19515 *
19516 * @param {string} name
19517 *
19518 * @return {Object} diagram service instance
19519 *
19520 * @method BaseViewer#get
19521 */
19522
19523 /**
19524 * Invoke a function in the context of this viewer.
19525 *
19526 * @example
19527 *
19528 * viewer.invoke(function(elementRegistry) {
19529 * var startEventShape = elementRegistry.get('StartEvent_1');
19530 * });
19531 *
19532 * @param {Function} fn to be invoked
19533 *
19534 * @return {Object} the functions return value
19535 *
19536 * @method BaseViewer#invoke
19537 */
19538
19539
19540 BaseViewer.prototype._setDefinitions = function(definitions) {
19541 this._definitions = definitions;
19542 };
19543
19544 BaseViewer.prototype.getModules = function() {
19545 return this._modules;
19546 };
19547
19548 /**
19549 * Remove all drawn elements from the viewer.
19550 *
19551 * After calling this method the viewer can still
19552 * be reused for opening another diagram.
19553 *
19554 * @method BaseViewer#clear
19555 */
19556 BaseViewer.prototype.clear = function() {
19557 if (!this.getDefinitions()) {
19558
19559 // no diagram to clear
19560 return;
19561 }
19562
19563 // remove businessObject#di binding
19564 //
19565 // this is necessary, as we establish the bindings
19566 // in the BpmnTreeWalker (and assume none are given
19567 // on reimport)
19568 this.get('elementRegistry').forEach(function(element) {
19569 var bo = element.businessObject;
19570
19571 if (bo && bo.di) {
19572 delete bo.di;
19573 }
19574 });
19575
19576 // remove drawn elements
19577 Diagram.prototype.clear.call(this);
19578 };
19579
19580 /**
19581 * Destroy the viewer instance and remove all its
19582 * remainders from the document tree.
19583 */
19584 BaseViewer.prototype.destroy = function() {
19585
19586 // diagram destroy
19587 Diagram.prototype.destroy.call(this);
19588
19589 // dom detach
19590 remove$1(this._container);
19591 };
19592
19593 /**
19594 * Register an event listener
19595 *
19596 * Remove a previously added listener via {@link #off(event, callback)}.
19597 *
19598 * @param {string} event
19599 * @param {number} [priority]
19600 * @param {Function} callback
19601 * @param {Object} [that]
19602 */
19603 BaseViewer.prototype.on = function(event, priority, callback, target) {
19604 return this.get('eventBus').on(event, priority, callback, target);
19605 };
19606
19607 /**
19608 * De-register an event listener
19609 *
19610 * @param {string} event
19611 * @param {Function} callback
19612 */
19613 BaseViewer.prototype.off = function(event, callback) {
19614 this.get('eventBus').off(event, callback);
19615 };
19616
19617 BaseViewer.prototype.attachTo = function(parentNode) {
19618
19619 if (!parentNode) {
19620 throw new Error('parentNode required');
19621 }
19622
19623 // ensure we detach from the
19624 // previous, old parent
19625 this.detach();
19626
19627 // unwrap jQuery if provided
19628 if (parentNode.get && parentNode.constructor.prototype.jquery) {
19629 parentNode = parentNode.get(0);
19630 }
19631
19632 if (typeof parentNode === 'string') {
19633 parentNode = query(parentNode);
19634 }
19635
19636 parentNode.appendChild(this._container);
19637
19638 this._emit('attach', {});
19639
19640 this.get('canvas').resized();
19641 };
19642
19643 BaseViewer.prototype.getDefinitions = function() {
19644 return this._definitions;
19645 };
19646
19647 BaseViewer.prototype.detach = function() {
19648
19649 var container = this._container,
19650 parentNode = container.parentNode;
19651
19652 if (!parentNode) {
19653 return;
19654 }
19655
19656 this._emit('detach', {});
19657
19658 parentNode.removeChild(container);
19659 };
19660
19661 BaseViewer.prototype._init = function(container, moddle, options) {
19662
19663 var baseModules = options.modules || this.getModules(),
19664 additionalModules = options.additionalModules || [],
19665 staticModules = [
19666 {
19667 bpmnjs: [ 'value', this ],
19668 moddle: [ 'value', moddle ]
19669 }
19670 ];
19671
19672 var diagramModules = [].concat(staticModules, baseModules, additionalModules);
19673
19674 var diagramOptions = assign(omit(options, [ 'additionalModules' ]), {
19675 canvas: assign({}, options.canvas, { container: container }),
19676 modules: diagramModules
19677 });
19678
19679 // invoke diagram constructor
19680 Diagram.call(this, diagramOptions);
19681
19682 if (options && options.container) {
19683 this.attachTo(options.container);
19684 }
19685 };
19686
19687 /**
19688 * Emit an event on the underlying {@link EventBus}
19689 *
19690 * @param {string} type
19691 * @param {Object} event
19692 *
19693 * @return {Object} event processing result (if any)
19694 */
19695 BaseViewer.prototype._emit = function(type, event) {
19696 return this.get('eventBus').fire(type, event);
19697 };
19698
19699 BaseViewer.prototype._createContainer = function(options) {
19700
19701 var container = domify('<div class="bjs-container"></div>');
19702
19703 assign(container.style, {
19704 width: ensureUnit(options.width),
19705 height: ensureUnit(options.height),
19706 position: options.position
19707 });
19708
19709 return container;
19710 };
19711
19712 BaseViewer.prototype._createModdle = function(options) {
19713 var moddleOptions = assign({}, this._moddleExtensions, options.moddleExtensions);
19714
19715 return new simple(moddleOptions);
19716 };
19717
19718 BaseViewer.prototype._modules = [];
19719
19720 // helpers ///////////////
19721
19722 function addWarningsToError(err, warningsAry) {
19723 err.warnings = warningsAry;
19724 return err;
19725 }
19726
19727 function checkValidationError(err) {
19728
19729 // check if we can help the user by indicating wrong BPMN 2.0 xml
19730 // (in case he or the exporting tool did not get that right)
19731
19732 var pattern = /unparsable content <([^>]+)> detected([\s\S]*)$/;
19733 var match = pattern.exec(err.message);
19734
19735 if (match) {
19736 err.message =
19737 'unparsable content <' + match[1] + '> detected; ' +
19738 'this may indicate an invalid BPMN 2.0 diagram file' + match[2];
19739 }
19740
19741 return err;
19742 }
19743
19744 var DEFAULT_OPTIONS = {
19745 width: '100%',
19746 height: '100%',
19747 position: 'relative'
19748 };
19749
19750
19751 /**
19752 * Ensure the passed argument is a proper unit (defaulting to px)
19753 */
19754 function ensureUnit(val) {
19755 return val + (isNumber(val) ? 'px' : '');
19756 }
19757
19758
19759 /**
19760 * Find BPMNDiagram in definitions by ID
19761 *
19762 * @param {ModdleElement<Definitions>} definitions
19763 * @param {string} diagramId
19764 *
19765 * @return {ModdleElement<BPMNDiagram>|null}
19766 */
19767 function findBPMNDiagram(definitions, diagramId) {
19768 if (!diagramId) {
19769 return null;
19770 }
19771
19772 return find(definitions.diagrams, function(element) {
19773 return element.id === diagramId;
19774 }) || null;
19775 }
19776
19777 /**
19778 * Adds the project logo to the diagram container as
19779 * required by the bpmn.io license.
19780 *
19781 * @see http://bpmn.io/license
19782 *
19783 * @param {Element} container
19784 */
19785 function addProjectLogo(container) {
19786 var img = BPMNIO_IMG;
19787
19788 var linkMarkup =
19789 '<a href="http://bpmn.io" ' +
19790 'target="_blank" ' +
19791 'class="bjs-powered-by" ' +
19792 'title="Powered by bpmn.io" ' +
19793 'style="position: absolute; bottom: 15px; right: 15px; z-index: 100; ' + LINK_STYLES + '">' +
19794 img +
19795 '</a>';
19796
19797 var linkElement = domify(linkMarkup);
19798
19799 container.appendChild(linkElement);
19800
19801 componentEvent.bind(linkElement, 'click', function(event) {
19802 open();
19803
19804 event.preventDefault();
19805 });
19806 }
19807
19808 /* </project-logo> */
19809
19810 /**
19811 * A viewer for BPMN 2.0 diagrams.
19812 *
19813 * Have a look at {@link NavigatedViewer} or {@link Modeler} for bundles that include
19814 * additional features.
19815 *
19816 *
19817 * ## Extending the Viewer
19818 *
19819 * In order to extend the viewer pass extension modules to bootstrap via the
19820 * `additionalModules` option. An extension module is an object that exposes
19821 * named services.
19822 *
19823 * The following example depicts the integration of a simple
19824 * logging component that integrates with interaction events:
19825 *
19826 *
19827 * ```javascript
19828 *
19829 * // logging component
19830 * function InteractionLogger(eventBus) {
19831 * eventBus.on('element.hover', function(event) {
19832 * console.log()
19833 * })
19834 * }
19835 *
19836 * InteractionLogger.$inject = [ 'eventBus' ]; // minification save
19837 *
19838 * // extension module
19839 * var extensionModule = {
19840 * __init__: [ 'interactionLogger' ],
19841 * interactionLogger: [ 'type', InteractionLogger ]
19842 * };
19843 *
19844 * // extend the viewer
19845 * var bpmnViewer = new Viewer({ additionalModules: [ extensionModule ] });
19846 * bpmnViewer.importXML(...);
19847 * ```
19848 *
19849 * @param {Object} [options] configuration options to pass to the viewer
19850 * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
19851 * @param {string|number} [options.width] the width of the viewer
19852 * @param {string|number} [options.height] the height of the viewer
19853 * @param {Object} [options.moddleExtensions] extension packages to provide
19854 * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
19855 * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
19856 */
19857 function Viewer(options) {
19858 BaseViewer.call(this, options);
19859 }
19860
19861 inherits$1(Viewer, BaseViewer);
19862
19863 // modules the viewer is composed of
19864 Viewer.prototype._modules = [
19865 CoreModule$1,
19866 TranslateModule,
19867 SelectionModule,
19868 OverlaysModule
19869 ];
19870
19871 // default moddle extensions the viewer is composed of
19872 Viewer.prototype._moddleExtensions = {};
19873
19874 return Viewer;
19875
19876})));