UNPKG

455 kBJavaScriptView Raw
1/*!
2 * bpmn-js - bpmn-navigated-viewer v6.1.0
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: 2019-12-16
12 */
13(function (global, factory) {
14 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
15 typeof define === 'function' && define.amd ? define(factory) :
16 (global = global || self, global.BpmnJS = factory());
17}(this, function () { 'use strict';
18
19 function createCommonjsModule(fn, module) {
20 return module = { exports: {} }, fn(module, module.exports), module.exports;
21 }
22
23 var inherits_browser = createCommonjsModule(function (module) {
24 if (typeof Object.create === 'function') {
25 // implementation from standard node.js 'util' module
26 module.exports = function inherits(ctor, superCtor) {
27 ctor.super_ = superCtor;
28 ctor.prototype = Object.create(superCtor.prototype, {
29 constructor: {
30 value: ctor,
31 enumerable: false,
32 writable: true,
33 configurable: true
34 }
35 });
36 };
37 } else {
38 // old school shim for old browsers
39 module.exports = function inherits(ctor, superCtor) {
40 ctor.super_ = superCtor;
41 var TempCtor = function () {};
42 TempCtor.prototype = superCtor.prototype;
43 ctor.prototype = new TempCtor();
44 ctor.prototype.constructor = ctor;
45 };
46 }
47 });
48
49 /**
50 * Flatten array, one level deep.
51 *
52 * @param {Array<?>} arr
53 *
54 * @return {Array<?>}
55 */
56
57 var nativeToString = Object.prototype.toString;
58 var nativeHasOwnProperty = Object.prototype.hasOwnProperty;
59 function isUndefined(obj) {
60 return obj === undefined;
61 }
62 function isDefined(obj) {
63 return obj !== undefined;
64 }
65 function isArray(obj) {
66 return nativeToString.call(obj) === '[object Array]';
67 }
68 function isObject(obj) {
69 return nativeToString.call(obj) === '[object Object]';
70 }
71 function isNumber(obj) {
72 return nativeToString.call(obj) === '[object Number]';
73 }
74 function isFunction(obj) {
75 var tag = nativeToString.call(obj);
76 return tag === '[object Function]' || tag === '[object AsyncFunction]' || tag === '[object GeneratorFunction]' || tag === '[object AsyncGeneratorFunction]' || tag === '[object Proxy]';
77 }
78 function isString(obj) {
79 return nativeToString.call(obj) === '[object String]';
80 }
81 /**
82 * Return true, if target owns a property with the given key.
83 *
84 * @param {Object} target
85 * @param {String} key
86 *
87 * @return {Boolean}
88 */
89
90 function has(target, key) {
91 return nativeHasOwnProperty.call(target, key);
92 }
93
94 /**
95 * Find element in collection.
96 *
97 * @param {Array|Object} collection
98 * @param {Function|Object} matcher
99 *
100 * @return {Object}
101 */
102
103 function find(collection, matcher) {
104 matcher = toMatcher(matcher);
105 var match;
106 forEach(collection, function (val, key) {
107 if (matcher(val, key)) {
108 match = val;
109 return false;
110 }
111 });
112 return match;
113 }
114 /**
115 * Find element in collection.
116 *
117 * @param {Array|Object} collection
118 * @param {Function} matcher
119 *
120 * @return {Array} result
121 */
122
123 function filter(collection, matcher) {
124 var result = [];
125 forEach(collection, function (val, key) {
126 if (matcher(val, key)) {
127 result.push(val);
128 }
129 });
130 return result;
131 }
132 /**
133 * Iterate over collection; returning something
134 * (non-undefined) will stop iteration.
135 *
136 * @param {Array|Object} collection
137 * @param {Function} iterator
138 *
139 * @return {Object} return result that stopped the iteration
140 */
141
142 function forEach(collection, iterator) {
143 var val, result;
144
145 if (isUndefined(collection)) {
146 return;
147 }
148
149 var convertKey = isArray(collection) ? toNum : identity;
150
151 for (var key in collection) {
152 if (has(collection, key)) {
153 val = collection[key];
154 result = iterator(val, convertKey(key));
155
156 if (result === false) {
157 return val;
158 }
159 }
160 }
161 }
162 /**
163 * Reduce collection, returning a single result.
164 *
165 * @param {Object|Array} collection
166 * @param {Function} iterator
167 * @param {Any} result
168 *
169 * @return {Any} result returned from last iterator
170 */
171
172 function reduce(collection, iterator, result) {
173 forEach(collection, function (value, idx) {
174 result = iterator(result, value, idx);
175 });
176 return result;
177 }
178 /**
179 * Return true if every element in the collection
180 * matches the criteria.
181 *
182 * @param {Object|Array} collection
183 * @param {Function} matcher
184 *
185 * @return {Boolean}
186 */
187
188 function every(collection, matcher) {
189 return !!reduce(collection, function (matches, val, key) {
190 return matches && matcher(val, key);
191 }, true);
192 }
193 /**
194 * Return true if some elements in the collection
195 * match the criteria.
196 *
197 * @param {Object|Array} collection
198 * @param {Function} matcher
199 *
200 * @return {Boolean}
201 */
202
203 function some(collection, matcher) {
204 return !!find(collection, matcher);
205 }
206 /**
207 * Transform a collection into another collection
208 * by piping each member through the given fn.
209 *
210 * @param {Object|Array} collection
211 * @param {Function} fn
212 *
213 * @return {Array} transformed collection
214 */
215
216 function map(collection, fn) {
217 var result = [];
218 forEach(collection, function (val, key) {
219 result.push(fn(val, key));
220 });
221 return result;
222 }
223 /**
224 * Create an object pattern matcher.
225 *
226 * @example
227 *
228 * const matcher = matchPattern({ id: 1 });
229 *
230 * var element = find(elements, matcher);
231 *
232 * @param {Object} pattern
233 *
234 * @return {Function} matcherFn
235 */
236
237 function matchPattern(pattern) {
238 return function (el) {
239 return every(pattern, function (val, key) {
240 return el[key] === val;
241 });
242 };
243 }
244
245 function toMatcher(matcher) {
246 return isFunction(matcher) ? matcher : function (e) {
247 return e === matcher;
248 };
249 }
250
251 function identity(arg) {
252 return arg;
253 }
254
255 function toNum(arg) {
256 return Number(arg);
257 }
258
259 /**
260 * Debounce fn, calling it only once if
261 * the given time elapsed between calls.
262 *
263 * @param {Function} fn
264 * @param {Number} timeout
265 *
266 * @return {Function} debounced function
267 */
268 function debounce(fn, timeout) {
269 var timer;
270 var lastArgs;
271 var lastThis;
272 var lastNow;
273
274 function fire() {
275 var now = Date.now();
276 var scheduledDiff = lastNow + timeout - now;
277
278 if (scheduledDiff > 0) {
279 return schedule(scheduledDiff);
280 }
281
282 fn.apply(lastThis, lastArgs);
283 timer = lastNow = lastArgs = lastThis = undefined;
284 }
285
286 function schedule(timeout) {
287 timer = setTimeout(fire, timeout);
288 }
289
290 return function () {
291 lastNow = Date.now();
292
293 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
294 args[_key] = arguments[_key];
295 }
296
297 lastArgs = args;
298 lastThis = this; // ensure an execution is scheduled
299
300 if (!timer) {
301 schedule(timeout);
302 }
303 };
304 }
305 /**
306 * Bind function against target <this>.
307 *
308 * @param {Function} fn
309 * @param {Object} target
310 *
311 * @return {Function} bound function
312 */
313
314 function bind(fn, target) {
315 return fn.bind(target);
316 }
317
318 function _extends() {
319 _extends = Object.assign || function (target) {
320 for (var i = 1; i < arguments.length; i++) {
321 var source = arguments[i];
322
323 for (var key in source) {
324 if (Object.prototype.hasOwnProperty.call(source, key)) {
325 target[key] = source[key];
326 }
327 }
328 }
329
330 return target;
331 };
332
333 return _extends.apply(this, arguments);
334 }
335
336 /**
337 * Convenience wrapper for `Object.assign`.
338 *
339 * @param {Object} target
340 * @param {...Object} others
341 *
342 * @return {Object} the target
343 */
344
345 function assign(target) {
346 for (var _len = arguments.length, others = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
347 others[_key - 1] = arguments[_key];
348 }
349
350 return _extends.apply(void 0, [target].concat(others));
351 }
352 /**
353 * Pick given properties from the target object.
354 *
355 * @param {Object} target
356 * @param {Array} properties
357 *
358 * @return {Object} target
359 */
360
361 function pick(target, properties) {
362 var result = {};
363 var obj = Object(target);
364 forEach(properties, function (prop) {
365 if (prop in obj) {
366 result[prop] = target[prop];
367 }
368 });
369 return result;
370 }
371 /**
372 * Pick all target properties, excluding the given ones.
373 *
374 * @param {Object} target
375 * @param {Array} properties
376 *
377 * @return {Object} target
378 */
379
380 function omit(target, properties) {
381 var result = {};
382 var obj = Object(target);
383 forEach(obj, function (prop, key) {
384 if (properties.indexOf(key) === -1) {
385 result[key] = prop;
386 }
387 });
388 return result;
389 }
390
391 var DEFAULT_RENDER_PRIORITY = 1000;
392
393 /**
394 * The base implementation of shape and connection renderers.
395 *
396 * @param {EventBus} eventBus
397 * @param {Number} [renderPriority=1000]
398 */
399 function BaseRenderer(eventBus, renderPriority) {
400 var self = this;
401
402 renderPriority = renderPriority || DEFAULT_RENDER_PRIORITY;
403
404 eventBus.on([ 'render.shape', 'render.connection' ], renderPriority, function(evt, context) {
405 var type = evt.type,
406 element = context.element,
407 visuals = context.gfx;
408
409 if (self.canRender(element)) {
410 if (type === 'render.shape') {
411 return self.drawShape(visuals, element);
412 } else {
413 return self.drawConnection(visuals, element);
414 }
415 }
416 });
417
418 eventBus.on([ 'render.getShapePath', 'render.getConnectionPath'], renderPriority, function(evt, element) {
419 if (self.canRender(element)) {
420 if (evt.type === 'render.getShapePath') {
421 return self.getShapePath(element);
422 } else {
423 return self.getConnectionPath(element);
424 }
425 }
426 });
427 }
428
429 /**
430 * Should check whether *this* renderer can render
431 * the element/connection.
432 *
433 * @param {element} element
434 *
435 * @returns {Boolean}
436 */
437 BaseRenderer.prototype.canRender = function() {};
438
439 /**
440 * Provides the shape's snap svg element to be drawn on the `canvas`.
441 *
442 * @param {djs.Graphics} visuals
443 * @param {Shape} shape
444 *
445 * @returns {Snap.svg} [returns a Snap.svg paper element ]
446 */
447 BaseRenderer.prototype.drawShape = function() {};
448
449 /**
450 * Provides the shape's snap svg element to be drawn on the `canvas`.
451 *
452 * @param {djs.Graphics} visuals
453 * @param {Connection} connection
454 *
455 * @returns {Snap.svg} [returns a Snap.svg paper element ]
456 */
457 BaseRenderer.prototype.drawConnection = function() {};
458
459 /**
460 * Gets the SVG path of a shape that represents it's visual bounds.
461 *
462 * @param {Shape} shape
463 *
464 * @return {string} svg path
465 */
466 BaseRenderer.prototype.getShapePath = function() {};
467
468 /**
469 * Gets the SVG path of a connection that represents it's visual bounds.
470 *
471 * @param {Connection} connection
472 *
473 * @return {string} svg path
474 */
475 BaseRenderer.prototype.getConnectionPath = function() {};
476
477 /**
478 * Is an element of the given BPMN type?
479 *
480 * @param {djs.model.Base|ModdleElement} element
481 * @param {String} type
482 *
483 * @return {Boolean}
484 */
485 function is(element, type) {
486 var bo = getBusinessObject(element);
487
488 return bo && (typeof bo.$instanceOf === 'function') && bo.$instanceOf(type);
489 }
490
491
492 /**
493 * Return the business object for a given element.
494 *
495 * @param {djs.model.Base|ModdleElement} element
496 *
497 * @return {ModdleElement}
498 */
499 function getBusinessObject(element) {
500 return (element && element.businessObject) || element;
501 }
502
503 function isExpanded(element) {
504
505 if (is(element, 'bpmn:CallActivity')) {
506 return false;
507 }
508
509 if (is(element, 'bpmn:SubProcess')) {
510 return !!getBusinessObject(element).di.isExpanded;
511 }
512
513 if (is(element, 'bpmn:Participant')) {
514 return !!getBusinessObject(element).processRef;
515 }
516
517 return true;
518 }
519
520 function isEventSubProcess(element) {
521 return element && !!getBusinessObject(element).triggeredByEvent;
522 }
523
524 function getLabelAttr(semantic) {
525 if (
526 is(semantic, 'bpmn:FlowElement') ||
527 is(semantic, 'bpmn:Participant') ||
528 is(semantic, 'bpmn:Lane') ||
529 is(semantic, 'bpmn:SequenceFlow') ||
530 is(semantic, 'bpmn:MessageFlow') ||
531 is(semantic, 'bpmn:DataInput') ||
532 is(semantic, 'bpmn:DataOutput')
533 ) {
534 return 'name';
535 }
536
537 if (is(semantic, 'bpmn:TextAnnotation')) {
538 return 'text';
539 }
540
541 if (is(semantic, 'bpmn:Group')) {
542 return 'categoryValueRef';
543 }
544 }
545
546 function getCategoryValue(semantic) {
547 var categoryValueRef = semantic['categoryValueRef'];
548
549 if (!categoryValueRef) {
550 return '';
551 }
552
553
554 return categoryValueRef.value || '';
555 }
556
557 function getLabel(element) {
558 var semantic = element.businessObject,
559 attr = getLabelAttr(semantic);
560
561 if (attr) {
562
563 if (attr === 'categoryValueRef') {
564
565 return getCategoryValue(semantic);
566 }
567
568 return semantic[attr] || '';
569 }
570 }
571
572 function ensureImported(element, target) {
573
574 if (element.ownerDocument !== target.ownerDocument) {
575 try {
576 // may fail on webkit
577 return target.ownerDocument.importNode(element, true);
578 } catch (e) {
579 // ignore
580 }
581 }
582
583 return element;
584 }
585
586 /**
587 * appendTo utility
588 */
589
590 /**
591 * Append a node to a target element and return the appended node.
592 *
593 * @param {SVGElement} element
594 * @param {SVGElement} target
595 *
596 * @return {SVGElement} the appended node
597 */
598 function appendTo(element, target) {
599 return target.appendChild(ensureImported(element, target));
600 }
601
602 /**
603 * append utility
604 */
605
606 /**
607 * Append a node to an element
608 *
609 * @param {SVGElement} element
610 * @param {SVGElement} node
611 *
612 * @return {SVGElement} the element
613 */
614 function append(target, node) {
615 appendTo(node, target);
616 return target;
617 }
618
619 /**
620 * attribute accessor utility
621 */
622
623 var LENGTH_ATTR = 2;
624
625 var CSS_PROPERTIES = {
626 'alignment-baseline': 1,
627 'baseline-shift': 1,
628 'clip': 1,
629 'clip-path': 1,
630 'clip-rule': 1,
631 'color': 1,
632 'color-interpolation': 1,
633 'color-interpolation-filters': 1,
634 'color-profile': 1,
635 'color-rendering': 1,
636 'cursor': 1,
637 'direction': 1,
638 'display': 1,
639 'dominant-baseline': 1,
640 'enable-background': 1,
641 'fill': 1,
642 'fill-opacity': 1,
643 'fill-rule': 1,
644 'filter': 1,
645 'flood-color': 1,
646 'flood-opacity': 1,
647 'font': 1,
648 'font-family': 1,
649 'font-size': LENGTH_ATTR,
650 'font-size-adjust': 1,
651 'font-stretch': 1,
652 'font-style': 1,
653 'font-variant': 1,
654 'font-weight': 1,
655 'glyph-orientation-horizontal': 1,
656 'glyph-orientation-vertical': 1,
657 'image-rendering': 1,
658 'kerning': 1,
659 'letter-spacing': 1,
660 'lighting-color': 1,
661 'marker': 1,
662 'marker-end': 1,
663 'marker-mid': 1,
664 'marker-start': 1,
665 'mask': 1,
666 'opacity': 1,
667 'overflow': 1,
668 'pointer-events': 1,
669 'shape-rendering': 1,
670 'stop-color': 1,
671 'stop-opacity': 1,
672 'stroke': 1,
673 'stroke-dasharray': 1,
674 'stroke-dashoffset': 1,
675 'stroke-linecap': 1,
676 'stroke-linejoin': 1,
677 'stroke-miterlimit': 1,
678 'stroke-opacity': 1,
679 'stroke-width': LENGTH_ATTR,
680 'text-anchor': 1,
681 'text-decoration': 1,
682 'text-rendering': 1,
683 'unicode-bidi': 1,
684 'visibility': 1,
685 'word-spacing': 1,
686 'writing-mode': 1
687 };
688
689
690 function getAttribute(node, name) {
691 if (CSS_PROPERTIES[name]) {
692 return node.style[name];
693 } else {
694 return node.getAttributeNS(null, name);
695 }
696 }
697
698 function setAttribute(node, name, value) {
699 var hyphenated = name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
700
701 var type = CSS_PROPERTIES[hyphenated];
702
703 if (type) {
704 // append pixel unit, unless present
705 if (type === LENGTH_ATTR && typeof value === 'number') {
706 value = String(value) + 'px';
707 }
708
709 node.style[hyphenated] = value;
710 } else {
711 node.setAttributeNS(null, name, value);
712 }
713 }
714
715 function setAttributes(node, attrs) {
716
717 var names = Object.keys(attrs), i, name;
718
719 for (i = 0, name; (name = names[i]); i++) {
720 setAttribute(node, name, attrs[name]);
721 }
722 }
723
724 /**
725 * Gets or sets raw attributes on a node.
726 *
727 * @param {SVGElement} node
728 * @param {Object} [attrs]
729 * @param {String} [name]
730 * @param {String} [value]
731 *
732 * @return {String}
733 */
734 function attr(node, name, value) {
735 if (typeof name === 'string') {
736 if (value !== undefined) {
737 setAttribute(node, name, value);
738 } else {
739 return getAttribute(node, name);
740 }
741 } else {
742 setAttributes(node, name);
743 }
744
745 return node;
746 }
747
748 /**
749 * Clear utility
750 */
751 function index(arr, obj) {
752 if (arr.indexOf) {
753 return arr.indexOf(obj);
754 }
755
756
757 for (var i = 0; i < arr.length; ++i) {
758 if (arr[i] === obj) {
759 return i;
760 }
761 }
762
763 return -1;
764 }
765
766 var re = /\s+/;
767
768 var toString = Object.prototype.toString;
769
770 function defined(o) {
771 return typeof o !== 'undefined';
772 }
773
774 /**
775 * Wrap `el` in a `ClassList`.
776 *
777 * @param {Element} el
778 * @return {ClassList}
779 * @api public
780 */
781
782 function classes(el) {
783 return new ClassList(el);
784 }
785
786 function ClassList(el) {
787 if (!el || !el.nodeType) {
788 throw new Error('A DOM element reference is required');
789 }
790 this.el = el;
791 this.list = el.classList;
792 }
793
794 /**
795 * Add class `name` if not already present.
796 *
797 * @param {String} name
798 * @return {ClassList}
799 * @api public
800 */
801
802 ClassList.prototype.add = function(name) {
803
804 // classList
805 if (this.list) {
806 this.list.add(name);
807 return this;
808 }
809
810 // fallback
811 var arr = this.array();
812 var i = index(arr, name);
813 if (!~i) {
814 arr.push(name);
815 }
816
817 if (defined(this.el.className.baseVal)) {
818 this.el.className.baseVal = arr.join(' ');
819 } else {
820 this.el.className = arr.join(' ');
821 }
822
823 return this;
824 };
825
826 /**
827 * Remove class `name` when present, or
828 * pass a regular expression to remove
829 * any which match.
830 *
831 * @param {String|RegExp} name
832 * @return {ClassList}
833 * @api public
834 */
835
836 ClassList.prototype.remove = function(name) {
837 if ('[object RegExp]' === toString.call(name)) {
838 return this.removeMatching(name);
839 }
840
841 // classList
842 if (this.list) {
843 this.list.remove(name);
844 return this;
845 }
846
847 // fallback
848 var arr = this.array();
849 var i = index(arr, name);
850 if (~i) {
851 arr.splice(i, 1);
852 }
853 this.el.className.baseVal = arr.join(' ');
854 return this;
855 };
856
857 /**
858 * Remove all classes matching `re`.
859 *
860 * @param {RegExp} re
861 * @return {ClassList}
862 * @api private
863 */
864
865 ClassList.prototype.removeMatching = function(re) {
866 var arr = this.array();
867 for (var i = 0; i < arr.length; i++) {
868 if (re.test(arr[i])) {
869 this.remove(arr[i]);
870 }
871 }
872 return this;
873 };
874
875 /**
876 * Toggle class `name`, can force state via `force`.
877 *
878 * For browsers that support classList, but do not support `force` yet,
879 * the mistake will be detected and corrected.
880 *
881 * @param {String} name
882 * @param {Boolean} force
883 * @return {ClassList}
884 * @api public
885 */
886
887 ClassList.prototype.toggle = function(name, force) {
888 // classList
889 if (this.list) {
890 if (defined(force)) {
891 if (force !== this.list.toggle(name, force)) {
892 this.list.toggle(name); // toggle again to correct
893 }
894 } else {
895 this.list.toggle(name);
896 }
897 return this;
898 }
899
900 // fallback
901 if (defined(force)) {
902 if (!force) {
903 this.remove(name);
904 } else {
905 this.add(name);
906 }
907 } else {
908 if (this.has(name)) {
909 this.remove(name);
910 } else {
911 this.add(name);
912 }
913 }
914
915 return this;
916 };
917
918 /**
919 * Return an array of classes.
920 *
921 * @return {Array}
922 * @api public
923 */
924
925 ClassList.prototype.array = function() {
926 var className = this.el.getAttribute('class') || '';
927 var str = className.replace(/^\s+|\s+$/g, '');
928 var arr = str.split(re);
929 if ('' === arr[0]) {
930 arr.shift();
931 }
932 return arr;
933 };
934
935 /**
936 * Check if class `name` is present.
937 *
938 * @param {String} name
939 * @return {ClassList}
940 * @api public
941 */
942
943 ClassList.prototype.has =
944 ClassList.prototype.contains = function(name) {
945 return (
946 this.list ?
947 this.list.contains(name) :
948 !! ~index(this.array(), name)
949 );
950 };
951
952 function remove(element) {
953 var parent = element.parentNode;
954
955 if (parent) {
956 parent.removeChild(element);
957 }
958
959 return element;
960 }
961
962 /**
963 * Clear utility
964 */
965
966 /**
967 * Removes all children from the given element
968 *
969 * @param {DOMElement} element
970 * @return {DOMElement} the element (for chaining)
971 */
972 function clear(element) {
973 var child;
974
975 while ((child = element.firstChild)) {
976 remove(child);
977 }
978
979 return element;
980 }
981
982 var ns = {
983 svg: 'http://www.w3.org/2000/svg'
984 };
985
986 /**
987 * DOM parsing utility
988 */
989
990 var SVG_START = '<svg xmlns="' + ns.svg + '"';
991
992 function parse(svg) {
993
994 var unwrap = false;
995
996 // ensure we import a valid svg document
997 if (svg.substring(0, 4) === '<svg') {
998 if (svg.indexOf(ns.svg) === -1) {
999 svg = SVG_START + svg.substring(4);
1000 }
1001 } else {
1002 // namespace svg
1003 svg = SVG_START + '>' + svg + '</svg>';
1004 unwrap = true;
1005 }
1006
1007 var parsed = parseDocument(svg);
1008
1009 if (!unwrap) {
1010 return parsed;
1011 }
1012
1013 var fragment = document.createDocumentFragment();
1014
1015 var parent = parsed.firstChild;
1016
1017 while (parent.firstChild) {
1018 fragment.appendChild(parent.firstChild);
1019 }
1020
1021 return fragment;
1022 }
1023
1024 function parseDocument(svg) {
1025
1026 var parser;
1027
1028 // parse
1029 parser = new DOMParser();
1030 parser.async = false;
1031
1032 return parser.parseFromString(svg, 'text/xml');
1033 }
1034
1035 /**
1036 * Create utility for SVG elements
1037 */
1038
1039
1040 /**
1041 * Create a specific type from name or SVG markup.
1042 *
1043 * @param {String} name the name or markup of the element
1044 * @param {Object} [attrs] attributes to set on the element
1045 *
1046 * @returns {SVGElement}
1047 */
1048 function create(name, attrs) {
1049 var element;
1050
1051 if (name.charAt(0) === '<') {
1052 element = parse(name).firstChild;
1053 element = document.importNode(element, true);
1054 } else {
1055 element = document.createElementNS(ns.svg, name);
1056 }
1057
1058 if (attrs) {
1059 attr(element, attrs);
1060 }
1061
1062 return element;
1063 }
1064
1065 /**
1066 * Geometry helpers
1067 */
1068
1069 // fake node used to instantiate svg geometry elements
1070 var node = create('svg');
1071
1072 function extend(object, props) {
1073 var i, k, keys = Object.keys(props);
1074
1075 for (i = 0; (k = keys[i]); i++) {
1076 object[k] = props[k];
1077 }
1078
1079 return object;
1080 }
1081
1082 /**
1083 * Create matrix via args.
1084 *
1085 * @example
1086 *
1087 * createMatrix({ a: 1, b: 1 });
1088 * createMatrix();
1089 * createMatrix(1, 2, 0, 0, 30, 20);
1090 *
1091 * @return {SVGMatrix}
1092 */
1093 function createMatrix(a, b, c, d, e, f) {
1094 var matrix = node.createSVGMatrix();
1095
1096 switch (arguments.length) {
1097 case 0:
1098 return matrix;
1099 case 1:
1100 return extend(matrix, a);
1101 case 6:
1102 return extend(matrix, {
1103 a: a,
1104 b: b,
1105 c: c,
1106 d: d,
1107 e: e,
1108 f: f
1109 });
1110 }
1111 }
1112
1113 function createTransform(matrix) {
1114 if (matrix) {
1115 return node.createSVGTransformFromMatrix(matrix);
1116 } else {
1117 return node.createSVGTransform();
1118 }
1119 }
1120
1121 /**
1122 * Serialization util
1123 */
1124
1125 var TEXT_ENTITIES = /([&<>]{1})/g;
1126 var ATTR_ENTITIES = /([\n\r"]{1})/g;
1127
1128 var ENTITY_REPLACEMENT = {
1129 '&': '&amp;',
1130 '<': '&lt;',
1131 '>': '&gt;',
1132 '"': '\''
1133 };
1134
1135 function escape(str, pattern) {
1136
1137 function replaceFn(match, entity) {
1138 return ENTITY_REPLACEMENT[entity] || entity;
1139 }
1140
1141 return str.replace(pattern, replaceFn);
1142 }
1143
1144 function serialize(node, output) {
1145
1146 var i, len, attrMap, attrNode, childNodes;
1147
1148 switch (node.nodeType) {
1149 // TEXT
1150 case 3:
1151 // replace special XML characters
1152 output.push(escape(node.textContent, TEXT_ENTITIES));
1153 break;
1154
1155 // ELEMENT
1156 case 1:
1157 output.push('<', node.tagName);
1158
1159 if (node.hasAttributes()) {
1160 attrMap = node.attributes;
1161 for (i = 0, len = attrMap.length; i < len; ++i) {
1162 attrNode = attrMap.item(i);
1163 output.push(' ', attrNode.name, '="', escape(attrNode.value, ATTR_ENTITIES), '"');
1164 }
1165 }
1166
1167 if (node.hasChildNodes()) {
1168 output.push('>');
1169 childNodes = node.childNodes;
1170 for (i = 0, len = childNodes.length; i < len; ++i) {
1171 serialize(childNodes.item(i), output);
1172 }
1173 output.push('</', node.tagName, '>');
1174 } else {
1175 output.push('/>');
1176 }
1177 break;
1178
1179 // COMMENT
1180 case 8:
1181 output.push('<!--', escape(node.nodeValue, TEXT_ENTITIES), '-->');
1182 break;
1183
1184 // CDATA
1185 case 4:
1186 output.push('<![CDATA[', node.nodeValue, ']]>');
1187 break;
1188
1189 default:
1190 throw new Error('unable to handle node ' + node.nodeType);
1191 }
1192
1193 return output;
1194 }
1195
1196 /**
1197 * innerHTML like functionality for SVG elements.
1198 * based on innerSVG (https://code.google.com/p/innersvg)
1199 */
1200
1201
1202 function set(element, svg) {
1203
1204 var parsed = parse(svg);
1205
1206 // clear element contents
1207 clear(element);
1208
1209 if (!svg) {
1210 return;
1211 }
1212
1213 if (!isFragment(parsed)) {
1214 // extract <svg> from parsed document
1215 parsed = parsed.documentElement;
1216 }
1217
1218 var nodes = slice(parsed.childNodes);
1219
1220 // import + append each node
1221 for (var i = 0; i < nodes.length; i++) {
1222 appendTo(nodes[i], element);
1223 }
1224
1225 }
1226
1227 function get(element) {
1228 var child = element.firstChild,
1229 output = [];
1230
1231 while (child) {
1232 serialize(child, output);
1233 child = child.nextSibling;
1234 }
1235
1236 return output.join('');
1237 }
1238
1239 function isFragment(node) {
1240 return node.nodeName === '#document-fragment';
1241 }
1242
1243 function innerSVG(element, svg) {
1244
1245 if (svg !== undefined) {
1246
1247 try {
1248 set(element, svg);
1249 } catch (e) {
1250 throw new Error('error parsing SVG: ' + e.message);
1251 }
1252
1253 return element;
1254 } else {
1255 return get(element);
1256 }
1257 }
1258
1259
1260 function slice(arr) {
1261 return Array.prototype.slice.call(arr);
1262 }
1263
1264 /**
1265 * transform accessor utility
1266 */
1267
1268 function wrapMatrix(transformList, transform) {
1269 if (transform instanceof SVGMatrix) {
1270 return transformList.createSVGTransformFromMatrix(transform);
1271 }
1272
1273 return transform;
1274 }
1275
1276
1277 function setTransforms(transformList, transforms) {
1278 var i, t;
1279
1280 transformList.clear();
1281
1282 for (i = 0; (t = transforms[i]); i++) {
1283 transformList.appendItem(wrapMatrix(transformList, t));
1284 }
1285 }
1286
1287 /**
1288 * Get or set the transforms on the given node.
1289 *
1290 * @param {SVGElement} node
1291 * @param {SVGTransform|SVGMatrix|Array<SVGTransform|SVGMatrix>} [transforms]
1292 *
1293 * @return {SVGTransform} the consolidated transform
1294 */
1295 function transform(node, transforms) {
1296 var transformList = node.transform.baseVal;
1297
1298 if (transforms) {
1299
1300 if (!Array.isArray(transforms)) {
1301 transforms = [ transforms ];
1302 }
1303
1304 setTransforms(transformList, transforms);
1305 }
1306
1307 return transformList.consolidate();
1308 }
1309
1310 function componentsToPath(elements) {
1311 return elements.join(',').replace(/,?([A-z]),?/g, '$1');
1312 }
1313
1314 function toSVGPoints(points) {
1315 var result = '';
1316
1317 for (var i = 0, p; (p = points[i]); i++) {
1318 result += p.x + ',' + p.y + ' ';
1319 }
1320
1321 return result;
1322 }
1323
1324 function createLine(points, attrs) {
1325
1326 var line = create('polyline');
1327 attr(line, { points: toSVGPoints(points) });
1328
1329 if (attrs) {
1330 attr(line, attrs);
1331 }
1332
1333 return line;
1334 }
1335
1336 function updateLine(gfx, points) {
1337 attr(gfx, { points: toSVGPoints(points) });
1338
1339 return gfx;
1340 }
1341
1342 // element utils //////////////////////
1343
1344 /**
1345 * Checks if eventDefinition of the given element matches with semantic type.
1346 *
1347 * @return {boolean} true if element is of the given semantic type
1348 */
1349 function isTypedEvent(event, eventDefinitionType, filter) {
1350
1351 function matches(definition, filter) {
1352 return every(filter, function(val, key) {
1353
1354 // we want a == conversion here, to be able to catch
1355 // undefined == false and friends
1356 /* jshint -W116 */
1357 return definition[key] == val;
1358 });
1359 }
1360
1361 return some(event.eventDefinitions, function(definition) {
1362 return definition.$type === eventDefinitionType && matches(event, filter);
1363 });
1364 }
1365
1366 function isThrowEvent(event) {
1367 return (event.$type === 'bpmn:IntermediateThrowEvent') || (event.$type === 'bpmn:EndEvent');
1368 }
1369
1370 function isCollection(element) {
1371 var dataObject = element.dataObjectRef;
1372
1373 return element.isCollection || (dataObject && dataObject.isCollection);
1374 }
1375
1376 function getDi(element) {
1377 return element.businessObject.di;
1378 }
1379
1380 function getSemantic(element) {
1381 return element.businessObject;
1382 }
1383
1384
1385 // color access //////////////////////
1386
1387 function getFillColor(element, defaultColor) {
1388 return getDi(element).get('bioc:fill') || defaultColor || 'white';
1389 }
1390
1391 function getStrokeColor(element, defaultColor) {
1392 return getDi(element).get('bioc:stroke') || defaultColor || 'black';
1393 }
1394
1395
1396 // cropping path customizations //////////////////////
1397
1398 function getCirclePath(shape) {
1399
1400 var cx = shape.x + shape.width / 2,
1401 cy = shape.y + shape.height / 2,
1402 radius = shape.width / 2;
1403
1404 var circlePath = [
1405 ['M', cx, cy],
1406 ['m', 0, -radius],
1407 ['a', radius, radius, 0, 1, 1, 0, 2 * radius],
1408 ['a', radius, radius, 0, 1, 1, 0, -2 * radius],
1409 ['z']
1410 ];
1411
1412 return componentsToPath(circlePath);
1413 }
1414
1415 function getRoundRectPath(shape, borderRadius) {
1416
1417 var x = shape.x,
1418 y = shape.y,
1419 width = shape.width,
1420 height = shape.height;
1421
1422 var roundRectPath = [
1423 ['M', x + borderRadius, y],
1424 ['l', width - borderRadius * 2, 0],
1425 ['a', borderRadius, borderRadius, 0, 0, 1, borderRadius, borderRadius],
1426 ['l', 0, height - borderRadius * 2],
1427 ['a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, borderRadius],
1428 ['l', borderRadius * 2 - width, 0],
1429 ['a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, -borderRadius],
1430 ['l', 0, borderRadius * 2 - height],
1431 ['a', borderRadius, borderRadius, 0, 0, 1, borderRadius, -borderRadius],
1432 ['z']
1433 ];
1434
1435 return componentsToPath(roundRectPath);
1436 }
1437
1438 function getDiamondPath(shape) {
1439
1440 var width = shape.width,
1441 height = shape.height,
1442 x = shape.x,
1443 y = shape.y,
1444 halfWidth = width / 2,
1445 halfHeight = height / 2;
1446
1447 var diamondPath = [
1448 ['M', x + halfWidth, y],
1449 ['l', halfWidth, halfHeight],
1450 ['l', -halfWidth, halfHeight],
1451 ['l', -halfWidth, -halfHeight],
1452 ['z']
1453 ];
1454
1455 return componentsToPath(diamondPath);
1456 }
1457
1458 function getRectPath(shape) {
1459 var x = shape.x,
1460 y = shape.y,
1461 width = shape.width,
1462 height = shape.height;
1463
1464 var rectPath = [
1465 ['M', x, y],
1466 ['l', width, 0],
1467 ['l', 0, height],
1468 ['l', -width, 0],
1469 ['z']
1470 ];
1471
1472 return componentsToPath(rectPath);
1473 }
1474
1475 /**
1476 * Set attribute `name` to `val`, or get attr `name`.
1477 *
1478 * @param {Element} el
1479 * @param {String} name
1480 * @param {String} [val]
1481 * @api public
1482 */
1483 function attr$1(el, name, val) {
1484 // get
1485 if (arguments.length == 2) {
1486 return el.getAttribute(name);
1487 }
1488
1489 // remove
1490 if (val === null) {
1491 return el.removeAttribute(name);
1492 }
1493
1494 // set
1495 el.setAttribute(name, val);
1496
1497 return el;
1498 }
1499
1500 var indexOf = [].indexOf;
1501
1502 var indexof = function(arr, obj){
1503 if (indexOf) return arr.indexOf(obj);
1504 for (var i = 0; i < arr.length; ++i) {
1505 if (arr[i] === obj) return i;
1506 }
1507 return -1;
1508 };
1509
1510 /**
1511 * Taken from https://github.com/component/classes
1512 *
1513 * Without the component bits.
1514 */
1515
1516 /**
1517 * Whitespace regexp.
1518 */
1519
1520 var re$1 = /\s+/;
1521
1522 /**
1523 * toString reference.
1524 */
1525
1526 var toString$1 = Object.prototype.toString;
1527
1528 /**
1529 * Wrap `el` in a `ClassList`.
1530 *
1531 * @param {Element} el
1532 * @return {ClassList}
1533 * @api public
1534 */
1535
1536 function classes$1(el) {
1537 return new ClassList$1(el);
1538 }
1539
1540 /**
1541 * Initialize a new ClassList for `el`.
1542 *
1543 * @param {Element} el
1544 * @api private
1545 */
1546
1547 function ClassList$1(el) {
1548 if (!el || !el.nodeType) {
1549 throw new Error('A DOM element reference is required');
1550 }
1551 this.el = el;
1552 this.list = el.classList;
1553 }
1554
1555 /**
1556 * Add class `name` if not already present.
1557 *
1558 * @param {String} name
1559 * @return {ClassList}
1560 * @api public
1561 */
1562
1563 ClassList$1.prototype.add = function (name) {
1564 // classList
1565 if (this.list) {
1566 this.list.add(name);
1567 return this;
1568 }
1569
1570 // fallback
1571 var arr = this.array();
1572 var i = indexof(arr, name);
1573 if (!~i) arr.push(name);
1574 this.el.className = arr.join(' ');
1575 return this;
1576 };
1577
1578 /**
1579 * Remove class `name` when present, or
1580 * pass a regular expression to remove
1581 * any which match.
1582 *
1583 * @param {String|RegExp} name
1584 * @return {ClassList}
1585 * @api public
1586 */
1587
1588 ClassList$1.prototype.remove = function (name) {
1589 if ('[object RegExp]' == toString$1.call(name)) {
1590 return this.removeMatching(name);
1591 }
1592
1593 // classList
1594 if (this.list) {
1595 this.list.remove(name);
1596 return this;
1597 }
1598
1599 // fallback
1600 var arr = this.array();
1601 var i = indexof(arr, name);
1602 if (~i) arr.splice(i, 1);
1603 this.el.className = arr.join(' ');
1604 return this;
1605 };
1606
1607 /**
1608 * Remove all classes matching `re`.
1609 *
1610 * @param {RegExp} re
1611 * @return {ClassList}
1612 * @api private
1613 */
1614
1615 ClassList$1.prototype.removeMatching = function (re) {
1616 var arr = this.array();
1617 for (var i = 0; i < arr.length; i++) {
1618 if (re.test(arr[i])) {
1619 this.remove(arr[i]);
1620 }
1621 }
1622 return this;
1623 };
1624
1625 /**
1626 * Toggle class `name`, can force state via `force`.
1627 *
1628 * For browsers that support classList, but do not support `force` yet,
1629 * the mistake will be detected and corrected.
1630 *
1631 * @param {String} name
1632 * @param {Boolean} force
1633 * @return {ClassList}
1634 * @api public
1635 */
1636
1637 ClassList$1.prototype.toggle = function (name, force) {
1638 // classList
1639 if (this.list) {
1640 if ('undefined' !== typeof force) {
1641 if (force !== this.list.toggle(name, force)) {
1642 this.list.toggle(name); // toggle again to correct
1643 }
1644 } else {
1645 this.list.toggle(name);
1646 }
1647 return this;
1648 }
1649
1650 // fallback
1651 if ('undefined' !== typeof force) {
1652 if (!force) {
1653 this.remove(name);
1654 } else {
1655 this.add(name);
1656 }
1657 } else {
1658 if (this.has(name)) {
1659 this.remove(name);
1660 } else {
1661 this.add(name);
1662 }
1663 }
1664
1665 return this;
1666 };
1667
1668 /**
1669 * Return an array of classes.
1670 *
1671 * @return {Array}
1672 * @api public
1673 */
1674
1675 ClassList$1.prototype.array = function () {
1676 var className = this.el.getAttribute('class') || '';
1677 var str = className.replace(/^\s+|\s+$/g, '');
1678 var arr = str.split(re$1);
1679 if ('' === arr[0]) arr.shift();
1680 return arr;
1681 };
1682
1683 /**
1684 * Check if class `name` is present.
1685 *
1686 * @param {String} name
1687 * @return {ClassList}
1688 * @api public
1689 */
1690
1691 ClassList$1.prototype.has = ClassList$1.prototype.contains = function (name) {
1692 return this.list ? this.list.contains(name) : !!~indexof(this.array(), name);
1693 };
1694
1695 /**
1696 * Remove all children from the given element.
1697 */
1698 function clear$1(el) {
1699
1700 var c;
1701
1702 while (el.childNodes.length) {
1703 c = el.childNodes[0];
1704 el.removeChild(c);
1705 }
1706
1707 return el;
1708 }
1709
1710 /**
1711 * Element prototype.
1712 */
1713
1714 var proto = Element.prototype;
1715
1716 /**
1717 * Vendor function.
1718 */
1719
1720 var vendor = proto.matchesSelector
1721 || proto.webkitMatchesSelector
1722 || proto.mozMatchesSelector
1723 || proto.msMatchesSelector
1724 || proto.oMatchesSelector;
1725
1726 /**
1727 * Expose `match()`.
1728 */
1729
1730 var matchesSelector = match;
1731
1732 /**
1733 * Match `el` to `selector`.
1734 *
1735 * @param {Element} el
1736 * @param {String} selector
1737 * @return {Boolean}
1738 * @api public
1739 */
1740
1741 function match(el, selector) {
1742 if (vendor) return vendor.call(el, selector);
1743 var nodes = el.parentNode.querySelectorAll(selector);
1744 for (var i = 0; i < nodes.length; ++i) {
1745 if (nodes[i] == el) return true;
1746 }
1747 return false;
1748 }
1749
1750 var closest = function (element, selector, checkYoSelf) {
1751 var parent = checkYoSelf ? element : element.parentNode;
1752
1753 while (parent && parent !== document) {
1754 if (matchesSelector(parent, selector)) return parent;
1755 parent = parent.parentNode;
1756 }
1757 };
1758
1759 var bind$1 = window.addEventListener ? 'addEventListener' : 'attachEvent',
1760 unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
1761 prefix = bind$1 !== 'addEventListener' ? 'on' : '';
1762
1763 /**
1764 * Bind `el` event `type` to `fn`.
1765 *
1766 * @param {Element} el
1767 * @param {String} type
1768 * @param {Function} fn
1769 * @param {Boolean} capture
1770 * @return {Function}
1771 * @api public
1772 */
1773
1774 var bind_1 = function(el, type, fn, capture){
1775 el[bind$1](prefix + type, fn, capture || false);
1776 return fn;
1777 };
1778
1779 /**
1780 * Unbind `el` event `type`'s callback `fn`.
1781 *
1782 * @param {Element} el
1783 * @param {String} type
1784 * @param {Function} fn
1785 * @param {Boolean} capture
1786 * @return {Function}
1787 * @api public
1788 */
1789
1790 var unbind_1 = function(el, type, fn, capture){
1791 el[unbind](prefix + type, fn, capture || false);
1792 return fn;
1793 };
1794
1795 var componentEvent = {
1796 bind: bind_1,
1797 unbind: unbind_1
1798 };
1799
1800 /**
1801 * Module dependencies.
1802 */
1803
1804
1805
1806 /**
1807 * Delegate event `type` to `selector`
1808 * and invoke `fn(e)`. A callback function
1809 * is returned which may be passed to `.unbind()`.
1810 *
1811 * @param {Element} el
1812 * @param {String} selector
1813 * @param {String} type
1814 * @param {Function} fn
1815 * @param {Boolean} capture
1816 * @return {Function}
1817 * @api public
1818 */
1819
1820 // Some events don't bubble, so we want to bind to the capture phase instead
1821 // when delegating.
1822 var forceCaptureEvents = ['focus', 'blur'];
1823
1824 var bind$1$1 = function(el, selector, type, fn, capture){
1825 if (forceCaptureEvents.indexOf(type) !== -1) capture = true;
1826
1827 return componentEvent.bind(el, type, function(e){
1828 var target = e.target || e.srcElement;
1829 e.delegateTarget = closest(target, selector, true);
1830 if (e.delegateTarget) fn.call(el, e);
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
1844 var unbind$1 = function(el, type, fn, capture){
1845 if (forceCaptureEvents.indexOf(type) !== -1) capture = true;
1846
1847 componentEvent.unbind(el, type, fn, capture);
1848 };
1849
1850 var delegateEvents = {
1851 bind: bind$1$1,
1852 unbind: unbind$1
1853 };
1854
1855 /**
1856 * Expose `parse`.
1857 */
1858
1859 var domify = parse$1;
1860
1861 /**
1862 * Tests for browser support.
1863 */
1864
1865 var innerHTMLBug = false;
1866 var bugTestDiv;
1867 if (typeof document !== 'undefined') {
1868 bugTestDiv = document.createElement('div');
1869 // Setup
1870 bugTestDiv.innerHTML = ' <link/><table></table><a href="/a">a</a><input type="checkbox"/>';
1871 // Make sure that link elements get serialized correctly by innerHTML
1872 // This requires a wrapper element in IE
1873 innerHTMLBug = !bugTestDiv.getElementsByTagName('link').length;
1874 bugTestDiv = undefined;
1875 }
1876
1877 /**
1878 * Wrap map from jquery.
1879 */
1880
1881 var map$1 = {
1882 legend: [1, '<fieldset>', '</fieldset>'],
1883 tr: [2, '<table><tbody>', '</tbody></table>'],
1884 col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
1885 // for script/link/style tags to work in IE6-8, you have to wrap
1886 // in a div with a non-whitespace character in front, ha!
1887 _default: innerHTMLBug ? [1, 'X<div>', '</div>'] : [0, '', '']
1888 };
1889
1890 map$1.td =
1891 map$1.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
1892
1893 map$1.option =
1894 map$1.optgroup = [1, '<select multiple="multiple">', '</select>'];
1895
1896 map$1.thead =
1897 map$1.tbody =
1898 map$1.colgroup =
1899 map$1.caption =
1900 map$1.tfoot = [1, '<table>', '</table>'];
1901
1902 map$1.polyline =
1903 map$1.ellipse =
1904 map$1.polygon =
1905 map$1.circle =
1906 map$1.text =
1907 map$1.line =
1908 map$1.path =
1909 map$1.rect =
1910 map$1.g = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>'];
1911
1912 /**
1913 * Parse `html` and return a DOM Node instance, which could be a TextNode,
1914 * HTML DOM Node of some kind (<div> for example), or a DocumentFragment
1915 * instance, depending on the contents of the `html` string.
1916 *
1917 * @param {String} html - HTML string to "domify"
1918 * @param {Document} doc - The `document` instance to create the Node for
1919 * @return {DOMNode} the TextNode, DOM Node, or DocumentFragment instance
1920 * @api private
1921 */
1922
1923 function parse$1(html, doc) {
1924 if ('string' != typeof html) throw new TypeError('String expected');
1925
1926 // default to the global `document` object
1927 if (!doc) doc = document;
1928
1929 // tag name
1930 var m = /<([\w:]+)/.exec(html);
1931 if (!m) return doc.createTextNode(html);
1932
1933 html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace
1934
1935 var tag = m[1];
1936
1937 // body support
1938 if (tag == 'body') {
1939 var el = doc.createElement('html');
1940 el.innerHTML = html;
1941 return el.removeChild(el.lastChild);
1942 }
1943
1944 // wrap map
1945 var wrap = map$1[tag] || map$1._default;
1946 var depth = wrap[0];
1947 var prefix = wrap[1];
1948 var suffix = wrap[2];
1949 var el = doc.createElement('div');
1950 el.innerHTML = prefix + html + suffix;
1951 while (depth--) el = el.lastChild;
1952
1953 // one element
1954 if (el.firstChild == el.lastChild) {
1955 return el.removeChild(el.firstChild);
1956 }
1957
1958 // several elements
1959 var fragment = doc.createDocumentFragment();
1960 while (el.firstChild) {
1961 fragment.appendChild(el.removeChild(el.firstChild));
1962 }
1963
1964 return fragment;
1965 }
1966
1967 var proto$1 = typeof Element !== 'undefined' ? Element.prototype : {};
1968 var vendor$1 = proto$1.matches
1969 || proto$1.matchesSelector
1970 || proto$1.webkitMatchesSelector
1971 || proto$1.mozMatchesSelector
1972 || proto$1.msMatchesSelector
1973 || proto$1.oMatchesSelector;
1974
1975 var matchesSelector$1 = match$1;
1976
1977 /**
1978 * Match `el` to `selector`.
1979 *
1980 * @param {Element} el
1981 * @param {String} selector
1982 * @return {Boolean}
1983 * @api public
1984 */
1985
1986 function match$1(el, selector) {
1987 if (!el || el.nodeType !== 1) return false;
1988 if (vendor$1) return vendor$1.call(el, selector);
1989 var nodes = el.parentNode.querySelectorAll(selector);
1990 for (var i = 0; i < nodes.length; i++) {
1991 if (nodes[i] == el) return true;
1992 }
1993 return false;
1994 }
1995
1996 function query(selector, el) {
1997 el = el || document;
1998
1999 return el.querySelector(selector);
2000 }
2001
2002 function all(selector, el) {
2003 el = el || document;
2004
2005 return el.querySelectorAll(selector);
2006 }
2007
2008 function remove$1(el) {
2009 el.parentNode && el.parentNode.removeChild(el);
2010 }
2011
2012 /**
2013 * @param {<SVGElement>} element
2014 * @param {Number} x
2015 * @param {Number} y
2016 * @param {Number} angle
2017 * @param {Number} amount
2018 */
2019 function transform$1(gfx, x, y, angle, amount) {
2020 var translate = createTransform();
2021 translate.setTranslate(x, y);
2022
2023 var rotate = createTransform();
2024 rotate.setRotate(angle || 0, 0, 0);
2025
2026 var scale = createTransform();
2027 scale.setScale(amount || 1, amount || 1);
2028
2029 transform(gfx, [ translate, rotate, scale ]);
2030 }
2031
2032
2033 /**
2034 * @param {SVGElement} element
2035 * @param {Number} x
2036 * @param {Number} y
2037 */
2038 function translate(gfx, x, y) {
2039 var translate = createTransform();
2040 translate.setTranslate(x, y);
2041
2042 transform(gfx, translate);
2043 }
2044
2045
2046 /**
2047 * @param {SVGElement} element
2048 * @param {Number} angle
2049 */
2050 function rotate(gfx, angle) {
2051 var rotate = createTransform();
2052 rotate.setRotate(angle, 0, 0);
2053
2054 transform(gfx, rotate);
2055 }
2056
2057 function createCommonjsModule$1(fn, module) {
2058 return module = { exports: {} }, fn(module, module.exports), module.exports;
2059 }
2060
2061 var hat_1 = createCommonjsModule$1(function (module) {
2062 var hat = module.exports = function (bits, base) {
2063 if (!base) base = 16;
2064 if (bits === undefined) bits = 128;
2065 if (bits <= 0) return '0';
2066
2067 var digits = Math.log(Math.pow(2, bits)) / Math.log(base);
2068 for (var i = 2; digits === Infinity; i *= 2) {
2069 digits = Math.log(Math.pow(2, bits / i)) / Math.log(base) * i;
2070 }
2071
2072 var rem = digits - Math.floor(digits);
2073
2074 var res = '';
2075
2076 for (var i = 0; i < Math.floor(digits); i++) {
2077 var x = Math.floor(Math.random() * base).toString(base);
2078 res = x + res;
2079 }
2080
2081 if (rem) {
2082 var b = Math.pow(base, rem);
2083 var x = Math.floor(Math.random() * b).toString(base);
2084 res = x + res;
2085 }
2086
2087 var parsed = parseInt(res, base);
2088 if (parsed !== Infinity && parsed >= Math.pow(2, bits)) {
2089 return hat(bits, base)
2090 }
2091 else return res;
2092 };
2093
2094 hat.rack = function (bits, base, expandBy) {
2095 var fn = function (data) {
2096 var iters = 0;
2097 do {
2098 if (iters ++ > 10) {
2099 if (expandBy) bits += expandBy;
2100 else throw new Error('too many ID collisions, use more bits')
2101 }
2102
2103 var id = hat(bits, base);
2104 } while (Object.hasOwnProperty.call(hats, id));
2105
2106 hats[id] = data;
2107 return id;
2108 };
2109 var hats = fn.hats = {};
2110
2111 fn.get = function (id) {
2112 return fn.hats[id];
2113 };
2114
2115 fn.set = function (id, value) {
2116 fn.hats[id] = value;
2117 return fn;
2118 };
2119
2120 fn.bits = bits || 128;
2121 fn.base = base || 16;
2122 return fn;
2123 };
2124 });
2125
2126 /**
2127 * Create a new id generator / cache instance.
2128 *
2129 * You may optionally provide a seed that is used internally.
2130 *
2131 * @param {Seed} seed
2132 */
2133
2134 function Ids(seed) {
2135 if (!(this instanceof Ids)) {
2136 return new Ids(seed);
2137 }
2138
2139 seed = seed || [128, 36, 1];
2140 this._seed = seed.length ? hat_1.rack(seed[0], seed[1], seed[2]) : seed;
2141 }
2142 /**
2143 * Generate a next id.
2144 *
2145 * @param {Object} [element] element to bind the id to
2146 *
2147 * @return {String} id
2148 */
2149
2150 Ids.prototype.next = function (element) {
2151 return this._seed(element || true);
2152 };
2153 /**
2154 * Generate a next id with a given prefix.
2155 *
2156 * @param {Object} [element] element to bind the id to
2157 *
2158 * @return {String} id
2159 */
2160
2161
2162 Ids.prototype.nextPrefixed = function (prefix, element) {
2163 var id;
2164
2165 do {
2166 id = prefix + this.next(true);
2167 } while (this.assigned(id)); // claim {prefix}{random}
2168
2169
2170 this.claim(id, element); // return
2171
2172 return id;
2173 };
2174 /**
2175 * Manually claim an existing id.
2176 *
2177 * @param {String} id
2178 * @param {String} [element] element the id is claimed by
2179 */
2180
2181
2182 Ids.prototype.claim = function (id, element) {
2183 this._seed.set(id, element || true);
2184 };
2185 /**
2186 * Returns true if the given id has already been assigned.
2187 *
2188 * @param {String} id
2189 * @return {Boolean}
2190 */
2191
2192
2193 Ids.prototype.assigned = function (id) {
2194 return this._seed.get(id) || false;
2195 };
2196 /**
2197 * Unclaim an id.
2198 *
2199 * @param {String} id the id to unclaim
2200 */
2201
2202
2203 Ids.prototype.unclaim = function (id) {
2204 delete this._seed.hats[id];
2205 };
2206 /**
2207 * Clear all claimed ids.
2208 */
2209
2210
2211 Ids.prototype.clear = function () {
2212 var hats = this._seed.hats,
2213 id;
2214
2215 for (id in hats) {
2216 this.unclaim(id);
2217 }
2218 };
2219
2220 var RENDERER_IDS = new Ids();
2221
2222 var TASK_BORDER_RADIUS = 10;
2223 var INNER_OUTER_DIST = 3;
2224
2225 var DEFAULT_FILL_OPACITY = .95,
2226 HIGH_FILL_OPACITY = .35;
2227
2228
2229 function BpmnRenderer(
2230 config, eventBus, styles, pathMap,
2231 canvas, textRenderer, priority) {
2232
2233 BaseRenderer.call(this, eventBus, priority);
2234
2235 var defaultFillColor = config && config.defaultFillColor,
2236 defaultStrokeColor = config && config.defaultStrokeColor;
2237
2238 var rendererId = RENDERER_IDS.next();
2239
2240 var markers = {};
2241
2242 var computeStyle = styles.computeStyle;
2243
2244 function addMarker(id, options) {
2245 var attrs = assign({
2246 fill: 'black',
2247 strokeWidth: 1,
2248 strokeLinecap: 'round',
2249 strokeDasharray: 'none'
2250 }, options.attrs);
2251
2252 var ref = options.ref || { x: 0, y: 0 };
2253
2254 var scale = options.scale || 1;
2255
2256 // fix for safari / chrome / firefox bug not correctly
2257 // resetting stroke dash array
2258 if (attrs.strokeDasharray === 'none') {
2259 attrs.strokeDasharray = [10000, 1];
2260 }
2261
2262 var marker = create('marker');
2263
2264 attr(options.element, attrs);
2265
2266 append(marker, options.element);
2267
2268 attr(marker, {
2269 id: id,
2270 viewBox: '0 0 20 20',
2271 refX: ref.x,
2272 refY: ref.y,
2273 markerWidth: 20 * scale,
2274 markerHeight: 20 * scale,
2275 orient: 'auto'
2276 });
2277
2278 var defs = query('defs', canvas._svg);
2279
2280 if (!defs) {
2281 defs = create('defs');
2282
2283 append(canvas._svg, defs);
2284 }
2285
2286 append(defs, marker);
2287
2288 markers[id] = marker;
2289 }
2290
2291 function colorEscape(str) {
2292
2293 // only allow characters and numbers
2294 return str.replace(/[^0-9a-zA-z]+/g, '_');
2295 }
2296
2297 function marker(type, fill, stroke) {
2298 var id = type + '-' + colorEscape(fill) + '-' + colorEscape(stroke) + '-' + rendererId;
2299
2300 if (!markers[id]) {
2301 createMarker(id, type, fill, stroke);
2302 }
2303
2304 return 'url(#' + id + ')';
2305 }
2306
2307 function createMarker(id, type, fill, stroke) {
2308
2309 if (type === 'sequenceflow-end') {
2310 var sequenceflowEnd = create('path');
2311 attr(sequenceflowEnd, { d: 'M 1 5 L 11 10 L 1 15 Z' });
2312
2313 addMarker(id, {
2314 element: sequenceflowEnd,
2315 ref: { x: 11, y: 10 },
2316 scale: 0.5,
2317 attrs: {
2318 fill: stroke,
2319 stroke: stroke
2320 }
2321 });
2322 }
2323
2324 if (type === 'messageflow-start') {
2325 var messageflowStart = create('circle');
2326 attr(messageflowStart, { cx: 6, cy: 6, r: 3.5 });
2327
2328 addMarker(id, {
2329 element: messageflowStart,
2330 attrs: {
2331 fill: fill,
2332 stroke: stroke
2333 },
2334 ref: { x: 6, y: 6 }
2335 });
2336 }
2337
2338 if (type === 'messageflow-end') {
2339 var messageflowEnd = create('path');
2340 attr(messageflowEnd, { d: 'm 1 5 l 0 -3 l 7 3 l -7 3 z' });
2341
2342 addMarker(id, {
2343 element: messageflowEnd,
2344 attrs: {
2345 fill: fill,
2346 stroke: stroke,
2347 strokeLinecap: 'butt'
2348 },
2349 ref: { x: 8.5, y: 5 }
2350 });
2351 }
2352
2353 if (type === 'association-start') {
2354 var associationStart = create('path');
2355 attr(associationStart, { d: 'M 11 5 L 1 10 L 11 15' });
2356
2357 addMarker(id, {
2358 element: associationStart,
2359 attrs: {
2360 fill: 'none',
2361 stroke: stroke,
2362 strokeWidth: 1.5
2363 },
2364 ref: { x: 1, y: 10 },
2365 scale: 0.5
2366 });
2367 }
2368
2369 if (type === 'association-end') {
2370 var associationEnd = create('path');
2371 attr(associationEnd, { d: 'M 1 5 L 11 10 L 1 15' });
2372
2373 addMarker(id, {
2374 element: associationEnd,
2375 attrs: {
2376 fill: 'none',
2377 stroke: stroke,
2378 strokeWidth: 1.5
2379 },
2380 ref: { x: 12, y: 10 },
2381 scale: 0.5
2382 });
2383 }
2384
2385 if (type === 'conditional-flow-marker') {
2386 var conditionalflowMarker = create('path');
2387 attr(conditionalflowMarker, { d: 'M 0 10 L 8 6 L 16 10 L 8 14 Z' });
2388
2389 addMarker(id, {
2390 element: conditionalflowMarker,
2391 attrs: {
2392 fill: fill,
2393 stroke: stroke
2394 },
2395 ref: { x: -1, y: 10 },
2396 scale: 0.5
2397 });
2398 }
2399
2400 if (type === 'conditional-default-flow-marker') {
2401 var conditionaldefaultflowMarker = create('path');
2402 attr(conditionaldefaultflowMarker, { d: 'M 6 4 L 10 16' });
2403
2404 addMarker(id, {
2405 element: conditionaldefaultflowMarker,
2406 attrs: {
2407 stroke: stroke
2408 },
2409 ref: { x: 0, y: 10 },
2410 scale: 0.5
2411 });
2412 }
2413 }
2414
2415 function drawCircle(parentGfx, width, height, offset, attrs) {
2416
2417 if (isObject(offset)) {
2418 attrs = offset;
2419 offset = 0;
2420 }
2421
2422 offset = offset || 0;
2423
2424 attrs = computeStyle(attrs, {
2425 stroke: 'black',
2426 strokeWidth: 2,
2427 fill: 'white'
2428 });
2429
2430 if (attrs.fill === 'none') {
2431 delete attrs.fillOpacity;
2432 }
2433
2434 var cx = width / 2,
2435 cy = height / 2;
2436
2437 var circle = create('circle');
2438 attr(circle, {
2439 cx: cx,
2440 cy: cy,
2441 r: Math.round((width + height) / 4 - offset)
2442 });
2443 attr(circle, attrs);
2444
2445 append(parentGfx, circle);
2446
2447 return circle;
2448 }
2449
2450 function drawRect(parentGfx, width, height, r, offset, attrs) {
2451
2452 if (isObject(offset)) {
2453 attrs = offset;
2454 offset = 0;
2455 }
2456
2457 offset = offset || 0;
2458
2459 attrs = computeStyle(attrs, {
2460 stroke: 'black',
2461 strokeWidth: 2,
2462 fill: 'white'
2463 });
2464
2465 var rect = create('rect');
2466 attr(rect, {
2467 x: offset,
2468 y: offset,
2469 width: width - offset * 2,
2470 height: height - offset * 2,
2471 rx: r,
2472 ry: r
2473 });
2474 attr(rect, attrs);
2475
2476 append(parentGfx, rect);
2477
2478 return rect;
2479 }
2480
2481 function drawDiamond(parentGfx, width, height, attrs) {
2482
2483 var x_2 = width / 2;
2484 var y_2 = height / 2;
2485
2486 var points = [{ x: x_2, y: 0 }, { x: width, y: y_2 }, { x: x_2, y: height }, { x: 0, y: y_2 }];
2487
2488 var pointsString = points.map(function(point) {
2489 return point.x + ',' + point.y;
2490 }).join(' ');
2491
2492 attrs = computeStyle(attrs, {
2493 stroke: 'black',
2494 strokeWidth: 2,
2495 fill: 'white'
2496 });
2497
2498 var polygon = create('polygon');
2499 attr(polygon, {
2500 points: pointsString
2501 });
2502 attr(polygon, attrs);
2503
2504 append(parentGfx, polygon);
2505
2506 return polygon;
2507 }
2508
2509 function drawLine(parentGfx, waypoints, attrs) {
2510 attrs = computeStyle(attrs, [ 'no-fill' ], {
2511 stroke: 'black',
2512 strokeWidth: 2,
2513 fill: 'none'
2514 });
2515
2516 var line = createLine(waypoints, attrs);
2517
2518 append(parentGfx, line);
2519
2520 return line;
2521 }
2522
2523 function drawPath(parentGfx, d, attrs) {
2524
2525 attrs = computeStyle(attrs, [ 'no-fill' ], {
2526 strokeWidth: 2,
2527 stroke: 'black'
2528 });
2529
2530 var path = create('path');
2531 attr(path, { d: d });
2532 attr(path, attrs);
2533
2534 append(parentGfx, path);
2535
2536 return path;
2537 }
2538
2539 function drawMarker(type, parentGfx, path, attrs) {
2540 return drawPath(parentGfx, path, assign({ 'data-marker': type }, attrs));
2541 }
2542
2543 function as(type) {
2544 return function(parentGfx, element) {
2545 return handlers[type](parentGfx, element);
2546 };
2547 }
2548
2549 function renderer(type) {
2550 return handlers[type];
2551 }
2552
2553 function renderEventContent(element, parentGfx) {
2554
2555 var event = getSemantic(element);
2556 var isThrowing = isThrowEvent(event);
2557
2558 if (event.eventDefinitions && event.eventDefinitions.length>1) {
2559 if (event.parallelMultiple) {
2560 return renderer('bpmn:ParallelMultipleEventDefinition')(parentGfx, element, isThrowing);
2561 }
2562 else {
2563 return renderer('bpmn:MultipleEventDefinition')(parentGfx, element, isThrowing);
2564 }
2565 }
2566
2567 if (isTypedEvent(event, 'bpmn:MessageEventDefinition')) {
2568 return renderer('bpmn:MessageEventDefinition')(parentGfx, element, isThrowing);
2569 }
2570
2571 if (isTypedEvent(event, 'bpmn:TimerEventDefinition')) {
2572 return renderer('bpmn:TimerEventDefinition')(parentGfx, element, isThrowing);
2573 }
2574
2575 if (isTypedEvent(event, 'bpmn:ConditionalEventDefinition')) {
2576 return renderer('bpmn:ConditionalEventDefinition')(parentGfx, element);
2577 }
2578
2579 if (isTypedEvent(event, 'bpmn:SignalEventDefinition')) {
2580 return renderer('bpmn:SignalEventDefinition')(parentGfx, element, isThrowing);
2581 }
2582
2583 if (isTypedEvent(event, 'bpmn:EscalationEventDefinition')) {
2584 return renderer('bpmn:EscalationEventDefinition')(parentGfx, element, isThrowing);
2585 }
2586
2587 if (isTypedEvent(event, 'bpmn:LinkEventDefinition')) {
2588 return renderer('bpmn:LinkEventDefinition')(parentGfx, element, isThrowing);
2589 }
2590
2591 if (isTypedEvent(event, 'bpmn:ErrorEventDefinition')) {
2592 return renderer('bpmn:ErrorEventDefinition')(parentGfx, element, isThrowing);
2593 }
2594
2595 if (isTypedEvent(event, 'bpmn:CancelEventDefinition')) {
2596 return renderer('bpmn:CancelEventDefinition')(parentGfx, element, isThrowing);
2597 }
2598
2599 if (isTypedEvent(event, 'bpmn:CompensateEventDefinition')) {
2600 return renderer('bpmn:CompensateEventDefinition')(parentGfx, element, isThrowing);
2601 }
2602
2603 if (isTypedEvent(event, 'bpmn:TerminateEventDefinition')) {
2604 return renderer('bpmn:TerminateEventDefinition')(parentGfx, element, isThrowing);
2605 }
2606
2607 return null;
2608 }
2609
2610 function renderLabel(parentGfx, label, options) {
2611
2612 options = assign({
2613 size: {
2614 width: 100
2615 }
2616 }, options);
2617
2618 var text = textRenderer.createText(label || '', options);
2619
2620 classes(text).add('djs-label');
2621
2622 append(parentGfx, text);
2623
2624 return text;
2625 }
2626
2627 function renderEmbeddedLabel(parentGfx, element, align) {
2628 var semantic = getSemantic(element);
2629
2630 return renderLabel(parentGfx, semantic.name, {
2631 box: element,
2632 align: align,
2633 padding: 5,
2634 style: {
2635 fill: getStrokeColor(element, defaultStrokeColor)
2636 }
2637 });
2638 }
2639
2640 function renderExternalLabel(parentGfx, element) {
2641
2642 var box = {
2643 width: 90,
2644 height: 30,
2645 x: element.width / 2 + element.x,
2646 y: element.height / 2 + element.y
2647 };
2648
2649 return renderLabel(parentGfx, getLabel(element), {
2650 box: box,
2651 fitBox: true,
2652 style: assign(
2653 {},
2654 textRenderer.getExternalStyle(),
2655 {
2656 fill: getStrokeColor(element, defaultStrokeColor)
2657 }
2658 )
2659 });
2660 }
2661
2662 function renderLaneLabel(parentGfx, text, element) {
2663 var textBox = renderLabel(parentGfx, text, {
2664 box: {
2665 height: 30,
2666 width: element.height
2667 },
2668 align: 'center-middle',
2669 style: {
2670 fill: getStrokeColor(element, defaultStrokeColor)
2671 }
2672 });
2673
2674 var top = -1 * element.height;
2675
2676 transform$1(textBox, 0, -top, 270);
2677 }
2678
2679 function createPathFromConnection(connection) {
2680 var waypoints = connection.waypoints;
2681
2682 var pathData = 'm ' + waypoints[0].x + ',' + waypoints[0].y;
2683 for (var i = 1; i < waypoints.length; i++) {
2684 pathData += 'L' + waypoints[i].x + ',' + waypoints[i].y + ' ';
2685 }
2686 return pathData;
2687 }
2688
2689 var handlers = this.handlers = {
2690 'bpmn:Event': function(parentGfx, element, attrs) {
2691
2692 if (!('fillOpacity' in attrs)) {
2693 attrs.fillOpacity = DEFAULT_FILL_OPACITY;
2694 }
2695
2696 return drawCircle(parentGfx, element.width, element.height, attrs);
2697 },
2698 'bpmn:StartEvent': function(parentGfx, element) {
2699 var attrs = {
2700 fill: getFillColor(element, defaultFillColor),
2701 stroke: getStrokeColor(element, defaultStrokeColor)
2702 };
2703
2704 var semantic = getSemantic(element);
2705
2706 if (!semantic.isInterrupting) {
2707 attrs = {
2708 strokeDasharray: '6',
2709 strokeLinecap: 'round',
2710 fill: getFillColor(element, defaultFillColor),
2711 stroke: getStrokeColor(element, defaultStrokeColor)
2712 };
2713 }
2714
2715 var circle = renderer('bpmn:Event')(parentGfx, element, attrs);
2716
2717 renderEventContent(element, parentGfx);
2718
2719 return circle;
2720 },
2721 'bpmn:MessageEventDefinition': function(parentGfx, element, isThrowing) {
2722 var pathData = pathMap.getScaledPath('EVENT_MESSAGE', {
2723 xScaleFactor: 0.9,
2724 yScaleFactor: 0.9,
2725 containerWidth: element.width,
2726 containerHeight: element.height,
2727 position: {
2728 mx: 0.235,
2729 my: 0.315
2730 }
2731 });
2732
2733 var fill = isThrowing ? getStrokeColor(element, defaultStrokeColor) : getFillColor(element, defaultFillColor);
2734 var stroke = isThrowing ? getFillColor(element, defaultFillColor) : getStrokeColor(element, defaultStrokeColor);
2735
2736 var messagePath = drawPath(parentGfx, pathData, {
2737 strokeWidth: 1,
2738 fill: fill,
2739 stroke: stroke
2740 });
2741
2742 return messagePath;
2743 },
2744 'bpmn:TimerEventDefinition': function(parentGfx, element) {
2745 var circle = drawCircle(parentGfx, element.width, element.height, 0.2 * element.height, {
2746 strokeWidth: 2,
2747 fill: getFillColor(element, defaultFillColor),
2748 stroke: getStrokeColor(element, defaultStrokeColor)
2749 });
2750
2751 var pathData = pathMap.getScaledPath('EVENT_TIMER_WH', {
2752 xScaleFactor: 0.75,
2753 yScaleFactor: 0.75,
2754 containerWidth: element.width,
2755 containerHeight: element.height,
2756 position: {
2757 mx: 0.5,
2758 my: 0.5
2759 }
2760 });
2761
2762 drawPath(parentGfx, pathData, {
2763 strokeWidth: 2,
2764 strokeLinecap: 'square',
2765 stroke: getStrokeColor(element, defaultStrokeColor)
2766 });
2767
2768 for (var i = 0;i < 12; i++) {
2769
2770 var linePathData = pathMap.getScaledPath('EVENT_TIMER_LINE', {
2771 xScaleFactor: 0.75,
2772 yScaleFactor: 0.75,
2773 containerWidth: element.width,
2774 containerHeight: element.height,
2775 position: {
2776 mx: 0.5,
2777 my: 0.5
2778 }
2779 });
2780
2781 var width = element.width / 2;
2782 var height = element.height / 2;
2783
2784 drawPath(parentGfx, linePathData, {
2785 strokeWidth: 1,
2786 strokeLinecap: 'square',
2787 transform: 'rotate(' + (i * 30) + ',' + height + ',' + width + ')',
2788 stroke: getStrokeColor(element, defaultStrokeColor)
2789 });
2790 }
2791
2792 return circle;
2793 },
2794 'bpmn:EscalationEventDefinition': function(parentGfx, event, isThrowing) {
2795 var pathData = pathMap.getScaledPath('EVENT_ESCALATION', {
2796 xScaleFactor: 1,
2797 yScaleFactor: 1,
2798 containerWidth: event.width,
2799 containerHeight: event.height,
2800 position: {
2801 mx: 0.5,
2802 my: 0.2
2803 }
2804 });
2805
2806 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2807
2808 return drawPath(parentGfx, pathData, {
2809 strokeWidth: 1,
2810 fill: fill,
2811 stroke: getStrokeColor(event, defaultStrokeColor)
2812 });
2813 },
2814 'bpmn:ConditionalEventDefinition': function(parentGfx, event) {
2815 var pathData = pathMap.getScaledPath('EVENT_CONDITIONAL', {
2816 xScaleFactor: 1,
2817 yScaleFactor: 1,
2818 containerWidth: event.width,
2819 containerHeight: event.height,
2820 position: {
2821 mx: 0.5,
2822 my: 0.222
2823 }
2824 });
2825
2826 return drawPath(parentGfx, pathData, {
2827 strokeWidth: 1,
2828 stroke: getStrokeColor(event, defaultStrokeColor)
2829 });
2830 },
2831 'bpmn:LinkEventDefinition': function(parentGfx, event, isThrowing) {
2832 var pathData = pathMap.getScaledPath('EVENT_LINK', {
2833 xScaleFactor: 1,
2834 yScaleFactor: 1,
2835 containerWidth: event.width,
2836 containerHeight: event.height,
2837 position: {
2838 mx: 0.57,
2839 my: 0.263
2840 }
2841 });
2842
2843 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2844
2845 return drawPath(parentGfx, pathData, {
2846 strokeWidth: 1,
2847 fill: fill,
2848 stroke: getStrokeColor(event, defaultStrokeColor)
2849 });
2850 },
2851 'bpmn:ErrorEventDefinition': function(parentGfx, event, isThrowing) {
2852 var pathData = pathMap.getScaledPath('EVENT_ERROR', {
2853 xScaleFactor: 1.1,
2854 yScaleFactor: 1.1,
2855 containerWidth: event.width,
2856 containerHeight: event.height,
2857 position: {
2858 mx: 0.2,
2859 my: 0.722
2860 }
2861 });
2862
2863 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2864
2865 return drawPath(parentGfx, pathData, {
2866 strokeWidth: 1,
2867 fill: fill,
2868 stroke: getStrokeColor(event, defaultStrokeColor)
2869 });
2870 },
2871 'bpmn:CancelEventDefinition': function(parentGfx, event, isThrowing) {
2872 var pathData = pathMap.getScaledPath('EVENT_CANCEL_45', {
2873 xScaleFactor: 1.0,
2874 yScaleFactor: 1.0,
2875 containerWidth: event.width,
2876 containerHeight: event.height,
2877 position: {
2878 mx: 0.638,
2879 my: -0.055
2880 }
2881 });
2882
2883 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2884
2885 var path = drawPath(parentGfx, pathData, {
2886 strokeWidth: 1,
2887 fill: fill,
2888 stroke: getStrokeColor(event, defaultStrokeColor)
2889 });
2890
2891 rotate(path, 45);
2892
2893 return path;
2894 },
2895 'bpmn:CompensateEventDefinition': function(parentGfx, event, isThrowing) {
2896 var pathData = pathMap.getScaledPath('EVENT_COMPENSATION', {
2897 xScaleFactor: 1,
2898 yScaleFactor: 1,
2899 containerWidth: event.width,
2900 containerHeight: event.height,
2901 position: {
2902 mx: 0.22,
2903 my: 0.5
2904 }
2905 });
2906
2907 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2908
2909 return drawPath(parentGfx, pathData, {
2910 strokeWidth: 1,
2911 fill: fill,
2912 stroke: getStrokeColor(event, defaultStrokeColor)
2913 });
2914 },
2915 'bpmn:SignalEventDefinition': function(parentGfx, event, isThrowing) {
2916 var pathData = pathMap.getScaledPath('EVENT_SIGNAL', {
2917 xScaleFactor: 0.9,
2918 yScaleFactor: 0.9,
2919 containerWidth: event.width,
2920 containerHeight: event.height,
2921 position: {
2922 mx: 0.5,
2923 my: 0.2
2924 }
2925 });
2926
2927 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2928
2929 return drawPath(parentGfx, pathData, {
2930 strokeWidth: 1,
2931 fill: fill,
2932 stroke: getStrokeColor(event, defaultStrokeColor)
2933 });
2934 },
2935 'bpmn:MultipleEventDefinition': function(parentGfx, event, isThrowing) {
2936 var pathData = pathMap.getScaledPath('EVENT_MULTIPLE', {
2937 xScaleFactor: 1.1,
2938 yScaleFactor: 1.1,
2939 containerWidth: event.width,
2940 containerHeight: event.height,
2941 position: {
2942 mx: 0.222,
2943 my: 0.36
2944 }
2945 });
2946
2947 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
2948
2949 return drawPath(parentGfx, pathData, {
2950 strokeWidth: 1,
2951 fill: fill
2952 });
2953 },
2954 'bpmn:ParallelMultipleEventDefinition': function(parentGfx, event) {
2955 var pathData = pathMap.getScaledPath('EVENT_PARALLEL_MULTIPLE', {
2956 xScaleFactor: 1.2,
2957 yScaleFactor: 1.2,
2958 containerWidth: event.width,
2959 containerHeight: event.height,
2960 position: {
2961 mx: 0.458,
2962 my: 0.194
2963 }
2964 });
2965
2966 return drawPath(parentGfx, pathData, {
2967 strokeWidth: 1,
2968 fill: getStrokeColor(event, defaultStrokeColor),
2969 stroke: getStrokeColor(event, defaultStrokeColor)
2970 });
2971 },
2972 'bpmn:EndEvent': function(parentGfx, element) {
2973 var circle = renderer('bpmn:Event')(parentGfx, element, {
2974 strokeWidth: 4,
2975 fill: getFillColor(element, defaultFillColor),
2976 stroke: getStrokeColor(element, defaultStrokeColor)
2977 });
2978
2979 renderEventContent(element, parentGfx);
2980
2981 return circle;
2982 },
2983 'bpmn:TerminateEventDefinition': function(parentGfx, element) {
2984 var circle = drawCircle(parentGfx, element.width, element.height, 8, {
2985 strokeWidth: 4,
2986 fill: getStrokeColor(element, defaultStrokeColor),
2987 stroke: getStrokeColor(element, defaultStrokeColor)
2988 });
2989
2990 return circle;
2991 },
2992 'bpmn:IntermediateEvent': function(parentGfx, element) {
2993 var outer = renderer('bpmn:Event')(parentGfx, element, {
2994 strokeWidth: 1,
2995 fill: getFillColor(element, defaultFillColor),
2996 stroke: getStrokeColor(element, defaultStrokeColor)
2997 });
2998
2999 /* inner */
3000 drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, {
3001 strokeWidth: 1,
3002 fill: getFillColor(element, 'none'),
3003 stroke: getStrokeColor(element, defaultStrokeColor)
3004 });
3005
3006 renderEventContent(element, parentGfx);
3007
3008 return outer;
3009 },
3010 'bpmn:IntermediateCatchEvent': as('bpmn:IntermediateEvent'),
3011 'bpmn:IntermediateThrowEvent': as('bpmn:IntermediateEvent'),
3012
3013 'bpmn:Activity': function(parentGfx, element, attrs) {
3014
3015 attrs = attrs || {};
3016
3017 if (!('fillOpacity' in attrs)) {
3018 attrs.fillOpacity = DEFAULT_FILL_OPACITY;
3019 }
3020
3021 return drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, attrs);
3022 },
3023
3024 'bpmn:Task': function(parentGfx, element) {
3025 var attrs = {
3026 fill: getFillColor(element, defaultFillColor),
3027 stroke: getStrokeColor(element, defaultStrokeColor)
3028 };
3029
3030 var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
3031
3032 renderEmbeddedLabel(parentGfx, element, 'center-middle');
3033 attachTaskMarkers(parentGfx, element);
3034
3035 return rect;
3036 },
3037 'bpmn:ServiceTask': function(parentGfx, element) {
3038 var task = renderer('bpmn:Task')(parentGfx, element);
3039
3040 var pathDataBG = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
3041 abspos: {
3042 x: 12,
3043 y: 18
3044 }
3045 });
3046
3047 /* service bg */ drawPath(parentGfx, pathDataBG, {
3048 strokeWidth: 1,
3049 fill: getFillColor(element, defaultFillColor),
3050 stroke: getStrokeColor(element, defaultStrokeColor)
3051 });
3052
3053 var fillPathData = pathMap.getScaledPath('TASK_TYPE_SERVICE_FILL', {
3054 abspos: {
3055 x: 17.2,
3056 y: 18
3057 }
3058 });
3059
3060 /* service fill */ drawPath(parentGfx, fillPathData, {
3061 strokeWidth: 0,
3062 fill: getFillColor(element, defaultFillColor)
3063 });
3064
3065 var pathData = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
3066 abspos: {
3067 x: 17,
3068 y: 22
3069 }
3070 });
3071
3072 /* service */ drawPath(parentGfx, pathData, {
3073 strokeWidth: 1,
3074 fill: getFillColor(element, defaultFillColor),
3075 stroke: getStrokeColor(element, defaultStrokeColor)
3076 });
3077
3078 return task;
3079 },
3080 'bpmn:UserTask': function(parentGfx, element) {
3081 var task = renderer('bpmn:Task')(parentGfx, element);
3082
3083 var x = 15;
3084 var y = 12;
3085
3086 var pathData = pathMap.getScaledPath('TASK_TYPE_USER_1', {
3087 abspos: {
3088 x: x,
3089 y: y
3090 }
3091 });
3092
3093 /* user path */ drawPath(parentGfx, pathData, {
3094 strokeWidth: 0.5,
3095 fill: getFillColor(element, defaultFillColor),
3096 stroke: getStrokeColor(element, defaultStrokeColor)
3097 });
3098
3099 var pathData2 = pathMap.getScaledPath('TASK_TYPE_USER_2', {
3100 abspos: {
3101 x: x,
3102 y: y
3103 }
3104 });
3105
3106 /* user2 path */ drawPath(parentGfx, pathData2, {
3107 strokeWidth: 0.5,
3108 fill: getFillColor(element, defaultFillColor),
3109 stroke: getStrokeColor(element, defaultStrokeColor)
3110 });
3111
3112 var pathData3 = pathMap.getScaledPath('TASK_TYPE_USER_3', {
3113 abspos: {
3114 x: x,
3115 y: y
3116 }
3117 });
3118
3119 /* user3 path */ drawPath(parentGfx, pathData3, {
3120 strokeWidth: 0.5,
3121 fill: getStrokeColor(element, defaultStrokeColor),
3122 stroke: getStrokeColor(element, defaultStrokeColor)
3123 });
3124
3125 return task;
3126 },
3127 'bpmn:ManualTask': function(parentGfx, element) {
3128 var task = renderer('bpmn:Task')(parentGfx, element);
3129
3130 var pathData = pathMap.getScaledPath('TASK_TYPE_MANUAL', {
3131 abspos: {
3132 x: 17,
3133 y: 15
3134 }
3135 });
3136
3137 /* manual path */ drawPath(parentGfx, pathData, {
3138 strokeWidth: 0.5, // 0.25,
3139 fill: getFillColor(element, defaultFillColor),
3140 stroke: getStrokeColor(element, defaultStrokeColor)
3141 });
3142
3143 return task;
3144 },
3145 'bpmn:SendTask': function(parentGfx, element) {
3146 var task = renderer('bpmn:Task')(parentGfx, element);
3147
3148 var pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
3149 xScaleFactor: 1,
3150 yScaleFactor: 1,
3151 containerWidth: 21,
3152 containerHeight: 14,
3153 position: {
3154 mx: 0.285,
3155 my: 0.357
3156 }
3157 });
3158
3159 /* send path */ drawPath(parentGfx, pathData, {
3160 strokeWidth: 1,
3161 fill: getStrokeColor(element, defaultStrokeColor),
3162 stroke: getFillColor(element, defaultFillColor)
3163 });
3164
3165 return task;
3166 },
3167 'bpmn:ReceiveTask' : function(parentGfx, element) {
3168 var semantic = getSemantic(element);
3169
3170 var task = renderer('bpmn:Task')(parentGfx, element);
3171 var pathData;
3172
3173 if (semantic.instantiate) {
3174 drawCircle(parentGfx, 28, 28, 20 * 0.22, { strokeWidth: 1 });
3175
3176 pathData = pathMap.getScaledPath('TASK_TYPE_INSTANTIATING_SEND', {
3177 abspos: {
3178 x: 7.77,
3179 y: 9.52
3180 }
3181 });
3182 } else {
3183
3184 pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
3185 xScaleFactor: 0.9,
3186 yScaleFactor: 0.9,
3187 containerWidth: 21,
3188 containerHeight: 14,
3189 position: {
3190 mx: 0.3,
3191 my: 0.4
3192 }
3193 });
3194 }
3195
3196 /* receive path */ drawPath(parentGfx, pathData, {
3197 strokeWidth: 1,
3198 fill: getFillColor(element, defaultFillColor),
3199 stroke: getStrokeColor(element, defaultStrokeColor)
3200 });
3201
3202 return task;
3203 },
3204 'bpmn:ScriptTask': function(parentGfx, element) {
3205 var task = renderer('bpmn:Task')(parentGfx, element);
3206
3207 var pathData = pathMap.getScaledPath('TASK_TYPE_SCRIPT', {
3208 abspos: {
3209 x: 15,
3210 y: 20
3211 }
3212 });
3213
3214 /* script path */ drawPath(parentGfx, pathData, {
3215 strokeWidth: 1,
3216 stroke: getStrokeColor(element, defaultStrokeColor)
3217 });
3218
3219 return task;
3220 },
3221 'bpmn:BusinessRuleTask': function(parentGfx, element) {
3222 var task = renderer('bpmn:Task')(parentGfx, element);
3223
3224 var headerPathData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_HEADER', {
3225 abspos: {
3226 x: 8,
3227 y: 8
3228 }
3229 });
3230
3231 var businessHeaderPath = drawPath(parentGfx, headerPathData);
3232 attr(businessHeaderPath, {
3233 strokeWidth: 1,
3234 fill: getFillColor(element, '#aaaaaa'),
3235 stroke: getStrokeColor(element, defaultStrokeColor)
3236 });
3237
3238 var headerData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_MAIN', {
3239 abspos: {
3240 x: 8,
3241 y: 8
3242 }
3243 });
3244
3245 var businessPath = drawPath(parentGfx, headerData);
3246 attr(businessPath, {
3247 strokeWidth: 1,
3248 stroke: getStrokeColor(element, defaultStrokeColor)
3249 });
3250
3251 return task;
3252 },
3253 'bpmn:SubProcess': function(parentGfx, element, attrs) {
3254 attrs = assign({
3255 fill: getFillColor(element, defaultFillColor),
3256 stroke: getStrokeColor(element, defaultStrokeColor)
3257 }, attrs);
3258
3259 var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
3260
3261 var expanded = isExpanded(element);
3262
3263 if (isEventSubProcess(element)) {
3264 attr(rect, {
3265 strokeDasharray: '1,2'
3266 });
3267 }
3268
3269 renderEmbeddedLabel(parentGfx, element, expanded ? 'center-top' : 'center-middle');
3270
3271 if (expanded) {
3272 attachTaskMarkers(parentGfx, element);
3273 } else {
3274 attachTaskMarkers(parentGfx, element, ['SubProcessMarker']);
3275 }
3276
3277 return rect;
3278 },
3279 'bpmn:AdHocSubProcess': function(parentGfx, element) {
3280 return renderer('bpmn:SubProcess')(parentGfx, element);
3281 },
3282 'bpmn:Transaction': function(parentGfx, element) {
3283 var outer = renderer('bpmn:SubProcess')(parentGfx, element);
3284
3285 var innerAttrs = styles.style([ 'no-fill', 'no-events' ], {
3286 stroke: getStrokeColor(element, defaultStrokeColor)
3287 });
3288
3289 /* inner path */ drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS - 2, INNER_OUTER_DIST, innerAttrs);
3290
3291 return outer;
3292 },
3293 'bpmn:CallActivity': function(parentGfx, element) {
3294 return renderer('bpmn:SubProcess')(parentGfx, element, {
3295 strokeWidth: 5
3296 });
3297 },
3298 'bpmn:Participant': function(parentGfx, element) {
3299
3300 var attrs = {
3301 fillOpacity: DEFAULT_FILL_OPACITY,
3302 fill: getFillColor(element, defaultFillColor),
3303 stroke: getStrokeColor(element, defaultStrokeColor)
3304 };
3305
3306 var lane = renderer('bpmn:Lane')(parentGfx, element, attrs);
3307
3308 var expandedPool = isExpanded(element);
3309
3310 if (expandedPool) {
3311 drawLine(parentGfx, [
3312 { x: 30, y: 0 },
3313 { x: 30, y: element.height }
3314 ], {
3315 stroke: getStrokeColor(element, defaultStrokeColor)
3316 });
3317 var text = getSemantic(element).name;
3318 renderLaneLabel(parentGfx, text, element);
3319 } else {
3320
3321 // Collapsed pool draw text inline
3322 var text2 = getSemantic(element).name;
3323 renderLabel(parentGfx, text2, {
3324 box: element, align: 'center-middle',
3325 style: {
3326 fill: getStrokeColor(element, defaultStrokeColor)
3327 }
3328 });
3329 }
3330
3331 var participantMultiplicity = !!(getSemantic(element).participantMultiplicity);
3332
3333 if (participantMultiplicity) {
3334 renderer('ParticipantMultiplicityMarker')(parentGfx, element);
3335 }
3336
3337 return lane;
3338 },
3339 'bpmn:Lane': function(parentGfx, element, attrs) {
3340 var rect = drawRect(parentGfx, element.width, element.height, 0, assign({
3341 fill: getFillColor(element, defaultFillColor),
3342 fillOpacity: HIGH_FILL_OPACITY,
3343 stroke: getStrokeColor(element, defaultStrokeColor)
3344 }, attrs));
3345
3346 var semantic = getSemantic(element);
3347
3348 if (semantic.$type === 'bpmn:Lane') {
3349 var text = semantic.name;
3350 renderLaneLabel(parentGfx, text, element);
3351 }
3352
3353 return rect;
3354 },
3355 'bpmn:InclusiveGateway': function(parentGfx, element) {
3356 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3357
3358 /* circle path */
3359 drawCircle(parentGfx, element.width, element.height, element.height * 0.24, {
3360 strokeWidth: 2.5,
3361 fill: getFillColor(element, defaultFillColor),
3362 stroke: getStrokeColor(element, defaultStrokeColor)
3363 });
3364
3365 return diamond;
3366 },
3367 'bpmn:ExclusiveGateway': function(parentGfx, element) {
3368 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3369
3370 var pathData = pathMap.getScaledPath('GATEWAY_EXCLUSIVE', {
3371 xScaleFactor: 0.4,
3372 yScaleFactor: 0.4,
3373 containerWidth: element.width,
3374 containerHeight: element.height,
3375 position: {
3376 mx: 0.32,
3377 my: 0.3
3378 }
3379 });
3380
3381 if ((getDi(element).isMarkerVisible)) {
3382 drawPath(parentGfx, pathData, {
3383 strokeWidth: 1,
3384 fill: getStrokeColor(element, defaultStrokeColor),
3385 stroke: getStrokeColor(element, defaultStrokeColor)
3386 });
3387 }
3388
3389 return diamond;
3390 },
3391 'bpmn:ComplexGateway': function(parentGfx, element) {
3392 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3393
3394 var pathData = pathMap.getScaledPath('GATEWAY_COMPLEX', {
3395 xScaleFactor: 0.5,
3396 yScaleFactor:0.5,
3397 containerWidth: element.width,
3398 containerHeight: element.height,
3399 position: {
3400 mx: 0.46,
3401 my: 0.26
3402 }
3403 });
3404
3405 /* complex path */ drawPath(parentGfx, pathData, {
3406 strokeWidth: 1,
3407 fill: getStrokeColor(element, defaultStrokeColor),
3408 stroke: getStrokeColor(element, defaultStrokeColor)
3409 });
3410
3411 return diamond;
3412 },
3413 'bpmn:ParallelGateway': function(parentGfx, element) {
3414 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3415
3416 var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
3417 xScaleFactor: 0.6,
3418 yScaleFactor:0.6,
3419 containerWidth: element.width,
3420 containerHeight: element.height,
3421 position: {
3422 mx: 0.46,
3423 my: 0.2
3424 }
3425 });
3426
3427 /* parallel path */ drawPath(parentGfx, pathData, {
3428 strokeWidth: 1,
3429 fill: getStrokeColor(element, defaultStrokeColor),
3430 stroke: getStrokeColor(element, defaultStrokeColor)
3431 });
3432
3433 return diamond;
3434 },
3435 'bpmn:EventBasedGateway': function(parentGfx, element) {
3436
3437 var semantic = getSemantic(element);
3438
3439 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
3440
3441 /* outer circle path */ drawCircle(parentGfx, element.width, element.height, element.height * 0.20, {
3442 strokeWidth: 1,
3443 fill: 'none',
3444 stroke: getStrokeColor(element, defaultStrokeColor)
3445 });
3446
3447 var type = semantic.eventGatewayType;
3448 var instantiate = !!semantic.instantiate;
3449
3450 function drawEvent() {
3451
3452 var pathData = pathMap.getScaledPath('GATEWAY_EVENT_BASED', {
3453 xScaleFactor: 0.18,
3454 yScaleFactor: 0.18,
3455 containerWidth: element.width,
3456 containerHeight: element.height,
3457 position: {
3458 mx: 0.36,
3459 my: 0.44
3460 }
3461 });
3462
3463 var attrs = {
3464 strokeWidth: 2,
3465 fill: getFillColor(element, 'none'),
3466 stroke: getStrokeColor(element, defaultStrokeColor)
3467 };
3468
3469 /* event path */ drawPath(parentGfx, pathData, attrs);
3470 }
3471
3472 if (type === 'Parallel') {
3473
3474 var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
3475 xScaleFactor: 0.4,
3476 yScaleFactor:0.4,
3477 containerWidth: element.width,
3478 containerHeight: element.height,
3479 position: {
3480 mx: 0.474,
3481 my: 0.296
3482 }
3483 });
3484
3485 var parallelPath = drawPath(parentGfx, pathData);
3486 attr(parallelPath, {
3487 strokeWidth: 1,
3488 fill: 'none'
3489 });
3490 } else if (type === 'Exclusive') {
3491
3492 if (!instantiate) {
3493 var innerCircle = drawCircle(parentGfx, element.width, element.height, element.height * 0.26);
3494 attr(innerCircle, {
3495 strokeWidth: 1,
3496 fill: 'none',
3497 stroke: getStrokeColor(element, defaultStrokeColor)
3498 });
3499 }
3500
3501 drawEvent();
3502 }
3503
3504
3505 return diamond;
3506 },
3507 'bpmn:Gateway': function(parentGfx, element) {
3508 var attrs = {
3509 fill: getFillColor(element, defaultFillColor),
3510 fillOpacity: DEFAULT_FILL_OPACITY,
3511 stroke: getStrokeColor(element, defaultStrokeColor)
3512 };
3513
3514 return drawDiamond(parentGfx, element.width, element.height, attrs);
3515 },
3516 'bpmn:SequenceFlow': function(parentGfx, element) {
3517 var pathData = createPathFromConnection(element);
3518
3519 var fill = getFillColor(element, defaultFillColor),
3520 stroke = getStrokeColor(element, defaultStrokeColor);
3521
3522 var attrs = {
3523 strokeLinejoin: 'round',
3524 markerEnd: marker('sequenceflow-end', fill, stroke),
3525 stroke: getStrokeColor(element, defaultStrokeColor)
3526 };
3527
3528 var path = drawPath(parentGfx, pathData, attrs);
3529
3530 var sequenceFlow = getSemantic(element);
3531
3532 var source;
3533
3534 if (element.source) {
3535 source = element.source.businessObject;
3536
3537 // conditional flow marker
3538 if (sequenceFlow.conditionExpression && source.$instanceOf('bpmn:Activity')) {
3539 attr(path, {
3540 markerStart: marker('conditional-flow-marker', fill, stroke)
3541 });
3542 }
3543
3544 // default marker
3545 if (source.default && (source.$instanceOf('bpmn:Gateway') || source.$instanceOf('bpmn:Activity')) &&
3546 source.default === sequenceFlow) {
3547 attr(path, {
3548 markerStart: marker('conditional-default-flow-marker', fill, stroke)
3549 });
3550 }
3551 }
3552
3553 return path;
3554 },
3555 'bpmn:Association': function(parentGfx, element, attrs) {
3556
3557 var semantic = getSemantic(element);
3558
3559 var fill = getFillColor(element, defaultFillColor),
3560 stroke = getStrokeColor(element, defaultStrokeColor);
3561
3562 attrs = assign({
3563 strokeDasharray: '0.5, 5',
3564 strokeLinecap: 'round',
3565 strokeLinejoin: 'round',
3566 stroke: getStrokeColor(element, defaultStrokeColor)
3567 }, attrs || {});
3568
3569 if (semantic.associationDirection === 'One' ||
3570 semantic.associationDirection === 'Both') {
3571 attrs.markerEnd = marker('association-end', fill, stroke);
3572 }
3573
3574 if (semantic.associationDirection === 'Both') {
3575 attrs.markerStart = marker('association-start', fill, stroke);
3576 }
3577
3578 return drawLine(parentGfx, element.waypoints, attrs);
3579 },
3580 'bpmn:DataInputAssociation': function(parentGfx, element) {
3581 var fill = getFillColor(element, defaultFillColor),
3582 stroke = getStrokeColor(element, defaultStrokeColor);
3583
3584 return renderer('bpmn:Association')(parentGfx, element, {
3585 markerEnd: marker('association-end', fill, stroke)
3586 });
3587 },
3588 'bpmn:DataOutputAssociation': function(parentGfx, element) {
3589 var fill = getFillColor(element, defaultFillColor),
3590 stroke = getStrokeColor(element, defaultStrokeColor);
3591
3592 return renderer('bpmn:Association')(parentGfx, element, {
3593 markerEnd: marker('association-end', fill, stroke)
3594 });
3595 },
3596 'bpmn:MessageFlow': function(parentGfx, element) {
3597
3598 var semantic = getSemantic(element),
3599 di = getDi(element);
3600
3601 var fill = getFillColor(element, defaultFillColor),
3602 stroke = getStrokeColor(element, defaultStrokeColor);
3603
3604 var pathData = createPathFromConnection(element);
3605
3606 var attrs = {
3607 markerEnd: marker('messageflow-end', fill, stroke),
3608 markerStart: marker('messageflow-start', fill, stroke),
3609 strokeDasharray: '10, 12',
3610 strokeLinecap: 'round',
3611 strokeLinejoin: 'round',
3612 strokeWidth: '1.5px',
3613 stroke: getStrokeColor(element, defaultStrokeColor)
3614 };
3615
3616 var path = drawPath(parentGfx, pathData, attrs);
3617
3618 if (semantic.messageRef) {
3619 var midPoint = path.getPointAtLength(path.getTotalLength() / 2);
3620
3621 var markerPathData = pathMap.getScaledPath('MESSAGE_FLOW_MARKER', {
3622 abspos: {
3623 x: midPoint.x,
3624 y: midPoint.y
3625 }
3626 });
3627
3628 var messageAttrs = { strokeWidth: 1 };
3629
3630 if (di.messageVisibleKind === 'initiating') {
3631 messageAttrs.fill = 'white';
3632 messageAttrs.stroke = 'black';
3633 } else {
3634 messageAttrs.fill = '#888';
3635 messageAttrs.stroke = 'white';
3636 }
3637
3638 drawPath(parentGfx, markerPathData, messageAttrs);
3639 }
3640
3641 return path;
3642 },
3643 'bpmn:DataObject': function(parentGfx, element) {
3644 var pathData = pathMap.getScaledPath('DATA_OBJECT_PATH', {
3645 xScaleFactor: 1,
3646 yScaleFactor: 1,
3647 containerWidth: element.width,
3648 containerHeight: element.height,
3649 position: {
3650 mx: 0.474,
3651 my: 0.296
3652 }
3653 });
3654
3655 var elementObject = drawPath(parentGfx, pathData, {
3656 fill: getFillColor(element, defaultFillColor),
3657 fillOpacity: DEFAULT_FILL_OPACITY,
3658 stroke: getStrokeColor(element, defaultStrokeColor)
3659 });
3660
3661 var semantic = getSemantic(element);
3662
3663 if (isCollection(semantic)) {
3664 renderDataItemCollection(parentGfx, element);
3665 }
3666
3667 return elementObject;
3668 },
3669 'bpmn:DataObjectReference': as('bpmn:DataObject'),
3670 'bpmn:DataInput': function(parentGfx, element) {
3671
3672 var arrowPathData = pathMap.getRawPath('DATA_ARROW');
3673
3674 // page
3675 var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
3676
3677 /* input arrow path */ drawPath(parentGfx, arrowPathData, { strokeWidth: 1 });
3678
3679 return elementObject;
3680 },
3681 'bpmn:DataOutput': function(parentGfx, element) {
3682 var arrowPathData = pathMap.getRawPath('DATA_ARROW');
3683
3684 // page
3685 var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
3686
3687 /* output arrow path */ drawPath(parentGfx, arrowPathData, {
3688 strokeWidth: 1,
3689 fill: 'black'
3690 });
3691
3692 return elementObject;
3693 },
3694 'bpmn:DataStoreReference': function(parentGfx, element) {
3695 var DATA_STORE_PATH = pathMap.getScaledPath('DATA_STORE', {
3696 xScaleFactor: 1,
3697 yScaleFactor: 1,
3698 containerWidth: element.width,
3699 containerHeight: element.height,
3700 position: {
3701 mx: 0,
3702 my: 0.133
3703 }
3704 });
3705
3706 var elementStore = drawPath(parentGfx, DATA_STORE_PATH, {
3707 strokeWidth: 2,
3708 fill: getFillColor(element, defaultFillColor),
3709 fillOpacity: DEFAULT_FILL_OPACITY,
3710 stroke: getStrokeColor(element, defaultStrokeColor)
3711 });
3712
3713 return elementStore;
3714 },
3715 'bpmn:BoundaryEvent': function(parentGfx, element) {
3716
3717 var semantic = getSemantic(element),
3718 cancel = semantic.cancelActivity;
3719
3720 var attrs = {
3721 strokeWidth: 1,
3722 fill: getFillColor(element, defaultFillColor),
3723 stroke: getStrokeColor(element, defaultStrokeColor)
3724 };
3725
3726 if (!cancel) {
3727 attrs.strokeDasharray = '6';
3728 attrs.strokeLinecap = 'round';
3729 }
3730
3731 // apply fillOpacity
3732 var outerAttrs = assign({}, attrs, {
3733 fillOpacity: 1
3734 });
3735
3736 // apply no-fill
3737 var innerAttrs = assign({}, attrs, {
3738 fill: 'none'
3739 });
3740
3741 var outer = renderer('bpmn:Event')(parentGfx, element, outerAttrs);
3742
3743 /* inner path */ drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, innerAttrs);
3744
3745 renderEventContent(element, parentGfx);
3746
3747 return outer;
3748 },
3749 'bpmn:Group': function(parentGfx, element) {
3750
3751 var group = drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, {
3752 stroke: getStrokeColor(element, defaultStrokeColor),
3753 strokeWidth: 1,
3754 strokeDasharray: '8,3,1,3',
3755 fill: 'none',
3756 pointerEvents: 'none'
3757 });
3758
3759 return group;
3760 },
3761 'label': function(parentGfx, element) {
3762 return renderExternalLabel(parentGfx, element);
3763 },
3764 'bpmn:TextAnnotation': function(parentGfx, element) {
3765 var style = {
3766 'fill': 'none',
3767 'stroke': 'none'
3768 };
3769
3770 var textElement = drawRect(parentGfx, element.width, element.height, 0, 0, style);
3771
3772 var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', {
3773 xScaleFactor: 1,
3774 yScaleFactor: 1,
3775 containerWidth: element.width,
3776 containerHeight: element.height,
3777 position: {
3778 mx: 0.0,
3779 my: 0.0
3780 }
3781 });
3782
3783 drawPath(parentGfx, textPathData, {
3784 stroke: getStrokeColor(element, defaultStrokeColor)
3785 });
3786
3787 var text = getSemantic(element).text || '';
3788 renderLabel(parentGfx, text, {
3789 box: element,
3790 align: 'left-top',
3791 padding: 5,
3792 style: {
3793 fill: getStrokeColor(element, defaultStrokeColor)
3794 }
3795 });
3796
3797 return textElement;
3798 },
3799 'ParticipantMultiplicityMarker': function(parentGfx, element) {
3800 var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
3801 xScaleFactor: 1,
3802 yScaleFactor: 1,
3803 containerWidth: element.width,
3804 containerHeight: element.height,
3805 position: {
3806 mx: ((element.width / 2) / element.width),
3807 my: (element.height - 15) / element.height
3808 }
3809 });
3810
3811 drawMarker('participant-multiplicity', parentGfx, markerPath, {
3812 strokeWidth: 1,
3813 fill: getFillColor(element, defaultFillColor),
3814 stroke: getStrokeColor(element, defaultStrokeColor)
3815 });
3816 },
3817 'SubProcessMarker': function(parentGfx, element) {
3818 var markerRect = drawRect(parentGfx, 14, 14, 0, {
3819 strokeWidth: 1,
3820 fill: getFillColor(element, defaultFillColor),
3821 stroke: getStrokeColor(element, defaultStrokeColor)
3822 });
3823
3824 // Process marker is placed in the middle of the box
3825 // therefore fixed values can be used here
3826 translate(markerRect, element.width / 2 - 7.5, element.height - 20);
3827
3828 var markerPath = pathMap.getScaledPath('MARKER_SUB_PROCESS', {
3829 xScaleFactor: 1.5,
3830 yScaleFactor: 1.5,
3831 containerWidth: element.width,
3832 containerHeight: element.height,
3833 position: {
3834 mx: (element.width / 2 - 7.5) / element.width,
3835 my: (element.height - 20) / element.height
3836 }
3837 });
3838
3839 drawMarker('sub-process', parentGfx, markerPath, {
3840 fill: getFillColor(element, defaultFillColor),
3841 stroke: getStrokeColor(element, defaultStrokeColor)
3842 });
3843 },
3844 'ParallelMarker': function(parentGfx, element, position) {
3845 var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
3846 xScaleFactor: 1,
3847 yScaleFactor: 1,
3848 containerWidth: element.width,
3849 containerHeight: element.height,
3850 position: {
3851 mx: ((element.width / 2 + position.parallel) / element.width),
3852 my: (element.height - 20) / element.height
3853 }
3854 });
3855
3856 drawMarker('parallel', parentGfx, markerPath, {
3857 fill: getFillColor(element, defaultFillColor),
3858 stroke: getStrokeColor(element, defaultStrokeColor)
3859 });
3860 },
3861 'SequentialMarker': function(parentGfx, element, position) {
3862 var markerPath = pathMap.getScaledPath('MARKER_SEQUENTIAL', {
3863 xScaleFactor: 1,
3864 yScaleFactor: 1,
3865 containerWidth: element.width,
3866 containerHeight: element.height,
3867 position: {
3868 mx: ((element.width / 2 + position.seq) / element.width),
3869 my: (element.height - 19) / element.height
3870 }
3871 });
3872
3873 drawMarker('sequential', parentGfx, markerPath, {
3874 fill: getFillColor(element, defaultFillColor),
3875 stroke: getStrokeColor(element, defaultStrokeColor)
3876 });
3877 },
3878 'CompensationMarker': function(parentGfx, element, position) {
3879 var markerMath = pathMap.getScaledPath('MARKER_COMPENSATION', {
3880 xScaleFactor: 1,
3881 yScaleFactor: 1,
3882 containerWidth: element.width,
3883 containerHeight: element.height,
3884 position: {
3885 mx: ((element.width / 2 + position.compensation) / element.width),
3886 my: (element.height - 13) / element.height
3887 }
3888 });
3889
3890 drawMarker('compensation', parentGfx, markerMath, {
3891 strokeWidth: 1,
3892 fill: getFillColor(element, defaultFillColor),
3893 stroke: getStrokeColor(element, defaultStrokeColor)
3894 });
3895 },
3896 'LoopMarker': function(parentGfx, element, position) {
3897 var markerPath = pathMap.getScaledPath('MARKER_LOOP', {
3898 xScaleFactor: 1,
3899 yScaleFactor: 1,
3900 containerWidth: element.width,
3901 containerHeight: element.height,
3902 position: {
3903 mx: ((element.width / 2 + position.loop) / element.width),
3904 my: (element.height - 7) / element.height
3905 }
3906 });
3907
3908 drawMarker('loop', parentGfx, markerPath, {
3909 strokeWidth: 1,
3910 fill: getFillColor(element, defaultFillColor),
3911 stroke: getStrokeColor(element, defaultStrokeColor),
3912 strokeLinecap: 'round',
3913 strokeMiterlimit: 0.5
3914 });
3915 },
3916 'AdhocMarker': function(parentGfx, element, position) {
3917 var markerPath = pathMap.getScaledPath('MARKER_ADHOC', {
3918 xScaleFactor: 1,
3919 yScaleFactor: 1,
3920 containerWidth: element.width,
3921 containerHeight: element.height,
3922 position: {
3923 mx: ((element.width / 2 + position.adhoc) / element.width),
3924 my: (element.height - 15) / element.height
3925 }
3926 });
3927
3928 drawMarker('adhoc', parentGfx, markerPath, {
3929 strokeWidth: 1,
3930 fill: getStrokeColor(element, defaultStrokeColor),
3931 stroke: getStrokeColor(element, defaultStrokeColor)
3932 });
3933 }
3934 };
3935
3936 function attachTaskMarkers(parentGfx, element, taskMarkers) {
3937 var obj = getSemantic(element);
3938
3939 var subprocess = taskMarkers && taskMarkers.indexOf('SubProcessMarker') !== -1;
3940 var position;
3941
3942 if (subprocess) {
3943 position = {
3944 seq: -21,
3945 parallel: -22,
3946 compensation: -42,
3947 loop: -18,
3948 adhoc: 10
3949 };
3950 } else {
3951 position = {
3952 seq: -3,
3953 parallel: -6,
3954 compensation: -27,
3955 loop: 0,
3956 adhoc: 10
3957 };
3958 }
3959
3960 forEach(taskMarkers, function(marker) {
3961 renderer(marker)(parentGfx, element, position);
3962 });
3963
3964 if (obj.isForCompensation) {
3965 renderer('CompensationMarker')(parentGfx, element, position);
3966 }
3967
3968 if (obj.$type === 'bpmn:AdHocSubProcess') {
3969 renderer('AdhocMarker')(parentGfx, element, position);
3970 }
3971
3972 var loopCharacteristics = obj.loopCharacteristics,
3973 isSequential = loopCharacteristics && loopCharacteristics.isSequential;
3974
3975 if (loopCharacteristics) {
3976
3977 if (isSequential === undefined) {
3978 renderer('LoopMarker')(parentGfx, element, position);
3979 }
3980
3981 if (isSequential === false) {
3982 renderer('ParallelMarker')(parentGfx, element, position);
3983 }
3984
3985 if (isSequential === true) {
3986 renderer('SequentialMarker')(parentGfx, element, position);
3987 }
3988 }
3989 }
3990
3991 function renderDataItemCollection(parentGfx, element) {
3992
3993 var yPosition = (element.height - 16) / element.height;
3994
3995 var pathData = pathMap.getScaledPath('DATA_OBJECT_COLLECTION_PATH', {
3996 xScaleFactor: 1,
3997 yScaleFactor: 1,
3998 containerWidth: element.width,
3999 containerHeight: element.height,
4000 position: {
4001 mx: 0.451,
4002 my: yPosition
4003 }
4004 });
4005
4006 /* collection path */ drawPath(parentGfx, pathData, {
4007 strokeWidth: 2
4008 });
4009 }
4010
4011
4012 // extension API, use at your own risk
4013 this._drawPath = drawPath;
4014
4015 }
4016
4017
4018 inherits_browser(BpmnRenderer, BaseRenderer);
4019
4020 BpmnRenderer.$inject = [
4021 'config.bpmnRenderer',
4022 'eventBus',
4023 'styles',
4024 'pathMap',
4025 'canvas',
4026 'textRenderer'
4027 ];
4028
4029
4030 BpmnRenderer.prototype.canRender = function(element) {
4031 return is(element, 'bpmn:BaseElement');
4032 };
4033
4034 BpmnRenderer.prototype.drawShape = 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.drawConnection = function(parentGfx, element) {
4043 var type = element.type;
4044 var h = this.handlers[type];
4045
4046 /* jshint -W040 */
4047 return h(parentGfx, element);
4048 };
4049
4050 BpmnRenderer.prototype.getShapePath = function(element) {
4051
4052 if (is(element, 'bpmn:Event')) {
4053 return getCirclePath(element);
4054 }
4055
4056 if (is(element, 'bpmn:Activity')) {
4057 return getRoundRectPath(element, TASK_BORDER_RADIUS);
4058 }
4059
4060 if (is(element, 'bpmn:Gateway')) {
4061 return getDiamondPath(element);
4062 }
4063
4064 return getRectPath(element);
4065 };
4066
4067 var DEFAULT_BOX_PADDING = 0;
4068
4069 var DEFAULT_LABEL_SIZE = {
4070 width: 150,
4071 height: 50
4072 };
4073
4074
4075 function parseAlign(align) {
4076
4077 var parts = align.split('-');
4078
4079 return {
4080 horizontal: parts[0] || 'center',
4081 vertical: parts[1] || 'top'
4082 };
4083 }
4084
4085 function parsePadding(padding) {
4086
4087 if (isObject(padding)) {
4088 return assign({ top: 0, left: 0, right: 0, bottom: 0 }, padding);
4089 } else {
4090 return {
4091 top: padding,
4092 left: padding,
4093 right: padding,
4094 bottom: padding
4095 };
4096 }
4097 }
4098
4099 function getTextBBox(text, fakeText) {
4100
4101 fakeText.textContent = text;
4102
4103 var textBBox;
4104
4105 try {
4106 var bbox,
4107 emptyLine = text === '';
4108
4109 // add dummy text, when line is empty to
4110 // determine correct height
4111 fakeText.textContent = emptyLine ? 'dummy' : text;
4112
4113 textBBox = fakeText.getBBox();
4114
4115 // take text rendering related horizontal
4116 // padding into account
4117 bbox = {
4118 width: textBBox.width + textBBox.x * 2,
4119 height: textBBox.height
4120 };
4121
4122 if (emptyLine) {
4123
4124 // correct width
4125 bbox.width = 0;
4126 }
4127
4128 return bbox;
4129 } catch (e) {
4130 return { width: 0, height: 0 };
4131 }
4132 }
4133
4134
4135 /**
4136 * Layout the next line and return the layouted element.
4137 *
4138 * Alters the lines passed.
4139 *
4140 * @param {Array<String>} lines
4141 * @return {Object} the line descriptor, an object { width, height, text }
4142 */
4143 function layoutNext(lines, maxWidth, fakeText) {
4144
4145 var originalLine = lines.shift(),
4146 fitLine = originalLine;
4147
4148 var textBBox;
4149
4150 for (;;) {
4151 textBBox = getTextBBox(fitLine, fakeText);
4152
4153 textBBox.width = fitLine ? textBBox.width : 0;
4154
4155 // try to fit
4156 if (fitLine === ' ' || fitLine === '' || textBBox.width < Math.round(maxWidth) || fitLine.length < 2) {
4157 return fit(lines, fitLine, originalLine, textBBox);
4158 }
4159
4160 fitLine = shortenLine(fitLine, textBBox.width, maxWidth);
4161 }
4162 }
4163
4164 function fit(lines, fitLine, originalLine, textBBox) {
4165 if (fitLine.length < originalLine.length) {
4166 var remainder = originalLine.slice(fitLine.length).trim();
4167
4168 lines.unshift(remainder);
4169 }
4170
4171 return {
4172 width: textBBox.width,
4173 height: textBBox.height,
4174 text: fitLine
4175 };
4176 }
4177
4178
4179 /**
4180 * Shortens a line based on spacing and hyphens.
4181 * Returns the shortened result on success.
4182 *
4183 * @param {String} line
4184 * @param {Number} maxLength the maximum characters of the string
4185 * @return {String} the shortened string
4186 */
4187 function semanticShorten(line, maxLength) {
4188 var parts = line.split(/(\s|-)/g),
4189 part,
4190 shortenedParts = [],
4191 length = 0;
4192
4193 // try to shorten via spaces + hyphens
4194 if (parts.length > 1) {
4195 while ((part = parts.shift())) {
4196 if (part.length + length < maxLength) {
4197 shortenedParts.push(part);
4198 length += part.length;
4199 } else {
4200
4201 // remove previous part, too if hyphen does not fit anymore
4202 if (part === '-') {
4203 shortenedParts.pop();
4204 }
4205
4206 break;
4207 }
4208 }
4209 }
4210
4211 return shortenedParts.join('');
4212 }
4213
4214
4215 function shortenLine(line, width, maxWidth) {
4216 var length = Math.max(line.length * (maxWidth / width), 1);
4217
4218 // try to shorten semantically (i.e. based on spaces and hyphens)
4219 var shortenedLine = semanticShorten(line, length);
4220
4221 if (!shortenedLine) {
4222
4223 // force shorten by cutting the long word
4224 shortenedLine = line.slice(0, Math.max(Math.round(length - 1), 1));
4225 }
4226
4227 return shortenedLine;
4228 }
4229
4230
4231 function getHelperSvg() {
4232 var helperSvg = document.getElementById('helper-svg');
4233
4234 if (!helperSvg) {
4235 helperSvg = create('svg');
4236
4237 attr(helperSvg, {
4238 id: 'helper-svg',
4239 width: 0,
4240 height: 0,
4241 style: 'visibility: hidden; position: fixed'
4242 });
4243
4244 document.body.appendChild(helperSvg);
4245 }
4246
4247 return helperSvg;
4248 }
4249
4250
4251 /**
4252 * Creates a new label utility
4253 *
4254 * @param {Object} config
4255 * @param {Dimensions} config.size
4256 * @param {Number} config.padding
4257 * @param {Object} config.style
4258 * @param {String} config.align
4259 */
4260 function Text(config) {
4261
4262 this._config = assign({}, {
4263 size: DEFAULT_LABEL_SIZE,
4264 padding: DEFAULT_BOX_PADDING,
4265 style: {},
4266 align: 'center-top'
4267 }, config || {});
4268 }
4269
4270 /**
4271 * Returns the layouted text as an SVG element.
4272 *
4273 * @param {String} text
4274 * @param {Object} options
4275 *
4276 * @return {SVGElement}
4277 */
4278 Text.prototype.createText = function(text, options) {
4279 return this.layoutText(text, options).element;
4280 };
4281
4282 /**
4283 * Returns a labels layouted dimensions.
4284 *
4285 * @param {String} text to layout
4286 * @param {Object} options
4287 *
4288 * @return {Dimensions}
4289 */
4290 Text.prototype.getDimensions = function(text, options) {
4291 return this.layoutText(text, options).dimensions;
4292 };
4293
4294 /**
4295 * Creates and returns a label and its bounding box.
4296 *
4297 * @method Text#createText
4298 *
4299 * @param {String} text the text to render on the label
4300 * @param {Object} options
4301 * @param {String} options.align how to align in the bounding box.
4302 * Any of { 'center-middle', 'center-top' },
4303 * defaults to 'center-top'.
4304 * @param {String} options.style style to be applied to the text
4305 * @param {boolean} options.fitBox indicates if box will be recalculated to
4306 * fit text
4307 *
4308 * @return {Object} { element, dimensions }
4309 */
4310 Text.prototype.layoutText = function(text, options) {
4311 var box = assign({}, this._config.size, options.box),
4312 style = assign({}, this._config.style, options.style),
4313 align = parseAlign(options.align || this._config.align),
4314 padding = parsePadding(options.padding !== undefined ? options.padding : this._config.padding),
4315 fitBox = options.fitBox || false;
4316
4317 var lineHeight = getLineHeight(style);
4318
4319 var lines = text.split(/\r?\n/g),
4320 layouted = [];
4321
4322 var maxWidth = box.width - padding.left - padding.right;
4323
4324 // ensure correct rendering by attaching helper text node to invisible SVG
4325 var helperText = create('text');
4326 attr(helperText, { x: 0, y: 0 });
4327 attr(helperText, style);
4328
4329 var helperSvg = getHelperSvg();
4330
4331 append(helperSvg, helperText);
4332
4333 while (lines.length) {
4334 layouted.push(layoutNext(lines, maxWidth, helperText));
4335 }
4336
4337 if (align.vertical === 'middle') {
4338 padding.top = padding.bottom = 0;
4339 }
4340
4341 var totalHeight = reduce(layouted, function(sum, line, idx) {
4342 return sum + (lineHeight || line.height);
4343 }, 0) + padding.top + padding.bottom;
4344
4345 var maxLineWidth = reduce(layouted, function(sum, line, idx) {
4346 return line.width > sum ? line.width : sum;
4347 }, 0);
4348
4349 // the y position of the next line
4350 var y = padding.top;
4351
4352 if (align.vertical === 'middle') {
4353 y += (box.height - totalHeight) / 2;
4354 }
4355
4356 // magic number initial offset
4357 y -= (lineHeight || layouted[0].height) / 4;
4358
4359
4360 var textElement = create('text');
4361
4362 attr(textElement, style);
4363
4364 // layout each line taking into account that parent
4365 // shape might resize to fit text size
4366 forEach(layouted, function(line) {
4367
4368 var x;
4369
4370 y += (lineHeight || line.height);
4371
4372 switch (align.horizontal) {
4373 case 'left':
4374 x = padding.left;
4375 break;
4376
4377 case 'right':
4378 x = ((fitBox ? maxLineWidth : maxWidth)
4379 - padding.right - line.width);
4380 break;
4381
4382 default:
4383
4384 // aka center
4385 x = Math.max((((fitBox ? maxLineWidth : maxWidth)
4386 - line.width) / 2 + padding.left), 0);
4387 }
4388
4389 var tspan = create('tspan');
4390 attr(tspan, { x: x, y: y });
4391
4392 tspan.textContent = line.text;
4393
4394 append(textElement, tspan);
4395 });
4396
4397 remove(helperText);
4398
4399 var dimensions = {
4400 width: maxLineWidth,
4401 height: totalHeight
4402 };
4403
4404 return {
4405 dimensions: dimensions,
4406 element: textElement
4407 };
4408 };
4409
4410
4411 function getLineHeight(style) {
4412 if ('fontSize' in style && 'lineHeight' in style) {
4413 return style.lineHeight * parseInt(style.fontSize, 10);
4414 }
4415 }
4416
4417 var DEFAULT_FONT_SIZE = 12;
4418 var LINE_HEIGHT_RATIO = 1.2;
4419
4420 var MIN_TEXT_ANNOTATION_HEIGHT = 30;
4421
4422
4423 function TextRenderer(config) {
4424
4425 var defaultStyle = assign({
4426 fontFamily: 'Arial, sans-serif',
4427 fontSize: DEFAULT_FONT_SIZE,
4428 fontWeight: 'normal',
4429 lineHeight: LINE_HEIGHT_RATIO
4430 }, config && config.defaultStyle || {});
4431
4432 var fontSize = parseInt(defaultStyle.fontSize, 10) - 1;
4433
4434 var externalStyle = assign({}, defaultStyle, {
4435 fontSize: fontSize
4436 }, config && config.externalStyle || {});
4437
4438 var textUtil = new Text({
4439 style: defaultStyle
4440 });
4441
4442 /**
4443 * Get the new bounds of an externally rendered,
4444 * layouted label.
4445 *
4446 * @param {Bounds} bounds
4447 * @param {String} text
4448 *
4449 * @return {Bounds}
4450 */
4451 this.getExternalLabelBounds = function(bounds, text) {
4452
4453 var layoutedDimensions = textUtil.getDimensions(text, {
4454 box: {
4455 width: 90,
4456 height: 30,
4457 x: bounds.width / 2 + bounds.x,
4458 y: bounds.height / 2 + bounds.y
4459 },
4460 style: externalStyle
4461 });
4462
4463 // resize label shape to fit label text
4464 return {
4465 x: Math.round(bounds.x + bounds.width / 2 - layoutedDimensions.width / 2),
4466 y: Math.round(bounds.y),
4467 width: Math.ceil(layoutedDimensions.width),
4468 height: Math.ceil(layoutedDimensions.height)
4469 };
4470
4471 };
4472
4473 /**
4474 * Get the new bounds of text annotation.
4475 *
4476 * @param {Bounds} bounds
4477 * @param {String} text
4478 *
4479 * @return {Bounds}
4480 */
4481 this.getTextAnnotationBounds = function(bounds, text) {
4482
4483 var layoutedDimensions = textUtil.getDimensions(text, {
4484 box: bounds,
4485 style: defaultStyle,
4486 align: 'left-top',
4487 padding: 5
4488 });
4489
4490 return {
4491 x: bounds.x,
4492 y: bounds.y,
4493 width: bounds.width,
4494 height: Math.max(MIN_TEXT_ANNOTATION_HEIGHT, Math.round(layoutedDimensions.height))
4495 };
4496 };
4497
4498 /**
4499 * Create a layouted text element.
4500 *
4501 * @param {String} text
4502 * @param {Object} [options]
4503 *
4504 * @return {SVGElement} rendered text
4505 */
4506 this.createText = function(text, options) {
4507 return textUtil.createText(text, options || {});
4508 };
4509
4510 /**
4511 * Get default text style.
4512 */
4513 this.getDefaultStyle = function() {
4514 return defaultStyle;
4515 };
4516
4517 /**
4518 * Get the external text style.
4519 */
4520 this.getExternalStyle = function() {
4521 return externalStyle;
4522 };
4523
4524 }
4525
4526 TextRenderer.$inject = [
4527 'config.textRenderer'
4528 ];
4529
4530 /**
4531 * Map containing SVG paths needed by BpmnRenderer.
4532 */
4533
4534 function PathMap() {
4535
4536 /**
4537 * Contains a map of path elements
4538 *
4539 * <h1>Path definition</h1>
4540 * A parameterized path is defined like this:
4541 * <pre>
4542 * 'GATEWAY_PARALLEL': {
4543 * d: 'm {mx},{my} {e.x0},0 0,{e.x1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
4544 '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
4545 * height: 17.5,
4546 * width: 17.5,
4547 * heightElements: [2.5, 7.5],
4548 * widthElements: [2.5, 7.5]
4549 * }
4550 * </pre>
4551 * <p>It's important to specify a correct <b>height and width</b> for the path as the scaling
4552 * is based on the ratio between the specified height and width in this object and the
4553 * height and width that is set as scale target (Note x,y coordinates will be scaled with
4554 * individual ratios).</p>
4555 * <p>The '<b>heightElements</b>' and '<b>widthElements</b>' array must contain the values that will be scaled.
4556 * The scaling is based on the computed ratios.
4557 * Coordinates on the y axis should be in the <b>heightElement</b>'s array, they will be scaled using
4558 * the computed ratio coefficient.
4559 * In the parameterized path the scaled values can be accessed through the 'e' object in {} brackets.
4560 * <ul>
4561 * <li>The values for the y axis can be accessed in the path string using {e.y0}, {e.y1}, ....</li>
4562 * <li>The values for the x axis can be accessed in the path string using {e.x0}, {e.x1}, ....</li>
4563 * </ul>
4564 * The numbers x0, x1 respectively y0, y1, ... map to the corresponding array index.
4565 * </p>
4566 */
4567 this.pathMap = {
4568 'EVENT_MESSAGE': {
4569 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}',
4570 height: 36,
4571 width: 36,
4572 heightElements: [6, 14],
4573 widthElements: [10.5, 21]
4574 },
4575 'EVENT_SIGNAL': {
4576 d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x1},0 Z',
4577 height: 36,
4578 width: 36,
4579 heightElements: [18],
4580 widthElements: [10, 20]
4581 },
4582 'EVENT_ESCALATION': {
4583 d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x0},-{e.y1} l -{e.x0},{e.y1} Z',
4584 height: 36,
4585 width: 36,
4586 heightElements: [20, 7],
4587 widthElements: [8]
4588 },
4589 'EVENT_CONDITIONAL': {
4590 d: 'M {e.x0},{e.y0} l {e.x1},0 l 0,{e.y2} l -{e.x1},0 Z ' +
4591 'M {e.x2},{e.y3} l {e.x0},0 ' +
4592 'M {e.x2},{e.y4} l {e.x0},0 ' +
4593 'M {e.x2},{e.y5} l {e.x0},0 ' +
4594 'M {e.x2},{e.y6} l {e.x0},0 ' +
4595 'M {e.x2},{e.y7} l {e.x0},0 ' +
4596 'M {e.x2},{e.y8} l {e.x0},0 ',
4597 height: 36,
4598 width: 36,
4599 heightElements: [8.5, 14.5, 18, 11.5, 14.5, 17.5, 20.5, 23.5, 26.5],
4600 widthElements: [10.5, 14.5, 12.5]
4601 },
4602 'EVENT_LINK': {
4603 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',
4604 height: 36,
4605 width: 36,
4606 heightElements: [4.4375, 6.75, 7.8125],
4607 widthElements: [9.84375, 13.5]
4608 },
4609 'EVENT_ERROR': {
4610 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',
4611 height: 36,
4612 width: 36,
4613 heightElements: [0.023, 8.737, 8.151, 16.564, 10.591, 8.714],
4614 widthElements: [0.085, 6.672, 6.97, 4.273, 5.337, 6.636]
4615 },
4616 'EVENT_CANCEL_45': {
4617 d: 'm {mx},{my} -{e.x1},0 0,{e.x0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
4618 '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
4619 height: 36,
4620 width: 36,
4621 heightElements: [4.75, 8.5],
4622 widthElements: [4.75, 8.5]
4623 },
4624 'EVENT_COMPENSATION': {
4625 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',
4626 height: 36,
4627 width: 36,
4628 heightElements: [6.5, 13, 0.4, 6.1],
4629 widthElements: [9, 9.3, 8.7]
4630 },
4631 'EVENT_TIMER_WH': {
4632 d: 'M {mx},{my} l {e.x0},-{e.y0} m -{e.x0},{e.y0} l {e.x1},{e.y1} ',
4633 height: 36,
4634 width: 36,
4635 heightElements: [10, 2],
4636 widthElements: [3, 7]
4637 },
4638 'EVENT_TIMER_LINE': {
4639 d: 'M {mx},{my} ' +
4640 'm {e.x0},{e.y0} l -{e.x1},{e.y1} ',
4641 height: 36,
4642 width: 36,
4643 heightElements: [10, 3],
4644 widthElements: [0, 0]
4645 },
4646 'EVENT_MULTIPLE': {
4647 d:'m {mx},{my} {e.x1},-{e.y0} {e.x1},{e.y0} -{e.x0},{e.y1} -{e.x2},0 z',
4648 height: 36,
4649 width: 36,
4650 heightElements: [6.28099, 12.56199],
4651 widthElements: [3.1405, 9.42149, 12.56198]
4652 },
4653 'EVENT_PARALLEL_MULTIPLE': {
4654 d:'m {mx},{my} {e.x0},0 0,{e.y1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
4655 '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
4656 height: 36,
4657 width: 36,
4658 heightElements: [2.56228, 7.68683],
4659 widthElements: [2.56228, 7.68683]
4660 },
4661 'GATEWAY_EXCLUSIVE': {
4662 d:'m {mx},{my} {e.x0},{e.y0} {e.x1},{e.y0} {e.x2},0 {e.x4},{e.y2} ' +
4663 '{e.x4},{e.y1} {e.x2},0 {e.x1},{e.y3} {e.x0},{e.y3} ' +
4664 '{e.x3},0 {e.x5},{e.y1} {e.x5},{e.y2} {e.x3},0 z',
4665 height: 17.5,
4666 width: 17.5,
4667 heightElements: [8.5, 6.5312, -6.5312, -8.5],
4668 widthElements: [6.5, -6.5, 3, -3, 5, -5]
4669 },
4670 'GATEWAY_PARALLEL': {
4671 d:'m {mx},{my} 0,{e.y1} -{e.x1},0 0,{e.y0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
4672 '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
4673 height: 30,
4674 width: 30,
4675 heightElements: [5, 12.5],
4676 widthElements: [5, 12.5]
4677 },
4678 'GATEWAY_EVENT_BASED': {
4679 d:'m {mx},{my} {e.x0},{e.y0} {e.x0},{e.y1} {e.x1},{e.y2} {e.x2},0 z',
4680 height: 11,
4681 width: 11,
4682 heightElements: [-6, 6, 12, -12],
4683 widthElements: [9, -3, -12]
4684 },
4685 'GATEWAY_COMPLEX': {
4686 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} ' +
4687 '{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} ' +
4688 '{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} ' +
4689 '-{e.x0},{e.y1} 0,-{e.y0} -{e.x3},0 z',
4690 height: 17.125,
4691 width: 17.125,
4692 heightElements: [4.875, 3.4375, 2.125, 3],
4693 widthElements: [3.4375, 2.125, 4.875, 3]
4694 },
4695 'DATA_OBJECT_PATH': {
4696 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',
4697 height: 61,
4698 width: 51,
4699 heightElements: [10, 50, 60],
4700 widthElements: [10, 40, 50, 60]
4701 },
4702 'DATA_OBJECT_COLLECTION_PATH': {
4703 d:'m {mx}, {my} ' +
4704 'm 0 15 l 0 -15 ' +
4705 'm 4 15 l 0 -15 ' +
4706 'm 4 15 l 0 -15 ',
4707 height: 61,
4708 width: 51,
4709 heightElements: [12],
4710 widthElements: [1, 6, 12, 15]
4711 },
4712 'DATA_ARROW': {
4713 d:'m 5,9 9,0 0,-3 5,5 -5,5 0,-3 -9,0 z',
4714 height: 61,
4715 width: 51,
4716 heightElements: [],
4717 widthElements: []
4718 },
4719 'DATA_STORE': {
4720 d:'m {mx},{my} ' +
4721 'l 0,{e.y2} ' +
4722 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' +
4723 'l 0,-{e.y2} ' +
4724 'c -{e.x0},-{e.y1} -{e.x1},-{e.y1} -{e.x2},0' +
4725 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' +
4726 'm -{e.x2},{e.y0}' +
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 height: 61,
4731 width: 61,
4732 heightElements: [7, 10, 45],
4733 widthElements: [2, 58, 60]
4734 },
4735 'TEXT_ANNOTATION': {
4736 d: 'm {mx}, {my} m 10,0 l -10,0 l 0,{e.y0} l 10,0',
4737 height: 30,
4738 width: 10,
4739 heightElements: [30],
4740 widthElements: [10]
4741 },
4742 'MARKER_SUB_PROCESS': {
4743 d: 'm{mx},{my} m 7,2 l 0,10 m -5,-5 l 10,0',
4744 height: 10,
4745 width: 10,
4746 heightElements: [],
4747 widthElements: []
4748 },
4749 'MARKER_PARALLEL': {
4750 d: 'm{mx},{my} m 3,2 l 0,10 m 3,-10 l 0,10 m 3,-10 l 0,10',
4751 height: 10,
4752 width: 10,
4753 heightElements: [],
4754 widthElements: []
4755 },
4756 'MARKER_SEQUENTIAL': {
4757 d: 'm{mx},{my} m 0,3 l 10,0 m -10,3 l 10,0 m -10,3 l 10,0',
4758 height: 10,
4759 width: 10,
4760 heightElements: [],
4761 widthElements: []
4762 },
4763 'MARKER_COMPENSATION': {
4764 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',
4765 height: 10,
4766 width: 21,
4767 heightElements: [],
4768 widthElements: []
4769 },
4770 'MARKER_LOOP': {
4771 d: 'm {mx},{my} c 3.526979,0 6.386161,-2.829858 6.386161,-6.320661 0,-3.490806 -2.859182,-6.320661 ' +
4772 '-6.386161,-6.320661 -3.526978,0 -6.38616,2.829855 -6.38616,6.320661 0,1.745402 ' +
4773 '0.714797,3.325567 1.870463,4.469381 0.577834,0.571908 1.265885,1.034728 2.029916,1.35457 ' +
4774 'l -0.718163,-3.909793 m 0.718163,3.909793 -3.885211,0.802902',
4775 height: 13.9,
4776 width: 13.7,
4777 heightElements: [],
4778 widthElements: []
4779 },
4780 'MARKER_ADHOC': {
4781 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 ' +
4782 '3.85579,1.15803 5.76082,1.79107 1.06385,0.34139996 2.24454,0.1438 3.18759,-0.43767 0.61743,-0.33642 ' +
4783 '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 ' +
4784 '-3.6918,1.66181996 -1.24459,0.0927 -2.46671,-0.2491 -3.59505,-0.74812 -1.35789,-0.55965 ' +
4785 '-2.75133,-1.33436996 -4.27027,-1.18121996 -1.37741,0.14601 -2.41842,1.13685996 -3.44288,1.96782996 z',
4786 height: 4,
4787 width: 15,
4788 heightElements: [],
4789 widthElements: []
4790 },
4791 'TASK_TYPE_SEND': {
4792 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}',
4793 height: 14,
4794 width: 21,
4795 heightElements: [6, 14],
4796 widthElements: [10.5, 21]
4797 },
4798 'TASK_TYPE_SCRIPT': {
4799 d: 'm {mx},{my} c 9.966553,-6.27276 -8.000926,-7.91932 2.968968,-14.938 l -8.802728,0 ' +
4800 'c -10.969894,7.01868 6.997585,8.66524 -2.968967,14.938 z ' +
4801 'm -7,-12 l 5,0 ' +
4802 'm -4.5,3 l 4.5,0 ' +
4803 'm -3,3 l 5,0' +
4804 'm -4,3 l 5,0',
4805 height: 15,
4806 width: 12.6,
4807 heightElements: [6, 14],
4808 widthElements: [10.5, 21]
4809 },
4810 'TASK_TYPE_USER_1': {
4811 d: 'm {mx},{my} c 0.909,-0.845 1.594,-2.049 1.594,-3.385 0,-2.554 -1.805,-4.62199999 ' +
4812 '-4.357,-4.62199999 -2.55199998,0 -4.28799998,2.06799999 -4.28799998,4.62199999 0,1.348 ' +
4813 '0.974,2.562 1.89599998,3.405 -0.52899998,0.187 -5.669,2.097 -5.794,4.7560005 v 6.718 ' +
4814 'h 17 v -6.718 c 0,-2.2980005 -5.5279996,-4.5950005 -6.0509996,-4.7760005 z' +
4815 'm -8,6 l 0,5.5 m 11,0 l 0,-5'
4816 },
4817 'TASK_TYPE_USER_2': {
4818 d: 'm {mx},{my} m 2.162,1.009 c 0,2.4470005 -2.158,4.4310005 -4.821,4.4310005 ' +
4819 '-2.66499998,0 -4.822,-1.981 -4.822,-4.4310005 '
4820 },
4821 'TASK_TYPE_USER_3': {
4822 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 ' +
4823 '4.124,0.965 -0.098,-0.57 -0.117,-3.79099999 -4.191,-4.13599999 -3.57499998,0.001 ' +
4824 '-4.20799998,3.36699999 -4.20699998,4.34799999 z'
4825 },
4826 'TASK_TYPE_MANUAL': {
4827 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 ' +
4828 '-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 ' +
4829 '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 ' +
4830 '-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 ' +
4831 '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 ' +
4832 '-10.86,-0.003 -11.0829995,-0.003 -0.022,-0.047 -0.045,-0.094 -0.069,-0.139 0.3939995,-0.319 ' +
4833 '2.0409995,-1.626 2.4149995,-2.017 0.469,-0.4870005 0.519,-1.1650005 0.162,-1.6040005 -0.414,-0.511 ' +
4834 '-0.973,-0.5 -1.48,-0.236 -1.4609995,0.764 -6.5999995,3.6430005 -7.7329995,4.2710005 -0.9,0.499 ' +
4835 '-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 ' +
4836 '-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 ' +
4837 '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 ' +
4838 '-5.824,-0.004 -6.04,-0.004 10e-4,-0.084 0.003,-0.586 10e-4,-0.67 z'
4839 },
4840 'TASK_TYPE_INSTANTIATING_SEND': {
4841 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'
4842 },
4843 'TASK_TYPE_SERVICE': {
4844 d: 'm {mx},{my} v -1.71335 c 0.352326,-0.0705 0.703932,-0.17838 1.047628,-0.32133 ' +
4845 '0.344416,-0.14465 0.665822,-0.32133 0.966377,-0.52145 l 1.19431,1.18005 1.567487,-1.57688 ' +
4846 '-1.195028,-1.18014 c 0.403376,-0.61394 0.683079,-1.29908 0.825447,-2.01824 l 1.622133,-0.01 ' +
4847 'v -2.2196 l -1.636514,0.01 c -0.07333,-0.35153 -0.178319,-0.70024 -0.323564,-1.04372 ' +
4848 '-0.145244,-0.34406 -0.321407,-0.6644 -0.522735,-0.96217 l 1.131035,-1.13631 -1.583305,-1.56293 ' +
4849 '-1.129598,1.13589 c -0.614052,-0.40108 -1.302883,-0.68093 -2.022633,-0.82247 l 0.0093,-1.61852 ' +
4850 '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 ' +
4851 '-0.665102,0.32092 -0.9635006,0.52046 l -1.1698628,-1.15823 -1.5667691,1.5792 1.1684265,1.15669 ' +
4852 'c -0.4026573,0.61283 -0.68308,1.29797 -0.8247287,2.01713 l -1.6588041,0.003 v 2.22174 ' +
4853 'l 1.6724648,-0.006 c 0.073327,0.35077 0.1797598,0.70243 0.3242851,1.04472 0.1452428,0.34448 ' +
4854 '0.3214064,0.6644 0.5227339,0.96066 l -1.1993431,1.19723 1.5840256,1.56011 1.1964668,-1.19348 ' +
4855 'c 0.6140517,0.40346 1.3028827,0.68232 2.0233517,0.82331 l 7.19e-4,1.69892 h 2.226848 z ' +
4856 'm 0.221462,-3.9957 c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
4857 '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
4858 '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
4859 },
4860 'TASK_TYPE_SERVICE_FILL': {
4861 d: 'm {mx},{my} c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
4862 '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
4863 '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
4864 },
4865 'TASK_TYPE_BUSINESS_RULE_HEADER': {
4866 d: 'm {mx},{my} 0,4 20,0 0,-4 z'
4867 },
4868 'TASK_TYPE_BUSINESS_RULE_MAIN': {
4869 d: 'm {mx},{my} 0,12 20,0 0,-12 z' +
4870 'm 0,8 l 20,0 ' +
4871 'm -13,-4 l 0,8'
4872 },
4873 'MESSAGE_FLOW_MARKER': {
4874 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'
4875 }
4876 };
4877
4878 this.getRawPath = function getRawPath(pathId) {
4879 return this.pathMap[pathId].d;
4880 };
4881
4882 /**
4883 * Scales the path to the given height and width.
4884 * <h1>Use case</h1>
4885 * <p>Use case is to scale the content of elements (event, gateways) based
4886 * on the element bounding box's size.
4887 * </p>
4888 * <h1>Why not transform</h1>
4889 * <p>Scaling a path with transform() will also scale the stroke and IE does not support
4890 * the option 'non-scaling-stroke' to prevent this.
4891 * Also there are use cases where only some parts of a path should be
4892 * scaled.</p>
4893 *
4894 * @param {String} pathId The ID of the path.
4895 * @param {Object} param <p>
4896 * Example param object scales the path to 60% size of the container (data.width, data.height).
4897 * <pre>
4898 * {
4899 * xScaleFactor: 0.6,
4900 * yScaleFactor:0.6,
4901 * containerWidth: data.width,
4902 * containerHeight: data.height,
4903 * position: {
4904 * mx: 0.46,
4905 * my: 0.2,
4906 * }
4907 * }
4908 * </pre>
4909 * <ul>
4910 * <li>targetpathwidth = xScaleFactor * containerWidth</li>
4911 * <li>targetpathheight = yScaleFactor * containerHeight</li>
4912 * <li>Position is used to set the starting coordinate of the path. M is computed:
4913 * <ul>
4914 * <li>position.x * containerWidth</li>
4915 * <li>position.y * containerHeight</li>
4916 * </ul>
4917 * Center of the container <pre> position: {
4918 * mx: 0.5,
4919 * my: 0.5,
4920 * }</pre>
4921 * Upper left corner of the container
4922 * <pre> position: {
4923 * mx: 0.0,
4924 * my: 0.0,
4925 * }</pre>
4926 * </li>
4927 * </ul>
4928 * </p>
4929 *
4930 */
4931 this.getScaledPath = function getScaledPath(pathId, param) {
4932 var rawPath = this.pathMap[pathId];
4933
4934 // positioning
4935 // compute the start point of the path
4936 var mx, my;
4937
4938 if (param.abspos) {
4939 mx = param.abspos.x;
4940 my = param.abspos.y;
4941 } else {
4942 mx = param.containerWidth * param.position.mx;
4943 my = param.containerHeight * param.position.my;
4944 }
4945
4946 var coordinates = {}; // map for the scaled coordinates
4947 if (param.position) {
4948
4949 // path
4950 var heightRatio = (param.containerHeight / rawPath.height) * param.yScaleFactor;
4951 var widthRatio = (param.containerWidth / rawPath.width) * param.xScaleFactor;
4952
4953
4954 // Apply height ratio
4955 for (var heightIndex = 0; heightIndex < rawPath.heightElements.length; heightIndex++) {
4956 coordinates['y' + heightIndex] = rawPath.heightElements[heightIndex] * heightRatio;
4957 }
4958
4959 // Apply width ratio
4960 for (var widthIndex = 0; widthIndex < rawPath.widthElements.length; widthIndex++) {
4961 coordinates['x' + widthIndex] = rawPath.widthElements[widthIndex] * widthRatio;
4962 }
4963 }
4964
4965 // Apply value to raw path
4966 var path = format(
4967 rawPath.d, {
4968 mx: mx,
4969 my: my,
4970 e: coordinates
4971 }
4972 );
4973 return path;
4974 };
4975 }
4976
4977 // helpers //////////////////////
4978
4979 // copied from https://github.com/adobe-webplatform/Snap.svg/blob/master/src/svg.js
4980 var tokenRegex = /\{([^}]+)\}/g,
4981 objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g; // matches .xxxxx or ["xxxxx"] to run over object properties
4982
4983 function replacer(all, key, obj) {
4984 var res = obj;
4985 key.replace(objNotationRegex, function(all, name, quote, quotedName, isFunc) {
4986 name = name || quotedName;
4987 if (res) {
4988 if (name in res) {
4989 res = res[name];
4990 }
4991 typeof res == 'function' && isFunc && (res = res());
4992 }
4993 });
4994 res = (res == null || res == obj ? all : res) + '';
4995
4996 return res;
4997 }
4998
4999 function format(str, obj) {
5000 return String(str).replace(tokenRegex, function(all, key) {
5001 return replacer(all, key, obj);
5002 });
5003 }
5004
5005 var DrawModule = {
5006 __init__: [ 'bpmnRenderer' ],
5007 bpmnRenderer: [ 'type', BpmnRenderer ],
5008 textRenderer: [ 'type', TextRenderer ],
5009 pathMap: [ 'type', PathMap ]
5010 };
5011
5012 /**
5013 * A simple translation stub to be used for multi-language support
5014 * in diagrams. Can be easily replaced with a more sophisticated
5015 * solution.
5016 *
5017 * @example
5018 *
5019 * // use it inside any diagram component by injecting `translate`.
5020 *
5021 * function MyService(translate) {
5022 * alert(translate('HELLO {you}', { you: 'You!' }));
5023 * }
5024 *
5025 * @param {String} template to interpolate
5026 * @param {Object} [replacements] a map with substitutes
5027 *
5028 * @return {String} the translated string
5029 */
5030 function translate$1(template, replacements) {
5031
5032 replacements = replacements || {};
5033
5034 return template.replace(/{([^}]+)}/g, function(_, key) {
5035 return replacements[key] || '{' + key + '}';
5036 });
5037 }
5038
5039 var TranslateModule = {
5040 translate: [ 'value', translate$1 ]
5041 };
5042
5043 var DEFAULT_LABEL_SIZE$1 = {
5044 width: 90,
5045 height: 20
5046 };
5047
5048 var FLOW_LABEL_INDENT = 15;
5049
5050
5051 /**
5052 * Returns true if the given semantic has an external label
5053 *
5054 * @param {BpmnElement} semantic
5055 * @return {Boolean} true if has label
5056 */
5057 function isLabelExternal(semantic) {
5058 return is(semantic, 'bpmn:Event') ||
5059 is(semantic, 'bpmn:Gateway') ||
5060 is(semantic, 'bpmn:DataStoreReference') ||
5061 is(semantic, 'bpmn:DataObjectReference') ||
5062 is(semantic, 'bpmn:DataInput') ||
5063 is(semantic, 'bpmn:DataOutput') ||
5064 is(semantic, 'bpmn:SequenceFlow') ||
5065 is(semantic, 'bpmn:MessageFlow') ||
5066 is(semantic, 'bpmn:Group');
5067 }
5068
5069 /**
5070 * Get the position for sequence flow labels
5071 *
5072 * @param {Array<Point>} waypoints
5073 * @return {Point} the label position
5074 */
5075 function getFlowLabelPosition(waypoints) {
5076
5077 // get the waypoints mid
5078 var mid = waypoints.length / 2 - 1;
5079
5080 var first = waypoints[Math.floor(mid)];
5081 var second = waypoints[Math.ceil(mid + 0.01)];
5082
5083 // get position
5084 var position = getWaypointsMid(waypoints);
5085
5086 // calculate angle
5087 var angle = Math.atan((second.y - first.y) / (second.x - first.x));
5088
5089 var x = position.x,
5090 y = position.y;
5091
5092 if (Math.abs(angle) < Math.PI / 2) {
5093 y -= FLOW_LABEL_INDENT;
5094 } else {
5095 x += FLOW_LABEL_INDENT;
5096 }
5097
5098 return { x: x, y: y };
5099 }
5100
5101
5102 /**
5103 * Get the middle of a number of waypoints
5104 *
5105 * @param {Array<Point>} waypoints
5106 * @return {Point} the mid point
5107 */
5108 function getWaypointsMid(waypoints) {
5109
5110 var mid = waypoints.length / 2 - 1;
5111
5112 var first = waypoints[Math.floor(mid)];
5113 var second = waypoints[Math.ceil(mid + 0.01)];
5114
5115 return {
5116 x: first.x + (second.x - first.x) / 2,
5117 y: first.y + (second.y - first.y) / 2
5118 };
5119 }
5120
5121
5122 function getExternalLabelMid(element) {
5123
5124 if (element.waypoints) {
5125 return getFlowLabelPosition(element.waypoints);
5126 } else if (is(element, 'bpmn:Group')) {
5127 return {
5128 x: element.x + element.width / 2,
5129 y: element.y + DEFAULT_LABEL_SIZE$1.height / 2
5130 };
5131 } else {
5132 return {
5133 x: element.x + element.width / 2,
5134 y: element.y + element.height + DEFAULT_LABEL_SIZE$1.height / 2
5135 };
5136 }
5137 }
5138
5139
5140 /**
5141 * Returns the bounds of an elements label, parsed from the elements DI or
5142 * generated from its bounds.
5143 *
5144 * @param {BpmnElement} semantic
5145 * @param {djs.model.Base} element
5146 */
5147 function getExternalLabelBounds(semantic, element) {
5148
5149 var mid,
5150 size,
5151 bounds,
5152 di = semantic.di,
5153 label = di.label;
5154
5155 if (label && label.bounds) {
5156 bounds = label.bounds;
5157
5158 size = {
5159 width: Math.max(DEFAULT_LABEL_SIZE$1.width, bounds.width),
5160 height: bounds.height
5161 };
5162
5163 mid = {
5164 x: bounds.x + bounds.width / 2,
5165 y: bounds.y + bounds.height / 2
5166 };
5167 } else {
5168
5169 mid = getExternalLabelMid(element);
5170
5171 size = DEFAULT_LABEL_SIZE$1;
5172 }
5173
5174 return assign({
5175 x: mid.x - size.width / 2,
5176 y: mid.y - size.height / 2
5177 }, size);
5178 }
5179
5180 /**
5181 * This file contains source code adapted from Snap.svg (licensed Apache-2.0).
5182 *
5183 * @see https://github.com/adobe-webplatform/Snap.svg/blob/master/src/path.js
5184 */
5185
5186 /* eslint no-fallthrough: "off" */
5187
5188 var math = Math,
5189 PI = math.PI;
5190
5191 function roundPoint(point) {
5192
5193 return {
5194 x: Math.round(point.x),
5195 y: Math.round(point.y)
5196 };
5197 }
5198
5199
5200 /**
5201 * Get the mid of the given bounds or point.
5202 *
5203 * @param {Bounds|Point} bounds
5204 *
5205 * @return {Point}
5206 */
5207 function getMid(bounds) {
5208 return roundPoint({
5209 x: bounds.x + (bounds.width || 0) / 2,
5210 y: bounds.y + (bounds.height || 0) / 2
5211 });
5212 }
5213
5214 function elementToString(e) {
5215 if (!e) {
5216 return '<null>';
5217 }
5218
5219 return '<' + e.$type + (e.id ? ' id="' + e.id : '') + '" />';
5220 }
5221
5222 function elementData(semantic, attrs) {
5223 return assign({
5224 id: semantic.id,
5225 type: semantic.$type,
5226 businessObject: semantic
5227 }, attrs);
5228 }
5229
5230 function getWaypoints(bo, source, target) {
5231
5232 var waypoints = bo.di.waypoint;
5233
5234 if (!waypoints || waypoints.length < 2) {
5235 return [ getMid(source), getMid(target) ];
5236 }
5237
5238 return waypoints.map(function(p) {
5239 return { x: p.x, y: p.y };
5240 });
5241 }
5242
5243 function notYetDrawn(translate, semantic, refSemantic, property) {
5244 return new Error(translate('element {element} referenced by {referenced}#{property} not yet drawn', {
5245 element: elementToString(refSemantic),
5246 referenced: elementToString(semantic),
5247 property: property
5248 }));
5249 }
5250
5251
5252 /**
5253 * An importer that adds bpmn elements to the canvas
5254 *
5255 * @param {EventBus} eventBus
5256 * @param {Canvas} canvas
5257 * @param {ElementFactory} elementFactory
5258 * @param {ElementRegistry} elementRegistry
5259 * @param {Function} translate
5260 * @param {TextRenderer} textRenderer
5261 */
5262 function BpmnImporter(
5263 eventBus, canvas, elementFactory,
5264 elementRegistry, translate, textRenderer) {
5265
5266 this._eventBus = eventBus;
5267 this._canvas = canvas;
5268 this._elementFactory = elementFactory;
5269 this._elementRegistry = elementRegistry;
5270 this._translate = translate;
5271 this._textRenderer = textRenderer;
5272 }
5273
5274 BpmnImporter.$inject = [
5275 'eventBus',
5276 'canvas',
5277 'elementFactory',
5278 'elementRegistry',
5279 'translate',
5280 'textRenderer'
5281 ];
5282
5283
5284 /**
5285 * Add bpmn element (semantic) to the canvas onto the
5286 * specified parent shape.
5287 */
5288 BpmnImporter.prototype.add = function(semantic, parentElement) {
5289
5290 var di = semantic.di,
5291 element,
5292 translate = this._translate,
5293 hidden;
5294
5295 var parentIndex;
5296
5297 // ROOT ELEMENT
5298 // handle the special case that we deal with a
5299 // invisible root element (process or collaboration)
5300 if (is(di, 'bpmndi:BPMNPlane')) {
5301
5302 // add a virtual element (not being drawn)
5303 element = this._elementFactory.createRoot(elementData(semantic));
5304
5305 this._canvas.setRootElement(element);
5306 }
5307
5308 // SHAPE
5309 else if (is(di, 'bpmndi:BPMNShape')) {
5310
5311 var collapsed = !isExpanded(semantic);
5312 hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
5313
5314 var bounds = semantic.di.bounds;
5315
5316 element = this._elementFactory.createShape(elementData(semantic, {
5317 collapsed: collapsed,
5318 hidden: hidden,
5319 x: Math.round(bounds.x),
5320 y: Math.round(bounds.y),
5321 width: Math.round(bounds.width),
5322 height: Math.round(bounds.height)
5323 }));
5324
5325 if (is(semantic, 'bpmn:BoundaryEvent')) {
5326 this._attachBoundary(semantic, element);
5327 }
5328
5329 // insert lanes behind other flow nodes (cf. #727)
5330 if (is(semantic, 'bpmn:Lane')) {
5331 parentIndex = 0;
5332 }
5333
5334 if (is(semantic, 'bpmn:DataStoreReference')) {
5335
5336 // check whether data store is inside our outside of its semantic parent
5337 if (!isPointInsideBBox(parentElement, getMid(bounds))) {
5338 parentElement = this._canvas.getRootElement();
5339 }
5340 }
5341
5342 this._canvas.addShape(element, parentElement, parentIndex);
5343 }
5344
5345 // CONNECTION
5346 else if (is(di, 'bpmndi:BPMNEdge')) {
5347
5348 var source = this._getSource(semantic),
5349 target = this._getTarget(semantic);
5350
5351 hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
5352
5353 element = this._elementFactory.createConnection(elementData(semantic, {
5354 hidden: hidden,
5355 source: source,
5356 target: target,
5357 waypoints: getWaypoints(semantic, source, target)
5358 }));
5359
5360 if (is(semantic, 'bpmn:DataAssociation')) {
5361
5362 // render always on top; this ensures DataAssociations
5363 // are rendered correctly across different "hacks" people
5364 // love to model such as cross participant / sub process
5365 // associations
5366 parentElement = null;
5367 }
5368
5369 // insert sequence flows behind other flow nodes (cf. #727)
5370 if (is(semantic, 'bpmn:SequenceFlow')) {
5371 parentIndex = 0;
5372 }
5373
5374 this._canvas.addConnection(element, parentElement, parentIndex);
5375 } else {
5376 throw new Error(translate('unknown di {di} for element {semantic}', {
5377 di: elementToString(di),
5378 semantic: elementToString(semantic)
5379 }));
5380 }
5381
5382 // (optional) LABEL
5383 if (isLabelExternal(semantic) && getLabel(element)) {
5384 this.addLabel(semantic, element);
5385 }
5386
5387
5388 this._eventBus.fire('bpmnElement.added', { element: element });
5389
5390 return element;
5391 };
5392
5393
5394 /**
5395 * Attach the boundary element to the given host
5396 *
5397 * @param {ModdleElement} boundarySemantic
5398 * @param {djs.model.Base} boundaryElement
5399 */
5400 BpmnImporter.prototype._attachBoundary = function(boundarySemantic, boundaryElement) {
5401 var translate = this._translate;
5402 var hostSemantic = boundarySemantic.attachedToRef;
5403
5404 if (!hostSemantic) {
5405 throw new Error(translate('missing {semantic}#attachedToRef', {
5406 semantic: elementToString(boundarySemantic)
5407 }));
5408 }
5409
5410 var host = this._elementRegistry.get(hostSemantic.id),
5411 attachers = host && host.attachers;
5412
5413 if (!host) {
5414 throw notYetDrawn(translate, boundarySemantic, hostSemantic, 'attachedToRef');
5415 }
5416
5417 // wire element.host <> host.attachers
5418 boundaryElement.host = host;
5419
5420 if (!attachers) {
5421 host.attachers = attachers = [];
5422 }
5423
5424 if (attachers.indexOf(boundaryElement) === -1) {
5425 attachers.push(boundaryElement);
5426 }
5427 };
5428
5429
5430 /**
5431 * add label for an element
5432 */
5433 BpmnImporter.prototype.addLabel = function(semantic, element) {
5434 var bounds,
5435 text,
5436 label;
5437
5438 bounds = getExternalLabelBounds(semantic, element);
5439
5440 text = getLabel(element);
5441
5442 if (text) {
5443
5444 // get corrected bounds from actual layouted text
5445 bounds = this._textRenderer.getExternalLabelBounds(bounds, text);
5446 }
5447
5448 label = this._elementFactory.createLabel(elementData(semantic, {
5449 id: semantic.id + '_label',
5450 labelTarget: element,
5451 type: 'label',
5452 hidden: element.hidden || !getLabel(element),
5453 x: Math.round(bounds.x),
5454 y: Math.round(bounds.y),
5455 width: Math.round(bounds.width),
5456 height: Math.round(bounds.height)
5457 }));
5458
5459 return this._canvas.addShape(label, element.parent);
5460 };
5461
5462 /**
5463 * Return the drawn connection end based on the given side.
5464 *
5465 * @throws {Error} if the end is not yet drawn
5466 */
5467 BpmnImporter.prototype._getEnd = function(semantic, side) {
5468
5469 var element,
5470 refSemantic,
5471 type = semantic.$type,
5472 translate = this._translate;
5473
5474 refSemantic = semantic[side + 'Ref'];
5475
5476 // handle mysterious isMany DataAssociation#sourceRef
5477 if (side === 'source' && type === 'bpmn:DataInputAssociation') {
5478 refSemantic = refSemantic && refSemantic[0];
5479 }
5480
5481 // fix source / target for DataInputAssociation / DataOutputAssociation
5482 if (side === 'source' && type === 'bpmn:DataOutputAssociation' ||
5483 side === 'target' && type === 'bpmn:DataInputAssociation') {
5484
5485 refSemantic = semantic.$parent;
5486 }
5487
5488 element = refSemantic && this._getElement(refSemantic);
5489
5490 if (element) {
5491 return element;
5492 }
5493
5494 if (refSemantic) {
5495 throw notYetDrawn(translate, semantic, refSemantic, side + 'Ref');
5496 } else {
5497 throw new Error(translate('{semantic}#{side} Ref not specified', {
5498 semantic: elementToString(semantic),
5499 side: side
5500 }));
5501 }
5502 };
5503
5504 BpmnImporter.prototype._getSource = function(semantic) {
5505 return this._getEnd(semantic, 'source');
5506 };
5507
5508 BpmnImporter.prototype._getTarget = function(semantic) {
5509 return this._getEnd(semantic, 'target');
5510 };
5511
5512
5513 BpmnImporter.prototype._getElement = function(semantic) {
5514 return this._elementRegistry.get(semantic.id);
5515 };
5516
5517
5518 // helpers ////////////////////
5519
5520 function isPointInsideBBox(bbox, point) {
5521 var x = point.x,
5522 y = point.y;
5523
5524 return x >= bbox.x &&
5525 x <= bbox.x + bbox.width &&
5526 y >= bbox.y &&
5527 y <= bbox.y + bbox.height;
5528 }
5529
5530 var ImportModule = {
5531 __depends__: [
5532 TranslateModule
5533 ],
5534 bpmnImporter: [ 'type', BpmnImporter ]
5535 };
5536
5537 var CoreModule = {
5538 __depends__: [
5539 DrawModule,
5540 ImportModule
5541 ]
5542 };
5543
5544 function getOriginal(event) {
5545 return event.originalEvent || event.srcEvent;
5546 }
5547
5548
5549 function toPoint(event) {
5550
5551 if (event.pointers && event.pointers.length) {
5552 event = event.pointers[0];
5553 }
5554
5555 if (event.touches && event.touches.length) {
5556 event = event.touches[0];
5557 }
5558
5559 return event ? {
5560 x: event.clientX,
5561 y: event.clientY
5562 } : null;
5563 }
5564
5565 function isMac() {
5566 return (/mac/i).test(navigator.platform);
5567 }
5568
5569 function isPrimaryButton(event) {
5570
5571 // button === 0 -> left áka primary mouse button
5572 return !(getOriginal(event) || event).button;
5573 }
5574
5575 function hasPrimaryModifier(event) {
5576 var originalEvent = getOriginal(event) || event;
5577
5578 if (!isPrimaryButton(event)) {
5579 return false;
5580 }
5581
5582 // Use alt as primary modifier key for mac OS
5583 if (isMac()) {
5584 return originalEvent.metaKey;
5585 } else {
5586 return originalEvent.ctrlKey;
5587 }
5588 }
5589
5590 function allowAll(e) { return true; }
5591
5592 var LOW_PRIORITY = 500;
5593
5594
5595 /**
5596 * A plugin that provides interaction events for diagram elements.
5597 *
5598 * It emits the following events:
5599 *
5600 * * element.click
5601 * * element.contextmenu
5602 * * element.dblclick
5603 * * element.hover
5604 * * element.mousedown
5605 * * element.mousemove
5606 * * element.mouseup
5607 * * element.out
5608 *
5609 * Each event is a tuple { element, gfx, originalEvent }.
5610 *
5611 * Canceling the event via Event#preventDefault()
5612 * prevents the original DOM operation.
5613 *
5614 * @param {EventBus} eventBus
5615 */
5616 function InteractionEvents(eventBus, elementRegistry, styles) {
5617
5618 var self = this;
5619
5620 /**
5621 * Fire an interaction event.
5622 *
5623 * @param {String} type local event name, e.g. element.click.
5624 * @param {DOMEvent} event native event
5625 * @param {djs.model.Base} [element] the diagram element to emit the event on;
5626 * defaults to the event target
5627 */
5628 function fire(type, event, element) {
5629
5630 if (isIgnored(type, event)) {
5631 return;
5632 }
5633
5634 var target, gfx, returnValue;
5635
5636 if (!element) {
5637 target = event.delegateTarget || event.target;
5638
5639 if (target) {
5640 gfx = target;
5641 element = elementRegistry.get(gfx);
5642 }
5643 } else {
5644 gfx = elementRegistry.getGraphics(element);
5645 }
5646
5647 if (!gfx || !element) {
5648 return;
5649 }
5650
5651 returnValue = eventBus.fire(type, {
5652 element: element,
5653 gfx: gfx,
5654 originalEvent: event
5655 });
5656
5657 if (returnValue === false) {
5658 event.stopPropagation();
5659 event.preventDefault();
5660 }
5661 }
5662
5663 // TODO(nikku): document this
5664 var handlers = {};
5665
5666 function mouseHandler(localEventName) {
5667 return handlers[localEventName];
5668 }
5669
5670 function isIgnored(localEventName, event) {
5671
5672 var filter = ignoredFilters[localEventName] || isPrimaryButton;
5673
5674 // only react on left mouse button interactions
5675 // except for interaction events that are enabled
5676 // for secundary mouse button
5677 return !filter(event);
5678 }
5679
5680 var bindings = {
5681 click: 'element.click',
5682 contextmenu: 'element.contextmenu',
5683 dblclick: 'element.dblclick',
5684 mousedown: 'element.mousedown',
5685 mousemove: 'element.mousemove',
5686 mouseover: 'element.hover',
5687 mouseout: 'element.out',
5688 mouseup: 'element.mouseup',
5689 };
5690
5691 var ignoredFilters = {
5692 'element.contextmenu': allowAll
5693 };
5694
5695
5696 // manual event trigger //////////
5697
5698 /**
5699 * Trigger an interaction event (based on a native dom event)
5700 * on the target shape or connection.
5701 *
5702 * @param {String} eventName the name of the triggered DOM event
5703 * @param {MouseEvent} event
5704 * @param {djs.model.Base} targetElement
5705 */
5706 function triggerMouseEvent(eventName, event, targetElement) {
5707
5708 // i.e. element.mousedown...
5709 var localEventName = bindings[eventName];
5710
5711 if (!localEventName) {
5712 throw new Error('unmapped DOM event name <' + eventName + '>');
5713 }
5714
5715 return fire(localEventName, event, targetElement);
5716 }
5717
5718
5719 var ELEMENT_SELECTOR = 'svg, .djs-element';
5720
5721 // event handling ///////
5722
5723 function registerEvent(node, event, localEvent, ignoredFilter) {
5724
5725 var handler = handlers[localEvent] = function(event) {
5726 fire(localEvent, event);
5727 };
5728
5729 if (ignoredFilter) {
5730 ignoredFilters[localEvent] = ignoredFilter;
5731 }
5732
5733 handler.$delegate = delegateEvents.bind(node, ELEMENT_SELECTOR, event, handler);
5734 }
5735
5736 function unregisterEvent(node, event, localEvent) {
5737
5738 var handler = mouseHandler(localEvent);
5739
5740 if (!handler) {
5741 return;
5742 }
5743
5744 delegateEvents.unbind(node, event, handler.$delegate);
5745 }
5746
5747 function registerEvents(svg) {
5748 forEach(bindings, function(val, key) {
5749 registerEvent(svg, key, val);
5750 });
5751 }
5752
5753 function unregisterEvents(svg) {
5754 forEach(bindings, function(val, key) {
5755 unregisterEvent(svg, key, val);
5756 });
5757 }
5758
5759 eventBus.on('canvas.destroy', function(event) {
5760 unregisterEvents(event.svg);
5761 });
5762
5763 eventBus.on('canvas.init', function(event) {
5764 registerEvents(event.svg);
5765 });
5766
5767
5768 // hit box updating ////////////////
5769
5770 eventBus.on([ 'shape.added', 'connection.added' ], function(event) {
5771 var element = event.element,
5772 gfx = event.gfx;
5773
5774 eventBus.fire('interactionEvents.createHit', { element: element, gfx: gfx });
5775 });
5776
5777 // Update djs-hit on change.
5778 // A low priortity is necessary, because djs-hit of labels has to be updated
5779 // after the label bounds have been updated in the renderer.
5780 eventBus.on([
5781 'shape.changed',
5782 'connection.changed'
5783 ], LOW_PRIORITY, function(event) {
5784
5785 var element = event.element,
5786 gfx = event.gfx;
5787
5788 eventBus.fire('interactionEvents.updateHit', { element: element, gfx: gfx });
5789 });
5790
5791 eventBus.on('interactionEvents.createHit', LOW_PRIORITY, function(event) {
5792 var element = event.element,
5793 gfx = event.gfx;
5794
5795 self.createDefaultHit(element, gfx);
5796 });
5797
5798 eventBus.on('interactionEvents.updateHit', function(event) {
5799 var element = event.element,
5800 gfx = event.gfx;
5801
5802 self.updateDefaultHit(element, gfx);
5803 });
5804
5805
5806 // hit styles ////////////
5807
5808 var STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-stroke');
5809
5810 var CLICK_STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-click-stroke');
5811
5812 var ALL_HIT_STYLE = createHitStyle('djs-hit djs-hit-all');
5813
5814 var HIT_TYPES = {
5815 'all': ALL_HIT_STYLE,
5816 'click-stroke': CLICK_STROKE_HIT_STYLE,
5817 'stroke': STROKE_HIT_STYLE
5818 };
5819
5820 function createHitStyle(classNames, attrs) {
5821
5822 attrs = assign({
5823 stroke: 'white',
5824 strokeWidth: 15
5825 }, attrs || {});
5826
5827 return styles.cls(classNames, [ 'no-fill', 'no-border' ], attrs);
5828 }
5829
5830
5831 // style helpers ///////////////
5832
5833 function applyStyle(hit, type) {
5834
5835 var attrs = HIT_TYPES[type];
5836
5837 if (!attrs) {
5838 throw new Error('invalid hit type <' + type + '>');
5839 }
5840
5841 attr(hit, attrs);
5842
5843 return hit;
5844 }
5845
5846 function appendHit(gfx, hit) {
5847 append(gfx, hit);
5848 }
5849
5850
5851 // API
5852
5853 /**
5854 * Remove hints on the given graphics.
5855 *
5856 * @param {SVGElement} gfx
5857 */
5858 this.removeHits = function(gfx) {
5859 var hits = all('.djs-hit', gfx);
5860
5861 forEach(hits, remove);
5862 };
5863
5864 /**
5865 * Create default hit for the given element.
5866 *
5867 * @param {djs.model.Base} element
5868 * @param {SVGElement} gfx
5869 *
5870 * @return {SVGElement} created hit
5871 */
5872 this.createDefaultHit = function(element, gfx) {
5873 var waypoints = element.waypoints,
5874 isFrame = element.isFrame,
5875 boxType;
5876
5877 if (waypoints) {
5878 return this.createWaypointsHit(gfx, waypoints);
5879 } else {
5880
5881 boxType = isFrame ? 'stroke' : 'all';
5882
5883 return this.createBoxHit(gfx, boxType, {
5884 width: element.width,
5885 height: element.height
5886 });
5887 }
5888 };
5889
5890 /**
5891 * Create hits for the given waypoints.
5892 *
5893 * @param {SVGElement} gfx
5894 * @param {Array<Point>} waypoints
5895 *
5896 * @return {SVGElement}
5897 */
5898 this.createWaypointsHit = function(gfx, waypoints) {
5899
5900 var hit = createLine(waypoints);
5901
5902 applyStyle(hit, 'stroke');
5903
5904 appendHit(gfx, hit);
5905
5906 return hit;
5907 };
5908
5909 /**
5910 * Create hits for a box.
5911 *
5912 * @param {SVGElement} gfx
5913 * @param {String} hitType
5914 * @param {Object} attrs
5915 *
5916 * @return {SVGElement}
5917 */
5918 this.createBoxHit = function(gfx, type, attrs) {
5919
5920 attrs = assign({
5921 x: 0,
5922 y: 0
5923 }, attrs);
5924
5925 var hit = create('rect');
5926
5927 applyStyle(hit, type);
5928
5929 attr(hit, attrs);
5930
5931 appendHit(gfx, hit);
5932
5933 return hit;
5934 };
5935
5936 /**
5937 * Update default hit of the element.
5938 *
5939 * @param {djs.model.Base} element
5940 * @param {SVGElement} gfx
5941 *
5942 * @return {SVGElement} updated hit
5943 */
5944 this.updateDefaultHit = function(element, gfx) {
5945
5946 var hit = query('.djs-hit', gfx);
5947
5948 if (!hit) {
5949 return;
5950 }
5951
5952 if (element.waypoints) {
5953 updateLine(hit, element.waypoints);
5954 } else {
5955 attr(hit, {
5956 width: element.width,
5957 height: element.height
5958 });
5959 }
5960
5961 return hit;
5962 };
5963
5964 this.fire = fire;
5965
5966 this.triggerMouseEvent = triggerMouseEvent;
5967
5968 this.mouseHandler = mouseHandler;
5969
5970 this.registerEvent = registerEvent;
5971 this.unregisterEvent = unregisterEvent;
5972 }
5973
5974
5975 InteractionEvents.$inject = [
5976 'eventBus',
5977 'elementRegistry',
5978 'styles'
5979 ];
5980
5981
5982 /**
5983 * An event indicating that the mouse hovered over an element
5984 *
5985 * @event element.hover
5986 *
5987 * @type {Object}
5988 * @property {djs.model.Base} element
5989 * @property {SVGElement} gfx
5990 * @property {Event} originalEvent
5991 */
5992
5993 /**
5994 * An event indicating that the mouse has left an element
5995 *
5996 * @event element.out
5997 *
5998 * @type {Object}
5999 * @property {djs.model.Base} element
6000 * @property {SVGElement} gfx
6001 * @property {Event} originalEvent
6002 */
6003
6004 /**
6005 * An event indicating that the mouse has clicked an element
6006 *
6007 * @event element.click
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 double clicked an element
6017 *
6018 * @event element.dblclick
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 gone down on an element.
6028 *
6029 * @event element.mousedown
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 gone up on an element.
6039 *
6040 * @event element.mouseup
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 context menu action is triggered
6050 * via mouse or touch controls.
6051 *
6052 * @event element.contextmenu
6053 *
6054 * @type {Object}
6055 * @property {djs.model.Base} element
6056 * @property {SVGElement} gfx
6057 * @property {Event} originalEvent
6058 */
6059
6060 var InteractionEventsModule = {
6061 __init__: [ 'interactionEvents' ],
6062 interactionEvents: [ 'type', InteractionEvents ]
6063 };
6064
6065 /**
6066 * Returns the surrounding bbox for all elements in
6067 * the array or the element primitive.
6068 *
6069 * @param {Array<djs.model.Shape>|djs.model.Shape} elements
6070 * @param {Boolean} stopRecursion
6071 */
6072 function getBBox(elements, stopRecursion) {
6073
6074 stopRecursion = !!stopRecursion;
6075 if (!isArray(elements)) {
6076 elements = [elements];
6077 }
6078
6079 var minX,
6080 minY,
6081 maxX,
6082 maxY;
6083
6084 forEach(elements, function(element) {
6085
6086 // If element is a connection the bbox must be computed first
6087 var bbox = element;
6088 if (element.waypoints && !stopRecursion) {
6089 bbox = getBBox(element.waypoints, true);
6090 }
6091
6092 var x = bbox.x,
6093 y = bbox.y,
6094 height = bbox.height || 0,
6095 width = bbox.width || 0;
6096
6097 if (x < minX || minX === undefined) {
6098 minX = x;
6099 }
6100 if (y < minY || minY === undefined) {
6101 minY = y;
6102 }
6103
6104 if ((x + width) > maxX || maxX === undefined) {
6105 maxX = x + width;
6106 }
6107 if ((y + height) > maxY || maxY === undefined) {
6108 maxY = y + height;
6109 }
6110 });
6111
6112 return {
6113 x: minX,
6114 y: minY,
6115 height: maxY - minY,
6116 width: maxX - minX
6117 };
6118 }
6119
6120
6121 function getType(element) {
6122
6123 if ('waypoints' in element) {
6124 return 'connection';
6125 }
6126
6127 if ('x' in element) {
6128 return 'shape';
6129 }
6130
6131 return 'root';
6132 }
6133
6134 function isFrameElement(element) {
6135
6136 return !!(element && element.isFrame);
6137 }
6138
6139 var LOW_PRIORITY$1 = 500;
6140
6141
6142 /**
6143 * @class
6144 *
6145 * A plugin that adds an outline to shapes and connections that may be activated and styled
6146 * via CSS classes.
6147 *
6148 * @param {EventBus} eventBus
6149 * @param {Styles} styles
6150 * @param {ElementRegistry} elementRegistry
6151 */
6152 function Outline(eventBus, styles, elementRegistry) {
6153
6154 this.offset = 6;
6155
6156 var OUTLINE_STYLE = styles.cls('djs-outline', [ 'no-fill' ]);
6157
6158 var self = this;
6159
6160 function createOutline(gfx, bounds) {
6161 var outline = create('rect');
6162
6163 attr(outline, assign({
6164 x: 10,
6165 y: 10,
6166 width: 100,
6167 height: 100
6168 }, OUTLINE_STYLE));
6169
6170 append(gfx, outline);
6171
6172 return outline;
6173 }
6174
6175 // A low priortity is necessary, because outlines of labels have to be updated
6176 // after the label bounds have been updated in the renderer.
6177 eventBus.on([ 'shape.added', 'shape.changed' ], LOW_PRIORITY$1, function(event) {
6178 var element = event.element,
6179 gfx = event.gfx;
6180
6181 var outline = query('.djs-outline', gfx);
6182
6183 if (!outline) {
6184 outline = createOutline(gfx);
6185 }
6186
6187 self.updateShapeOutline(outline, element);
6188 });
6189
6190 eventBus.on([ 'connection.added', 'connection.changed' ], function(event) {
6191 var element = event.element,
6192 gfx = event.gfx;
6193
6194 var outline = query('.djs-outline', gfx);
6195
6196 if (!outline) {
6197 outline = createOutline(gfx);
6198 }
6199
6200 self.updateConnectionOutline(outline, element);
6201 });
6202 }
6203
6204
6205 /**
6206 * Updates the outline of a shape respecting the dimension of the
6207 * element and an outline offset.
6208 *
6209 * @param {SVGElement} outline
6210 * @param {djs.model.Base} element
6211 */
6212 Outline.prototype.updateShapeOutline = function(outline, element) {
6213
6214 attr(outline, {
6215 x: -this.offset,
6216 y: -this.offset,
6217 width: element.width + this.offset * 2,
6218 height: element.height + this.offset * 2
6219 });
6220
6221 };
6222
6223
6224 /**
6225 * Updates the outline of a connection respecting the bounding box of
6226 * the connection and an outline offset.
6227 *
6228 * @param {SVGElement} outline
6229 * @param {djs.model.Base} element
6230 */
6231 Outline.prototype.updateConnectionOutline = function(outline, connection) {
6232
6233 var bbox = getBBox(connection);
6234
6235 attr(outline, {
6236 x: bbox.x - this.offset,
6237 y: bbox.y - this.offset,
6238 width: bbox.width + this.offset * 2,
6239 height: bbox.height + this.offset * 2
6240 });
6241
6242 };
6243
6244
6245 Outline.$inject = ['eventBus', 'styles', 'elementRegistry'];
6246
6247 var OutlineModule = {
6248 __init__: [ 'outline' ],
6249 outline: [ 'type', Outline ]
6250 };
6251
6252 /**
6253 * A service that offers the current selection in a diagram.
6254 * Offers the api to control the selection, too.
6255 *
6256 * @class
6257 *
6258 * @param {EventBus} eventBus the event bus
6259 */
6260 function Selection(eventBus) {
6261
6262 this._eventBus = eventBus;
6263
6264 this._selectedElements = [];
6265
6266 var self = this;
6267
6268 eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
6269 var element = e.element;
6270 self.deselect(element);
6271 });
6272
6273 eventBus.on([ 'diagram.clear' ], function(e) {
6274 self.select(null);
6275 });
6276 }
6277
6278 Selection.$inject = [ 'eventBus' ];
6279
6280
6281 Selection.prototype.deselect = function(element) {
6282 var selectedElements = this._selectedElements;
6283
6284 var idx = selectedElements.indexOf(element);
6285
6286 if (idx !== -1) {
6287 var oldSelection = selectedElements.slice();
6288
6289 selectedElements.splice(idx, 1);
6290
6291 this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
6292 }
6293 };
6294
6295
6296 Selection.prototype.get = function() {
6297 return this._selectedElements;
6298 };
6299
6300 Selection.prototype.isSelected = function(element) {
6301 return this._selectedElements.indexOf(element) !== -1;
6302 };
6303
6304
6305 /**
6306 * This method selects one or more elements on the diagram.
6307 *
6308 * By passing an additional add parameter you can decide whether or not the element(s)
6309 * should be added to the already existing selection or not.
6310 *
6311 * @method Selection#select
6312 *
6313 * @param {Object|Object[]} elements element or array of elements to be selected
6314 * @param {boolean} [add] whether the element(s) should be appended to the current selection, defaults to false
6315 */
6316 Selection.prototype.select = function(elements, add) {
6317 var selectedElements = this._selectedElements,
6318 oldSelection = selectedElements.slice();
6319
6320 if (!isArray(elements)) {
6321 elements = elements ? [ elements ] : [];
6322 }
6323
6324 // selection may be cleared by passing an empty array or null
6325 // to the method
6326 if (add) {
6327 forEach(elements, function(element) {
6328 if (selectedElements.indexOf(element) !== -1) {
6329
6330 // already selected
6331 return;
6332 } else {
6333 selectedElements.push(element);
6334 }
6335 });
6336 } else {
6337 this._selectedElements = selectedElements = elements.slice();
6338 }
6339
6340 this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
6341 };
6342
6343 var MARKER_HOVER = 'hover',
6344 MARKER_SELECTED = 'selected';
6345
6346
6347 /**
6348 * A plugin that adds a visible selection UI to shapes and connections
6349 * by appending the <code>hover</code> and <code>selected</code> classes to them.
6350 *
6351 * @class
6352 *
6353 * Makes elements selectable, too.
6354 *
6355 * @param {EventBus} events
6356 * @param {SelectionService} selection
6357 * @param {Canvas} canvas
6358 */
6359 function SelectionVisuals(events, canvas, selection, styles) {
6360
6361 this._multiSelectionBox = null;
6362
6363 function addMarker(e, cls) {
6364 canvas.addMarker(e, cls);
6365 }
6366
6367 function removeMarker(e, cls) {
6368 canvas.removeMarker(e, cls);
6369 }
6370
6371 events.on('element.hover', function(event) {
6372 addMarker(event.element, MARKER_HOVER);
6373 });
6374
6375 events.on('element.out', function(event) {
6376 removeMarker(event.element, MARKER_HOVER);
6377 });
6378
6379 events.on('selection.changed', function(event) {
6380
6381 function deselect(s) {
6382 removeMarker(s, MARKER_SELECTED);
6383 }
6384
6385 function select(s) {
6386 addMarker(s, MARKER_SELECTED);
6387 }
6388
6389 var oldSelection = event.oldSelection,
6390 newSelection = event.newSelection;
6391
6392 forEach(oldSelection, function(e) {
6393 if (newSelection.indexOf(e) === -1) {
6394 deselect(e);
6395 }
6396 });
6397
6398 forEach(newSelection, function(e) {
6399 if (oldSelection.indexOf(e) === -1) {
6400 select(e);
6401 }
6402 });
6403 });
6404 }
6405
6406 SelectionVisuals.$inject = [
6407 'eventBus',
6408 'canvas',
6409 'selection',
6410 'styles'
6411 ];
6412
6413 function SelectionBehavior(
6414 eventBus, selection, canvas,
6415 elementRegistry) {
6416
6417 eventBus.on('create.end', 500, function(e) {
6418
6419 var context = e.context,
6420 canExecute = context.canExecute,
6421 elements = context.elements,
6422 hints = context.hints || {},
6423 autoSelect = hints.autoSelect;
6424
6425 // select elements after they have been created
6426 if (canExecute) {
6427 if (autoSelect === false) {
6428
6429 // select no elements
6430 return;
6431 }
6432
6433 if (isArray(autoSelect)) {
6434 selection.select(autoSelect);
6435 } else {
6436
6437 // select all elements by default
6438 selection.select(elements);
6439 }
6440 }
6441 });
6442
6443 eventBus.on('connect.end', 500, function(e) {
6444
6445 // select the connect end target
6446 // after a connect operation
6447 if (e.context.canExecute && e.context.target) {
6448 selection.select(e.context.target);
6449 }
6450 });
6451
6452 eventBus.on('shape.move.end', 500, function(e) {
6453 var previousSelection = e.previousSelection || [];
6454
6455 var shape = elementRegistry.get(e.context.shape.id);
6456
6457 // make sure at least the main moved element is being
6458 // selected after a move operation
6459 var inSelection = find(previousSelection, function(selectedShape) {
6460 return shape.id === selectedShape.id;
6461 });
6462
6463 if (!inSelection) {
6464 selection.select(shape);
6465 }
6466 });
6467
6468 // Shift + click selection
6469 eventBus.on('element.click', function(event) {
6470
6471 var element = event.element;
6472
6473 // do not select the root element
6474 // or connections
6475 if (element === canvas.getRootElement()) {
6476 element = null;
6477 }
6478
6479 var isSelected = selection.isSelected(element),
6480 isMultiSelect = selection.get().length > 1;
6481
6482 // mouse-event: SELECTION_KEY
6483 var add = hasPrimaryModifier(event);
6484
6485 // select OR deselect element in multi selection
6486 if (isSelected && isMultiSelect) {
6487 if (add) {
6488 return selection.deselect(element);
6489 } else {
6490 return selection.select(element);
6491 }
6492 } else
6493 if (!isSelected) {
6494 selection.select(element, add);
6495 } else {
6496 selection.deselect(element);
6497 }
6498 });
6499 }
6500
6501 SelectionBehavior.$inject = [
6502 'eventBus',
6503 'selection',
6504 'canvas',
6505 'elementRegistry'
6506 ];
6507
6508 var SelectionModule = {
6509 __init__: [ 'selectionVisuals', 'selectionBehavior' ],
6510 __depends__: [
6511 InteractionEventsModule,
6512 OutlineModule
6513 ],
6514 selection: [ 'type', Selection ],
6515 selectionVisuals: [ 'type', SelectionVisuals ],
6516 selectionBehavior: [ 'type', SelectionBehavior ]
6517 };
6518
6519 /**
6520 * Util that provides unique IDs.
6521 *
6522 * @class djs.util.IdGenerator
6523 * @constructor
6524 * @memberOf djs.util
6525 *
6526 * The ids can be customized via a given prefix and contain a random value to avoid collisions.
6527 *
6528 * @param {String} prefix a prefix to prepend to generated ids (for better readability)
6529 */
6530 function IdGenerator(prefix) {
6531
6532 this._counter = 0;
6533 this._prefix = (prefix ? prefix + '-' : '') + Math.floor(Math.random() * 1000000000) + '-';
6534 }
6535
6536 /**
6537 * Returns a next unique ID.
6538 *
6539 * @method djs.util.IdGenerator#next
6540 *
6541 * @returns {String} the id
6542 */
6543 IdGenerator.prototype.next = function() {
6544 return this._prefix + (++this._counter);
6545 };
6546
6547 // document wide unique overlay ids
6548 var ids = new IdGenerator('ov');
6549
6550 var LOW_PRIORITY$2 = 500;
6551
6552
6553 /**
6554 * A service that allows users to attach overlays to diagram elements.
6555 *
6556 * The overlay service will take care of overlay positioning during updates.
6557 *
6558 * @example
6559 *
6560 * // add a pink badge on the top left of the shape
6561 * overlays.add(someShape, {
6562 * position: {
6563 * top: -5,
6564 * left: -5
6565 * },
6566 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
6567 * });
6568 *
6569 * // or add via shape id
6570 *
6571 * overlays.add('some-element-id', {
6572 * position: {
6573 * top: -5,
6574 * left: -5
6575 * }
6576 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
6577 * });
6578 *
6579 * // or add with optional type
6580 *
6581 * overlays.add(someShape, 'badge', {
6582 * position: {
6583 * top: -5,
6584 * left: -5
6585 * }
6586 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
6587 * });
6588 *
6589 *
6590 * // remove an overlay
6591 *
6592 * var id = overlays.add(...);
6593 * overlays.remove(id);
6594 *
6595 *
6596 * You may configure overlay defaults during tool by providing a `config` module
6597 * with `overlays.defaults` as an entry:
6598 *
6599 * {
6600 * overlays: {
6601 * defaults: {
6602 * show: {
6603 * minZoom: 0.7,
6604 * maxZoom: 5.0
6605 * },
6606 * scale: {
6607 * min: 1
6608 * }
6609 * }
6610 * }
6611 *
6612 * @param {Object} config
6613 * @param {EventBus} eventBus
6614 * @param {Canvas} canvas
6615 * @param {ElementRegistry} elementRegistry
6616 */
6617 function Overlays(config, eventBus, canvas, elementRegistry) {
6618
6619 this._eventBus = eventBus;
6620 this._canvas = canvas;
6621 this._elementRegistry = elementRegistry;
6622
6623 this._ids = ids;
6624
6625 this._overlayDefaults = assign({
6626
6627 // no show constraints
6628 show: null,
6629
6630 // always scale
6631 scale: true
6632 }, config && config.defaults);
6633
6634 /**
6635 * Mapping overlayId -> overlay
6636 */
6637 this._overlays = {};
6638
6639 /**
6640 * Mapping elementId -> overlay container
6641 */
6642 this._overlayContainers = [];
6643
6644 // root html element for all overlays
6645 this._overlayRoot = createRoot(canvas.getContainer());
6646
6647 this._init();
6648 }
6649
6650
6651 Overlays.$inject = [
6652 'config.overlays',
6653 'eventBus',
6654 'canvas',
6655 'elementRegistry'
6656 ];
6657
6658
6659 /**
6660 * Returns the overlay with the specified id or a list of overlays
6661 * for an element with a given type.
6662 *
6663 * @example
6664 *
6665 * // return the single overlay with the given id
6666 * overlays.get('some-id');
6667 *
6668 * // return all overlays for the shape
6669 * overlays.get({ element: someShape });
6670 *
6671 * // return all overlays on shape with type 'badge'
6672 * overlays.get({ element: someShape, type: 'badge' });
6673 *
6674 * // shape can also be specified as id
6675 * overlays.get({ element: 'element-id', type: 'badge' });
6676 *
6677 *
6678 * @param {Object} search
6679 * @param {String} [search.id]
6680 * @param {String|djs.model.Base} [search.element]
6681 * @param {String} [search.type]
6682 *
6683 * @return {Object|Array<Object>} the overlay(s)
6684 */
6685 Overlays.prototype.get = function(search) {
6686
6687 if (isString(search)) {
6688 search = { id: search };
6689 }
6690
6691 if (isString(search.element)) {
6692 search.element = this._elementRegistry.get(search.element);
6693 }
6694
6695 if (search.element) {
6696 var container = this._getOverlayContainer(search.element, true);
6697
6698 // return a list of overlays when searching by element (+type)
6699 if (container) {
6700 return search.type ? filter(container.overlays, matchPattern({ type: search.type })) : container.overlays.slice();
6701 } else {
6702 return [];
6703 }
6704 } else
6705 if (search.type) {
6706 return filter(this._overlays, matchPattern({ type: search.type }));
6707 } else {
6708
6709 // return single element when searching by id
6710 return search.id ? this._overlays[search.id] : null;
6711 }
6712 };
6713
6714 /**
6715 * Adds a HTML overlay to an element.
6716 *
6717 * @param {String|djs.model.Base} element attach overlay to this shape
6718 * @param {String} [type] optional type to assign to the overlay
6719 * @param {Object} overlay the overlay configuration
6720 *
6721 * @param {String|DOMElement} overlay.html html element to use as an overlay
6722 * @param {Object} [overlay.show] show configuration
6723 * @param {Number} [overlay.show.minZoom] minimal zoom level to show the overlay
6724 * @param {Number} [overlay.show.maxZoom] maximum zoom level to show the overlay
6725 * @param {Object} overlay.position where to attach the overlay
6726 * @param {Number} [overlay.position.left] relative to element bbox left attachment
6727 * @param {Number} [overlay.position.top] relative to element bbox top attachment
6728 * @param {Number} [overlay.position.bottom] relative to element bbox bottom attachment
6729 * @param {Number} [overlay.position.right] relative to element bbox right attachment
6730 * @param {Boolean|Object} [overlay.scale=true] false to preserve the same size regardless of
6731 * diagram zoom
6732 * @param {Number} [overlay.scale.min]
6733 * @param {Number} [overlay.scale.max]
6734 *
6735 * @return {String} id that may be used to reference the overlay for update or removal
6736 */
6737 Overlays.prototype.add = function(element, type, overlay) {
6738
6739 if (isObject(type)) {
6740 overlay = type;
6741 type = null;
6742 }
6743
6744 if (!element.id) {
6745 element = this._elementRegistry.get(element);
6746 }
6747
6748 if (!overlay.position) {
6749 throw new Error('must specifiy overlay position');
6750 }
6751
6752 if (!overlay.html) {
6753 throw new Error('must specifiy overlay html');
6754 }
6755
6756 if (!element) {
6757 throw new Error('invalid element specified');
6758 }
6759
6760 var id = this._ids.next();
6761
6762 overlay = assign({}, this._overlayDefaults, overlay, {
6763 id: id,
6764 type: type,
6765 element: element,
6766 html: overlay.html
6767 });
6768
6769 this._addOverlay(overlay);
6770
6771 return id;
6772 };
6773
6774
6775 /**
6776 * Remove an overlay with the given id or all overlays matching the given filter.
6777 *
6778 * @see Overlays#get for filter options.
6779 *
6780 * @param {String} [id]
6781 * @param {Object} [filter]
6782 */
6783 Overlays.prototype.remove = function(filter) {
6784
6785 var overlays = this.get(filter) || [];
6786
6787 if (!isArray(overlays)) {
6788 overlays = [ overlays ];
6789 }
6790
6791 var self = this;
6792
6793 forEach(overlays, function(overlay) {
6794
6795 var container = self._getOverlayContainer(overlay.element, true);
6796
6797 if (overlay) {
6798 remove$1(overlay.html);
6799 remove$1(overlay.htmlContainer);
6800
6801 delete overlay.htmlContainer;
6802 delete overlay.element;
6803
6804 delete self._overlays[overlay.id];
6805 }
6806
6807 if (container) {
6808 var idx = container.overlays.indexOf(overlay);
6809 if (idx !== -1) {
6810 container.overlays.splice(idx, 1);
6811 }
6812 }
6813 });
6814
6815 };
6816
6817
6818 Overlays.prototype.show = function() {
6819 setVisible(this._overlayRoot);
6820 };
6821
6822
6823 Overlays.prototype.hide = function() {
6824 setVisible(this._overlayRoot, false);
6825 };
6826
6827 Overlays.prototype.clear = function() {
6828 this._overlays = {};
6829
6830 this._overlayContainers = [];
6831
6832 clear$1(this._overlayRoot);
6833 };
6834
6835 Overlays.prototype._updateOverlayContainer = function(container) {
6836 var element = container.element,
6837 html = container.html;
6838
6839 // update container left,top according to the elements x,y coordinates
6840 // this ensures we can attach child elements relative to this container
6841
6842 var x = element.x,
6843 y = element.y;
6844
6845 if (element.waypoints) {
6846 var bbox = getBBox(element);
6847 x = bbox.x;
6848 y = bbox.y;
6849 }
6850
6851 setPosition(html, x, y);
6852
6853 attr$1(container.html, 'data-container-id', element.id);
6854 };
6855
6856
6857 Overlays.prototype._updateOverlay = function(overlay) {
6858
6859 var position = overlay.position,
6860 htmlContainer = overlay.htmlContainer,
6861 element = overlay.element;
6862
6863 // update overlay html relative to shape because
6864 // it is already positioned on the element
6865
6866 // update relative
6867 var left = position.left,
6868 top = position.top;
6869
6870 if (position.right !== undefined) {
6871
6872 var width;
6873
6874 if (element.waypoints) {
6875 width = getBBox(element).width;
6876 } else {
6877 width = element.width;
6878 }
6879
6880 left = position.right * -1 + width;
6881 }
6882
6883 if (position.bottom !== undefined) {
6884
6885 var height;
6886
6887 if (element.waypoints) {
6888 height = getBBox(element).height;
6889 } else {
6890 height = element.height;
6891 }
6892
6893 top = position.bottom * -1 + height;
6894 }
6895
6896 setPosition(htmlContainer, left || 0, top || 0);
6897 };
6898
6899
6900 Overlays.prototype._createOverlayContainer = function(element) {
6901 var html = domify('<div class="djs-overlays" style="position: absolute" />');
6902
6903 this._overlayRoot.appendChild(html);
6904
6905 var container = {
6906 html: html,
6907 element: element,
6908 overlays: []
6909 };
6910
6911 this._updateOverlayContainer(container);
6912
6913 this._overlayContainers.push(container);
6914
6915 return container;
6916 };
6917
6918
6919 Overlays.prototype._updateRoot = function(viewbox) {
6920 var scale = viewbox.scale || 1;
6921
6922 var matrix = 'matrix(' +
6923 [
6924 scale,
6925 0,
6926 0,
6927 scale,
6928 -1 * viewbox.x * scale,
6929 -1 * viewbox.y * scale
6930 ].join(',') +
6931 ')';
6932
6933 setTransform(this._overlayRoot, matrix);
6934 };
6935
6936
6937 Overlays.prototype._getOverlayContainer = function(element, raw) {
6938 var container = find(this._overlayContainers, function(c) {
6939 return c.element === element;
6940 });
6941
6942
6943 if (!container && !raw) {
6944 return this._createOverlayContainer(element);
6945 }
6946
6947 return container;
6948 };
6949
6950
6951 Overlays.prototype._addOverlay = function(overlay) {
6952
6953 var id = overlay.id,
6954 element = overlay.element,
6955 html = overlay.html,
6956 htmlContainer,
6957 overlayContainer;
6958
6959 // unwrap jquery (for those who need it)
6960 if (html.get && html.constructor.prototype.jquery) {
6961 html = html.get(0);
6962 }
6963
6964 // create proper html elements from
6965 // overlay HTML strings
6966 if (isString(html)) {
6967 html = domify(html);
6968 }
6969
6970 overlayContainer = this._getOverlayContainer(element);
6971
6972 htmlContainer = domify('<div class="djs-overlay" data-overlay-id="' + id + '" style="position: absolute">');
6973
6974 htmlContainer.appendChild(html);
6975
6976 if (overlay.type) {
6977 classes$1(htmlContainer).add('djs-overlay-' + overlay.type);
6978 }
6979
6980 overlay.htmlContainer = htmlContainer;
6981
6982 overlayContainer.overlays.push(overlay);
6983 overlayContainer.html.appendChild(htmlContainer);
6984
6985 this._overlays[id] = overlay;
6986
6987 this._updateOverlay(overlay);
6988 this._updateOverlayVisibilty(overlay, this._canvas.viewbox());
6989 };
6990
6991
6992 Overlays.prototype._updateOverlayVisibilty = function(overlay, viewbox) {
6993 var show = overlay.show,
6994 minZoom = show && show.minZoom,
6995 maxZoom = show && show.maxZoom,
6996 htmlContainer = overlay.htmlContainer,
6997 visible = true;
6998
6999 if (show) {
7000 if (
7001 (isDefined(minZoom) && minZoom > viewbox.scale) ||
7002 (isDefined(maxZoom) && maxZoom < viewbox.scale)
7003 ) {
7004 visible = false;
7005 }
7006
7007 setVisible(htmlContainer, visible);
7008 }
7009
7010 this._updateOverlayScale(overlay, viewbox);
7011 };
7012
7013
7014 Overlays.prototype._updateOverlayScale = function(overlay, viewbox) {
7015 var shouldScale = overlay.scale,
7016 minScale,
7017 maxScale,
7018 htmlContainer = overlay.htmlContainer;
7019
7020 var scale, transform = '';
7021
7022 if (shouldScale !== true) {
7023
7024 if (shouldScale === false) {
7025 minScale = 1;
7026 maxScale = 1;
7027 } else {
7028 minScale = shouldScale.min;
7029 maxScale = shouldScale.max;
7030 }
7031
7032 if (isDefined(minScale) && viewbox.scale < minScale) {
7033 scale = (1 / viewbox.scale || 1) * minScale;
7034 }
7035
7036 if (isDefined(maxScale) && viewbox.scale > maxScale) {
7037 scale = (1 / viewbox.scale || 1) * maxScale;
7038 }
7039 }
7040
7041 if (isDefined(scale)) {
7042 transform = 'scale(' + scale + ',' + scale + ')';
7043 }
7044
7045 setTransform(htmlContainer, transform);
7046 };
7047
7048
7049 Overlays.prototype._updateOverlaysVisibilty = function(viewbox) {
7050
7051 var self = this;
7052
7053 forEach(this._overlays, function(overlay) {
7054 self._updateOverlayVisibilty(overlay, viewbox);
7055 });
7056 };
7057
7058
7059 Overlays.prototype._init = function() {
7060
7061 var eventBus = this._eventBus;
7062
7063 var self = this;
7064
7065
7066 // scroll/zoom integration
7067
7068 function updateViewbox(viewbox) {
7069 self._updateRoot(viewbox);
7070 self._updateOverlaysVisibilty(viewbox);
7071
7072 self.show();
7073 }
7074
7075 eventBus.on('canvas.viewbox.changing', function(event) {
7076 self.hide();
7077 });
7078
7079 eventBus.on('canvas.viewbox.changed', function(event) {
7080 updateViewbox(event.viewbox);
7081 });
7082
7083
7084 // remove integration
7085
7086 eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
7087 var element = e.element;
7088 var overlays = self.get({ element: element });
7089
7090 forEach(overlays, function(o) {
7091 self.remove(o.id);
7092 });
7093
7094 var container = self._getOverlayContainer(element);
7095
7096 if (container) {
7097 remove$1(container.html);
7098 var i = self._overlayContainers.indexOf(container);
7099 if (i !== -1) {
7100 self._overlayContainers.splice(i, 1);
7101 }
7102 }
7103 });
7104
7105
7106 // move integration
7107
7108 eventBus.on('element.changed', LOW_PRIORITY$2, function(e) {
7109 var element = e.element;
7110
7111 var container = self._getOverlayContainer(element, true);
7112
7113 if (container) {
7114 forEach(container.overlays, function(overlay) {
7115 self._updateOverlay(overlay);
7116 });
7117
7118 self._updateOverlayContainer(container);
7119 }
7120 });
7121
7122
7123 // marker integration, simply add them on the overlays as classes, too.
7124
7125 eventBus.on('element.marker.update', function(e) {
7126 var container = self._getOverlayContainer(e.element, true);
7127 if (container) {
7128 classes$1(container.html)[e.add ? 'add' : 'remove'](e.marker);
7129 }
7130 });
7131
7132
7133 // clear overlays with diagram
7134
7135 eventBus.on('diagram.clear', this.clear, this);
7136 };
7137
7138
7139
7140 // helpers /////////////////////////////
7141
7142 function createRoot(parentNode) {
7143 var root = domify(
7144 '<div class="djs-overlay-container" style="position: absolute; width: 0; height: 0;" />'
7145 );
7146
7147 parentNode.insertBefore(root, parentNode.firstChild);
7148
7149 return root;
7150 }
7151
7152 function setPosition(el, x, y) {
7153 assign(el.style, { left: x + 'px', top: y + 'px' });
7154 }
7155
7156 function setVisible(el, visible) {
7157 el.style.display = visible === false ? 'none' : '';
7158 }
7159
7160 function setTransform(el, transform) {
7161
7162 el.style['transform-origin'] = 'top left';
7163
7164 [ '', '-ms-', '-webkit-' ].forEach(function(prefix) {
7165 el.style[prefix + 'transform'] = transform;
7166 });
7167 }
7168
7169 var OverlaysModule = {
7170 __init__: [ 'overlays' ],
7171 overlays: [ 'type', Overlays ]
7172 };
7173
7174 var CLASS_PATTERN = /^class /;
7175
7176 function isClass(fn) {
7177 return CLASS_PATTERN.test(fn.toString());
7178 }
7179
7180 function isArray$1(obj) {
7181 return Object.prototype.toString.call(obj) === '[object Array]';
7182 }
7183
7184 function annotate() {
7185 var args = Array.prototype.slice.call(arguments);
7186
7187 if (args.length === 1 && isArray$1(args[0])) {
7188 args = args[0];
7189 }
7190
7191 var fn = args.pop();
7192
7193 fn.$inject = args;
7194
7195 return fn;
7196 }
7197
7198 // Current limitations:
7199 // - can't put into "function arg" comments
7200 // function /* (no parenthesis like this) */ (){}
7201 // function abc( /* xx (no parenthesis like this) */ a, b) {}
7202 //
7203 // Just put the comment before function or inside:
7204 // /* (((this is fine))) */ function(a, b) {}
7205 // function abc(a) { /* (((this is fine))) */}
7206 //
7207 // - can't reliably auto-annotate constructor; we'll match the
7208 // first constructor(...) pattern found which may be the one
7209 // of a nested class, too.
7210
7211 var CONSTRUCTOR_ARGS = /constructor\s*[^(]*\(\s*([^)]*)\)/m;
7212 var FN_ARGS = /^function\s*[^(]*\(\s*([^)]*)\)/m;
7213 var FN_ARG = /\/\*([^*]*)\*\//m;
7214
7215 function parse$2(fn) {
7216
7217 if (typeof fn !== 'function') {
7218 throw new Error('Cannot annotate "' + fn + '". Expected a function!');
7219 }
7220
7221 var match = fn.toString().match(isClass(fn) ? CONSTRUCTOR_ARGS : FN_ARGS);
7222
7223 // may parse class without constructor
7224 if (!match) {
7225 return [];
7226 }
7227
7228 return match[1] && match[1].split(',').map(function (arg) {
7229 match = arg.match(FN_ARG);
7230 return match ? match[1].trim() : arg.trim();
7231 }) || [];
7232 }
7233
7234 function Module() {
7235 var providers = [];
7236
7237 this.factory = function (name, factory) {
7238 providers.push([name, 'factory', factory]);
7239 return this;
7240 };
7241
7242 this.value = function (name, value) {
7243 providers.push([name, 'value', value]);
7244 return this;
7245 };
7246
7247 this.type = function (name, type) {
7248 providers.push([name, 'type', type]);
7249 return this;
7250 };
7251
7252 this.forEach = function (iterator) {
7253 providers.forEach(iterator);
7254 };
7255 }
7256
7257 var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
7258
7259 function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
7260
7261 function Injector(modules, parent) {
7262 parent = parent || {
7263 get: function get(name, strict) {
7264 currentlyResolving.push(name);
7265
7266 if (strict === false) {
7267 return null;
7268 } else {
7269 throw error('No provider for "' + name + '"!');
7270 }
7271 }
7272 };
7273
7274 var currentlyResolving = [];
7275 var providers = this._providers = Object.create(parent._providers || null);
7276 var instances = this._instances = Object.create(null);
7277
7278 var self = instances.injector = this;
7279
7280 var error = function error(msg) {
7281 var stack = currentlyResolving.join(' -> ');
7282 currentlyResolving.length = 0;
7283 return new Error(stack ? msg + ' (Resolving: ' + stack + ')' : msg);
7284 };
7285
7286 /**
7287 * Return a named service.
7288 *
7289 * @param {String} name
7290 * @param {Boolean} [strict=true] if false, resolve missing services to null
7291 *
7292 * @return {Object}
7293 */
7294 var get = function get(name, strict) {
7295 if (!providers[name] && name.indexOf('.') !== -1) {
7296 var parts = name.split('.');
7297 var pivot = get(parts.shift());
7298
7299 while (parts.length) {
7300 pivot = pivot[parts.shift()];
7301 }
7302
7303 return pivot;
7304 }
7305
7306 if (hasProp(instances, name)) {
7307 return instances[name];
7308 }
7309
7310 if (hasProp(providers, name)) {
7311 if (currentlyResolving.indexOf(name) !== -1) {
7312 currentlyResolving.push(name);
7313 throw error('Cannot resolve circular dependency!');
7314 }
7315
7316 currentlyResolving.push(name);
7317 instances[name] = providers[name][0](providers[name][1]);
7318 currentlyResolving.pop();
7319
7320 return instances[name];
7321 }
7322
7323 return parent.get(name, strict);
7324 };
7325
7326 var fnDef = function fnDef(fn) {
7327 var locals = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7328
7329 if (typeof fn !== 'function') {
7330 if (isArray$1(fn)) {
7331 fn = annotate(fn.slice());
7332 } else {
7333 throw new Error('Cannot invoke "' + fn + '". Expected a function!');
7334 }
7335 }
7336
7337 var inject = fn.$inject || parse$2(fn);
7338 var dependencies = inject.map(function (dep) {
7339 if (hasProp(locals, dep)) {
7340 return locals[dep];
7341 } else {
7342 return get(dep);
7343 }
7344 });
7345
7346 return {
7347 fn: fn,
7348 dependencies: dependencies
7349 };
7350 };
7351
7352 var instantiate = function instantiate(Type) {
7353 var _fnDef = fnDef(Type),
7354 dependencies = _fnDef.dependencies,
7355 fn = _fnDef.fn;
7356
7357 return new (Function.prototype.bind.apply(fn, [null].concat(_toConsumableArray(dependencies))))();
7358 };
7359
7360 var invoke = function invoke(func, context, locals) {
7361 var _fnDef2 = fnDef(func, locals),
7362 dependencies = _fnDef2.dependencies,
7363 fn = _fnDef2.fn;
7364
7365 return fn.call.apply(fn, [context].concat(_toConsumableArray(dependencies)));
7366 };
7367
7368 var createPrivateInjectorFactory = function createPrivateInjectorFactory(privateChildInjector) {
7369 return annotate(function (key) {
7370 return privateChildInjector.get(key);
7371 });
7372 };
7373
7374 var createChild = function createChild(modules, forceNewInstances) {
7375 if (forceNewInstances && forceNewInstances.length) {
7376 var fromParentModule = Object.create(null);
7377 var matchedScopes = Object.create(null);
7378
7379 var privateInjectorsCache = [];
7380 var privateChildInjectors = [];
7381 var privateChildFactories = [];
7382
7383 var provider;
7384 var cacheIdx;
7385 var privateChildInjector;
7386 var privateChildInjectorFactory;
7387 for (var name in providers) {
7388 provider = providers[name];
7389
7390 if (forceNewInstances.indexOf(name) !== -1) {
7391 if (provider[2] === 'private') {
7392 cacheIdx = privateInjectorsCache.indexOf(provider[3]);
7393 if (cacheIdx === -1) {
7394 privateChildInjector = provider[3].createChild([], forceNewInstances);
7395 privateChildInjectorFactory = createPrivateInjectorFactory(privateChildInjector);
7396 privateInjectorsCache.push(provider[3]);
7397 privateChildInjectors.push(privateChildInjector);
7398 privateChildFactories.push(privateChildInjectorFactory);
7399 fromParentModule[name] = [privateChildInjectorFactory, name, 'private', privateChildInjector];
7400 } else {
7401 fromParentModule[name] = [privateChildFactories[cacheIdx], name, 'private', privateChildInjectors[cacheIdx]];
7402 }
7403 } else {
7404 fromParentModule[name] = [provider[2], provider[1]];
7405 }
7406 matchedScopes[name] = true;
7407 }
7408
7409 if ((provider[2] === 'factory' || provider[2] === 'type') && provider[1].$scope) {
7410 /* jshint -W083 */
7411 forceNewInstances.forEach(function (scope) {
7412 if (provider[1].$scope.indexOf(scope) !== -1) {
7413 fromParentModule[name] = [provider[2], provider[1]];
7414 matchedScopes[scope] = true;
7415 }
7416 });
7417 }
7418 }
7419
7420 forceNewInstances.forEach(function (scope) {
7421 if (!matchedScopes[scope]) {
7422 throw new Error('No provider for "' + scope + '". Cannot use provider from the parent!');
7423 }
7424 });
7425
7426 modules.unshift(fromParentModule);
7427 }
7428
7429 return new Injector(modules, self);
7430 };
7431
7432 var factoryMap = {
7433 factory: invoke,
7434 type: instantiate,
7435 value: function value(_value) {
7436 return _value;
7437 }
7438 };
7439
7440 modules.forEach(function (module) {
7441
7442 function arrayUnwrap(type, value) {
7443 if (type !== 'value' && isArray$1(value)) {
7444 value = annotate(value.slice());
7445 }
7446
7447 return value;
7448 }
7449
7450 // TODO(vojta): handle wrong inputs (modules)
7451 if (module instanceof Module) {
7452 module.forEach(function (provider) {
7453 var name = provider[0];
7454 var type = provider[1];
7455 var value = provider[2];
7456
7457 providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
7458 });
7459 } else if ((typeof module === 'undefined' ? 'undefined' : _typeof(module)) === 'object') {
7460 if (module.__exports__) {
7461 var clonedModule = Object.keys(module).reduce(function (m, key) {
7462 if (key.substring(0, 2) !== '__') {
7463 m[key] = module[key];
7464 }
7465 return m;
7466 }, Object.create(null));
7467
7468 var privateInjector = new Injector((module.__modules__ || []).concat([clonedModule]), self);
7469 var getFromPrivateInjector = annotate(function (key) {
7470 return privateInjector.get(key);
7471 });
7472 module.__exports__.forEach(function (key) {
7473 providers[key] = [getFromPrivateInjector, key, 'private', privateInjector];
7474 });
7475 } else {
7476 Object.keys(module).forEach(function (name) {
7477 if (module[name][2] === 'private') {
7478 providers[name] = module[name];
7479 return;
7480 }
7481
7482 var type = module[name][0];
7483 var value = module[name][1];
7484
7485 providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
7486 });
7487 }
7488 }
7489 });
7490
7491 // public API
7492 this.get = get;
7493 this.invoke = invoke;
7494 this.instantiate = instantiate;
7495 this.createChild = createChild;
7496 }
7497
7498 // helpers /////////////////
7499
7500 function hasProp(obj, prop) {
7501 return Object.hasOwnProperty.call(obj, prop);
7502 }
7503
7504 // apply default renderer with lowest possible priority
7505 // so that it only kicks in if noone else could render
7506 var DEFAULT_RENDER_PRIORITY$1 = 1;
7507
7508 /**
7509 * The default renderer used for shapes and connections.
7510 *
7511 * @param {EventBus} eventBus
7512 * @param {Styles} styles
7513 */
7514 function DefaultRenderer(eventBus, styles) {
7515
7516 //
7517 BaseRenderer.call(this, eventBus, DEFAULT_RENDER_PRIORITY$1);
7518
7519 this.CONNECTION_STYLE = styles.style([ 'no-fill' ], { strokeWidth: 5, stroke: 'fuchsia' });
7520 this.SHAPE_STYLE = styles.style({ fill: 'white', stroke: 'fuchsia', strokeWidth: 2 });
7521 this.FRAME_STYLE = styles.style([ 'no-fill' ], { stroke: 'fuchsia', strokeDasharray: 4, strokeWidth: 2 });
7522 }
7523
7524 inherits_browser(DefaultRenderer, BaseRenderer);
7525
7526
7527 DefaultRenderer.prototype.canRender = function() {
7528 return true;
7529 };
7530
7531 DefaultRenderer.prototype.drawShape = function drawShape(visuals, element) {
7532 var rect = create('rect');
7533
7534 attr(rect, {
7535 x: 0,
7536 y: 0,
7537 width: element.width || 0,
7538 height: element.height || 0
7539 });
7540
7541 if (isFrameElement(element)) {
7542 attr(rect, this.FRAME_STYLE);
7543 } else {
7544 attr(rect, this.SHAPE_STYLE);
7545 }
7546
7547 append(visuals, rect);
7548
7549 return rect;
7550 };
7551
7552 DefaultRenderer.prototype.drawConnection = function drawConnection(visuals, connection) {
7553
7554 var line = createLine(connection.waypoints, this.CONNECTION_STYLE);
7555 append(visuals, line);
7556
7557 return line;
7558 };
7559
7560 DefaultRenderer.prototype.getShapePath = function getShapePath(shape) {
7561
7562 var x = shape.x,
7563 y = shape.y,
7564 width = shape.width,
7565 height = shape.height;
7566
7567 var shapePath = [
7568 ['M', x, y],
7569 ['l', width, 0],
7570 ['l', 0, height],
7571 ['l', -width, 0],
7572 ['z']
7573 ];
7574
7575 return componentsToPath(shapePath);
7576 };
7577
7578 DefaultRenderer.prototype.getConnectionPath = function getConnectionPath(connection) {
7579 var waypoints = connection.waypoints;
7580
7581 var idx, point, connectionPath = [];
7582
7583 for (idx = 0; (point = waypoints[idx]); idx++) {
7584
7585 // take invisible docking into account
7586 // when creating the path
7587 point = point.original || point;
7588
7589 connectionPath.push([ idx === 0 ? 'M' : 'L', point.x, point.y ]);
7590 }
7591
7592 return componentsToPath(connectionPath);
7593 };
7594
7595
7596 DefaultRenderer.$inject = [ 'eventBus', 'styles' ];
7597
7598 /**
7599 * A component that manages shape styles
7600 */
7601 function Styles() {
7602
7603 var defaultTraits = {
7604
7605 'no-fill': {
7606 fill: 'none'
7607 },
7608 'no-border': {
7609 strokeOpacity: 0.0
7610 },
7611 'no-events': {
7612 pointerEvents: 'none'
7613 }
7614 };
7615
7616 var self = this;
7617
7618 /**
7619 * Builds a style definition from a className, a list of traits and an object of additional attributes.
7620 *
7621 * @param {String} className
7622 * @param {Array<String>} traits
7623 * @param {Object} additionalAttrs
7624 *
7625 * @return {Object} the style defintion
7626 */
7627 this.cls = function(className, traits, additionalAttrs) {
7628 var attrs = this.style(traits, additionalAttrs);
7629
7630 return assign(attrs, { 'class': className });
7631 };
7632
7633 /**
7634 * Builds a style definition from a list of traits and an object of additional attributes.
7635 *
7636 * @param {Array<String>} traits
7637 * @param {Object} additionalAttrs
7638 *
7639 * @return {Object} the style defintion
7640 */
7641 this.style = function(traits, additionalAttrs) {
7642
7643 if (!isArray(traits) && !additionalAttrs) {
7644 additionalAttrs = traits;
7645 traits = [];
7646 }
7647
7648 var attrs = reduce(traits, function(attrs, t) {
7649 return assign(attrs, defaultTraits[t] || {});
7650 }, {});
7651
7652 return additionalAttrs ? assign(attrs, additionalAttrs) : attrs;
7653 };
7654
7655 this.computeStyle = function(custom, traits, defaultStyles) {
7656 if (!isArray(traits)) {
7657 defaultStyles = traits;
7658 traits = [];
7659 }
7660
7661 return self.style(traits || [], assign({}, defaultStyles, custom || {}));
7662 };
7663 }
7664
7665 var DrawModule$1 = {
7666 __init__: [ 'defaultRenderer' ],
7667 defaultRenderer: [ 'type', DefaultRenderer ],
7668 styles: [ 'type', Styles ]
7669 };
7670
7671 /**
7672 * Failsafe remove an element from a collection
7673 *
7674 * @param {Array<Object>} [collection]
7675 * @param {Object} [element]
7676 *
7677 * @return {Number} the previous index of the element
7678 */
7679 function remove$2(collection, element) {
7680
7681 if (!collection || !element) {
7682 return -1;
7683 }
7684
7685 var idx = collection.indexOf(element);
7686
7687 if (idx !== -1) {
7688 collection.splice(idx, 1);
7689 }
7690
7691 return idx;
7692 }
7693
7694 /**
7695 * Fail save add an element to the given connection, ensuring
7696 * it does not yet exist.
7697 *
7698 * @param {Array<Object>} collection
7699 * @param {Object} element
7700 * @param {Number} idx
7701 */
7702 function add(collection, element, idx) {
7703
7704 if (!collection || !element) {
7705 return;
7706 }
7707
7708 if (typeof idx !== 'number') {
7709 idx = -1;
7710 }
7711
7712 var currentIdx = collection.indexOf(element);
7713
7714 if (currentIdx !== -1) {
7715
7716 if (currentIdx === idx) {
7717
7718 // nothing to do, position has not changed
7719 return;
7720 } else {
7721
7722 if (idx !== -1) {
7723
7724 // remove from current position
7725 collection.splice(currentIdx, 1);
7726 } else {
7727
7728 // already exists in collection
7729 return;
7730 }
7731 }
7732 }
7733
7734 if (idx !== -1) {
7735
7736 // insert at specified position
7737 collection.splice(idx, 0, element);
7738 } else {
7739
7740 // push to end
7741 collection.push(element);
7742 }
7743 }
7744
7745 function round(number, resolution) {
7746 return Math.round(number * resolution) / resolution;
7747 }
7748
7749 function ensurePx(number) {
7750 return isNumber(number) ? number + 'px' : number;
7751 }
7752
7753 /**
7754 * Creates a HTML container element for a SVG element with
7755 * the given configuration
7756 *
7757 * @param {Object} options
7758 * @return {HTMLElement} the container element
7759 */
7760 function createContainer(options) {
7761
7762 options = assign({}, { width: '100%', height: '100%' }, options);
7763
7764 var container = options.container || document.body;
7765
7766 // create a <div> around the svg element with the respective size
7767 // this way we can always get the correct container size
7768 // (this is impossible for <svg> elements at the moment)
7769 var parent = document.createElement('div');
7770 parent.setAttribute('class', 'djs-container');
7771
7772 assign(parent.style, {
7773 position: 'relative',
7774 overflow: 'hidden',
7775 width: ensurePx(options.width),
7776 height: ensurePx(options.height)
7777 });
7778
7779 container.appendChild(parent);
7780
7781 return parent;
7782 }
7783
7784 function createGroup(parent, cls, childIndex) {
7785 var group = create('g');
7786 classes(group).add(cls);
7787
7788 var index = childIndex !== undefined ? childIndex : parent.childNodes.length - 1;
7789
7790 // must ensure second argument is node or _null_
7791 // cf. https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore
7792 parent.insertBefore(group, parent.childNodes[index] || null);
7793
7794 return group;
7795 }
7796
7797 var BASE_LAYER = 'base';
7798
7799
7800 var REQUIRED_MODEL_ATTRS = {
7801 shape: [ 'x', 'y', 'width', 'height' ],
7802 connection: [ 'waypoints' ]
7803 };
7804
7805 /**
7806 * The main drawing canvas.
7807 *
7808 * @class
7809 * @constructor
7810 *
7811 * @emits Canvas#canvas.init
7812 *
7813 * @param {Object} config
7814 * @param {EventBus} eventBus
7815 * @param {GraphicsFactory} graphicsFactory
7816 * @param {ElementRegistry} elementRegistry
7817 */
7818 function Canvas(config, eventBus, graphicsFactory, elementRegistry) {
7819
7820 this._eventBus = eventBus;
7821 this._elementRegistry = elementRegistry;
7822 this._graphicsFactory = graphicsFactory;
7823
7824 this._init(config || {});
7825 }
7826
7827 Canvas.$inject = [
7828 'config.canvas',
7829 'eventBus',
7830 'graphicsFactory',
7831 'elementRegistry'
7832 ];
7833
7834
7835 Canvas.prototype._init = function(config) {
7836
7837 var eventBus = this._eventBus;
7838
7839 // Creates a <svg> element that is wrapped into a <div>.
7840 // This way we are always able to correctly figure out the size of the svg element
7841 // by querying the parent node.
7842 //
7843 // (It is not possible to get the size of a svg element cross browser @ 2014-04-01)
7844 //
7845 // <div class="djs-container" style="width: {desired-width}, height: {desired-height}">
7846 // <svg width="100%" height="100%">
7847 // ...
7848 // </svg>
7849 // </div>
7850
7851 // html container
7852 var container = this._container = createContainer(config);
7853
7854 var svg = this._svg = create('svg');
7855 attr(svg, { width: '100%', height: '100%' });
7856
7857 append(container, svg);
7858
7859 var viewport = this._viewport = createGroup(svg, 'viewport');
7860
7861 this._layers = {};
7862
7863 // debounce canvas.viewbox.changed events
7864 // for smoother diagram interaction
7865 if (config.deferUpdate !== false) {
7866 this._viewboxChanged = debounce(bind(this._viewboxChanged, this), 300);
7867 }
7868
7869 eventBus.on('diagram.init', function() {
7870
7871 /**
7872 * An event indicating that the canvas is ready to be drawn on.
7873 *
7874 * @memberOf Canvas
7875 *
7876 * @event canvas.init
7877 *
7878 * @type {Object}
7879 * @property {SVGElement} svg the created svg element
7880 * @property {SVGElement} viewport the direct parent of diagram elements and shapes
7881 */
7882 eventBus.fire('canvas.init', {
7883 svg: svg,
7884 viewport: viewport
7885 });
7886
7887 }, this);
7888
7889 // reset viewbox on shape changes to
7890 // recompute the viewbox
7891 eventBus.on([
7892 'shape.added',
7893 'connection.added',
7894 'shape.removed',
7895 'connection.removed',
7896 'elements.changed'
7897 ], function() {
7898 delete this._cachedViewbox;
7899 }, this);
7900
7901 eventBus.on('diagram.destroy', 500, this._destroy, this);
7902 eventBus.on('diagram.clear', 500, this._clear, this);
7903 };
7904
7905 Canvas.prototype._destroy = function(emit) {
7906 this._eventBus.fire('canvas.destroy', {
7907 svg: this._svg,
7908 viewport: this._viewport
7909 });
7910
7911 var parent = this._container.parentNode;
7912
7913 if (parent) {
7914 parent.removeChild(this._container);
7915 }
7916
7917 delete this._svg;
7918 delete this._container;
7919 delete this._layers;
7920 delete this._rootElement;
7921 delete this._viewport;
7922 };
7923
7924 Canvas.prototype._clear = function() {
7925
7926 var self = this;
7927
7928 var allElements = this._elementRegistry.getAll();
7929
7930 // remove all elements
7931 allElements.forEach(function(element) {
7932 var type = getType(element);
7933
7934 if (type === 'root') {
7935 self.setRootElement(null, true);
7936 } else {
7937 self._removeElement(element, type);
7938 }
7939 });
7940
7941 // force recomputation of view box
7942 delete this._cachedViewbox;
7943 };
7944
7945 /**
7946 * Returns the default layer on which
7947 * all elements are drawn.
7948 *
7949 * @returns {SVGElement}
7950 */
7951 Canvas.prototype.getDefaultLayer = function() {
7952 return this.getLayer(BASE_LAYER, 0);
7953 };
7954
7955 /**
7956 * Returns a layer that is used to draw elements
7957 * or annotations on it.
7958 *
7959 * Non-existing layers retrieved through this method
7960 * will be created. During creation, the optional index
7961 * may be used to create layers below or above existing layers.
7962 * A layer with a certain index is always created above all
7963 * existing layers with the same index.
7964 *
7965 * @param {String} name
7966 * @param {Number} index
7967 *
7968 * @returns {SVGElement}
7969 */
7970 Canvas.prototype.getLayer = function(name, index) {
7971
7972 if (!name) {
7973 throw new Error('must specify a name');
7974 }
7975
7976 var layer = this._layers[name];
7977
7978 if (!layer) {
7979 layer = this._layers[name] = this._createLayer(name, index);
7980 }
7981
7982 // throw an error if layer creation / retrival is
7983 // requested on different index
7984 if (typeof index !== 'undefined' && layer.index !== index) {
7985 throw new Error('layer <' + name + '> already created at index <' + index + '>');
7986 }
7987
7988 return layer.group;
7989 };
7990
7991 /**
7992 * Creates a given layer and returns it.
7993 *
7994 * @param {String} name
7995 * @param {Number} [index=0]
7996 *
7997 * @return {Object} layer descriptor with { index, group: SVGGroup }
7998 */
7999 Canvas.prototype._createLayer = function(name, index) {
8000
8001 if (!index) {
8002 index = 0;
8003 }
8004
8005 var childIndex = reduce(this._layers, function(childIndex, layer) {
8006 if (index >= layer.index) {
8007 childIndex++;
8008 }
8009
8010 return childIndex;
8011 }, 0);
8012
8013 return {
8014 group: createGroup(this._viewport, 'layer-' + name, childIndex),
8015 index: index
8016 };
8017
8018 };
8019
8020 /**
8021 * Returns the html element that encloses the
8022 * drawing canvas.
8023 *
8024 * @return {DOMNode}
8025 */
8026 Canvas.prototype.getContainer = function() {
8027 return this._container;
8028 };
8029
8030
8031 // markers //////////////////////
8032
8033 Canvas.prototype._updateMarker = function(element, marker, add) {
8034 var container;
8035
8036 if (!element.id) {
8037 element = this._elementRegistry.get(element);
8038 }
8039
8040 // we need to access all
8041 container = this._elementRegistry._elements[element.id];
8042
8043 if (!container) {
8044 return;
8045 }
8046
8047 forEach([ container.gfx, container.secondaryGfx ], function(gfx) {
8048 if (gfx) {
8049
8050 // invoke either addClass or removeClass based on mode
8051 if (add) {
8052 classes(gfx).add(marker);
8053 } else {
8054 classes(gfx).remove(marker);
8055 }
8056 }
8057 });
8058
8059 /**
8060 * An event indicating that a marker has been updated for an element
8061 *
8062 * @event element.marker.update
8063 * @type {Object}
8064 * @property {djs.model.Element} element the shape
8065 * @property {Object} gfx the graphical representation of the shape
8066 * @property {String} marker
8067 * @property {Boolean} add true if the marker was added, false if it got removed
8068 */
8069 this._eventBus.fire('element.marker.update', { element: element, gfx: container.gfx, marker: marker, add: !!add });
8070 };
8071
8072
8073 /**
8074 * Adds a marker to an element (basically a css class).
8075 *
8076 * Fires the element.marker.update event, making it possible to
8077 * integrate extension into the marker life-cycle, too.
8078 *
8079 * @example
8080 * canvas.addMarker('foo', 'some-marker');
8081 *
8082 * var fooGfx = canvas.getGraphics('foo');
8083 *
8084 * fooGfx; // <g class="... some-marker"> ... </g>
8085 *
8086 * @param {String|djs.model.Base} element
8087 * @param {String} marker
8088 */
8089 Canvas.prototype.addMarker = function(element, marker) {
8090 this._updateMarker(element, marker, true);
8091 };
8092
8093
8094 /**
8095 * Remove a marker from an element.
8096 *
8097 * Fires the element.marker.update event, making it possible to
8098 * integrate extension into the marker life-cycle, too.
8099 *
8100 * @param {String|djs.model.Base} element
8101 * @param {String} marker
8102 */
8103 Canvas.prototype.removeMarker = function(element, marker) {
8104 this._updateMarker(element, marker, false);
8105 };
8106
8107 /**
8108 * Check the existence of a marker on element.
8109 *
8110 * @param {String|djs.model.Base} element
8111 * @param {String} marker
8112 */
8113 Canvas.prototype.hasMarker = function(element, marker) {
8114 if (!element.id) {
8115 element = this._elementRegistry.get(element);
8116 }
8117
8118 var gfx = this.getGraphics(element);
8119
8120 return classes(gfx).has(marker);
8121 };
8122
8123 /**
8124 * Toggles a marker on an element.
8125 *
8126 * Fires the element.marker.update event, making it possible to
8127 * integrate extension into the marker life-cycle, too.
8128 *
8129 * @param {String|djs.model.Base} element
8130 * @param {String} marker
8131 */
8132 Canvas.prototype.toggleMarker = function(element, marker) {
8133 if (this.hasMarker(element, marker)) {
8134 this.removeMarker(element, marker);
8135 } else {
8136 this.addMarker(element, marker);
8137 }
8138 };
8139
8140 Canvas.prototype.getRootElement = function() {
8141 if (!this._rootElement) {
8142 this.setRootElement({ id: '__implicitroot', children: [] });
8143 }
8144
8145 return this._rootElement;
8146 };
8147
8148
8149
8150 // root element handling //////////////////////
8151
8152 /**
8153 * Sets a given element as the new root element for the canvas
8154 * and returns the new root element.
8155 *
8156 * @param {Object|djs.model.Root} element
8157 * @param {Boolean} [override] whether to override the current root element, if any
8158 *
8159 * @return {Object|djs.model.Root} new root element
8160 */
8161 Canvas.prototype.setRootElement = function(element, override) {
8162
8163 if (element) {
8164 this._ensureValid('root', element);
8165 }
8166
8167 var currentRoot = this._rootElement,
8168 elementRegistry = this._elementRegistry,
8169 eventBus = this._eventBus;
8170
8171 if (currentRoot) {
8172 if (!override) {
8173 throw new Error('rootElement already set, need to specify override');
8174 }
8175
8176 // simulate element remove event sequence
8177 eventBus.fire('root.remove', { element: currentRoot });
8178 eventBus.fire('root.removed', { element: currentRoot });
8179
8180 elementRegistry.remove(currentRoot);
8181 }
8182
8183 if (element) {
8184 var gfx = this.getDefaultLayer();
8185
8186 // resemble element add event sequence
8187 eventBus.fire('root.add', { element: element });
8188
8189 elementRegistry.add(element, gfx, this._svg);
8190
8191 eventBus.fire('root.added', { element: element, gfx: gfx });
8192 }
8193
8194 this._rootElement = element;
8195
8196 return element;
8197 };
8198
8199
8200
8201 // add functionality //////////////////////
8202
8203 Canvas.prototype._ensureValid = function(type, element) {
8204 if (!element.id) {
8205 throw new Error('element must have an id');
8206 }
8207
8208 if (this._elementRegistry.get(element.id)) {
8209 throw new Error('element with id ' + element.id + ' already exists');
8210 }
8211
8212 var requiredAttrs = REQUIRED_MODEL_ATTRS[type];
8213
8214 var valid = every(requiredAttrs, function(attr) {
8215 return typeof element[attr] !== 'undefined';
8216 });
8217
8218 if (!valid) {
8219 throw new Error(
8220 'must supply { ' + requiredAttrs.join(', ') + ' } with ' + type);
8221 }
8222 };
8223
8224 Canvas.prototype._setParent = function(element, parent, parentIndex) {
8225 add(parent.children, element, parentIndex);
8226 element.parent = parent;
8227 };
8228
8229 /**
8230 * Adds an element to the canvas.
8231 *
8232 * This wires the parent <-> child relationship between the element and
8233 * a explicitly specified parent or an implicit root element.
8234 *
8235 * During add it emits the events
8236 *
8237 * * <{type}.add> (element, parent)
8238 * * <{type}.added> (element, gfx)
8239 *
8240 * Extensions may hook into these events to perform their magic.
8241 *
8242 * @param {String} type
8243 * @param {Object|djs.model.Base} element
8244 * @param {Object|djs.model.Base} [parent]
8245 * @param {Number} [parentIndex]
8246 *
8247 * @return {Object|djs.model.Base} the added element
8248 */
8249 Canvas.prototype._addElement = function(type, element, parent, parentIndex) {
8250
8251 parent = parent || this.getRootElement();
8252
8253 var eventBus = this._eventBus,
8254 graphicsFactory = this._graphicsFactory;
8255
8256 this._ensureValid(type, element);
8257
8258 eventBus.fire(type + '.add', { element: element, parent: parent });
8259
8260 this._setParent(element, parent, parentIndex);
8261
8262 // create graphics
8263 var gfx = graphicsFactory.create(type, element, parentIndex);
8264
8265 this._elementRegistry.add(element, gfx);
8266
8267 // update its visual
8268 graphicsFactory.update(type, element, gfx);
8269
8270 eventBus.fire(type + '.added', { element: element, gfx: gfx });
8271
8272 return element;
8273 };
8274
8275 /**
8276 * Adds a shape to the canvas
8277 *
8278 * @param {Object|djs.model.Shape} shape to add to the diagram
8279 * @param {djs.model.Base} [parent]
8280 * @param {Number} [parentIndex]
8281 *
8282 * @return {djs.model.Shape} the added shape
8283 */
8284 Canvas.prototype.addShape = function(shape, parent, parentIndex) {
8285 return this._addElement('shape', shape, parent, parentIndex);
8286 };
8287
8288 /**
8289 * Adds a connection to the canvas
8290 *
8291 * @param {Object|djs.model.Connection} connection to add to the diagram
8292 * @param {djs.model.Base} [parent]
8293 * @param {Number} [parentIndex]
8294 *
8295 * @return {djs.model.Connection} the added connection
8296 */
8297 Canvas.prototype.addConnection = function(connection, parent, parentIndex) {
8298 return this._addElement('connection', connection, parent, parentIndex);
8299 };
8300
8301
8302 /**
8303 * Internal remove element
8304 */
8305 Canvas.prototype._removeElement = function(element, type) {
8306
8307 var elementRegistry = this._elementRegistry,
8308 graphicsFactory = this._graphicsFactory,
8309 eventBus = this._eventBus;
8310
8311 element = elementRegistry.get(element.id || element);
8312
8313 if (!element) {
8314
8315 // element was removed already
8316 return;
8317 }
8318
8319 eventBus.fire(type + '.remove', { element: element });
8320
8321 graphicsFactory.remove(element);
8322
8323 // unset parent <-> child relationship
8324 remove$2(element.parent && element.parent.children, element);
8325 element.parent = null;
8326
8327 eventBus.fire(type + '.removed', { element: element });
8328
8329 elementRegistry.remove(element);
8330
8331 return element;
8332 };
8333
8334
8335 /**
8336 * Removes a shape from the canvas
8337 *
8338 * @param {String|djs.model.Shape} shape or shape id to be removed
8339 *
8340 * @return {djs.model.Shape} the removed shape
8341 */
8342 Canvas.prototype.removeShape = function(shape) {
8343
8344 /**
8345 * An event indicating that a shape is about to be removed from the canvas.
8346 *
8347 * @memberOf Canvas
8348 *
8349 * @event shape.remove
8350 * @type {Object}
8351 * @property {djs.model.Shape} element the shape descriptor
8352 * @property {Object} gfx the graphical representation of the shape
8353 */
8354
8355 /**
8356 * An event indicating that a shape has been removed from the canvas.
8357 *
8358 * @memberOf Canvas
8359 *
8360 * @event shape.removed
8361 * @type {Object}
8362 * @property {djs.model.Shape} element the shape descriptor
8363 * @property {Object} gfx the graphical representation of the shape
8364 */
8365 return this._removeElement(shape, 'shape');
8366 };
8367
8368
8369 /**
8370 * Removes a connection from the canvas
8371 *
8372 * @param {String|djs.model.Connection} connection or connection id to be removed
8373 *
8374 * @return {djs.model.Connection} the removed connection
8375 */
8376 Canvas.prototype.removeConnection = function(connection) {
8377
8378 /**
8379 * An event indicating that a connection is about to be removed from the canvas.
8380 *
8381 * @memberOf Canvas
8382 *
8383 * @event connection.remove
8384 * @type {Object}
8385 * @property {djs.model.Connection} element the connection descriptor
8386 * @property {Object} gfx the graphical representation of the connection
8387 */
8388
8389 /**
8390 * An event indicating that a connection has been removed from the canvas.
8391 *
8392 * @memberOf Canvas
8393 *
8394 * @event connection.removed
8395 * @type {Object}
8396 * @property {djs.model.Connection} element the connection descriptor
8397 * @property {Object} gfx the graphical representation of the connection
8398 */
8399 return this._removeElement(connection, 'connection');
8400 };
8401
8402
8403 /**
8404 * Return the graphical object underlaying a certain diagram element
8405 *
8406 * @param {String|djs.model.Base} element descriptor of the element
8407 * @param {Boolean} [secondary=false] whether to return the secondary connected element
8408 *
8409 * @return {SVGElement}
8410 */
8411 Canvas.prototype.getGraphics = function(element, secondary) {
8412 return this._elementRegistry.getGraphics(element, secondary);
8413 };
8414
8415
8416 /**
8417 * Perform a viewbox update via a given change function.
8418 *
8419 * @param {Function} changeFn
8420 */
8421 Canvas.prototype._changeViewbox = function(changeFn) {
8422
8423 // notify others of the upcoming viewbox change
8424 this._eventBus.fire('canvas.viewbox.changing');
8425
8426 // perform actual change
8427 changeFn.apply(this);
8428
8429 // reset the cached viewbox so that
8430 // a new get operation on viewbox or zoom
8431 // triggers a viewbox re-computation
8432 this._cachedViewbox = null;
8433
8434 // notify others of the change; this step
8435 // may or may not be debounced
8436 this._viewboxChanged();
8437 };
8438
8439 Canvas.prototype._viewboxChanged = function() {
8440 this._eventBus.fire('canvas.viewbox.changed', { viewbox: this.viewbox() });
8441 };
8442
8443
8444 /**
8445 * Gets or sets the view box of the canvas, i.e. the
8446 * area that is currently displayed.
8447 *
8448 * The getter may return a cached viewbox (if it is currently
8449 * changing). To force a recomputation, pass `false` as the first argument.
8450 *
8451 * @example
8452 *
8453 * canvas.viewbox({ x: 100, y: 100, width: 500, height: 500 })
8454 *
8455 * // sets the visible area of the diagram to (100|100) -> (600|100)
8456 * // and and scales it according to the diagram width
8457 *
8458 * var viewbox = canvas.viewbox(); // pass `false` to force recomputing the box.
8459 *
8460 * console.log(viewbox);
8461 * // {
8462 * // inner: Dimensions,
8463 * // outer: Dimensions,
8464 * // scale,
8465 * // x, y,
8466 * // width, height
8467 * // }
8468 *
8469 * // if the current diagram is zoomed and scrolled, you may reset it to the
8470 * // default zoom via this method, too:
8471 *
8472 * var zoomedAndScrolledViewbox = canvas.viewbox();
8473 *
8474 * canvas.viewbox({
8475 * x: 0,
8476 * y: 0,
8477 * width: zoomedAndScrolledViewbox.outer.width,
8478 * height: zoomedAndScrolledViewbox.outer.height
8479 * });
8480 *
8481 * @param {Object} [box] the new view box to set
8482 * @param {Number} box.x the top left X coordinate of the canvas visible in view box
8483 * @param {Number} box.y the top left Y coordinate of the canvas visible in view box
8484 * @param {Number} box.width the visible width
8485 * @param {Number} box.height
8486 *
8487 * @return {Object} the current view box
8488 */
8489 Canvas.prototype.viewbox = function(box) {
8490
8491 if (box === undefined && this._cachedViewbox) {
8492 return this._cachedViewbox;
8493 }
8494
8495 var viewport = this._viewport,
8496 innerBox,
8497 outerBox = this.getSize(),
8498 matrix,
8499 transform$1,
8500 scale,
8501 x, y;
8502
8503 if (!box) {
8504
8505 // compute the inner box based on the
8506 // diagrams default layer. This allows us to exclude
8507 // external components, such as overlays
8508 innerBox = this.getDefaultLayer().getBBox();
8509
8510 transform$1 = transform(viewport);
8511 matrix = transform$1 ? transform$1.matrix : createMatrix();
8512 scale = round(matrix.a, 1000);
8513
8514 x = round(-matrix.e || 0, 1000);
8515 y = round(-matrix.f || 0, 1000);
8516
8517 box = this._cachedViewbox = {
8518 x: x ? x / scale : 0,
8519 y: y ? y / scale : 0,
8520 width: outerBox.width / scale,
8521 height: outerBox.height / scale,
8522 scale: scale,
8523 inner: {
8524 width: innerBox.width,
8525 height: innerBox.height,
8526 x: innerBox.x,
8527 y: innerBox.y
8528 },
8529 outer: outerBox
8530 };
8531
8532 return box;
8533 } else {
8534
8535 this._changeViewbox(function() {
8536 scale = Math.min(outerBox.width / box.width, outerBox.height / box.height);
8537
8538 var matrix = this._svg.createSVGMatrix()
8539 .scale(scale)
8540 .translate(-box.x, -box.y);
8541
8542 transform(viewport, matrix);
8543 });
8544 }
8545
8546 return box;
8547 };
8548
8549
8550 /**
8551 * Gets or sets the scroll of the canvas.
8552 *
8553 * @param {Object} [delta] the new scroll to apply.
8554 *
8555 * @param {Number} [delta.dx]
8556 * @param {Number} [delta.dy]
8557 */
8558 Canvas.prototype.scroll = function(delta) {
8559
8560 var node = this._viewport;
8561 var matrix = node.getCTM();
8562
8563 if (delta) {
8564 this._changeViewbox(function() {
8565 delta = assign({ dx: 0, dy: 0 }, delta || {});
8566
8567 matrix = this._svg.createSVGMatrix().translate(delta.dx, delta.dy).multiply(matrix);
8568
8569 setCTM(node, matrix);
8570 });
8571 }
8572
8573 return { x: matrix.e, y: matrix.f };
8574 };
8575
8576
8577 /**
8578 * Gets or sets the current zoom of the canvas, optionally zooming
8579 * to the specified position.
8580 *
8581 * The getter may return a cached zoom level. Call it with `false` as
8582 * the first argument to force recomputation of the current level.
8583 *
8584 * @param {String|Number} [newScale] the new zoom level, either a number, i.e. 0.9,
8585 * or `fit-viewport` to adjust the size to fit the current viewport
8586 * @param {String|Point} [center] the reference point { x: .., y: ..} to zoom to, 'auto' to zoom into mid or null
8587 *
8588 * @return {Number} the current scale
8589 */
8590 Canvas.prototype.zoom = function(newScale, center) {
8591
8592 if (!newScale) {
8593 return this.viewbox(newScale).scale;
8594 }
8595
8596 if (newScale === 'fit-viewport') {
8597 return this._fitViewport(center);
8598 }
8599
8600 var outer,
8601 matrix;
8602
8603 this._changeViewbox(function() {
8604
8605 if (typeof center !== 'object') {
8606 outer = this.viewbox().outer;
8607
8608 center = {
8609 x: outer.width / 2,
8610 y: outer.height / 2
8611 };
8612 }
8613
8614 matrix = this._setZoom(newScale, center);
8615 });
8616
8617 return round(matrix.a, 1000);
8618 };
8619
8620 function setCTM(node, m) {
8621 var mstr = 'matrix(' + m.a + ',' + m.b + ',' + m.c + ',' + m.d + ',' + m.e + ',' + m.f + ')';
8622 node.setAttribute('transform', mstr);
8623 }
8624
8625 Canvas.prototype._fitViewport = function(center) {
8626
8627 var vbox = this.viewbox(),
8628 outer = vbox.outer,
8629 inner = vbox.inner,
8630 newScale,
8631 newViewbox;
8632
8633 // display the complete diagram without zooming in.
8634 // instead of relying on internal zoom, we perform a
8635 // hard reset on the canvas viewbox to realize this
8636 //
8637 // if diagram does not need to be zoomed in, we focus it around
8638 // the diagram origin instead
8639
8640 if (inner.x >= 0 &&
8641 inner.y >= 0 &&
8642 inner.x + inner.width <= outer.width &&
8643 inner.y + inner.height <= outer.height &&
8644 !center) {
8645
8646 newViewbox = {
8647 x: 0,
8648 y: 0,
8649 width: Math.max(inner.width + inner.x, outer.width),
8650 height: Math.max(inner.height + inner.y, outer.height)
8651 };
8652 } else {
8653
8654 newScale = Math.min(1, outer.width / inner.width, outer.height / inner.height);
8655 newViewbox = {
8656 x: inner.x + (center ? inner.width / 2 - outer.width / newScale / 2 : 0),
8657 y: inner.y + (center ? inner.height / 2 - outer.height / newScale / 2 : 0),
8658 width: outer.width / newScale,
8659 height: outer.height / newScale
8660 };
8661 }
8662
8663 this.viewbox(newViewbox);
8664
8665 return this.viewbox(false).scale;
8666 };
8667
8668
8669 Canvas.prototype._setZoom = function(scale, center) {
8670
8671 var svg = this._svg,
8672 viewport = this._viewport;
8673
8674 var matrix = svg.createSVGMatrix();
8675 var point = svg.createSVGPoint();
8676
8677 var centerPoint,
8678 originalPoint,
8679 currentMatrix,
8680 scaleMatrix,
8681 newMatrix;
8682
8683 currentMatrix = viewport.getCTM();
8684
8685 var currentScale = currentMatrix.a;
8686
8687 if (center) {
8688 centerPoint = assign(point, center);
8689
8690 // revert applied viewport transformations
8691 originalPoint = centerPoint.matrixTransform(currentMatrix.inverse());
8692
8693 // create scale matrix
8694 scaleMatrix = matrix
8695 .translate(originalPoint.x, originalPoint.y)
8696 .scale(1 / currentScale * scale)
8697 .translate(-originalPoint.x, -originalPoint.y);
8698
8699 newMatrix = currentMatrix.multiply(scaleMatrix);
8700 } else {
8701 newMatrix = matrix.scale(scale);
8702 }
8703
8704 setCTM(this._viewport, newMatrix);
8705
8706 return newMatrix;
8707 };
8708
8709
8710 /**
8711 * Returns the size of the canvas
8712 *
8713 * @return {Dimensions}
8714 */
8715 Canvas.prototype.getSize = function() {
8716 return {
8717 width: this._container.clientWidth,
8718 height: this._container.clientHeight
8719 };
8720 };
8721
8722
8723 /**
8724 * Return the absolute bounding box for the given element
8725 *
8726 * The absolute bounding box may be used to display overlays in the
8727 * callers (browser) coordinate system rather than the zoomed in/out
8728 * canvas coordinates.
8729 *
8730 * @param {ElementDescriptor} element
8731 * @return {Bounds} the absolute bounding box
8732 */
8733 Canvas.prototype.getAbsoluteBBox = function(element) {
8734 var vbox = this.viewbox();
8735 var bbox;
8736
8737 // connection
8738 // use svg bbox
8739 if (element.waypoints) {
8740 var gfx = this.getGraphics(element);
8741
8742 bbox = gfx.getBBox();
8743 }
8744
8745 // shapes
8746 // use data
8747 else {
8748 bbox = element;
8749 }
8750
8751 var x = bbox.x * vbox.scale - vbox.x * vbox.scale;
8752 var y = bbox.y * vbox.scale - vbox.y * vbox.scale;
8753
8754 var width = bbox.width * vbox.scale;
8755 var height = bbox.height * vbox.scale;
8756
8757 return {
8758 x: x,
8759 y: y,
8760 width: width,
8761 height: height
8762 };
8763 };
8764
8765 /**
8766 * Fires an event in order other modules can react to the
8767 * canvas resizing
8768 */
8769 Canvas.prototype.resized = function() {
8770
8771 // force recomputation of view box
8772 delete this._cachedViewbox;
8773
8774 this._eventBus.fire('canvas.resized');
8775 };
8776
8777 var ELEMENT_ID = 'data-element-id';
8778
8779
8780 /**
8781 * @class
8782 *
8783 * A registry that keeps track of all shapes in the diagram.
8784 */
8785 function ElementRegistry(eventBus) {
8786 this._elements = {};
8787
8788 this._eventBus = eventBus;
8789 }
8790
8791 ElementRegistry.$inject = [ 'eventBus' ];
8792
8793 /**
8794 * Register a pair of (element, gfx, (secondaryGfx)).
8795 *
8796 * @param {djs.model.Base} element
8797 * @param {SVGElement} gfx
8798 * @param {SVGElement} [secondaryGfx] optional other element to register, too
8799 */
8800 ElementRegistry.prototype.add = function(element, gfx, secondaryGfx) {
8801
8802 var id = element.id;
8803
8804 this._validateId(id);
8805
8806 // associate dom node with element
8807 attr(gfx, ELEMENT_ID, id);
8808
8809 if (secondaryGfx) {
8810 attr(secondaryGfx, ELEMENT_ID, id);
8811 }
8812
8813 this._elements[id] = { element: element, gfx: gfx, secondaryGfx: secondaryGfx };
8814 };
8815
8816 /**
8817 * Removes an element from the registry.
8818 *
8819 * @param {djs.model.Base} element
8820 */
8821 ElementRegistry.prototype.remove = function(element) {
8822 var elements = this._elements,
8823 id = element.id || element,
8824 container = id && elements[id];
8825
8826 if (container) {
8827
8828 // unset element id on gfx
8829 attr(container.gfx, ELEMENT_ID, '');
8830
8831 if (container.secondaryGfx) {
8832 attr(container.secondaryGfx, ELEMENT_ID, '');
8833 }
8834
8835 delete elements[id];
8836 }
8837 };
8838
8839 /**
8840 * Update the id of an element
8841 *
8842 * @param {djs.model.Base} element
8843 * @param {String} newId
8844 */
8845 ElementRegistry.prototype.updateId = function(element, newId) {
8846
8847 this._validateId(newId);
8848
8849 if (typeof element === 'string') {
8850 element = this.get(element);
8851 }
8852
8853 this._eventBus.fire('element.updateId', {
8854 element: element,
8855 newId: newId
8856 });
8857
8858 var gfx = this.getGraphics(element),
8859 secondaryGfx = this.getGraphics(element, true);
8860
8861 this.remove(element);
8862
8863 element.id = newId;
8864
8865 this.add(element, gfx, secondaryGfx);
8866 };
8867
8868 /**
8869 * Return the model element for a given id or graphics.
8870 *
8871 * @example
8872 *
8873 * elementRegistry.get('SomeElementId_1');
8874 * elementRegistry.get(gfx);
8875 *
8876 *
8877 * @param {String|SVGElement} filter for selecting the element
8878 *
8879 * @return {djs.model.Base}
8880 */
8881 ElementRegistry.prototype.get = function(filter) {
8882 var id;
8883
8884 if (typeof filter === 'string') {
8885 id = filter;
8886 } else {
8887 id = filter && attr(filter, ELEMENT_ID);
8888 }
8889
8890 var container = this._elements[id];
8891 return container && container.element;
8892 };
8893
8894 /**
8895 * Return all elements that match a given filter function.
8896 *
8897 * @param {Function} fn
8898 *
8899 * @return {Array<djs.model.Base>}
8900 */
8901 ElementRegistry.prototype.filter = function(fn) {
8902
8903 var filtered = [];
8904
8905 this.forEach(function(element, gfx) {
8906 if (fn(element, gfx)) {
8907 filtered.push(element);
8908 }
8909 });
8910
8911 return filtered;
8912 };
8913
8914 /**
8915 * Return all rendered model elements.
8916 *
8917 * @return {Array<djs.model.Base>}
8918 */
8919 ElementRegistry.prototype.getAll = function() {
8920 return this.filter(function(e) { return e; });
8921 };
8922
8923 /**
8924 * Iterate over all diagram elements.
8925 *
8926 * @param {Function} fn
8927 */
8928 ElementRegistry.prototype.forEach = function(fn) {
8929
8930 var map = this._elements;
8931
8932 Object.keys(map).forEach(function(id) {
8933 var container = map[id],
8934 element = container.element,
8935 gfx = container.gfx;
8936
8937 return fn(element, gfx);
8938 });
8939 };
8940
8941 /**
8942 * Return the graphical representation of an element or its id.
8943 *
8944 * @example
8945 * elementRegistry.getGraphics('SomeElementId_1');
8946 * elementRegistry.getGraphics(rootElement); // <g ...>
8947 *
8948 * elementRegistry.getGraphics(rootElement, true); // <svg ...>
8949 *
8950 *
8951 * @param {String|djs.model.Base} filter
8952 * @param {Boolean} [secondary=false] whether to return the secondary connected element
8953 *
8954 * @return {SVGElement}
8955 */
8956 ElementRegistry.prototype.getGraphics = function(filter, secondary) {
8957 var id = filter.id || filter;
8958
8959 var container = this._elements[id];
8960 return container && (secondary ? container.secondaryGfx : container.gfx);
8961 };
8962
8963 /**
8964 * Validate the suitability of the given id and signals a problem
8965 * with an exception.
8966 *
8967 * @param {String} id
8968 *
8969 * @throws {Error} if id is empty or already assigned
8970 */
8971 ElementRegistry.prototype._validateId = function(id) {
8972 if (!id) {
8973 throw new Error('element must have an id');
8974 }
8975
8976 if (this._elements[id]) {
8977 throw new Error('element with id ' + id + ' already added');
8978 }
8979 };
8980
8981 /**
8982 * An empty collection stub. Use {@link RefsCollection.extend} to extend a
8983 * collection with ref semantics.
8984 *
8985 * @class RefsCollection
8986 */
8987
8988 /**
8989 * Extends a collection with {@link Refs} aware methods
8990 *
8991 * @memberof RefsCollection
8992 * @static
8993 *
8994 * @param {Array<Object>} collection
8995 * @param {Refs} refs instance
8996 * @param {Object} property represented by the collection
8997 * @param {Object} target object the collection is attached to
8998 *
8999 * @return {RefsCollection<Object>} the extended array
9000 */
9001 function extend$1(collection, refs, property, target) {
9002
9003 var inverseProperty = property.inverse;
9004
9005 /**
9006 * Removes the given element from the array and returns it.
9007 *
9008 * @method RefsCollection#remove
9009 *
9010 * @param {Object} element the element to remove
9011 */
9012 Object.defineProperty(collection, 'remove', {
9013 value: function(element) {
9014 var idx = this.indexOf(element);
9015 if (idx !== -1) {
9016 this.splice(idx, 1);
9017
9018 // unset inverse
9019 refs.unset(element, inverseProperty, target);
9020 }
9021
9022 return element;
9023 }
9024 });
9025
9026 /**
9027 * Returns true if the collection contains the given element
9028 *
9029 * @method RefsCollection#contains
9030 *
9031 * @param {Object} element the element to check for
9032 */
9033 Object.defineProperty(collection, 'contains', {
9034 value: function(element) {
9035 return this.indexOf(element) !== -1;
9036 }
9037 });
9038
9039 /**
9040 * Adds an element to the array, unless it exists already (set semantics).
9041 *
9042 * @method RefsCollection#add
9043 *
9044 * @param {Object} element the element to add
9045 * @param {Number} optional index to add element to
9046 * (possibly moving other elements around)
9047 */
9048 Object.defineProperty(collection, 'add', {
9049 value: function(element, idx) {
9050
9051 var currentIdx = this.indexOf(element);
9052
9053 if (typeof idx === 'undefined') {
9054
9055 if (currentIdx !== -1) {
9056 // element already in collection (!)
9057 return;
9058 }
9059
9060 // add to end of array, as no idx is specified
9061 idx = this.length;
9062 }
9063
9064 // handle already in collection
9065 if (currentIdx !== -1) {
9066
9067 // remove element from currentIdx
9068 this.splice(currentIdx, 1);
9069 }
9070
9071 // add element at idx
9072 this.splice(idx, 0, element);
9073
9074 if (currentIdx === -1) {
9075 // set inverse, unless element was
9076 // in collection already
9077 refs.set(element, inverseProperty, target);
9078 }
9079 }
9080 });
9081
9082 // a simple marker, identifying this element
9083 // as being a refs collection
9084 Object.defineProperty(collection, '__refs_collection', {
9085 value: true
9086 });
9087
9088 return collection;
9089 }
9090
9091
9092 function isExtended(collection) {
9093 return collection.__refs_collection === true;
9094 }
9095
9096 var extend_1 = extend$1;
9097
9098 var isExtended_1 = isExtended;
9099
9100 var collection = {
9101 extend: extend_1,
9102 isExtended: isExtended_1
9103 };
9104
9105 function hasOwnProperty(e, property) {
9106 return Object.prototype.hasOwnProperty.call(e, property.name || property);
9107 }
9108
9109 function defineCollectionProperty(ref, property, target) {
9110
9111 var collection$1 = collection.extend(target[property.name] || [], ref, property, target);
9112
9113 Object.defineProperty(target, property.name, {
9114 enumerable: property.enumerable,
9115 value: collection$1
9116 });
9117
9118 if (collection$1.length) {
9119
9120 collection$1.forEach(function(o) {
9121 ref.set(o, property.inverse, target);
9122 });
9123 }
9124 }
9125
9126
9127 function defineProperty(ref, property, target) {
9128
9129 var inverseProperty = property.inverse;
9130
9131 var _value = target[property.name];
9132
9133 Object.defineProperty(target, property.name, {
9134 configurable: property.configurable,
9135 enumerable: property.enumerable,
9136
9137 get: function() {
9138 return _value;
9139 },
9140
9141 set: function(value) {
9142
9143 // return if we already performed all changes
9144 if (value === _value) {
9145 return;
9146 }
9147
9148 var old = _value;
9149
9150 // temporary set null
9151 _value = null;
9152
9153 if (old) {
9154 ref.unset(old, inverseProperty, target);
9155 }
9156
9157 // set new value
9158 _value = value;
9159
9160 // set inverse value
9161 ref.set(_value, inverseProperty, target);
9162 }
9163 });
9164
9165 }
9166
9167 /**
9168 * Creates a new references object defining two inversly related
9169 * attribute descriptors a and b.
9170 *
9171 * <p>
9172 * When bound to an object using {@link Refs#bind} the references
9173 * get activated and ensure that add and remove operations are applied
9174 * reversely, too.
9175 * </p>
9176 *
9177 * <p>
9178 * For attributes represented as collections {@link Refs} provides the
9179 * {@link RefsCollection#add}, {@link RefsCollection#remove} and {@link RefsCollection#contains} extensions
9180 * that must be used to properly hook into the inverse change mechanism.
9181 * </p>
9182 *
9183 * @class Refs
9184 *
9185 * @classdesc A bi-directional reference between two attributes.
9186 *
9187 * @param {Refs.AttributeDescriptor} a property descriptor
9188 * @param {Refs.AttributeDescriptor} b property descriptor
9189 *
9190 * @example
9191 *
9192 * var refs = Refs({ name: 'wheels', collection: true, enumerable: true }, { name: 'car' });
9193 *
9194 * var car = { name: 'toyota' };
9195 * var wheels = [{ pos: 'front-left' }, { pos: 'front-right' }];
9196 *
9197 * refs.bind(car, 'wheels');
9198 *
9199 * car.wheels // []
9200 * car.wheels.add(wheels[0]);
9201 * car.wheels.add(wheels[1]);
9202 *
9203 * car.wheels // [{ pos: 'front-left' }, { pos: 'front-right' }]
9204 *
9205 * wheels[0].car // { name: 'toyota' };
9206 * car.wheels.remove(wheels[0]);
9207 *
9208 * wheels[0].car // undefined
9209 */
9210 function Refs(a, b) {
9211
9212 if (!(this instanceof Refs)) {
9213 return new Refs(a, b);
9214 }
9215
9216 // link
9217 a.inverse = b;
9218 b.inverse = a;
9219
9220 this.props = {};
9221 this.props[a.name] = a;
9222 this.props[b.name] = b;
9223 }
9224
9225 /**
9226 * Binds one side of a bi-directional reference to a
9227 * target object.
9228 *
9229 * @memberOf Refs
9230 *
9231 * @param {Object} target
9232 * @param {String} property
9233 */
9234 Refs.prototype.bind = function(target, property) {
9235 if (typeof property === 'string') {
9236 if (!this.props[property]) {
9237 throw new Error('no property <' + property + '> in ref');
9238 }
9239 property = this.props[property];
9240 }
9241
9242 if (property.collection) {
9243 defineCollectionProperty(this, property, target);
9244 } else {
9245 defineProperty(this, property, target);
9246 }
9247 };
9248
9249 Refs.prototype.ensureRefsCollection = function(target, property) {
9250
9251 var collection$1 = target[property.name];
9252
9253 if (!collection.isExtended(collection$1)) {
9254 defineCollectionProperty(this, property, target);
9255 }
9256
9257 return collection$1;
9258 };
9259
9260 Refs.prototype.ensureBound = function(target, property) {
9261 if (!hasOwnProperty(target, property)) {
9262 this.bind(target, property);
9263 }
9264 };
9265
9266 Refs.prototype.unset = function(target, property, value) {
9267
9268 if (target) {
9269 this.ensureBound(target, property);
9270
9271 if (property.collection) {
9272 this.ensureRefsCollection(target, property).remove(value);
9273 } else {
9274 target[property.name] = undefined;
9275 }
9276 }
9277 };
9278
9279 Refs.prototype.set = function(target, property, value) {
9280
9281 if (target) {
9282 this.ensureBound(target, property);
9283
9284 if (property.collection) {
9285 this.ensureRefsCollection(target, property).add(value);
9286 } else {
9287 target[property.name] = value;
9288 }
9289 }
9290 };
9291
9292 var refs = Refs;
9293
9294 var objectRefs = refs;
9295
9296 var Collection = collection;
9297 objectRefs.Collection = Collection;
9298
9299 var parentRefs = new objectRefs({ name: 'children', enumerable: true, collection: true }, { name: 'parent' }),
9300 labelRefs = new objectRefs({ name: 'labels', enumerable: true, collection: true }, { name: 'labelTarget' }),
9301 attacherRefs = new objectRefs({ name: 'attachers', collection: true }, { name: 'host' }),
9302 outgoingRefs = new objectRefs({ name: 'outgoing', collection: true }, { name: 'source' }),
9303 incomingRefs = new objectRefs({ name: 'incoming', collection: true }, { name: 'target' });
9304
9305 /**
9306 * @namespace djs.model
9307 */
9308
9309 /**
9310 * @memberOf djs.model
9311 */
9312
9313 /**
9314 * The basic graphical representation
9315 *
9316 * @class
9317 *
9318 * @abstract
9319 */
9320 function Base() {
9321
9322 /**
9323 * The object that backs up the shape
9324 *
9325 * @name Base#businessObject
9326 * @type Object
9327 */
9328 Object.defineProperty(this, 'businessObject', {
9329 writable: true
9330 });
9331
9332
9333 /**
9334 * Single label support, will mapped to multi label array
9335 *
9336 * @name Base#label
9337 * @type Object
9338 */
9339 Object.defineProperty(this, 'label', {
9340 get: function() {
9341 return this.labels[0];
9342 },
9343 set: function(newLabel) {
9344
9345 var label = this.label,
9346 labels = this.labels;
9347
9348 if (!newLabel && label) {
9349 labels.remove(label);
9350 } else {
9351 labels.add(newLabel, 0);
9352 }
9353 }
9354 });
9355
9356 /**
9357 * The parent shape
9358 *
9359 * @name Base#parent
9360 * @type Shape
9361 */
9362 parentRefs.bind(this, 'parent');
9363
9364 /**
9365 * The list of labels
9366 *
9367 * @name Base#labels
9368 * @type Label
9369 */
9370 labelRefs.bind(this, 'labels');
9371
9372 /**
9373 * The list of outgoing connections
9374 *
9375 * @name Base#outgoing
9376 * @type Array<Connection>
9377 */
9378 outgoingRefs.bind(this, 'outgoing');
9379
9380 /**
9381 * The list of incoming connections
9382 *
9383 * @name Base#incoming
9384 * @type Array<Connection>
9385 */
9386 incomingRefs.bind(this, 'incoming');
9387 }
9388
9389
9390 /**
9391 * A graphical object
9392 *
9393 * @class
9394 * @constructor
9395 *
9396 * @extends Base
9397 */
9398 function Shape() {
9399 Base.call(this);
9400
9401 /**
9402 * Indicates frame shapes
9403 *
9404 * @name Shape#isFrame
9405 * @type Boolean
9406 */
9407
9408 /**
9409 * The list of children
9410 *
9411 * @name Shape#children
9412 * @type Array<Base>
9413 */
9414 parentRefs.bind(this, 'children');
9415
9416 /**
9417 * @name Shape#host
9418 * @type Shape
9419 */
9420 attacherRefs.bind(this, 'host');
9421
9422 /**
9423 * @name Shape#attachers
9424 * @type Shape
9425 */
9426 attacherRefs.bind(this, 'attachers');
9427 }
9428
9429 inherits_browser(Shape, Base);
9430
9431
9432 /**
9433 * A root graphical object
9434 *
9435 * @class
9436 * @constructor
9437 *
9438 * @extends Shape
9439 */
9440 function Root() {
9441 Shape.call(this);
9442 }
9443
9444 inherits_browser(Root, Shape);
9445
9446
9447 /**
9448 * A label for an element
9449 *
9450 * @class
9451 * @constructor
9452 *
9453 * @extends Shape
9454 */
9455 function Label() {
9456 Shape.call(this);
9457
9458 /**
9459 * The labeled element
9460 *
9461 * @name Label#labelTarget
9462 * @type Base
9463 */
9464 labelRefs.bind(this, 'labelTarget');
9465 }
9466
9467 inherits_browser(Label, Shape);
9468
9469
9470 /**
9471 * A connection between two elements
9472 *
9473 * @class
9474 * @constructor
9475 *
9476 * @extends Base
9477 */
9478 function Connection() {
9479 Base.call(this);
9480
9481 /**
9482 * The element this connection originates from
9483 *
9484 * @name Connection#source
9485 * @type Base
9486 */
9487 outgoingRefs.bind(this, 'source');
9488
9489 /**
9490 * The element this connection points to
9491 *
9492 * @name Connection#target
9493 * @type Base
9494 */
9495 incomingRefs.bind(this, 'target');
9496 }
9497
9498 inherits_browser(Connection, Base);
9499
9500
9501 var types = {
9502 connection: Connection,
9503 shape: Shape,
9504 label: Label,
9505 root: Root
9506 };
9507
9508 /**
9509 * Creates a new model element of the specified type
9510 *
9511 * @method create
9512 *
9513 * @example
9514 *
9515 * var shape1 = Model.create('shape', { x: 10, y: 10, width: 100, height: 100 });
9516 * var shape2 = Model.create('shape', { x: 210, y: 210, width: 100, height: 100 });
9517 *
9518 * var connection = Model.create('connection', { waypoints: [ { x: 110, y: 55 }, {x: 210, y: 55 } ] });
9519 *
9520 * @param {String} type lower-cased model name
9521 * @param {Object} attrs attributes to initialize the new model instance with
9522 *
9523 * @return {Base} the new model instance
9524 */
9525 function create$1(type, attrs) {
9526 var Type = types[type];
9527 if (!Type) {
9528 throw new Error('unknown type: <' + type + '>');
9529 }
9530 return assign(new Type(), attrs);
9531 }
9532
9533 /**
9534 * A factory for diagram-js shapes
9535 */
9536 function ElementFactory() {
9537 this._uid = 12;
9538 }
9539
9540
9541 ElementFactory.prototype.createRoot = function(attrs) {
9542 return this.create('root', attrs);
9543 };
9544
9545 ElementFactory.prototype.createLabel = function(attrs) {
9546 return this.create('label', attrs);
9547 };
9548
9549 ElementFactory.prototype.createShape = function(attrs) {
9550 return this.create('shape', attrs);
9551 };
9552
9553 ElementFactory.prototype.createConnection = function(attrs) {
9554 return this.create('connection', attrs);
9555 };
9556
9557 /**
9558 * Create a model element with the given type and
9559 * a number of pre-set attributes.
9560 *
9561 * @param {String} type
9562 * @param {Object} attrs
9563 * @return {djs.model.Base} the newly created model instance
9564 */
9565 ElementFactory.prototype.create = function(type, attrs) {
9566
9567 attrs = assign({}, attrs || {});
9568
9569 if (!attrs.id) {
9570 attrs.id = type + '_' + (this._uid++);
9571 }
9572
9573 return create$1(type, attrs);
9574 };
9575
9576 var FN_REF = '__fn';
9577
9578 var DEFAULT_PRIORITY = 1000;
9579
9580 var slice$1 = Array.prototype.slice;
9581
9582 /**
9583 * A general purpose event bus.
9584 *
9585 * This component is used to communicate across a diagram instance.
9586 * Other parts of a diagram can use it to listen to and broadcast events.
9587 *
9588 *
9589 * ## Registering for Events
9590 *
9591 * The event bus provides the {@link EventBus#on} and {@link EventBus#once}
9592 * methods to register for events. {@link EventBus#off} can be used to
9593 * remove event registrations. Listeners receive an instance of {@link Event}
9594 * as the first argument. It allows them to hook into the event execution.
9595 *
9596 * ```javascript
9597 *
9598 * // listen for event
9599 * eventBus.on('foo', function(event) {
9600 *
9601 * // access event type
9602 * event.type; // 'foo'
9603 *
9604 * // stop propagation to other listeners
9605 * event.stopPropagation();
9606 *
9607 * // prevent event default
9608 * event.preventDefault();
9609 * });
9610 *
9611 * // listen for event with custom payload
9612 * eventBus.on('bar', function(event, payload) {
9613 * console.log(payload);
9614 * });
9615 *
9616 * // listen for event returning value
9617 * eventBus.on('foobar', function(event) {
9618 *
9619 * // stop event propagation + prevent default
9620 * return false;
9621 *
9622 * // stop event propagation + return custom result
9623 * return {
9624 * complex: 'listening result'
9625 * };
9626 * });
9627 *
9628 *
9629 * // listen with custom priority (default=1000, higher is better)
9630 * eventBus.on('priorityfoo', 1500, function(event) {
9631 * console.log('invoked first!');
9632 * });
9633 *
9634 *
9635 * // listen for event and pass the context (`this`)
9636 * eventBus.on('foobar', function(event) {
9637 * this.foo();
9638 * }, this);
9639 * ```
9640 *
9641 *
9642 * ## Emitting Events
9643 *
9644 * Events can be emitted via the event bus using {@link EventBus#fire}.
9645 *
9646 * ```javascript
9647 *
9648 * // false indicates that the default action
9649 * // was prevented by listeners
9650 * if (eventBus.fire('foo') === false) {
9651 * console.log('default has been prevented!');
9652 * };
9653 *
9654 *
9655 * // custom args + return value listener
9656 * eventBus.on('sum', function(event, a, b) {
9657 * return a + b;
9658 * });
9659 *
9660 * // you can pass custom arguments + retrieve result values.
9661 * var sum = eventBus.fire('sum', 1, 2);
9662 * console.log(sum); // 3
9663 * ```
9664 */
9665 function EventBus() {
9666 this._listeners = {};
9667
9668 // cleanup on destroy on lowest priority to allow
9669 // message passing until the bitter end
9670 this.on('diagram.destroy', 1, this._destroy, this);
9671 }
9672
9673
9674 /**
9675 * Register an event listener for events with the given name.
9676 *
9677 * The callback will be invoked with `event, ...additionalArguments`
9678 * that have been passed to {@link EventBus#fire}.
9679 *
9680 * Returning false from a listener will prevent the events default action
9681 * (if any is specified). To stop an event from being processed further in
9682 * other listeners execute {@link Event#stopPropagation}.
9683 *
9684 * Returning anything but `undefined` from a listener will stop the listener propagation.
9685 *
9686 * @param {String|Array<String>} events
9687 * @param {Number} [priority=1000] the priority in which this listener is called, larger is higher
9688 * @param {Function} callback
9689 * @param {Object} [that] Pass context (`this`) to the callback
9690 */
9691 EventBus.prototype.on = function(events, priority, callback, that) {
9692
9693 events = isArray(events) ? events : [ events ];
9694
9695 if (isFunction(priority)) {
9696 that = callback;
9697 callback = priority;
9698 priority = DEFAULT_PRIORITY;
9699 }
9700
9701 if (!isNumber(priority)) {
9702 throw new Error('priority must be a number');
9703 }
9704
9705 var actualCallback = callback;
9706
9707 if (that) {
9708 actualCallback = bind(callback, that);
9709
9710 // make sure we remember and are able to remove
9711 // bound callbacks via {@link #off} using the original
9712 // callback
9713 actualCallback[FN_REF] = callback[FN_REF] || callback;
9714 }
9715
9716 var self = this;
9717
9718 events.forEach(function(e) {
9719 self._addListener(e, {
9720 priority: priority,
9721 callback: actualCallback,
9722 next: null
9723 });
9724 });
9725 };
9726
9727
9728 /**
9729 * Register an event listener that is executed only once.
9730 *
9731 * @param {String} event the event name to register for
9732 * @param {Number} [priority=1000] the priority in which this listener is called, larger is higher
9733 * @param {Function} callback the callback to execute
9734 * @param {Object} [that] Pass context (`this`) to the callback
9735 */
9736 EventBus.prototype.once = function(event, priority, callback, that) {
9737 var self = this;
9738
9739 if (isFunction(priority)) {
9740 that = callback;
9741 callback = priority;
9742 priority = DEFAULT_PRIORITY;
9743 }
9744
9745 if (!isNumber(priority)) {
9746 throw new Error('priority must be a number');
9747 }
9748
9749 function wrappedCallback() {
9750 var result = callback.apply(that, arguments);
9751
9752 self.off(event, wrappedCallback);
9753
9754 return result;
9755 }
9756
9757 // make sure we remember and are able to remove
9758 // bound callbacks via {@link #off} using the original
9759 // callback
9760 wrappedCallback[FN_REF] = callback;
9761
9762 this.on(event, priority, wrappedCallback);
9763 };
9764
9765
9766 /**
9767 * Removes event listeners by event and callback.
9768 *
9769 * If no callback is given, all listeners for a given event name are being removed.
9770 *
9771 * @param {String|Array<String>} events
9772 * @param {Function} [callback]
9773 */
9774 EventBus.prototype.off = function(events, callback) {
9775
9776 events = isArray(events) ? events : [ events ];
9777
9778 var self = this;
9779
9780 events.forEach(function(event) {
9781 self._removeListener(event, callback);
9782 });
9783
9784 };
9785
9786
9787 /**
9788 * Create an EventBus event.
9789 *
9790 * @param {Object} data
9791 *
9792 * @return {Object} event, recognized by the eventBus
9793 */
9794 EventBus.prototype.createEvent = function(data) {
9795 var event = new InternalEvent();
9796
9797 event.init(data);
9798
9799 return event;
9800 };
9801
9802
9803 /**
9804 * Fires a named event.
9805 *
9806 * @example
9807 *
9808 * // fire event by name
9809 * events.fire('foo');
9810 *
9811 * // fire event object with nested type
9812 * var event = { type: 'foo' };
9813 * events.fire(event);
9814 *
9815 * // fire event with explicit type
9816 * var event = { x: 10, y: 20 };
9817 * events.fire('element.moved', event);
9818 *
9819 * // pass additional arguments to the event
9820 * events.on('foo', function(event, bar) {
9821 * alert(bar);
9822 * });
9823 *
9824 * events.fire({ type: 'foo' }, 'I am bar!');
9825 *
9826 * @param {String} [name] the optional event name
9827 * @param {Object} [event] the event object
9828 * @param {...Object} additional arguments to be passed to the callback functions
9829 *
9830 * @return {Boolean} the events return value, if specified or false if the
9831 * default action was prevented by listeners
9832 */
9833 EventBus.prototype.fire = function(type, data) {
9834
9835 var event,
9836 firstListener,
9837 returnValue,
9838 args;
9839
9840 args = slice$1.call(arguments);
9841
9842 if (typeof type === 'object') {
9843 data = type;
9844 type = data.type;
9845 }
9846
9847 if (!type) {
9848 throw new Error('no event type specified');
9849 }
9850
9851 firstListener = this._listeners[type];
9852
9853 if (!firstListener) {
9854 return;
9855 }
9856
9857 // we make sure we fire instances of our home made
9858 // events here. We wrap them only once, though
9859 if (data instanceof InternalEvent) {
9860
9861 // we are fine, we alread have an event
9862 event = data;
9863 } else {
9864 event = this.createEvent(data);
9865 }
9866
9867 // ensure we pass the event as the first parameter
9868 args[0] = event;
9869
9870 // original event type (in case we delegate)
9871 var originalType = event.type;
9872
9873 // update event type before delegation
9874 if (type !== originalType) {
9875 event.type = type;
9876 }
9877
9878 try {
9879 returnValue = this._invokeListeners(event, args, firstListener);
9880 } finally {
9881
9882 // reset event type after delegation
9883 if (type !== originalType) {
9884 event.type = originalType;
9885 }
9886 }
9887
9888 // set the return value to false if the event default
9889 // got prevented and no other return value exists
9890 if (returnValue === undefined && event.defaultPrevented) {
9891 returnValue = false;
9892 }
9893
9894 return returnValue;
9895 };
9896
9897
9898 EventBus.prototype.handleError = function(error) {
9899 return this.fire('error', { error: error }) === false;
9900 };
9901
9902
9903 EventBus.prototype._destroy = function() {
9904 this._listeners = {};
9905 };
9906
9907 EventBus.prototype._invokeListeners = function(event, args, listener) {
9908
9909 var returnValue;
9910
9911 while (listener) {
9912
9913 // handle stopped propagation
9914 if (event.cancelBubble) {
9915 break;
9916 }
9917
9918 returnValue = this._invokeListener(event, args, listener);
9919
9920 listener = listener.next;
9921 }
9922
9923 return returnValue;
9924 };
9925
9926 EventBus.prototype._invokeListener = function(event, args, listener) {
9927
9928 var returnValue;
9929
9930 try {
9931
9932 // returning false prevents the default action
9933 returnValue = invokeFunction(listener.callback, args);
9934
9935 // stop propagation on return value
9936 if (returnValue !== undefined) {
9937 event.returnValue = returnValue;
9938 event.stopPropagation();
9939 }
9940
9941 // prevent default on return false
9942 if (returnValue === false) {
9943 event.preventDefault();
9944 }
9945 } catch (e) {
9946 if (!this.handleError(e)) {
9947 console.error('unhandled error in event listener');
9948 console.error(e.stack);
9949
9950 throw e;
9951 }
9952 }
9953
9954 return returnValue;
9955 };
9956
9957 /*
9958 * Add new listener with a certain priority to the list
9959 * of listeners (for the given event).
9960 *
9961 * The semantics of listener registration / listener execution are
9962 * first register, first serve: New listeners will always be inserted
9963 * after existing listeners with the same priority.
9964 *
9965 * Example: Inserting two listeners with priority 1000 and 1300
9966 *
9967 * * before: [ 1500, 1500, 1000, 1000 ]
9968 * * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ]
9969 *
9970 * @param {String} event
9971 * @param {Object} listener { priority, callback }
9972 */
9973 EventBus.prototype._addListener = function(event, newListener) {
9974
9975 var listener = this._getListeners(event),
9976 previousListener;
9977
9978 // no prior listeners
9979 if (!listener) {
9980 this._setListeners(event, newListener);
9981
9982 return;
9983 }
9984
9985 // ensure we order listeners by priority from
9986 // 0 (high) to n > 0 (low)
9987 while (listener) {
9988
9989 if (listener.priority < newListener.priority) {
9990
9991 newListener.next = listener;
9992
9993 if (previousListener) {
9994 previousListener.next = newListener;
9995 } else {
9996 this._setListeners(event, newListener);
9997 }
9998
9999 return;
10000 }
10001
10002 previousListener = listener;
10003 listener = listener.next;
10004 }
10005
10006 // add new listener to back
10007 previousListener.next = newListener;
10008 };
10009
10010
10011 EventBus.prototype._getListeners = function(name) {
10012 return this._listeners[name];
10013 };
10014
10015 EventBus.prototype._setListeners = function(name, listener) {
10016 this._listeners[name] = listener;
10017 };
10018
10019 EventBus.prototype._removeListener = function(event, callback) {
10020
10021 var listener = this._getListeners(event),
10022 nextListener,
10023 previousListener,
10024 listenerCallback;
10025
10026 if (!callback) {
10027
10028 // clear listeners
10029 this._setListeners(event, null);
10030
10031 return;
10032 }
10033
10034 while (listener) {
10035
10036 nextListener = listener.next;
10037
10038 listenerCallback = listener.callback;
10039
10040 if (listenerCallback === callback || listenerCallback[FN_REF] === callback) {
10041 if (previousListener) {
10042 previousListener.next = nextListener;
10043 } else {
10044
10045 // new first listener
10046 this._setListeners(event, nextListener);
10047 }
10048 }
10049
10050 previousListener = listener;
10051 listener = nextListener;
10052 }
10053 };
10054
10055 /**
10056 * A event that is emitted via the event bus.
10057 */
10058 function InternalEvent() { }
10059
10060 InternalEvent.prototype.stopPropagation = function() {
10061 this.cancelBubble = true;
10062 };
10063
10064 InternalEvent.prototype.preventDefault = function() {
10065 this.defaultPrevented = true;
10066 };
10067
10068 InternalEvent.prototype.init = function(data) {
10069 assign(this, data || {});
10070 };
10071
10072
10073 /**
10074 * Invoke function. Be fast...
10075 *
10076 * @param {Function} fn
10077 * @param {Array<Object>} args
10078 *
10079 * @return {Any}
10080 */
10081 function invokeFunction(fn, args) {
10082 return fn.apply(null, args);
10083 }
10084
10085 /**
10086 * SVGs for elements are generated by the {@link GraphicsFactory}.
10087 *
10088 * This utility gives quick access to the important semantic
10089 * parts of an element.
10090 */
10091
10092 /**
10093 * Returns the visual part of a diagram element
10094 *
10095 * @param {Snap<SVGElement>} gfx
10096 *
10097 * @return {Snap<SVGElement>}
10098 */
10099 function getVisual(gfx) {
10100 return gfx.childNodes[0];
10101 }
10102
10103 /**
10104 * Returns the children for a given diagram element.
10105 *
10106 * @param {Snap<SVGElement>} gfx
10107 * @return {Snap<SVGElement>}
10108 */
10109 function getChildren(gfx) {
10110 return gfx.parentNode.childNodes[1];
10111 }
10112
10113 /**
10114 * A factory that creates graphical elements
10115 *
10116 * @param {EventBus} eventBus
10117 * @param {ElementRegistry} elementRegistry
10118 */
10119 function GraphicsFactory(eventBus, elementRegistry) {
10120 this._eventBus = eventBus;
10121 this._elementRegistry = elementRegistry;
10122 }
10123
10124 GraphicsFactory.$inject = [ 'eventBus' , 'elementRegistry' ];
10125
10126
10127 GraphicsFactory.prototype._getChildrenContainer = function(element) {
10128
10129 var gfx = this._elementRegistry.getGraphics(element);
10130
10131 var childrenGfx;
10132
10133 // root element
10134 if (!element.parent) {
10135 childrenGfx = gfx;
10136 } else {
10137 childrenGfx = getChildren(gfx);
10138 if (!childrenGfx) {
10139 childrenGfx = create('g');
10140 classes(childrenGfx).add('djs-children');
10141
10142 append(gfx.parentNode, childrenGfx);
10143 }
10144 }
10145
10146 return childrenGfx;
10147 };
10148
10149 /**
10150 * Clears the graphical representation of the element and returns the
10151 * cleared visual (the <g class="djs-visual" /> element).
10152 */
10153 GraphicsFactory.prototype._clear = function(gfx) {
10154 var visual = getVisual(gfx);
10155
10156 clear$1(visual);
10157
10158 return visual;
10159 };
10160
10161 /**
10162 * Creates a gfx container for shapes and connections
10163 *
10164 * The layout is as follows:
10165 *
10166 * <g class="djs-group">
10167 *
10168 * <!-- the gfx -->
10169 * <g class="djs-element djs-(shape|connection|frame)">
10170 * <g class="djs-visual">
10171 * <!-- the renderer draws in here -->
10172 * </g>
10173 *
10174 * <!-- extensions (overlays, click box, ...) goes here
10175 * </g>
10176 *
10177 * <!-- the gfx child nodes -->
10178 * <g class="djs-children"></g>
10179 * </g>
10180 *
10181 * @param {String} type the type of the element, i.e. shape | connection
10182 * @param {SVGElement} [childrenGfx]
10183 * @param {Number} [parentIndex] position to create container in parent
10184 * @param {Boolean} [isFrame] is frame element
10185 *
10186 * @return {SVGElement}
10187 */
10188 GraphicsFactory.prototype._createContainer = function(
10189 type, childrenGfx, parentIndex, isFrame
10190 ) {
10191 var outerGfx = create('g');
10192 classes(outerGfx).add('djs-group');
10193
10194 // insert node at position
10195 if (typeof parentIndex !== 'undefined') {
10196 prependTo(outerGfx, childrenGfx, childrenGfx.childNodes[parentIndex]);
10197 } else {
10198 append(childrenGfx, outerGfx);
10199 }
10200
10201 var gfx = create('g');
10202 classes(gfx).add('djs-element');
10203 classes(gfx).add('djs-' + type);
10204
10205 if (isFrame) {
10206 classes(gfx).add('djs-frame');
10207 }
10208
10209 append(outerGfx, gfx);
10210
10211 // create visual
10212 var visual = create('g');
10213 classes(visual).add('djs-visual');
10214
10215 append(gfx, visual);
10216
10217 return gfx;
10218 };
10219
10220 GraphicsFactory.prototype.create = function(type, element, parentIndex) {
10221 var childrenGfx = this._getChildrenContainer(element.parent);
10222 return this._createContainer(type, childrenGfx, parentIndex, isFrameElement(element));
10223 };
10224
10225 GraphicsFactory.prototype.updateContainments = function(elements) {
10226
10227 var self = this,
10228 elementRegistry = this._elementRegistry,
10229 parents;
10230
10231 parents = reduce(elements, function(map, e) {
10232
10233 if (e.parent) {
10234 map[e.parent.id] = e.parent;
10235 }
10236
10237 return map;
10238 }, {});
10239
10240 // update all parents of changed and reorganized their children
10241 // in the correct order (as indicated in our model)
10242 forEach(parents, function(parent) {
10243
10244 var children = parent.children;
10245
10246 if (!children) {
10247 return;
10248 }
10249
10250 var childrenGfx = self._getChildrenContainer(parent);
10251
10252 forEach(children.slice().reverse(), function(child) {
10253 var childGfx = elementRegistry.getGraphics(child);
10254
10255 prependTo(childGfx.parentNode, childrenGfx);
10256 });
10257 });
10258 };
10259
10260 GraphicsFactory.prototype.drawShape = function(visual, element) {
10261 var eventBus = this._eventBus;
10262
10263 return eventBus.fire('render.shape', { gfx: visual, element: element });
10264 };
10265
10266 GraphicsFactory.prototype.getShapePath = function(element) {
10267 var eventBus = this._eventBus;
10268
10269 return eventBus.fire('render.getShapePath', element);
10270 };
10271
10272 GraphicsFactory.prototype.drawConnection = function(visual, element) {
10273 var eventBus = this._eventBus;
10274
10275 return eventBus.fire('render.connection', { gfx: visual, element: element });
10276 };
10277
10278 GraphicsFactory.prototype.getConnectionPath = function(waypoints) {
10279 var eventBus = this._eventBus;
10280
10281 return eventBus.fire('render.getConnectionPath', waypoints);
10282 };
10283
10284 GraphicsFactory.prototype.update = function(type, element, gfx) {
10285
10286 // do NOT update root element
10287 if (!element.parent) {
10288 return;
10289 }
10290
10291 var visual = this._clear(gfx);
10292
10293 // redraw
10294 if (type === 'shape') {
10295 this.drawShape(visual, element);
10296
10297 // update positioning
10298 translate(gfx, element.x, element.y);
10299 } else
10300 if (type === 'connection') {
10301 this.drawConnection(visual, element);
10302 } else {
10303 throw new Error('unknown type: ' + type);
10304 }
10305
10306 if (element.hidden) {
10307 attr(gfx, 'display', 'none');
10308 } else {
10309 attr(gfx, 'display', 'block');
10310 }
10311 };
10312
10313 GraphicsFactory.prototype.remove = function(element) {
10314 var gfx = this._elementRegistry.getGraphics(element);
10315
10316 // remove
10317 remove(gfx.parentNode);
10318 };
10319
10320
10321 // helpers //////////
10322
10323 function prependTo(newNode, parentNode, siblingNode) {
10324 var node = siblingNode || parentNode.firstChild;
10325
10326 // do not prepend node to itself to prevent IE from crashing
10327 // https://github.com/bpmn-io/bpmn-js/issues/746
10328 if (newNode === node) {
10329 return;
10330 }
10331
10332 parentNode.insertBefore(newNode, node);
10333 }
10334
10335 var CoreModule$1 = {
10336 __depends__: [ DrawModule$1 ],
10337 __init__: [ 'canvas' ],
10338 canvas: [ 'type', Canvas ],
10339 elementRegistry: [ 'type', ElementRegistry ],
10340 elementFactory: [ 'type', ElementFactory ],
10341 eventBus: [ 'type', EventBus ],
10342 graphicsFactory: [ 'type', GraphicsFactory ]
10343 };
10344
10345 /**
10346 * Bootstrap an injector from a list of modules, instantiating a number of default components
10347 *
10348 * @ignore
10349 * @param {Array<didi.Module>} bootstrapModules
10350 *
10351 * @return {didi.Injector} a injector to use to access the components
10352 */
10353 function bootstrap(bootstrapModules) {
10354
10355 var modules = [],
10356 components = [];
10357
10358 function hasModule(m) {
10359 return modules.indexOf(m) >= 0;
10360 }
10361
10362 function addModule(m) {
10363 modules.push(m);
10364 }
10365
10366 function visit(m) {
10367 if (hasModule(m)) {
10368 return;
10369 }
10370
10371 (m.__depends__ || []).forEach(visit);
10372
10373 if (hasModule(m)) {
10374 return;
10375 }
10376
10377 addModule(m);
10378
10379 (m.__init__ || []).forEach(function(c) {
10380 components.push(c);
10381 });
10382 }
10383
10384 bootstrapModules.forEach(visit);
10385
10386 var injector = new Injector(modules);
10387
10388 components.forEach(function(c) {
10389
10390 try {
10391
10392 // eagerly resolve component (fn or string)
10393 injector[typeof c === 'string' ? 'get' : 'invoke'](c);
10394 } catch (e) {
10395 console.error('Failed to instantiate component');
10396 console.error(e.stack);
10397
10398 throw e;
10399 }
10400 });
10401
10402 return injector;
10403 }
10404
10405 /**
10406 * Creates an injector from passed options.
10407 *
10408 * @ignore
10409 * @param {Object} options
10410 * @return {didi.Injector}
10411 */
10412 function createInjector(options) {
10413
10414 options = options || {};
10415
10416 var configModule = {
10417 'config': ['value', options]
10418 };
10419
10420 var modules = [ configModule, CoreModule$1 ].concat(options.modules || []);
10421
10422 return bootstrap(modules);
10423 }
10424
10425
10426 /**
10427 * The main diagram-js entry point that bootstraps the diagram with the given
10428 * configuration.
10429 *
10430 * To register extensions with the diagram, pass them as Array<didi.Module> to the constructor.
10431 *
10432 * @class djs.Diagram
10433 * @memberOf djs
10434 * @constructor
10435 *
10436 * @example
10437 *
10438 * <caption>Creating a plug-in that logs whenever a shape is added to the canvas.</caption>
10439 *
10440 * // plug-in implemenentation
10441 * function MyLoggingPlugin(eventBus) {
10442 * eventBus.on('shape.added', function(event) {
10443 * console.log('shape ', event.shape, ' was added to the diagram');
10444 * });
10445 * }
10446 *
10447 * // export as module
10448 * export default {
10449 * __init__: [ 'myLoggingPlugin' ],
10450 * myLoggingPlugin: [ 'type', MyLoggingPlugin ]
10451 * };
10452 *
10453 *
10454 * // instantiate the diagram with the new plug-in
10455 *
10456 * import MyLoggingModule from 'path-to-my-logging-plugin';
10457 *
10458 * var diagram = new Diagram({
10459 * modules: [
10460 * MyLoggingModule
10461 * ]
10462 * });
10463 *
10464 * diagram.invoke([ 'canvas', function(canvas) {
10465 * // add shape to drawing canvas
10466 * canvas.addShape({ x: 10, y: 10 });
10467 * });
10468 *
10469 * // 'shape ... was added to the diagram' logged to console
10470 *
10471 * @param {Object} options
10472 * @param {Array<didi.Module>} [options.modules] external modules to instantiate with the diagram
10473 * @param {didi.Injector} [injector] an (optional) injector to bootstrap the diagram with
10474 */
10475 function Diagram(options, injector) {
10476
10477 // create injector unless explicitly specified
10478 this.injector = injector = injector || createInjector(options);
10479
10480 // API
10481
10482 /**
10483 * Resolves a diagram service
10484 *
10485 * @method Diagram#get
10486 *
10487 * @param {String} name the name of the diagram service to be retrieved
10488 * @param {Boolean} [strict=true] if false, resolve missing services to null
10489 */
10490 this.get = injector.get;
10491
10492 /**
10493 * Executes a function into which diagram services are injected
10494 *
10495 * @method Diagram#invoke
10496 *
10497 * @param {Function|Object[]} fn the function to resolve
10498 * @param {Object} locals a number of locals to use to resolve certain dependencies
10499 */
10500 this.invoke = injector.invoke;
10501
10502 // init
10503
10504 // indicate via event
10505
10506
10507 /**
10508 * An event indicating that all plug-ins are loaded.
10509 *
10510 * Use this event to fire other events to interested plug-ins
10511 *
10512 * @memberOf Diagram
10513 *
10514 * @event diagram.init
10515 *
10516 * @example
10517 *
10518 * eventBus.on('diagram.init', function() {
10519 * eventBus.fire('my-custom-event', { foo: 'BAR' });
10520 * });
10521 *
10522 * @type {Object}
10523 */
10524 this.get('eventBus').fire('diagram.init');
10525 }
10526
10527
10528 /**
10529 * Destroys the diagram
10530 *
10531 * @method Diagram#destroy
10532 */
10533 Diagram.prototype.destroy = function() {
10534 this.get('eventBus').fire('diagram.destroy');
10535 };
10536
10537 /**
10538 * Clear the diagram, removing all contents.
10539 */
10540 Diagram.prototype.clear = function() {
10541 this.get('eventBus').fire('diagram.clear');
10542 };
10543
10544 /**
10545 * Moddle base element.
10546 */
10547 function Base$1() { }
10548
10549 Base$1.prototype.get = function(name) {
10550 return this.$model.properties.get(this, name);
10551 };
10552
10553 Base$1.prototype.set = function(name, value) {
10554 this.$model.properties.set(this, name, value);
10555 };
10556
10557 /**
10558 * A model element factory.
10559 *
10560 * @param {Moddle} model
10561 * @param {Properties} properties
10562 */
10563 function Factory(model, properties) {
10564 this.model = model;
10565 this.properties = properties;
10566 }
10567
10568
10569 Factory.prototype.createType = function(descriptor) {
10570
10571 var model = this.model;
10572
10573 var props = this.properties,
10574 prototype = Object.create(Base$1.prototype);
10575
10576 // initialize default values
10577 forEach(descriptor.properties, function(p) {
10578 if (!p.isMany && p.default !== undefined) {
10579 prototype[p.name] = p.default;
10580 }
10581 });
10582
10583 props.defineModel(prototype, model);
10584 props.defineDescriptor(prototype, descriptor);
10585
10586 var name = descriptor.ns.name;
10587
10588 /**
10589 * The new type constructor
10590 */
10591 function ModdleElement(attrs) {
10592 props.define(this, '$type', { value: name, enumerable: true });
10593 props.define(this, '$attrs', { value: {} });
10594 props.define(this, '$parent', { writable: true });
10595
10596 forEach(attrs, bind(function(val, key) {
10597 this.set(key, val);
10598 }, this));
10599 }
10600
10601 ModdleElement.prototype = prototype;
10602
10603 ModdleElement.hasType = prototype.$instanceOf = this.model.hasType;
10604
10605 // static links
10606 props.defineModel(ModdleElement, model);
10607 props.defineDescriptor(ModdleElement, descriptor);
10608
10609 return ModdleElement;
10610 };
10611
10612 /**
10613 * Built-in moddle types
10614 */
10615 var BUILTINS = {
10616 String: true,
10617 Boolean: true,
10618 Integer: true,
10619 Real: true,
10620 Element: true
10621 };
10622
10623 /**
10624 * Converters for built in types from string representations
10625 */
10626 var TYPE_CONVERTERS = {
10627 String: function(s) { return s; },
10628 Boolean: function(s) { return s === 'true'; },
10629 Integer: function(s) { return parseInt(s, 10); },
10630 Real: function(s) { return parseFloat(s, 10); }
10631 };
10632
10633 /**
10634 * Convert a type to its real representation
10635 */
10636 function coerceType(type, value) {
10637
10638 var converter = TYPE_CONVERTERS[type];
10639
10640 if (converter) {
10641 return converter(value);
10642 } else {
10643 return value;
10644 }
10645 }
10646
10647 /**
10648 * Return whether the given type is built-in
10649 */
10650 function isBuiltIn(type) {
10651 return !!BUILTINS[type];
10652 }
10653
10654 /**
10655 * Return whether the given type is simple
10656 */
10657 function isSimple(type) {
10658 return !!TYPE_CONVERTERS[type];
10659 }
10660
10661 /**
10662 * Parses a namespaced attribute name of the form (ns:)localName to an object,
10663 * given a default prefix to assume in case no explicit namespace is given.
10664 *
10665 * @param {String} name
10666 * @param {String} [defaultPrefix] the default prefix to take, if none is present.
10667 *
10668 * @return {Object} the parsed name
10669 */
10670 function parseName(name, defaultPrefix) {
10671 var parts = name.split(/:/),
10672 localName, prefix;
10673
10674 // no prefix (i.e. only local name)
10675 if (parts.length === 1) {
10676 localName = name;
10677 prefix = defaultPrefix;
10678 } else
10679 // prefix + local name
10680 if (parts.length === 2) {
10681 localName = parts[1];
10682 prefix = parts[0];
10683 } else {
10684 throw new Error('expected <prefix:localName> or <localName>, got ' + name);
10685 }
10686
10687 name = (prefix ? prefix + ':' : '') + localName;
10688
10689 return {
10690 name: name,
10691 prefix: prefix,
10692 localName: localName
10693 };
10694 }
10695
10696 /**
10697 * A utility to build element descriptors.
10698 */
10699 function DescriptorBuilder(nameNs) {
10700 this.ns = nameNs;
10701 this.name = nameNs.name;
10702 this.allTypes = [];
10703 this.allTypesByName = {};
10704 this.properties = [];
10705 this.propertiesByName = {};
10706 }
10707
10708
10709 DescriptorBuilder.prototype.build = function() {
10710 return pick(this, [
10711 'ns',
10712 'name',
10713 'allTypes',
10714 'allTypesByName',
10715 'properties',
10716 'propertiesByName',
10717 'bodyProperty',
10718 'idProperty'
10719 ]);
10720 };
10721
10722 /**
10723 * Add property at given index.
10724 *
10725 * @param {Object} p
10726 * @param {Number} [idx]
10727 * @param {Boolean} [validate=true]
10728 */
10729 DescriptorBuilder.prototype.addProperty = function(p, idx, validate) {
10730
10731 if (typeof idx === 'boolean') {
10732 validate = idx;
10733 idx = undefined;
10734 }
10735
10736 this.addNamedProperty(p, validate !== false);
10737
10738 var properties = this.properties;
10739
10740 if (idx !== undefined) {
10741 properties.splice(idx, 0, p);
10742 } else {
10743 properties.push(p);
10744 }
10745 };
10746
10747
10748 DescriptorBuilder.prototype.replaceProperty = function(oldProperty, newProperty, replace) {
10749 var oldNameNs = oldProperty.ns;
10750
10751 var props = this.properties,
10752 propertiesByName = this.propertiesByName,
10753 rename = oldProperty.name !== newProperty.name;
10754
10755 if (oldProperty.isId) {
10756 if (!newProperty.isId) {
10757 throw new Error(
10758 'property <' + newProperty.ns.name + '> must be id property ' +
10759 'to refine <' + oldProperty.ns.name + '>');
10760 }
10761
10762 this.setIdProperty(newProperty, false);
10763 }
10764
10765 if (oldProperty.isBody) {
10766
10767 if (!newProperty.isBody) {
10768 throw new Error(
10769 'property <' + newProperty.ns.name + '> must be body property ' +
10770 'to refine <' + oldProperty.ns.name + '>');
10771 }
10772
10773 // TODO: Check compatibility
10774 this.setBodyProperty(newProperty, false);
10775 }
10776
10777 // validate existence and get location of old property
10778 var idx = props.indexOf(oldProperty);
10779 if (idx === -1) {
10780 throw new Error('property <' + oldNameNs.name + '> not found in property list');
10781 }
10782
10783 // remove old property
10784 props.splice(idx, 1);
10785
10786 // replacing the named property is intentional
10787 //
10788 // * validate only if this is a "rename" operation
10789 // * add at specific index unless we "replace"
10790 //
10791 this.addProperty(newProperty, replace ? undefined : idx, rename);
10792
10793 // make new property available under old name
10794 propertiesByName[oldNameNs.name] = propertiesByName[oldNameNs.localName] = newProperty;
10795 };
10796
10797
10798 DescriptorBuilder.prototype.redefineProperty = function(p, targetPropertyName, replace) {
10799
10800 var nsPrefix = p.ns.prefix;
10801 var parts = targetPropertyName.split('#');
10802
10803 var name = parseName(parts[0], nsPrefix);
10804 var attrName = parseName(parts[1], name.prefix).name;
10805
10806 var redefinedProperty = this.propertiesByName[attrName];
10807 if (!redefinedProperty) {
10808 throw new Error('refined property <' + attrName + '> not found');
10809 } else {
10810 this.replaceProperty(redefinedProperty, p, replace);
10811 }
10812
10813 delete p.redefines;
10814 };
10815
10816 DescriptorBuilder.prototype.addNamedProperty = function(p, validate) {
10817 var ns = p.ns,
10818 propsByName = this.propertiesByName;
10819
10820 if (validate) {
10821 this.assertNotDefined(p, ns.name);
10822 this.assertNotDefined(p, ns.localName);
10823 }
10824
10825 propsByName[ns.name] = propsByName[ns.localName] = p;
10826 };
10827
10828 DescriptorBuilder.prototype.removeNamedProperty = function(p) {
10829 var ns = p.ns,
10830 propsByName = this.propertiesByName;
10831
10832 delete propsByName[ns.name];
10833 delete propsByName[ns.localName];
10834 };
10835
10836 DescriptorBuilder.prototype.setBodyProperty = function(p, validate) {
10837
10838 if (validate && this.bodyProperty) {
10839 throw new Error(
10840 'body property defined multiple times ' +
10841 '(<' + this.bodyProperty.ns.name + '>, <' + p.ns.name + '>)');
10842 }
10843
10844 this.bodyProperty = p;
10845 };
10846
10847 DescriptorBuilder.prototype.setIdProperty = function(p, validate) {
10848
10849 if (validate && this.idProperty) {
10850 throw new Error(
10851 'id property defined multiple times ' +
10852 '(<' + this.idProperty.ns.name + '>, <' + p.ns.name + '>)');
10853 }
10854
10855 this.idProperty = p;
10856 };
10857
10858 DescriptorBuilder.prototype.assertNotDefined = function(p, name) {
10859 var propertyName = p.name,
10860 definedProperty = this.propertiesByName[propertyName];
10861
10862 if (definedProperty) {
10863 throw new Error(
10864 'property <' + propertyName + '> already defined; ' +
10865 'override of <' + definedProperty.definedBy.ns.name + '#' + definedProperty.ns.name + '> by ' +
10866 '<' + p.definedBy.ns.name + '#' + p.ns.name + '> not allowed without redefines');
10867 }
10868 };
10869
10870 DescriptorBuilder.prototype.hasProperty = function(name) {
10871 return this.propertiesByName[name];
10872 };
10873
10874 DescriptorBuilder.prototype.addTrait = function(t, inherited) {
10875
10876 var typesByName = this.allTypesByName,
10877 types = this.allTypes;
10878
10879 var typeName = t.name;
10880
10881 if (typeName in typesByName) {
10882 return;
10883 }
10884
10885 forEach(t.properties, bind(function(p) {
10886
10887 // clone property to allow extensions
10888 p = assign({}, p, {
10889 name: p.ns.localName,
10890 inherited: inherited
10891 });
10892
10893 Object.defineProperty(p, 'definedBy', {
10894 value: t
10895 });
10896
10897 var replaces = p.replaces,
10898 redefines = p.redefines;
10899
10900 // add replace/redefine support
10901 if (replaces || redefines) {
10902 this.redefineProperty(p, replaces || redefines, replaces);
10903 } else {
10904 if (p.isBody) {
10905 this.setBodyProperty(p);
10906 }
10907 if (p.isId) {
10908 this.setIdProperty(p);
10909 }
10910 this.addProperty(p);
10911 }
10912 }, this));
10913
10914 types.push(t);
10915 typesByName[typeName] = t;
10916 };
10917
10918 /**
10919 * A registry of Moddle packages.
10920 *
10921 * @param {Array<Package>} packages
10922 * @param {Properties} properties
10923 */
10924 function Registry(packages, properties) {
10925 this.packageMap = {};
10926 this.typeMap = {};
10927
10928 this.packages = [];
10929
10930 this.properties = properties;
10931
10932 forEach(packages, bind(this.registerPackage, this));
10933 }
10934
10935
10936 Registry.prototype.getPackage = function(uriOrPrefix) {
10937 return this.packageMap[uriOrPrefix];
10938 };
10939
10940 Registry.prototype.getPackages = function() {
10941 return this.packages;
10942 };
10943
10944
10945 Registry.prototype.registerPackage = function(pkg) {
10946
10947 // copy package
10948 pkg = assign({}, pkg);
10949
10950 var pkgMap = this.packageMap;
10951
10952 ensureAvailable(pkgMap, pkg, 'prefix');
10953 ensureAvailable(pkgMap, pkg, 'uri');
10954
10955 // register types
10956 forEach(pkg.types, bind(function(descriptor) {
10957 this.registerType(descriptor, pkg);
10958 }, this));
10959
10960 pkgMap[pkg.uri] = pkgMap[pkg.prefix] = pkg;
10961 this.packages.push(pkg);
10962 };
10963
10964
10965 /**
10966 * Register a type from a specific package with us
10967 */
10968 Registry.prototype.registerType = function(type, pkg) {
10969
10970 type = assign({}, type, {
10971 superClass: (type.superClass || []).slice(),
10972 extends: (type.extends || []).slice(),
10973 properties: (type.properties || []).slice(),
10974 meta: assign((type.meta || {}))
10975 });
10976
10977 var ns = parseName(type.name, pkg.prefix),
10978 name = ns.name,
10979 propertiesByName = {};
10980
10981 // parse properties
10982 forEach(type.properties, bind(function(p) {
10983
10984 // namespace property names
10985 var propertyNs = parseName(p.name, ns.prefix),
10986 propertyName = propertyNs.name;
10987
10988 // namespace property types
10989 if (!isBuiltIn(p.type)) {
10990 p.type = parseName(p.type, propertyNs.prefix).name;
10991 }
10992
10993 assign(p, {
10994 ns: propertyNs,
10995 name: propertyName
10996 });
10997
10998 propertiesByName[propertyName] = p;
10999 }, this));
11000
11001 // update ns + name
11002 assign(type, {
11003 ns: ns,
11004 name: name,
11005 propertiesByName: propertiesByName
11006 });
11007
11008 forEach(type.extends, bind(function(extendsName) {
11009 var extended = this.typeMap[extendsName];
11010
11011 extended.traits = extended.traits || [];
11012 extended.traits.push(name);
11013 }, this));
11014
11015 // link to package
11016 this.definePackage(type, pkg);
11017
11018 // register
11019 this.typeMap[name] = type;
11020 };
11021
11022
11023 /**
11024 * Traverse the type hierarchy from bottom to top,
11025 * calling iterator with (type, inherited) for all elements in
11026 * the inheritance chain.
11027 *
11028 * @param {Object} nsName
11029 * @param {Function} iterator
11030 * @param {Boolean} [trait=false]
11031 */
11032 Registry.prototype.mapTypes = function(nsName, iterator, trait) {
11033
11034 var type = isBuiltIn(nsName.name) ? { name: nsName.name } : this.typeMap[nsName.name];
11035
11036 var self = this;
11037
11038 /**
11039 * Traverse the selected trait.
11040 *
11041 * @param {String} cls
11042 */
11043 function traverseTrait(cls) {
11044 return traverseSuper(cls, true);
11045 }
11046
11047 /**
11048 * Traverse the selected super type or trait
11049 *
11050 * @param {String} cls
11051 * @param {Boolean} [trait=false]
11052 */
11053 function traverseSuper(cls, trait) {
11054 var parentNs = parseName(cls, isBuiltIn(cls) ? '' : nsName.prefix);
11055 self.mapTypes(parentNs, iterator, trait);
11056 }
11057
11058 if (!type) {
11059 throw new Error('unknown type <' + nsName.name + '>');
11060 }
11061
11062 forEach(type.superClass, trait ? traverseTrait : traverseSuper);
11063
11064 // call iterator with (type, inherited=!trait)
11065 iterator(type, !trait);
11066
11067 forEach(type.traits, traverseTrait);
11068 };
11069
11070
11071 /**
11072 * Returns the effective descriptor for a type.
11073 *
11074 * @param {String} type the namespaced name (ns:localName) of the type
11075 *
11076 * @return {Descriptor} the resulting effective descriptor
11077 */
11078 Registry.prototype.getEffectiveDescriptor = function(name) {
11079
11080 var nsName = parseName(name);
11081
11082 var builder = new DescriptorBuilder(nsName);
11083
11084 this.mapTypes(nsName, function(type, inherited) {
11085 builder.addTrait(type, inherited);
11086 });
11087
11088 var descriptor = builder.build();
11089
11090 // define package link
11091 this.definePackage(descriptor, descriptor.allTypes[descriptor.allTypes.length - 1].$pkg);
11092
11093 return descriptor;
11094 };
11095
11096
11097 Registry.prototype.definePackage = function(target, pkg) {
11098 this.properties.define(target, '$pkg', { value: pkg });
11099 };
11100
11101
11102
11103 ///////// helpers ////////////////////////////
11104
11105 function ensureAvailable(packageMap, pkg, identifierKey) {
11106
11107 var value = pkg[identifierKey];
11108
11109 if (value in packageMap) {
11110 throw new Error('package with ' + identifierKey + ' <' + value + '> already defined');
11111 }
11112 }
11113
11114 /**
11115 * A utility that gets and sets properties of model elements.
11116 *
11117 * @param {Model} model
11118 */
11119 function Properties(model) {
11120 this.model = model;
11121 }
11122
11123
11124 /**
11125 * Sets a named property on the target element.
11126 * If the value is undefined, the property gets deleted.
11127 *
11128 * @param {Object} target
11129 * @param {String} name
11130 * @param {Object} value
11131 */
11132 Properties.prototype.set = function(target, name, value) {
11133
11134 var property = this.model.getPropertyDescriptor(target, name);
11135
11136 var propertyName = property && property.name;
11137
11138 if (isUndefined$1(value)) {
11139 // unset the property, if the specified value is undefined;
11140 // delete from $attrs (for extensions) or the target itself
11141 if (property) {
11142 delete target[propertyName];
11143 } else {
11144 delete target.$attrs[name];
11145 }
11146 } else {
11147 // set the property, defining well defined properties on the fly
11148 // or simply updating them in target.$attrs (for extensions)
11149 if (property) {
11150 if (propertyName in target) {
11151 target[propertyName] = value;
11152 } else {
11153 defineProperty$1(target, property, value);
11154 }
11155 } else {
11156 target.$attrs[name] = value;
11157 }
11158 }
11159 };
11160
11161 /**
11162 * Returns the named property of the given element
11163 *
11164 * @param {Object} target
11165 * @param {String} name
11166 *
11167 * @return {Object}
11168 */
11169 Properties.prototype.get = function(target, name) {
11170
11171 var property = this.model.getPropertyDescriptor(target, name);
11172
11173 if (!property) {
11174 return target.$attrs[name];
11175 }
11176
11177 var propertyName = property.name;
11178
11179 // check if access to collection property and lazily initialize it
11180 if (!target[propertyName] && property.isMany) {
11181 defineProperty$1(target, property, []);
11182 }
11183
11184 return target[propertyName];
11185 };
11186
11187
11188 /**
11189 * Define a property on the target element
11190 *
11191 * @param {Object} target
11192 * @param {String} name
11193 * @param {Object} options
11194 */
11195 Properties.prototype.define = function(target, name, options) {
11196 Object.defineProperty(target, name, options);
11197 };
11198
11199
11200 /**
11201 * Define the descriptor for an element
11202 */
11203 Properties.prototype.defineDescriptor = function(target, descriptor) {
11204 this.define(target, '$descriptor', { value: descriptor });
11205 };
11206
11207 /**
11208 * Define the model for an element
11209 */
11210 Properties.prototype.defineModel = function(target, model) {
11211 this.define(target, '$model', { value: model });
11212 };
11213
11214
11215 function isUndefined$1(val) {
11216 return typeof val === 'undefined';
11217 }
11218
11219 function defineProperty$1(target, property, value) {
11220 Object.defineProperty(target, property.name, {
11221 enumerable: !property.isReference,
11222 writable: true,
11223 value: value,
11224 configurable: true
11225 });
11226 }
11227
11228 //// Moddle implementation /////////////////////////////////////////////////
11229
11230 /**
11231 * @class Moddle
11232 *
11233 * A model that can be used to create elements of a specific type.
11234 *
11235 * @example
11236 *
11237 * var Moddle = require('moddle');
11238 *
11239 * var pkg = {
11240 * name: 'mypackage',
11241 * prefix: 'my',
11242 * types: [
11243 * { name: 'Root' }
11244 * ]
11245 * };
11246 *
11247 * var moddle = new Moddle([pkg]);
11248 *
11249 * @param {Array<Package>} packages the packages to contain
11250 */
11251 function Moddle(packages) {
11252
11253 this.properties = new Properties(this);
11254
11255 this.factory = new Factory(this, this.properties);
11256 this.registry = new Registry(packages, this.properties);
11257
11258 this.typeCache = {};
11259 }
11260
11261
11262 /**
11263 * Create an instance of the specified type.
11264 *
11265 * @method Moddle#create
11266 *
11267 * @example
11268 *
11269 * var foo = moddle.create('my:Foo');
11270 * var bar = moddle.create('my:Bar', { id: 'BAR_1' });
11271 *
11272 * @param {String|Object} descriptor the type descriptor or name know to the model
11273 * @param {Object} attrs a number of attributes to initialize the model instance with
11274 * @return {Object} model instance
11275 */
11276 Moddle.prototype.create = function(descriptor, attrs) {
11277 var Type = this.getType(descriptor);
11278
11279 if (!Type) {
11280 throw new Error('unknown type <' + descriptor + '>');
11281 }
11282
11283 return new Type(attrs);
11284 };
11285
11286
11287 /**
11288 * Returns the type representing a given descriptor
11289 *
11290 * @method Moddle#getType
11291 *
11292 * @example
11293 *
11294 * var Foo = moddle.getType('my:Foo');
11295 * var foo = new Foo({ 'id' : 'FOO_1' });
11296 *
11297 * @param {String|Object} descriptor the type descriptor or name know to the model
11298 * @return {Object} the type representing the descriptor
11299 */
11300 Moddle.prototype.getType = function(descriptor) {
11301
11302 var cache = this.typeCache;
11303
11304 var name = isString(descriptor) ? descriptor : descriptor.ns.name;
11305
11306 var type = cache[name];
11307
11308 if (!type) {
11309 descriptor = this.registry.getEffectiveDescriptor(name);
11310 type = cache[name] = this.factory.createType(descriptor);
11311 }
11312
11313 return type;
11314 };
11315
11316
11317 /**
11318 * Creates an any-element type to be used within model instances.
11319 *
11320 * This can be used to create custom elements that lie outside the meta-model.
11321 * The created element contains all the meta-data required to serialize it
11322 * as part of meta-model elements.
11323 *
11324 * @method Moddle#createAny
11325 *
11326 * @example
11327 *
11328 * var foo = moddle.createAny('vendor:Foo', 'http://vendor', {
11329 * value: 'bar'
11330 * });
11331 *
11332 * var container = moddle.create('my:Container', 'http://my', {
11333 * any: [ foo ]
11334 * });
11335 *
11336 * // go ahead and serialize the stuff
11337 *
11338 *
11339 * @param {String} name the name of the element
11340 * @param {String} nsUri the namespace uri of the element
11341 * @param {Object} [properties] a map of properties to initialize the instance with
11342 * @return {Object} the any type instance
11343 */
11344 Moddle.prototype.createAny = function(name, nsUri, properties) {
11345
11346 var nameNs = parseName(name);
11347
11348 var element = {
11349 $type: name,
11350 $instanceOf: function(type) {
11351 return type === this.$type;
11352 }
11353 };
11354
11355 var descriptor = {
11356 name: name,
11357 isGeneric: true,
11358 ns: {
11359 prefix: nameNs.prefix,
11360 localName: nameNs.localName,
11361 uri: nsUri
11362 }
11363 };
11364
11365 this.properties.defineDescriptor(element, descriptor);
11366 this.properties.defineModel(element, this);
11367 this.properties.define(element, '$parent', { enumerable: false, writable: true });
11368
11369 forEach(properties, function(a, key) {
11370 if (isObject(a) && a.value !== undefined) {
11371 element[a.name] = a.value;
11372 } else {
11373 element[key] = a;
11374 }
11375 });
11376
11377 return element;
11378 };
11379
11380 /**
11381 * Returns a registered package by uri or prefix
11382 *
11383 * @return {Object} the package
11384 */
11385 Moddle.prototype.getPackage = function(uriOrPrefix) {
11386 return this.registry.getPackage(uriOrPrefix);
11387 };
11388
11389 /**
11390 * Returns a snapshot of all known packages
11391 *
11392 * @return {Object} the package
11393 */
11394 Moddle.prototype.getPackages = function() {
11395 return this.registry.getPackages();
11396 };
11397
11398 /**
11399 * Returns the descriptor for an element
11400 */
11401 Moddle.prototype.getElementDescriptor = function(element) {
11402 return element.$descriptor;
11403 };
11404
11405 /**
11406 * Returns true if the given descriptor or instance
11407 * represents the given type.
11408 *
11409 * May be applied to this, if element is omitted.
11410 */
11411 Moddle.prototype.hasType = function(element, type) {
11412 if (type === undefined) {
11413 type = element;
11414 element = this;
11415 }
11416
11417 var descriptor = element.$model.getElementDescriptor(element);
11418
11419 return (type in descriptor.allTypesByName);
11420 };
11421
11422 /**
11423 * Returns the descriptor of an elements named property
11424 */
11425 Moddle.prototype.getPropertyDescriptor = function(element, property) {
11426 return this.getElementDescriptor(element).propertiesByName[property];
11427 };
11428
11429 /**
11430 * Returns a mapped type's descriptor
11431 */
11432 Moddle.prototype.getTypeDescriptor = function(type) {
11433 return this.registry.typeMap[type];
11434 };
11435
11436 var fromCharCode = String.fromCharCode;
11437
11438 var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
11439
11440 var ENTITY_PATTERN = /&#(\d+);|&#x([0-9a-f]+);|&(\w+);/ig;
11441
11442 var ENTITY_MAPPING = {
11443 'amp': '&',
11444 'apos': '\'',
11445 'gt': '>',
11446 'lt': '<',
11447 'quot': '"'
11448 };
11449
11450 // map UPPERCASE variants of supported special chars
11451 Object.keys(ENTITY_MAPPING).forEach(function(k) {
11452 ENTITY_MAPPING[k.toUpperCase()] = ENTITY_MAPPING[k];
11453 });
11454
11455
11456 function replaceEntities(_, d, x, z) {
11457
11458 // reserved names, i.e. &nbsp;
11459 if (z) {
11460 if (hasOwnProperty$1.call(ENTITY_MAPPING, z)) {
11461 return ENTITY_MAPPING[z];
11462 } else {
11463 // fall back to original value
11464 return '&' + z + ';';
11465 }
11466 }
11467
11468 // decimal encoded char
11469 if (d) {
11470 return fromCharCode(d);
11471 }
11472
11473 // hex encoded char
11474 return fromCharCode(parseInt(x, 16));
11475 }
11476
11477
11478 /**
11479 * A basic entity decoder that can decode a minimal
11480 * sub-set of reserved names (&amp;) as well as
11481 * hex (&#xaaf;) and decimal (&#1231;) encoded characters.
11482 *
11483 * @param {string} str
11484 *
11485 * @return {string} decoded string
11486 */
11487 function decodeEntities(s) {
11488 if (s.length > 3 && s.indexOf('&') !== -1) {
11489 return s.replace(ENTITY_PATTERN, replaceEntities);
11490 }
11491
11492 return s;
11493 }
11494
11495 var XSI_URI = 'http://www.w3.org/2001/XMLSchema-instance';
11496 var XSI_PREFIX = 'xsi';
11497 var XSI_TYPE = 'xsi:type';
11498
11499 var NON_WHITESPACE_OUTSIDE_ROOT_NODE = 'non-whitespace outside of root node';
11500
11501 function error(msg) {
11502 return new Error(msg);
11503 }
11504
11505 function missingNamespaceForPrefix(prefix) {
11506 return 'missing namespace for prefix <' + prefix + '>';
11507 }
11508
11509 function getter(getFn) {
11510 return {
11511 'get': getFn,
11512 'enumerable': true
11513 };
11514 }
11515
11516 function cloneNsMatrix(nsMatrix) {
11517 var clone = {}, key;
11518 for (key in nsMatrix) {
11519 clone[key] = nsMatrix[key];
11520 }
11521 return clone;
11522 }
11523
11524 function uriPrefix(prefix) {
11525 return prefix + '$uri';
11526 }
11527
11528 function buildNsMatrix(nsUriToPrefix) {
11529 var nsMatrix = {},
11530 uri,
11531 prefix;
11532
11533 for (uri in nsUriToPrefix) {
11534 prefix = nsUriToPrefix[uri];
11535 nsMatrix[prefix] = prefix;
11536 nsMatrix[uriPrefix(prefix)] = uri;
11537 }
11538
11539 return nsMatrix;
11540 }
11541
11542 function noopGetContext() {
11543 return { 'line': 0, 'column': 0 };
11544 }
11545
11546 function throwFunc(err) {
11547 throw err;
11548 }
11549
11550 /**
11551 * Creates a new parser with the given options.
11552 *
11553 * @constructor
11554 *
11555 * @param {!Object<string, ?>=} options
11556 */
11557 function Parser(options) {
11558
11559 if (!this) {
11560 return new Parser(options);
11561 }
11562
11563 var proxy = options && options['proxy'];
11564
11565 var onText,
11566 onOpenTag,
11567 onCloseTag,
11568 onCDATA,
11569 onError = throwFunc,
11570 onWarning,
11571 onComment,
11572 onQuestion,
11573 onAttention;
11574
11575 var getContext = noopGetContext;
11576
11577 /**
11578 * Do we need to parse the current elements attributes for namespaces?
11579 *
11580 * @type {boolean}
11581 */
11582 var maybeNS = false;
11583
11584 /**
11585 * Do we process namespaces at all?
11586 *
11587 * @type {boolean}
11588 */
11589 var isNamespace = false;
11590
11591 /**
11592 * The caught error returned on parse end
11593 *
11594 * @type {Error}
11595 */
11596 var returnError = null;
11597
11598 /**
11599 * Should we stop parsing?
11600 *
11601 * @type {boolean}
11602 */
11603 var parseStop = false;
11604
11605 /**
11606 * A map of { uri: prefix } used by the parser.
11607 *
11608 * This map will ensure we can normalize prefixes during processing;
11609 * for each uri, only one prefix will be exposed to the handlers.
11610 *
11611 * @type {!Object<string, string>}}
11612 */
11613 var nsUriToPrefix;
11614
11615 /**
11616 * Handle parse error.
11617 *
11618 * @param {string|Error} err
11619 */
11620 function handleError(err) {
11621 if (!(err instanceof Error)) {
11622 err = error(err);
11623 }
11624
11625 returnError = err;
11626
11627 onError(err, getContext);
11628 }
11629
11630 /**
11631 * Handle parse error.
11632 *
11633 * @param {string|Error} err
11634 */
11635 function handleWarning(err) {
11636
11637 if (!onWarning) {
11638 return;
11639 }
11640
11641 if (!(err instanceof Error)) {
11642 err = error(err);
11643 }
11644
11645 onWarning(err, getContext);
11646 }
11647
11648 /**
11649 * Register parse listener.
11650 *
11651 * @param {string} name
11652 * @param {Function} cb
11653 *
11654 * @return {Parser}
11655 */
11656 this['on'] = function(name, cb) {
11657
11658 if (typeof cb !== 'function') {
11659 throw error('required args <name, cb>');
11660 }
11661
11662 switch (name) {
11663 case 'openTag': onOpenTag = cb; break;
11664 case 'text': onText = cb; break;
11665 case 'closeTag': onCloseTag = cb; break;
11666 case 'error': onError = cb; break;
11667 case 'warn': onWarning = cb; break;
11668 case 'cdata': onCDATA = cb; break;
11669 case 'attention': onAttention = cb; break; // <!XXXXX zzzz="eeee">
11670 case 'question': onQuestion = cb; break; // <? .... ?>
11671 case 'comment': onComment = cb; break;
11672 default:
11673 throw error('unsupported event: ' + name);
11674 }
11675
11676 return this;
11677 };
11678
11679 /**
11680 * Set the namespace to prefix mapping.
11681 *
11682 * @example
11683 *
11684 * parser.ns({
11685 * 'http://foo': 'foo',
11686 * 'http://bar': 'bar'
11687 * });
11688 *
11689 * @param {!Object<string, string>} nsMap
11690 *
11691 * @return {Parser}
11692 */
11693 this['ns'] = function(nsMap) {
11694
11695 if (typeof nsMap === 'undefined') {
11696 nsMap = {};
11697 }
11698
11699 if (typeof nsMap !== 'object') {
11700 throw error('required args <nsMap={}>');
11701 }
11702
11703 var _nsUriToPrefix = {}, k;
11704
11705 for (k in nsMap) {
11706 _nsUriToPrefix[k] = nsMap[k];
11707 }
11708
11709 // FORCE default mapping for schema instance
11710 _nsUriToPrefix[XSI_URI] = XSI_PREFIX;
11711
11712 isNamespace = true;
11713 nsUriToPrefix = _nsUriToPrefix;
11714
11715 return this;
11716 };
11717
11718 /**
11719 * Parse xml string.
11720 *
11721 * @param {string} xml
11722 *
11723 * @return {Error} returnError, if not thrown
11724 */
11725 this['parse'] = function(xml) {
11726 if (typeof xml !== 'string') {
11727 throw error('required args <xml=string>');
11728 }
11729
11730 returnError = null;
11731
11732 parse(xml);
11733
11734 getContext = noopGetContext;
11735 parseStop = false;
11736
11737 return returnError;
11738 };
11739
11740 /**
11741 * Stop parsing.
11742 */
11743 this['stop'] = function() {
11744 parseStop = true;
11745 };
11746
11747 /**
11748 * Parse string, invoking configured listeners on element.
11749 *
11750 * @param {string} xml
11751 */
11752 function parse(xml) {
11753 var nsMatrixStack = isNamespace ? [] : null,
11754 nsMatrix = isNamespace ? buildNsMatrix(nsUriToPrefix) : null,
11755 _nsMatrix,
11756 nodeStack = [],
11757 anonymousNsCount = 0,
11758 tagStart = false,
11759 tagEnd = false,
11760 i = 0, j = 0,
11761 x, y, q, w,
11762 xmlns,
11763 elementName,
11764 _elementName,
11765 elementProxy
11766 ;
11767
11768 var attrsString = '',
11769 attrsStart = 0,
11770 cachedAttrs // false = parsed with errors, null = needs parsing
11771 ;
11772
11773 /**
11774 * Parse attributes on demand and returns the parsed attributes.
11775 *
11776 * Return semantics: (1) `false` on attribute parse error,
11777 * (2) object hash on extracted attrs.
11778 *
11779 * @return {boolean|Object}
11780 */
11781 function getAttrs() {
11782 if (cachedAttrs !== null) {
11783 return cachedAttrs;
11784 }
11785
11786 var nsUri,
11787 nsUriPrefix,
11788 nsName,
11789 defaultAlias = isNamespace && nsMatrix['xmlns'],
11790 attrList = isNamespace && maybeNS ? [] : null,
11791 i = attrsStart,
11792 s = attrsString,
11793 l = s.length,
11794 hasNewMatrix,
11795 newalias,
11796 value,
11797 alias,
11798 name,
11799 attrs = {},
11800 seenAttrs = {},
11801 skipAttr,
11802 w,
11803 j;
11804
11805 parseAttr:
11806 for (; i < l; i++) {
11807 skipAttr = false;
11808 w = s.charCodeAt(i);
11809
11810 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE={ \f\n\r\t\v}
11811 continue;
11812 }
11813
11814 // wait for non whitespace character
11815 if (w < 65 || w > 122 || (w > 90 && w < 97)) {
11816 if (w !== 95 && w !== 58) { // char 95"_" 58":"
11817 handleWarning('illegal first char attribute name');
11818 skipAttr = true;
11819 }
11820 }
11821
11822 // parse attribute name
11823 for (j = i + 1; j < l; j++) {
11824 w = s.charCodeAt(j);
11825
11826 if (
11827 w > 96 && w < 123 ||
11828 w > 64 && w < 91 ||
11829 w > 47 && w < 59 ||
11830 w === 46 || // '.'
11831 w === 45 || // '-'
11832 w === 95 // '_'
11833 ) {
11834 continue;
11835 }
11836
11837 // unexpected whitespace
11838 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
11839 handleWarning('missing attribute value');
11840 i = j;
11841
11842 continue parseAttr;
11843 }
11844
11845 // expected "="
11846 if (w === 61) { // "=" == 61
11847 break;
11848 }
11849
11850 handleWarning('illegal attribute name char');
11851 skipAttr = true;
11852 }
11853
11854 name = s.substring(i, j);
11855
11856 if (name === 'xmlns:xmlns') {
11857 handleWarning('illegal declaration of xmlns');
11858 skipAttr = true;
11859 }
11860
11861 w = s.charCodeAt(j + 1);
11862
11863 if (w === 34) { // '"'
11864 j = s.indexOf('"', i = j + 2);
11865
11866 if (j === -1) {
11867 j = s.indexOf('\'', i);
11868
11869 if (j !== -1) {
11870 handleWarning('attribute value quote missmatch');
11871 skipAttr = true;
11872 }
11873 }
11874
11875 } else if (w === 39) { // "'"
11876 j = s.indexOf('\'', i = j + 2);
11877
11878 if (j === -1) {
11879 j = s.indexOf('"', i);
11880
11881 if (j !== -1) {
11882 handleWarning('attribute value quote missmatch');
11883 skipAttr = true;
11884 }
11885 }
11886
11887 } else {
11888 handleWarning('missing attribute value quotes');
11889 skipAttr = true;
11890
11891 // skip to next space
11892 for (j = j + 1; j < l; j++) {
11893 w = s.charCodeAt(j + 1);
11894
11895 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
11896 break;
11897 }
11898 }
11899
11900 }
11901
11902 if (j === -1) {
11903 handleWarning('missing closing quotes');
11904
11905 j = l;
11906 skipAttr = true;
11907 }
11908
11909 if (!skipAttr) {
11910 value = s.substring(i, j);
11911 }
11912
11913 i = j;
11914
11915 // ensure SPACE follows attribute
11916 // skip illegal content otherwise
11917 // example a="b"c
11918 for (; j + 1 < l; j++) {
11919 w = s.charCodeAt(j + 1);
11920
11921 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
11922 break;
11923 }
11924
11925 // FIRST ILLEGAL CHAR
11926 if (i === j) {
11927 handleWarning('illegal character after attribute end');
11928 skipAttr = true;
11929 }
11930 }
11931
11932 // advance cursor to next attribute
11933 i = j + 1;
11934
11935 if (skipAttr) {
11936 continue parseAttr;
11937 }
11938
11939 // check attribute re-declaration
11940 if (name in seenAttrs) {
11941 handleWarning('attribute <' + name + '> already defined');
11942 continue;
11943 }
11944
11945 seenAttrs[name] = true;
11946
11947 if (!isNamespace) {
11948 attrs[name] = value;
11949 continue;
11950 }
11951
11952 // try to extract namespace information
11953 if (maybeNS) {
11954 newalias = (
11955 name === 'xmlns'
11956 ? 'xmlns'
11957 : (name.charCodeAt(0) === 120 && name.substr(0, 6) === 'xmlns:')
11958 ? name.substr(6)
11959 : null
11960 );
11961
11962 // handle xmlns(:alias) assignment
11963 if (newalias !== null) {
11964 nsUri = decodeEntities(value);
11965 nsUriPrefix = uriPrefix(newalias);
11966
11967 alias = nsUriToPrefix[nsUri];
11968
11969 if (!alias) {
11970 // no prefix defined or prefix collision
11971 if (
11972 (newalias === 'xmlns') ||
11973 (nsUriPrefix in nsMatrix && nsMatrix[nsUriPrefix] !== nsUri)
11974 ) {
11975 // alocate free ns prefix
11976 do {
11977 alias = 'ns' + (anonymousNsCount++);
11978 } while (typeof nsMatrix[alias] !== 'undefined');
11979 } else {
11980 alias = newalias;
11981 }
11982
11983 nsUriToPrefix[nsUri] = alias;
11984 }
11985
11986 if (nsMatrix[newalias] !== alias) {
11987 if (!hasNewMatrix) {
11988 nsMatrix = cloneNsMatrix(nsMatrix);
11989 hasNewMatrix = true;
11990 }
11991
11992 nsMatrix[newalias] = alias;
11993 if (newalias === 'xmlns') {
11994 nsMatrix[uriPrefix(alias)] = nsUri;
11995 defaultAlias = alias;
11996 }
11997
11998 nsMatrix[nsUriPrefix] = nsUri;
11999 }
12000
12001 // expose xmlns(:asd)="..." in attributes
12002 attrs[name] = value;
12003 continue;
12004 }
12005
12006 // collect attributes until all namespace
12007 // declarations are processed
12008 attrList.push(name, value);
12009 continue;
12010
12011 } /** end if (maybeNs) */
12012
12013 // handle attributes on element without
12014 // namespace declarations
12015 w = name.indexOf(':');
12016 if (w === -1) {
12017 attrs[name] = value;
12018 continue;
12019 }
12020
12021 // normalize ns attribute name
12022 if (!(nsName = nsMatrix[name.substring(0, w)])) {
12023 handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
12024 continue;
12025 }
12026
12027 name = defaultAlias === nsName
12028 ? name.substr(w + 1)
12029 : nsName + name.substr(w);
12030 // end: normalize ns attribute name
12031
12032 // normalize xsi:type ns attribute value
12033 if (name === XSI_TYPE) {
12034 w = value.indexOf(':');
12035
12036 if (w !== -1) {
12037 nsName = value.substring(0, w);
12038 // handle default prefixes, i.e. xs:String gracefully
12039 nsName = nsMatrix[nsName] || nsName;
12040 value = nsName + value.substring(w);
12041 } else {
12042 value = defaultAlias + ':' + value;
12043 }
12044 }
12045 // end: normalize xsi:type ns attribute value
12046
12047 attrs[name] = value;
12048 }
12049
12050
12051 // handle deferred, possibly namespaced attributes
12052 if (maybeNS) {
12053
12054 // normalize captured attributes
12055 for (i = 0, l = attrList.length; i < l; i++) {
12056
12057 name = attrList[i++];
12058 value = attrList[i];
12059
12060 w = name.indexOf(':');
12061
12062 if (w !== -1) {
12063 // normalize ns attribute name
12064 if (!(nsName = nsMatrix[name.substring(0, w)])) {
12065 handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
12066 continue;
12067 }
12068
12069 name = defaultAlias === nsName
12070 ? name.substr(w + 1)
12071 : nsName + name.substr(w);
12072 // end: normalize ns attribute name
12073
12074 // normalize xsi:type ns attribute value
12075 if (name === XSI_TYPE) {
12076 w = value.indexOf(':');
12077
12078 if (w !== -1) {
12079 nsName = value.substring(0, w);
12080 // handle default prefixes, i.e. xs:String gracefully
12081 nsName = nsMatrix[nsName] || nsName;
12082 value = nsName + value.substring(w);
12083 } else {
12084 value = defaultAlias + ':' + value;
12085 }
12086 }
12087 // end: normalize xsi:type ns attribute value
12088 }
12089
12090 attrs[name] = value;
12091 }
12092 // end: normalize captured attributes
12093 }
12094
12095 return cachedAttrs = attrs;
12096 }
12097
12098 /**
12099 * Extract the parse context { line, column, part }
12100 * from the current parser position.
12101 *
12102 * @return {Object} parse context
12103 */
12104 function getParseContext() {
12105 var splitsRe = /(\r\n|\r|\n)/g;
12106
12107 var line = 0;
12108 var column = 0;
12109 var startOfLine = 0;
12110 var endOfLine = j;
12111 var match;
12112 var data;
12113
12114 while (i >= startOfLine) {
12115
12116 match = splitsRe.exec(xml);
12117
12118 if (!match) {
12119 break;
12120 }
12121
12122 // end of line = (break idx + break chars)
12123 endOfLine = match[0].length + match.index;
12124
12125 if (endOfLine > i) {
12126 break;
12127 }
12128
12129 // advance to next line
12130 line += 1;
12131
12132 startOfLine = endOfLine;
12133 }
12134
12135 // EOF errors
12136 if (i == -1) {
12137 column = endOfLine;
12138 data = xml.substring(j);
12139 } else
12140 // start errors
12141 if (j === 0) {
12142 console.log(i - startOfLine);
12143 data = xml.substring(j, i);
12144 }
12145 // other errors
12146 else {
12147 column = i - startOfLine;
12148 data = (j == -1 ? xml.substring(i) : xml.substring(i, j + 1));
12149 }
12150
12151 return {
12152 'data': data,
12153 'line': line,
12154 'column': column
12155 };
12156 }
12157
12158 getContext = getParseContext;
12159
12160
12161 if (proxy) {
12162 elementProxy = Object.create({}, {
12163 'name': getter(function() {
12164 return elementName;
12165 }),
12166 'originalName': getter(function() {
12167 return _elementName;
12168 }),
12169 'attrs': getter(getAttrs),
12170 'ns': getter(function() {
12171 return nsMatrix;
12172 })
12173 });
12174 }
12175
12176 // actual parse logic
12177 while (j !== -1) {
12178
12179 if (xml.charCodeAt(j) === 60) { // "<"
12180 i = j;
12181 } else {
12182 i = xml.indexOf('<', j);
12183 }
12184
12185 // parse end
12186 if (i === -1) {
12187 if (nodeStack.length) {
12188 return handleError('unexpected end of file');
12189 }
12190
12191 if (j === 0) {
12192 return handleError('missing start tag');
12193 }
12194
12195 if (j < xml.length) {
12196 if (xml.substring(j).trim()) {
12197 handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
12198 }
12199 }
12200
12201 return;
12202 }
12203
12204 // parse text
12205 if (j !== i) {
12206
12207 if (nodeStack.length) {
12208 if (onText) {
12209 onText(xml.substring(j, i), decodeEntities, getContext);
12210
12211 if (parseStop) {
12212 return;
12213 }
12214 }
12215 } else {
12216 if (xml.substring(j, i).trim()) {
12217 handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
12218
12219 if (parseStop) {
12220 return;
12221 }
12222 }
12223 }
12224 }
12225
12226 w = xml.charCodeAt(i+1);
12227
12228 // parse comments + CDATA
12229 if (w === 33) { // "!"
12230 w = xml.charCodeAt(i+2);
12231 if (w === 91 && xml.substr(i + 3, 6) === 'CDATA[') { // 91 == "["
12232 j = xml.indexOf(']]>', i);
12233 if (j === -1) {
12234 return handleError('unclosed cdata');
12235 }
12236
12237 if (onCDATA) {
12238 onCDATA(xml.substring(i + 9, j), getContext);
12239 if (parseStop) {
12240 return;
12241 }
12242 }
12243
12244 j += 3;
12245 continue;
12246 }
12247
12248
12249 if (w === 45 && xml.charCodeAt(i + 3) === 45) { // 45 == "-"
12250 j = xml.indexOf('-->', i);
12251 if (j === -1) {
12252 return handleError('unclosed comment');
12253 }
12254
12255
12256 if (onComment) {
12257 onComment(xml.substring(i + 4, j), decodeEntities, getContext);
12258 if (parseStop) {
12259 return;
12260 }
12261 }
12262
12263 j += 3;
12264 continue;
12265 }
12266
12267 j = xml.indexOf('>', i + 1);
12268 if (j === -1) {
12269 return handleError('unclosed tag');
12270 }
12271
12272 if (onAttention) {
12273 onAttention(xml.substring(i, j + 1), decodeEntities, getContext);
12274 if (parseStop) {
12275 return;
12276 }
12277 }
12278
12279 j += 1;
12280 continue;
12281 }
12282
12283 if (w === 63) { // "?"
12284 j = xml.indexOf('?>', i);
12285 if (j === -1) {
12286 return handleError('unclosed question');
12287 }
12288
12289 if (onQuestion) {
12290 onQuestion(xml.substring(i, j + 2), getContext);
12291 if (parseStop) {
12292 return;
12293 }
12294 }
12295
12296 j += 2;
12297 continue;
12298 }
12299
12300 j = xml.indexOf('>', i + 1);
12301
12302 if (j == -1) {
12303 return handleError('unclosed tag');
12304 }
12305
12306 // don't process attributes;
12307 // there are none
12308 cachedAttrs = {};
12309
12310 // if (xml.charCodeAt(i+1) === 47) { // </...
12311 if (w === 47) { // </...
12312 tagStart = false;
12313 tagEnd = true;
12314
12315 if (!nodeStack.length) {
12316 return handleError('missing open tag');
12317 }
12318
12319 // verify open <-> close tag match
12320 x = elementName = nodeStack.pop();
12321 q = i + 2 + x.length;
12322
12323 if (xml.substring(i + 2, q) !== x) {
12324 return handleError('closing tag mismatch');
12325 }
12326
12327 // verify chars in close tag
12328 for (; q < j; q++) {
12329 w = xml.charCodeAt(q);
12330
12331 if (w === 32 || (w > 8 && w < 14)) { // \f\n\r\t\v space
12332 continue;
12333 }
12334
12335 return handleError('close tag');
12336 }
12337
12338 } else {
12339 if (xml.charCodeAt(j - 1) === 47) { // .../>
12340 x = elementName = xml.substring(i + 1, j - 1);
12341
12342 tagStart = true;
12343 tagEnd = true;
12344
12345 } else {
12346 x = elementName = xml.substring(i + 1, j);
12347
12348 tagStart = true;
12349 tagEnd = false;
12350 }
12351
12352 if (!(w > 96 && w < 123 || w > 64 && w < 91 || w === 95 || w === 58)) { // char 95"_" 58":"
12353 return handleError('illegal first char nodeName');
12354 }
12355
12356 for (q = 1, y = x.length; q < y; q++) {
12357 w = x.charCodeAt(q);
12358
12359 if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w == 46) {
12360 continue;
12361 }
12362
12363 if (w === 32 || (w < 14 && w > 8)) { // \f\n\r\t\v space
12364 elementName = x.substring(0, q);
12365 // maybe there are attributes
12366 cachedAttrs = null;
12367 break;
12368 }
12369
12370 return handleError('invalid nodeName');
12371 }
12372
12373 if (!tagEnd) {
12374 nodeStack.push(elementName);
12375 }
12376 }
12377
12378 if (isNamespace) {
12379
12380 _nsMatrix = nsMatrix;
12381
12382 if (tagStart) {
12383 // remember old namespace
12384 // unless we're self-closing
12385 if (!tagEnd) {
12386 nsMatrixStack.push(_nsMatrix);
12387 }
12388
12389 if (cachedAttrs === null) {
12390 // quick check, whether there may be namespace
12391 // declarations on the node; if that is the case
12392 // we need to eagerly parse the node attributes
12393 if ((maybeNS = x.indexOf('xmlns', q) !== -1)) {
12394 attrsStart = q;
12395 attrsString = x;
12396
12397 getAttrs();
12398
12399 maybeNS = false;
12400 }
12401 }
12402 }
12403
12404 _elementName = elementName;
12405
12406 w = elementName.indexOf(':');
12407 if (w !== -1) {
12408 xmlns = nsMatrix[elementName.substring(0, w)];
12409
12410 // prefix given; namespace must exist
12411 if (!xmlns) {
12412 return handleError('missing namespace on <' + _elementName + '>');
12413 }
12414
12415 elementName = elementName.substr(w + 1);
12416 } else {
12417 xmlns = nsMatrix['xmlns'];
12418
12419 // if no default namespace is defined,
12420 // we'll import the element as anonymous.
12421 //
12422 // it is up to users to correct that to the document defined
12423 // targetNamespace, or whatever their undersanding of the
12424 // XML spec mandates.
12425 }
12426
12427 // adjust namespace prefixs as configured
12428 if (xmlns) {
12429 elementName = xmlns + ':' + elementName;
12430 }
12431
12432 }
12433
12434 if (tagStart) {
12435 attrsStart = q;
12436 attrsString = x;
12437
12438 if (onOpenTag) {
12439 if (proxy) {
12440 onOpenTag(elementProxy, decodeEntities, tagEnd, getContext);
12441 } else {
12442 onOpenTag(elementName, getAttrs, decodeEntities, tagEnd, getContext);
12443 }
12444
12445 if (parseStop) {
12446 return;
12447 }
12448 }
12449
12450 }
12451
12452 if (tagEnd) {
12453
12454 if (onCloseTag) {
12455 onCloseTag(proxy ? elementProxy : elementName, decodeEntities, tagStart, getContext);
12456
12457 if (parseStop) {
12458 return;
12459 }
12460 }
12461
12462 // restore old namespace
12463 if (isNamespace) {
12464 if (!tagStart) {
12465 nsMatrix = nsMatrixStack.pop();
12466 } else {
12467 nsMatrix = _nsMatrix;
12468 }
12469 }
12470 }
12471
12472 j += 1;
12473 }
12474 } /** end parse */
12475
12476 }
12477
12478 function hasLowerCaseAlias(pkg) {
12479 return pkg.xml && pkg.xml.tagAlias === 'lowerCase';
12480 }
12481
12482 var DEFAULT_NS_MAP = {
12483 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'
12484 };
12485
12486 var XSI_TYPE$1 = 'xsi:type';
12487
12488 function serializeFormat(element) {
12489 return element.xml && element.xml.serialize;
12490 }
12491
12492 function serializeAsType(element) {
12493 return serializeFormat(element) === XSI_TYPE$1;
12494 }
12495
12496 function serializeAsProperty(element) {
12497 return serializeFormat(element) === 'property';
12498 }
12499
12500 function capitalize(str) {
12501 return str.charAt(0).toUpperCase() + str.slice(1);
12502 }
12503
12504 function aliasToName(aliasNs, pkg) {
12505
12506 if (!hasLowerCaseAlias(pkg)) {
12507 return aliasNs.name;
12508 }
12509
12510 return aliasNs.prefix + ':' + capitalize(aliasNs.localName);
12511 }
12512
12513 function prefixedToName(nameNs, pkg) {
12514
12515 var name = nameNs.name,
12516 localName = nameNs.localName;
12517
12518 var typePrefix = pkg.xml && pkg.xml.typePrefix;
12519
12520 if (typePrefix && localName.indexOf(typePrefix) === 0) {
12521 return nameNs.prefix + ':' + localName.slice(typePrefix.length);
12522 } else {
12523 return name;
12524 }
12525 }
12526
12527 function normalizeXsiTypeName(name, model) {
12528
12529 var nameNs = parseName(name);
12530 var pkg = model.getPackage(nameNs.prefix);
12531
12532 return prefixedToName(nameNs, pkg);
12533 }
12534
12535 function error$1(message) {
12536 return new Error(message);
12537 }
12538
12539 /**
12540 * Get the moddle descriptor for a given instance or type.
12541 *
12542 * @param {ModdleElement|Function} element
12543 *
12544 * @return {Object} the moddle descriptor
12545 */
12546 function getModdleDescriptor(element) {
12547 return element.$descriptor;
12548 }
12549
12550 function defer(fn) {
12551 setTimeout(fn, 0);
12552 }
12553
12554 /**
12555 * A parse context.
12556 *
12557 * @class
12558 *
12559 * @param {Object} options
12560 * @param {ElementHandler} options.rootHandler the root handler for parsing a document
12561 * @param {boolean} [options.lax=false] whether or not to ignore invalid elements
12562 */
12563 function Context(options) {
12564
12565 /**
12566 * @property {ElementHandler} rootHandler
12567 */
12568
12569 /**
12570 * @property {Boolean} lax
12571 */
12572
12573 assign(this, options);
12574
12575 this.elementsById = {};
12576 this.references = [];
12577 this.warnings = [];
12578
12579 /**
12580 * Add an unresolved reference.
12581 *
12582 * @param {Object} reference
12583 */
12584 this.addReference = function(reference) {
12585 this.references.push(reference);
12586 };
12587
12588 /**
12589 * Add a processed element.
12590 *
12591 * @param {ModdleElement} element
12592 */
12593 this.addElement = function(element) {
12594
12595 if (!element) {
12596 throw error$1('expected element');
12597 }
12598
12599 var elementsById = this.elementsById;
12600
12601 var descriptor = getModdleDescriptor(element);
12602
12603 var idProperty = descriptor.idProperty,
12604 id;
12605
12606 if (idProperty) {
12607 id = element.get(idProperty.name);
12608
12609 if (id) {
12610 // for QName validation as per http://www.w3.org/TR/REC-xml/#NT-NameChar
12611 if (!/^([a-z][\w-.]*:)?[a-z_][\w-.]*$/i.test(id)) {
12612 throw new Error('illegal ID <' + id + '>');
12613 }
12614
12615 if (elementsById[id]) {
12616 throw error$1('duplicate ID <' + id + '>');
12617 }
12618
12619 elementsById[id] = element;
12620 }
12621 }
12622 };
12623
12624 /**
12625 * Add an import warning.
12626 *
12627 * @param {Object} warning
12628 * @param {String} warning.message
12629 * @param {Error} [warning.error]
12630 */
12631 this.addWarning = function(warning) {
12632 this.warnings.push(warning);
12633 };
12634 }
12635
12636 function BaseHandler() {}
12637
12638 BaseHandler.prototype.handleEnd = function() {};
12639 BaseHandler.prototype.handleText = function() {};
12640 BaseHandler.prototype.handleNode = function() {};
12641
12642
12643 /**
12644 * A simple pass through handler that does nothing except for
12645 * ignoring all input it receives.
12646 *
12647 * This is used to ignore unknown elements and
12648 * attributes.
12649 */
12650 function NoopHandler() { }
12651
12652 NoopHandler.prototype = Object.create(BaseHandler.prototype);
12653
12654 NoopHandler.prototype.handleNode = function() {
12655 return this;
12656 };
12657
12658 function BodyHandler() {}
12659
12660 BodyHandler.prototype = Object.create(BaseHandler.prototype);
12661
12662 BodyHandler.prototype.handleText = function(text) {
12663 this.body = (this.body || '') + text;
12664 };
12665
12666 function ReferenceHandler(property, context) {
12667 this.property = property;
12668 this.context = context;
12669 }
12670
12671 ReferenceHandler.prototype = Object.create(BodyHandler.prototype);
12672
12673 ReferenceHandler.prototype.handleNode = function(node) {
12674
12675 if (this.element) {
12676 throw error$1('expected no sub nodes');
12677 } else {
12678 this.element = this.createReference(node);
12679 }
12680
12681 return this;
12682 };
12683
12684 ReferenceHandler.prototype.handleEnd = function() {
12685 this.element.id = this.body;
12686 };
12687
12688 ReferenceHandler.prototype.createReference = function(node) {
12689 return {
12690 property: this.property.ns.name,
12691 id: ''
12692 };
12693 };
12694
12695 function ValueHandler(propertyDesc, element) {
12696 this.element = element;
12697 this.propertyDesc = propertyDesc;
12698 }
12699
12700 ValueHandler.prototype = Object.create(BodyHandler.prototype);
12701
12702 ValueHandler.prototype.handleEnd = function() {
12703
12704 var value = this.body || '',
12705 element = this.element,
12706 propertyDesc = this.propertyDesc;
12707
12708 value = coerceType(propertyDesc.type, value);
12709
12710 if (propertyDesc.isMany) {
12711 element.get(propertyDesc.name).push(value);
12712 } else {
12713 element.set(propertyDesc.name, value);
12714 }
12715 };
12716
12717
12718 function BaseElementHandler() {}
12719
12720 BaseElementHandler.prototype = Object.create(BodyHandler.prototype);
12721
12722 BaseElementHandler.prototype.handleNode = function(node) {
12723 var parser = this,
12724 element = this.element;
12725
12726 if (!element) {
12727 element = this.element = this.createElement(node);
12728
12729 this.context.addElement(element);
12730 } else {
12731 parser = this.handleChild(node);
12732 }
12733
12734 return parser;
12735 };
12736
12737 /**
12738 * @class Reader.ElementHandler
12739 *
12740 */
12741 function ElementHandler(model, typeName, context) {
12742 this.model = model;
12743 this.type = model.getType(typeName);
12744 this.context = context;
12745 }
12746
12747 ElementHandler.prototype = Object.create(BaseElementHandler.prototype);
12748
12749 ElementHandler.prototype.addReference = function(reference) {
12750 this.context.addReference(reference);
12751 };
12752
12753 ElementHandler.prototype.handleText = function(text) {
12754
12755 var element = this.element,
12756 descriptor = getModdleDescriptor(element),
12757 bodyProperty = descriptor.bodyProperty;
12758
12759 if (!bodyProperty) {
12760 throw error$1('unexpected body text <' + text + '>');
12761 }
12762
12763 BodyHandler.prototype.handleText.call(this, text);
12764 };
12765
12766 ElementHandler.prototype.handleEnd = function() {
12767
12768 var value = this.body,
12769 element = this.element,
12770 descriptor = getModdleDescriptor(element),
12771 bodyProperty = descriptor.bodyProperty;
12772
12773 if (bodyProperty && value !== undefined) {
12774 value = coerceType(bodyProperty.type, value);
12775 element.set(bodyProperty.name, value);
12776 }
12777 };
12778
12779 /**
12780 * Create an instance of the model from the given node.
12781 *
12782 * @param {Element} node the xml node
12783 */
12784 ElementHandler.prototype.createElement = function(node) {
12785 var attributes = node.attributes,
12786 Type = this.type,
12787 descriptor = getModdleDescriptor(Type),
12788 context = this.context,
12789 instance = new Type({}),
12790 model = this.model,
12791 propNameNs;
12792
12793 forEach(attributes, function(value, name) {
12794
12795 var prop = descriptor.propertiesByName[name],
12796 values;
12797
12798 if (prop && prop.isReference) {
12799
12800 if (!prop.isMany) {
12801 context.addReference({
12802 element: instance,
12803 property: prop.ns.name,
12804 id: value
12805 });
12806 } else {
12807 // IDREFS: parse references as whitespace-separated list
12808 values = value.split(' ');
12809
12810 forEach(values, function(v) {
12811 context.addReference({
12812 element: instance,
12813 property: prop.ns.name,
12814 id: v
12815 });
12816 });
12817 }
12818
12819 } else {
12820 if (prop) {
12821 value = coerceType(prop.type, value);
12822 } else
12823 if (name !== 'xmlns') {
12824 propNameNs = parseName(name, descriptor.ns.prefix);
12825
12826 // check whether attribute is defined in a well-known namespace
12827 // if that is the case we emit a warning to indicate potential misuse
12828 if (model.getPackage(propNameNs.prefix)) {
12829
12830 context.addWarning({
12831 message: 'unknown attribute <' + name + '>',
12832 element: instance,
12833 property: name,
12834 value: value
12835 });
12836 }
12837 }
12838
12839 instance.set(name, value);
12840 }
12841 });
12842
12843 return instance;
12844 };
12845
12846 ElementHandler.prototype.getPropertyForNode = function(node) {
12847
12848 var name = node.name;
12849 var nameNs = parseName(name);
12850
12851 var type = this.type,
12852 model = this.model,
12853 descriptor = getModdleDescriptor(type);
12854
12855 var propertyName = nameNs.name,
12856 property = descriptor.propertiesByName[propertyName],
12857 elementTypeName,
12858 elementType;
12859
12860 // search for properties by name first
12861
12862 if (property) {
12863
12864 if (serializeAsType(property)) {
12865 elementTypeName = node.attributes[XSI_TYPE$1];
12866
12867 // xsi type is optional, if it does not exists the
12868 // default type is assumed
12869 if (elementTypeName) {
12870
12871 // take possible type prefixes from XML
12872 // into account, i.e.: xsi:type="t{ActualType}"
12873 elementTypeName = normalizeXsiTypeName(elementTypeName, model);
12874
12875 elementType = model.getType(elementTypeName);
12876
12877 return assign({}, property, {
12878 effectiveType: getModdleDescriptor(elementType).name
12879 });
12880 }
12881 }
12882
12883 // search for properties by name first
12884 return property;
12885 }
12886
12887 var pkg = model.getPackage(nameNs.prefix);
12888
12889 if (pkg) {
12890 elementTypeName = aliasToName(nameNs, pkg);
12891 elementType = model.getType(elementTypeName);
12892
12893 // search for collection members later
12894 property = find(descriptor.properties, function(p) {
12895 return !p.isVirtual && !p.isReference && !p.isAttribute && elementType.hasType(p.type);
12896 });
12897
12898 if (property) {
12899 return assign({}, property, {
12900 effectiveType: getModdleDescriptor(elementType).name
12901 });
12902 }
12903 } else {
12904 // parse unknown element (maybe extension)
12905 property = find(descriptor.properties, function(p) {
12906 return !p.isReference && !p.isAttribute && p.type === 'Element';
12907 });
12908
12909 if (property) {
12910 return property;
12911 }
12912 }
12913
12914 throw error$1('unrecognized element <' + nameNs.name + '>');
12915 };
12916
12917 ElementHandler.prototype.toString = function() {
12918 return 'ElementDescriptor[' + getModdleDescriptor(this.type).name + ']';
12919 };
12920
12921 ElementHandler.prototype.valueHandler = function(propertyDesc, element) {
12922 return new ValueHandler(propertyDesc, element);
12923 };
12924
12925 ElementHandler.prototype.referenceHandler = function(propertyDesc) {
12926 return new ReferenceHandler(propertyDesc, this.context);
12927 };
12928
12929 ElementHandler.prototype.handler = function(type) {
12930 if (type === 'Element') {
12931 return new GenericElementHandler(this.model, type, this.context);
12932 } else {
12933 return new ElementHandler(this.model, type, this.context);
12934 }
12935 };
12936
12937 /**
12938 * Handle the child element parsing
12939 *
12940 * @param {Element} node the xml node
12941 */
12942 ElementHandler.prototype.handleChild = function(node) {
12943 var propertyDesc, type, element, childHandler;
12944
12945 propertyDesc = this.getPropertyForNode(node);
12946 element = this.element;
12947
12948 type = propertyDesc.effectiveType || propertyDesc.type;
12949
12950 if (isSimple(type)) {
12951 return this.valueHandler(propertyDesc, element);
12952 }
12953
12954 if (propertyDesc.isReference) {
12955 childHandler = this.referenceHandler(propertyDesc).handleNode(node);
12956 } else {
12957 childHandler = this.handler(type).handleNode(node);
12958 }
12959
12960 var newElement = childHandler.element;
12961
12962 // child handles may decide to skip elements
12963 // by not returning anything
12964 if (newElement !== undefined) {
12965
12966 if (propertyDesc.isMany) {
12967 element.get(propertyDesc.name).push(newElement);
12968 } else {
12969 element.set(propertyDesc.name, newElement);
12970 }
12971
12972 if (propertyDesc.isReference) {
12973 assign(newElement, {
12974 element: element
12975 });
12976
12977 this.context.addReference(newElement);
12978 } else {
12979 // establish child -> parent relationship
12980 newElement.$parent = element;
12981 }
12982 }
12983
12984 return childHandler;
12985 };
12986
12987 /**
12988 * An element handler that performs special validation
12989 * to ensure the node it gets initialized with matches
12990 * the handlers type (namespace wise).
12991 *
12992 * @param {Moddle} model
12993 * @param {String} typeName
12994 * @param {Context} context
12995 */
12996 function RootElementHandler(model, typeName, context) {
12997 ElementHandler.call(this, model, typeName, context);
12998 }
12999
13000 RootElementHandler.prototype = Object.create(ElementHandler.prototype);
13001
13002 RootElementHandler.prototype.createElement = function(node) {
13003
13004 var name = node.name,
13005 nameNs = parseName(name),
13006 model = this.model,
13007 type = this.type,
13008 pkg = model.getPackage(nameNs.prefix),
13009 typeName = pkg && aliasToName(nameNs, pkg) || name;
13010
13011 // verify the correct namespace if we parse
13012 // the first element in the handler tree
13013 //
13014 // this ensures we don't mistakenly import wrong namespace elements
13015 if (!type.hasType(typeName)) {
13016 throw error$1('unexpected element <' + node.originalName + '>');
13017 }
13018
13019 return ElementHandler.prototype.createElement.call(this, node);
13020 };
13021
13022
13023 function GenericElementHandler(model, typeName, context) {
13024 this.model = model;
13025 this.context = context;
13026 }
13027
13028 GenericElementHandler.prototype = Object.create(BaseElementHandler.prototype);
13029
13030 GenericElementHandler.prototype.createElement = function(node) {
13031
13032 var name = node.name,
13033 ns = parseName(name),
13034 prefix = ns.prefix,
13035 uri = node.ns[prefix + '$uri'],
13036 attributes = node.attributes;
13037
13038 return this.model.createAny(name, uri, attributes);
13039 };
13040
13041 GenericElementHandler.prototype.handleChild = function(node) {
13042
13043 var handler = new GenericElementHandler(this.model, 'Element', this.context).handleNode(node),
13044 element = this.element;
13045
13046 var newElement = handler.element,
13047 children;
13048
13049 if (newElement !== undefined) {
13050 children = element.$children = element.$children || [];
13051 children.push(newElement);
13052
13053 // establish child -> parent relationship
13054 newElement.$parent = element;
13055 }
13056
13057 return handler;
13058 };
13059
13060 GenericElementHandler.prototype.handleEnd = function() {
13061 if (this.body) {
13062 this.element.$body = this.body;
13063 }
13064 };
13065
13066 /**
13067 * A reader for a meta-model
13068 *
13069 * @param {Object} options
13070 * @param {Model} options.model used to read xml files
13071 * @param {Boolean} options.lax whether to make parse errors warnings
13072 */
13073 function Reader(options) {
13074
13075 if (options instanceof Moddle) {
13076 options = {
13077 model: options
13078 };
13079 }
13080
13081 assign(this, { lax: false }, options);
13082 }
13083
13084
13085 /**
13086 * Parse the given XML into a moddle document tree.
13087 *
13088 * @param {String} xml
13089 * @param {ElementHandler|Object} options or rootHandler
13090 * @param {Function} done
13091 */
13092 Reader.prototype.fromXML = function(xml, options, done) {
13093
13094 var rootHandler = options.rootHandler;
13095
13096 if (options instanceof ElementHandler) {
13097 // root handler passed via (xml, { rootHandler: ElementHandler }, ...)
13098 rootHandler = options;
13099 options = {};
13100 } else {
13101 if (typeof options === 'string') {
13102 // rootHandler passed via (xml, 'someString', ...)
13103 rootHandler = this.handler(options);
13104 options = {};
13105 } else if (typeof rootHandler === 'string') {
13106 // rootHandler passed via (xml, { rootHandler: 'someString' }, ...)
13107 rootHandler = this.handler(rootHandler);
13108 }
13109 }
13110
13111 var model = this.model,
13112 lax = this.lax;
13113
13114 var context = new Context(assign({}, options, { rootHandler: rootHandler })),
13115 parser = new Parser({ proxy: true }),
13116 stack = createStack();
13117
13118 rootHandler.context = context;
13119
13120 // push root handler
13121 stack.push(rootHandler);
13122
13123
13124 /**
13125 * Handle error.
13126 *
13127 * @param {Error} err
13128 * @param {Function} getContext
13129 * @param {boolean} lax
13130 *
13131 * @return {boolean} true if handled
13132 */
13133 function handleError(err, getContext, lax) {
13134
13135 var ctx = getContext();
13136
13137 var line = ctx.line,
13138 column = ctx.column,
13139 data = ctx.data;
13140
13141 // we receive the full context data here,
13142 // for elements trim down the information
13143 // to the tag name, only
13144 if (data.charAt(0) === '<' && data.indexOf(' ') !== -1) {
13145 data = data.slice(0, data.indexOf(' ')) + '>';
13146 }
13147
13148 var message =
13149 'unparsable content ' + (data ? data + ' ' : '') + 'detected\n\t' +
13150 'line: ' + line + '\n\t' +
13151 'column: ' + column + '\n\t' +
13152 'nested error: ' + err.message;
13153
13154 if (lax) {
13155 context.addWarning({
13156 message: message,
13157 error: err
13158 });
13159
13160 return true;
13161 } else {
13162 throw error$1(message);
13163 }
13164 }
13165
13166 function handleWarning(err, getContext) {
13167 // just like handling errors in <lax=true> mode
13168 return handleError(err, getContext, true);
13169 }
13170
13171 /**
13172 * Resolve collected references on parse end.
13173 */
13174 function resolveReferences() {
13175
13176 var elementsById = context.elementsById;
13177 var references = context.references;
13178
13179 var i, r;
13180
13181 for (i = 0; (r = references[i]); i++) {
13182 var element = r.element;
13183 var reference = elementsById[r.id];
13184 var property = getModdleDescriptor(element).propertiesByName[r.property];
13185
13186 if (!reference) {
13187 context.addWarning({
13188 message: 'unresolved reference <' + r.id + '>',
13189 element: r.element,
13190 property: r.property,
13191 value: r.id
13192 });
13193 }
13194
13195 if (property.isMany) {
13196 var collection = element.get(property.name),
13197 idx = collection.indexOf(r);
13198
13199 // we replace an existing place holder (idx != -1) or
13200 // append to the collection instead
13201 if (idx === -1) {
13202 idx = collection.length;
13203 }
13204
13205 if (!reference) {
13206 // remove unresolvable reference
13207 collection.splice(idx, 1);
13208 } else {
13209 // add or update reference in collection
13210 collection[idx] = reference;
13211 }
13212 } else {
13213 element.set(property.name, reference);
13214 }
13215 }
13216 }
13217
13218 function handleClose() {
13219 stack.pop().handleEnd();
13220 }
13221
13222 var PREAMBLE_START_PATTERN = /^<\?xml /i;
13223
13224 var ENCODING_PATTERN = / encoding="([^"]+)"/i;
13225
13226 var UTF_8_PATTERN = /^utf-8$/i;
13227
13228 function handleQuestion(question) {
13229
13230 if (!PREAMBLE_START_PATTERN.test(question)) {
13231 return;
13232 }
13233
13234 var match = ENCODING_PATTERN.exec(question);
13235 var encoding = match && match[1];
13236
13237 if (!encoding || UTF_8_PATTERN.test(encoding)) {
13238 return;
13239 }
13240
13241 context.addWarning({
13242 message:
13243 'unsupported document encoding <' + encoding + '>, ' +
13244 'falling back to UTF-8'
13245 });
13246 }
13247
13248 function handleOpen(node, getContext) {
13249 var handler = stack.peek();
13250
13251 try {
13252 stack.push(handler.handleNode(node));
13253 } catch (err) {
13254
13255 if (handleError(err, getContext, lax)) {
13256 stack.push(new NoopHandler());
13257 }
13258 }
13259 }
13260
13261 function handleCData(text, getContext) {
13262
13263 try {
13264 stack.peek().handleText(text);
13265 } catch (err) {
13266 handleWarning(err, getContext);
13267 }
13268 }
13269
13270 function handleText(text, getContext) {
13271 // strip whitespace only nodes, i.e. before
13272 // <!CDATA[ ... ]> sections and in between tags
13273 text = text.trim();
13274
13275 if (!text) {
13276 return;
13277 }
13278
13279 handleCData(text, getContext);
13280 }
13281
13282 var uriMap = model.getPackages().reduce(function(uriMap, p) {
13283 uriMap[p.uri] = p.prefix;
13284
13285 return uriMap;
13286 }, {});
13287
13288 parser
13289 .ns(uriMap)
13290 .on('openTag', function(obj, decodeStr, selfClosing, getContext) {
13291
13292 // gracefully handle unparsable attributes (attrs=false)
13293 var attrs = obj.attrs || {};
13294
13295 var decodedAttrs = Object.keys(attrs).reduce(function(d, key) {
13296 var value = decodeStr(attrs[key]);
13297
13298 d[key] = value;
13299
13300 return d;
13301 }, {});
13302
13303 var node = {
13304 name: obj.name,
13305 originalName: obj.originalName,
13306 attributes: decodedAttrs,
13307 ns: obj.ns
13308 };
13309
13310 handleOpen(node, getContext);
13311 })
13312 .on('question', handleQuestion)
13313 .on('closeTag', handleClose)
13314 .on('cdata', handleCData)
13315 .on('text', function(text, decodeEntities, getContext) {
13316 handleText(decodeEntities(text), getContext);
13317 })
13318 .on('error', handleError)
13319 .on('warn', handleWarning);
13320
13321 // deferred parse XML to make loading really ascnchronous
13322 // this ensures the execution environment (node or browser)
13323 // is kept responsive and that certain optimization strategies
13324 // can kick in
13325 defer(function() {
13326 var err;
13327
13328 try {
13329 parser.parse(xml);
13330
13331 resolveReferences();
13332 } catch (e) {
13333 err = e;
13334 }
13335
13336 var element = rootHandler.element;
13337
13338 // handle the situation that we could not extract
13339 // the desired root element from the document
13340 if (!err && !element) {
13341 err = error$1('failed to parse document as <' + rootHandler.type.$descriptor.name + '>');
13342 }
13343
13344 done(err, err ? undefined : element, context);
13345 });
13346 };
13347
13348 Reader.prototype.handler = function(name) {
13349 return new RootElementHandler(this.model, name);
13350 };
13351
13352
13353 // helpers //////////////////////////
13354
13355 function createStack() {
13356 var stack = [];
13357
13358 Object.defineProperty(stack, 'peek', {
13359 value: function() {
13360 return this[this.length - 1];
13361 }
13362 });
13363
13364 return stack;
13365 }
13366
13367 var XML_PREAMBLE = '<?xml version="1.0" encoding="UTF-8"?>\n';
13368
13369 var ESCAPE_ATTR_CHARS = /<|>|'|"|&|\n\r|\n/g;
13370 var ESCAPE_CHARS = /<|>|&/g;
13371
13372
13373 function Namespaces(parent) {
13374
13375 var prefixMap = {};
13376 var uriMap = {};
13377 var used = {};
13378
13379 var wellknown = [];
13380 var custom = [];
13381
13382 // API
13383
13384 this.byUri = function(uri) {
13385 return uriMap[uri] || (
13386 parent && parent.byUri(uri)
13387 );
13388 };
13389
13390 this.add = function(ns, isWellknown) {
13391
13392 uriMap[ns.uri] = ns;
13393
13394 if (isWellknown) {
13395 wellknown.push(ns);
13396 } else {
13397 custom.push(ns);
13398 }
13399
13400 this.mapPrefix(ns.prefix, ns.uri);
13401 };
13402
13403 this.uriByPrefix = function(prefix) {
13404 return prefixMap[prefix || 'xmlns'];
13405 };
13406
13407 this.mapPrefix = function(prefix, uri) {
13408 prefixMap[prefix || 'xmlns'] = uri;
13409 };
13410
13411 this.logUsed = function(ns) {
13412 var uri = ns.uri;
13413
13414 used[uri] = this.byUri(uri);
13415 };
13416
13417 this.getUsed = function(ns) {
13418
13419 function isUsed(ns) {
13420 return used[ns.uri];
13421 }
13422
13423 var allNs = [].concat(wellknown, custom);
13424
13425 return allNs.filter(isUsed);
13426 };
13427
13428 }
13429
13430 function lower(string) {
13431 return string.charAt(0).toLowerCase() + string.slice(1);
13432 }
13433
13434 function nameToAlias(name, pkg) {
13435 if (hasLowerCaseAlias(pkg)) {
13436 return lower(name);
13437 } else {
13438 return name;
13439 }
13440 }
13441
13442 function inherits(ctor, superCtor) {
13443 ctor.super_ = superCtor;
13444 ctor.prototype = Object.create(superCtor.prototype, {
13445 constructor: {
13446 value: ctor,
13447 enumerable: false,
13448 writable: true,
13449 configurable: true
13450 }
13451 });
13452 }
13453
13454 function nsName(ns) {
13455 if (isString(ns)) {
13456 return ns;
13457 } else {
13458 return (ns.prefix ? ns.prefix + ':' : '') + ns.localName;
13459 }
13460 }
13461
13462 function getNsAttrs(namespaces) {
13463
13464 return map(namespaces.getUsed(), function(ns) {
13465 var name = 'xmlns' + (ns.prefix ? ':' + ns.prefix : '');
13466 return { name: name, value: ns.uri };
13467 });
13468
13469 }
13470
13471 function getElementNs(ns, descriptor) {
13472 if (descriptor.isGeneric) {
13473 return assign({ localName: descriptor.ns.localName }, ns);
13474 } else {
13475 return assign({ localName: nameToAlias(descriptor.ns.localName, descriptor.$pkg) }, ns);
13476 }
13477 }
13478
13479 function getPropertyNs(ns, descriptor) {
13480 return assign({ localName: descriptor.ns.localName }, ns);
13481 }
13482
13483 function getSerializableProperties(element) {
13484 var descriptor = element.$descriptor;
13485
13486 return filter(descriptor.properties, function(p) {
13487 var name = p.name;
13488
13489 if (p.isVirtual) {
13490 return false;
13491 }
13492
13493 // do not serialize defaults
13494 if (!element.hasOwnProperty(name)) {
13495 return false;
13496 }
13497
13498 var value = element[name];
13499
13500 // do not serialize default equals
13501 if (value === p.default) {
13502 return false;
13503 }
13504
13505 // do not serialize null properties
13506 if (value === null) {
13507 return false;
13508 }
13509
13510 return p.isMany ? value.length : true;
13511 });
13512 }
13513
13514 var ESCAPE_ATTR_MAP = {
13515 '\n': '#10',
13516 '\n\r': '#10',
13517 '"': '#34',
13518 '\'': '#39',
13519 '<': '#60',
13520 '>': '#62',
13521 '&': '#38'
13522 };
13523
13524 var ESCAPE_MAP = {
13525 '<': 'lt',
13526 '>': 'gt',
13527 '&': 'amp'
13528 };
13529
13530 function escape$1(str, charPattern, replaceMap) {
13531
13532 // ensure we are handling strings here
13533 str = isString(str) ? str : '' + str;
13534
13535 return str.replace(charPattern, function(s) {
13536 return '&' + replaceMap[s] + ';';
13537 });
13538 }
13539
13540 /**
13541 * Escape a string attribute to not contain any bad values (line breaks, '"', ...)
13542 *
13543 * @param {String} str the string to escape
13544 * @return {String} the escaped string
13545 */
13546 function escapeAttr(str) {
13547 return escape$1(str, ESCAPE_ATTR_CHARS, ESCAPE_ATTR_MAP);
13548 }
13549
13550 function escapeBody(str) {
13551 return escape$1(str, ESCAPE_CHARS, ESCAPE_MAP);
13552 }
13553
13554 function filterAttributes(props) {
13555 return filter(props, function(p) { return p.isAttr; });
13556 }
13557
13558 function filterContained(props) {
13559 return filter(props, function(p) { return !p.isAttr; });
13560 }
13561
13562
13563 function ReferenceSerializer(tagName) {
13564 this.tagName = tagName;
13565 }
13566
13567 ReferenceSerializer.prototype.build = function(element) {
13568 this.element = element;
13569 return this;
13570 };
13571
13572 ReferenceSerializer.prototype.serializeTo = function(writer) {
13573 writer
13574 .appendIndent()
13575 .append('<' + this.tagName + '>' + this.element.id + '</' + this.tagName + '>')
13576 .appendNewLine();
13577 };
13578
13579 function BodySerializer() {}
13580
13581 BodySerializer.prototype.serializeValue =
13582 BodySerializer.prototype.serializeTo = function(writer) {
13583 writer.append(
13584 this.escape
13585 ? escapeBody(this.value)
13586 : this.value
13587 );
13588 };
13589
13590 BodySerializer.prototype.build = function(prop, value) {
13591 this.value = value;
13592
13593 if (prop.type === 'String' && value.search(ESCAPE_CHARS) !== -1) {
13594 this.escape = true;
13595 }
13596
13597 return this;
13598 };
13599
13600 function ValueSerializer(tagName) {
13601 this.tagName = tagName;
13602 }
13603
13604 inherits(ValueSerializer, BodySerializer);
13605
13606 ValueSerializer.prototype.serializeTo = function(writer) {
13607
13608 writer
13609 .appendIndent()
13610 .append('<' + this.tagName + '>');
13611
13612 this.serializeValue(writer);
13613
13614 writer
13615 .append('</' + this.tagName + '>')
13616 .appendNewLine();
13617 };
13618
13619 function ElementSerializer(parent, propertyDescriptor) {
13620 this.body = [];
13621 this.attrs = [];
13622
13623 this.parent = parent;
13624 this.propertyDescriptor = propertyDescriptor;
13625 }
13626
13627 ElementSerializer.prototype.build = function(element) {
13628 this.element = element;
13629
13630 var elementDescriptor = element.$descriptor,
13631 propertyDescriptor = this.propertyDescriptor;
13632
13633 var otherAttrs,
13634 properties;
13635
13636 var isGeneric = elementDescriptor.isGeneric;
13637
13638 if (isGeneric) {
13639 otherAttrs = this.parseGeneric(element);
13640 } else {
13641 otherAttrs = this.parseNsAttributes(element);
13642 }
13643
13644 if (propertyDescriptor) {
13645 this.ns = this.nsPropertyTagName(propertyDescriptor);
13646 } else {
13647 this.ns = this.nsTagName(elementDescriptor);
13648 }
13649
13650 // compute tag name
13651 this.tagName = this.addTagName(this.ns);
13652
13653 if (!isGeneric) {
13654 properties = getSerializableProperties(element);
13655
13656 this.parseAttributes(filterAttributes(properties));
13657 this.parseContainments(filterContained(properties));
13658 }
13659
13660 this.parseGenericAttributes(element, otherAttrs);
13661
13662 return this;
13663 };
13664
13665 ElementSerializer.prototype.nsTagName = function(descriptor) {
13666 var effectiveNs = this.logNamespaceUsed(descriptor.ns);
13667 return getElementNs(effectiveNs, descriptor);
13668 };
13669
13670 ElementSerializer.prototype.nsPropertyTagName = function(descriptor) {
13671 var effectiveNs = this.logNamespaceUsed(descriptor.ns);
13672 return getPropertyNs(effectiveNs, descriptor);
13673 };
13674
13675 ElementSerializer.prototype.isLocalNs = function(ns) {
13676 return ns.uri === this.ns.uri;
13677 };
13678
13679 /**
13680 * Get the actual ns attribute name for the given element.
13681 *
13682 * @param {Object} element
13683 * @param {Boolean} [element.inherited=false]
13684 *
13685 * @return {Object} nsName
13686 */
13687 ElementSerializer.prototype.nsAttributeName = function(element) {
13688
13689 var ns;
13690
13691 if (isString(element)) {
13692 ns = parseName(element);
13693 } else {
13694 ns = element.ns;
13695 }
13696
13697 // return just local name for inherited attributes
13698 if (element.inherited) {
13699 return { localName: ns.localName };
13700 }
13701
13702 // parse + log effective ns
13703 var effectiveNs = this.logNamespaceUsed(ns);
13704
13705 // LOG ACTUAL namespace use
13706 this.getNamespaces().logUsed(effectiveNs);
13707
13708 // strip prefix if same namespace like parent
13709 if (this.isLocalNs(effectiveNs)) {
13710 return { localName: ns.localName };
13711 } else {
13712 return assign({ localName: ns.localName }, effectiveNs);
13713 }
13714 };
13715
13716 ElementSerializer.prototype.parseGeneric = function(element) {
13717
13718 var self = this,
13719 body = this.body;
13720
13721 var attributes = [];
13722
13723 forEach(element, function(val, key) {
13724
13725 var nonNsAttr;
13726
13727 if (key === '$body') {
13728 body.push(new BodySerializer().build({ type: 'String' }, val));
13729 } else
13730 if (key === '$children') {
13731 forEach(val, function(child) {
13732 body.push(new ElementSerializer(self).build(child));
13733 });
13734 } else
13735 if (key.indexOf('$') !== 0) {
13736 nonNsAttr = self.parseNsAttribute(element, key, val);
13737
13738 if (nonNsAttr) {
13739 attributes.push({ name: key, value: val });
13740 }
13741 }
13742 });
13743
13744 return attributes;
13745 };
13746
13747 ElementSerializer.prototype.parseNsAttribute = function(element, name, value) {
13748 var model = element.$model;
13749
13750 var nameNs = parseName(name);
13751
13752 var ns;
13753
13754 // parse xmlns:foo="http://foo.bar"
13755 if (nameNs.prefix === 'xmlns') {
13756 ns = { prefix: nameNs.localName, uri: value };
13757 }
13758
13759 // parse xmlns="http://foo.bar"
13760 if (!nameNs.prefix && nameNs.localName === 'xmlns') {
13761 ns = { uri: value };
13762 }
13763
13764 if (!ns) {
13765 return {
13766 name: name,
13767 value: value
13768 };
13769 }
13770
13771 if (model && model.getPackage(value)) {
13772 // register well known namespace
13773 this.logNamespace(ns, true, true);
13774 } else {
13775 // log custom namespace directly as used
13776 var actualNs = this.logNamespaceUsed(ns, true);
13777
13778 this.getNamespaces().logUsed(actualNs);
13779 }
13780 };
13781
13782
13783 /**
13784 * Parse namespaces and return a list of left over generic attributes
13785 *
13786 * @param {Object} element
13787 * @return {Array<Object>}
13788 */
13789 ElementSerializer.prototype.parseNsAttributes = function(element, attrs) {
13790 var self = this;
13791
13792 var genericAttrs = element.$attrs;
13793
13794 var attributes = [];
13795
13796 // parse namespace attributes first
13797 // and log them. push non namespace attributes to a list
13798 // and process them later
13799 forEach(genericAttrs, function(value, name) {
13800
13801 var nonNsAttr = self.parseNsAttribute(element, name, value);
13802
13803 if (nonNsAttr) {
13804 attributes.push(nonNsAttr);
13805 }
13806 });
13807
13808 return attributes;
13809 };
13810
13811 ElementSerializer.prototype.parseGenericAttributes = function(element, attributes) {
13812
13813 var self = this;
13814
13815 forEach(attributes, function(attr) {
13816
13817 // do not serialize xsi:type attribute
13818 // it is set manually based on the actual implementation type
13819 if (attr.name === XSI_TYPE$1) {
13820 return;
13821 }
13822
13823 try {
13824 self.addAttribute(self.nsAttributeName(attr.name), attr.value);
13825 } catch (e) {
13826 console.warn(
13827 'missing namespace information for ',
13828 attr.name, '=', attr.value, 'on', element,
13829 e);
13830 }
13831 });
13832 };
13833
13834 ElementSerializer.prototype.parseContainments = function(properties) {
13835
13836 var self = this,
13837 body = this.body,
13838 element = this.element;
13839
13840 forEach(properties, function(p) {
13841 var value = element.get(p.name),
13842 isReference = p.isReference,
13843 isMany = p.isMany;
13844
13845 if (!isMany) {
13846 value = [ value ];
13847 }
13848
13849 if (p.isBody) {
13850 body.push(new BodySerializer().build(p, value[0]));
13851 } else
13852 if (isSimple(p.type)) {
13853 forEach(value, function(v) {
13854 body.push(new ValueSerializer(self.addTagName(self.nsPropertyTagName(p))).build(p, v));
13855 });
13856 } else
13857 if (isReference) {
13858 forEach(value, function(v) {
13859 body.push(new ReferenceSerializer(self.addTagName(self.nsPropertyTagName(p))).build(v));
13860 });
13861 } else {
13862 // allow serialization via type
13863 // rather than element name
13864 var asType = serializeAsType(p),
13865 asProperty = serializeAsProperty(p);
13866
13867 forEach(value, function(v) {
13868 var serializer;
13869
13870 if (asType) {
13871 serializer = new TypeSerializer(self, p);
13872 } else
13873 if (asProperty) {
13874 serializer = new ElementSerializer(self, p);
13875 } else {
13876 serializer = new ElementSerializer(self);
13877 }
13878
13879 body.push(serializer.build(v));
13880 });
13881 }
13882 });
13883 };
13884
13885 ElementSerializer.prototype.getNamespaces = function(local) {
13886
13887 var namespaces = this.namespaces,
13888 parent = this.parent,
13889 parentNamespaces;
13890
13891 if (!namespaces) {
13892 parentNamespaces = parent && parent.getNamespaces();
13893
13894 if (local || !parentNamespaces) {
13895 this.namespaces = namespaces = new Namespaces(parentNamespaces);
13896 } else {
13897 namespaces = parentNamespaces;
13898 }
13899 }
13900
13901 return namespaces;
13902 };
13903
13904 ElementSerializer.prototype.logNamespace = function(ns, wellknown, local) {
13905 var namespaces = this.getNamespaces(local);
13906
13907 var nsUri = ns.uri,
13908 nsPrefix = ns.prefix;
13909
13910 var existing = namespaces.byUri(nsUri);
13911
13912 if (!existing) {
13913 namespaces.add(ns, wellknown);
13914 }
13915
13916 namespaces.mapPrefix(nsPrefix, nsUri);
13917
13918 return ns;
13919 };
13920
13921 ElementSerializer.prototype.logNamespaceUsed = function(ns, local) {
13922 var element = this.element,
13923 model = element.$model,
13924 namespaces = this.getNamespaces(local);
13925
13926 // ns may be
13927 //
13928 // * prefix only
13929 // * prefix:uri
13930 // * localName only
13931
13932 var prefix = ns.prefix,
13933 uri = ns.uri,
13934 newPrefix, idx,
13935 wellknownUri;
13936
13937 // handle anonymous namespaces (elementForm=unqualified), cf. #23
13938 if (!prefix && !uri) {
13939 return { localName: ns.localName };
13940 }
13941
13942 wellknownUri = DEFAULT_NS_MAP[prefix] || model && (model.getPackage(prefix) || {}).uri;
13943
13944 uri = uri || wellknownUri || namespaces.uriByPrefix(prefix);
13945
13946 if (!uri) {
13947 throw new Error('no namespace uri given for prefix <' + prefix + '>');
13948 }
13949
13950 ns = namespaces.byUri(uri);
13951
13952 if (!ns) {
13953 newPrefix = prefix;
13954 idx = 1;
13955
13956 // find a prefix that is not mapped yet
13957 while (namespaces.uriByPrefix(newPrefix)) {
13958 newPrefix = prefix + '_' + idx++;
13959 }
13960
13961 ns = this.logNamespace({ prefix: newPrefix, uri: uri }, wellknownUri === uri);
13962 }
13963
13964 if (prefix) {
13965 namespaces.mapPrefix(prefix, uri);
13966 }
13967
13968 return ns;
13969 };
13970
13971 ElementSerializer.prototype.parseAttributes = function(properties) {
13972 var self = this,
13973 element = this.element;
13974
13975 forEach(properties, function(p) {
13976
13977 var value = element.get(p.name);
13978
13979 if (p.isReference) {
13980
13981 if (!p.isMany) {
13982 value = value.id;
13983 }
13984 else {
13985 var values = [];
13986 forEach(value, function(v) {
13987 values.push(v.id);
13988 });
13989 // IDREFS is a whitespace-separated list of references.
13990 value = values.join(' ');
13991 }
13992
13993 }
13994
13995 self.addAttribute(self.nsAttributeName(p), value);
13996 });
13997 };
13998
13999 ElementSerializer.prototype.addTagName = function(nsTagName) {
14000 var actualNs = this.logNamespaceUsed(nsTagName);
14001
14002 this.getNamespaces().logUsed(actualNs);
14003
14004 return nsName(nsTagName);
14005 };
14006
14007 ElementSerializer.prototype.addAttribute = function(name, value) {
14008 var attrs = this.attrs;
14009
14010 if (isString(value)) {
14011 value = escapeAttr(value);
14012 }
14013
14014 attrs.push({ name: name, value: value });
14015 };
14016
14017 ElementSerializer.prototype.serializeAttributes = function(writer) {
14018 var attrs = this.attrs,
14019 namespaces = this.namespaces;
14020
14021 if (namespaces) {
14022 attrs = getNsAttrs(namespaces).concat(attrs);
14023 }
14024
14025 forEach(attrs, function(a) {
14026 writer
14027 .append(' ')
14028 .append(nsName(a.name)).append('="').append(a.value).append('"');
14029 });
14030 };
14031
14032 ElementSerializer.prototype.serializeTo = function(writer) {
14033 var firstBody = this.body[0],
14034 indent = firstBody && firstBody.constructor !== BodySerializer;
14035
14036 writer
14037 .appendIndent()
14038 .append('<' + this.tagName);
14039
14040 this.serializeAttributes(writer);
14041
14042 writer.append(firstBody ? '>' : ' />');
14043
14044 if (firstBody) {
14045
14046 if (indent) {
14047 writer
14048 .appendNewLine()
14049 .indent();
14050 }
14051
14052 forEach(this.body, function(b) {
14053 b.serializeTo(writer);
14054 });
14055
14056 if (indent) {
14057 writer
14058 .unindent()
14059 .appendIndent();
14060 }
14061
14062 writer.append('</' + this.tagName + '>');
14063 }
14064
14065 writer.appendNewLine();
14066 };
14067
14068 /**
14069 * A serializer for types that handles serialization of data types
14070 */
14071 function TypeSerializer(parent, propertyDescriptor) {
14072 ElementSerializer.call(this, parent, propertyDescriptor);
14073 }
14074
14075 inherits(TypeSerializer, ElementSerializer);
14076
14077 TypeSerializer.prototype.parseNsAttributes = function(element) {
14078
14079 // extracted attributes
14080 var attributes = ElementSerializer.prototype.parseNsAttributes.call(this, element);
14081
14082 var descriptor = element.$descriptor;
14083
14084 // only serialize xsi:type if necessary
14085 if (descriptor.name === this.propertyDescriptor.type) {
14086 return attributes;
14087 }
14088
14089 var typeNs = this.typeNs = this.nsTagName(descriptor);
14090 this.getNamespaces().logUsed(this.typeNs);
14091
14092 // add xsi:type attribute to represent the elements
14093 // actual type
14094
14095 var pkg = element.$model.getPackage(typeNs.uri),
14096 typePrefix = (pkg.xml && pkg.xml.typePrefix) || '';
14097
14098 this.addAttribute(
14099 this.nsAttributeName(XSI_TYPE$1),
14100 (typeNs.prefix ? typeNs.prefix + ':' : '') + typePrefix + descriptor.ns.localName
14101 );
14102
14103 return attributes;
14104 };
14105
14106 TypeSerializer.prototype.isLocalNs = function(ns) {
14107 return ns.uri === (this.typeNs || this.ns).uri;
14108 };
14109
14110 function SavingWriter() {
14111 this.value = '';
14112
14113 this.write = function(str) {
14114 this.value += str;
14115 };
14116 }
14117
14118 function FormatingWriter(out, format) {
14119
14120 var indent = [''];
14121
14122 this.append = function(str) {
14123 out.write(str);
14124
14125 return this;
14126 };
14127
14128 this.appendNewLine = function() {
14129 if (format) {
14130 out.write('\n');
14131 }
14132
14133 return this;
14134 };
14135
14136 this.appendIndent = function() {
14137 if (format) {
14138 out.write(indent.join(' '));
14139 }
14140
14141 return this;
14142 };
14143
14144 this.indent = function() {
14145 indent.push('');
14146 return this;
14147 };
14148
14149 this.unindent = function() {
14150 indent.pop();
14151 return this;
14152 };
14153 }
14154
14155 /**
14156 * A writer for meta-model backed document trees
14157 *
14158 * @param {Object} options output options to pass into the writer
14159 */
14160 function Writer(options) {
14161
14162 options = assign({ format: false, preamble: true }, options || {});
14163
14164 function toXML(tree, writer) {
14165 var internalWriter = writer || new SavingWriter();
14166 var formatingWriter = new FormatingWriter(internalWriter, options.format);
14167
14168 if (options.preamble) {
14169 formatingWriter.append(XML_PREAMBLE);
14170 }
14171
14172 new ElementSerializer().build(tree).serializeTo(formatingWriter);
14173
14174 if (!writer) {
14175 return internalWriter.value;
14176 }
14177 }
14178
14179 return {
14180 toXML: toXML
14181 };
14182 }
14183
14184 /**
14185 * A sub class of {@link Moddle} with support for import and export of BPMN 2.0 xml files.
14186 *
14187 * @class BpmnModdle
14188 * @extends Moddle
14189 *
14190 * @param {Object|Array} packages to use for instantiating the model
14191 * @param {Object} [options] additional options to pass over
14192 */
14193 function BpmnModdle(packages, options) {
14194 Moddle.call(this, packages, options);
14195 }
14196
14197 BpmnModdle.prototype = Object.create(Moddle.prototype);
14198
14199
14200 /**
14201 * Instantiates a BPMN model tree from a given xml string.
14202 *
14203 * @param {String} xmlStr
14204 * @param {String} [typeName='bpmn:Definitions'] name of the root element
14205 * @param {Object} [options] options to pass to the underlying reader
14206 * @param {Function} done callback that is invoked with (err, result, parseContext)
14207 * once the import completes
14208 */
14209 BpmnModdle.prototype.fromXML = function(xmlStr, typeName, options, done) {
14210
14211 if (!isString(typeName)) {
14212 done = options;
14213 options = typeName;
14214 typeName = 'bpmn:Definitions';
14215 }
14216
14217 if (isFunction(options)) {
14218 done = options;
14219 options = {};
14220 }
14221
14222 var reader = new Reader(assign({ model: this, lax: true }, options));
14223 var rootHandler = reader.handler(typeName);
14224
14225 reader.fromXML(xmlStr, rootHandler, done);
14226 };
14227
14228
14229 /**
14230 * Serializes a BPMN 2.0 object tree to XML.
14231 *
14232 * @param {String} element the root element, typically an instance of `bpmn:Definitions`
14233 * @param {Object} [options] to pass to the underlying writer
14234 * @param {Function} done callback invoked with (err, xmlStr) once the import completes
14235 */
14236 BpmnModdle.prototype.toXML = function(element, options, done) {
14237
14238 if (isFunction(options)) {
14239 done = options;
14240 options = {};
14241 }
14242
14243 var writer = new Writer(options);
14244
14245 var result;
14246 var err;
14247
14248 try {
14249 result = writer.toXML(element);
14250 } catch (e) {
14251 err = e;
14252 }
14253
14254 return done(err, result);
14255 };
14256
14257 var name = "BPMN20";
14258 var uri = "http://www.omg.org/spec/BPMN/20100524/MODEL";
14259 var associations = [
14260 ];
14261 var types$1 = [
14262 {
14263 name: "Interface",
14264 superClass: [
14265 "RootElement"
14266 ],
14267 properties: [
14268 {
14269 name: "name",
14270 isAttr: true,
14271 type: "String"
14272 },
14273 {
14274 name: "operations",
14275 type: "Operation",
14276 isMany: true
14277 },
14278 {
14279 name: "implementationRef",
14280 type: "String",
14281 isAttr: true
14282 }
14283 ]
14284 },
14285 {
14286 name: "Operation",
14287 superClass: [
14288 "BaseElement"
14289 ],
14290 properties: [
14291 {
14292 name: "name",
14293 isAttr: true,
14294 type: "String"
14295 },
14296 {
14297 name: "inMessageRef",
14298 type: "Message",
14299 isReference: true
14300 },
14301 {
14302 name: "outMessageRef",
14303 type: "Message",
14304 isReference: true
14305 },
14306 {
14307 name: "errorRef",
14308 type: "Error",
14309 isMany: true,
14310 isReference: true
14311 },
14312 {
14313 name: "implementationRef",
14314 type: "String",
14315 isAttr: true
14316 }
14317 ]
14318 },
14319 {
14320 name: "EndPoint",
14321 superClass: [
14322 "RootElement"
14323 ]
14324 },
14325 {
14326 name: "Auditing",
14327 superClass: [
14328 "BaseElement"
14329 ]
14330 },
14331 {
14332 name: "GlobalTask",
14333 superClass: [
14334 "CallableElement"
14335 ],
14336 properties: [
14337 {
14338 name: "resources",
14339 type: "ResourceRole",
14340 isMany: true
14341 }
14342 ]
14343 },
14344 {
14345 name: "Monitoring",
14346 superClass: [
14347 "BaseElement"
14348 ]
14349 },
14350 {
14351 name: "Performer",
14352 superClass: [
14353 "ResourceRole"
14354 ]
14355 },
14356 {
14357 name: "Process",
14358 superClass: [
14359 "FlowElementsContainer",
14360 "CallableElement"
14361 ],
14362 properties: [
14363 {
14364 name: "processType",
14365 type: "ProcessType",
14366 isAttr: true
14367 },
14368 {
14369 name: "isClosed",
14370 isAttr: true,
14371 type: "Boolean"
14372 },
14373 {
14374 name: "auditing",
14375 type: "Auditing"
14376 },
14377 {
14378 name: "monitoring",
14379 type: "Monitoring"
14380 },
14381 {
14382 name: "properties",
14383 type: "Property",
14384 isMany: true
14385 },
14386 {
14387 name: "laneSets",
14388 type: "LaneSet",
14389 isMany: true,
14390 replaces: "FlowElementsContainer#laneSets"
14391 },
14392 {
14393 name: "flowElements",
14394 type: "FlowElement",
14395 isMany: true,
14396 replaces: "FlowElementsContainer#flowElements"
14397 },
14398 {
14399 name: "artifacts",
14400 type: "Artifact",
14401 isMany: true
14402 },
14403 {
14404 name: "resources",
14405 type: "ResourceRole",
14406 isMany: true
14407 },
14408 {
14409 name: "correlationSubscriptions",
14410 type: "CorrelationSubscription",
14411 isMany: true
14412 },
14413 {
14414 name: "supports",
14415 type: "Process",
14416 isMany: true,
14417 isReference: true
14418 },
14419 {
14420 name: "definitionalCollaborationRef",
14421 type: "Collaboration",
14422 isAttr: true,
14423 isReference: true
14424 },
14425 {
14426 name: "isExecutable",
14427 isAttr: true,
14428 type: "Boolean"
14429 }
14430 ]
14431 },
14432 {
14433 name: "LaneSet",
14434 superClass: [
14435 "BaseElement"
14436 ],
14437 properties: [
14438 {
14439 name: "lanes",
14440 type: "Lane",
14441 isMany: true
14442 },
14443 {
14444 name: "name",
14445 isAttr: true,
14446 type: "String"
14447 }
14448 ]
14449 },
14450 {
14451 name: "Lane",
14452 superClass: [
14453 "BaseElement"
14454 ],
14455 properties: [
14456 {
14457 name: "name",
14458 isAttr: true,
14459 type: "String"
14460 },
14461 {
14462 name: "partitionElementRef",
14463 type: "BaseElement",
14464 isAttr: true,
14465 isReference: true
14466 },
14467 {
14468 name: "partitionElement",
14469 type: "BaseElement"
14470 },
14471 {
14472 name: "flowNodeRef",
14473 type: "FlowNode",
14474 isMany: true,
14475 isReference: true
14476 },
14477 {
14478 name: "childLaneSet",
14479 type: "LaneSet",
14480 xml: {
14481 serialize: "xsi:type"
14482 }
14483 }
14484 ]
14485 },
14486 {
14487 name: "GlobalManualTask",
14488 superClass: [
14489 "GlobalTask"
14490 ]
14491 },
14492 {
14493 name: "ManualTask",
14494 superClass: [
14495 "Task"
14496 ]
14497 },
14498 {
14499 name: "UserTask",
14500 superClass: [
14501 "Task"
14502 ],
14503 properties: [
14504 {
14505 name: "renderings",
14506 type: "Rendering",
14507 isMany: true
14508 },
14509 {
14510 name: "implementation",
14511 isAttr: true,
14512 type: "String"
14513 }
14514 ]
14515 },
14516 {
14517 name: "Rendering",
14518 superClass: [
14519 "BaseElement"
14520 ]
14521 },
14522 {
14523 name: "HumanPerformer",
14524 superClass: [
14525 "Performer"
14526 ]
14527 },
14528 {
14529 name: "PotentialOwner",
14530 superClass: [
14531 "HumanPerformer"
14532 ]
14533 },
14534 {
14535 name: "GlobalUserTask",
14536 superClass: [
14537 "GlobalTask"
14538 ],
14539 properties: [
14540 {
14541 name: "implementation",
14542 isAttr: true,
14543 type: "String"
14544 },
14545 {
14546 name: "renderings",
14547 type: "Rendering",
14548 isMany: true
14549 }
14550 ]
14551 },
14552 {
14553 name: "Gateway",
14554 isAbstract: true,
14555 superClass: [
14556 "FlowNode"
14557 ],
14558 properties: [
14559 {
14560 name: "gatewayDirection",
14561 type: "GatewayDirection",
14562 "default": "Unspecified",
14563 isAttr: true
14564 }
14565 ]
14566 },
14567 {
14568 name: "EventBasedGateway",
14569 superClass: [
14570 "Gateway"
14571 ],
14572 properties: [
14573 {
14574 name: "instantiate",
14575 "default": false,
14576 isAttr: true,
14577 type: "Boolean"
14578 },
14579 {
14580 name: "eventGatewayType",
14581 type: "EventBasedGatewayType",
14582 isAttr: true,
14583 "default": "Exclusive"
14584 }
14585 ]
14586 },
14587 {
14588 name: "ComplexGateway",
14589 superClass: [
14590 "Gateway"
14591 ],
14592 properties: [
14593 {
14594 name: "activationCondition",
14595 type: "Expression",
14596 xml: {
14597 serialize: "xsi:type"
14598 }
14599 },
14600 {
14601 name: "default",
14602 type: "SequenceFlow",
14603 isAttr: true,
14604 isReference: true
14605 }
14606 ]
14607 },
14608 {
14609 name: "ExclusiveGateway",
14610 superClass: [
14611 "Gateway"
14612 ],
14613 properties: [
14614 {
14615 name: "default",
14616 type: "SequenceFlow",
14617 isAttr: true,
14618 isReference: true
14619 }
14620 ]
14621 },
14622 {
14623 name: "InclusiveGateway",
14624 superClass: [
14625 "Gateway"
14626 ],
14627 properties: [
14628 {
14629 name: "default",
14630 type: "SequenceFlow",
14631 isAttr: true,
14632 isReference: true
14633 }
14634 ]
14635 },
14636 {
14637 name: "ParallelGateway",
14638 superClass: [
14639 "Gateway"
14640 ]
14641 },
14642 {
14643 name: "RootElement",
14644 isAbstract: true,
14645 superClass: [
14646 "BaseElement"
14647 ]
14648 },
14649 {
14650 name: "Relationship",
14651 superClass: [
14652 "BaseElement"
14653 ],
14654 properties: [
14655 {
14656 name: "type",
14657 isAttr: true,
14658 type: "String"
14659 },
14660 {
14661 name: "direction",
14662 type: "RelationshipDirection",
14663 isAttr: true
14664 },
14665 {
14666 name: "source",
14667 isMany: true,
14668 isReference: true,
14669 type: "Element"
14670 },
14671 {
14672 name: "target",
14673 isMany: true,
14674 isReference: true,
14675 type: "Element"
14676 }
14677 ]
14678 },
14679 {
14680 name: "BaseElement",
14681 isAbstract: true,
14682 properties: [
14683 {
14684 name: "id",
14685 isAttr: true,
14686 type: "String",
14687 isId: true
14688 },
14689 {
14690 name: "documentation",
14691 type: "Documentation",
14692 isMany: true
14693 },
14694 {
14695 name: "extensionDefinitions",
14696 type: "ExtensionDefinition",
14697 isMany: true,
14698 isReference: true
14699 },
14700 {
14701 name: "extensionElements",
14702 type: "ExtensionElements"
14703 }
14704 ]
14705 },
14706 {
14707 name: "Extension",
14708 properties: [
14709 {
14710 name: "mustUnderstand",
14711 "default": false,
14712 isAttr: true,
14713 type: "Boolean"
14714 },
14715 {
14716 name: "definition",
14717 type: "ExtensionDefinition",
14718 isAttr: true,
14719 isReference: true
14720 }
14721 ]
14722 },
14723 {
14724 name: "ExtensionDefinition",
14725 properties: [
14726 {
14727 name: "name",
14728 isAttr: true,
14729 type: "String"
14730 },
14731 {
14732 name: "extensionAttributeDefinitions",
14733 type: "ExtensionAttributeDefinition",
14734 isMany: true
14735 }
14736 ]
14737 },
14738 {
14739 name: "ExtensionAttributeDefinition",
14740 properties: [
14741 {
14742 name: "name",
14743 isAttr: true,
14744 type: "String"
14745 },
14746 {
14747 name: "type",
14748 isAttr: true,
14749 type: "String"
14750 },
14751 {
14752 name: "isReference",
14753 "default": false,
14754 isAttr: true,
14755 type: "Boolean"
14756 },
14757 {
14758 name: "extensionDefinition",
14759 type: "ExtensionDefinition",
14760 isAttr: true,
14761 isReference: true
14762 }
14763 ]
14764 },
14765 {
14766 name: "ExtensionElements",
14767 properties: [
14768 {
14769 name: "valueRef",
14770 isAttr: true,
14771 isReference: true,
14772 type: "Element"
14773 },
14774 {
14775 name: "values",
14776 type: "Element",
14777 isMany: true
14778 },
14779 {
14780 name: "extensionAttributeDefinition",
14781 type: "ExtensionAttributeDefinition",
14782 isAttr: true,
14783 isReference: true
14784 }
14785 ]
14786 },
14787 {
14788 name: "Documentation",
14789 superClass: [
14790 "BaseElement"
14791 ],
14792 properties: [
14793 {
14794 name: "text",
14795 type: "String",
14796 isBody: true
14797 },
14798 {
14799 name: "textFormat",
14800 "default": "text/plain",
14801 isAttr: true,
14802 type: "String"
14803 }
14804 ]
14805 },
14806 {
14807 name: "Event",
14808 isAbstract: true,
14809 superClass: [
14810 "FlowNode",
14811 "InteractionNode"
14812 ],
14813 properties: [
14814 {
14815 name: "properties",
14816 type: "Property",
14817 isMany: true
14818 }
14819 ]
14820 },
14821 {
14822 name: "IntermediateCatchEvent",
14823 superClass: [
14824 "CatchEvent"
14825 ]
14826 },
14827 {
14828 name: "IntermediateThrowEvent",
14829 superClass: [
14830 "ThrowEvent"
14831 ]
14832 },
14833 {
14834 name: "EndEvent",
14835 superClass: [
14836 "ThrowEvent"
14837 ]
14838 },
14839 {
14840 name: "StartEvent",
14841 superClass: [
14842 "CatchEvent"
14843 ],
14844 properties: [
14845 {
14846 name: "isInterrupting",
14847 "default": true,
14848 isAttr: true,
14849 type: "Boolean"
14850 }
14851 ]
14852 },
14853 {
14854 name: "ThrowEvent",
14855 isAbstract: true,
14856 superClass: [
14857 "Event"
14858 ],
14859 properties: [
14860 {
14861 name: "dataInputs",
14862 type: "DataInput",
14863 isMany: true
14864 },
14865 {
14866 name: "dataInputAssociations",
14867 type: "DataInputAssociation",
14868 isMany: true
14869 },
14870 {
14871 name: "inputSet",
14872 type: "InputSet"
14873 },
14874 {
14875 name: "eventDefinitions",
14876 type: "EventDefinition",
14877 isMany: true
14878 },
14879 {
14880 name: "eventDefinitionRef",
14881 type: "EventDefinition",
14882 isMany: true,
14883 isReference: true
14884 }
14885 ]
14886 },
14887 {
14888 name: "CatchEvent",
14889 isAbstract: true,
14890 superClass: [
14891 "Event"
14892 ],
14893 properties: [
14894 {
14895 name: "parallelMultiple",
14896 isAttr: true,
14897 type: "Boolean",
14898 "default": false
14899 },
14900 {
14901 name: "dataOutputs",
14902 type: "DataOutput",
14903 isMany: true
14904 },
14905 {
14906 name: "dataOutputAssociations",
14907 type: "DataOutputAssociation",
14908 isMany: true
14909 },
14910 {
14911 name: "outputSet",
14912 type: "OutputSet"
14913 },
14914 {
14915 name: "eventDefinitions",
14916 type: "EventDefinition",
14917 isMany: true
14918 },
14919 {
14920 name: "eventDefinitionRef",
14921 type: "EventDefinition",
14922 isMany: true,
14923 isReference: true
14924 }
14925 ]
14926 },
14927 {
14928 name: "BoundaryEvent",
14929 superClass: [
14930 "CatchEvent"
14931 ],
14932 properties: [
14933 {
14934 name: "cancelActivity",
14935 "default": true,
14936 isAttr: true,
14937 type: "Boolean"
14938 },
14939 {
14940 name: "attachedToRef",
14941 type: "Activity",
14942 isAttr: true,
14943 isReference: true
14944 }
14945 ]
14946 },
14947 {
14948 name: "EventDefinition",
14949 isAbstract: true,
14950 superClass: [
14951 "RootElement"
14952 ]
14953 },
14954 {
14955 name: "CancelEventDefinition",
14956 superClass: [
14957 "EventDefinition"
14958 ]
14959 },
14960 {
14961 name: "ErrorEventDefinition",
14962 superClass: [
14963 "EventDefinition"
14964 ],
14965 properties: [
14966 {
14967 name: "errorRef",
14968 type: "Error",
14969 isAttr: true,
14970 isReference: true
14971 }
14972 ]
14973 },
14974 {
14975 name: "TerminateEventDefinition",
14976 superClass: [
14977 "EventDefinition"
14978 ]
14979 },
14980 {
14981 name: "EscalationEventDefinition",
14982 superClass: [
14983 "EventDefinition"
14984 ],
14985 properties: [
14986 {
14987 name: "escalationRef",
14988 type: "Escalation",
14989 isAttr: true,
14990 isReference: true
14991 }
14992 ]
14993 },
14994 {
14995 name: "Escalation",
14996 properties: [
14997 {
14998 name: "structureRef",
14999 type: "ItemDefinition",
15000 isAttr: true,
15001 isReference: true
15002 },
15003 {
15004 name: "name",
15005 isAttr: true,
15006 type: "String"
15007 },
15008 {
15009 name: "escalationCode",
15010 isAttr: true,
15011 type: "String"
15012 }
15013 ],
15014 superClass: [
15015 "RootElement"
15016 ]
15017 },
15018 {
15019 name: "CompensateEventDefinition",
15020 superClass: [
15021 "EventDefinition"
15022 ],
15023 properties: [
15024 {
15025 name: "waitForCompletion",
15026 isAttr: true,
15027 type: "Boolean",
15028 "default": true
15029 },
15030 {
15031 name: "activityRef",
15032 type: "Activity",
15033 isAttr: true,
15034 isReference: true
15035 }
15036 ]
15037 },
15038 {
15039 name: "TimerEventDefinition",
15040 superClass: [
15041 "EventDefinition"
15042 ],
15043 properties: [
15044 {
15045 name: "timeDate",
15046 type: "Expression",
15047 xml: {
15048 serialize: "xsi:type"
15049 }
15050 },
15051 {
15052 name: "timeCycle",
15053 type: "Expression",
15054 xml: {
15055 serialize: "xsi:type"
15056 }
15057 },
15058 {
15059 name: "timeDuration",
15060 type: "Expression",
15061 xml: {
15062 serialize: "xsi:type"
15063 }
15064 }
15065 ]
15066 },
15067 {
15068 name: "LinkEventDefinition",
15069 superClass: [
15070 "EventDefinition"
15071 ],
15072 properties: [
15073 {
15074 name: "name",
15075 isAttr: true,
15076 type: "String"
15077 },
15078 {
15079 name: "target",
15080 type: "LinkEventDefinition",
15081 isAttr: true,
15082 isReference: true
15083 },
15084 {
15085 name: "source",
15086 type: "LinkEventDefinition",
15087 isMany: true,
15088 isReference: true
15089 }
15090 ]
15091 },
15092 {
15093 name: "MessageEventDefinition",
15094 superClass: [
15095 "EventDefinition"
15096 ],
15097 properties: [
15098 {
15099 name: "messageRef",
15100 type: "Message",
15101 isAttr: true,
15102 isReference: true
15103 },
15104 {
15105 name: "operationRef",
15106 type: "Operation",
15107 isAttr: true,
15108 isReference: true
15109 }
15110 ]
15111 },
15112 {
15113 name: "ConditionalEventDefinition",
15114 superClass: [
15115 "EventDefinition"
15116 ],
15117 properties: [
15118 {
15119 name: "condition",
15120 type: "Expression",
15121 xml: {
15122 serialize: "xsi:type"
15123 }
15124 }
15125 ]
15126 },
15127 {
15128 name: "SignalEventDefinition",
15129 superClass: [
15130 "EventDefinition"
15131 ],
15132 properties: [
15133 {
15134 name: "signalRef",
15135 type: "Signal",
15136 isAttr: true,
15137 isReference: true
15138 }
15139 ]
15140 },
15141 {
15142 name: "Signal",
15143 superClass: [
15144 "RootElement"
15145 ],
15146 properties: [
15147 {
15148 name: "structureRef",
15149 type: "ItemDefinition",
15150 isAttr: true,
15151 isReference: true
15152 },
15153 {
15154 name: "name",
15155 isAttr: true,
15156 type: "String"
15157 }
15158 ]
15159 },
15160 {
15161 name: "ImplicitThrowEvent",
15162 superClass: [
15163 "ThrowEvent"
15164 ]
15165 },
15166 {
15167 name: "DataState",
15168 superClass: [
15169 "BaseElement"
15170 ],
15171 properties: [
15172 {
15173 name: "name",
15174 isAttr: true,
15175 type: "String"
15176 }
15177 ]
15178 },
15179 {
15180 name: "ItemAwareElement",
15181 superClass: [
15182 "BaseElement"
15183 ],
15184 properties: [
15185 {
15186 name: "itemSubjectRef",
15187 type: "ItemDefinition",
15188 isAttr: true,
15189 isReference: true
15190 },
15191 {
15192 name: "dataState",
15193 type: "DataState"
15194 }
15195 ]
15196 },
15197 {
15198 name: "DataAssociation",
15199 superClass: [
15200 "BaseElement"
15201 ],
15202 properties: [
15203 {
15204 name: "assignment",
15205 type: "Assignment",
15206 isMany: true
15207 },
15208 {
15209 name: "sourceRef",
15210 type: "ItemAwareElement",
15211 isMany: true,
15212 isReference: true
15213 },
15214 {
15215 name: "targetRef",
15216 type: "ItemAwareElement",
15217 isReference: true
15218 },
15219 {
15220 name: "transformation",
15221 type: "FormalExpression",
15222 xml: {
15223 serialize: "property"
15224 }
15225 }
15226 ]
15227 },
15228 {
15229 name: "DataInput",
15230 superClass: [
15231 "ItemAwareElement"
15232 ],
15233 properties: [
15234 {
15235 name: "name",
15236 isAttr: true,
15237 type: "String"
15238 },
15239 {
15240 name: "isCollection",
15241 "default": false,
15242 isAttr: true,
15243 type: "Boolean"
15244 },
15245 {
15246 name: "inputSetRef",
15247 type: "InputSet",
15248 isVirtual: true,
15249 isMany: true,
15250 isReference: true
15251 },
15252 {
15253 name: "inputSetWithOptional",
15254 type: "InputSet",
15255 isVirtual: true,
15256 isMany: true,
15257 isReference: true
15258 },
15259 {
15260 name: "inputSetWithWhileExecuting",
15261 type: "InputSet",
15262 isVirtual: true,
15263 isMany: true,
15264 isReference: true
15265 }
15266 ]
15267 },
15268 {
15269 name: "DataOutput",
15270 superClass: [
15271 "ItemAwareElement"
15272 ],
15273 properties: [
15274 {
15275 name: "name",
15276 isAttr: true,
15277 type: "String"
15278 },
15279 {
15280 name: "isCollection",
15281 "default": false,
15282 isAttr: true,
15283 type: "Boolean"
15284 },
15285 {
15286 name: "outputSetRef",
15287 type: "OutputSet",
15288 isVirtual: true,
15289 isMany: true,
15290 isReference: true
15291 },
15292 {
15293 name: "outputSetWithOptional",
15294 type: "OutputSet",
15295 isVirtual: true,
15296 isMany: true,
15297 isReference: true
15298 },
15299 {
15300 name: "outputSetWithWhileExecuting",
15301 type: "OutputSet",
15302 isVirtual: true,
15303 isMany: true,
15304 isReference: true
15305 }
15306 ]
15307 },
15308 {
15309 name: "InputSet",
15310 superClass: [
15311 "BaseElement"
15312 ],
15313 properties: [
15314 {
15315 name: "name",
15316 isAttr: true,
15317 type: "String"
15318 },
15319 {
15320 name: "dataInputRefs",
15321 type: "DataInput",
15322 isMany: true,
15323 isReference: true
15324 },
15325 {
15326 name: "optionalInputRefs",
15327 type: "DataInput",
15328 isMany: true,
15329 isReference: true
15330 },
15331 {
15332 name: "whileExecutingInputRefs",
15333 type: "DataInput",
15334 isMany: true,
15335 isReference: true
15336 },
15337 {
15338 name: "outputSetRefs",
15339 type: "OutputSet",
15340 isMany: true,
15341 isReference: true
15342 }
15343 ]
15344 },
15345 {
15346 name: "OutputSet",
15347 superClass: [
15348 "BaseElement"
15349 ],
15350 properties: [
15351 {
15352 name: "dataOutputRefs",
15353 type: "DataOutput",
15354 isMany: true,
15355 isReference: true
15356 },
15357 {
15358 name: "name",
15359 isAttr: true,
15360 type: "String"
15361 },
15362 {
15363 name: "inputSetRefs",
15364 type: "InputSet",
15365 isMany: true,
15366 isReference: true
15367 },
15368 {
15369 name: "optionalOutputRefs",
15370 type: "DataOutput",
15371 isMany: true,
15372 isReference: true
15373 },
15374 {
15375 name: "whileExecutingOutputRefs",
15376 type: "DataOutput",
15377 isMany: true,
15378 isReference: true
15379 }
15380 ]
15381 },
15382 {
15383 name: "Property",
15384 superClass: [
15385 "ItemAwareElement"
15386 ],
15387 properties: [
15388 {
15389 name: "name",
15390 isAttr: true,
15391 type: "String"
15392 }
15393 ]
15394 },
15395 {
15396 name: "DataInputAssociation",
15397 superClass: [
15398 "DataAssociation"
15399 ]
15400 },
15401 {
15402 name: "DataOutputAssociation",
15403 superClass: [
15404 "DataAssociation"
15405 ]
15406 },
15407 {
15408 name: "InputOutputSpecification",
15409 superClass: [
15410 "BaseElement"
15411 ],
15412 properties: [
15413 {
15414 name: "dataInputs",
15415 type: "DataInput",
15416 isMany: true
15417 },
15418 {
15419 name: "dataOutputs",
15420 type: "DataOutput",
15421 isMany: true
15422 },
15423 {
15424 name: "inputSets",
15425 type: "InputSet",
15426 isMany: true
15427 },
15428 {
15429 name: "outputSets",
15430 type: "OutputSet",
15431 isMany: true
15432 }
15433 ]
15434 },
15435 {
15436 name: "DataObject",
15437 superClass: [
15438 "FlowElement",
15439 "ItemAwareElement"
15440 ],
15441 properties: [
15442 {
15443 name: "isCollection",
15444 "default": false,
15445 isAttr: true,
15446 type: "Boolean"
15447 }
15448 ]
15449 },
15450 {
15451 name: "InputOutputBinding",
15452 properties: [
15453 {
15454 name: "inputDataRef",
15455 type: "InputSet",
15456 isAttr: true,
15457 isReference: true
15458 },
15459 {
15460 name: "outputDataRef",
15461 type: "OutputSet",
15462 isAttr: true,
15463 isReference: true
15464 },
15465 {
15466 name: "operationRef",
15467 type: "Operation",
15468 isAttr: true,
15469 isReference: true
15470 }
15471 ]
15472 },
15473 {
15474 name: "Assignment",
15475 superClass: [
15476 "BaseElement"
15477 ],
15478 properties: [
15479 {
15480 name: "from",
15481 type: "Expression",
15482 xml: {
15483 serialize: "xsi:type"
15484 }
15485 },
15486 {
15487 name: "to",
15488 type: "Expression",
15489 xml: {
15490 serialize: "xsi:type"
15491 }
15492 }
15493 ]
15494 },
15495 {
15496 name: "DataStore",
15497 superClass: [
15498 "RootElement",
15499 "ItemAwareElement"
15500 ],
15501 properties: [
15502 {
15503 name: "name",
15504 isAttr: true,
15505 type: "String"
15506 },
15507 {
15508 name: "capacity",
15509 isAttr: true,
15510 type: "Integer"
15511 },
15512 {
15513 name: "isUnlimited",
15514 "default": true,
15515 isAttr: true,
15516 type: "Boolean"
15517 }
15518 ]
15519 },
15520 {
15521 name: "DataStoreReference",
15522 superClass: [
15523 "ItemAwareElement",
15524 "FlowElement"
15525 ],
15526 properties: [
15527 {
15528 name: "dataStoreRef",
15529 type: "DataStore",
15530 isAttr: true,
15531 isReference: true
15532 }
15533 ]
15534 },
15535 {
15536 name: "DataObjectReference",
15537 superClass: [
15538 "ItemAwareElement",
15539 "FlowElement"
15540 ],
15541 properties: [
15542 {
15543 name: "dataObjectRef",
15544 type: "DataObject",
15545 isAttr: true,
15546 isReference: true
15547 }
15548 ]
15549 },
15550 {
15551 name: "ConversationLink",
15552 superClass: [
15553 "BaseElement"
15554 ],
15555 properties: [
15556 {
15557 name: "sourceRef",
15558 type: "InteractionNode",
15559 isAttr: true,
15560 isReference: true
15561 },
15562 {
15563 name: "targetRef",
15564 type: "InteractionNode",
15565 isAttr: true,
15566 isReference: true
15567 },
15568 {
15569 name: "name",
15570 isAttr: true,
15571 type: "String"
15572 }
15573 ]
15574 },
15575 {
15576 name: "ConversationAssociation",
15577 superClass: [
15578 "BaseElement"
15579 ],
15580 properties: [
15581 {
15582 name: "innerConversationNodeRef",
15583 type: "ConversationNode",
15584 isAttr: true,
15585 isReference: true
15586 },
15587 {
15588 name: "outerConversationNodeRef",
15589 type: "ConversationNode",
15590 isAttr: true,
15591 isReference: true
15592 }
15593 ]
15594 },
15595 {
15596 name: "CallConversation",
15597 superClass: [
15598 "ConversationNode"
15599 ],
15600 properties: [
15601 {
15602 name: "calledCollaborationRef",
15603 type: "Collaboration",
15604 isAttr: true,
15605 isReference: true
15606 },
15607 {
15608 name: "participantAssociations",
15609 type: "ParticipantAssociation",
15610 isMany: true
15611 }
15612 ]
15613 },
15614 {
15615 name: "Conversation",
15616 superClass: [
15617 "ConversationNode"
15618 ]
15619 },
15620 {
15621 name: "SubConversation",
15622 superClass: [
15623 "ConversationNode"
15624 ],
15625 properties: [
15626 {
15627 name: "conversationNodes",
15628 type: "ConversationNode",
15629 isMany: true
15630 }
15631 ]
15632 },
15633 {
15634 name: "ConversationNode",
15635 isAbstract: true,
15636 superClass: [
15637 "InteractionNode",
15638 "BaseElement"
15639 ],
15640 properties: [
15641 {
15642 name: "name",
15643 isAttr: true,
15644 type: "String"
15645 },
15646 {
15647 name: "participantRef",
15648 type: "Participant",
15649 isMany: true,
15650 isReference: true
15651 },
15652 {
15653 name: "messageFlowRefs",
15654 type: "MessageFlow",
15655 isMany: true,
15656 isReference: true
15657 },
15658 {
15659 name: "correlationKeys",
15660 type: "CorrelationKey",
15661 isMany: true
15662 }
15663 ]
15664 },
15665 {
15666 name: "GlobalConversation",
15667 superClass: [
15668 "Collaboration"
15669 ]
15670 },
15671 {
15672 name: "PartnerEntity",
15673 superClass: [
15674 "RootElement"
15675 ],
15676 properties: [
15677 {
15678 name: "name",
15679 isAttr: true,
15680 type: "String"
15681 },
15682 {
15683 name: "participantRef",
15684 type: "Participant",
15685 isMany: true,
15686 isReference: true
15687 }
15688 ]
15689 },
15690 {
15691 name: "PartnerRole",
15692 superClass: [
15693 "RootElement"
15694 ],
15695 properties: [
15696 {
15697 name: "name",
15698 isAttr: true,
15699 type: "String"
15700 },
15701 {
15702 name: "participantRef",
15703 type: "Participant",
15704 isMany: true,
15705 isReference: true
15706 }
15707 ]
15708 },
15709 {
15710 name: "CorrelationProperty",
15711 superClass: [
15712 "RootElement"
15713 ],
15714 properties: [
15715 {
15716 name: "correlationPropertyRetrievalExpression",
15717 type: "CorrelationPropertyRetrievalExpression",
15718 isMany: true
15719 },
15720 {
15721 name: "name",
15722 isAttr: true,
15723 type: "String"
15724 },
15725 {
15726 name: "type",
15727 type: "ItemDefinition",
15728 isAttr: true,
15729 isReference: true
15730 }
15731 ]
15732 },
15733 {
15734 name: "Error",
15735 superClass: [
15736 "RootElement"
15737 ],
15738 properties: [
15739 {
15740 name: "structureRef",
15741 type: "ItemDefinition",
15742 isAttr: true,
15743 isReference: true
15744 },
15745 {
15746 name: "name",
15747 isAttr: true,
15748 type: "String"
15749 },
15750 {
15751 name: "errorCode",
15752 isAttr: true,
15753 type: "String"
15754 }
15755 ]
15756 },
15757 {
15758 name: "CorrelationKey",
15759 superClass: [
15760 "BaseElement"
15761 ],
15762 properties: [
15763 {
15764 name: "correlationPropertyRef",
15765 type: "CorrelationProperty",
15766 isMany: true,
15767 isReference: true
15768 },
15769 {
15770 name: "name",
15771 isAttr: true,
15772 type: "String"
15773 }
15774 ]
15775 },
15776 {
15777 name: "Expression",
15778 superClass: [
15779 "BaseElement"
15780 ],
15781 isAbstract: false,
15782 properties: [
15783 {
15784 name: "body",
15785 type: "String",
15786 isBody: true
15787 }
15788 ]
15789 },
15790 {
15791 name: "FormalExpression",
15792 superClass: [
15793 "Expression"
15794 ],
15795 properties: [
15796 {
15797 name: "language",
15798 isAttr: true,
15799 type: "String"
15800 },
15801 {
15802 name: "evaluatesToTypeRef",
15803 type: "ItemDefinition",
15804 isAttr: true,
15805 isReference: true
15806 }
15807 ]
15808 },
15809 {
15810 name: "Message",
15811 superClass: [
15812 "RootElement"
15813 ],
15814 properties: [
15815 {
15816 name: "name",
15817 isAttr: true,
15818 type: "String"
15819 },
15820 {
15821 name: "itemRef",
15822 type: "ItemDefinition",
15823 isAttr: true,
15824 isReference: true
15825 }
15826 ]
15827 },
15828 {
15829 name: "ItemDefinition",
15830 superClass: [
15831 "RootElement"
15832 ],
15833 properties: [
15834 {
15835 name: "itemKind",
15836 type: "ItemKind",
15837 isAttr: true
15838 },
15839 {
15840 name: "structureRef",
15841 type: "String",
15842 isAttr: true
15843 },
15844 {
15845 name: "isCollection",
15846 "default": false,
15847 isAttr: true,
15848 type: "Boolean"
15849 },
15850 {
15851 name: "import",
15852 type: "Import",
15853 isAttr: true,
15854 isReference: true
15855 }
15856 ]
15857 },
15858 {
15859 name: "FlowElement",
15860 isAbstract: true,
15861 superClass: [
15862 "BaseElement"
15863 ],
15864 properties: [
15865 {
15866 name: "name",
15867 isAttr: true,
15868 type: "String"
15869 },
15870 {
15871 name: "auditing",
15872 type: "Auditing"
15873 },
15874 {
15875 name: "monitoring",
15876 type: "Monitoring"
15877 },
15878 {
15879 name: "categoryValueRef",
15880 type: "CategoryValue",
15881 isMany: true,
15882 isReference: true
15883 }
15884 ]
15885 },
15886 {
15887 name: "SequenceFlow",
15888 superClass: [
15889 "FlowElement"
15890 ],
15891 properties: [
15892 {
15893 name: "isImmediate",
15894 isAttr: true,
15895 type: "Boolean"
15896 },
15897 {
15898 name: "conditionExpression",
15899 type: "Expression",
15900 xml: {
15901 serialize: "xsi:type"
15902 }
15903 },
15904 {
15905 name: "sourceRef",
15906 type: "FlowNode",
15907 isAttr: true,
15908 isReference: true
15909 },
15910 {
15911 name: "targetRef",
15912 type: "FlowNode",
15913 isAttr: true,
15914 isReference: true
15915 }
15916 ]
15917 },
15918 {
15919 name: "FlowElementsContainer",
15920 isAbstract: true,
15921 superClass: [
15922 "BaseElement"
15923 ],
15924 properties: [
15925 {
15926 name: "laneSets",
15927 type: "LaneSet",
15928 isMany: true
15929 },
15930 {
15931 name: "flowElements",
15932 type: "FlowElement",
15933 isMany: true
15934 }
15935 ]
15936 },
15937 {
15938 name: "CallableElement",
15939 isAbstract: true,
15940 superClass: [
15941 "RootElement"
15942 ],
15943 properties: [
15944 {
15945 name: "name",
15946 isAttr: true,
15947 type: "String"
15948 },
15949 {
15950 name: "ioSpecification",
15951 type: "InputOutputSpecification",
15952 xml: {
15953 serialize: "property"
15954 }
15955 },
15956 {
15957 name: "supportedInterfaceRef",
15958 type: "Interface",
15959 isMany: true,
15960 isReference: true
15961 },
15962 {
15963 name: "ioBinding",
15964 type: "InputOutputBinding",
15965 isMany: true,
15966 xml: {
15967 serialize: "property"
15968 }
15969 }
15970 ]
15971 },
15972 {
15973 name: "FlowNode",
15974 isAbstract: true,
15975 superClass: [
15976 "FlowElement"
15977 ],
15978 properties: [
15979 {
15980 name: "incoming",
15981 type: "SequenceFlow",
15982 isMany: true,
15983 isReference: true
15984 },
15985 {
15986 name: "outgoing",
15987 type: "SequenceFlow",
15988 isMany: true,
15989 isReference: true
15990 },
15991 {
15992 name: "lanes",
15993 type: "Lane",
15994 isVirtual: true,
15995 isMany: true,
15996 isReference: true
15997 }
15998 ]
15999 },
16000 {
16001 name: "CorrelationPropertyRetrievalExpression",
16002 superClass: [
16003 "BaseElement"
16004 ],
16005 properties: [
16006 {
16007 name: "messagePath",
16008 type: "FormalExpression"
16009 },
16010 {
16011 name: "messageRef",
16012 type: "Message",
16013 isAttr: true,
16014 isReference: true
16015 }
16016 ]
16017 },
16018 {
16019 name: "CorrelationPropertyBinding",
16020 superClass: [
16021 "BaseElement"
16022 ],
16023 properties: [
16024 {
16025 name: "dataPath",
16026 type: "FormalExpression"
16027 },
16028 {
16029 name: "correlationPropertyRef",
16030 type: "CorrelationProperty",
16031 isAttr: true,
16032 isReference: true
16033 }
16034 ]
16035 },
16036 {
16037 name: "Resource",
16038 superClass: [
16039 "RootElement"
16040 ],
16041 properties: [
16042 {
16043 name: "name",
16044 isAttr: true,
16045 type: "String"
16046 },
16047 {
16048 name: "resourceParameters",
16049 type: "ResourceParameter",
16050 isMany: true
16051 }
16052 ]
16053 },
16054 {
16055 name: "ResourceParameter",
16056 superClass: [
16057 "BaseElement"
16058 ],
16059 properties: [
16060 {
16061 name: "name",
16062 isAttr: true,
16063 type: "String"
16064 },
16065 {
16066 name: "isRequired",
16067 isAttr: true,
16068 type: "Boolean"
16069 },
16070 {
16071 name: "type",
16072 type: "ItemDefinition",
16073 isAttr: true,
16074 isReference: true
16075 }
16076 ]
16077 },
16078 {
16079 name: "CorrelationSubscription",
16080 superClass: [
16081 "BaseElement"
16082 ],
16083 properties: [
16084 {
16085 name: "correlationKeyRef",
16086 type: "CorrelationKey",
16087 isAttr: true,
16088 isReference: true
16089 },
16090 {
16091 name: "correlationPropertyBinding",
16092 type: "CorrelationPropertyBinding",
16093 isMany: true
16094 }
16095 ]
16096 },
16097 {
16098 name: "MessageFlow",
16099 superClass: [
16100 "BaseElement"
16101 ],
16102 properties: [
16103 {
16104 name: "name",
16105 isAttr: true,
16106 type: "String"
16107 },
16108 {
16109 name: "sourceRef",
16110 type: "InteractionNode",
16111 isAttr: true,
16112 isReference: true
16113 },
16114 {
16115 name: "targetRef",
16116 type: "InteractionNode",
16117 isAttr: true,
16118 isReference: true
16119 },
16120 {
16121 name: "messageRef",
16122 type: "Message",
16123 isAttr: true,
16124 isReference: true
16125 }
16126 ]
16127 },
16128 {
16129 name: "MessageFlowAssociation",
16130 superClass: [
16131 "BaseElement"
16132 ],
16133 properties: [
16134 {
16135 name: "innerMessageFlowRef",
16136 type: "MessageFlow",
16137 isAttr: true,
16138 isReference: true
16139 },
16140 {
16141 name: "outerMessageFlowRef",
16142 type: "MessageFlow",
16143 isAttr: true,
16144 isReference: true
16145 }
16146 ]
16147 },
16148 {
16149 name: "InteractionNode",
16150 isAbstract: true,
16151 properties: [
16152 {
16153 name: "incomingConversationLinks",
16154 type: "ConversationLink",
16155 isVirtual: true,
16156 isMany: true,
16157 isReference: true
16158 },
16159 {
16160 name: "outgoingConversationLinks",
16161 type: "ConversationLink",
16162 isVirtual: true,
16163 isMany: true,
16164 isReference: true
16165 }
16166 ]
16167 },
16168 {
16169 name: "Participant",
16170 superClass: [
16171 "InteractionNode",
16172 "BaseElement"
16173 ],
16174 properties: [
16175 {
16176 name: "name",
16177 isAttr: true,
16178 type: "String"
16179 },
16180 {
16181 name: "interfaceRef",
16182 type: "Interface",
16183 isMany: true,
16184 isReference: true
16185 },
16186 {
16187 name: "participantMultiplicity",
16188 type: "ParticipantMultiplicity"
16189 },
16190 {
16191 name: "endPointRefs",
16192 type: "EndPoint",
16193 isMany: true,
16194 isReference: true
16195 },
16196 {
16197 name: "processRef",
16198 type: "Process",
16199 isAttr: true,
16200 isReference: true
16201 }
16202 ]
16203 },
16204 {
16205 name: "ParticipantAssociation",
16206 superClass: [
16207 "BaseElement"
16208 ],
16209 properties: [
16210 {
16211 name: "innerParticipantRef",
16212 type: "Participant",
16213 isAttr: true,
16214 isReference: true
16215 },
16216 {
16217 name: "outerParticipantRef",
16218 type: "Participant",
16219 isAttr: true,
16220 isReference: true
16221 }
16222 ]
16223 },
16224 {
16225 name: "ParticipantMultiplicity",
16226 properties: [
16227 {
16228 name: "minimum",
16229 "default": 0,
16230 isAttr: true,
16231 type: "Integer"
16232 },
16233 {
16234 name: "maximum",
16235 "default": 1,
16236 isAttr: true,
16237 type: "Integer"
16238 }
16239 ],
16240 superClass: [
16241 "BaseElement"
16242 ]
16243 },
16244 {
16245 name: "Collaboration",
16246 superClass: [
16247 "RootElement"
16248 ],
16249 properties: [
16250 {
16251 name: "name",
16252 isAttr: true,
16253 type: "String"
16254 },
16255 {
16256 name: "isClosed",
16257 isAttr: true,
16258 type: "Boolean"
16259 },
16260 {
16261 name: "participants",
16262 type: "Participant",
16263 isMany: true
16264 },
16265 {
16266 name: "messageFlows",
16267 type: "MessageFlow",
16268 isMany: true
16269 },
16270 {
16271 name: "artifacts",
16272 type: "Artifact",
16273 isMany: true
16274 },
16275 {
16276 name: "conversations",
16277 type: "ConversationNode",
16278 isMany: true
16279 },
16280 {
16281 name: "conversationAssociations",
16282 type: "ConversationAssociation"
16283 },
16284 {
16285 name: "participantAssociations",
16286 type: "ParticipantAssociation",
16287 isMany: true
16288 },
16289 {
16290 name: "messageFlowAssociations",
16291 type: "MessageFlowAssociation",
16292 isMany: true
16293 },
16294 {
16295 name: "correlationKeys",
16296 type: "CorrelationKey",
16297 isMany: true
16298 },
16299 {
16300 name: "choreographyRef",
16301 type: "Choreography",
16302 isMany: true,
16303 isReference: true
16304 },
16305 {
16306 name: "conversationLinks",
16307 type: "ConversationLink",
16308 isMany: true
16309 }
16310 ]
16311 },
16312 {
16313 name: "ChoreographyActivity",
16314 isAbstract: true,
16315 superClass: [
16316 "FlowNode"
16317 ],
16318 properties: [
16319 {
16320 name: "participantRef",
16321 type: "Participant",
16322 isMany: true,
16323 isReference: true
16324 },
16325 {
16326 name: "initiatingParticipantRef",
16327 type: "Participant",
16328 isAttr: true,
16329 isReference: true
16330 },
16331 {
16332 name: "correlationKeys",
16333 type: "CorrelationKey",
16334 isMany: true
16335 },
16336 {
16337 name: "loopType",
16338 type: "ChoreographyLoopType",
16339 "default": "None",
16340 isAttr: true
16341 }
16342 ]
16343 },
16344 {
16345 name: "CallChoreography",
16346 superClass: [
16347 "ChoreographyActivity"
16348 ],
16349 properties: [
16350 {
16351 name: "calledChoreographyRef",
16352 type: "Choreography",
16353 isAttr: true,
16354 isReference: true
16355 },
16356 {
16357 name: "participantAssociations",
16358 type: "ParticipantAssociation",
16359 isMany: true
16360 }
16361 ]
16362 },
16363 {
16364 name: "SubChoreography",
16365 superClass: [
16366 "ChoreographyActivity",
16367 "FlowElementsContainer"
16368 ],
16369 properties: [
16370 {
16371 name: "artifacts",
16372 type: "Artifact",
16373 isMany: true
16374 }
16375 ]
16376 },
16377 {
16378 name: "ChoreographyTask",
16379 superClass: [
16380 "ChoreographyActivity"
16381 ],
16382 properties: [
16383 {
16384 name: "messageFlowRef",
16385 type: "MessageFlow",
16386 isMany: true,
16387 isReference: true
16388 }
16389 ]
16390 },
16391 {
16392 name: "Choreography",
16393 superClass: [
16394 "Collaboration",
16395 "FlowElementsContainer"
16396 ]
16397 },
16398 {
16399 name: "GlobalChoreographyTask",
16400 superClass: [
16401 "Choreography"
16402 ],
16403 properties: [
16404 {
16405 name: "initiatingParticipantRef",
16406 type: "Participant",
16407 isAttr: true,
16408 isReference: true
16409 }
16410 ]
16411 },
16412 {
16413 name: "TextAnnotation",
16414 superClass: [
16415 "Artifact"
16416 ],
16417 properties: [
16418 {
16419 name: "text",
16420 type: "String"
16421 },
16422 {
16423 name: "textFormat",
16424 "default": "text/plain",
16425 isAttr: true,
16426 type: "String"
16427 }
16428 ]
16429 },
16430 {
16431 name: "Group",
16432 superClass: [
16433 "Artifact"
16434 ],
16435 properties: [
16436 {
16437 name: "categoryValueRef",
16438 type: "CategoryValue",
16439 isAttr: true,
16440 isReference: true
16441 }
16442 ]
16443 },
16444 {
16445 name: "Association",
16446 superClass: [
16447 "Artifact"
16448 ],
16449 properties: [
16450 {
16451 name: "associationDirection",
16452 type: "AssociationDirection",
16453 isAttr: true
16454 },
16455 {
16456 name: "sourceRef",
16457 type: "BaseElement",
16458 isAttr: true,
16459 isReference: true
16460 },
16461 {
16462 name: "targetRef",
16463 type: "BaseElement",
16464 isAttr: true,
16465 isReference: true
16466 }
16467 ]
16468 },
16469 {
16470 name: "Category",
16471 superClass: [
16472 "RootElement"
16473 ],
16474 properties: [
16475 {
16476 name: "categoryValue",
16477 type: "CategoryValue",
16478 isMany: true
16479 },
16480 {
16481 name: "name",
16482 isAttr: true,
16483 type: "String"
16484 }
16485 ]
16486 },
16487 {
16488 name: "Artifact",
16489 isAbstract: true,
16490 superClass: [
16491 "BaseElement"
16492 ]
16493 },
16494 {
16495 name: "CategoryValue",
16496 superClass: [
16497 "BaseElement"
16498 ],
16499 properties: [
16500 {
16501 name: "categorizedFlowElements",
16502 type: "FlowElement",
16503 isVirtual: true,
16504 isMany: true,
16505 isReference: true
16506 },
16507 {
16508 name: "value",
16509 isAttr: true,
16510 type: "String"
16511 }
16512 ]
16513 },
16514 {
16515 name: "Activity",
16516 isAbstract: true,
16517 superClass: [
16518 "FlowNode"
16519 ],
16520 properties: [
16521 {
16522 name: "isForCompensation",
16523 "default": false,
16524 isAttr: true,
16525 type: "Boolean"
16526 },
16527 {
16528 name: "default",
16529 type: "SequenceFlow",
16530 isAttr: true,
16531 isReference: true
16532 },
16533 {
16534 name: "ioSpecification",
16535 type: "InputOutputSpecification",
16536 xml: {
16537 serialize: "property"
16538 }
16539 },
16540 {
16541 name: "boundaryEventRefs",
16542 type: "BoundaryEvent",
16543 isMany: true,
16544 isReference: true
16545 },
16546 {
16547 name: "properties",
16548 type: "Property",
16549 isMany: true
16550 },
16551 {
16552 name: "dataInputAssociations",
16553 type: "DataInputAssociation",
16554 isMany: true
16555 },
16556 {
16557 name: "dataOutputAssociations",
16558 type: "DataOutputAssociation",
16559 isMany: true
16560 },
16561 {
16562 name: "startQuantity",
16563 "default": 1,
16564 isAttr: true,
16565 type: "Integer"
16566 },
16567 {
16568 name: "resources",
16569 type: "ResourceRole",
16570 isMany: true
16571 },
16572 {
16573 name: "completionQuantity",
16574 "default": 1,
16575 isAttr: true,
16576 type: "Integer"
16577 },
16578 {
16579 name: "loopCharacteristics",
16580 type: "LoopCharacteristics"
16581 }
16582 ]
16583 },
16584 {
16585 name: "ServiceTask",
16586 superClass: [
16587 "Task"
16588 ],
16589 properties: [
16590 {
16591 name: "implementation",
16592 isAttr: true,
16593 type: "String"
16594 },
16595 {
16596 name: "operationRef",
16597 type: "Operation",
16598 isAttr: true,
16599 isReference: true
16600 }
16601 ]
16602 },
16603 {
16604 name: "SubProcess",
16605 superClass: [
16606 "Activity",
16607 "FlowElementsContainer",
16608 "InteractionNode"
16609 ],
16610 properties: [
16611 {
16612 name: "triggeredByEvent",
16613 "default": false,
16614 isAttr: true,
16615 type: "Boolean"
16616 },
16617 {
16618 name: "artifacts",
16619 type: "Artifact",
16620 isMany: true
16621 }
16622 ]
16623 },
16624 {
16625 name: "LoopCharacteristics",
16626 isAbstract: true,
16627 superClass: [
16628 "BaseElement"
16629 ]
16630 },
16631 {
16632 name: "MultiInstanceLoopCharacteristics",
16633 superClass: [
16634 "LoopCharacteristics"
16635 ],
16636 properties: [
16637 {
16638 name: "isSequential",
16639 "default": false,
16640 isAttr: true,
16641 type: "Boolean"
16642 },
16643 {
16644 name: "behavior",
16645 type: "MultiInstanceBehavior",
16646 "default": "All",
16647 isAttr: true
16648 },
16649 {
16650 name: "loopCardinality",
16651 type: "Expression",
16652 xml: {
16653 serialize: "xsi:type"
16654 }
16655 },
16656 {
16657 name: "loopDataInputRef",
16658 type: "ItemAwareElement",
16659 isReference: true
16660 },
16661 {
16662 name: "loopDataOutputRef",
16663 type: "ItemAwareElement",
16664 isReference: true
16665 },
16666 {
16667 name: "inputDataItem",
16668 type: "DataInput",
16669 xml: {
16670 serialize: "property"
16671 }
16672 },
16673 {
16674 name: "outputDataItem",
16675 type: "DataOutput",
16676 xml: {
16677 serialize: "property"
16678 }
16679 },
16680 {
16681 name: "complexBehaviorDefinition",
16682 type: "ComplexBehaviorDefinition",
16683 isMany: true
16684 },
16685 {
16686 name: "completionCondition",
16687 type: "Expression",
16688 xml: {
16689 serialize: "xsi:type"
16690 }
16691 },
16692 {
16693 name: "oneBehaviorEventRef",
16694 type: "EventDefinition",
16695 isAttr: true,
16696 isReference: true
16697 },
16698 {
16699 name: "noneBehaviorEventRef",
16700 type: "EventDefinition",
16701 isAttr: true,
16702 isReference: true
16703 }
16704 ]
16705 },
16706 {
16707 name: "StandardLoopCharacteristics",
16708 superClass: [
16709 "LoopCharacteristics"
16710 ],
16711 properties: [
16712 {
16713 name: "testBefore",
16714 "default": false,
16715 isAttr: true,
16716 type: "Boolean"
16717 },
16718 {
16719 name: "loopCondition",
16720 type: "Expression",
16721 xml: {
16722 serialize: "xsi:type"
16723 }
16724 },
16725 {
16726 name: "loopMaximum",
16727 type: "Integer",
16728 isAttr: true
16729 }
16730 ]
16731 },
16732 {
16733 name: "CallActivity",
16734 superClass: [
16735 "Activity"
16736 ],
16737 properties: [
16738 {
16739 name: "calledElement",
16740 type: "String",
16741 isAttr: true
16742 }
16743 ]
16744 },
16745 {
16746 name: "Task",
16747 superClass: [
16748 "Activity",
16749 "InteractionNode"
16750 ]
16751 },
16752 {
16753 name: "SendTask",
16754 superClass: [
16755 "Task"
16756 ],
16757 properties: [
16758 {
16759 name: "implementation",
16760 isAttr: true,
16761 type: "String"
16762 },
16763 {
16764 name: "operationRef",
16765 type: "Operation",
16766 isAttr: true,
16767 isReference: true
16768 },
16769 {
16770 name: "messageRef",
16771 type: "Message",
16772 isAttr: true,
16773 isReference: true
16774 }
16775 ]
16776 },
16777 {
16778 name: "ReceiveTask",
16779 superClass: [
16780 "Task"
16781 ],
16782 properties: [
16783 {
16784 name: "implementation",
16785 isAttr: true,
16786 type: "String"
16787 },
16788 {
16789 name: "instantiate",
16790 "default": false,
16791 isAttr: true,
16792 type: "Boolean"
16793 },
16794 {
16795 name: "operationRef",
16796 type: "Operation",
16797 isAttr: true,
16798 isReference: true
16799 },
16800 {
16801 name: "messageRef",
16802 type: "Message",
16803 isAttr: true,
16804 isReference: true
16805 }
16806 ]
16807 },
16808 {
16809 name: "ScriptTask",
16810 superClass: [
16811 "Task"
16812 ],
16813 properties: [
16814 {
16815 name: "scriptFormat",
16816 isAttr: true,
16817 type: "String"
16818 },
16819 {
16820 name: "script",
16821 type: "String"
16822 }
16823 ]
16824 },
16825 {
16826 name: "BusinessRuleTask",
16827 superClass: [
16828 "Task"
16829 ],
16830 properties: [
16831 {
16832 name: "implementation",
16833 isAttr: true,
16834 type: "String"
16835 }
16836 ]
16837 },
16838 {
16839 name: "AdHocSubProcess",
16840 superClass: [
16841 "SubProcess"
16842 ],
16843 properties: [
16844 {
16845 name: "completionCondition",
16846 type: "Expression",
16847 xml: {
16848 serialize: "xsi:type"
16849 }
16850 },
16851 {
16852 name: "ordering",
16853 type: "AdHocOrdering",
16854 isAttr: true
16855 },
16856 {
16857 name: "cancelRemainingInstances",
16858 "default": true,
16859 isAttr: true,
16860 type: "Boolean"
16861 }
16862 ]
16863 },
16864 {
16865 name: "Transaction",
16866 superClass: [
16867 "SubProcess"
16868 ],
16869 properties: [
16870 {
16871 name: "protocol",
16872 isAttr: true,
16873 type: "String"
16874 },
16875 {
16876 name: "method",
16877 isAttr: true,
16878 type: "String"
16879 }
16880 ]
16881 },
16882 {
16883 name: "GlobalScriptTask",
16884 superClass: [
16885 "GlobalTask"
16886 ],
16887 properties: [
16888 {
16889 name: "scriptLanguage",
16890 isAttr: true,
16891 type: "String"
16892 },
16893 {
16894 name: "script",
16895 isAttr: true,
16896 type: "String"
16897 }
16898 ]
16899 },
16900 {
16901 name: "GlobalBusinessRuleTask",
16902 superClass: [
16903 "GlobalTask"
16904 ],
16905 properties: [
16906 {
16907 name: "implementation",
16908 isAttr: true,
16909 type: "String"
16910 }
16911 ]
16912 },
16913 {
16914 name: "ComplexBehaviorDefinition",
16915 superClass: [
16916 "BaseElement"
16917 ],
16918 properties: [
16919 {
16920 name: "condition",
16921 type: "FormalExpression"
16922 },
16923 {
16924 name: "event",
16925 type: "ImplicitThrowEvent"
16926 }
16927 ]
16928 },
16929 {
16930 name: "ResourceRole",
16931 superClass: [
16932 "BaseElement"
16933 ],
16934 properties: [
16935 {
16936 name: "resourceRef",
16937 type: "Resource",
16938 isReference: true
16939 },
16940 {
16941 name: "resourceParameterBindings",
16942 type: "ResourceParameterBinding",
16943 isMany: true
16944 },
16945 {
16946 name: "resourceAssignmentExpression",
16947 type: "ResourceAssignmentExpression"
16948 },
16949 {
16950 name: "name",
16951 isAttr: true,
16952 type: "String"
16953 }
16954 ]
16955 },
16956 {
16957 name: "ResourceParameterBinding",
16958 properties: [
16959 {
16960 name: "expression",
16961 type: "Expression",
16962 xml: {
16963 serialize: "xsi:type"
16964 }
16965 },
16966 {
16967 name: "parameterRef",
16968 type: "ResourceParameter",
16969 isAttr: true,
16970 isReference: true
16971 }
16972 ],
16973 superClass: [
16974 "BaseElement"
16975 ]
16976 },
16977 {
16978 name: "ResourceAssignmentExpression",
16979 properties: [
16980 {
16981 name: "expression",
16982 type: "Expression",
16983 xml: {
16984 serialize: "xsi:type"
16985 }
16986 }
16987 ],
16988 superClass: [
16989 "BaseElement"
16990 ]
16991 },
16992 {
16993 name: "Import",
16994 properties: [
16995 {
16996 name: "importType",
16997 isAttr: true,
16998 type: "String"
16999 },
17000 {
17001 name: "location",
17002 isAttr: true,
17003 type: "String"
17004 },
17005 {
17006 name: "namespace",
17007 isAttr: true,
17008 type: "String"
17009 }
17010 ]
17011 },
17012 {
17013 name: "Definitions",
17014 superClass: [
17015 "BaseElement"
17016 ],
17017 properties: [
17018 {
17019 name: "name",
17020 isAttr: true,
17021 type: "String"
17022 },
17023 {
17024 name: "targetNamespace",
17025 isAttr: true,
17026 type: "String"
17027 },
17028 {
17029 name: "expressionLanguage",
17030 "default": "http://www.w3.org/1999/XPath",
17031 isAttr: true,
17032 type: "String"
17033 },
17034 {
17035 name: "typeLanguage",
17036 "default": "http://www.w3.org/2001/XMLSchema",
17037 isAttr: true,
17038 type: "String"
17039 },
17040 {
17041 name: "imports",
17042 type: "Import",
17043 isMany: true
17044 },
17045 {
17046 name: "extensions",
17047 type: "Extension",
17048 isMany: true
17049 },
17050 {
17051 name: "rootElements",
17052 type: "RootElement",
17053 isMany: true
17054 },
17055 {
17056 name: "diagrams",
17057 isMany: true,
17058 type: "bpmndi:BPMNDiagram"
17059 },
17060 {
17061 name: "exporter",
17062 isAttr: true,
17063 type: "String"
17064 },
17065 {
17066 name: "relationships",
17067 type: "Relationship",
17068 isMany: true
17069 },
17070 {
17071 name: "exporterVersion",
17072 isAttr: true,
17073 type: "String"
17074 }
17075 ]
17076 }
17077 ];
17078 var enumerations = [
17079 {
17080 name: "ProcessType",
17081 literalValues: [
17082 {
17083 name: "None"
17084 },
17085 {
17086 name: "Public"
17087 },
17088 {
17089 name: "Private"
17090 }
17091 ]
17092 },
17093 {
17094 name: "GatewayDirection",
17095 literalValues: [
17096 {
17097 name: "Unspecified"
17098 },
17099 {
17100 name: "Converging"
17101 },
17102 {
17103 name: "Diverging"
17104 },
17105 {
17106 name: "Mixed"
17107 }
17108 ]
17109 },
17110 {
17111 name: "EventBasedGatewayType",
17112 literalValues: [
17113 {
17114 name: "Parallel"
17115 },
17116 {
17117 name: "Exclusive"
17118 }
17119 ]
17120 },
17121 {
17122 name: "RelationshipDirection",
17123 literalValues: [
17124 {
17125 name: "None"
17126 },
17127 {
17128 name: "Forward"
17129 },
17130 {
17131 name: "Backward"
17132 },
17133 {
17134 name: "Both"
17135 }
17136 ]
17137 },
17138 {
17139 name: "ItemKind",
17140 literalValues: [
17141 {
17142 name: "Physical"
17143 },
17144 {
17145 name: "Information"
17146 }
17147 ]
17148 },
17149 {
17150 name: "ChoreographyLoopType",
17151 literalValues: [
17152 {
17153 name: "None"
17154 },
17155 {
17156 name: "Standard"
17157 },
17158 {
17159 name: "MultiInstanceSequential"
17160 },
17161 {
17162 name: "MultiInstanceParallel"
17163 }
17164 ]
17165 },
17166 {
17167 name: "AssociationDirection",
17168 literalValues: [
17169 {
17170 name: "None"
17171 },
17172 {
17173 name: "One"
17174 },
17175 {
17176 name: "Both"
17177 }
17178 ]
17179 },
17180 {
17181 name: "MultiInstanceBehavior",
17182 literalValues: [
17183 {
17184 name: "None"
17185 },
17186 {
17187 name: "One"
17188 },
17189 {
17190 name: "All"
17191 },
17192 {
17193 name: "Complex"
17194 }
17195 ]
17196 },
17197 {
17198 name: "AdHocOrdering",
17199 literalValues: [
17200 {
17201 name: "Parallel"
17202 },
17203 {
17204 name: "Sequential"
17205 }
17206 ]
17207 }
17208 ];
17209 var prefix$1 = "bpmn";
17210 var xml = {
17211 tagAlias: "lowerCase",
17212 typePrefix: "t"
17213 };
17214 var BpmnPackage = {
17215 name: name,
17216 uri: uri,
17217 associations: associations,
17218 types: types$1,
17219 enumerations: enumerations,
17220 prefix: prefix$1,
17221 xml: xml
17222 };
17223
17224 var name$1 = "BPMNDI";
17225 var uri$1 = "http://www.omg.org/spec/BPMN/20100524/DI";
17226 var types$1$1 = [
17227 {
17228 name: "BPMNDiagram",
17229 properties: [
17230 {
17231 name: "plane",
17232 type: "BPMNPlane",
17233 redefines: "di:Diagram#rootElement"
17234 },
17235 {
17236 name: "labelStyle",
17237 type: "BPMNLabelStyle",
17238 isMany: true
17239 }
17240 ],
17241 superClass: [
17242 "di:Diagram"
17243 ]
17244 },
17245 {
17246 name: "BPMNPlane",
17247 properties: [
17248 {
17249 name: "bpmnElement",
17250 isAttr: true,
17251 isReference: true,
17252 type: "bpmn:BaseElement",
17253 redefines: "di:DiagramElement#modelElement"
17254 }
17255 ],
17256 superClass: [
17257 "di:Plane"
17258 ]
17259 },
17260 {
17261 name: "BPMNShape",
17262 properties: [
17263 {
17264 name: "bpmnElement",
17265 isAttr: true,
17266 isReference: true,
17267 type: "bpmn:BaseElement",
17268 redefines: "di:DiagramElement#modelElement"
17269 },
17270 {
17271 name: "isHorizontal",
17272 isAttr: true,
17273 type: "Boolean"
17274 },
17275 {
17276 name: "isExpanded",
17277 isAttr: true,
17278 type: "Boolean"
17279 },
17280 {
17281 name: "isMarkerVisible",
17282 isAttr: true,
17283 type: "Boolean"
17284 },
17285 {
17286 name: "label",
17287 type: "BPMNLabel"
17288 },
17289 {
17290 name: "isMessageVisible",
17291 isAttr: true,
17292 type: "Boolean"
17293 },
17294 {
17295 name: "participantBandKind",
17296 type: "ParticipantBandKind",
17297 isAttr: true
17298 },
17299 {
17300 name: "choreographyActivityShape",
17301 type: "BPMNShape",
17302 isAttr: true,
17303 isReference: true
17304 }
17305 ],
17306 superClass: [
17307 "di:LabeledShape"
17308 ]
17309 },
17310 {
17311 name: "BPMNEdge",
17312 properties: [
17313 {
17314 name: "label",
17315 type: "BPMNLabel"
17316 },
17317 {
17318 name: "bpmnElement",
17319 isAttr: true,
17320 isReference: true,
17321 type: "bpmn:BaseElement",
17322 redefines: "di:DiagramElement#modelElement"
17323 },
17324 {
17325 name: "sourceElement",
17326 isAttr: true,
17327 isReference: true,
17328 type: "di:DiagramElement",
17329 redefines: "di:Edge#source"
17330 },
17331 {
17332 name: "targetElement",
17333 isAttr: true,
17334 isReference: true,
17335 type: "di:DiagramElement",
17336 redefines: "di:Edge#target"
17337 },
17338 {
17339 name: "messageVisibleKind",
17340 type: "MessageVisibleKind",
17341 isAttr: true,
17342 "default": "initiating"
17343 }
17344 ],
17345 superClass: [
17346 "di:LabeledEdge"
17347 ]
17348 },
17349 {
17350 name: "BPMNLabel",
17351 properties: [
17352 {
17353 name: "labelStyle",
17354 type: "BPMNLabelStyle",
17355 isAttr: true,
17356 isReference: true,
17357 redefines: "di:DiagramElement#style"
17358 }
17359 ],
17360 superClass: [
17361 "di:Label"
17362 ]
17363 },
17364 {
17365 name: "BPMNLabelStyle",
17366 properties: [
17367 {
17368 name: "font",
17369 type: "dc:Font"
17370 }
17371 ],
17372 superClass: [
17373 "di:Style"
17374 ]
17375 }
17376 ];
17377 var enumerations$1 = [
17378 {
17379 name: "ParticipantBandKind",
17380 literalValues: [
17381 {
17382 name: "top_initiating"
17383 },
17384 {
17385 name: "middle_initiating"
17386 },
17387 {
17388 name: "bottom_initiating"
17389 },
17390 {
17391 name: "top_non_initiating"
17392 },
17393 {
17394 name: "middle_non_initiating"
17395 },
17396 {
17397 name: "bottom_non_initiating"
17398 }
17399 ]
17400 },
17401 {
17402 name: "MessageVisibleKind",
17403 literalValues: [
17404 {
17405 name: "initiating"
17406 },
17407 {
17408 name: "non_initiating"
17409 }
17410 ]
17411 }
17412 ];
17413 var associations$1 = [
17414 ];
17415 var prefix$1$1 = "bpmndi";
17416 var BpmnDiPackage = {
17417 name: name$1,
17418 uri: uri$1,
17419 types: types$1$1,
17420 enumerations: enumerations$1,
17421 associations: associations$1,
17422 prefix: prefix$1$1
17423 };
17424
17425 var name$2 = "DC";
17426 var uri$2 = "http://www.omg.org/spec/DD/20100524/DC";
17427 var types$2 = [
17428 {
17429 name: "Boolean"
17430 },
17431 {
17432 name: "Integer"
17433 },
17434 {
17435 name: "Real"
17436 },
17437 {
17438 name: "String"
17439 },
17440 {
17441 name: "Font",
17442 properties: [
17443 {
17444 name: "name",
17445 type: "String",
17446 isAttr: true
17447 },
17448 {
17449 name: "size",
17450 type: "Real",
17451 isAttr: true
17452 },
17453 {
17454 name: "isBold",
17455 type: "Boolean",
17456 isAttr: true
17457 },
17458 {
17459 name: "isItalic",
17460 type: "Boolean",
17461 isAttr: true
17462 },
17463 {
17464 name: "isUnderline",
17465 type: "Boolean",
17466 isAttr: true
17467 },
17468 {
17469 name: "isStrikeThrough",
17470 type: "Boolean",
17471 isAttr: true
17472 }
17473 ]
17474 },
17475 {
17476 name: "Point",
17477 properties: [
17478 {
17479 name: "x",
17480 type: "Real",
17481 "default": "0",
17482 isAttr: true
17483 },
17484 {
17485 name: "y",
17486 type: "Real",
17487 "default": "0",
17488 isAttr: true
17489 }
17490 ]
17491 },
17492 {
17493 name: "Bounds",
17494 properties: [
17495 {
17496 name: "x",
17497 type: "Real",
17498 "default": "0",
17499 isAttr: true
17500 },
17501 {
17502 name: "y",
17503 type: "Real",
17504 "default": "0",
17505 isAttr: true
17506 },
17507 {
17508 name: "width",
17509 type: "Real",
17510 isAttr: true
17511 },
17512 {
17513 name: "height",
17514 type: "Real",
17515 isAttr: true
17516 }
17517 ]
17518 }
17519 ];
17520 var prefix$2 = "dc";
17521 var associations$2 = [
17522 ];
17523 var DcPackage = {
17524 name: name$2,
17525 uri: uri$2,
17526 types: types$2,
17527 prefix: prefix$2,
17528 associations: associations$2
17529 };
17530
17531 var name$3 = "DI";
17532 var uri$3 = "http://www.omg.org/spec/DD/20100524/DI";
17533 var types$3 = [
17534 {
17535 name: "DiagramElement",
17536 isAbstract: true,
17537 properties: [
17538 {
17539 name: "id",
17540 type: "String",
17541 isAttr: true,
17542 isId: true
17543 },
17544 {
17545 name: "extension",
17546 type: "Extension"
17547 },
17548 {
17549 name: "owningDiagram",
17550 type: "Diagram",
17551 isReadOnly: true,
17552 isVirtual: true,
17553 isReference: true
17554 },
17555 {
17556 name: "owningElement",
17557 type: "DiagramElement",
17558 isReadOnly: true,
17559 isVirtual: true,
17560 isReference: true
17561 },
17562 {
17563 name: "modelElement",
17564 isReadOnly: true,
17565 isVirtual: true,
17566 isReference: true,
17567 type: "Element"
17568 },
17569 {
17570 name: "style",
17571 type: "Style",
17572 isReadOnly: true,
17573 isVirtual: true,
17574 isReference: true
17575 },
17576 {
17577 name: "ownedElement",
17578 type: "DiagramElement",
17579 isReadOnly: true,
17580 isVirtual: true,
17581 isMany: true
17582 }
17583 ]
17584 },
17585 {
17586 name: "Node",
17587 isAbstract: true,
17588 superClass: [
17589 "DiagramElement"
17590 ]
17591 },
17592 {
17593 name: "Edge",
17594 isAbstract: true,
17595 superClass: [
17596 "DiagramElement"
17597 ],
17598 properties: [
17599 {
17600 name: "source",
17601 type: "DiagramElement",
17602 isReadOnly: true,
17603 isVirtual: true,
17604 isReference: true
17605 },
17606 {
17607 name: "target",
17608 type: "DiagramElement",
17609 isReadOnly: true,
17610 isVirtual: true,
17611 isReference: true
17612 },
17613 {
17614 name: "waypoint",
17615 isUnique: false,
17616 isMany: true,
17617 type: "dc:Point",
17618 xml: {
17619 serialize: "xsi:type"
17620 }
17621 }
17622 ]
17623 },
17624 {
17625 name: "Diagram",
17626 isAbstract: true,
17627 properties: [
17628 {
17629 name: "id",
17630 type: "String",
17631 isAttr: true,
17632 isId: true
17633 },
17634 {
17635 name: "rootElement",
17636 type: "DiagramElement",
17637 isReadOnly: true,
17638 isVirtual: true
17639 },
17640 {
17641 name: "name",
17642 isAttr: true,
17643 type: "String"
17644 },
17645 {
17646 name: "documentation",
17647 isAttr: true,
17648 type: "String"
17649 },
17650 {
17651 name: "resolution",
17652 isAttr: true,
17653 type: "Real"
17654 },
17655 {
17656 name: "ownedStyle",
17657 type: "Style",
17658 isReadOnly: true,
17659 isVirtual: true,
17660 isMany: true
17661 }
17662 ]
17663 },
17664 {
17665 name: "Shape",
17666 isAbstract: true,
17667 superClass: [
17668 "Node"
17669 ],
17670 properties: [
17671 {
17672 name: "bounds",
17673 type: "dc:Bounds"
17674 }
17675 ]
17676 },
17677 {
17678 name: "Plane",
17679 isAbstract: true,
17680 superClass: [
17681 "Node"
17682 ],
17683 properties: [
17684 {
17685 name: "planeElement",
17686 type: "DiagramElement",
17687 subsettedProperty: "DiagramElement-ownedElement",
17688 isMany: true
17689 }
17690 ]
17691 },
17692 {
17693 name: "LabeledEdge",
17694 isAbstract: true,
17695 superClass: [
17696 "Edge"
17697 ],
17698 properties: [
17699 {
17700 name: "ownedLabel",
17701 type: "Label",
17702 isReadOnly: true,
17703 subsettedProperty: "DiagramElement-ownedElement",
17704 isVirtual: true,
17705 isMany: true
17706 }
17707 ]
17708 },
17709 {
17710 name: "LabeledShape",
17711 isAbstract: true,
17712 superClass: [
17713 "Shape"
17714 ],
17715 properties: [
17716 {
17717 name: "ownedLabel",
17718 type: "Label",
17719 isReadOnly: true,
17720 subsettedProperty: "DiagramElement-ownedElement",
17721 isVirtual: true,
17722 isMany: true
17723 }
17724 ]
17725 },
17726 {
17727 name: "Label",
17728 isAbstract: true,
17729 superClass: [
17730 "Node"
17731 ],
17732 properties: [
17733 {
17734 name: "bounds",
17735 type: "dc:Bounds"
17736 }
17737 ]
17738 },
17739 {
17740 name: "Style",
17741 isAbstract: true,
17742 properties: [
17743 {
17744 name: "id",
17745 type: "String",
17746 isAttr: true,
17747 isId: true
17748 }
17749 ]
17750 },
17751 {
17752 name: "Extension",
17753 properties: [
17754 {
17755 name: "values",
17756 type: "Element",
17757 isMany: true
17758 }
17759 ]
17760 }
17761 ];
17762 var associations$3 = [
17763 ];
17764 var prefix$3 = "di";
17765 var xml$1 = {
17766 tagAlias: "lowerCase"
17767 };
17768 var DiPackage = {
17769 name: name$3,
17770 uri: uri$3,
17771 types: types$3,
17772 associations: associations$3,
17773 prefix: prefix$3,
17774 xml: xml$1
17775 };
17776
17777 var name$4 = "bpmn.io colors for BPMN";
17778 var uri$4 = "http://bpmn.io/schema/bpmn/biocolor/1.0";
17779 var prefix$4 = "bioc";
17780 var types$4 = [
17781 {
17782 name: "ColoredShape",
17783 "extends": [
17784 "bpmndi:BPMNShape"
17785 ],
17786 properties: [
17787 {
17788 name: "stroke",
17789 isAttr: true,
17790 type: "String"
17791 },
17792 {
17793 name: "fill",
17794 isAttr: true,
17795 type: "String"
17796 }
17797 ]
17798 },
17799 {
17800 name: "ColoredEdge",
17801 "extends": [
17802 "bpmndi:BPMNEdge"
17803 ],
17804 properties: [
17805 {
17806 name: "stroke",
17807 isAttr: true,
17808 type: "String"
17809 },
17810 {
17811 name: "fill",
17812 isAttr: true,
17813 type: "String"
17814 }
17815 ]
17816 }
17817 ];
17818 var enumerations$2 = [
17819 ];
17820 var associations$4 = [
17821 ];
17822 var BiocPackage = {
17823 name: name$4,
17824 uri: uri$4,
17825 prefix: prefix$4,
17826 types: types$4,
17827 enumerations: enumerations$2,
17828 associations: associations$4
17829 };
17830
17831 var packages = {
17832 bpmn: BpmnPackage,
17833 bpmndi: BpmnDiPackage,
17834 dc: DcPackage,
17835 di: DiPackage,
17836 bioc: BiocPackage
17837 };
17838
17839 function simple(additionalPackages, options) {
17840 var pks = assign({}, packages, additionalPackages);
17841
17842 return new BpmnModdle(pks, options);
17843 }
17844
17845 var diRefs = new objectRefs(
17846 { name: 'bpmnElement', enumerable: true },
17847 { name: 'di', configurable: true }
17848 );
17849
17850 /**
17851 * Returns true if an element has the given meta-model type
17852 *
17853 * @param {ModdleElement} element
17854 * @param {String} type
17855 *
17856 * @return {Boolean}
17857 */
17858 function is$1(element, type) {
17859 return element.$instanceOf(type);
17860 }
17861
17862
17863 /**
17864 * Find a suitable display candidate for definitions where the DI does not
17865 * correctly specify one.
17866 */
17867 function findDisplayCandidate(definitions) {
17868 return find(definitions.rootElements, function(e) {
17869 return is$1(e, 'bpmn:Process') || is$1(e, 'bpmn:Collaboration');
17870 });
17871 }
17872
17873
17874 function BpmnTreeWalker(handler, translate) {
17875
17876 // list of containers already walked
17877 var handledElements = {};
17878
17879 // list of elements to handle deferred to ensure
17880 // prerequisites are drawn
17881 var deferred = [];
17882
17883 // Helpers //////////////////////
17884
17885 function contextual(fn, ctx) {
17886 return function(e) {
17887 fn(e, ctx);
17888 };
17889 }
17890
17891 function handled(element) {
17892 handledElements[element.id] = element;
17893 }
17894
17895 function isHandled(element) {
17896 return handledElements[element.id];
17897 }
17898
17899 function visit(element, ctx) {
17900
17901 var gfx = element.gfx;
17902
17903 // avoid multiple rendering of elements
17904 if (gfx) {
17905 throw new Error(
17906 translate('already rendered {element}', { element: elementToString(element) })
17907 );
17908 }
17909
17910 // call handler
17911 return handler.element(element, ctx);
17912 }
17913
17914 function visitRoot(element, diagram) {
17915 return handler.root(element, diagram);
17916 }
17917
17918 function visitIfDi(element, ctx) {
17919
17920 try {
17921 var gfx = element.di && visit(element, ctx);
17922
17923 handled(element);
17924
17925 return gfx;
17926 } catch (e) {
17927 logError(e.message, { element: element, error: e });
17928
17929 console.error(translate('failed to import {element}', { element: elementToString(element) }));
17930 console.error(e);
17931 }
17932 }
17933
17934 function logError(message, context) {
17935 handler.error(message, context);
17936 }
17937
17938 // DI handling //////////////////////
17939
17940 function registerDi(di) {
17941 var bpmnElement = di.bpmnElement;
17942
17943 if (bpmnElement) {
17944 if (bpmnElement.di) {
17945 logError(
17946 translate('multiple DI elements defined for {element}', {
17947 element: elementToString(bpmnElement)
17948 }),
17949 { element: bpmnElement }
17950 );
17951 } else {
17952 diRefs.bind(bpmnElement, 'di');
17953 bpmnElement.di = di;
17954 }
17955 } else {
17956 logError(
17957 translate('no bpmnElement referenced in {element}', {
17958 element: elementToString(di)
17959 }),
17960 { element: di }
17961 );
17962 }
17963 }
17964
17965 function handleDiagram(diagram) {
17966 handlePlane(diagram.plane);
17967 }
17968
17969 function handlePlane(plane) {
17970 registerDi(plane);
17971
17972 forEach(plane.planeElement, handlePlaneElement);
17973 }
17974
17975 function handlePlaneElement(planeElement) {
17976 registerDi(planeElement);
17977 }
17978
17979
17980 // Semantic handling //////////////////////
17981
17982 /**
17983 * Handle definitions and return the rendered diagram (if any)
17984 *
17985 * @param {ModdleElement} definitions to walk and import
17986 * @param {ModdleElement} [diagram] specific diagram to import and display
17987 *
17988 * @throws {Error} if no diagram to display could be found
17989 */
17990 function handleDefinitions(definitions, diagram) {
17991
17992 // make sure we walk the correct bpmnElement
17993
17994 var diagrams = definitions.diagrams;
17995
17996 if (diagram && diagrams.indexOf(diagram) === -1) {
17997 throw new Error(translate('diagram not part of bpmn:Definitions'));
17998 }
17999
18000 if (!diagram && diagrams && diagrams.length) {
18001 diagram = diagrams[0];
18002 }
18003
18004 // no diagram -> nothing to import
18005 if (!diagram) {
18006 throw new Error(translate('no diagram to display'));
18007 }
18008
18009 // load DI from selected diagram only
18010 handleDiagram(diagram);
18011
18012
18013 var plane = diagram.plane;
18014
18015 if (!plane) {
18016 throw new Error(translate(
18017 'no plane for {element}',
18018 { element: elementToString(diagram) }
18019 ));
18020 }
18021
18022 var rootElement = plane.bpmnElement;
18023
18024 // ensure we default to a suitable display candidate (process or collaboration),
18025 // even if non is specified in DI
18026 if (!rootElement) {
18027 rootElement = findDisplayCandidate(definitions);
18028
18029 if (!rootElement) {
18030 throw new Error(translate('no process or collaboration to display'));
18031 } else {
18032
18033 logError(
18034 translate('correcting missing bpmnElement on {plane} to {rootElement}', {
18035 plane: elementToString(plane),
18036 rootElement: elementToString(rootElement)
18037 })
18038 );
18039
18040 // correct DI on the fly
18041 plane.bpmnElement = rootElement;
18042 registerDi(plane);
18043 }
18044 }
18045
18046
18047 var ctx = visitRoot(rootElement, plane);
18048
18049 if (is$1(rootElement, 'bpmn:Process')) {
18050 handleProcess(rootElement, ctx);
18051 } else if (is$1(rootElement, 'bpmn:Collaboration')) {
18052 handleCollaboration(rootElement);
18053
18054 // force drawing of everything not yet drawn that is part of the target DI
18055 handleUnhandledProcesses(definitions.rootElements, ctx);
18056 } else {
18057 throw new Error(
18058 translate('unsupported bpmnElement for {plane}: {rootElement}', {
18059 plane: elementToString(plane),
18060 rootElement: elementToString(rootElement)
18061 })
18062 );
18063 }
18064
18065 // handle all deferred elements
18066 handleDeferred();
18067 }
18068
18069 function handleDeferred() {
18070
18071 var fn;
18072
18073 // drain deferred until empty
18074 while (deferred.length) {
18075 fn = deferred.shift();
18076
18077 fn();
18078 }
18079 }
18080
18081 function handleProcess(process, context) {
18082 handleFlowElementsContainer(process, context);
18083 handleIoSpecification(process.ioSpecification, context);
18084
18085 handleArtifacts(process.artifacts, context);
18086
18087 // log process handled
18088 handled(process);
18089 }
18090
18091 function handleUnhandledProcesses(rootElements, ctx) {
18092
18093 // walk through all processes that have not yet been drawn and draw them
18094 // if they contain lanes with DI information.
18095 // we do this to pass the free-floating lane test cases in the MIWG test suite
18096 var processes = filter(rootElements, function(e) {
18097 return !isHandled(e) && is$1(e, 'bpmn:Process') && e.laneSets;
18098 });
18099
18100 processes.forEach(contextual(handleProcess, ctx));
18101 }
18102
18103 function handleMessageFlow(messageFlow, context) {
18104 visitIfDi(messageFlow, context);
18105 }
18106
18107 function handleMessageFlows(messageFlows, context) {
18108 forEach(messageFlows, contextual(handleMessageFlow, context));
18109 }
18110
18111 function handleDataAssociation(association, context) {
18112 visitIfDi(association, context);
18113 }
18114
18115 function handleDataInput(dataInput, context) {
18116 visitIfDi(dataInput, context);
18117 }
18118
18119 function handleDataOutput(dataOutput, context) {
18120 visitIfDi(dataOutput, context);
18121 }
18122
18123 function handleArtifact(artifact, context) {
18124
18125 // bpmn:TextAnnotation
18126 // bpmn:Group
18127 // bpmn:Association
18128
18129 visitIfDi(artifact, context);
18130 }
18131
18132 function handleArtifacts(artifacts, context) {
18133
18134 forEach(artifacts, function(e) {
18135 if (is$1(e, 'bpmn:Association')) {
18136 deferred.push(function() {
18137 handleArtifact(e, context);
18138 });
18139 } else {
18140 handleArtifact(e, context);
18141 }
18142 });
18143 }
18144
18145 function handleIoSpecification(ioSpecification, context) {
18146
18147 if (!ioSpecification) {
18148 return;
18149 }
18150
18151 forEach(ioSpecification.dataInputs, contextual(handleDataInput, context));
18152 forEach(ioSpecification.dataOutputs, contextual(handleDataOutput, context));
18153 }
18154
18155 function handleSubProcess(subProcess, context) {
18156 handleFlowElementsContainer(subProcess, context);
18157 handleArtifacts(subProcess.artifacts, context);
18158 }
18159
18160 function handleFlowNode(flowNode, context) {
18161 var childCtx = visitIfDi(flowNode, context);
18162
18163 if (is$1(flowNode, 'bpmn:SubProcess')) {
18164 handleSubProcess(flowNode, childCtx || context);
18165 }
18166
18167 if (is$1(flowNode, 'bpmn:Activity')) {
18168 handleIoSpecification(flowNode.ioSpecification, context);
18169 }
18170
18171 // defer handling of associations
18172 // affected types:
18173 //
18174 // * bpmn:Activity
18175 // * bpmn:ThrowEvent
18176 // * bpmn:CatchEvent
18177 //
18178 deferred.push(function() {
18179 forEach(flowNode.dataInputAssociations, contextual(handleDataAssociation, context));
18180 forEach(flowNode.dataOutputAssociations, contextual(handleDataAssociation, context));
18181 });
18182 }
18183
18184 function handleSequenceFlow(sequenceFlow, context) {
18185 visitIfDi(sequenceFlow, context);
18186 }
18187
18188 function handleDataElement(dataObject, context) {
18189 visitIfDi(dataObject, context);
18190 }
18191
18192 function handleLane(lane, context) {
18193
18194 deferred.push(function() {
18195
18196 var newContext = visitIfDi(lane, context);
18197
18198 if (lane.childLaneSet) {
18199 handleLaneSet(lane.childLaneSet, newContext || context);
18200 }
18201
18202 wireFlowNodeRefs(lane);
18203 });
18204 }
18205
18206 function handleLaneSet(laneSet, context) {
18207 forEach(laneSet.lanes, contextual(handleLane, context));
18208 }
18209
18210 function handleLaneSets(laneSets, context) {
18211 forEach(laneSets, contextual(handleLaneSet, context));
18212 }
18213
18214 function handleFlowElementsContainer(container, context) {
18215 handleFlowElements(container.flowElements, context);
18216
18217 if (container.laneSets) {
18218 handleLaneSets(container.laneSets, context);
18219 }
18220 }
18221
18222 function handleFlowElements(flowElements, context) {
18223 forEach(flowElements, function(e) {
18224 if (is$1(e, 'bpmn:SequenceFlow')) {
18225 deferred.push(function() {
18226 handleSequenceFlow(e, context);
18227 });
18228 } else if (is$1(e, 'bpmn:BoundaryEvent')) {
18229 deferred.unshift(function() {
18230 handleFlowNode(e, context);
18231 });
18232 } else if (is$1(e, 'bpmn:FlowNode')) {
18233 handleFlowNode(e, context);
18234 } else if (is$1(e, 'bpmn:DataObject')) ; else if (is$1(e, 'bpmn:DataStoreReference')) {
18235 handleDataElement(e, context);
18236 } else if (is$1(e, 'bpmn:DataObjectReference')) {
18237 handleDataElement(e, context);
18238 } else {
18239 logError(
18240 translate('unrecognized flowElement {element} in context {context}', {
18241 element: elementToString(e),
18242 context: (context ? elementToString(context.businessObject) : 'null')
18243 }),
18244 { element: e, context: context }
18245 );
18246 }
18247 });
18248 }
18249
18250 function handleParticipant(participant, context) {
18251 var newCtx = visitIfDi(participant, context);
18252
18253 var process = participant.processRef;
18254 if (process) {
18255 handleProcess(process, newCtx || context);
18256 }
18257 }
18258
18259 function handleCollaboration(collaboration) {
18260
18261 forEach(collaboration.participants, contextual(handleParticipant));
18262
18263 handleArtifacts(collaboration.artifacts);
18264
18265 // handle message flows latest in the process
18266 deferred.push(function() {
18267 handleMessageFlows(collaboration.messageFlows);
18268 });
18269 }
18270
18271
18272 function wireFlowNodeRefs(lane) {
18273
18274 // wire the virtual flowNodeRefs <-> relationship
18275 forEach(lane.flowNodeRef, function(flowNode) {
18276 var lanes = flowNode.get('lanes');
18277
18278 if (lanes) {
18279 lanes.push(lane);
18280 }
18281 });
18282 }
18283
18284 // API //////////////////////
18285
18286 return {
18287 handleDeferred: handleDeferred,
18288 handleDefinitions: handleDefinitions,
18289 handleSubProcess: handleSubProcess,
18290 registerDi: registerDi
18291 };
18292 }
18293
18294 /**
18295 * Import the definitions into a diagram.
18296 *
18297 * Errors and warnings are reported through the specified callback.
18298 *
18299 * @param {djs.Diagram} diagram
18300 * @param {ModdleElement<Definitions>} definitions
18301 * @param {ModdleElement<BPMNDiagram>} [bpmnDiagram] the diagram to be rendered
18302 * (if not provided, the first one will be rendered)
18303 * @param {Function} done the callback, invoked with (err, [ warning ]) once the import is done
18304 */
18305 function importBpmnDiagram(diagram, definitions, bpmnDiagram, done) {
18306
18307 if (isFunction(bpmnDiagram)) {
18308 done = bpmnDiagram;
18309 bpmnDiagram = null;
18310 }
18311
18312 var importer,
18313 eventBus,
18314 translate;
18315
18316 var error,
18317 warnings = [];
18318
18319 /**
18320 * Walk the diagram semantically, importing (=drawing)
18321 * all elements you encounter.
18322 *
18323 * @param {ModdleElement<Definitions>} definitions
18324 * @param {ModdleElement<BPMNDiagram>} bpmnDiagram
18325 */
18326 function render(definitions, bpmnDiagram) {
18327
18328 var visitor = {
18329
18330 root: function(element) {
18331 return importer.add(element);
18332 },
18333
18334 element: function(element, parentShape) {
18335 return importer.add(element, parentShape);
18336 },
18337
18338 error: function(message, context) {
18339 warnings.push({ message: message, context: context });
18340 }
18341 };
18342
18343 var walker = new BpmnTreeWalker(visitor, translate);
18344
18345 // traverse BPMN 2.0 document model,
18346 // starting at definitions
18347 walker.handleDefinitions(definitions, bpmnDiagram);
18348 }
18349
18350 try {
18351 importer = diagram.get('bpmnImporter');
18352 eventBus = diagram.get('eventBus');
18353 translate = diagram.get('translate');
18354
18355 eventBus.fire('import.render.start', { definitions: definitions });
18356
18357 render(definitions, bpmnDiagram);
18358
18359 eventBus.fire('import.render.complete', {
18360 error: error,
18361 warnings: warnings
18362 });
18363 } catch (e) {
18364 error = e;
18365 }
18366
18367 done(error, warnings);
18368 }
18369
18370 /**
18371 * This file must not be changed or exchanged.
18372 *
18373 * @see http://bpmn.io/license for more information.
18374 */
18375
18376
18377 // inlined ../../resources/logo.svg
18378 var BPMNIO_LOGO_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 960"><path fill="#fff" d="M960 60v839c0 33-27 61-60 61H60c-33 0-60-27-60-60V60C0 27 27 0 60 0h839c34 0 61 27 61 60z"/><path fill="#52b415" d="M217 548a205 205 0 0 0-144 58 202 202 0 0 0-4 286 202 202 0 0 0 285 3 200 200 0 0 0 48-219 203 203 0 0 0-185-128zM752 6a206 206 0 0 0-192 285 206 206 0 0 0 269 111 207 207 0 0 0 111-260A204 204 0 0 0 752 6zM62 0A62 62 0 0 0 0 62v398l60 46a259 259 0 0 1 89-36c5-28 10-57 14-85l99 2 12 85a246 246 0 0 1 88 38l70-52 69 71-52 68c17 30 29 58 35 90l86 14-2 100-86 12a240 240 0 0 1-38 89l43 58h413c37 0 60-27 60-61V407a220 220 0 0 1-44 40l21 85-93 39-45-76a258 258 0 0 1-98 1l-45 76-94-39 22-85a298 298 0 0 1-70-69l-86 22-38-94 76-45a258 258 0 0 1-1-98l-76-45 40-94 85 22a271 271 0 0 1 41-47z"/></svg>';
18379
18380 var BPMNIO_LOGO_URL = 'data:image/svg+xml,' + encodeURIComponent(BPMNIO_LOGO_SVG);
18381
18382 var BPMNIO_IMG = '<img width="52" height="52" src="' + BPMNIO_LOGO_URL + '" />';
18383
18384 function css(attrs) {
18385 return attrs.join(';');
18386 }
18387
18388 var LIGHTBOX_STYLES = css([
18389 'z-index: 1001',
18390 'position: fixed',
18391 'top: 0',
18392 'left: 0',
18393 'right: 0',
18394 'bottom: 0'
18395 ]);
18396
18397 var BACKDROP_STYLES = css([
18398 'width: 100%',
18399 'height: 100%',
18400 'background: rgba(0,0,0,0.2)'
18401 ]);
18402
18403 var NOTICE_STYLES = css([
18404 'position: absolute',
18405 'left: 50%',
18406 'top: 40%',
18407 'margin: 0 -130px',
18408 'width: 260px',
18409 'padding: 10px',
18410 'background: white',
18411 'border: solid 1px #AAA',
18412 'border-radius: 3px',
18413 'font-family: Helvetica, Arial, sans-serif',
18414 'font-size: 14px',
18415 'line-height: 1.2em'
18416 ]);
18417
18418 var LIGHTBOX_MARKUP =
18419 '<div class="bjs-powered-by-lightbox" style="' + LIGHTBOX_STYLES + '">' +
18420 '<div class="backdrop" style="' + BACKDROP_STYLES + '"></div>' +
18421 '<div class="notice" style="' + NOTICE_STYLES + '">' +
18422 '<a href="http://bpmn.io" target="_blank" style="float: left; margin-right: 10px">' +
18423 BPMNIO_IMG +
18424 '</a>' +
18425 'Web-based tooling for BPMN, DMN and CMMN diagrams ' +
18426 'powered by <a href="http://bpmn.io" target="_blank">bpmn.io</a>.' +
18427 '</div>' +
18428 '</div>';
18429
18430
18431 var lightbox;
18432
18433 function open() {
18434
18435 if (!lightbox) {
18436 lightbox = domify(LIGHTBOX_MARKUP);
18437
18438 delegateEvents.bind(lightbox, '.backdrop', 'click', function(event) {
18439 document.body.removeChild(lightbox);
18440 });
18441 }
18442
18443 document.body.appendChild(lightbox);
18444 }
18445
18446 /**
18447 * The code in the <project-logo></project-logo> area
18448 * must not be changed.
18449 *
18450 * @see http://bpmn.io/license for more information.
18451 */
18452
18453
18454 /**
18455 * A base viewer for BPMN 2.0 diagrams.
18456 *
18457 * Have a look at {@link Viewer}, {@link NavigatedViewer} or {@link Modeler} for
18458 * bundles that include actual features.
18459 *
18460 * @param {Object} [options] configuration options to pass to the viewer
18461 * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
18462 * @param {String|Number} [options.width] the width of the viewer
18463 * @param {String|Number} [options.height] the height of the viewer
18464 * @param {Object} [options.moddleExtensions] extension packages to provide
18465 * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
18466 * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
18467 */
18468 function BaseViewer(options) {
18469
18470 options = assign({}, DEFAULT_OPTIONS, options);
18471
18472 this._moddle = this._createModdle(options);
18473
18474 this._container = this._createContainer(options);
18475
18476 /* <project-logo> */
18477
18478 addProjectLogo(this._container);
18479
18480 /* </project-logo> */
18481
18482 this._init(this._container, this._moddle, options);
18483 }
18484
18485 inherits_browser(BaseViewer, Diagram);
18486
18487
18488 /**
18489 * Parse and render a BPMN 2.0 diagram.
18490 *
18491 * Once finished the viewer reports back the result to the
18492 * provided callback function with (err, warnings).
18493 *
18494 * ## Life-Cycle Events
18495 *
18496 * During import the viewer will fire life-cycle events:
18497 *
18498 * * import.parse.start (about to read model from xml)
18499 * * import.parse.complete (model read; may have worked or not)
18500 * * import.render.start (graphical import start)
18501 * * import.render.complete (graphical import finished)
18502 * * import.done (everything done)
18503 *
18504 * You can use these events to hook into the life-cycle.
18505 *
18506 * @param {String} xml the BPMN 2.0 xml
18507 * @param {ModdleElement<BPMNDiagram>|String} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
18508 * @param {Function} [done] invoked with (err, warnings=[])
18509 */
18510 BaseViewer.prototype.importXML = function(xml, bpmnDiagram, done) {
18511
18512 if (isFunction(bpmnDiagram)) {
18513 done = bpmnDiagram;
18514 bpmnDiagram = null;
18515 }
18516
18517 // done is optional
18518 done = done || function() {};
18519
18520 var self = this;
18521
18522 // hook in pre-parse listeners +
18523 // allow xml manipulation
18524 xml = this._emit('import.parse.start', { xml: xml }) || xml;
18525
18526 this._moddle.fromXML(xml, 'bpmn:Definitions', function(err, definitions, context) {
18527
18528 // hook in post parse listeners +
18529 // allow definitions manipulation
18530 definitions = self._emit('import.parse.complete', {
18531 error: err,
18532 definitions: definitions,
18533 context: context
18534 }) || definitions;
18535
18536 var parseWarnings = context.warnings;
18537
18538 if (err) {
18539 err = checkValidationError(err);
18540
18541 self._emit('import.done', { error: err, warnings: parseWarnings });
18542
18543 return done(err, parseWarnings);
18544 }
18545
18546 self.importDefinitions(definitions, bpmnDiagram, function(err, importWarnings) {
18547 var allWarnings = [].concat(parseWarnings, importWarnings || []);
18548
18549 self._emit('import.done', { error: err, warnings: allWarnings });
18550
18551 done(err, allWarnings);
18552 });
18553 });
18554 };
18555
18556 /**
18557 * Import parsed definitions and render a BPMN 2.0 diagram.
18558 *
18559 * Once finished the viewer reports back the result to the
18560 * provided callback function with (err, warnings).
18561 *
18562 * ## Life-Cycle Events
18563 *
18564 * During import the viewer will fire life-cycle events:
18565 *
18566 * * import.render.start (graphical import start)
18567 * * import.render.complete (graphical import finished)
18568 *
18569 * You can use these events to hook into the life-cycle.
18570 *
18571 * @param {ModdleElement<Definitions>} definitions parsed BPMN 2.0 definitions
18572 * @param {ModdleElement<BPMNDiagram>|String} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
18573 * @param {Function} [done] invoked with (err, warnings=[])
18574 */
18575 BaseViewer.prototype.importDefinitions = function(definitions, bpmnDiagram, done) {
18576
18577 if (isFunction(bpmnDiagram)) {
18578 done = bpmnDiagram;
18579 bpmnDiagram = null;
18580 }
18581
18582 // done is optional
18583 done = done || function() {};
18584
18585 this._setDefinitions(definitions);
18586
18587 return this.open(bpmnDiagram, done);
18588 };
18589
18590 /**
18591 * Open diagram of previously imported XML.
18592 *
18593 * Once finished the viewer reports back the result to the
18594 * provided callback function with (err, warnings).
18595 *
18596 * ## Life-Cycle Events
18597 *
18598 * During switch the viewer will fire life-cycle events:
18599 *
18600 * * import.render.start (graphical import start)
18601 * * import.render.complete (graphical import finished)
18602 *
18603 * You can use these events to hook into the life-cycle.
18604 *
18605 * @param {String|ModdleElement<BPMNDiagram>} [bpmnDiagramOrId] id or the diagram to open
18606 * @param {Function} [done] invoked with (err, warnings=[])
18607 */
18608 BaseViewer.prototype.open = function(bpmnDiagramOrId, done) {
18609
18610 if (isFunction(bpmnDiagramOrId)) {
18611 done = bpmnDiagramOrId;
18612 bpmnDiagramOrId = null;
18613 }
18614
18615 var definitions = this._definitions;
18616 var bpmnDiagram = bpmnDiagramOrId;
18617
18618 // done is optional
18619 done = done || function() {};
18620
18621 if (!definitions) {
18622 return done(new Error('no XML imported'));
18623 }
18624
18625 if (typeof bpmnDiagramOrId === 'string') {
18626 bpmnDiagram = findBPMNDiagram(definitions, bpmnDiagramOrId);
18627
18628 if (!bpmnDiagram) {
18629 return done(new Error('BPMNDiagram <' + bpmnDiagramOrId + '> not found'));
18630 }
18631 }
18632
18633 // clear existing rendered diagram
18634 // catch synchronous exceptions during #clear()
18635 try {
18636 this.clear();
18637 } catch (error) {
18638 return done(error);
18639 }
18640
18641 // perform graphical import
18642 return importBpmnDiagram(this, definitions, bpmnDiagram, done);
18643 };
18644
18645 /**
18646 * Export the currently displayed BPMN 2.0 diagram as
18647 * a BPMN 2.0 XML document.
18648 *
18649 * ## Life-Cycle Events
18650 *
18651 * During XML saving the viewer will fire life-cycle events:
18652 *
18653 * * saveXML.start (before serialization)
18654 * * saveXML.serialized (after xml generation)
18655 * * saveXML.done (everything done)
18656 *
18657 * You can use these events to hook into the life-cycle.
18658 *
18659 * @param {Object} [options] export options
18660 * @param {Boolean} [options.format=false] output formatted XML
18661 * @param {Boolean} [options.preamble=true] output preamble
18662 *
18663 * @param {Function} done invoked with (err, xml)
18664 */
18665 BaseViewer.prototype.saveXML = function(options, done) {
18666
18667 if (!done) {
18668 done = options;
18669 options = {};
18670 }
18671
18672 var self = this;
18673
18674 var definitions = this._definitions;
18675
18676 if (!definitions) {
18677 return done(new Error('no definitions loaded'));
18678 }
18679
18680 // allow to fiddle around with definitions
18681 definitions = this._emit('saveXML.start', {
18682 definitions: definitions
18683 }) || definitions;
18684
18685 this._moddle.toXML(definitions, options, function(err, xml) {
18686
18687 try {
18688 xml = self._emit('saveXML.serialized', {
18689 error: err,
18690 xml: xml
18691 }) || xml;
18692
18693 self._emit('saveXML.done', {
18694 error: err,
18695 xml: xml
18696 });
18697 } catch (e) {
18698 console.error('error in saveXML life-cycle listener', e);
18699 }
18700
18701 done(err, xml);
18702 });
18703 };
18704
18705 /**
18706 * Export the currently displayed BPMN 2.0 diagram as
18707 * an SVG image.
18708 *
18709 * ## Life-Cycle Events
18710 *
18711 * During SVG saving the viewer will fire life-cycle events:
18712 *
18713 * * saveSVG.start (before serialization)
18714 * * saveSVG.done (everything done)
18715 *
18716 * You can use these events to hook into the life-cycle.
18717 *
18718 * @param {Object} [options]
18719 * @param {Function} done invoked with (err, svgStr)
18720 */
18721 BaseViewer.prototype.saveSVG = function(options, done) {
18722
18723 if (!done) {
18724 done = options;
18725 options = {};
18726 }
18727
18728 this._emit('saveSVG.start');
18729
18730 var svg, err;
18731
18732 try {
18733 var canvas = this.get('canvas');
18734
18735 var contentNode = canvas.getDefaultLayer(),
18736 defsNode = query('defs', canvas._svg);
18737
18738 var contents = innerSVG(contentNode),
18739 defs = defsNode ? '<defs>' + innerSVG(defsNode) + '</defs>' : '';
18740
18741 var bbox = contentNode.getBBox();
18742
18743 svg =
18744 '<?xml version="1.0" encoding="utf-8"?>\n' +
18745 '<!-- created with bpmn-js / http://bpmn.io -->\n' +
18746 '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
18747 '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
18748 'width="' + bbox.width + '" height="' + bbox.height + '" ' +
18749 'viewBox="' + bbox.x + ' ' + bbox.y + ' ' + bbox.width + ' ' + bbox.height + '" version="1.1">' +
18750 defs + contents +
18751 '</svg>';
18752 } catch (e) {
18753 err = e;
18754 }
18755
18756 this._emit('saveSVG.done', {
18757 error: err,
18758 svg: svg
18759 });
18760
18761 done(err, svg);
18762 };
18763
18764 /**
18765 * Get a named diagram service.
18766 *
18767 * @example
18768 *
18769 * var elementRegistry = viewer.get('elementRegistry');
18770 * var startEventShape = elementRegistry.get('StartEvent_1');
18771 *
18772 * @param {String} name
18773 *
18774 * @return {Object} diagram service instance
18775 *
18776 * @method BaseViewer#get
18777 */
18778
18779 /**
18780 * Invoke a function in the context of this viewer.
18781 *
18782 * @example
18783 *
18784 * viewer.invoke(function(elementRegistry) {
18785 * var startEventShape = elementRegistry.get('StartEvent_1');
18786 * });
18787 *
18788 * @param {Function} fn to be invoked
18789 *
18790 * @return {Object} the functions return value
18791 *
18792 * @method BaseViewer#invoke
18793 */
18794
18795
18796 BaseViewer.prototype._setDefinitions = function(definitions) {
18797 this._definitions = definitions;
18798 };
18799
18800 BaseViewer.prototype.getModules = function() {
18801 return this._modules;
18802 };
18803
18804 /**
18805 * Remove all drawn elements from the viewer.
18806 *
18807 * After calling this method the viewer can still
18808 * be reused for opening another diagram.
18809 *
18810 * @method BaseViewer#clear
18811 */
18812 BaseViewer.prototype.clear = function() {
18813 if (!this.getDefinitions()) {
18814
18815 // no diagram to clear
18816 return;
18817 }
18818
18819 // remove businessObject#di binding
18820 //
18821 // this is necessary, as we establish the bindings
18822 // in the BpmnTreeWalker (and assume none are given
18823 // on reimport)
18824 this.get('elementRegistry').forEach(function(element) {
18825 var bo = element.businessObject;
18826
18827 if (bo && bo.di) {
18828 delete bo.di;
18829 }
18830 });
18831
18832 // remove drawn elements
18833 Diagram.prototype.clear.call(this);
18834 };
18835
18836 /**
18837 * Destroy the viewer instance and remove all its
18838 * remainders from the document tree.
18839 */
18840 BaseViewer.prototype.destroy = function() {
18841
18842 // diagram destroy
18843 Diagram.prototype.destroy.call(this);
18844
18845 // dom detach
18846 remove$1(this._container);
18847 };
18848
18849 /**
18850 * Register an event listener
18851 *
18852 * Remove a previously added listener via {@link #off(event, callback)}.
18853 *
18854 * @param {String} event
18855 * @param {Number} [priority]
18856 * @param {Function} callback
18857 * @param {Object} [that]
18858 */
18859 BaseViewer.prototype.on = function(event, priority, callback, target) {
18860 return this.get('eventBus').on(event, priority, callback, target);
18861 };
18862
18863 /**
18864 * De-register an event listener
18865 *
18866 * @param {String} event
18867 * @param {Function} callback
18868 */
18869 BaseViewer.prototype.off = function(event, callback) {
18870 this.get('eventBus').off(event, callback);
18871 };
18872
18873 BaseViewer.prototype.attachTo = function(parentNode) {
18874
18875 if (!parentNode) {
18876 throw new Error('parentNode required');
18877 }
18878
18879 // ensure we detach from the
18880 // previous, old parent
18881 this.detach();
18882
18883 // unwrap jQuery if provided
18884 if (parentNode.get && parentNode.constructor.prototype.jquery) {
18885 parentNode = parentNode.get(0);
18886 }
18887
18888 if (typeof parentNode === 'string') {
18889 parentNode = query(parentNode);
18890 }
18891
18892 parentNode.appendChild(this._container);
18893
18894 this._emit('attach', {});
18895
18896 this.get('canvas').resized();
18897 };
18898
18899 BaseViewer.prototype.getDefinitions = function() {
18900 return this._definitions;
18901 };
18902
18903 BaseViewer.prototype.detach = function() {
18904
18905 var container = this._container,
18906 parentNode = container.parentNode;
18907
18908 if (!parentNode) {
18909 return;
18910 }
18911
18912 this._emit('detach', {});
18913
18914 parentNode.removeChild(container);
18915 };
18916
18917 BaseViewer.prototype._init = function(container, moddle, options) {
18918
18919 var baseModules = options.modules || this.getModules(),
18920 additionalModules = options.additionalModules || [],
18921 staticModules = [
18922 {
18923 bpmnjs: [ 'value', this ],
18924 moddle: [ 'value', moddle ]
18925 }
18926 ];
18927
18928 var diagramModules = [].concat(staticModules, baseModules, additionalModules);
18929
18930 var diagramOptions = assign(omit(options, [ 'additionalModules' ]), {
18931 canvas: assign({}, options.canvas, { container: container }),
18932 modules: diagramModules
18933 });
18934
18935 // invoke diagram constructor
18936 Diagram.call(this, diagramOptions);
18937
18938 if (options && options.container) {
18939 this.attachTo(options.container);
18940 }
18941 };
18942
18943 /**
18944 * Emit an event on the underlying {@link EventBus}
18945 *
18946 * @param {String} type
18947 * @param {Object} event
18948 *
18949 * @return {Object} event processing result (if any)
18950 */
18951 BaseViewer.prototype._emit = function(type, event) {
18952 return this.get('eventBus').fire(type, event);
18953 };
18954
18955 BaseViewer.prototype._createContainer = function(options) {
18956
18957 var container = domify('<div class="bjs-container"></div>');
18958
18959 assign(container.style, {
18960 width: ensureUnit(options.width),
18961 height: ensureUnit(options.height),
18962 position: options.position
18963 });
18964
18965 return container;
18966 };
18967
18968 BaseViewer.prototype._createModdle = function(options) {
18969 var moddleOptions = assign({}, this._moddleExtensions, options.moddleExtensions);
18970
18971 return new simple(moddleOptions);
18972 };
18973
18974 BaseViewer.prototype._modules = [];
18975
18976
18977 // helpers ///////////////
18978
18979 function checkValidationError(err) {
18980
18981 // check if we can help the user by indicating wrong BPMN 2.0 xml
18982 // (in case he or the exporting tool did not get that right)
18983
18984 var pattern = /unparsable content <([^>]+)> detected([\s\S]*)$/;
18985 var match = pattern.exec(err.message);
18986
18987 if (match) {
18988 err.message =
18989 'unparsable content <' + match[1] + '> detected; ' +
18990 'this may indicate an invalid BPMN 2.0 diagram file' + match[2];
18991 }
18992
18993 return err;
18994 }
18995
18996 var DEFAULT_OPTIONS = {
18997 width: '100%',
18998 height: '100%',
18999 position: 'relative'
19000 };
19001
19002
19003 /**
19004 * Ensure the passed argument is a proper unit (defaulting to px)
19005 */
19006 function ensureUnit(val) {
19007 return val + (isNumber(val) ? 'px' : '');
19008 }
19009
19010
19011 /**
19012 * Find BPMNDiagram in definitions by ID
19013 *
19014 * @param {ModdleElement<Definitions>} definitions
19015 * @param {String} diagramId
19016 *
19017 * @return {ModdleElement<BPMNDiagram>|null}
19018 */
19019 function findBPMNDiagram(definitions, diagramId) {
19020 if (!diagramId) {
19021 return null;
19022 }
19023
19024 return find(definitions.diagrams, function(element) {
19025 return element.id === diagramId;
19026 }) || null;
19027 }
19028
19029 /**
19030 * Adds the project logo to the diagram container as
19031 * required by the bpmn.io license.
19032 *
19033 * @see http://bpmn.io/license
19034 *
19035 * @param {Element} container
19036 */
19037 function addProjectLogo(container) {
19038 var img = BPMNIO_IMG;
19039
19040 var linkMarkup =
19041 '<a href="http://bpmn.io" ' +
19042 'target="_blank" ' +
19043 'class="bjs-powered-by" ' +
19044 'title="Powered by bpmn.io" ' +
19045 'style="position: absolute; bottom: 15px; right: 15px; z-index: 100">' +
19046 img +
19047 '</a>';
19048
19049 var linkElement = domify(linkMarkup);
19050
19051 container.appendChild(linkElement);
19052
19053 componentEvent.bind(linkElement, 'click', function(event) {
19054 open();
19055
19056 event.preventDefault();
19057 });
19058 }
19059
19060 /* </project-logo> */
19061
19062 /**
19063 * A viewer for BPMN 2.0 diagrams.
19064 *
19065 * Have a look at {@link NavigatedViewer} or {@link Modeler} for bundles that include
19066 * additional features.
19067 *
19068 *
19069 * ## Extending the Viewer
19070 *
19071 * In order to extend the viewer pass extension modules to bootstrap via the
19072 * `additionalModules` option. An extension module is an object that exposes
19073 * named services.
19074 *
19075 * The following example depicts the integration of a simple
19076 * logging component that integrates with interaction events:
19077 *
19078 *
19079 * ```javascript
19080 *
19081 * // logging component
19082 * function InteractionLogger(eventBus) {
19083 * eventBus.on('element.hover', function(event) {
19084 * console.log()
19085 * })
19086 * }
19087 *
19088 * InteractionLogger.$inject = [ 'eventBus' ]; // minification save
19089 *
19090 * // extension module
19091 * var extensionModule = {
19092 * __init__: [ 'interactionLogger' ],
19093 * interactionLogger: [ 'type', InteractionLogger ]
19094 * };
19095 *
19096 * // extend the viewer
19097 * var bpmnViewer = new Viewer({ additionalModules: [ extensionModule ] });
19098 * bpmnViewer.importXML(...);
19099 * ```
19100 *
19101 * @param {Object} [options] configuration options to pass to the viewer
19102 * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
19103 * @param {String|Number} [options.width] the width of the viewer
19104 * @param {String|Number} [options.height] the height of the viewer
19105 * @param {Object} [options.moddleExtensions] extension packages to provide
19106 * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
19107 * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
19108 */
19109 function Viewer(options) {
19110 BaseViewer.call(this, options);
19111 }
19112
19113 inherits_browser(Viewer, BaseViewer);
19114
19115 // modules the viewer is composed of
19116 Viewer.prototype._modules = [
19117 CoreModule,
19118 TranslateModule,
19119 SelectionModule,
19120 OverlaysModule
19121 ];
19122
19123 // default moddle extensions the viewer is composed of
19124 Viewer.prototype._moddleExtensions = {};
19125
19126 /**
19127 * Returns true if event was triggered with any modifier
19128 * @param {KeyboardEvent} event
19129 */
19130 function hasModifier(event) {
19131 return (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey);
19132 }
19133
19134 /**
19135 * @param {KeyboardEvent} event
19136 */
19137 function isCmd(event) {
19138
19139 // ensure we don't react to AltGr
19140 // (mapped to CTRL + ALT)
19141 if (event.altKey) {
19142 return false;
19143 }
19144
19145 return event.ctrlKey || event.metaKey;
19146 }
19147
19148 /**
19149 * Checks if key pressed is one of provided keys.
19150 *
19151 * @param {String|String[]} keys
19152 * @param {KeyboardEvent} event
19153 */
19154 function isKey(keys, event) {
19155 keys = isArray(keys) ? keys : [ keys ];
19156
19157 return keys.indexOf(event.key) > -1;
19158 }
19159
19160 /**
19161 * @param {KeyboardEvent} event
19162 */
19163 function isShift(event) {
19164 return event.shiftKey;
19165 }
19166
19167 var KEYDOWN_EVENT = 'keyboard.keydown',
19168 KEYUP_EVENT = 'keyboard.keyup';
19169
19170 var DEFAULT_PRIORITY$1 = 1000;
19171
19172
19173 /**
19174 * A keyboard abstraction that may be activated and
19175 * deactivated by users at will, consuming key events
19176 * and triggering diagram actions.
19177 *
19178 * For keys pressed down, keyboard fires `keyboard.keydown` event.
19179 * The event context contains one field which is `KeyboardEvent` event.
19180 *
19181 * The implementation fires the following key events that allow
19182 * other components to hook into key handling:
19183 *
19184 * - keyboard.bind
19185 * - keyboard.unbind
19186 * - keyboard.init
19187 * - keyboard.destroy
19188 *
19189 * All events contain one field which is node.
19190 *
19191 * A default binding for the keyboard may be specified via the
19192 * `keyboard.bindTo` configuration option.
19193 *
19194 * @param {Config} config
19195 * @param {EventBus} eventBus
19196 */
19197 function Keyboard(config, eventBus) {
19198 var self = this;
19199
19200 this._config = config || {};
19201 this._eventBus = eventBus;
19202
19203 this._keydownHandler = this._keydownHandler.bind(this);
19204 this._keyupHandler = this._keyupHandler.bind(this);
19205
19206 // properly clean dom registrations
19207 eventBus.on('diagram.destroy', function() {
19208 self._fire('destroy');
19209
19210 self.unbind();
19211 });
19212
19213 eventBus.on('diagram.init', function() {
19214 self._fire('init');
19215 });
19216
19217 eventBus.on('attach', function() {
19218 if (config && config.bindTo) {
19219 self.bind(config.bindTo);
19220 }
19221 });
19222
19223 eventBus.on('detach', function() {
19224 self.unbind();
19225 });
19226 }
19227
19228 Keyboard.$inject = [
19229 'config.keyboard',
19230 'eventBus'
19231 ];
19232
19233 Keyboard.prototype._keydownHandler = function(event) {
19234 this._keyHandler(event, KEYDOWN_EVENT);
19235 };
19236
19237 Keyboard.prototype._keyupHandler = function(event) {
19238 this._keyHandler(event, KEYUP_EVENT);
19239 };
19240
19241 Keyboard.prototype._keyHandler = function(event, type) {
19242 var target = event.target,
19243 eventBusResult;
19244
19245 if (isInput(target)) {
19246 return;
19247 }
19248
19249 var context = {
19250 keyEvent: event
19251 };
19252
19253 eventBusResult = this._eventBus.fire(type || KEYDOWN_EVENT, context);
19254
19255 if (eventBusResult) {
19256 event.preventDefault();
19257 }
19258 };
19259
19260 Keyboard.prototype.bind = function(node) {
19261
19262 // make sure that the keyboard is only bound once to the DOM
19263 this.unbind();
19264
19265 this._node = node;
19266
19267 // bind key events
19268 componentEvent.bind(node, 'keydown', this._keydownHandler, true);
19269 componentEvent.bind(node, 'keyup', this._keyupHandler, true);
19270
19271 this._fire('bind');
19272 };
19273
19274 Keyboard.prototype.getBinding = function() {
19275 return this._node;
19276 };
19277
19278 Keyboard.prototype.unbind = function() {
19279 var node = this._node;
19280
19281 if (node) {
19282 this._fire('unbind');
19283
19284 // unbind key events
19285 componentEvent.unbind(node, 'keydown', this._keydownHandler, true);
19286 componentEvent.unbind(node, 'keyup', this._keyupHandler, true);
19287 }
19288
19289 this._node = null;
19290 };
19291
19292 Keyboard.prototype._fire = function(event) {
19293 this._eventBus.fire('keyboard.' + event, { node: this._node });
19294 };
19295
19296 /**
19297 * Add a listener function that is notified with `KeyboardEvent` whenever
19298 * the keyboard is bound and the user presses a key. If no priority is
19299 * provided, the default value of 1000 is used.
19300 *
19301 * @param {Number} [priority]
19302 * @param {Function} listener
19303 * @param {string} type
19304 */
19305 Keyboard.prototype.addListener = function(priority, listener, type) {
19306 if (isFunction(priority)) {
19307 type = listener;
19308 listener = priority;
19309 priority = DEFAULT_PRIORITY$1;
19310 }
19311
19312 this._eventBus.on(type || KEYDOWN_EVENT, priority, listener);
19313 };
19314
19315 Keyboard.prototype.removeListener = function(listener, type) {
19316 this._eventBus.off(type || KEYDOWN_EVENT, listener);
19317 };
19318
19319 Keyboard.prototype.hasModifier = hasModifier;
19320 Keyboard.prototype.isCmd = isCmd;
19321 Keyboard.prototype.isShift = isShift;
19322 Keyboard.prototype.isKey = isKey;
19323
19324
19325
19326 // helpers ///////
19327
19328 function isInput(target) {
19329 return target && (matchesSelector$1(target, 'input, textarea') || target.contentEditable === 'true');
19330 }
19331
19332 var LOW_PRIORITY$3 = 500;
19333
19334
19335 /**
19336 * Adds default keyboard bindings.
19337 *
19338 * This does not pull in any features will bind only actions that
19339 * have previously been registered against the editorActions component.
19340 *
19341 * @param {EventBus} eventBus
19342 * @param {Keyboard} keyboard
19343 */
19344 function KeyboardBindings(eventBus, keyboard) {
19345
19346 var self = this;
19347
19348 eventBus.on('editorActions.init', LOW_PRIORITY$3, function(event) {
19349
19350 var editorActions = event.editorActions;
19351
19352 self.registerBindings(keyboard, editorActions);
19353 });
19354 }
19355
19356 KeyboardBindings.$inject = [
19357 'eventBus',
19358 'keyboard'
19359 ];
19360
19361
19362 /**
19363 * Register available keyboard bindings.
19364 *
19365 * @param {Keyboard} keyboard
19366 * @param {EditorActions} editorActions
19367 */
19368 KeyboardBindings.prototype.registerBindings = function(keyboard, editorActions) {
19369
19370 /**
19371 * Add keyboard binding if respective editor action
19372 * is registered.
19373 *
19374 * @param {String} action name
19375 * @param {Function} fn that implements the key binding
19376 */
19377 function addListener(action, fn) {
19378
19379 if (editorActions.isRegistered(action)) {
19380 keyboard.addListener(fn);
19381 }
19382 }
19383
19384
19385 // undo
19386 // (CTRL|CMD) + Z
19387 addListener('undo', function(context) {
19388
19389 var event = context.keyEvent;
19390
19391 if (isCmd(event) && !isShift(event) && isKey(['z', 'Z'], event)) {
19392 editorActions.trigger('undo');
19393
19394 return true;
19395 }
19396 });
19397
19398 // redo
19399 // CTRL + Y
19400 // CMD + SHIFT + Z
19401 addListener('redo', function(context) {
19402
19403 var event = context.keyEvent;
19404
19405 if (isCmd(event) && (isKey(['y', 'Y'], event) || (isKey(['z', 'Z'], event) && isShift(event)))) {
19406 editorActions.trigger('redo');
19407
19408 return true;
19409 }
19410 });
19411
19412 // copy
19413 // CTRL/CMD + C
19414 addListener('copy', function(context) {
19415
19416 var event = context.keyEvent;
19417
19418 if (isCmd(event) && isKey(['c', 'C'], event)) {
19419 editorActions.trigger('copy');
19420
19421 return true;
19422 }
19423 });
19424
19425 // paste
19426 // CTRL/CMD + V
19427 addListener('paste', function(context) {
19428
19429 var event = context.keyEvent;
19430
19431 if (isCmd(event) && isKey(['v', 'V'], event)) {
19432 editorActions.trigger('paste');
19433
19434 return true;
19435 }
19436 });
19437
19438 // zoom in one step
19439 // CTRL/CMD + +
19440 addListener('stepZoom', function(context) {
19441
19442 var event = context.keyEvent;
19443
19444 if (isKey([ '+', 'Add' ], event) && isCmd(event)) {
19445 editorActions.trigger('stepZoom', { value: 1 });
19446
19447 return true;
19448 }
19449 });
19450
19451 // zoom out one step
19452 // CTRL + -
19453 addListener('stepZoom', function(context) {
19454
19455 var event = context.keyEvent;
19456
19457 if (isKey([ '-', 'Subtract' ], event) && isCmd(event)) {
19458 editorActions.trigger('stepZoom', { value: -1 });
19459
19460 return true;
19461 }
19462 });
19463
19464 // zoom to the default level
19465 // CTRL + 0
19466 addListener('zoom', function(context) {
19467
19468 var event = context.keyEvent;
19469
19470 if (isKey('0', event) && isCmd(event)) {
19471 editorActions.trigger('zoom', { value: 1 });
19472
19473 return true;
19474 }
19475 });
19476
19477 // delete selected element
19478 // DEL
19479 addListener('removeSelection', function(context) {
19480
19481 var event = context.keyEvent;
19482
19483 if (isKey([ 'Delete', 'Del' ], event)) {
19484 editorActions.trigger('removeSelection');
19485
19486 return true;
19487 }
19488 });
19489 };
19490
19491 var KeyboardModule = {
19492 __init__: [ 'keyboard', 'keyboardBindings' ],
19493 keyboard: [ 'type', Keyboard ],
19494 keyboardBindings: [ 'type', KeyboardBindings ]
19495 };
19496
19497 var DEFAULT_CONFIG = {
19498 moveSpeed: 50,
19499 moveSpeedAccelerated: 200
19500 };
19501
19502
19503 /**
19504 * A feature that allows users to move the canvas using the keyboard.
19505 *
19506 * @param {Object} config
19507 * @param {Number} [config.moveSpeed=50]
19508 * @param {Number} [config.moveSpeedAccelerated=200]
19509 * @param {Keyboard} keyboard
19510 * @param {Canvas} canvas
19511 */
19512 function KeyboardMove(
19513 config,
19514 keyboard,
19515 canvas
19516 ) {
19517
19518 var self = this;
19519
19520 this._config = assign({}, DEFAULT_CONFIG, config || {});
19521
19522 keyboard.addListener(arrowsListener);
19523
19524
19525 function arrowsListener(context) {
19526
19527 var event = context.keyEvent,
19528 config = self._config;
19529
19530 if (!keyboard.isCmd(event)) {
19531 return;
19532 }
19533
19534 if (keyboard.isKey([
19535 'ArrowLeft', 'Left',
19536 'ArrowUp', 'Up',
19537 'ArrowDown', 'Down',
19538 'ArrowRight', 'Right'
19539 ], event)) {
19540
19541 var speed = (
19542 keyboard.isShift(event) ?
19543 config.moveSpeedAccelerated :
19544 config.moveSpeed
19545 );
19546
19547 var direction;
19548
19549 switch (event.key) {
19550 case 'ArrowLeft':
19551 case 'Left':
19552 direction = 'left';
19553 break;
19554 case 'ArrowUp':
19555 case 'Up':
19556 direction = 'up';
19557 break;
19558 case 'ArrowRight':
19559 case 'Right':
19560 direction = 'right';
19561 break;
19562 case 'ArrowDown':
19563 case 'Down':
19564 direction = 'down';
19565 break;
19566 }
19567
19568 self.moveCanvas({
19569 speed: speed,
19570 direction: direction
19571 });
19572
19573 return true;
19574 }
19575 }
19576
19577 this.moveCanvas = function(opts) {
19578
19579 var dx = 0,
19580 dy = 0,
19581 speed = opts.speed;
19582
19583 var actualSpeed = speed / Math.min(Math.sqrt(canvas.viewbox().scale), 1);
19584
19585 switch (opts.direction) {
19586 case 'left': // Left
19587 dx = actualSpeed;
19588 break;
19589 case 'up': // Up
19590 dy = actualSpeed;
19591 break;
19592 case 'right': // Right
19593 dx = -actualSpeed;
19594 break;
19595 case 'down': // Down
19596 dy = -actualSpeed;
19597 break;
19598 }
19599
19600 canvas.scroll({
19601 dx: dx,
19602 dy: dy
19603 });
19604 };
19605
19606 }
19607
19608
19609 KeyboardMove.$inject = [
19610 'config.keyboardMove',
19611 'keyboard',
19612 'canvas'
19613 ];
19614
19615 var KeyboardMoveModule = {
19616 __depends__: [
19617 KeyboardModule
19618 ],
19619 __init__: [ 'keyboardMove' ],
19620 keyboardMove: [ 'type', KeyboardMove ]
19621 };
19622
19623 var CURSOR_CLS_PATTERN = /^djs-cursor-.*$/;
19624
19625
19626 function set$1(mode) {
19627 var classes = classes$1(document.body);
19628
19629 classes.removeMatching(CURSOR_CLS_PATTERN);
19630
19631 if (mode) {
19632 classes.add('djs-cursor-' + mode);
19633 }
19634 }
19635
19636 function unset() {
19637 set$1(null);
19638 }
19639
19640 var TRAP_PRIORITY = 5000;
19641
19642 /**
19643 * Installs a click trap that prevents a ghost click following a dragging operation.
19644 *
19645 * @return {Function} a function to immediately remove the installed trap.
19646 */
19647 function install(eventBus, eventName) {
19648
19649 eventName = eventName || 'element.click';
19650
19651 function trap() {
19652 return false;
19653 }
19654
19655 eventBus.once(eventName, TRAP_PRIORITY, trap);
19656
19657 return function() {
19658 eventBus.off(eventName, trap);
19659 };
19660 }
19661
19662 function delta(a, b) {
19663 return {
19664 x: a.x - b.x,
19665 y: a.y - b.y
19666 };
19667 }
19668
19669 var THRESHOLD = 15;
19670
19671
19672 /**
19673 * Move the canvas via mouse.
19674 *
19675 * @param {EventBus} eventBus
19676 * @param {Canvas} canvas
19677 */
19678 function MoveCanvas(eventBus, canvas) {
19679
19680 var context;
19681
19682
19683 // listen for move on element mouse down;
19684 // allow others to hook into the event before us though
19685 // (dragging / element moving will do this)
19686 eventBus.on('element.mousedown', 500, function(e) {
19687 return handleStart(e.originalEvent);
19688 });
19689
19690
19691 function handleMove(event) {
19692
19693 var start = context.start,
19694 position = toPoint(event),
19695 delta$1 = delta(position, start);
19696
19697 if (!context.dragging && length(delta$1) > THRESHOLD) {
19698 context.dragging = true;
19699
19700 install(eventBus);
19701
19702 set$1('grab');
19703 }
19704
19705 if (context.dragging) {
19706
19707 var lastPosition = context.last || context.start;
19708
19709 delta$1 = delta(position, lastPosition);
19710
19711 canvas.scroll({
19712 dx: delta$1.x,
19713 dy: delta$1.y
19714 });
19715
19716 context.last = position;
19717 }
19718
19719 // prevent select
19720 event.preventDefault();
19721 }
19722
19723
19724 function handleEnd(event) {
19725 componentEvent.unbind(document, 'mousemove', handleMove);
19726 componentEvent.unbind(document, 'mouseup', handleEnd);
19727
19728 context = null;
19729
19730 unset();
19731 }
19732
19733 function handleStart(event) {
19734
19735 // event is already handled by '.djs-draggable'
19736 if (closest(event.target, '.djs-draggable')) {
19737 return;
19738 }
19739
19740
19741 // reject non-left left mouse button or modifier key
19742 if (event.button || event.ctrlKey || event.shiftKey || event.altKey) {
19743 return;
19744 }
19745
19746 context = {
19747 start: toPoint(event)
19748 };
19749
19750 componentEvent.bind(document, 'mousemove', handleMove);
19751 componentEvent.bind(document, 'mouseup', handleEnd);
19752
19753 // we've handled the event
19754 return true;
19755 }
19756 }
19757
19758
19759 MoveCanvas.$inject = [
19760 'eventBus',
19761 'canvas'
19762 ];
19763
19764
19765
19766 // helpers ///////
19767
19768 function length(point) {
19769 return Math.sqrt(Math.pow(point.x, 2) + Math.pow(point.y, 2));
19770 }
19771
19772 var MoveCanvasModule = {
19773 __init__: [ 'moveCanvas' ],
19774 moveCanvas: [ 'type', MoveCanvas ]
19775 };
19776
19777 /**
19778 * Get the logarithm of x with base 10
19779 * @param {Integer} value
19780 */
19781 function log10(x) {
19782 return Math.log(x) / Math.log(10);
19783 }
19784
19785 /**
19786 * Get step size for given range and number of steps.
19787 *
19788 * @param {Object} range
19789 * @param {number} range.min
19790 * @param {number} range.max
19791 */
19792 function getStepSize(range, steps) {
19793
19794 var minLinearRange = log10(range.min),
19795 maxLinearRange = log10(range.max);
19796
19797 var absoluteLinearRange = Math.abs(minLinearRange) + Math.abs(maxLinearRange);
19798
19799 return absoluteLinearRange / steps;
19800 }
19801
19802 function cap(range, scale) {
19803 return Math.max(range.min, Math.min(range.max, scale));
19804 }
19805
19806 var sign = Math.sign || function(n) {
19807 return n >= 0 ? 1 : -1;
19808 };
19809
19810 var RANGE = { min: 0.2, max: 4 },
19811 NUM_STEPS = 10;
19812
19813 var DELTA_THRESHOLD = 0.1;
19814
19815 var DEFAULT_SCALE = 0.75;
19816
19817 /**
19818 * An implementation of zooming and scrolling within the
19819 * {@link Canvas} via the mouse wheel.
19820 *
19821 * Mouse wheel zooming / scrolling may be disabled using
19822 * the {@link toggle(enabled)} method.
19823 *
19824 * @param {Object} [config]
19825 * @param {Boolean} [config.enabled=true] default enabled state
19826 * @param {Number} [config.scale=.75] scroll sensivity
19827 * @param {EventBus} eventBus
19828 * @param {Canvas} canvas
19829 */
19830 function ZoomScroll(config, eventBus, canvas) {
19831
19832 config = config || {};
19833
19834 this._enabled = false;
19835
19836 this._canvas = canvas;
19837 this._container = canvas._container;
19838
19839 this._handleWheel = bind(this._handleWheel, this);
19840
19841 this._totalDelta = 0;
19842 this._scale = config.scale || DEFAULT_SCALE;
19843
19844 var self = this;
19845
19846 eventBus.on('canvas.init', function(e) {
19847 self._init(config.enabled !== false);
19848 });
19849 }
19850
19851 ZoomScroll.$inject = [
19852 'config.zoomScroll',
19853 'eventBus',
19854 'canvas'
19855 ];
19856
19857 ZoomScroll.prototype.scroll = function scroll(delta) {
19858 this._canvas.scroll(delta);
19859 };
19860
19861
19862 ZoomScroll.prototype.reset = function reset() {
19863 this._canvas.zoom('fit-viewport');
19864 };
19865
19866 /**
19867 * Zoom depending on delta.
19868 *
19869 * @param {number} delta
19870 * @param {Object} position
19871 */
19872 ZoomScroll.prototype.zoom = function zoom(delta, position) {
19873
19874 // zoom with half the step size of stepZoom
19875 var stepSize = getStepSize(RANGE, NUM_STEPS * 2);
19876
19877 // add until threshold reached
19878 this._totalDelta += delta;
19879
19880 if (Math.abs(this._totalDelta) > DELTA_THRESHOLD) {
19881 this._zoom(delta, position, stepSize);
19882
19883 // reset
19884 this._totalDelta = 0;
19885 }
19886 };
19887
19888
19889 ZoomScroll.prototype._handleWheel = function handleWheel(event) {
19890
19891 // event is already handled by '.djs-scrollable'
19892 if (closest(event.target, '.djs-scrollable', true)) {
19893 return;
19894 }
19895
19896 var element = this._container;
19897
19898 event.preventDefault();
19899
19900 // pinch to zoom is mapped to wheel + ctrlKey = true
19901 // in modern browsers (!)
19902
19903 var isZoom = event.ctrlKey;
19904
19905 var isHorizontalScroll = event.shiftKey;
19906
19907 var factor = -1 * this._scale,
19908 delta;
19909
19910 if (isZoom) {
19911 factor *= event.deltaMode === 0 ? 0.020 : 0.32;
19912 } else {
19913 factor *= event.deltaMode === 0 ? 1.0 : 16.0;
19914 }
19915
19916 if (isZoom) {
19917 var elementRect = element.getBoundingClientRect();
19918
19919 var offset = {
19920 x: event.clientX - elementRect.left,
19921 y: event.clientY - elementRect.top
19922 };
19923
19924 delta = (
19925 Math.sqrt(
19926 Math.pow(event.deltaY, 2) +
19927 Math.pow(event.deltaX, 2)
19928 ) * sign(event.deltaY) * factor
19929 );
19930
19931 // zoom in relative to diagram {x,y} coordinates
19932 this.zoom(delta, offset);
19933 } else {
19934
19935 if (isHorizontalScroll) {
19936 delta = {
19937 dx: factor * event.deltaY,
19938 dy: 0
19939 };
19940 } else {
19941 delta = {
19942 dx: factor * event.deltaX,
19943 dy: factor * event.deltaY
19944 };
19945 }
19946
19947 this.scroll(delta);
19948 }
19949 };
19950
19951 /**
19952 * Zoom with fixed step size.
19953 *
19954 * @param {number} delta - Zoom delta (1 for zooming in, -1 for out).
19955 * @param {Object} position
19956 */
19957 ZoomScroll.prototype.stepZoom = function stepZoom(delta, position) {
19958
19959 var stepSize = getStepSize(RANGE, NUM_STEPS);
19960
19961 this._zoom(delta, position, stepSize);
19962 };
19963
19964
19965 /**
19966 * Zoom in/out given a step size.
19967 *
19968 * @param {number} delta
19969 * @param {Object} position
19970 * @param {number} stepSize
19971 */
19972 ZoomScroll.prototype._zoom = function(delta, position, stepSize) {
19973 var canvas = this._canvas;
19974
19975 var direction = delta > 0 ? 1 : -1;
19976
19977 var currentLinearZoomLevel = log10(canvas.zoom());
19978
19979 // snap to a proximate zoom step
19980 var newLinearZoomLevel = Math.round(currentLinearZoomLevel / stepSize) * stepSize;
19981
19982 // increase or decrease one zoom step in the given direction
19983 newLinearZoomLevel += stepSize * direction;
19984
19985 // calculate the absolute logarithmic zoom level based on the linear zoom level
19986 // (e.g. 2 for an absolute x2 zoom)
19987 var newLogZoomLevel = Math.pow(10, newLinearZoomLevel);
19988
19989 canvas.zoom(cap(RANGE, newLogZoomLevel), position);
19990 };
19991
19992
19993 /**
19994 * Toggle the zoom scroll ability via mouse wheel.
19995 *
19996 * @param {Boolean} [newEnabled] new enabled state
19997 */
19998 ZoomScroll.prototype.toggle = function toggle(newEnabled) {
19999
20000 var element = this._container;
20001 var handleWheel = this._handleWheel;
20002
20003 var oldEnabled = this._enabled;
20004
20005 if (typeof newEnabled === 'undefined') {
20006 newEnabled = !oldEnabled;
20007 }
20008
20009 // only react on actual changes
20010 if (oldEnabled !== newEnabled) {
20011
20012 // add or remove wheel listener based on
20013 // changed enabled state
20014 componentEvent[newEnabled ? 'bind' : 'unbind'](element, 'wheel', handleWheel, false);
20015 }
20016
20017 this._enabled = newEnabled;
20018
20019 return newEnabled;
20020 };
20021
20022
20023 ZoomScroll.prototype._init = function(newEnabled) {
20024 this.toggle(newEnabled);
20025 };
20026
20027 var ZoomScrollModule = {
20028 __init__: [ 'zoomScroll' ],
20029 zoomScroll: [ 'type', ZoomScroll ]
20030 };
20031
20032 /**
20033 * A viewer that includes mouse navigation facilities
20034 *
20035 * @param {Object} options
20036 */
20037 function NavigatedViewer(options) {
20038 Viewer.call(this, options);
20039 }
20040
20041 inherits_browser(NavigatedViewer, Viewer);
20042
20043
20044 NavigatedViewer.prototype._navigationModules = [
20045 KeyboardMoveModule,
20046 MoveCanvasModule,
20047 ZoomScrollModule
20048 ];
20049
20050 NavigatedViewer.prototype._modules = [].concat(
20051 Viewer.prototype._modules,
20052 NavigatedViewer.prototype._navigationModules
20053 );
20054
20055 return NavigatedViewer;
20056
20057}));