UNPKG

449 kBJavaScriptView Raw
1/*!
2 * bpmn-js - bpmn-viewer v6.0.6
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-11
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 /**
20 * Flatten array, one level deep.
21 *
22 * @param {Array<?>} arr
23 *
24 * @return {Array<?>}
25 */
26
27 var nativeToString = Object.prototype.toString;
28 var nativeHasOwnProperty = Object.prototype.hasOwnProperty;
29 function isUndefined(obj) {
30 return obj === undefined;
31 }
32 function isDefined(obj) {
33 return obj !== undefined;
34 }
35 function isArray(obj) {
36 return nativeToString.call(obj) === '[object Array]';
37 }
38 function isObject(obj) {
39 return nativeToString.call(obj) === '[object Object]';
40 }
41 function isNumber(obj) {
42 return nativeToString.call(obj) === '[object Number]';
43 }
44 function isFunction(obj) {
45 var tag = nativeToString.call(obj);
46 return tag === '[object Function]' || tag === '[object AsyncFunction]' || tag === '[object GeneratorFunction]' || tag === '[object AsyncGeneratorFunction]' || tag === '[object Proxy]';
47 }
48 function isString(obj) {
49 return nativeToString.call(obj) === '[object String]';
50 }
51 /**
52 * Return true, if target owns a property with the given key.
53 *
54 * @param {Object} target
55 * @param {String} key
56 *
57 * @return {Boolean}
58 */
59
60 function has(target, key) {
61 return nativeHasOwnProperty.call(target, key);
62 }
63
64 /**
65 * Find element in collection.
66 *
67 * @param {Array|Object} collection
68 * @param {Function|Object} matcher
69 *
70 * @return {Object}
71 */
72
73 function find(collection, matcher) {
74 matcher = toMatcher(matcher);
75 var match;
76 forEach(collection, function (val, key) {
77 if (matcher(val, key)) {
78 match = val;
79 return false;
80 }
81 });
82 return match;
83 }
84 /**
85 * Find element in collection.
86 *
87 * @param {Array|Object} collection
88 * @param {Function} matcher
89 *
90 * @return {Array} result
91 */
92
93 function filter(collection, matcher) {
94 var result = [];
95 forEach(collection, function (val, key) {
96 if (matcher(val, key)) {
97 result.push(val);
98 }
99 });
100 return result;
101 }
102 /**
103 * Iterate over collection; returning something
104 * (non-undefined) will stop iteration.
105 *
106 * @param {Array|Object} collection
107 * @param {Function} iterator
108 *
109 * @return {Object} return result that stopped the iteration
110 */
111
112 function forEach(collection, iterator) {
113 var val, result;
114
115 if (isUndefined(collection)) {
116 return;
117 }
118
119 var convertKey = isArray(collection) ? toNum : identity;
120
121 for (var key in collection) {
122 if (has(collection, key)) {
123 val = collection[key];
124 result = iterator(val, convertKey(key));
125
126 if (result === false) {
127 return val;
128 }
129 }
130 }
131 }
132 /**
133 * Reduce collection, returning a single result.
134 *
135 * @param {Object|Array} collection
136 * @param {Function} iterator
137 * @param {Any} result
138 *
139 * @return {Any} result returned from last iterator
140 */
141
142 function reduce(collection, iterator, result) {
143 forEach(collection, function (value, idx) {
144 result = iterator(result, value, idx);
145 });
146 return result;
147 }
148 /**
149 * Return true if every element in the collection
150 * matches the criteria.
151 *
152 * @param {Object|Array} collection
153 * @param {Function} matcher
154 *
155 * @return {Boolean}
156 */
157
158 function every(collection, matcher) {
159 return !!reduce(collection, function (matches, val, key) {
160 return matches && matcher(val, key);
161 }, true);
162 }
163 /**
164 * Return true if some elements in the collection
165 * match the criteria.
166 *
167 * @param {Object|Array} collection
168 * @param {Function} matcher
169 *
170 * @return {Boolean}
171 */
172
173 function some(collection, matcher) {
174 return !!find(collection, matcher);
175 }
176 /**
177 * Transform a collection into another collection
178 * by piping each member through the given fn.
179 *
180 * @param {Object|Array} collection
181 * @param {Function} fn
182 *
183 * @return {Array} transformed collection
184 */
185
186 function map(collection, fn) {
187 var result = [];
188 forEach(collection, function (val, key) {
189 result.push(fn(val, key));
190 });
191 return result;
192 }
193 /**
194 * Create an object pattern matcher.
195 *
196 * @example
197 *
198 * const matcher = matchPattern({ id: 1 });
199 *
200 * var element = find(elements, matcher);
201 *
202 * @param {Object} pattern
203 *
204 * @return {Function} matcherFn
205 */
206
207 function matchPattern(pattern) {
208 return function (el) {
209 return every(pattern, function (val, key) {
210 return el[key] === val;
211 });
212 };
213 }
214
215 function toMatcher(matcher) {
216 return isFunction(matcher) ? matcher : function (e) {
217 return e === matcher;
218 };
219 }
220
221 function identity(arg) {
222 return arg;
223 }
224
225 function toNum(arg) {
226 return Number(arg);
227 }
228
229 /**
230 * Debounce fn, calling it only once if
231 * the given time elapsed between calls.
232 *
233 * @param {Function} fn
234 * @param {Number} timeout
235 *
236 * @return {Function} debounced function
237 */
238 function debounce(fn, timeout) {
239 var timer;
240 var lastArgs;
241 var lastThis;
242 var lastNow;
243
244 function fire() {
245 var now = Date.now();
246 var scheduledDiff = lastNow + timeout - now;
247
248 if (scheduledDiff > 0) {
249 return schedule(scheduledDiff);
250 }
251
252 fn.apply(lastThis, lastArgs);
253 timer = lastNow = lastArgs = lastThis = undefined;
254 }
255
256 function schedule(timeout) {
257 timer = setTimeout(fire, timeout);
258 }
259
260 return function () {
261 lastNow = Date.now();
262
263 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
264 args[_key] = arguments[_key];
265 }
266
267 lastArgs = args;
268 lastThis = this; // ensure an execution is scheduled
269
270 if (!timer) {
271 schedule(timeout);
272 }
273 };
274 }
275 /**
276 * Bind function against target <this>.
277 *
278 * @param {Function} fn
279 * @param {Object} target
280 *
281 * @return {Function} bound function
282 */
283
284 function bind(fn, target) {
285 return fn.bind(target);
286 }
287
288 function _extends() {
289 _extends = Object.assign || function (target) {
290 for (var i = 1; i < arguments.length; i++) {
291 var source = arguments[i];
292
293 for (var key in source) {
294 if (Object.prototype.hasOwnProperty.call(source, key)) {
295 target[key] = source[key];
296 }
297 }
298 }
299
300 return target;
301 };
302
303 return _extends.apply(this, arguments);
304 }
305
306 /**
307 * Convenience wrapper for `Object.assign`.
308 *
309 * @param {Object} target
310 * @param {...Object} others
311 *
312 * @return {Object} the target
313 */
314
315 function assign(target) {
316 for (var _len = arguments.length, others = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
317 others[_key - 1] = arguments[_key];
318 }
319
320 return _extends.apply(void 0, [target].concat(others));
321 }
322 /**
323 * Pick given properties from the target object.
324 *
325 * @param {Object} target
326 * @param {Array} properties
327 *
328 * @return {Object} target
329 */
330
331 function pick(target, properties) {
332 var result = {};
333 var obj = Object(target);
334 forEach(properties, function (prop) {
335 if (prop in obj) {
336 result[prop] = target[prop];
337 }
338 });
339 return result;
340 }
341 /**
342 * Pick all target properties, excluding the given ones.
343 *
344 * @param {Object} target
345 * @param {Array} properties
346 *
347 * @return {Object} target
348 */
349
350 function omit(target, properties) {
351 var result = {};
352 var obj = Object(target);
353 forEach(obj, function (prop, key) {
354 if (properties.indexOf(key) === -1) {
355 result[key] = prop;
356 }
357 });
358 return result;
359 }
360
361 /**
362 * Set attribute `name` to `val`, or get attr `name`.
363 *
364 * @param {Element} el
365 * @param {String} name
366 * @param {String} [val]
367 * @api public
368 */
369 function attr(el, name, val) {
370 // get
371 if (arguments.length == 2) {
372 return el.getAttribute(name);
373 }
374
375 // remove
376 if (val === null) {
377 return el.removeAttribute(name);
378 }
379
380 // set
381 el.setAttribute(name, val);
382
383 return el;
384 }
385
386 var indexOf = [].indexOf;
387
388 var indexof = function(arr, obj){
389 if (indexOf) return arr.indexOf(obj);
390 for (var i = 0; i < arr.length; ++i) {
391 if (arr[i] === obj) return i;
392 }
393 return -1;
394 };
395
396 /**
397 * Taken from https://github.com/component/classes
398 *
399 * Without the component bits.
400 */
401
402 /**
403 * Whitespace regexp.
404 */
405
406 var re = /\s+/;
407
408 /**
409 * toString reference.
410 */
411
412 var toString = Object.prototype.toString;
413
414 /**
415 * Wrap `el` in a `ClassList`.
416 *
417 * @param {Element} el
418 * @return {ClassList}
419 * @api public
420 */
421
422 function classes(el) {
423 return new ClassList(el);
424 }
425
426 /**
427 * Initialize a new ClassList for `el`.
428 *
429 * @param {Element} el
430 * @api private
431 */
432
433 function ClassList(el) {
434 if (!el || !el.nodeType) {
435 throw new Error('A DOM element reference is required');
436 }
437 this.el = el;
438 this.list = el.classList;
439 }
440
441 /**
442 * Add class `name` if not already present.
443 *
444 * @param {String} name
445 * @return {ClassList}
446 * @api public
447 */
448
449 ClassList.prototype.add = function (name) {
450 // classList
451 if (this.list) {
452 this.list.add(name);
453 return this;
454 }
455
456 // fallback
457 var arr = this.array();
458 var i = indexof(arr, name);
459 if (!~i) arr.push(name);
460 this.el.className = arr.join(' ');
461 return this;
462 };
463
464 /**
465 * Remove class `name` when present, or
466 * pass a regular expression to remove
467 * any which match.
468 *
469 * @param {String|RegExp} name
470 * @return {ClassList}
471 * @api public
472 */
473
474 ClassList.prototype.remove = function (name) {
475 if ('[object RegExp]' == toString.call(name)) {
476 return this.removeMatching(name);
477 }
478
479 // classList
480 if (this.list) {
481 this.list.remove(name);
482 return this;
483 }
484
485 // fallback
486 var arr = this.array();
487 var i = indexof(arr, name);
488 if (~i) arr.splice(i, 1);
489 this.el.className = arr.join(' ');
490 return this;
491 };
492
493 /**
494 * Remove all classes matching `re`.
495 *
496 * @param {RegExp} re
497 * @return {ClassList}
498 * @api private
499 */
500
501 ClassList.prototype.removeMatching = function (re) {
502 var arr = this.array();
503 for (var i = 0; i < arr.length; i++) {
504 if (re.test(arr[i])) {
505 this.remove(arr[i]);
506 }
507 }
508 return this;
509 };
510
511 /**
512 * Toggle class `name`, can force state via `force`.
513 *
514 * For browsers that support classList, but do not support `force` yet,
515 * the mistake will be detected and corrected.
516 *
517 * @param {String} name
518 * @param {Boolean} force
519 * @return {ClassList}
520 * @api public
521 */
522
523 ClassList.prototype.toggle = function (name, force) {
524 // classList
525 if (this.list) {
526 if ('undefined' !== typeof force) {
527 if (force !== this.list.toggle(name, force)) {
528 this.list.toggle(name); // toggle again to correct
529 }
530 } else {
531 this.list.toggle(name);
532 }
533 return this;
534 }
535
536 // fallback
537 if ('undefined' !== typeof force) {
538 if (!force) {
539 this.remove(name);
540 } else {
541 this.add(name);
542 }
543 } else {
544 if (this.has(name)) {
545 this.remove(name);
546 } else {
547 this.add(name);
548 }
549 }
550
551 return this;
552 };
553
554 /**
555 * Return an array of classes.
556 *
557 * @return {Array}
558 * @api public
559 */
560
561 ClassList.prototype.array = function () {
562 var className = this.el.getAttribute('class') || '';
563 var str = className.replace(/^\s+|\s+$/g, '');
564 var arr = str.split(re);
565 if ('' === arr[0]) arr.shift();
566 return arr;
567 };
568
569 /**
570 * Check if class `name` is present.
571 *
572 * @param {String} name
573 * @return {ClassList}
574 * @api public
575 */
576
577 ClassList.prototype.has = ClassList.prototype.contains = function (name) {
578 return this.list ? this.list.contains(name) : !!~indexof(this.array(), name);
579 };
580
581 /**
582 * Remove all children from the given element.
583 */
584 function clear(el) {
585
586 var c;
587
588 while (el.childNodes.length) {
589 c = el.childNodes[0];
590 el.removeChild(c);
591 }
592
593 return el;
594 }
595
596 /**
597 * Element prototype.
598 */
599
600 var proto = Element.prototype;
601
602 /**
603 * Vendor function.
604 */
605
606 var vendor = proto.matchesSelector
607 || proto.webkitMatchesSelector
608 || proto.mozMatchesSelector
609 || proto.msMatchesSelector
610 || proto.oMatchesSelector;
611
612 /**
613 * Expose `match()`.
614 */
615
616 var matchesSelector = match;
617
618 /**
619 * Match `el` to `selector`.
620 *
621 * @param {Element} el
622 * @param {String} selector
623 * @return {Boolean}
624 * @api public
625 */
626
627 function match(el, selector) {
628 if (vendor) return vendor.call(el, selector);
629 var nodes = el.parentNode.querySelectorAll(selector);
630 for (var i = 0; i < nodes.length; ++i) {
631 if (nodes[i] == el) return true;
632 }
633 return false;
634 }
635
636 var closest = function (element, selector, checkYoSelf) {
637 var parent = checkYoSelf ? element : element.parentNode;
638
639 while (parent && parent !== document) {
640 if (matchesSelector(parent, selector)) return parent;
641 parent = parent.parentNode;
642 }
643 };
644
645 var bind$1 = window.addEventListener ? 'addEventListener' : 'attachEvent',
646 unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
647 prefix = bind$1 !== 'addEventListener' ? 'on' : '';
648
649 /**
650 * Bind `el` event `type` to `fn`.
651 *
652 * @param {Element} el
653 * @param {String} type
654 * @param {Function} fn
655 * @param {Boolean} capture
656 * @return {Function}
657 * @api public
658 */
659
660 var bind_1 = function(el, type, fn, capture){
661 el[bind$1](prefix + type, fn, capture || false);
662 return fn;
663 };
664
665 /**
666 * Unbind `el` event `type`'s callback `fn`.
667 *
668 * @param {Element} el
669 * @param {String} type
670 * @param {Function} fn
671 * @param {Boolean} capture
672 * @return {Function}
673 * @api public
674 */
675
676 var unbind_1 = function(el, type, fn, capture){
677 el[unbind](prefix + type, fn, capture || false);
678 return fn;
679 };
680
681 var componentEvent = {
682 bind: bind_1,
683 unbind: unbind_1
684 };
685
686 /**
687 * Module dependencies.
688 */
689
690
691
692 /**
693 * Delegate event `type` to `selector`
694 * and invoke `fn(e)`. A callback function
695 * is returned which may be passed to `.unbind()`.
696 *
697 * @param {Element} el
698 * @param {String} selector
699 * @param {String} type
700 * @param {Function} fn
701 * @param {Boolean} capture
702 * @return {Function}
703 * @api public
704 */
705
706 // Some events don't bubble, so we want to bind to the capture phase instead
707 // when delegating.
708 var forceCaptureEvents = ['focus', 'blur'];
709
710 var bind$1$1 = function(el, selector, type, fn, capture){
711 if (forceCaptureEvents.indexOf(type) !== -1) capture = true;
712
713 return componentEvent.bind(el, type, function(e){
714 var target = e.target || e.srcElement;
715 e.delegateTarget = closest(target, selector, true);
716 if (e.delegateTarget) fn.call(el, e);
717 }, capture);
718 };
719
720 /**
721 * Unbind event `type`'s callback `fn`.
722 *
723 * @param {Element} el
724 * @param {String} type
725 * @param {Function} fn
726 * @param {Boolean} capture
727 * @api public
728 */
729
730 var unbind$1 = function(el, type, fn, capture){
731 if (forceCaptureEvents.indexOf(type) !== -1) capture = true;
732
733 componentEvent.unbind(el, type, fn, capture);
734 };
735
736 var delegateEvents = {
737 bind: bind$1$1,
738 unbind: unbind$1
739 };
740
741 /**
742 * Expose `parse`.
743 */
744
745 var domify = parse;
746
747 /**
748 * Tests for browser support.
749 */
750
751 var innerHTMLBug = false;
752 var bugTestDiv;
753 if (typeof document !== 'undefined') {
754 bugTestDiv = document.createElement('div');
755 // Setup
756 bugTestDiv.innerHTML = ' <link/><table></table><a href="/a">a</a><input type="checkbox"/>';
757 // Make sure that link elements get serialized correctly by innerHTML
758 // This requires a wrapper element in IE
759 innerHTMLBug = !bugTestDiv.getElementsByTagName('link').length;
760 bugTestDiv = undefined;
761 }
762
763 /**
764 * Wrap map from jquery.
765 */
766
767 var map$1 = {
768 legend: [1, '<fieldset>', '</fieldset>'],
769 tr: [2, '<table><tbody>', '</tbody></table>'],
770 col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
771 // for script/link/style tags to work in IE6-8, you have to wrap
772 // in a div with a non-whitespace character in front, ha!
773 _default: innerHTMLBug ? [1, 'X<div>', '</div>'] : [0, '', '']
774 };
775
776 map$1.td =
777 map$1.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
778
779 map$1.option =
780 map$1.optgroup = [1, '<select multiple="multiple">', '</select>'];
781
782 map$1.thead =
783 map$1.tbody =
784 map$1.colgroup =
785 map$1.caption =
786 map$1.tfoot = [1, '<table>', '</table>'];
787
788 map$1.polyline =
789 map$1.ellipse =
790 map$1.polygon =
791 map$1.circle =
792 map$1.text =
793 map$1.line =
794 map$1.path =
795 map$1.rect =
796 map$1.g = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>'];
797
798 /**
799 * Parse `html` and return a DOM Node instance, which could be a TextNode,
800 * HTML DOM Node of some kind (<div> for example), or a DocumentFragment
801 * instance, depending on the contents of the `html` string.
802 *
803 * @param {String} html - HTML string to "domify"
804 * @param {Document} doc - The `document` instance to create the Node for
805 * @return {DOMNode} the TextNode, DOM Node, or DocumentFragment instance
806 * @api private
807 */
808
809 function parse(html, doc) {
810 if ('string' != typeof html) throw new TypeError('String expected');
811
812 // default to the global `document` object
813 if (!doc) doc = document;
814
815 // tag name
816 var m = /<([\w:]+)/.exec(html);
817 if (!m) return doc.createTextNode(html);
818
819 html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace
820
821 var tag = m[1];
822
823 // body support
824 if (tag == 'body') {
825 var el = doc.createElement('html');
826 el.innerHTML = html;
827 return el.removeChild(el.lastChild);
828 }
829
830 // wrap map
831 var wrap = map$1[tag] || map$1._default;
832 var depth = wrap[0];
833 var prefix = wrap[1];
834 var suffix = wrap[2];
835 var el = doc.createElement('div');
836 el.innerHTML = prefix + html + suffix;
837 while (depth--) el = el.lastChild;
838
839 // one element
840 if (el.firstChild == el.lastChild) {
841 return el.removeChild(el.firstChild);
842 }
843
844 // several elements
845 var fragment = doc.createDocumentFragment();
846 while (el.firstChild) {
847 fragment.appendChild(el.removeChild(el.firstChild));
848 }
849
850 return fragment;
851 }
852
853 var proto$1 = typeof Element !== 'undefined' ? Element.prototype : {};
854 var vendor$1 = proto$1.matches
855 || proto$1.matchesSelector
856 || proto$1.webkitMatchesSelector
857 || proto$1.mozMatchesSelector
858 || proto$1.msMatchesSelector
859 || proto$1.oMatchesSelector;
860
861 function query(selector, el) {
862 el = el || document;
863
864 return el.querySelector(selector);
865 }
866
867 function all(selector, el) {
868 el = el || document;
869
870 return el.querySelectorAll(selector);
871 }
872
873 function remove(el) {
874 el.parentNode && el.parentNode.removeChild(el);
875 }
876
877 function ensureImported(element, target) {
878
879 if (element.ownerDocument !== target.ownerDocument) {
880 try {
881 // may fail on webkit
882 return target.ownerDocument.importNode(element, true);
883 } catch (e) {
884 // ignore
885 }
886 }
887
888 return element;
889 }
890
891 /**
892 * appendTo utility
893 */
894
895 /**
896 * Append a node to a target element and return the appended node.
897 *
898 * @param {SVGElement} element
899 * @param {SVGElement} target
900 *
901 * @return {SVGElement} the appended node
902 */
903 function appendTo(element, target) {
904 return target.appendChild(ensureImported(element, target));
905 }
906
907 /**
908 * append utility
909 */
910
911 /**
912 * Append a node to an element
913 *
914 * @param {SVGElement} element
915 * @param {SVGElement} node
916 *
917 * @return {SVGElement} the element
918 */
919 function append(target, node) {
920 appendTo(node, target);
921 return target;
922 }
923
924 /**
925 * attribute accessor utility
926 */
927
928 var LENGTH_ATTR = 2;
929
930 var CSS_PROPERTIES = {
931 'alignment-baseline': 1,
932 'baseline-shift': 1,
933 'clip': 1,
934 'clip-path': 1,
935 'clip-rule': 1,
936 'color': 1,
937 'color-interpolation': 1,
938 'color-interpolation-filters': 1,
939 'color-profile': 1,
940 'color-rendering': 1,
941 'cursor': 1,
942 'direction': 1,
943 'display': 1,
944 'dominant-baseline': 1,
945 'enable-background': 1,
946 'fill': 1,
947 'fill-opacity': 1,
948 'fill-rule': 1,
949 'filter': 1,
950 'flood-color': 1,
951 'flood-opacity': 1,
952 'font': 1,
953 'font-family': 1,
954 'font-size': LENGTH_ATTR,
955 'font-size-adjust': 1,
956 'font-stretch': 1,
957 'font-style': 1,
958 'font-variant': 1,
959 'font-weight': 1,
960 'glyph-orientation-horizontal': 1,
961 'glyph-orientation-vertical': 1,
962 'image-rendering': 1,
963 'kerning': 1,
964 'letter-spacing': 1,
965 'lighting-color': 1,
966 'marker': 1,
967 'marker-end': 1,
968 'marker-mid': 1,
969 'marker-start': 1,
970 'mask': 1,
971 'opacity': 1,
972 'overflow': 1,
973 'pointer-events': 1,
974 'shape-rendering': 1,
975 'stop-color': 1,
976 'stop-opacity': 1,
977 'stroke': 1,
978 'stroke-dasharray': 1,
979 'stroke-dashoffset': 1,
980 'stroke-linecap': 1,
981 'stroke-linejoin': 1,
982 'stroke-miterlimit': 1,
983 'stroke-opacity': 1,
984 'stroke-width': LENGTH_ATTR,
985 'text-anchor': 1,
986 'text-decoration': 1,
987 'text-rendering': 1,
988 'unicode-bidi': 1,
989 'visibility': 1,
990 'word-spacing': 1,
991 'writing-mode': 1
992 };
993
994
995 function getAttribute(node, name) {
996 if (CSS_PROPERTIES[name]) {
997 return node.style[name];
998 } else {
999 return node.getAttributeNS(null, name);
1000 }
1001 }
1002
1003 function setAttribute(node, name, value) {
1004 var hyphenated = name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
1005
1006 var type = CSS_PROPERTIES[hyphenated];
1007
1008 if (type) {
1009 // append pixel unit, unless present
1010 if (type === LENGTH_ATTR && typeof value === 'number') {
1011 value = String(value) + 'px';
1012 }
1013
1014 node.style[hyphenated] = value;
1015 } else {
1016 node.setAttributeNS(null, name, value);
1017 }
1018 }
1019
1020 function setAttributes(node, attrs) {
1021
1022 var names = Object.keys(attrs), i, name;
1023
1024 for (i = 0, name; (name = names[i]); i++) {
1025 setAttribute(node, name, attrs[name]);
1026 }
1027 }
1028
1029 /**
1030 * Gets or sets raw attributes on a node.
1031 *
1032 * @param {SVGElement} node
1033 * @param {Object} [attrs]
1034 * @param {String} [name]
1035 * @param {String} [value]
1036 *
1037 * @return {String}
1038 */
1039 function attr$1(node, name, value) {
1040 if (typeof name === 'string') {
1041 if (value !== undefined) {
1042 setAttribute(node, name, value);
1043 } else {
1044 return getAttribute(node, name);
1045 }
1046 } else {
1047 setAttributes(node, name);
1048 }
1049
1050 return node;
1051 }
1052
1053 /**
1054 * Clear utility
1055 */
1056 function index(arr, obj) {
1057 if (arr.indexOf) {
1058 return arr.indexOf(obj);
1059 }
1060
1061
1062 for (var i = 0; i < arr.length; ++i) {
1063 if (arr[i] === obj) {
1064 return i;
1065 }
1066 }
1067
1068 return -1;
1069 }
1070
1071 var re$1 = /\s+/;
1072
1073 var toString$1 = Object.prototype.toString;
1074
1075 function defined(o) {
1076 return typeof o !== 'undefined';
1077 }
1078
1079 /**
1080 * Wrap `el` in a `ClassList`.
1081 *
1082 * @param {Element} el
1083 * @return {ClassList}
1084 * @api public
1085 */
1086
1087 function classes$1(el) {
1088 return new ClassList$1(el);
1089 }
1090
1091 function ClassList$1(el) {
1092 if (!el || !el.nodeType) {
1093 throw new Error('A DOM element reference is required');
1094 }
1095 this.el = el;
1096 this.list = el.classList;
1097 }
1098
1099 /**
1100 * Add class `name` if not already present.
1101 *
1102 * @param {String} name
1103 * @return {ClassList}
1104 * @api public
1105 */
1106
1107 ClassList$1.prototype.add = function(name) {
1108
1109 // classList
1110 if (this.list) {
1111 this.list.add(name);
1112 return this;
1113 }
1114
1115 // fallback
1116 var arr = this.array();
1117 var i = index(arr, name);
1118 if (!~i) {
1119 arr.push(name);
1120 }
1121
1122 if (defined(this.el.className.baseVal)) {
1123 this.el.className.baseVal = arr.join(' ');
1124 } else {
1125 this.el.className = arr.join(' ');
1126 }
1127
1128 return this;
1129 };
1130
1131 /**
1132 * Remove class `name` when present, or
1133 * pass a regular expression to remove
1134 * any which match.
1135 *
1136 * @param {String|RegExp} name
1137 * @return {ClassList}
1138 * @api public
1139 */
1140
1141 ClassList$1.prototype.remove = function(name) {
1142 if ('[object RegExp]' === toString$1.call(name)) {
1143 return this.removeMatching(name);
1144 }
1145
1146 // classList
1147 if (this.list) {
1148 this.list.remove(name);
1149 return this;
1150 }
1151
1152 // fallback
1153 var arr = this.array();
1154 var i = index(arr, name);
1155 if (~i) {
1156 arr.splice(i, 1);
1157 }
1158 this.el.className.baseVal = arr.join(' ');
1159 return this;
1160 };
1161
1162 /**
1163 * Remove all classes matching `re`.
1164 *
1165 * @param {RegExp} re
1166 * @return {ClassList}
1167 * @api private
1168 */
1169
1170 ClassList$1.prototype.removeMatching = function(re) {
1171 var arr = this.array();
1172 for (var i = 0; i < arr.length; i++) {
1173 if (re.test(arr[i])) {
1174 this.remove(arr[i]);
1175 }
1176 }
1177 return this;
1178 };
1179
1180 /**
1181 * Toggle class `name`, can force state via `force`.
1182 *
1183 * For browsers that support classList, but do not support `force` yet,
1184 * the mistake will be detected and corrected.
1185 *
1186 * @param {String} name
1187 * @param {Boolean} force
1188 * @return {ClassList}
1189 * @api public
1190 */
1191
1192 ClassList$1.prototype.toggle = function(name, force) {
1193 // classList
1194 if (this.list) {
1195 if (defined(force)) {
1196 if (force !== this.list.toggle(name, force)) {
1197 this.list.toggle(name); // toggle again to correct
1198 }
1199 } else {
1200 this.list.toggle(name);
1201 }
1202 return this;
1203 }
1204
1205 // fallback
1206 if (defined(force)) {
1207 if (!force) {
1208 this.remove(name);
1209 } else {
1210 this.add(name);
1211 }
1212 } else {
1213 if (this.has(name)) {
1214 this.remove(name);
1215 } else {
1216 this.add(name);
1217 }
1218 }
1219
1220 return this;
1221 };
1222
1223 /**
1224 * Return an array of classes.
1225 *
1226 * @return {Array}
1227 * @api public
1228 */
1229
1230 ClassList$1.prototype.array = function() {
1231 var className = this.el.getAttribute('class') || '';
1232 var str = className.replace(/^\s+|\s+$/g, '');
1233 var arr = str.split(re$1);
1234 if ('' === arr[0]) {
1235 arr.shift();
1236 }
1237 return arr;
1238 };
1239
1240 /**
1241 * Check if class `name` is present.
1242 *
1243 * @param {String} name
1244 * @return {ClassList}
1245 * @api public
1246 */
1247
1248 ClassList$1.prototype.has =
1249 ClassList$1.prototype.contains = function(name) {
1250 return (
1251 this.list ?
1252 this.list.contains(name) :
1253 !! ~index(this.array(), name)
1254 );
1255 };
1256
1257 function remove$1(element) {
1258 var parent = element.parentNode;
1259
1260 if (parent) {
1261 parent.removeChild(element);
1262 }
1263
1264 return element;
1265 }
1266
1267 /**
1268 * Clear utility
1269 */
1270
1271 /**
1272 * Removes all children from the given element
1273 *
1274 * @param {DOMElement} element
1275 * @return {DOMElement} the element (for chaining)
1276 */
1277 function clear$1(element) {
1278 var child;
1279
1280 while ((child = element.firstChild)) {
1281 remove$1(child);
1282 }
1283
1284 return element;
1285 }
1286
1287 var ns = {
1288 svg: 'http://www.w3.org/2000/svg'
1289 };
1290
1291 /**
1292 * DOM parsing utility
1293 */
1294
1295 var SVG_START = '<svg xmlns="' + ns.svg + '"';
1296
1297 function parse$1(svg) {
1298
1299 var unwrap = false;
1300
1301 // ensure we import a valid svg document
1302 if (svg.substring(0, 4) === '<svg') {
1303 if (svg.indexOf(ns.svg) === -1) {
1304 svg = SVG_START + svg.substring(4);
1305 }
1306 } else {
1307 // namespace svg
1308 svg = SVG_START + '>' + svg + '</svg>';
1309 unwrap = true;
1310 }
1311
1312 var parsed = parseDocument(svg);
1313
1314 if (!unwrap) {
1315 return parsed;
1316 }
1317
1318 var fragment = document.createDocumentFragment();
1319
1320 var parent = parsed.firstChild;
1321
1322 while (parent.firstChild) {
1323 fragment.appendChild(parent.firstChild);
1324 }
1325
1326 return fragment;
1327 }
1328
1329 function parseDocument(svg) {
1330
1331 var parser;
1332
1333 // parse
1334 parser = new DOMParser();
1335 parser.async = false;
1336
1337 return parser.parseFromString(svg, 'text/xml');
1338 }
1339
1340 /**
1341 * Create utility for SVG elements
1342 */
1343
1344
1345 /**
1346 * Create a specific type from name or SVG markup.
1347 *
1348 * @param {String} name the name or markup of the element
1349 * @param {Object} [attrs] attributes to set on the element
1350 *
1351 * @returns {SVGElement}
1352 */
1353 function create(name, attrs) {
1354 var element;
1355
1356 if (name.charAt(0) === '<') {
1357 element = parse$1(name).firstChild;
1358 element = document.importNode(element, true);
1359 } else {
1360 element = document.createElementNS(ns.svg, name);
1361 }
1362
1363 if (attrs) {
1364 attr$1(element, attrs);
1365 }
1366
1367 return element;
1368 }
1369
1370 /**
1371 * Geometry helpers
1372 */
1373
1374 // fake node used to instantiate svg geometry elements
1375 var node = create('svg');
1376
1377 function extend(object, props) {
1378 var i, k, keys = Object.keys(props);
1379
1380 for (i = 0; (k = keys[i]); i++) {
1381 object[k] = props[k];
1382 }
1383
1384 return object;
1385 }
1386
1387 /**
1388 * Create matrix via args.
1389 *
1390 * @example
1391 *
1392 * createMatrix({ a: 1, b: 1 });
1393 * createMatrix();
1394 * createMatrix(1, 2, 0, 0, 30, 20);
1395 *
1396 * @return {SVGMatrix}
1397 */
1398 function createMatrix(a, b, c, d, e, f) {
1399 var matrix = node.createSVGMatrix();
1400
1401 switch (arguments.length) {
1402 case 0:
1403 return matrix;
1404 case 1:
1405 return extend(matrix, a);
1406 case 6:
1407 return extend(matrix, {
1408 a: a,
1409 b: b,
1410 c: c,
1411 d: d,
1412 e: e,
1413 f: f
1414 });
1415 }
1416 }
1417
1418 function createTransform(matrix) {
1419 if (matrix) {
1420 return node.createSVGTransformFromMatrix(matrix);
1421 } else {
1422 return node.createSVGTransform();
1423 }
1424 }
1425
1426 /**
1427 * Serialization util
1428 */
1429
1430 var TEXT_ENTITIES = /([&<>]{1})/g;
1431 var ATTR_ENTITIES = /([\n\r"]{1})/g;
1432
1433 var ENTITY_REPLACEMENT = {
1434 '&': '&amp;',
1435 '<': '&lt;',
1436 '>': '&gt;',
1437 '"': '\''
1438 };
1439
1440 function escape(str, pattern) {
1441
1442 function replaceFn(match, entity) {
1443 return ENTITY_REPLACEMENT[entity] || entity;
1444 }
1445
1446 return str.replace(pattern, replaceFn);
1447 }
1448
1449 function serialize(node, output) {
1450
1451 var i, len, attrMap, attrNode, childNodes;
1452
1453 switch (node.nodeType) {
1454 // TEXT
1455 case 3:
1456 // replace special XML characters
1457 output.push(escape(node.textContent, TEXT_ENTITIES));
1458 break;
1459
1460 // ELEMENT
1461 case 1:
1462 output.push('<', node.tagName);
1463
1464 if (node.hasAttributes()) {
1465 attrMap = node.attributes;
1466 for (i = 0, len = attrMap.length; i < len; ++i) {
1467 attrNode = attrMap.item(i);
1468 output.push(' ', attrNode.name, '="', escape(attrNode.value, ATTR_ENTITIES), '"');
1469 }
1470 }
1471
1472 if (node.hasChildNodes()) {
1473 output.push('>');
1474 childNodes = node.childNodes;
1475 for (i = 0, len = childNodes.length; i < len; ++i) {
1476 serialize(childNodes.item(i), output);
1477 }
1478 output.push('</', node.tagName, '>');
1479 } else {
1480 output.push('/>');
1481 }
1482 break;
1483
1484 // COMMENT
1485 case 8:
1486 output.push('<!--', escape(node.nodeValue, TEXT_ENTITIES), '-->');
1487 break;
1488
1489 // CDATA
1490 case 4:
1491 output.push('<![CDATA[', node.nodeValue, ']]>');
1492 break;
1493
1494 default:
1495 throw new Error('unable to handle node ' + node.nodeType);
1496 }
1497
1498 return output;
1499 }
1500
1501 /**
1502 * innerHTML like functionality for SVG elements.
1503 * based on innerSVG (https://code.google.com/p/innersvg)
1504 */
1505
1506
1507 function set(element, svg) {
1508
1509 var parsed = parse$1(svg);
1510
1511 // clear element contents
1512 clear$1(element);
1513
1514 if (!svg) {
1515 return;
1516 }
1517
1518 if (!isFragment(parsed)) {
1519 // extract <svg> from parsed document
1520 parsed = parsed.documentElement;
1521 }
1522
1523 var nodes = slice(parsed.childNodes);
1524
1525 // import + append each node
1526 for (var i = 0; i < nodes.length; i++) {
1527 appendTo(nodes[i], element);
1528 }
1529
1530 }
1531
1532 function get(element) {
1533 var child = element.firstChild,
1534 output = [];
1535
1536 while (child) {
1537 serialize(child, output);
1538 child = child.nextSibling;
1539 }
1540
1541 return output.join('');
1542 }
1543
1544 function isFragment(node) {
1545 return node.nodeName === '#document-fragment';
1546 }
1547
1548 function innerSVG(element, svg) {
1549
1550 if (svg !== undefined) {
1551
1552 try {
1553 set(element, svg);
1554 } catch (e) {
1555 throw new Error('error parsing SVG: ' + e.message);
1556 }
1557
1558 return element;
1559 } else {
1560 return get(element);
1561 }
1562 }
1563
1564
1565 function slice(arr) {
1566 return Array.prototype.slice.call(arr);
1567 }
1568
1569 /**
1570 * transform accessor utility
1571 */
1572
1573 function wrapMatrix(transformList, transform) {
1574 if (transform instanceof SVGMatrix) {
1575 return transformList.createSVGTransformFromMatrix(transform);
1576 }
1577
1578 return transform;
1579 }
1580
1581
1582 function setTransforms(transformList, transforms) {
1583 var i, t;
1584
1585 transformList.clear();
1586
1587 for (i = 0; (t = transforms[i]); i++) {
1588 transformList.appendItem(wrapMatrix(transformList, t));
1589 }
1590 }
1591
1592 /**
1593 * Get or set the transforms on the given node.
1594 *
1595 * @param {SVGElement} node
1596 * @param {SVGTransform|SVGMatrix|Array<SVGTransform|SVGMatrix>} [transforms]
1597 *
1598 * @return {SVGTransform} the consolidated transform
1599 */
1600 function transform(node, transforms) {
1601 var transformList = node.transform.baseVal;
1602
1603 if (transforms) {
1604
1605 if (!Array.isArray(transforms)) {
1606 transforms = [ transforms ];
1607 }
1608
1609 setTransforms(transformList, transforms);
1610 }
1611
1612 return transformList.consolidate();
1613 }
1614
1615 var CLASS_PATTERN = /^class /;
1616
1617 function isClass(fn) {
1618 return CLASS_PATTERN.test(fn.toString());
1619 }
1620
1621 function isArray$1(obj) {
1622 return Object.prototype.toString.call(obj) === '[object Array]';
1623 }
1624
1625 function annotate() {
1626 var args = Array.prototype.slice.call(arguments);
1627
1628 if (args.length === 1 && isArray$1(args[0])) {
1629 args = args[0];
1630 }
1631
1632 var fn = args.pop();
1633
1634 fn.$inject = args;
1635
1636 return fn;
1637 }
1638
1639 // Current limitations:
1640 // - can't put into "function arg" comments
1641 // function /* (no parenthesis like this) */ (){}
1642 // function abc( /* xx (no parenthesis like this) */ a, b) {}
1643 //
1644 // Just put the comment before function or inside:
1645 // /* (((this is fine))) */ function(a, b) {}
1646 // function abc(a) { /* (((this is fine))) */}
1647 //
1648 // - can't reliably auto-annotate constructor; we'll match the
1649 // first constructor(...) pattern found which may be the one
1650 // of a nested class, too.
1651
1652 var CONSTRUCTOR_ARGS = /constructor\s*[^(]*\(\s*([^)]*)\)/m;
1653 var FN_ARGS = /^function\s*[^(]*\(\s*([^)]*)\)/m;
1654 var FN_ARG = /\/\*([^*]*)\*\//m;
1655
1656 function parse$2(fn) {
1657
1658 if (typeof fn !== 'function') {
1659 throw new Error('Cannot annotate "' + fn + '". Expected a function!');
1660 }
1661
1662 var match = fn.toString().match(isClass(fn) ? CONSTRUCTOR_ARGS : FN_ARGS);
1663
1664 // may parse class without constructor
1665 if (!match) {
1666 return [];
1667 }
1668
1669 return match[1] && match[1].split(',').map(function (arg) {
1670 match = arg.match(FN_ARG);
1671 return match ? match[1].trim() : arg.trim();
1672 }) || [];
1673 }
1674
1675 function Module() {
1676 var providers = [];
1677
1678 this.factory = function (name, factory) {
1679 providers.push([name, 'factory', factory]);
1680 return this;
1681 };
1682
1683 this.value = function (name, value) {
1684 providers.push([name, 'value', value]);
1685 return this;
1686 };
1687
1688 this.type = function (name, type) {
1689 providers.push([name, 'type', type]);
1690 return this;
1691 };
1692
1693 this.forEach = function (iterator) {
1694 providers.forEach(iterator);
1695 };
1696 }
1697
1698 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; };
1699
1700 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); } }
1701
1702 function Injector(modules, parent) {
1703 parent = parent || {
1704 get: function get(name, strict) {
1705 currentlyResolving.push(name);
1706
1707 if (strict === false) {
1708 return null;
1709 } else {
1710 throw error('No provider for "' + name + '"!');
1711 }
1712 }
1713 };
1714
1715 var currentlyResolving = [];
1716 var providers = this._providers = Object.create(parent._providers || null);
1717 var instances = this._instances = Object.create(null);
1718
1719 var self = instances.injector = this;
1720
1721 var error = function error(msg) {
1722 var stack = currentlyResolving.join(' -> ');
1723 currentlyResolving.length = 0;
1724 return new Error(stack ? msg + ' (Resolving: ' + stack + ')' : msg);
1725 };
1726
1727 /**
1728 * Return a named service.
1729 *
1730 * @param {String} name
1731 * @param {Boolean} [strict=true] if false, resolve missing services to null
1732 *
1733 * @return {Object}
1734 */
1735 var get = function get(name, strict) {
1736 if (!providers[name] && name.indexOf('.') !== -1) {
1737 var parts = name.split('.');
1738 var pivot = get(parts.shift());
1739
1740 while (parts.length) {
1741 pivot = pivot[parts.shift()];
1742 }
1743
1744 return pivot;
1745 }
1746
1747 if (hasProp(instances, name)) {
1748 return instances[name];
1749 }
1750
1751 if (hasProp(providers, name)) {
1752 if (currentlyResolving.indexOf(name) !== -1) {
1753 currentlyResolving.push(name);
1754 throw error('Cannot resolve circular dependency!');
1755 }
1756
1757 currentlyResolving.push(name);
1758 instances[name] = providers[name][0](providers[name][1]);
1759 currentlyResolving.pop();
1760
1761 return instances[name];
1762 }
1763
1764 return parent.get(name, strict);
1765 };
1766
1767 var fnDef = function fnDef(fn) {
1768 var locals = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1769
1770 if (typeof fn !== 'function') {
1771 if (isArray$1(fn)) {
1772 fn = annotate(fn.slice());
1773 } else {
1774 throw new Error('Cannot invoke "' + fn + '". Expected a function!');
1775 }
1776 }
1777
1778 var inject = fn.$inject || parse$2(fn);
1779 var dependencies = inject.map(function (dep) {
1780 if (hasProp(locals, dep)) {
1781 return locals[dep];
1782 } else {
1783 return get(dep);
1784 }
1785 });
1786
1787 return {
1788 fn: fn,
1789 dependencies: dependencies
1790 };
1791 };
1792
1793 var instantiate = function instantiate(Type) {
1794 var _fnDef = fnDef(Type),
1795 dependencies = _fnDef.dependencies,
1796 fn = _fnDef.fn;
1797
1798 return new (Function.prototype.bind.apply(fn, [null].concat(_toConsumableArray(dependencies))))();
1799 };
1800
1801 var invoke = function invoke(func, context, locals) {
1802 var _fnDef2 = fnDef(func, locals),
1803 dependencies = _fnDef2.dependencies,
1804 fn = _fnDef2.fn;
1805
1806 return fn.call.apply(fn, [context].concat(_toConsumableArray(dependencies)));
1807 };
1808
1809 var createPrivateInjectorFactory = function createPrivateInjectorFactory(privateChildInjector) {
1810 return annotate(function (key) {
1811 return privateChildInjector.get(key);
1812 });
1813 };
1814
1815 var createChild = function createChild(modules, forceNewInstances) {
1816 if (forceNewInstances && forceNewInstances.length) {
1817 var fromParentModule = Object.create(null);
1818 var matchedScopes = Object.create(null);
1819
1820 var privateInjectorsCache = [];
1821 var privateChildInjectors = [];
1822 var privateChildFactories = [];
1823
1824 var provider;
1825 var cacheIdx;
1826 var privateChildInjector;
1827 var privateChildInjectorFactory;
1828 for (var name in providers) {
1829 provider = providers[name];
1830
1831 if (forceNewInstances.indexOf(name) !== -1) {
1832 if (provider[2] === 'private') {
1833 cacheIdx = privateInjectorsCache.indexOf(provider[3]);
1834 if (cacheIdx === -1) {
1835 privateChildInjector = provider[3].createChild([], forceNewInstances);
1836 privateChildInjectorFactory = createPrivateInjectorFactory(privateChildInjector);
1837 privateInjectorsCache.push(provider[3]);
1838 privateChildInjectors.push(privateChildInjector);
1839 privateChildFactories.push(privateChildInjectorFactory);
1840 fromParentModule[name] = [privateChildInjectorFactory, name, 'private', privateChildInjector];
1841 } else {
1842 fromParentModule[name] = [privateChildFactories[cacheIdx], name, 'private', privateChildInjectors[cacheIdx]];
1843 }
1844 } else {
1845 fromParentModule[name] = [provider[2], provider[1]];
1846 }
1847 matchedScopes[name] = true;
1848 }
1849
1850 if ((provider[2] === 'factory' || provider[2] === 'type') && provider[1].$scope) {
1851 /* jshint -W083 */
1852 forceNewInstances.forEach(function (scope) {
1853 if (provider[1].$scope.indexOf(scope) !== -1) {
1854 fromParentModule[name] = [provider[2], provider[1]];
1855 matchedScopes[scope] = true;
1856 }
1857 });
1858 }
1859 }
1860
1861 forceNewInstances.forEach(function (scope) {
1862 if (!matchedScopes[scope]) {
1863 throw new Error('No provider for "' + scope + '". Cannot use provider from the parent!');
1864 }
1865 });
1866
1867 modules.unshift(fromParentModule);
1868 }
1869
1870 return new Injector(modules, self);
1871 };
1872
1873 var factoryMap = {
1874 factory: invoke,
1875 type: instantiate,
1876 value: function value(_value) {
1877 return _value;
1878 }
1879 };
1880
1881 modules.forEach(function (module) {
1882
1883 function arrayUnwrap(type, value) {
1884 if (type !== 'value' && isArray$1(value)) {
1885 value = annotate(value.slice());
1886 }
1887
1888 return value;
1889 }
1890
1891 // TODO(vojta): handle wrong inputs (modules)
1892 if (module instanceof Module) {
1893 module.forEach(function (provider) {
1894 var name = provider[0];
1895 var type = provider[1];
1896 var value = provider[2];
1897
1898 providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
1899 });
1900 } else if ((typeof module === 'undefined' ? 'undefined' : _typeof(module)) === 'object') {
1901 if (module.__exports__) {
1902 var clonedModule = Object.keys(module).reduce(function (m, key) {
1903 if (key.substring(0, 2) !== '__') {
1904 m[key] = module[key];
1905 }
1906 return m;
1907 }, Object.create(null));
1908
1909 var privateInjector = new Injector((module.__modules__ || []).concat([clonedModule]), self);
1910 var getFromPrivateInjector = annotate(function (key) {
1911 return privateInjector.get(key);
1912 });
1913 module.__exports__.forEach(function (key) {
1914 providers[key] = [getFromPrivateInjector, key, 'private', privateInjector];
1915 });
1916 } else {
1917 Object.keys(module).forEach(function (name) {
1918 if (module[name][2] === 'private') {
1919 providers[name] = module[name];
1920 return;
1921 }
1922
1923 var type = module[name][0];
1924 var value = module[name][1];
1925
1926 providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
1927 });
1928 }
1929 }
1930 });
1931
1932 // public API
1933 this.get = get;
1934 this.invoke = invoke;
1935 this.instantiate = instantiate;
1936 this.createChild = createChild;
1937 }
1938
1939 // helpers /////////////////
1940
1941 function hasProp(obj, prop) {
1942 return Object.hasOwnProperty.call(obj, prop);
1943 }
1944
1945 function createCommonjsModule(fn, module) {
1946 return module = { exports: {} }, fn(module, module.exports), module.exports;
1947 }
1948
1949 var inherits_browser = createCommonjsModule(function (module) {
1950 if (typeof Object.create === 'function') {
1951 // implementation from standard node.js 'util' module
1952 module.exports = function inherits(ctor, superCtor) {
1953 ctor.super_ = superCtor;
1954 ctor.prototype = Object.create(superCtor.prototype, {
1955 constructor: {
1956 value: ctor,
1957 enumerable: false,
1958 writable: true,
1959 configurable: true
1960 }
1961 });
1962 };
1963 } else {
1964 // old school shim for old browsers
1965 module.exports = function inherits(ctor, superCtor) {
1966 ctor.super_ = superCtor;
1967 var TempCtor = function () {};
1968 TempCtor.prototype = superCtor.prototype;
1969 ctor.prototype = new TempCtor();
1970 ctor.prototype.constructor = ctor;
1971 };
1972 }
1973 });
1974
1975 var DEFAULT_RENDER_PRIORITY = 1000;
1976
1977 /**
1978 * The base implementation of shape and connection renderers.
1979 *
1980 * @param {EventBus} eventBus
1981 * @param {Number} [renderPriority=1000]
1982 */
1983 function BaseRenderer(eventBus, renderPriority) {
1984 var self = this;
1985
1986 renderPriority = renderPriority || DEFAULT_RENDER_PRIORITY;
1987
1988 eventBus.on([ 'render.shape', 'render.connection' ], renderPriority, function(evt, context) {
1989 var type = evt.type,
1990 element = context.element,
1991 visuals = context.gfx;
1992
1993 if (self.canRender(element)) {
1994 if (type === 'render.shape') {
1995 return self.drawShape(visuals, element);
1996 } else {
1997 return self.drawConnection(visuals, element);
1998 }
1999 }
2000 });
2001
2002 eventBus.on([ 'render.getShapePath', 'render.getConnectionPath'], renderPriority, function(evt, element) {
2003 if (self.canRender(element)) {
2004 if (evt.type === 'render.getShapePath') {
2005 return self.getShapePath(element);
2006 } else {
2007 return self.getConnectionPath(element);
2008 }
2009 }
2010 });
2011 }
2012
2013 /**
2014 * Should check whether *this* renderer can render
2015 * the element/connection.
2016 *
2017 * @param {element} element
2018 *
2019 * @returns {Boolean}
2020 */
2021 BaseRenderer.prototype.canRender = function() {};
2022
2023 /**
2024 * Provides the shape's snap svg element to be drawn on the `canvas`.
2025 *
2026 * @param {djs.Graphics} visuals
2027 * @param {Shape} shape
2028 *
2029 * @returns {Snap.svg} [returns a Snap.svg paper element ]
2030 */
2031 BaseRenderer.prototype.drawShape = function() {};
2032
2033 /**
2034 * Provides the shape's snap svg element to be drawn on the `canvas`.
2035 *
2036 * @param {djs.Graphics} visuals
2037 * @param {Connection} connection
2038 *
2039 * @returns {Snap.svg} [returns a Snap.svg paper element ]
2040 */
2041 BaseRenderer.prototype.drawConnection = function() {};
2042
2043 /**
2044 * Gets the SVG path of a shape that represents it's visual bounds.
2045 *
2046 * @param {Shape} shape
2047 *
2048 * @return {string} svg path
2049 */
2050 BaseRenderer.prototype.getShapePath = function() {};
2051
2052 /**
2053 * Gets the SVG path of a connection that represents it's visual bounds.
2054 *
2055 * @param {Connection} connection
2056 *
2057 * @return {string} svg path
2058 */
2059 BaseRenderer.prototype.getConnectionPath = function() {};
2060
2061 function componentsToPath(elements) {
2062 return elements.join(',').replace(/,?([A-z]),?/g, '$1');
2063 }
2064
2065 function toSVGPoints(points) {
2066 var result = '';
2067
2068 for (var i = 0, p; (p = points[i]); i++) {
2069 result += p.x + ',' + p.y + ' ';
2070 }
2071
2072 return result;
2073 }
2074
2075 function createLine(points, attrs) {
2076
2077 var line = create('polyline');
2078 attr$1(line, { points: toSVGPoints(points) });
2079
2080 if (attrs) {
2081 attr$1(line, attrs);
2082 }
2083
2084 return line;
2085 }
2086
2087 function updateLine(gfx, points) {
2088 attr$1(gfx, { points: toSVGPoints(points) });
2089
2090 return gfx;
2091 }
2092
2093 /**
2094 * Returns the surrounding bbox for all elements in
2095 * the array or the element primitive.
2096 *
2097 * @param {Array<djs.model.Shape>|djs.model.Shape} elements
2098 * @param {Boolean} stopRecursion
2099 */
2100 function getBBox(elements, stopRecursion) {
2101
2102 stopRecursion = !!stopRecursion;
2103 if (!isArray(elements)) {
2104 elements = [elements];
2105 }
2106
2107 var minX,
2108 minY,
2109 maxX,
2110 maxY;
2111
2112 forEach(elements, function(element) {
2113
2114 // If element is a connection the bbox must be computed first
2115 var bbox = element;
2116 if (element.waypoints && !stopRecursion) {
2117 bbox = getBBox(element.waypoints, true);
2118 }
2119
2120 var x = bbox.x,
2121 y = bbox.y,
2122 height = bbox.height || 0,
2123 width = bbox.width || 0;
2124
2125 if (x < minX || minX === undefined) {
2126 minX = x;
2127 }
2128 if (y < minY || minY === undefined) {
2129 minY = y;
2130 }
2131
2132 if ((x + width) > maxX || maxX === undefined) {
2133 maxX = x + width;
2134 }
2135 if ((y + height) > maxY || maxY === undefined) {
2136 maxY = y + height;
2137 }
2138 });
2139
2140 return {
2141 x: minX,
2142 y: minY,
2143 height: maxY - minY,
2144 width: maxX - minX
2145 };
2146 }
2147
2148
2149 function getType(element) {
2150
2151 if ('waypoints' in element) {
2152 return 'connection';
2153 }
2154
2155 if ('x' in element) {
2156 return 'shape';
2157 }
2158
2159 return 'root';
2160 }
2161
2162 function isFrameElement(element) {
2163
2164 return !!(element && element.isFrame);
2165 }
2166
2167 // apply default renderer with lowest possible priority
2168 // so that it only kicks in if noone else could render
2169 var DEFAULT_RENDER_PRIORITY$1 = 1;
2170
2171 /**
2172 * The default renderer used for shapes and connections.
2173 *
2174 * @param {EventBus} eventBus
2175 * @param {Styles} styles
2176 */
2177 function DefaultRenderer(eventBus, styles) {
2178
2179 //
2180 BaseRenderer.call(this, eventBus, DEFAULT_RENDER_PRIORITY$1);
2181
2182 this.CONNECTION_STYLE = styles.style([ 'no-fill' ], { strokeWidth: 5, stroke: 'fuchsia' });
2183 this.SHAPE_STYLE = styles.style({ fill: 'white', stroke: 'fuchsia', strokeWidth: 2 });
2184 this.FRAME_STYLE = styles.style([ 'no-fill' ], { stroke: 'fuchsia', strokeDasharray: 4, strokeWidth: 2 });
2185 }
2186
2187 inherits_browser(DefaultRenderer, BaseRenderer);
2188
2189
2190 DefaultRenderer.prototype.canRender = function() {
2191 return true;
2192 };
2193
2194 DefaultRenderer.prototype.drawShape = function drawShape(visuals, element) {
2195 var rect = create('rect');
2196
2197 attr$1(rect, {
2198 x: 0,
2199 y: 0,
2200 width: element.width || 0,
2201 height: element.height || 0
2202 });
2203
2204 if (isFrameElement(element)) {
2205 attr$1(rect, this.FRAME_STYLE);
2206 } else {
2207 attr$1(rect, this.SHAPE_STYLE);
2208 }
2209
2210 append(visuals, rect);
2211
2212 return rect;
2213 };
2214
2215 DefaultRenderer.prototype.drawConnection = function drawConnection(visuals, connection) {
2216
2217 var line = createLine(connection.waypoints, this.CONNECTION_STYLE);
2218 append(visuals, line);
2219
2220 return line;
2221 };
2222
2223 DefaultRenderer.prototype.getShapePath = function getShapePath(shape) {
2224
2225 var x = shape.x,
2226 y = shape.y,
2227 width = shape.width,
2228 height = shape.height;
2229
2230 var shapePath = [
2231 ['M', x, y],
2232 ['l', width, 0],
2233 ['l', 0, height],
2234 ['l', -width, 0],
2235 ['z']
2236 ];
2237
2238 return componentsToPath(shapePath);
2239 };
2240
2241 DefaultRenderer.prototype.getConnectionPath = function getConnectionPath(connection) {
2242 var waypoints = connection.waypoints;
2243
2244 var idx, point, connectionPath = [];
2245
2246 for (idx = 0; (point = waypoints[idx]); idx++) {
2247
2248 // take invisible docking into account
2249 // when creating the path
2250 point = point.original || point;
2251
2252 connectionPath.push([ idx === 0 ? 'M' : 'L', point.x, point.y ]);
2253 }
2254
2255 return componentsToPath(connectionPath);
2256 };
2257
2258
2259 DefaultRenderer.$inject = [ 'eventBus', 'styles' ];
2260
2261 /**
2262 * A component that manages shape styles
2263 */
2264 function Styles() {
2265
2266 var defaultTraits = {
2267
2268 'no-fill': {
2269 fill: 'none'
2270 },
2271 'no-border': {
2272 strokeOpacity: 0.0
2273 },
2274 'no-events': {
2275 pointerEvents: 'none'
2276 }
2277 };
2278
2279 var self = this;
2280
2281 /**
2282 * Builds a style definition from a className, a list of traits and an object of additional attributes.
2283 *
2284 * @param {String} className
2285 * @param {Array<String>} traits
2286 * @param {Object} additionalAttrs
2287 *
2288 * @return {Object} the style defintion
2289 */
2290 this.cls = function(className, traits, additionalAttrs) {
2291 var attrs = this.style(traits, additionalAttrs);
2292
2293 return assign(attrs, { 'class': className });
2294 };
2295
2296 /**
2297 * Builds a style definition from a list of traits and an object of additional attributes.
2298 *
2299 * @param {Array<String>} traits
2300 * @param {Object} additionalAttrs
2301 *
2302 * @return {Object} the style defintion
2303 */
2304 this.style = function(traits, additionalAttrs) {
2305
2306 if (!isArray(traits) && !additionalAttrs) {
2307 additionalAttrs = traits;
2308 traits = [];
2309 }
2310
2311 var attrs = reduce(traits, function(attrs, t) {
2312 return assign(attrs, defaultTraits[t] || {});
2313 }, {});
2314
2315 return additionalAttrs ? assign(attrs, additionalAttrs) : attrs;
2316 };
2317
2318 this.computeStyle = function(custom, traits, defaultStyles) {
2319 if (!isArray(traits)) {
2320 defaultStyles = traits;
2321 traits = [];
2322 }
2323
2324 return self.style(traits || [], assign({}, defaultStyles, custom || {}));
2325 };
2326 }
2327
2328 var DrawModule = {
2329 __init__: [ 'defaultRenderer' ],
2330 defaultRenderer: [ 'type', DefaultRenderer ],
2331 styles: [ 'type', Styles ]
2332 };
2333
2334 /**
2335 * Failsafe remove an element from a collection
2336 *
2337 * @param {Array<Object>} [collection]
2338 * @param {Object} [element]
2339 *
2340 * @return {Number} the previous index of the element
2341 */
2342 function remove$2(collection, element) {
2343
2344 if (!collection || !element) {
2345 return -1;
2346 }
2347
2348 var idx = collection.indexOf(element);
2349
2350 if (idx !== -1) {
2351 collection.splice(idx, 1);
2352 }
2353
2354 return idx;
2355 }
2356
2357 /**
2358 * Fail save add an element to the given connection, ensuring
2359 * it does not yet exist.
2360 *
2361 * @param {Array<Object>} collection
2362 * @param {Object} element
2363 * @param {Number} idx
2364 */
2365 function add(collection, element, idx) {
2366
2367 if (!collection || !element) {
2368 return;
2369 }
2370
2371 if (typeof idx !== 'number') {
2372 idx = -1;
2373 }
2374
2375 var currentIdx = collection.indexOf(element);
2376
2377 if (currentIdx !== -1) {
2378
2379 if (currentIdx === idx) {
2380
2381 // nothing to do, position has not changed
2382 return;
2383 } else {
2384
2385 if (idx !== -1) {
2386
2387 // remove from current position
2388 collection.splice(currentIdx, 1);
2389 } else {
2390
2391 // already exists in collection
2392 return;
2393 }
2394 }
2395 }
2396
2397 if (idx !== -1) {
2398
2399 // insert at specified position
2400 collection.splice(idx, 0, element);
2401 } else {
2402
2403 // push to end
2404 collection.push(element);
2405 }
2406 }
2407
2408 function round(number, resolution) {
2409 return Math.round(number * resolution) / resolution;
2410 }
2411
2412 function ensurePx(number) {
2413 return isNumber(number) ? number + 'px' : number;
2414 }
2415
2416 /**
2417 * Creates a HTML container element for a SVG element with
2418 * the given configuration
2419 *
2420 * @param {Object} options
2421 * @return {HTMLElement} the container element
2422 */
2423 function createContainer(options) {
2424
2425 options = assign({}, { width: '100%', height: '100%' }, options);
2426
2427 var container = options.container || document.body;
2428
2429 // create a <div> around the svg element with the respective size
2430 // this way we can always get the correct container size
2431 // (this is impossible for <svg> elements at the moment)
2432 var parent = document.createElement('div');
2433 parent.setAttribute('class', 'djs-container');
2434
2435 assign(parent.style, {
2436 position: 'relative',
2437 overflow: 'hidden',
2438 width: ensurePx(options.width),
2439 height: ensurePx(options.height)
2440 });
2441
2442 container.appendChild(parent);
2443
2444 return parent;
2445 }
2446
2447 function createGroup(parent, cls, childIndex) {
2448 var group = create('g');
2449 classes$1(group).add(cls);
2450
2451 var index = childIndex !== undefined ? childIndex : parent.childNodes.length - 1;
2452
2453 // must ensure second argument is node or _null_
2454 // cf. https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore
2455 parent.insertBefore(group, parent.childNodes[index] || null);
2456
2457 return group;
2458 }
2459
2460 var BASE_LAYER = 'base';
2461
2462
2463 var REQUIRED_MODEL_ATTRS = {
2464 shape: [ 'x', 'y', 'width', 'height' ],
2465 connection: [ 'waypoints' ]
2466 };
2467
2468 /**
2469 * The main drawing canvas.
2470 *
2471 * @class
2472 * @constructor
2473 *
2474 * @emits Canvas#canvas.init
2475 *
2476 * @param {Object} config
2477 * @param {EventBus} eventBus
2478 * @param {GraphicsFactory} graphicsFactory
2479 * @param {ElementRegistry} elementRegistry
2480 */
2481 function Canvas(config, eventBus, graphicsFactory, elementRegistry) {
2482
2483 this._eventBus = eventBus;
2484 this._elementRegistry = elementRegistry;
2485 this._graphicsFactory = graphicsFactory;
2486
2487 this._init(config || {});
2488 }
2489
2490 Canvas.$inject = [
2491 'config.canvas',
2492 'eventBus',
2493 'graphicsFactory',
2494 'elementRegistry'
2495 ];
2496
2497
2498 Canvas.prototype._init = function(config) {
2499
2500 var eventBus = this._eventBus;
2501
2502 // Creates a <svg> element that is wrapped into a <div>.
2503 // This way we are always able to correctly figure out the size of the svg element
2504 // by querying the parent node.
2505 //
2506 // (It is not possible to get the size of a svg element cross browser @ 2014-04-01)
2507 //
2508 // <div class="djs-container" style="width: {desired-width}, height: {desired-height}">
2509 // <svg width="100%" height="100%">
2510 // ...
2511 // </svg>
2512 // </div>
2513
2514 // html container
2515 var container = this._container = createContainer(config);
2516
2517 var svg = this._svg = create('svg');
2518 attr$1(svg, { width: '100%', height: '100%' });
2519
2520 append(container, svg);
2521
2522 var viewport = this._viewport = createGroup(svg, 'viewport');
2523
2524 this._layers = {};
2525
2526 // debounce canvas.viewbox.changed events
2527 // for smoother diagram interaction
2528 if (config.deferUpdate !== false) {
2529 this._viewboxChanged = debounce(bind(this._viewboxChanged, this), 300);
2530 }
2531
2532 eventBus.on('diagram.init', function() {
2533
2534 /**
2535 * An event indicating that the canvas is ready to be drawn on.
2536 *
2537 * @memberOf Canvas
2538 *
2539 * @event canvas.init
2540 *
2541 * @type {Object}
2542 * @property {SVGElement} svg the created svg element
2543 * @property {SVGElement} viewport the direct parent of diagram elements and shapes
2544 */
2545 eventBus.fire('canvas.init', {
2546 svg: svg,
2547 viewport: viewport
2548 });
2549
2550 }, this);
2551
2552 // reset viewbox on shape changes to
2553 // recompute the viewbox
2554 eventBus.on([
2555 'shape.added',
2556 'connection.added',
2557 'shape.removed',
2558 'connection.removed',
2559 'elements.changed'
2560 ], function() {
2561 delete this._cachedViewbox;
2562 }, this);
2563
2564 eventBus.on('diagram.destroy', 500, this._destroy, this);
2565 eventBus.on('diagram.clear', 500, this._clear, this);
2566 };
2567
2568 Canvas.prototype._destroy = function(emit) {
2569 this._eventBus.fire('canvas.destroy', {
2570 svg: this._svg,
2571 viewport: this._viewport
2572 });
2573
2574 var parent = this._container.parentNode;
2575
2576 if (parent) {
2577 parent.removeChild(this._container);
2578 }
2579
2580 delete this._svg;
2581 delete this._container;
2582 delete this._layers;
2583 delete this._rootElement;
2584 delete this._viewport;
2585 };
2586
2587 Canvas.prototype._clear = function() {
2588
2589 var self = this;
2590
2591 var allElements = this._elementRegistry.getAll();
2592
2593 // remove all elements
2594 allElements.forEach(function(element) {
2595 var type = getType(element);
2596
2597 if (type === 'root') {
2598 self.setRootElement(null, true);
2599 } else {
2600 self._removeElement(element, type);
2601 }
2602 });
2603
2604 // force recomputation of view box
2605 delete this._cachedViewbox;
2606 };
2607
2608 /**
2609 * Returns the default layer on which
2610 * all elements are drawn.
2611 *
2612 * @returns {SVGElement}
2613 */
2614 Canvas.prototype.getDefaultLayer = function() {
2615 return this.getLayer(BASE_LAYER, 0);
2616 };
2617
2618 /**
2619 * Returns a layer that is used to draw elements
2620 * or annotations on it.
2621 *
2622 * Non-existing layers retrieved through this method
2623 * will be created. During creation, the optional index
2624 * may be used to create layers below or above existing layers.
2625 * A layer with a certain index is always created above all
2626 * existing layers with the same index.
2627 *
2628 * @param {String} name
2629 * @param {Number} index
2630 *
2631 * @returns {SVGElement}
2632 */
2633 Canvas.prototype.getLayer = function(name, index) {
2634
2635 if (!name) {
2636 throw new Error('must specify a name');
2637 }
2638
2639 var layer = this._layers[name];
2640
2641 if (!layer) {
2642 layer = this._layers[name] = this._createLayer(name, index);
2643 }
2644
2645 // throw an error if layer creation / retrival is
2646 // requested on different index
2647 if (typeof index !== 'undefined' && layer.index !== index) {
2648 throw new Error('layer <' + name + '> already created at index <' + index + '>');
2649 }
2650
2651 return layer.group;
2652 };
2653
2654 /**
2655 * Creates a given layer and returns it.
2656 *
2657 * @param {String} name
2658 * @param {Number} [index=0]
2659 *
2660 * @return {Object} layer descriptor with { index, group: SVGGroup }
2661 */
2662 Canvas.prototype._createLayer = function(name, index) {
2663
2664 if (!index) {
2665 index = 0;
2666 }
2667
2668 var childIndex = reduce(this._layers, function(childIndex, layer) {
2669 if (index >= layer.index) {
2670 childIndex++;
2671 }
2672
2673 return childIndex;
2674 }, 0);
2675
2676 return {
2677 group: createGroup(this._viewport, 'layer-' + name, childIndex),
2678 index: index
2679 };
2680
2681 };
2682
2683 /**
2684 * Returns the html element that encloses the
2685 * drawing canvas.
2686 *
2687 * @return {DOMNode}
2688 */
2689 Canvas.prototype.getContainer = function() {
2690 return this._container;
2691 };
2692
2693
2694 // markers //////////////////////
2695
2696 Canvas.prototype._updateMarker = function(element, marker, add) {
2697 var container;
2698
2699 if (!element.id) {
2700 element = this._elementRegistry.get(element);
2701 }
2702
2703 // we need to access all
2704 container = this._elementRegistry._elements[element.id];
2705
2706 if (!container) {
2707 return;
2708 }
2709
2710 forEach([ container.gfx, container.secondaryGfx ], function(gfx) {
2711 if (gfx) {
2712
2713 // invoke either addClass or removeClass based on mode
2714 if (add) {
2715 classes$1(gfx).add(marker);
2716 } else {
2717 classes$1(gfx).remove(marker);
2718 }
2719 }
2720 });
2721
2722 /**
2723 * An event indicating that a marker has been updated for an element
2724 *
2725 * @event element.marker.update
2726 * @type {Object}
2727 * @property {djs.model.Element} element the shape
2728 * @property {Object} gfx the graphical representation of the shape
2729 * @property {String} marker
2730 * @property {Boolean} add true if the marker was added, false if it got removed
2731 */
2732 this._eventBus.fire('element.marker.update', { element: element, gfx: container.gfx, marker: marker, add: !!add });
2733 };
2734
2735
2736 /**
2737 * Adds a marker to an element (basically a css class).
2738 *
2739 * Fires the element.marker.update event, making it possible to
2740 * integrate extension into the marker life-cycle, too.
2741 *
2742 * @example
2743 * canvas.addMarker('foo', 'some-marker');
2744 *
2745 * var fooGfx = canvas.getGraphics('foo');
2746 *
2747 * fooGfx; // <g class="... some-marker"> ... </g>
2748 *
2749 * @param {String|djs.model.Base} element
2750 * @param {String} marker
2751 */
2752 Canvas.prototype.addMarker = function(element, marker) {
2753 this._updateMarker(element, marker, true);
2754 };
2755
2756
2757 /**
2758 * Remove a marker from an element.
2759 *
2760 * Fires the element.marker.update event, making it possible to
2761 * integrate extension into the marker life-cycle, too.
2762 *
2763 * @param {String|djs.model.Base} element
2764 * @param {String} marker
2765 */
2766 Canvas.prototype.removeMarker = function(element, marker) {
2767 this._updateMarker(element, marker, false);
2768 };
2769
2770 /**
2771 * Check the existence of a marker on element.
2772 *
2773 * @param {String|djs.model.Base} element
2774 * @param {String} marker
2775 */
2776 Canvas.prototype.hasMarker = function(element, marker) {
2777 if (!element.id) {
2778 element = this._elementRegistry.get(element);
2779 }
2780
2781 var gfx = this.getGraphics(element);
2782
2783 return classes$1(gfx).has(marker);
2784 };
2785
2786 /**
2787 * Toggles a marker on an element.
2788 *
2789 * Fires the element.marker.update event, making it possible to
2790 * integrate extension into the marker life-cycle, too.
2791 *
2792 * @param {String|djs.model.Base} element
2793 * @param {String} marker
2794 */
2795 Canvas.prototype.toggleMarker = function(element, marker) {
2796 if (this.hasMarker(element, marker)) {
2797 this.removeMarker(element, marker);
2798 } else {
2799 this.addMarker(element, marker);
2800 }
2801 };
2802
2803 Canvas.prototype.getRootElement = function() {
2804 if (!this._rootElement) {
2805 this.setRootElement({ id: '__implicitroot', children: [] });
2806 }
2807
2808 return this._rootElement;
2809 };
2810
2811
2812
2813 // root element handling //////////////////////
2814
2815 /**
2816 * Sets a given element as the new root element for the canvas
2817 * and returns the new root element.
2818 *
2819 * @param {Object|djs.model.Root} element
2820 * @param {Boolean} [override] whether to override the current root element, if any
2821 *
2822 * @return {Object|djs.model.Root} new root element
2823 */
2824 Canvas.prototype.setRootElement = function(element, override) {
2825
2826 if (element) {
2827 this._ensureValid('root', element);
2828 }
2829
2830 var currentRoot = this._rootElement,
2831 elementRegistry = this._elementRegistry,
2832 eventBus = this._eventBus;
2833
2834 if (currentRoot) {
2835 if (!override) {
2836 throw new Error('rootElement already set, need to specify override');
2837 }
2838
2839 // simulate element remove event sequence
2840 eventBus.fire('root.remove', { element: currentRoot });
2841 eventBus.fire('root.removed', { element: currentRoot });
2842
2843 elementRegistry.remove(currentRoot);
2844 }
2845
2846 if (element) {
2847 var gfx = this.getDefaultLayer();
2848
2849 // resemble element add event sequence
2850 eventBus.fire('root.add', { element: element });
2851
2852 elementRegistry.add(element, gfx, this._svg);
2853
2854 eventBus.fire('root.added', { element: element, gfx: gfx });
2855 }
2856
2857 this._rootElement = element;
2858
2859 return element;
2860 };
2861
2862
2863
2864 // add functionality //////////////////////
2865
2866 Canvas.prototype._ensureValid = function(type, element) {
2867 if (!element.id) {
2868 throw new Error('element must have an id');
2869 }
2870
2871 if (this._elementRegistry.get(element.id)) {
2872 throw new Error('element with id ' + element.id + ' already exists');
2873 }
2874
2875 var requiredAttrs = REQUIRED_MODEL_ATTRS[type];
2876
2877 var valid = every(requiredAttrs, function(attr) {
2878 return typeof element[attr] !== 'undefined';
2879 });
2880
2881 if (!valid) {
2882 throw new Error(
2883 'must supply { ' + requiredAttrs.join(', ') + ' } with ' + type);
2884 }
2885 };
2886
2887 Canvas.prototype._setParent = function(element, parent, parentIndex) {
2888 add(parent.children, element, parentIndex);
2889 element.parent = parent;
2890 };
2891
2892 /**
2893 * Adds an element to the canvas.
2894 *
2895 * This wires the parent <-> child relationship between the element and
2896 * a explicitly specified parent or an implicit root element.
2897 *
2898 * During add it emits the events
2899 *
2900 * * <{type}.add> (element, parent)
2901 * * <{type}.added> (element, gfx)
2902 *
2903 * Extensions may hook into these events to perform their magic.
2904 *
2905 * @param {String} type
2906 * @param {Object|djs.model.Base} element
2907 * @param {Object|djs.model.Base} [parent]
2908 * @param {Number} [parentIndex]
2909 *
2910 * @return {Object|djs.model.Base} the added element
2911 */
2912 Canvas.prototype._addElement = function(type, element, parent, parentIndex) {
2913
2914 parent = parent || this.getRootElement();
2915
2916 var eventBus = this._eventBus,
2917 graphicsFactory = this._graphicsFactory;
2918
2919 this._ensureValid(type, element);
2920
2921 eventBus.fire(type + '.add', { element: element, parent: parent });
2922
2923 this._setParent(element, parent, parentIndex);
2924
2925 // create graphics
2926 var gfx = graphicsFactory.create(type, element, parentIndex);
2927
2928 this._elementRegistry.add(element, gfx);
2929
2930 // update its visual
2931 graphicsFactory.update(type, element, gfx);
2932
2933 eventBus.fire(type + '.added', { element: element, gfx: gfx });
2934
2935 return element;
2936 };
2937
2938 /**
2939 * Adds a shape to the canvas
2940 *
2941 * @param {Object|djs.model.Shape} shape to add to the diagram
2942 * @param {djs.model.Base} [parent]
2943 * @param {Number} [parentIndex]
2944 *
2945 * @return {djs.model.Shape} the added shape
2946 */
2947 Canvas.prototype.addShape = function(shape, parent, parentIndex) {
2948 return this._addElement('shape', shape, parent, parentIndex);
2949 };
2950
2951 /**
2952 * Adds a connection to the canvas
2953 *
2954 * @param {Object|djs.model.Connection} connection to add to the diagram
2955 * @param {djs.model.Base} [parent]
2956 * @param {Number} [parentIndex]
2957 *
2958 * @return {djs.model.Connection} the added connection
2959 */
2960 Canvas.prototype.addConnection = function(connection, parent, parentIndex) {
2961 return this._addElement('connection', connection, parent, parentIndex);
2962 };
2963
2964
2965 /**
2966 * Internal remove element
2967 */
2968 Canvas.prototype._removeElement = function(element, type) {
2969
2970 var elementRegistry = this._elementRegistry,
2971 graphicsFactory = this._graphicsFactory,
2972 eventBus = this._eventBus;
2973
2974 element = elementRegistry.get(element.id || element);
2975
2976 if (!element) {
2977
2978 // element was removed already
2979 return;
2980 }
2981
2982 eventBus.fire(type + '.remove', { element: element });
2983
2984 graphicsFactory.remove(element);
2985
2986 // unset parent <-> child relationship
2987 remove$2(element.parent && element.parent.children, element);
2988 element.parent = null;
2989
2990 eventBus.fire(type + '.removed', { element: element });
2991
2992 elementRegistry.remove(element);
2993
2994 return element;
2995 };
2996
2997
2998 /**
2999 * Removes a shape from the canvas
3000 *
3001 * @param {String|djs.model.Shape} shape or shape id to be removed
3002 *
3003 * @return {djs.model.Shape} the removed shape
3004 */
3005 Canvas.prototype.removeShape = function(shape) {
3006
3007 /**
3008 * An event indicating that a shape is about to be removed from the canvas.
3009 *
3010 * @memberOf Canvas
3011 *
3012 * @event shape.remove
3013 * @type {Object}
3014 * @property {djs.model.Shape} element the shape descriptor
3015 * @property {Object} gfx the graphical representation of the shape
3016 */
3017
3018 /**
3019 * An event indicating that a shape has been removed from the canvas.
3020 *
3021 * @memberOf Canvas
3022 *
3023 * @event shape.removed
3024 * @type {Object}
3025 * @property {djs.model.Shape} element the shape descriptor
3026 * @property {Object} gfx the graphical representation of the shape
3027 */
3028 return this._removeElement(shape, 'shape');
3029 };
3030
3031
3032 /**
3033 * Removes a connection from the canvas
3034 *
3035 * @param {String|djs.model.Connection} connection or connection id to be removed
3036 *
3037 * @return {djs.model.Connection} the removed connection
3038 */
3039 Canvas.prototype.removeConnection = function(connection) {
3040
3041 /**
3042 * An event indicating that a connection is about to be removed from the canvas.
3043 *
3044 * @memberOf Canvas
3045 *
3046 * @event connection.remove
3047 * @type {Object}
3048 * @property {djs.model.Connection} element the connection descriptor
3049 * @property {Object} gfx the graphical representation of the connection
3050 */
3051
3052 /**
3053 * An event indicating that a connection has been removed from the canvas.
3054 *
3055 * @memberOf Canvas
3056 *
3057 * @event connection.removed
3058 * @type {Object}
3059 * @property {djs.model.Connection} element the connection descriptor
3060 * @property {Object} gfx the graphical representation of the connection
3061 */
3062 return this._removeElement(connection, 'connection');
3063 };
3064
3065
3066 /**
3067 * Return the graphical object underlaying a certain diagram element
3068 *
3069 * @param {String|djs.model.Base} element descriptor of the element
3070 * @param {Boolean} [secondary=false] whether to return the secondary connected element
3071 *
3072 * @return {SVGElement}
3073 */
3074 Canvas.prototype.getGraphics = function(element, secondary) {
3075 return this._elementRegistry.getGraphics(element, secondary);
3076 };
3077
3078
3079 /**
3080 * Perform a viewbox update via a given change function.
3081 *
3082 * @param {Function} changeFn
3083 */
3084 Canvas.prototype._changeViewbox = function(changeFn) {
3085
3086 // notify others of the upcoming viewbox change
3087 this._eventBus.fire('canvas.viewbox.changing');
3088
3089 // perform actual change
3090 changeFn.apply(this);
3091
3092 // reset the cached viewbox so that
3093 // a new get operation on viewbox or zoom
3094 // triggers a viewbox re-computation
3095 this._cachedViewbox = null;
3096
3097 // notify others of the change; this step
3098 // may or may not be debounced
3099 this._viewboxChanged();
3100 };
3101
3102 Canvas.prototype._viewboxChanged = function() {
3103 this._eventBus.fire('canvas.viewbox.changed', { viewbox: this.viewbox() });
3104 };
3105
3106
3107 /**
3108 * Gets or sets the view box of the canvas, i.e. the
3109 * area that is currently displayed.
3110 *
3111 * The getter may return a cached viewbox (if it is currently
3112 * changing). To force a recomputation, pass `false` as the first argument.
3113 *
3114 * @example
3115 *
3116 * canvas.viewbox({ x: 100, y: 100, width: 500, height: 500 })
3117 *
3118 * // sets the visible area of the diagram to (100|100) -> (600|100)
3119 * // and and scales it according to the diagram width
3120 *
3121 * var viewbox = canvas.viewbox(); // pass `false` to force recomputing the box.
3122 *
3123 * console.log(viewbox);
3124 * // {
3125 * // inner: Dimensions,
3126 * // outer: Dimensions,
3127 * // scale,
3128 * // x, y,
3129 * // width, height
3130 * // }
3131 *
3132 * // if the current diagram is zoomed and scrolled, you may reset it to the
3133 * // default zoom via this method, too:
3134 *
3135 * var zoomedAndScrolledViewbox = canvas.viewbox();
3136 *
3137 * canvas.viewbox({
3138 * x: 0,
3139 * y: 0,
3140 * width: zoomedAndScrolledViewbox.outer.width,
3141 * height: zoomedAndScrolledViewbox.outer.height
3142 * });
3143 *
3144 * @param {Object} [box] the new view box to set
3145 * @param {Number} box.x the top left X coordinate of the canvas visible in view box
3146 * @param {Number} box.y the top left Y coordinate of the canvas visible in view box
3147 * @param {Number} box.width the visible width
3148 * @param {Number} box.height
3149 *
3150 * @return {Object} the current view box
3151 */
3152 Canvas.prototype.viewbox = function(box) {
3153
3154 if (box === undefined && this._cachedViewbox) {
3155 return this._cachedViewbox;
3156 }
3157
3158 var viewport = this._viewport,
3159 innerBox,
3160 outerBox = this.getSize(),
3161 matrix,
3162 transform$1,
3163 scale,
3164 x, y;
3165
3166 if (!box) {
3167
3168 // compute the inner box based on the
3169 // diagrams default layer. This allows us to exclude
3170 // external components, such as overlays
3171 innerBox = this.getDefaultLayer().getBBox();
3172
3173 transform$1 = transform(viewport);
3174 matrix = transform$1 ? transform$1.matrix : createMatrix();
3175 scale = round(matrix.a, 1000);
3176
3177 x = round(-matrix.e || 0, 1000);
3178 y = round(-matrix.f || 0, 1000);
3179
3180 box = this._cachedViewbox = {
3181 x: x ? x / scale : 0,
3182 y: y ? y / scale : 0,
3183 width: outerBox.width / scale,
3184 height: outerBox.height / scale,
3185 scale: scale,
3186 inner: {
3187 width: innerBox.width,
3188 height: innerBox.height,
3189 x: innerBox.x,
3190 y: innerBox.y
3191 },
3192 outer: outerBox
3193 };
3194
3195 return box;
3196 } else {
3197
3198 this._changeViewbox(function() {
3199 scale = Math.min(outerBox.width / box.width, outerBox.height / box.height);
3200
3201 var matrix = this._svg.createSVGMatrix()
3202 .scale(scale)
3203 .translate(-box.x, -box.y);
3204
3205 transform(viewport, matrix);
3206 });
3207 }
3208
3209 return box;
3210 };
3211
3212
3213 /**
3214 * Gets or sets the scroll of the canvas.
3215 *
3216 * @param {Object} [delta] the new scroll to apply.
3217 *
3218 * @param {Number} [delta.dx]
3219 * @param {Number} [delta.dy]
3220 */
3221 Canvas.prototype.scroll = function(delta) {
3222
3223 var node = this._viewport;
3224 var matrix = node.getCTM();
3225
3226 if (delta) {
3227 this._changeViewbox(function() {
3228 delta = assign({ dx: 0, dy: 0 }, delta || {});
3229
3230 matrix = this._svg.createSVGMatrix().translate(delta.dx, delta.dy).multiply(matrix);
3231
3232 setCTM(node, matrix);
3233 });
3234 }
3235
3236 return { x: matrix.e, y: matrix.f };
3237 };
3238
3239
3240 /**
3241 * Gets or sets the current zoom of the canvas, optionally zooming
3242 * to the specified position.
3243 *
3244 * The getter may return a cached zoom level. Call it with `false` as
3245 * the first argument to force recomputation of the current level.
3246 *
3247 * @param {String|Number} [newScale] the new zoom level, either a number, i.e. 0.9,
3248 * or `fit-viewport` to adjust the size to fit the current viewport
3249 * @param {String|Point} [center] the reference point { x: .., y: ..} to zoom to, 'auto' to zoom into mid or null
3250 *
3251 * @return {Number} the current scale
3252 */
3253 Canvas.prototype.zoom = function(newScale, center) {
3254
3255 if (!newScale) {
3256 return this.viewbox(newScale).scale;
3257 }
3258
3259 if (newScale === 'fit-viewport') {
3260 return this._fitViewport(center);
3261 }
3262
3263 var outer,
3264 matrix;
3265
3266 this._changeViewbox(function() {
3267
3268 if (typeof center !== 'object') {
3269 outer = this.viewbox().outer;
3270
3271 center = {
3272 x: outer.width / 2,
3273 y: outer.height / 2
3274 };
3275 }
3276
3277 matrix = this._setZoom(newScale, center);
3278 });
3279
3280 return round(matrix.a, 1000);
3281 };
3282
3283 function setCTM(node, m) {
3284 var mstr = 'matrix(' + m.a + ',' + m.b + ',' + m.c + ',' + m.d + ',' + m.e + ',' + m.f + ')';
3285 node.setAttribute('transform', mstr);
3286 }
3287
3288 Canvas.prototype._fitViewport = function(center) {
3289
3290 var vbox = this.viewbox(),
3291 outer = vbox.outer,
3292 inner = vbox.inner,
3293 newScale,
3294 newViewbox;
3295
3296 // display the complete diagram without zooming in.
3297 // instead of relying on internal zoom, we perform a
3298 // hard reset on the canvas viewbox to realize this
3299 //
3300 // if diagram does not need to be zoomed in, we focus it around
3301 // the diagram origin instead
3302
3303 if (inner.x >= 0 &&
3304 inner.y >= 0 &&
3305 inner.x + inner.width <= outer.width &&
3306 inner.y + inner.height <= outer.height &&
3307 !center) {
3308
3309 newViewbox = {
3310 x: 0,
3311 y: 0,
3312 width: Math.max(inner.width + inner.x, outer.width),
3313 height: Math.max(inner.height + inner.y, outer.height)
3314 };
3315 } else {
3316
3317 newScale = Math.min(1, outer.width / inner.width, outer.height / inner.height);
3318 newViewbox = {
3319 x: inner.x + (center ? inner.width / 2 - outer.width / newScale / 2 : 0),
3320 y: inner.y + (center ? inner.height / 2 - outer.height / newScale / 2 : 0),
3321 width: outer.width / newScale,
3322 height: outer.height / newScale
3323 };
3324 }
3325
3326 this.viewbox(newViewbox);
3327
3328 return this.viewbox(false).scale;
3329 };
3330
3331
3332 Canvas.prototype._setZoom = function(scale, center) {
3333
3334 var svg = this._svg,
3335 viewport = this._viewport;
3336
3337 var matrix = svg.createSVGMatrix();
3338 var point = svg.createSVGPoint();
3339
3340 var centerPoint,
3341 originalPoint,
3342 currentMatrix,
3343 scaleMatrix,
3344 newMatrix;
3345
3346 currentMatrix = viewport.getCTM();
3347
3348 var currentScale = currentMatrix.a;
3349
3350 if (center) {
3351 centerPoint = assign(point, center);
3352
3353 // revert applied viewport transformations
3354 originalPoint = centerPoint.matrixTransform(currentMatrix.inverse());
3355
3356 // create scale matrix
3357 scaleMatrix = matrix
3358 .translate(originalPoint.x, originalPoint.y)
3359 .scale(1 / currentScale * scale)
3360 .translate(-originalPoint.x, -originalPoint.y);
3361
3362 newMatrix = currentMatrix.multiply(scaleMatrix);
3363 } else {
3364 newMatrix = matrix.scale(scale);
3365 }
3366
3367 setCTM(this._viewport, newMatrix);
3368
3369 return newMatrix;
3370 };
3371
3372
3373 /**
3374 * Returns the size of the canvas
3375 *
3376 * @return {Dimensions}
3377 */
3378 Canvas.prototype.getSize = function() {
3379 return {
3380 width: this._container.clientWidth,
3381 height: this._container.clientHeight
3382 };
3383 };
3384
3385
3386 /**
3387 * Return the absolute bounding box for the given element
3388 *
3389 * The absolute bounding box may be used to display overlays in the
3390 * callers (browser) coordinate system rather than the zoomed in/out
3391 * canvas coordinates.
3392 *
3393 * @param {ElementDescriptor} element
3394 * @return {Bounds} the absolute bounding box
3395 */
3396 Canvas.prototype.getAbsoluteBBox = function(element) {
3397 var vbox = this.viewbox();
3398 var bbox;
3399
3400 // connection
3401 // use svg bbox
3402 if (element.waypoints) {
3403 var gfx = this.getGraphics(element);
3404
3405 bbox = gfx.getBBox();
3406 }
3407
3408 // shapes
3409 // use data
3410 else {
3411 bbox = element;
3412 }
3413
3414 var x = bbox.x * vbox.scale - vbox.x * vbox.scale;
3415 var y = bbox.y * vbox.scale - vbox.y * vbox.scale;
3416
3417 var width = bbox.width * vbox.scale;
3418 var height = bbox.height * vbox.scale;
3419
3420 return {
3421 x: x,
3422 y: y,
3423 width: width,
3424 height: height
3425 };
3426 };
3427
3428 /**
3429 * Fires an event in order other modules can react to the
3430 * canvas resizing
3431 */
3432 Canvas.prototype.resized = function() {
3433
3434 // force recomputation of view box
3435 delete this._cachedViewbox;
3436
3437 this._eventBus.fire('canvas.resized');
3438 };
3439
3440 var ELEMENT_ID = 'data-element-id';
3441
3442
3443 /**
3444 * @class
3445 *
3446 * A registry that keeps track of all shapes in the diagram.
3447 */
3448 function ElementRegistry(eventBus) {
3449 this._elements = {};
3450
3451 this._eventBus = eventBus;
3452 }
3453
3454 ElementRegistry.$inject = [ 'eventBus' ];
3455
3456 /**
3457 * Register a pair of (element, gfx, (secondaryGfx)).
3458 *
3459 * @param {djs.model.Base} element
3460 * @param {SVGElement} gfx
3461 * @param {SVGElement} [secondaryGfx] optional other element to register, too
3462 */
3463 ElementRegistry.prototype.add = function(element, gfx, secondaryGfx) {
3464
3465 var id = element.id;
3466
3467 this._validateId(id);
3468
3469 // associate dom node with element
3470 attr$1(gfx, ELEMENT_ID, id);
3471
3472 if (secondaryGfx) {
3473 attr$1(secondaryGfx, ELEMENT_ID, id);
3474 }
3475
3476 this._elements[id] = { element: element, gfx: gfx, secondaryGfx: secondaryGfx };
3477 };
3478
3479 /**
3480 * Removes an element from the registry.
3481 *
3482 * @param {djs.model.Base} element
3483 */
3484 ElementRegistry.prototype.remove = function(element) {
3485 var elements = this._elements,
3486 id = element.id || element,
3487 container = id && elements[id];
3488
3489 if (container) {
3490
3491 // unset element id on gfx
3492 attr$1(container.gfx, ELEMENT_ID, '');
3493
3494 if (container.secondaryGfx) {
3495 attr$1(container.secondaryGfx, ELEMENT_ID, '');
3496 }
3497
3498 delete elements[id];
3499 }
3500 };
3501
3502 /**
3503 * Update the id of an element
3504 *
3505 * @param {djs.model.Base} element
3506 * @param {String} newId
3507 */
3508 ElementRegistry.prototype.updateId = function(element, newId) {
3509
3510 this._validateId(newId);
3511
3512 if (typeof element === 'string') {
3513 element = this.get(element);
3514 }
3515
3516 this._eventBus.fire('element.updateId', {
3517 element: element,
3518 newId: newId
3519 });
3520
3521 var gfx = this.getGraphics(element),
3522 secondaryGfx = this.getGraphics(element, true);
3523
3524 this.remove(element);
3525
3526 element.id = newId;
3527
3528 this.add(element, gfx, secondaryGfx);
3529 };
3530
3531 /**
3532 * Return the model element for a given id or graphics.
3533 *
3534 * @example
3535 *
3536 * elementRegistry.get('SomeElementId_1');
3537 * elementRegistry.get(gfx);
3538 *
3539 *
3540 * @param {String|SVGElement} filter for selecting the element
3541 *
3542 * @return {djs.model.Base}
3543 */
3544 ElementRegistry.prototype.get = function(filter) {
3545 var id;
3546
3547 if (typeof filter === 'string') {
3548 id = filter;
3549 } else {
3550 id = filter && attr$1(filter, ELEMENT_ID);
3551 }
3552
3553 var container = this._elements[id];
3554 return container && container.element;
3555 };
3556
3557 /**
3558 * Return all elements that match a given filter function.
3559 *
3560 * @param {Function} fn
3561 *
3562 * @return {Array<djs.model.Base>}
3563 */
3564 ElementRegistry.prototype.filter = function(fn) {
3565
3566 var filtered = [];
3567
3568 this.forEach(function(element, gfx) {
3569 if (fn(element, gfx)) {
3570 filtered.push(element);
3571 }
3572 });
3573
3574 return filtered;
3575 };
3576
3577 /**
3578 * Return all rendered model elements.
3579 *
3580 * @return {Array<djs.model.Base>}
3581 */
3582 ElementRegistry.prototype.getAll = function() {
3583 return this.filter(function(e) { return e; });
3584 };
3585
3586 /**
3587 * Iterate over all diagram elements.
3588 *
3589 * @param {Function} fn
3590 */
3591 ElementRegistry.prototype.forEach = function(fn) {
3592
3593 var map = this._elements;
3594
3595 Object.keys(map).forEach(function(id) {
3596 var container = map[id],
3597 element = container.element,
3598 gfx = container.gfx;
3599
3600 return fn(element, gfx);
3601 });
3602 };
3603
3604 /**
3605 * Return the graphical representation of an element or its id.
3606 *
3607 * @example
3608 * elementRegistry.getGraphics('SomeElementId_1');
3609 * elementRegistry.getGraphics(rootElement); // <g ...>
3610 *
3611 * elementRegistry.getGraphics(rootElement, true); // <svg ...>
3612 *
3613 *
3614 * @param {String|djs.model.Base} filter
3615 * @param {Boolean} [secondary=false] whether to return the secondary connected element
3616 *
3617 * @return {SVGElement}
3618 */
3619 ElementRegistry.prototype.getGraphics = function(filter, secondary) {
3620 var id = filter.id || filter;
3621
3622 var container = this._elements[id];
3623 return container && (secondary ? container.secondaryGfx : container.gfx);
3624 };
3625
3626 /**
3627 * Validate the suitability of the given id and signals a problem
3628 * with an exception.
3629 *
3630 * @param {String} id
3631 *
3632 * @throws {Error} if id is empty or already assigned
3633 */
3634 ElementRegistry.prototype._validateId = function(id) {
3635 if (!id) {
3636 throw new Error('element must have an id');
3637 }
3638
3639 if (this._elements[id]) {
3640 throw new Error('element with id ' + id + ' already added');
3641 }
3642 };
3643
3644 /**
3645 * An empty collection stub. Use {@link RefsCollection.extend} to extend a
3646 * collection with ref semantics.
3647 *
3648 * @class RefsCollection
3649 */
3650
3651 /**
3652 * Extends a collection with {@link Refs} aware methods
3653 *
3654 * @memberof RefsCollection
3655 * @static
3656 *
3657 * @param {Array<Object>} collection
3658 * @param {Refs} refs instance
3659 * @param {Object} property represented by the collection
3660 * @param {Object} target object the collection is attached to
3661 *
3662 * @return {RefsCollection<Object>} the extended array
3663 */
3664 function extend$1(collection, refs, property, target) {
3665
3666 var inverseProperty = property.inverse;
3667
3668 /**
3669 * Removes the given element from the array and returns it.
3670 *
3671 * @method RefsCollection#remove
3672 *
3673 * @param {Object} element the element to remove
3674 */
3675 Object.defineProperty(collection, 'remove', {
3676 value: function(element) {
3677 var idx = this.indexOf(element);
3678 if (idx !== -1) {
3679 this.splice(idx, 1);
3680
3681 // unset inverse
3682 refs.unset(element, inverseProperty, target);
3683 }
3684
3685 return element;
3686 }
3687 });
3688
3689 /**
3690 * Returns true if the collection contains the given element
3691 *
3692 * @method RefsCollection#contains
3693 *
3694 * @param {Object} element the element to check for
3695 */
3696 Object.defineProperty(collection, 'contains', {
3697 value: function(element) {
3698 return this.indexOf(element) !== -1;
3699 }
3700 });
3701
3702 /**
3703 * Adds an element to the array, unless it exists already (set semantics).
3704 *
3705 * @method RefsCollection#add
3706 *
3707 * @param {Object} element the element to add
3708 * @param {Number} optional index to add element to
3709 * (possibly moving other elements around)
3710 */
3711 Object.defineProperty(collection, 'add', {
3712 value: function(element, idx) {
3713
3714 var currentIdx = this.indexOf(element);
3715
3716 if (typeof idx === 'undefined') {
3717
3718 if (currentIdx !== -1) {
3719 // element already in collection (!)
3720 return;
3721 }
3722
3723 // add to end of array, as no idx is specified
3724 idx = this.length;
3725 }
3726
3727 // handle already in collection
3728 if (currentIdx !== -1) {
3729
3730 // remove element from currentIdx
3731 this.splice(currentIdx, 1);
3732 }
3733
3734 // add element at idx
3735 this.splice(idx, 0, element);
3736
3737 if (currentIdx === -1) {
3738 // set inverse, unless element was
3739 // in collection already
3740 refs.set(element, inverseProperty, target);
3741 }
3742 }
3743 });
3744
3745 // a simple marker, identifying this element
3746 // as being a refs collection
3747 Object.defineProperty(collection, '__refs_collection', {
3748 value: true
3749 });
3750
3751 return collection;
3752 }
3753
3754
3755 function isExtended(collection) {
3756 return collection.__refs_collection === true;
3757 }
3758
3759 var extend_1 = extend$1;
3760
3761 var isExtended_1 = isExtended;
3762
3763 var collection = {
3764 extend: extend_1,
3765 isExtended: isExtended_1
3766 };
3767
3768 function hasOwnProperty(e, property) {
3769 return Object.prototype.hasOwnProperty.call(e, property.name || property);
3770 }
3771
3772 function defineCollectionProperty(ref, property, target) {
3773
3774 var collection$1 = collection.extend(target[property.name] || [], ref, property, target);
3775
3776 Object.defineProperty(target, property.name, {
3777 enumerable: property.enumerable,
3778 value: collection$1
3779 });
3780
3781 if (collection$1.length) {
3782
3783 collection$1.forEach(function(o) {
3784 ref.set(o, property.inverse, target);
3785 });
3786 }
3787 }
3788
3789
3790 function defineProperty(ref, property, target) {
3791
3792 var inverseProperty = property.inverse;
3793
3794 var _value = target[property.name];
3795
3796 Object.defineProperty(target, property.name, {
3797 configurable: property.configurable,
3798 enumerable: property.enumerable,
3799
3800 get: function() {
3801 return _value;
3802 },
3803
3804 set: function(value) {
3805
3806 // return if we already performed all changes
3807 if (value === _value) {
3808 return;
3809 }
3810
3811 var old = _value;
3812
3813 // temporary set null
3814 _value = null;
3815
3816 if (old) {
3817 ref.unset(old, inverseProperty, target);
3818 }
3819
3820 // set new value
3821 _value = value;
3822
3823 // set inverse value
3824 ref.set(_value, inverseProperty, target);
3825 }
3826 });
3827
3828 }
3829
3830 /**
3831 * Creates a new references object defining two inversly related
3832 * attribute descriptors a and b.
3833 *
3834 * <p>
3835 * When bound to an object using {@link Refs#bind} the references
3836 * get activated and ensure that add and remove operations are applied
3837 * reversely, too.
3838 * </p>
3839 *
3840 * <p>
3841 * For attributes represented as collections {@link Refs} provides the
3842 * {@link RefsCollection#add}, {@link RefsCollection#remove} and {@link RefsCollection#contains} extensions
3843 * that must be used to properly hook into the inverse change mechanism.
3844 * </p>
3845 *
3846 * @class Refs
3847 *
3848 * @classdesc A bi-directional reference between two attributes.
3849 *
3850 * @param {Refs.AttributeDescriptor} a property descriptor
3851 * @param {Refs.AttributeDescriptor} b property descriptor
3852 *
3853 * @example
3854 *
3855 * var refs = Refs({ name: 'wheels', collection: true, enumerable: true }, { name: 'car' });
3856 *
3857 * var car = { name: 'toyota' };
3858 * var wheels = [{ pos: 'front-left' }, { pos: 'front-right' }];
3859 *
3860 * refs.bind(car, 'wheels');
3861 *
3862 * car.wheels // []
3863 * car.wheels.add(wheels[0]);
3864 * car.wheels.add(wheels[1]);
3865 *
3866 * car.wheels // [{ pos: 'front-left' }, { pos: 'front-right' }]
3867 *
3868 * wheels[0].car // { name: 'toyota' };
3869 * car.wheels.remove(wheels[0]);
3870 *
3871 * wheels[0].car // undefined
3872 */
3873 function Refs(a, b) {
3874
3875 if (!(this instanceof Refs)) {
3876 return new Refs(a, b);
3877 }
3878
3879 // link
3880 a.inverse = b;
3881 b.inverse = a;
3882
3883 this.props = {};
3884 this.props[a.name] = a;
3885 this.props[b.name] = b;
3886 }
3887
3888 /**
3889 * Binds one side of a bi-directional reference to a
3890 * target object.
3891 *
3892 * @memberOf Refs
3893 *
3894 * @param {Object} target
3895 * @param {String} property
3896 */
3897 Refs.prototype.bind = function(target, property) {
3898 if (typeof property === 'string') {
3899 if (!this.props[property]) {
3900 throw new Error('no property <' + property + '> in ref');
3901 }
3902 property = this.props[property];
3903 }
3904
3905 if (property.collection) {
3906 defineCollectionProperty(this, property, target);
3907 } else {
3908 defineProperty(this, property, target);
3909 }
3910 };
3911
3912 Refs.prototype.ensureRefsCollection = function(target, property) {
3913
3914 var collection$1 = target[property.name];
3915
3916 if (!collection.isExtended(collection$1)) {
3917 defineCollectionProperty(this, property, target);
3918 }
3919
3920 return collection$1;
3921 };
3922
3923 Refs.prototype.ensureBound = function(target, property) {
3924 if (!hasOwnProperty(target, property)) {
3925 this.bind(target, property);
3926 }
3927 };
3928
3929 Refs.prototype.unset = function(target, property, value) {
3930
3931 if (target) {
3932 this.ensureBound(target, property);
3933
3934 if (property.collection) {
3935 this.ensureRefsCollection(target, property).remove(value);
3936 } else {
3937 target[property.name] = undefined;
3938 }
3939 }
3940 };
3941
3942 Refs.prototype.set = function(target, property, value) {
3943
3944 if (target) {
3945 this.ensureBound(target, property);
3946
3947 if (property.collection) {
3948 this.ensureRefsCollection(target, property).add(value);
3949 } else {
3950 target[property.name] = value;
3951 }
3952 }
3953 };
3954
3955 var refs = Refs;
3956
3957 var objectRefs = refs;
3958
3959 var Collection = collection;
3960 objectRefs.Collection = Collection;
3961
3962 var parentRefs = new objectRefs({ name: 'children', enumerable: true, collection: true }, { name: 'parent' }),
3963 labelRefs = new objectRefs({ name: 'labels', enumerable: true, collection: true }, { name: 'labelTarget' }),
3964 attacherRefs = new objectRefs({ name: 'attachers', collection: true }, { name: 'host' }),
3965 outgoingRefs = new objectRefs({ name: 'outgoing', collection: true }, { name: 'source' }),
3966 incomingRefs = new objectRefs({ name: 'incoming', collection: true }, { name: 'target' });
3967
3968 /**
3969 * @namespace djs.model
3970 */
3971
3972 /**
3973 * @memberOf djs.model
3974 */
3975
3976 /**
3977 * The basic graphical representation
3978 *
3979 * @class
3980 *
3981 * @abstract
3982 */
3983 function Base() {
3984
3985 /**
3986 * The object that backs up the shape
3987 *
3988 * @name Base#businessObject
3989 * @type Object
3990 */
3991 Object.defineProperty(this, 'businessObject', {
3992 writable: true
3993 });
3994
3995
3996 /**
3997 * Single label support, will mapped to multi label array
3998 *
3999 * @name Base#label
4000 * @type Object
4001 */
4002 Object.defineProperty(this, 'label', {
4003 get: function() {
4004 return this.labels[0];
4005 },
4006 set: function(newLabel) {
4007
4008 var label = this.label,
4009 labels = this.labels;
4010
4011 if (!newLabel && label) {
4012 labels.remove(label);
4013 } else {
4014 labels.add(newLabel, 0);
4015 }
4016 }
4017 });
4018
4019 /**
4020 * The parent shape
4021 *
4022 * @name Base#parent
4023 * @type Shape
4024 */
4025 parentRefs.bind(this, 'parent');
4026
4027 /**
4028 * The list of labels
4029 *
4030 * @name Base#labels
4031 * @type Label
4032 */
4033 labelRefs.bind(this, 'labels');
4034
4035 /**
4036 * The list of outgoing connections
4037 *
4038 * @name Base#outgoing
4039 * @type Array<Connection>
4040 */
4041 outgoingRefs.bind(this, 'outgoing');
4042
4043 /**
4044 * The list of incoming connections
4045 *
4046 * @name Base#incoming
4047 * @type Array<Connection>
4048 */
4049 incomingRefs.bind(this, 'incoming');
4050 }
4051
4052
4053 /**
4054 * A graphical object
4055 *
4056 * @class
4057 * @constructor
4058 *
4059 * @extends Base
4060 */
4061 function Shape() {
4062 Base.call(this);
4063
4064 /**
4065 * Indicates frame shapes
4066 *
4067 * @name Shape#isFrame
4068 * @type Boolean
4069 */
4070
4071 /**
4072 * The list of children
4073 *
4074 * @name Shape#children
4075 * @type Array<Base>
4076 */
4077 parentRefs.bind(this, 'children');
4078
4079 /**
4080 * @name Shape#host
4081 * @type Shape
4082 */
4083 attacherRefs.bind(this, 'host');
4084
4085 /**
4086 * @name Shape#attachers
4087 * @type Shape
4088 */
4089 attacherRefs.bind(this, 'attachers');
4090 }
4091
4092 inherits_browser(Shape, Base);
4093
4094
4095 /**
4096 * A root graphical object
4097 *
4098 * @class
4099 * @constructor
4100 *
4101 * @extends Shape
4102 */
4103 function Root() {
4104 Shape.call(this);
4105 }
4106
4107 inherits_browser(Root, Shape);
4108
4109
4110 /**
4111 * A label for an element
4112 *
4113 * @class
4114 * @constructor
4115 *
4116 * @extends Shape
4117 */
4118 function Label() {
4119 Shape.call(this);
4120
4121 /**
4122 * The labeled element
4123 *
4124 * @name Label#labelTarget
4125 * @type Base
4126 */
4127 labelRefs.bind(this, 'labelTarget');
4128 }
4129
4130 inherits_browser(Label, Shape);
4131
4132
4133 /**
4134 * A connection between two elements
4135 *
4136 * @class
4137 * @constructor
4138 *
4139 * @extends Base
4140 */
4141 function Connection() {
4142 Base.call(this);
4143
4144 /**
4145 * The element this connection originates from
4146 *
4147 * @name Connection#source
4148 * @type Base
4149 */
4150 outgoingRefs.bind(this, 'source');
4151
4152 /**
4153 * The element this connection points to
4154 *
4155 * @name Connection#target
4156 * @type Base
4157 */
4158 incomingRefs.bind(this, 'target');
4159 }
4160
4161 inherits_browser(Connection, Base);
4162
4163
4164 var types = {
4165 connection: Connection,
4166 shape: Shape,
4167 label: Label,
4168 root: Root
4169 };
4170
4171 /**
4172 * Creates a new model element of the specified type
4173 *
4174 * @method create
4175 *
4176 * @example
4177 *
4178 * var shape1 = Model.create('shape', { x: 10, y: 10, width: 100, height: 100 });
4179 * var shape2 = Model.create('shape', { x: 210, y: 210, width: 100, height: 100 });
4180 *
4181 * var connection = Model.create('connection', { waypoints: [ { x: 110, y: 55 }, {x: 210, y: 55 } ] });
4182 *
4183 * @param {String} type lower-cased model name
4184 * @param {Object} attrs attributes to initialize the new model instance with
4185 *
4186 * @return {Base} the new model instance
4187 */
4188 function create$1(type, attrs) {
4189 var Type = types[type];
4190 if (!Type) {
4191 throw new Error('unknown type: <' + type + '>');
4192 }
4193 return assign(new Type(), attrs);
4194 }
4195
4196 /**
4197 * A factory for diagram-js shapes
4198 */
4199 function ElementFactory() {
4200 this._uid = 12;
4201 }
4202
4203
4204 ElementFactory.prototype.createRoot = function(attrs) {
4205 return this.create('root', attrs);
4206 };
4207
4208 ElementFactory.prototype.createLabel = function(attrs) {
4209 return this.create('label', attrs);
4210 };
4211
4212 ElementFactory.prototype.createShape = function(attrs) {
4213 return this.create('shape', attrs);
4214 };
4215
4216 ElementFactory.prototype.createConnection = function(attrs) {
4217 return this.create('connection', attrs);
4218 };
4219
4220 /**
4221 * Create a model element with the given type and
4222 * a number of pre-set attributes.
4223 *
4224 * @param {String} type
4225 * @param {Object} attrs
4226 * @return {djs.model.Base} the newly created model instance
4227 */
4228 ElementFactory.prototype.create = function(type, attrs) {
4229
4230 attrs = assign({}, attrs || {});
4231
4232 if (!attrs.id) {
4233 attrs.id = type + '_' + (this._uid++);
4234 }
4235
4236 return create$1(type, attrs);
4237 };
4238
4239 var FN_REF = '__fn';
4240
4241 var DEFAULT_PRIORITY = 1000;
4242
4243 var slice$1 = Array.prototype.slice;
4244
4245 /**
4246 * A general purpose event bus.
4247 *
4248 * This component is used to communicate across a diagram instance.
4249 * Other parts of a diagram can use it to listen to and broadcast events.
4250 *
4251 *
4252 * ## Registering for Events
4253 *
4254 * The event bus provides the {@link EventBus#on} and {@link EventBus#once}
4255 * methods to register for events. {@link EventBus#off} can be used to
4256 * remove event registrations. Listeners receive an instance of {@link Event}
4257 * as the first argument. It allows them to hook into the event execution.
4258 *
4259 * ```javascript
4260 *
4261 * // listen for event
4262 * eventBus.on('foo', function(event) {
4263 *
4264 * // access event type
4265 * event.type; // 'foo'
4266 *
4267 * // stop propagation to other listeners
4268 * event.stopPropagation();
4269 *
4270 * // prevent event default
4271 * event.preventDefault();
4272 * });
4273 *
4274 * // listen for event with custom payload
4275 * eventBus.on('bar', function(event, payload) {
4276 * console.log(payload);
4277 * });
4278 *
4279 * // listen for event returning value
4280 * eventBus.on('foobar', function(event) {
4281 *
4282 * // stop event propagation + prevent default
4283 * return false;
4284 *
4285 * // stop event propagation + return custom result
4286 * return {
4287 * complex: 'listening result'
4288 * };
4289 * });
4290 *
4291 *
4292 * // listen with custom priority (default=1000, higher is better)
4293 * eventBus.on('priorityfoo', 1500, function(event) {
4294 * console.log('invoked first!');
4295 * });
4296 *
4297 *
4298 * // listen for event and pass the context (`this`)
4299 * eventBus.on('foobar', function(event) {
4300 * this.foo();
4301 * }, this);
4302 * ```
4303 *
4304 *
4305 * ## Emitting Events
4306 *
4307 * Events can be emitted via the event bus using {@link EventBus#fire}.
4308 *
4309 * ```javascript
4310 *
4311 * // false indicates that the default action
4312 * // was prevented by listeners
4313 * if (eventBus.fire('foo') === false) {
4314 * console.log('default has been prevented!');
4315 * };
4316 *
4317 *
4318 * // custom args + return value listener
4319 * eventBus.on('sum', function(event, a, b) {
4320 * return a + b;
4321 * });
4322 *
4323 * // you can pass custom arguments + retrieve result values.
4324 * var sum = eventBus.fire('sum', 1, 2);
4325 * console.log(sum); // 3
4326 * ```
4327 */
4328 function EventBus() {
4329 this._listeners = {};
4330
4331 // cleanup on destroy on lowest priority to allow
4332 // message passing until the bitter end
4333 this.on('diagram.destroy', 1, this._destroy, this);
4334 }
4335
4336
4337 /**
4338 * Register an event listener for events with the given name.
4339 *
4340 * The callback will be invoked with `event, ...additionalArguments`
4341 * that have been passed to {@link EventBus#fire}.
4342 *
4343 * Returning false from a listener will prevent the events default action
4344 * (if any is specified). To stop an event from being processed further in
4345 * other listeners execute {@link Event#stopPropagation}.
4346 *
4347 * Returning anything but `undefined` from a listener will stop the listener propagation.
4348 *
4349 * @param {String|Array<String>} events
4350 * @param {Number} [priority=1000] the priority in which this listener is called, larger is higher
4351 * @param {Function} callback
4352 * @param {Object} [that] Pass context (`this`) to the callback
4353 */
4354 EventBus.prototype.on = function(events, priority, callback, that) {
4355
4356 events = isArray(events) ? events : [ events ];
4357
4358 if (isFunction(priority)) {
4359 that = callback;
4360 callback = priority;
4361 priority = DEFAULT_PRIORITY;
4362 }
4363
4364 if (!isNumber(priority)) {
4365 throw new Error('priority must be a number');
4366 }
4367
4368 var actualCallback = callback;
4369
4370 if (that) {
4371 actualCallback = bind(callback, that);
4372
4373 // make sure we remember and are able to remove
4374 // bound callbacks via {@link #off} using the original
4375 // callback
4376 actualCallback[FN_REF] = callback[FN_REF] || callback;
4377 }
4378
4379 var self = this;
4380
4381 events.forEach(function(e) {
4382 self._addListener(e, {
4383 priority: priority,
4384 callback: actualCallback,
4385 next: null
4386 });
4387 });
4388 };
4389
4390
4391 /**
4392 * Register an event listener that is executed only once.
4393 *
4394 * @param {String} event the event name to register for
4395 * @param {Number} [priority=1000] the priority in which this listener is called, larger is higher
4396 * @param {Function} callback the callback to execute
4397 * @param {Object} [that] Pass context (`this`) to the callback
4398 */
4399 EventBus.prototype.once = function(event, priority, callback, that) {
4400 var self = this;
4401
4402 if (isFunction(priority)) {
4403 that = callback;
4404 callback = priority;
4405 priority = DEFAULT_PRIORITY;
4406 }
4407
4408 if (!isNumber(priority)) {
4409 throw new Error('priority must be a number');
4410 }
4411
4412 function wrappedCallback() {
4413 var result = callback.apply(that, arguments);
4414
4415 self.off(event, wrappedCallback);
4416
4417 return result;
4418 }
4419
4420 // make sure we remember and are able to remove
4421 // bound callbacks via {@link #off} using the original
4422 // callback
4423 wrappedCallback[FN_REF] = callback;
4424
4425 this.on(event, priority, wrappedCallback);
4426 };
4427
4428
4429 /**
4430 * Removes event listeners by event and callback.
4431 *
4432 * If no callback is given, all listeners for a given event name are being removed.
4433 *
4434 * @param {String|Array<String>} events
4435 * @param {Function} [callback]
4436 */
4437 EventBus.prototype.off = function(events, callback) {
4438
4439 events = isArray(events) ? events : [ events ];
4440
4441 var self = this;
4442
4443 events.forEach(function(event) {
4444 self._removeListener(event, callback);
4445 });
4446
4447 };
4448
4449
4450 /**
4451 * Create an EventBus event.
4452 *
4453 * @param {Object} data
4454 *
4455 * @return {Object} event, recognized by the eventBus
4456 */
4457 EventBus.prototype.createEvent = function(data) {
4458 var event = new InternalEvent();
4459
4460 event.init(data);
4461
4462 return event;
4463 };
4464
4465
4466 /**
4467 * Fires a named event.
4468 *
4469 * @example
4470 *
4471 * // fire event by name
4472 * events.fire('foo');
4473 *
4474 * // fire event object with nested type
4475 * var event = { type: 'foo' };
4476 * events.fire(event);
4477 *
4478 * // fire event with explicit type
4479 * var event = { x: 10, y: 20 };
4480 * events.fire('element.moved', event);
4481 *
4482 * // pass additional arguments to the event
4483 * events.on('foo', function(event, bar) {
4484 * alert(bar);
4485 * });
4486 *
4487 * events.fire({ type: 'foo' }, 'I am bar!');
4488 *
4489 * @param {String} [name] the optional event name
4490 * @param {Object} [event] the event object
4491 * @param {...Object} additional arguments to be passed to the callback functions
4492 *
4493 * @return {Boolean} the events return value, if specified or false if the
4494 * default action was prevented by listeners
4495 */
4496 EventBus.prototype.fire = function(type, data) {
4497
4498 var event,
4499 firstListener,
4500 returnValue,
4501 args;
4502
4503 args = slice$1.call(arguments);
4504
4505 if (typeof type === 'object') {
4506 data = type;
4507 type = data.type;
4508 }
4509
4510 if (!type) {
4511 throw new Error('no event type specified');
4512 }
4513
4514 firstListener = this._listeners[type];
4515
4516 if (!firstListener) {
4517 return;
4518 }
4519
4520 // we make sure we fire instances of our home made
4521 // events here. We wrap them only once, though
4522 if (data instanceof InternalEvent) {
4523
4524 // we are fine, we alread have an event
4525 event = data;
4526 } else {
4527 event = this.createEvent(data);
4528 }
4529
4530 // ensure we pass the event as the first parameter
4531 args[0] = event;
4532
4533 // original event type (in case we delegate)
4534 var originalType = event.type;
4535
4536 // update event type before delegation
4537 if (type !== originalType) {
4538 event.type = type;
4539 }
4540
4541 try {
4542 returnValue = this._invokeListeners(event, args, firstListener);
4543 } finally {
4544
4545 // reset event type after delegation
4546 if (type !== originalType) {
4547 event.type = originalType;
4548 }
4549 }
4550
4551 // set the return value to false if the event default
4552 // got prevented and no other return value exists
4553 if (returnValue === undefined && event.defaultPrevented) {
4554 returnValue = false;
4555 }
4556
4557 return returnValue;
4558 };
4559
4560
4561 EventBus.prototype.handleError = function(error) {
4562 return this.fire('error', { error: error }) === false;
4563 };
4564
4565
4566 EventBus.prototype._destroy = function() {
4567 this._listeners = {};
4568 };
4569
4570 EventBus.prototype._invokeListeners = function(event, args, listener) {
4571
4572 var returnValue;
4573
4574 while (listener) {
4575
4576 // handle stopped propagation
4577 if (event.cancelBubble) {
4578 break;
4579 }
4580
4581 returnValue = this._invokeListener(event, args, listener);
4582
4583 listener = listener.next;
4584 }
4585
4586 return returnValue;
4587 };
4588
4589 EventBus.prototype._invokeListener = function(event, args, listener) {
4590
4591 var returnValue;
4592
4593 try {
4594
4595 // returning false prevents the default action
4596 returnValue = invokeFunction(listener.callback, args);
4597
4598 // stop propagation on return value
4599 if (returnValue !== undefined) {
4600 event.returnValue = returnValue;
4601 event.stopPropagation();
4602 }
4603
4604 // prevent default on return false
4605 if (returnValue === false) {
4606 event.preventDefault();
4607 }
4608 } catch (e) {
4609 if (!this.handleError(e)) {
4610 console.error('unhandled error in event listener');
4611 console.error(e.stack);
4612
4613 throw e;
4614 }
4615 }
4616
4617 return returnValue;
4618 };
4619
4620 /*
4621 * Add new listener with a certain priority to the list
4622 * of listeners (for the given event).
4623 *
4624 * The semantics of listener registration / listener execution are
4625 * first register, first serve: New listeners will always be inserted
4626 * after existing listeners with the same priority.
4627 *
4628 * Example: Inserting two listeners with priority 1000 and 1300
4629 *
4630 * * before: [ 1500, 1500, 1000, 1000 ]
4631 * * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ]
4632 *
4633 * @param {String} event
4634 * @param {Object} listener { priority, callback }
4635 */
4636 EventBus.prototype._addListener = function(event, newListener) {
4637
4638 var listener = this._getListeners(event),
4639 previousListener;
4640
4641 // no prior listeners
4642 if (!listener) {
4643 this._setListeners(event, newListener);
4644
4645 return;
4646 }
4647
4648 // ensure we order listeners by priority from
4649 // 0 (high) to n > 0 (low)
4650 while (listener) {
4651
4652 if (listener.priority < newListener.priority) {
4653
4654 newListener.next = listener;
4655
4656 if (previousListener) {
4657 previousListener.next = newListener;
4658 } else {
4659 this._setListeners(event, newListener);
4660 }
4661
4662 return;
4663 }
4664
4665 previousListener = listener;
4666 listener = listener.next;
4667 }
4668
4669 // add new listener to back
4670 previousListener.next = newListener;
4671 };
4672
4673
4674 EventBus.prototype._getListeners = function(name) {
4675 return this._listeners[name];
4676 };
4677
4678 EventBus.prototype._setListeners = function(name, listener) {
4679 this._listeners[name] = listener;
4680 };
4681
4682 EventBus.prototype._removeListener = function(event, callback) {
4683
4684 var listener = this._getListeners(event),
4685 nextListener,
4686 previousListener,
4687 listenerCallback;
4688
4689 if (!callback) {
4690
4691 // clear listeners
4692 this._setListeners(event, null);
4693
4694 return;
4695 }
4696
4697 while (listener) {
4698
4699 nextListener = listener.next;
4700
4701 listenerCallback = listener.callback;
4702
4703 if (listenerCallback === callback || listenerCallback[FN_REF] === callback) {
4704 if (previousListener) {
4705 previousListener.next = nextListener;
4706 } else {
4707
4708 // new first listener
4709 this._setListeners(event, nextListener);
4710 }
4711 }
4712
4713 previousListener = listener;
4714 listener = nextListener;
4715 }
4716 };
4717
4718 /**
4719 * A event that is emitted via the event bus.
4720 */
4721 function InternalEvent() { }
4722
4723 InternalEvent.prototype.stopPropagation = function() {
4724 this.cancelBubble = true;
4725 };
4726
4727 InternalEvent.prototype.preventDefault = function() {
4728 this.defaultPrevented = true;
4729 };
4730
4731 InternalEvent.prototype.init = function(data) {
4732 assign(this, data || {});
4733 };
4734
4735
4736 /**
4737 * Invoke function. Be fast...
4738 *
4739 * @param {Function} fn
4740 * @param {Array<Object>} args
4741 *
4742 * @return {Any}
4743 */
4744 function invokeFunction(fn, args) {
4745 return fn.apply(null, args);
4746 }
4747
4748 /**
4749 * SVGs for elements are generated by the {@link GraphicsFactory}.
4750 *
4751 * This utility gives quick access to the important semantic
4752 * parts of an element.
4753 */
4754
4755 /**
4756 * Returns the visual part of a diagram element
4757 *
4758 * @param {Snap<SVGElement>} gfx
4759 *
4760 * @return {Snap<SVGElement>}
4761 */
4762 function getVisual(gfx) {
4763 return gfx.childNodes[0];
4764 }
4765
4766 /**
4767 * Returns the children for a given diagram element.
4768 *
4769 * @param {Snap<SVGElement>} gfx
4770 * @return {Snap<SVGElement>}
4771 */
4772 function getChildren(gfx) {
4773 return gfx.parentNode.childNodes[1];
4774 }
4775
4776 /**
4777 * @param {<SVGElement>} element
4778 * @param {Number} x
4779 * @param {Number} y
4780 * @param {Number} angle
4781 * @param {Number} amount
4782 */
4783 function transform$1(gfx, x, y, angle, amount) {
4784 var translate = createTransform();
4785 translate.setTranslate(x, y);
4786
4787 var rotate = createTransform();
4788 rotate.setRotate(angle, 0, 0);
4789
4790 var scale = createTransform();
4791 scale.setScale(amount || 1, amount || 1);
4792
4793 transform(gfx, [ translate, rotate, scale ]);
4794 }
4795
4796
4797 /**
4798 * @param {SVGElement} element
4799 * @param {Number} x
4800 * @param {Number} y
4801 */
4802 function translate(gfx, x, y) {
4803 var translate = createTransform();
4804 translate.setTranslate(x, y);
4805
4806 transform(gfx, translate);
4807 }
4808
4809
4810 /**
4811 * @param {SVGElement} element
4812 * @param {Number} angle
4813 */
4814 function rotate(gfx, angle) {
4815 var rotate = createTransform();
4816 rotate.setRotate(angle, 0, 0);
4817
4818 transform(gfx, rotate);
4819 }
4820
4821 /**
4822 * A factory that creates graphical elements
4823 *
4824 * @param {EventBus} eventBus
4825 * @param {ElementRegistry} elementRegistry
4826 */
4827 function GraphicsFactory(eventBus, elementRegistry) {
4828 this._eventBus = eventBus;
4829 this._elementRegistry = elementRegistry;
4830 }
4831
4832 GraphicsFactory.$inject = [ 'eventBus' , 'elementRegistry' ];
4833
4834
4835 GraphicsFactory.prototype._getChildren = function(element) {
4836
4837 var gfx = this._elementRegistry.getGraphics(element);
4838
4839 var childrenGfx;
4840
4841 // root element
4842 if (!element.parent) {
4843 childrenGfx = gfx;
4844 } else {
4845 childrenGfx = getChildren(gfx);
4846 if (!childrenGfx) {
4847 childrenGfx = create('g');
4848 classes$1(childrenGfx).add('djs-children');
4849
4850 append(gfx.parentNode, childrenGfx);
4851 }
4852 }
4853
4854 return childrenGfx;
4855 };
4856
4857 /**
4858 * Clears the graphical representation of the element and returns the
4859 * cleared visual (the <g class="djs-visual" /> element).
4860 */
4861 GraphicsFactory.prototype._clear = function(gfx) {
4862 var visual = getVisual(gfx);
4863
4864 clear(visual);
4865
4866 return visual;
4867 };
4868
4869 /**
4870 * Creates a gfx container for shapes and connections
4871 *
4872 * The layout is as follows:
4873 *
4874 * <g class="djs-group">
4875 *
4876 * <!-- the gfx -->
4877 * <g class="djs-element djs-(shape|connection|frame)">
4878 * <g class="djs-visual">
4879 * <!-- the renderer draws in here -->
4880 * </g>
4881 *
4882 * <!-- extensions (overlays, click box, ...) goes here
4883 * </g>
4884 *
4885 * <!-- the gfx child nodes -->
4886 * <g class="djs-children"></g>
4887 * </g>
4888 *
4889 * @param {String} type the type of the element, i.e. shape | connection
4890 * @param {SVGElement} [childrenGfx]
4891 * @param {Number} [parentIndex] position to create container in parent
4892 * @param {Boolean} [isFrame] is frame element
4893 *
4894 * @return {SVGElement}
4895 */
4896 GraphicsFactory.prototype._createContainer = function(
4897 type, childrenGfx, parentIndex, isFrame
4898 ) {
4899 var outerGfx = create('g');
4900 classes$1(outerGfx).add('djs-group');
4901
4902 // insert node at position
4903 if (typeof parentIndex !== 'undefined') {
4904 prependTo(outerGfx, childrenGfx, childrenGfx.childNodes[parentIndex]);
4905 } else {
4906 append(childrenGfx, outerGfx);
4907 }
4908
4909 var gfx = create('g');
4910 classes$1(gfx).add('djs-element');
4911 classes$1(gfx).add('djs-' + type);
4912
4913 if (isFrame) {
4914 classes$1(gfx).add('djs-frame');
4915 }
4916
4917 append(outerGfx, gfx);
4918
4919 // create visual
4920 var visual = create('g');
4921 classes$1(visual).add('djs-visual');
4922
4923 append(gfx, visual);
4924
4925 return gfx;
4926 };
4927
4928 GraphicsFactory.prototype.create = function(type, element, parentIndex) {
4929 var childrenGfx = this._getChildren(element.parent);
4930 return this._createContainer(type, childrenGfx, parentIndex, isFrameElement(element));
4931 };
4932
4933 GraphicsFactory.prototype.updateContainments = function(elements) {
4934
4935 var self = this,
4936 elementRegistry = this._elementRegistry,
4937 parents;
4938
4939 parents = reduce(elements, function(map, e) {
4940
4941 if (e.parent) {
4942 map[e.parent.id] = e.parent;
4943 }
4944
4945 return map;
4946 }, {});
4947
4948 // update all parents of changed and reorganized their children
4949 // in the correct order (as indicated in our model)
4950 forEach(parents, function(parent) {
4951
4952 var children = parent.children;
4953
4954 if (!children) {
4955 return;
4956 }
4957
4958 var childGfx = self._getChildren(parent);
4959
4960 forEach(children.slice().reverse(), function(c) {
4961 var gfx = elementRegistry.getGraphics(c);
4962
4963 prependTo(gfx.parentNode, childGfx);
4964 });
4965 });
4966 };
4967
4968 GraphicsFactory.prototype.drawShape = function(visual, element) {
4969 var eventBus = this._eventBus;
4970
4971 return eventBus.fire('render.shape', { gfx: visual, element: element });
4972 };
4973
4974 GraphicsFactory.prototype.getShapePath = function(element) {
4975 var eventBus = this._eventBus;
4976
4977 return eventBus.fire('render.getShapePath', element);
4978 };
4979
4980 GraphicsFactory.prototype.drawConnection = function(visual, element) {
4981 var eventBus = this._eventBus;
4982
4983 return eventBus.fire('render.connection', { gfx: visual, element: element });
4984 };
4985
4986 GraphicsFactory.prototype.getConnectionPath = function(waypoints) {
4987 var eventBus = this._eventBus;
4988
4989 return eventBus.fire('render.getConnectionPath', waypoints);
4990 };
4991
4992 GraphicsFactory.prototype.update = function(type, element, gfx) {
4993
4994 // do NOT update root element
4995 if (!element.parent) {
4996 return;
4997 }
4998
4999 var visual = this._clear(gfx);
5000
5001 // redraw
5002 if (type === 'shape') {
5003 this.drawShape(visual, element);
5004
5005 // update positioning
5006 translate(gfx, element.x, element.y);
5007 } else
5008 if (type === 'connection') {
5009 this.drawConnection(visual, element);
5010 } else {
5011 throw new Error('unknown type: ' + type);
5012 }
5013
5014 if (element.hidden) {
5015 attr$1(gfx, 'display', 'none');
5016 } else {
5017 attr$1(gfx, 'display', 'block');
5018 }
5019 };
5020
5021 GraphicsFactory.prototype.remove = function(element) {
5022 var gfx = this._elementRegistry.getGraphics(element);
5023
5024 // remove
5025 remove$1(gfx.parentNode);
5026 };
5027
5028
5029 // helpers //////////
5030
5031 function prependTo(newNode, parentNode, siblingNode) {
5032 var node = siblingNode || parentNode.firstChild;
5033
5034 // do not prepend node to itself to prevent IE from crashing
5035 // https://github.com/bpmn-io/bpmn-js/issues/746
5036 if (newNode === node) {
5037 return;
5038 }
5039
5040 parentNode.insertBefore(newNode, node);
5041 }
5042
5043 var CoreModule = {
5044 __depends__: [ DrawModule ],
5045 __init__: [ 'canvas' ],
5046 canvas: [ 'type', Canvas ],
5047 elementRegistry: [ 'type', ElementRegistry ],
5048 elementFactory: [ 'type', ElementFactory ],
5049 eventBus: [ 'type', EventBus ],
5050 graphicsFactory: [ 'type', GraphicsFactory ]
5051 };
5052
5053 /**
5054 * Bootstrap an injector from a list of modules, instantiating a number of default components
5055 *
5056 * @ignore
5057 * @param {Array<didi.Module>} bootstrapModules
5058 *
5059 * @return {didi.Injector} a injector to use to access the components
5060 */
5061 function bootstrap(bootstrapModules) {
5062
5063 var modules = [],
5064 components = [];
5065
5066 function hasModule(m) {
5067 return modules.indexOf(m) >= 0;
5068 }
5069
5070 function addModule(m) {
5071 modules.push(m);
5072 }
5073
5074 function visit(m) {
5075 if (hasModule(m)) {
5076 return;
5077 }
5078
5079 (m.__depends__ || []).forEach(visit);
5080
5081 if (hasModule(m)) {
5082 return;
5083 }
5084
5085 addModule(m);
5086
5087 (m.__init__ || []).forEach(function(c) {
5088 components.push(c);
5089 });
5090 }
5091
5092 bootstrapModules.forEach(visit);
5093
5094 var injector = new Injector(modules);
5095
5096 components.forEach(function(c) {
5097
5098 try {
5099
5100 // eagerly resolve component (fn or string)
5101 injector[typeof c === 'string' ? 'get' : 'invoke'](c);
5102 } catch (e) {
5103 console.error('Failed to instantiate component');
5104 console.error(e.stack);
5105
5106 throw e;
5107 }
5108 });
5109
5110 return injector;
5111 }
5112
5113 /**
5114 * Creates an injector from passed options.
5115 *
5116 * @ignore
5117 * @param {Object} options
5118 * @return {didi.Injector}
5119 */
5120 function createInjector(options) {
5121
5122 options = options || {};
5123
5124 var configModule = {
5125 'config': ['value', options]
5126 };
5127
5128 var modules = [ configModule, CoreModule ].concat(options.modules || []);
5129
5130 return bootstrap(modules);
5131 }
5132
5133
5134 /**
5135 * The main diagram-js entry point that bootstraps the diagram with the given
5136 * configuration.
5137 *
5138 * To register extensions with the diagram, pass them as Array<didi.Module> to the constructor.
5139 *
5140 * @class djs.Diagram
5141 * @memberOf djs
5142 * @constructor
5143 *
5144 * @example
5145 *
5146 * <caption>Creating a plug-in that logs whenever a shape is added to the canvas.</caption>
5147 *
5148 * // plug-in implemenentation
5149 * function MyLoggingPlugin(eventBus) {
5150 * eventBus.on('shape.added', function(event) {
5151 * console.log('shape ', event.shape, ' was added to the diagram');
5152 * });
5153 * }
5154 *
5155 * // export as module
5156 * export default {
5157 * __init__: [ 'myLoggingPlugin' ],
5158 * myLoggingPlugin: [ 'type', MyLoggingPlugin ]
5159 * };
5160 *
5161 *
5162 * // instantiate the diagram with the new plug-in
5163 *
5164 * import MyLoggingModule from 'path-to-my-logging-plugin';
5165 *
5166 * var diagram = new Diagram({
5167 * modules: [
5168 * MyLoggingModule
5169 * ]
5170 * });
5171 *
5172 * diagram.invoke([ 'canvas', function(canvas) {
5173 * // add shape to drawing canvas
5174 * canvas.addShape({ x: 10, y: 10 });
5175 * });
5176 *
5177 * // 'shape ... was added to the diagram' logged to console
5178 *
5179 * @param {Object} options
5180 * @param {Array<didi.Module>} [options.modules] external modules to instantiate with the diagram
5181 * @param {didi.Injector} [injector] an (optional) injector to bootstrap the diagram with
5182 */
5183 function Diagram(options, injector) {
5184
5185 // create injector unless explicitly specified
5186 this.injector = injector = injector || createInjector(options);
5187
5188 // API
5189
5190 /**
5191 * Resolves a diagram service
5192 *
5193 * @method Diagram#get
5194 *
5195 * @param {String} name the name of the diagram service to be retrieved
5196 * @param {Boolean} [strict=true] if false, resolve missing services to null
5197 */
5198 this.get = injector.get;
5199
5200 /**
5201 * Executes a function into which diagram services are injected
5202 *
5203 * @method Diagram#invoke
5204 *
5205 * @param {Function|Object[]} fn the function to resolve
5206 * @param {Object} locals a number of locals to use to resolve certain dependencies
5207 */
5208 this.invoke = injector.invoke;
5209
5210 // init
5211
5212 // indicate via event
5213
5214
5215 /**
5216 * An event indicating that all plug-ins are loaded.
5217 *
5218 * Use this event to fire other events to interested plug-ins
5219 *
5220 * @memberOf Diagram
5221 *
5222 * @event diagram.init
5223 *
5224 * @example
5225 *
5226 * eventBus.on('diagram.init', function() {
5227 * eventBus.fire('my-custom-event', { foo: 'BAR' });
5228 * });
5229 *
5230 * @type {Object}
5231 */
5232 this.get('eventBus').fire('diagram.init');
5233 }
5234
5235
5236 /**
5237 * Destroys the diagram
5238 *
5239 * @method Diagram#destroy
5240 */
5241 Diagram.prototype.destroy = function() {
5242 this.get('eventBus').fire('diagram.destroy');
5243 };
5244
5245 /**
5246 * Clear the diagram, removing all contents.
5247 */
5248 Diagram.prototype.clear = function() {
5249 this.get('eventBus').fire('diagram.clear');
5250 };
5251
5252 /**
5253 * Moddle base element.
5254 */
5255 function Base$1() { }
5256
5257 Base$1.prototype.get = function(name) {
5258 return this.$model.properties.get(this, name);
5259 };
5260
5261 Base$1.prototype.set = function(name, value) {
5262 this.$model.properties.set(this, name, value);
5263 };
5264
5265 /**
5266 * A model element factory.
5267 *
5268 * @param {Moddle} model
5269 * @param {Properties} properties
5270 */
5271 function Factory(model, properties) {
5272 this.model = model;
5273 this.properties = properties;
5274 }
5275
5276
5277 Factory.prototype.createType = function(descriptor) {
5278
5279 var model = this.model;
5280
5281 var props = this.properties,
5282 prototype = Object.create(Base$1.prototype);
5283
5284 // initialize default values
5285 forEach(descriptor.properties, function(p) {
5286 if (!p.isMany && p.default !== undefined) {
5287 prototype[p.name] = p.default;
5288 }
5289 });
5290
5291 props.defineModel(prototype, model);
5292 props.defineDescriptor(prototype, descriptor);
5293
5294 var name = descriptor.ns.name;
5295
5296 /**
5297 * The new type constructor
5298 */
5299 function ModdleElement(attrs) {
5300 props.define(this, '$type', { value: name, enumerable: true });
5301 props.define(this, '$attrs', { value: {} });
5302 props.define(this, '$parent', { writable: true });
5303
5304 forEach(attrs, bind(function(val, key) {
5305 this.set(key, val);
5306 }, this));
5307 }
5308
5309 ModdleElement.prototype = prototype;
5310
5311 ModdleElement.hasType = prototype.$instanceOf = this.model.hasType;
5312
5313 // static links
5314 props.defineModel(ModdleElement, model);
5315 props.defineDescriptor(ModdleElement, descriptor);
5316
5317 return ModdleElement;
5318 };
5319
5320 /**
5321 * Built-in moddle types
5322 */
5323 var BUILTINS = {
5324 String: true,
5325 Boolean: true,
5326 Integer: true,
5327 Real: true,
5328 Element: true
5329 };
5330
5331 /**
5332 * Converters for built in types from string representations
5333 */
5334 var TYPE_CONVERTERS = {
5335 String: function(s) { return s; },
5336 Boolean: function(s) { return s === 'true'; },
5337 Integer: function(s) { return parseInt(s, 10); },
5338 Real: function(s) { return parseFloat(s, 10); }
5339 };
5340
5341 /**
5342 * Convert a type to its real representation
5343 */
5344 function coerceType(type, value) {
5345
5346 var converter = TYPE_CONVERTERS[type];
5347
5348 if (converter) {
5349 return converter(value);
5350 } else {
5351 return value;
5352 }
5353 }
5354
5355 /**
5356 * Return whether the given type is built-in
5357 */
5358 function isBuiltIn(type) {
5359 return !!BUILTINS[type];
5360 }
5361
5362 /**
5363 * Return whether the given type is simple
5364 */
5365 function isSimple(type) {
5366 return !!TYPE_CONVERTERS[type];
5367 }
5368
5369 /**
5370 * Parses a namespaced attribute name of the form (ns:)localName to an object,
5371 * given a default prefix to assume in case no explicit namespace is given.
5372 *
5373 * @param {String} name
5374 * @param {String} [defaultPrefix] the default prefix to take, if none is present.
5375 *
5376 * @return {Object} the parsed name
5377 */
5378 function parseName(name, defaultPrefix) {
5379 var parts = name.split(/:/),
5380 localName, prefix;
5381
5382 // no prefix (i.e. only local name)
5383 if (parts.length === 1) {
5384 localName = name;
5385 prefix = defaultPrefix;
5386 } else
5387 // prefix + local name
5388 if (parts.length === 2) {
5389 localName = parts[1];
5390 prefix = parts[0];
5391 } else {
5392 throw new Error('expected <prefix:localName> or <localName>, got ' + name);
5393 }
5394
5395 name = (prefix ? prefix + ':' : '') + localName;
5396
5397 return {
5398 name: name,
5399 prefix: prefix,
5400 localName: localName
5401 };
5402 }
5403
5404 /**
5405 * A utility to build element descriptors.
5406 */
5407 function DescriptorBuilder(nameNs) {
5408 this.ns = nameNs;
5409 this.name = nameNs.name;
5410 this.allTypes = [];
5411 this.allTypesByName = {};
5412 this.properties = [];
5413 this.propertiesByName = {};
5414 }
5415
5416
5417 DescriptorBuilder.prototype.build = function() {
5418 return pick(this, [
5419 'ns',
5420 'name',
5421 'allTypes',
5422 'allTypesByName',
5423 'properties',
5424 'propertiesByName',
5425 'bodyProperty',
5426 'idProperty'
5427 ]);
5428 };
5429
5430 /**
5431 * Add property at given index.
5432 *
5433 * @param {Object} p
5434 * @param {Number} [idx]
5435 * @param {Boolean} [validate=true]
5436 */
5437 DescriptorBuilder.prototype.addProperty = function(p, idx, validate) {
5438
5439 if (typeof idx === 'boolean') {
5440 validate = idx;
5441 idx = undefined;
5442 }
5443
5444 this.addNamedProperty(p, validate !== false);
5445
5446 var properties = this.properties;
5447
5448 if (idx !== undefined) {
5449 properties.splice(idx, 0, p);
5450 } else {
5451 properties.push(p);
5452 }
5453 };
5454
5455
5456 DescriptorBuilder.prototype.replaceProperty = function(oldProperty, newProperty, replace) {
5457 var oldNameNs = oldProperty.ns;
5458
5459 var props = this.properties,
5460 propertiesByName = this.propertiesByName,
5461 rename = oldProperty.name !== newProperty.name;
5462
5463 if (oldProperty.isId) {
5464 if (!newProperty.isId) {
5465 throw new Error(
5466 'property <' + newProperty.ns.name + '> must be id property ' +
5467 'to refine <' + oldProperty.ns.name + '>');
5468 }
5469
5470 this.setIdProperty(newProperty, false);
5471 }
5472
5473 if (oldProperty.isBody) {
5474
5475 if (!newProperty.isBody) {
5476 throw new Error(
5477 'property <' + newProperty.ns.name + '> must be body property ' +
5478 'to refine <' + oldProperty.ns.name + '>');
5479 }
5480
5481 // TODO: Check compatibility
5482 this.setBodyProperty(newProperty, false);
5483 }
5484
5485 // validate existence and get location of old property
5486 var idx = props.indexOf(oldProperty);
5487 if (idx === -1) {
5488 throw new Error('property <' + oldNameNs.name + '> not found in property list');
5489 }
5490
5491 // remove old property
5492 props.splice(idx, 1);
5493
5494 // replacing the named property is intentional
5495 //
5496 // * validate only if this is a "rename" operation
5497 // * add at specific index unless we "replace"
5498 //
5499 this.addProperty(newProperty, replace ? undefined : idx, rename);
5500
5501 // make new property available under old name
5502 propertiesByName[oldNameNs.name] = propertiesByName[oldNameNs.localName] = newProperty;
5503 };
5504
5505
5506 DescriptorBuilder.prototype.redefineProperty = function(p, targetPropertyName, replace) {
5507
5508 var nsPrefix = p.ns.prefix;
5509 var parts = targetPropertyName.split('#');
5510
5511 var name = parseName(parts[0], nsPrefix);
5512 var attrName = parseName(parts[1], name.prefix).name;
5513
5514 var redefinedProperty = this.propertiesByName[attrName];
5515 if (!redefinedProperty) {
5516 throw new Error('refined property <' + attrName + '> not found');
5517 } else {
5518 this.replaceProperty(redefinedProperty, p, replace);
5519 }
5520
5521 delete p.redefines;
5522 };
5523
5524 DescriptorBuilder.prototype.addNamedProperty = function(p, validate) {
5525 var ns = p.ns,
5526 propsByName = this.propertiesByName;
5527
5528 if (validate) {
5529 this.assertNotDefined(p, ns.name);
5530 this.assertNotDefined(p, ns.localName);
5531 }
5532
5533 propsByName[ns.name] = propsByName[ns.localName] = p;
5534 };
5535
5536 DescriptorBuilder.prototype.removeNamedProperty = function(p) {
5537 var ns = p.ns,
5538 propsByName = this.propertiesByName;
5539
5540 delete propsByName[ns.name];
5541 delete propsByName[ns.localName];
5542 };
5543
5544 DescriptorBuilder.prototype.setBodyProperty = function(p, validate) {
5545
5546 if (validate && this.bodyProperty) {
5547 throw new Error(
5548 'body property defined multiple times ' +
5549 '(<' + this.bodyProperty.ns.name + '>, <' + p.ns.name + '>)');
5550 }
5551
5552 this.bodyProperty = p;
5553 };
5554
5555 DescriptorBuilder.prototype.setIdProperty = function(p, validate) {
5556
5557 if (validate && this.idProperty) {
5558 throw new Error(
5559 'id property defined multiple times ' +
5560 '(<' + this.idProperty.ns.name + '>, <' + p.ns.name + '>)');
5561 }
5562
5563 this.idProperty = p;
5564 };
5565
5566 DescriptorBuilder.prototype.assertNotDefined = function(p, name) {
5567 var propertyName = p.name,
5568 definedProperty = this.propertiesByName[propertyName];
5569
5570 if (definedProperty) {
5571 throw new Error(
5572 'property <' + propertyName + '> already defined; ' +
5573 'override of <' + definedProperty.definedBy.ns.name + '#' + definedProperty.ns.name + '> by ' +
5574 '<' + p.definedBy.ns.name + '#' + p.ns.name + '> not allowed without redefines');
5575 }
5576 };
5577
5578 DescriptorBuilder.prototype.hasProperty = function(name) {
5579 return this.propertiesByName[name];
5580 };
5581
5582 DescriptorBuilder.prototype.addTrait = function(t, inherited) {
5583
5584 var typesByName = this.allTypesByName,
5585 types = this.allTypes;
5586
5587 var typeName = t.name;
5588
5589 if (typeName in typesByName) {
5590 return;
5591 }
5592
5593 forEach(t.properties, bind(function(p) {
5594
5595 // clone property to allow extensions
5596 p = assign({}, p, {
5597 name: p.ns.localName,
5598 inherited: inherited
5599 });
5600
5601 Object.defineProperty(p, 'definedBy', {
5602 value: t
5603 });
5604
5605 var replaces = p.replaces,
5606 redefines = p.redefines;
5607
5608 // add replace/redefine support
5609 if (replaces || redefines) {
5610 this.redefineProperty(p, replaces || redefines, replaces);
5611 } else {
5612 if (p.isBody) {
5613 this.setBodyProperty(p);
5614 }
5615 if (p.isId) {
5616 this.setIdProperty(p);
5617 }
5618 this.addProperty(p);
5619 }
5620 }, this));
5621
5622 types.push(t);
5623 typesByName[typeName] = t;
5624 };
5625
5626 /**
5627 * A registry of Moddle packages.
5628 *
5629 * @param {Array<Package>} packages
5630 * @param {Properties} properties
5631 */
5632 function Registry(packages, properties) {
5633 this.packageMap = {};
5634 this.typeMap = {};
5635
5636 this.packages = [];
5637
5638 this.properties = properties;
5639
5640 forEach(packages, bind(this.registerPackage, this));
5641 }
5642
5643
5644 Registry.prototype.getPackage = function(uriOrPrefix) {
5645 return this.packageMap[uriOrPrefix];
5646 };
5647
5648 Registry.prototype.getPackages = function() {
5649 return this.packages;
5650 };
5651
5652
5653 Registry.prototype.registerPackage = function(pkg) {
5654
5655 // copy package
5656 pkg = assign({}, pkg);
5657
5658 var pkgMap = this.packageMap;
5659
5660 ensureAvailable(pkgMap, pkg, 'prefix');
5661 ensureAvailable(pkgMap, pkg, 'uri');
5662
5663 // register types
5664 forEach(pkg.types, bind(function(descriptor) {
5665 this.registerType(descriptor, pkg);
5666 }, this));
5667
5668 pkgMap[pkg.uri] = pkgMap[pkg.prefix] = pkg;
5669 this.packages.push(pkg);
5670 };
5671
5672
5673 /**
5674 * Register a type from a specific package with us
5675 */
5676 Registry.prototype.registerType = function(type, pkg) {
5677
5678 type = assign({}, type, {
5679 superClass: (type.superClass || []).slice(),
5680 extends: (type.extends || []).slice(),
5681 properties: (type.properties || []).slice(),
5682 meta: assign((type.meta || {}))
5683 });
5684
5685 var ns = parseName(type.name, pkg.prefix),
5686 name = ns.name,
5687 propertiesByName = {};
5688
5689 // parse properties
5690 forEach(type.properties, bind(function(p) {
5691
5692 // namespace property names
5693 var propertyNs = parseName(p.name, ns.prefix),
5694 propertyName = propertyNs.name;
5695
5696 // namespace property types
5697 if (!isBuiltIn(p.type)) {
5698 p.type = parseName(p.type, propertyNs.prefix).name;
5699 }
5700
5701 assign(p, {
5702 ns: propertyNs,
5703 name: propertyName
5704 });
5705
5706 propertiesByName[propertyName] = p;
5707 }, this));
5708
5709 // update ns + name
5710 assign(type, {
5711 ns: ns,
5712 name: name,
5713 propertiesByName: propertiesByName
5714 });
5715
5716 forEach(type.extends, bind(function(extendsName) {
5717 var extended = this.typeMap[extendsName];
5718
5719 extended.traits = extended.traits || [];
5720 extended.traits.push(name);
5721 }, this));
5722
5723 // link to package
5724 this.definePackage(type, pkg);
5725
5726 // register
5727 this.typeMap[name] = type;
5728 };
5729
5730
5731 /**
5732 * Traverse the type hierarchy from bottom to top,
5733 * calling iterator with (type, inherited) for all elements in
5734 * the inheritance chain.
5735 *
5736 * @param {Object} nsName
5737 * @param {Function} iterator
5738 * @param {Boolean} [trait=false]
5739 */
5740 Registry.prototype.mapTypes = function(nsName, iterator, trait) {
5741
5742 var type = isBuiltIn(nsName.name) ? { name: nsName.name } : this.typeMap[nsName.name];
5743
5744 var self = this;
5745
5746 /**
5747 * Traverse the selected trait.
5748 *
5749 * @param {String} cls
5750 */
5751 function traverseTrait(cls) {
5752 return traverseSuper(cls, true);
5753 }
5754
5755 /**
5756 * Traverse the selected super type or trait
5757 *
5758 * @param {String} cls
5759 * @param {Boolean} [trait=false]
5760 */
5761 function traverseSuper(cls, trait) {
5762 var parentNs = parseName(cls, isBuiltIn(cls) ? '' : nsName.prefix);
5763 self.mapTypes(parentNs, iterator, trait);
5764 }
5765
5766 if (!type) {
5767 throw new Error('unknown type <' + nsName.name + '>');
5768 }
5769
5770 forEach(type.superClass, trait ? traverseTrait : traverseSuper);
5771
5772 // call iterator with (type, inherited=!trait)
5773 iterator(type, !trait);
5774
5775 forEach(type.traits, traverseTrait);
5776 };
5777
5778
5779 /**
5780 * Returns the effective descriptor for a type.
5781 *
5782 * @param {String} type the namespaced name (ns:localName) of the type
5783 *
5784 * @return {Descriptor} the resulting effective descriptor
5785 */
5786 Registry.prototype.getEffectiveDescriptor = function(name) {
5787
5788 var nsName = parseName(name);
5789
5790 var builder = new DescriptorBuilder(nsName);
5791
5792 this.mapTypes(nsName, function(type, inherited) {
5793 builder.addTrait(type, inherited);
5794 });
5795
5796 var descriptor = builder.build();
5797
5798 // define package link
5799 this.definePackage(descriptor, descriptor.allTypes[descriptor.allTypes.length - 1].$pkg);
5800
5801 return descriptor;
5802 };
5803
5804
5805 Registry.prototype.definePackage = function(target, pkg) {
5806 this.properties.define(target, '$pkg', { value: pkg });
5807 };
5808
5809
5810
5811 ///////// helpers ////////////////////////////
5812
5813 function ensureAvailable(packageMap, pkg, identifierKey) {
5814
5815 var value = pkg[identifierKey];
5816
5817 if (value in packageMap) {
5818 throw new Error('package with ' + identifierKey + ' <' + value + '> already defined');
5819 }
5820 }
5821
5822 /**
5823 * A utility that gets and sets properties of model elements.
5824 *
5825 * @param {Model} model
5826 */
5827 function Properties(model) {
5828 this.model = model;
5829 }
5830
5831
5832 /**
5833 * Sets a named property on the target element.
5834 * If the value is undefined, the property gets deleted.
5835 *
5836 * @param {Object} target
5837 * @param {String} name
5838 * @param {Object} value
5839 */
5840 Properties.prototype.set = function(target, name, value) {
5841
5842 var property = this.model.getPropertyDescriptor(target, name);
5843
5844 var propertyName = property && property.name;
5845
5846 if (isUndefined$1(value)) {
5847 // unset the property, if the specified value is undefined;
5848 // delete from $attrs (for extensions) or the target itself
5849 if (property) {
5850 delete target[propertyName];
5851 } else {
5852 delete target.$attrs[name];
5853 }
5854 } else {
5855 // set the property, defining well defined properties on the fly
5856 // or simply updating them in target.$attrs (for extensions)
5857 if (property) {
5858 if (propertyName in target) {
5859 target[propertyName] = value;
5860 } else {
5861 defineProperty$1(target, property, value);
5862 }
5863 } else {
5864 target.$attrs[name] = value;
5865 }
5866 }
5867 };
5868
5869 /**
5870 * Returns the named property of the given element
5871 *
5872 * @param {Object} target
5873 * @param {String} name
5874 *
5875 * @return {Object}
5876 */
5877 Properties.prototype.get = function(target, name) {
5878
5879 var property = this.model.getPropertyDescriptor(target, name);
5880
5881 if (!property) {
5882 return target.$attrs[name];
5883 }
5884
5885 var propertyName = property.name;
5886
5887 // check if access to collection property and lazily initialize it
5888 if (!target[propertyName] && property.isMany) {
5889 defineProperty$1(target, property, []);
5890 }
5891
5892 return target[propertyName];
5893 };
5894
5895
5896 /**
5897 * Define a property on the target element
5898 *
5899 * @param {Object} target
5900 * @param {String} name
5901 * @param {Object} options
5902 */
5903 Properties.prototype.define = function(target, name, options) {
5904 Object.defineProperty(target, name, options);
5905 };
5906
5907
5908 /**
5909 * Define the descriptor for an element
5910 */
5911 Properties.prototype.defineDescriptor = function(target, descriptor) {
5912 this.define(target, '$descriptor', { value: descriptor });
5913 };
5914
5915 /**
5916 * Define the model for an element
5917 */
5918 Properties.prototype.defineModel = function(target, model) {
5919 this.define(target, '$model', { value: model });
5920 };
5921
5922
5923 function isUndefined$1(val) {
5924 return typeof val === 'undefined';
5925 }
5926
5927 function defineProperty$1(target, property, value) {
5928 Object.defineProperty(target, property.name, {
5929 enumerable: !property.isReference,
5930 writable: true,
5931 value: value,
5932 configurable: true
5933 });
5934 }
5935
5936 //// Moddle implementation /////////////////////////////////////////////////
5937
5938 /**
5939 * @class Moddle
5940 *
5941 * A model that can be used to create elements of a specific type.
5942 *
5943 * @example
5944 *
5945 * var Moddle = require('moddle');
5946 *
5947 * var pkg = {
5948 * name: 'mypackage',
5949 * prefix: 'my',
5950 * types: [
5951 * { name: 'Root' }
5952 * ]
5953 * };
5954 *
5955 * var moddle = new Moddle([pkg]);
5956 *
5957 * @param {Array<Package>} packages the packages to contain
5958 */
5959 function Moddle(packages) {
5960
5961 this.properties = new Properties(this);
5962
5963 this.factory = new Factory(this, this.properties);
5964 this.registry = new Registry(packages, this.properties);
5965
5966 this.typeCache = {};
5967 }
5968
5969
5970 /**
5971 * Create an instance of the specified type.
5972 *
5973 * @method Moddle#create
5974 *
5975 * @example
5976 *
5977 * var foo = moddle.create('my:Foo');
5978 * var bar = moddle.create('my:Bar', { id: 'BAR_1' });
5979 *
5980 * @param {String|Object} descriptor the type descriptor or name know to the model
5981 * @param {Object} attrs a number of attributes to initialize the model instance with
5982 * @return {Object} model instance
5983 */
5984 Moddle.prototype.create = function(descriptor, attrs) {
5985 var Type = this.getType(descriptor);
5986
5987 if (!Type) {
5988 throw new Error('unknown type <' + descriptor + '>');
5989 }
5990
5991 return new Type(attrs);
5992 };
5993
5994
5995 /**
5996 * Returns the type representing a given descriptor
5997 *
5998 * @method Moddle#getType
5999 *
6000 * @example
6001 *
6002 * var Foo = moddle.getType('my:Foo');
6003 * var foo = new Foo({ 'id' : 'FOO_1' });
6004 *
6005 * @param {String|Object} descriptor the type descriptor or name know to the model
6006 * @return {Object} the type representing the descriptor
6007 */
6008 Moddle.prototype.getType = function(descriptor) {
6009
6010 var cache = this.typeCache;
6011
6012 var name = isString(descriptor) ? descriptor : descriptor.ns.name;
6013
6014 var type = cache[name];
6015
6016 if (!type) {
6017 descriptor = this.registry.getEffectiveDescriptor(name);
6018 type = cache[name] = this.factory.createType(descriptor);
6019 }
6020
6021 return type;
6022 };
6023
6024
6025 /**
6026 * Creates an any-element type to be used within model instances.
6027 *
6028 * This can be used to create custom elements that lie outside the meta-model.
6029 * The created element contains all the meta-data required to serialize it
6030 * as part of meta-model elements.
6031 *
6032 * @method Moddle#createAny
6033 *
6034 * @example
6035 *
6036 * var foo = moddle.createAny('vendor:Foo', 'http://vendor', {
6037 * value: 'bar'
6038 * });
6039 *
6040 * var container = moddle.create('my:Container', 'http://my', {
6041 * any: [ foo ]
6042 * });
6043 *
6044 * // go ahead and serialize the stuff
6045 *
6046 *
6047 * @param {String} name the name of the element
6048 * @param {String} nsUri the namespace uri of the element
6049 * @param {Object} [properties] a map of properties to initialize the instance with
6050 * @return {Object} the any type instance
6051 */
6052 Moddle.prototype.createAny = function(name, nsUri, properties) {
6053
6054 var nameNs = parseName(name);
6055
6056 var element = {
6057 $type: name,
6058 $instanceOf: function(type) {
6059 return type === this.$type;
6060 }
6061 };
6062
6063 var descriptor = {
6064 name: name,
6065 isGeneric: true,
6066 ns: {
6067 prefix: nameNs.prefix,
6068 localName: nameNs.localName,
6069 uri: nsUri
6070 }
6071 };
6072
6073 this.properties.defineDescriptor(element, descriptor);
6074 this.properties.defineModel(element, this);
6075 this.properties.define(element, '$parent', { enumerable: false, writable: true });
6076
6077 forEach(properties, function(a, key) {
6078 if (isObject(a) && a.value !== undefined) {
6079 element[a.name] = a.value;
6080 } else {
6081 element[key] = a;
6082 }
6083 });
6084
6085 return element;
6086 };
6087
6088 /**
6089 * Returns a registered package by uri or prefix
6090 *
6091 * @return {Object} the package
6092 */
6093 Moddle.prototype.getPackage = function(uriOrPrefix) {
6094 return this.registry.getPackage(uriOrPrefix);
6095 };
6096
6097 /**
6098 * Returns a snapshot of all known packages
6099 *
6100 * @return {Object} the package
6101 */
6102 Moddle.prototype.getPackages = function() {
6103 return this.registry.getPackages();
6104 };
6105
6106 /**
6107 * Returns the descriptor for an element
6108 */
6109 Moddle.prototype.getElementDescriptor = function(element) {
6110 return element.$descriptor;
6111 };
6112
6113 /**
6114 * Returns true if the given descriptor or instance
6115 * represents the given type.
6116 *
6117 * May be applied to this, if element is omitted.
6118 */
6119 Moddle.prototype.hasType = function(element, type) {
6120 if (type === undefined) {
6121 type = element;
6122 element = this;
6123 }
6124
6125 var descriptor = element.$model.getElementDescriptor(element);
6126
6127 return (type in descriptor.allTypesByName);
6128 };
6129
6130 /**
6131 * Returns the descriptor of an elements named property
6132 */
6133 Moddle.prototype.getPropertyDescriptor = function(element, property) {
6134 return this.getElementDescriptor(element).propertiesByName[property];
6135 };
6136
6137 /**
6138 * Returns a mapped type's descriptor
6139 */
6140 Moddle.prototype.getTypeDescriptor = function(type) {
6141 return this.registry.typeMap[type];
6142 };
6143
6144 var fromCharCode = String.fromCharCode;
6145
6146 var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
6147
6148 var ENTITY_PATTERN = /&#(\d+);|&#x([0-9a-f]+);|&(\w+);/ig;
6149
6150 var ENTITY_MAPPING = {
6151 'amp': '&',
6152 'apos': '\'',
6153 'gt': '>',
6154 'lt': '<',
6155 'quot': '"'
6156 };
6157
6158 // map UPPERCASE variants of supported special chars
6159 Object.keys(ENTITY_MAPPING).forEach(function(k) {
6160 ENTITY_MAPPING[k.toUpperCase()] = ENTITY_MAPPING[k];
6161 });
6162
6163
6164 function replaceEntities(_, d, x, z) {
6165
6166 // reserved names, i.e. &nbsp;
6167 if (z) {
6168 if (hasOwnProperty$1.call(ENTITY_MAPPING, z)) {
6169 return ENTITY_MAPPING[z];
6170 } else {
6171 // fall back to original value
6172 return '&' + z + ';';
6173 }
6174 }
6175
6176 // decimal encoded char
6177 if (d) {
6178 return fromCharCode(d);
6179 }
6180
6181 // hex encoded char
6182 return fromCharCode(parseInt(x, 16));
6183 }
6184
6185
6186 /**
6187 * A basic entity decoder that can decode a minimal
6188 * sub-set of reserved names (&amp;) as well as
6189 * hex (&#xaaf;) and decimal (&#1231;) encoded characters.
6190 *
6191 * @param {string} str
6192 *
6193 * @return {string} decoded string
6194 */
6195 function decodeEntities(s) {
6196 if (s.length > 3 && s.indexOf('&') !== -1) {
6197 return s.replace(ENTITY_PATTERN, replaceEntities);
6198 }
6199
6200 return s;
6201 }
6202
6203 var XSI_URI = 'http://www.w3.org/2001/XMLSchema-instance';
6204 var XSI_PREFIX = 'xsi';
6205 var XSI_TYPE = 'xsi:type';
6206
6207 var NON_WHITESPACE_OUTSIDE_ROOT_NODE = 'non-whitespace outside of root node';
6208
6209 function error(msg) {
6210 return new Error(msg);
6211 }
6212
6213 function missingNamespaceForPrefix(prefix) {
6214 return 'missing namespace for prefix <' + prefix + '>';
6215 }
6216
6217 function getter(getFn) {
6218 return {
6219 'get': getFn,
6220 'enumerable': true
6221 };
6222 }
6223
6224 function cloneNsMatrix(nsMatrix) {
6225 var clone = {}, key;
6226 for (key in nsMatrix) {
6227 clone[key] = nsMatrix[key];
6228 }
6229 return clone;
6230 }
6231
6232 function uriPrefix(prefix) {
6233 return prefix + '$uri';
6234 }
6235
6236 function buildNsMatrix(nsUriToPrefix) {
6237 var nsMatrix = {},
6238 uri,
6239 prefix;
6240
6241 for (uri in nsUriToPrefix) {
6242 prefix = nsUriToPrefix[uri];
6243 nsMatrix[prefix] = prefix;
6244 nsMatrix[uriPrefix(prefix)] = uri;
6245 }
6246
6247 return nsMatrix;
6248 }
6249
6250 function noopGetContext() {
6251 return { 'line': 0, 'column': 0 };
6252 }
6253
6254 function throwFunc(err) {
6255 throw err;
6256 }
6257
6258 /**
6259 * Creates a new parser with the given options.
6260 *
6261 * @constructor
6262 *
6263 * @param {!Object<string, ?>=} options
6264 */
6265 function Parser(options) {
6266
6267 if (!this) {
6268 return new Parser(options);
6269 }
6270
6271 var proxy = options && options['proxy'];
6272
6273 var onText,
6274 onOpenTag,
6275 onCloseTag,
6276 onCDATA,
6277 onError = throwFunc,
6278 onWarning,
6279 onComment,
6280 onQuestion,
6281 onAttention;
6282
6283 var getContext = noopGetContext;
6284
6285 /**
6286 * Do we need to parse the current elements attributes for namespaces?
6287 *
6288 * @type {boolean}
6289 */
6290 var maybeNS = false;
6291
6292 /**
6293 * Do we process namespaces at all?
6294 *
6295 * @type {boolean}
6296 */
6297 var isNamespace = false;
6298
6299 /**
6300 * The caught error returned on parse end
6301 *
6302 * @type {Error}
6303 */
6304 var returnError = null;
6305
6306 /**
6307 * Should we stop parsing?
6308 *
6309 * @type {boolean}
6310 */
6311 var parseStop = false;
6312
6313 /**
6314 * A map of { uri: prefix } used by the parser.
6315 *
6316 * This map will ensure we can normalize prefixes during processing;
6317 * for each uri, only one prefix will be exposed to the handlers.
6318 *
6319 * @type {!Object<string, string>}}
6320 */
6321 var nsUriToPrefix;
6322
6323 /**
6324 * Handle parse error.
6325 *
6326 * @param {string|Error} err
6327 */
6328 function handleError(err) {
6329 if (!(err instanceof Error)) {
6330 err = error(err);
6331 }
6332
6333 returnError = err;
6334
6335 onError(err, getContext);
6336 }
6337
6338 /**
6339 * Handle parse error.
6340 *
6341 * @param {string|Error} err
6342 */
6343 function handleWarning(err) {
6344
6345 if (!onWarning) {
6346 return;
6347 }
6348
6349 if (!(err instanceof Error)) {
6350 err = error(err);
6351 }
6352
6353 onWarning(err, getContext);
6354 }
6355
6356 /**
6357 * Register parse listener.
6358 *
6359 * @param {string} name
6360 * @param {Function} cb
6361 *
6362 * @return {Parser}
6363 */
6364 this['on'] = function(name, cb) {
6365
6366 if (typeof cb !== 'function') {
6367 throw error('required args <name, cb>');
6368 }
6369
6370 switch (name) {
6371 case 'openTag': onOpenTag = cb; break;
6372 case 'text': onText = cb; break;
6373 case 'closeTag': onCloseTag = cb; break;
6374 case 'error': onError = cb; break;
6375 case 'warn': onWarning = cb; break;
6376 case 'cdata': onCDATA = cb; break;
6377 case 'attention': onAttention = cb; break; // <!XXXXX zzzz="eeee">
6378 case 'question': onQuestion = cb; break; // <? .... ?>
6379 case 'comment': onComment = cb; break;
6380 default:
6381 throw error('unsupported event: ' + name);
6382 }
6383
6384 return this;
6385 };
6386
6387 /**
6388 * Set the namespace to prefix mapping.
6389 *
6390 * @example
6391 *
6392 * parser.ns({
6393 * 'http://foo': 'foo',
6394 * 'http://bar': 'bar'
6395 * });
6396 *
6397 * @param {!Object<string, string>} nsMap
6398 *
6399 * @return {Parser}
6400 */
6401 this['ns'] = function(nsMap) {
6402
6403 if (typeof nsMap === 'undefined') {
6404 nsMap = {};
6405 }
6406
6407 if (typeof nsMap !== 'object') {
6408 throw error('required args <nsMap={}>');
6409 }
6410
6411 var _nsUriToPrefix = {}, k;
6412
6413 for (k in nsMap) {
6414 _nsUriToPrefix[k] = nsMap[k];
6415 }
6416
6417 // FORCE default mapping for schema instance
6418 _nsUriToPrefix[XSI_URI] = XSI_PREFIX;
6419
6420 isNamespace = true;
6421 nsUriToPrefix = _nsUriToPrefix;
6422
6423 return this;
6424 };
6425
6426 /**
6427 * Parse xml string.
6428 *
6429 * @param {string} xml
6430 *
6431 * @return {Error} returnError, if not thrown
6432 */
6433 this['parse'] = function(xml) {
6434 if (typeof xml !== 'string') {
6435 throw error('required args <xml=string>');
6436 }
6437
6438 returnError = null;
6439
6440 parse(xml);
6441
6442 getContext = noopGetContext;
6443 parseStop = false;
6444
6445 return returnError;
6446 };
6447
6448 /**
6449 * Stop parsing.
6450 */
6451 this['stop'] = function() {
6452 parseStop = true;
6453 };
6454
6455 /**
6456 * Parse string, invoking configured listeners on element.
6457 *
6458 * @param {string} xml
6459 */
6460 function parse(xml) {
6461 var nsMatrixStack = isNamespace ? [] : null,
6462 nsMatrix = isNamespace ? buildNsMatrix(nsUriToPrefix) : null,
6463 _nsMatrix,
6464 nodeStack = [],
6465 anonymousNsCount = 0,
6466 tagStart = false,
6467 tagEnd = false,
6468 i = 0, j = 0,
6469 x, y, q, w,
6470 xmlns,
6471 elementName,
6472 _elementName,
6473 elementProxy
6474 ;
6475
6476 var attrsString = '',
6477 attrsStart = 0,
6478 cachedAttrs // false = parsed with errors, null = needs parsing
6479 ;
6480
6481 /**
6482 * Parse attributes on demand and returns the parsed attributes.
6483 *
6484 * Return semantics: (1) `false` on attribute parse error,
6485 * (2) object hash on extracted attrs.
6486 *
6487 * @return {boolean|Object}
6488 */
6489 function getAttrs() {
6490 if (cachedAttrs !== null) {
6491 return cachedAttrs;
6492 }
6493
6494 var nsUri,
6495 nsUriPrefix,
6496 nsName,
6497 defaultAlias = isNamespace && nsMatrix['xmlns'],
6498 attrList = isNamespace && maybeNS ? [] : null,
6499 i = attrsStart,
6500 s = attrsString,
6501 l = s.length,
6502 hasNewMatrix,
6503 newalias,
6504 value,
6505 alias,
6506 name,
6507 attrs = {},
6508 seenAttrs = {},
6509 skipAttr,
6510 w,
6511 j;
6512
6513 parseAttr:
6514 for (; i < l; i++) {
6515 skipAttr = false;
6516 w = s.charCodeAt(i);
6517
6518 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE={ \f\n\r\t\v}
6519 continue;
6520 }
6521
6522 // wait for non whitespace character
6523 if (w < 65 || w > 122 || (w > 90 && w < 97)) {
6524 if (w !== 95 && w !== 58) { // char 95"_" 58":"
6525 handleWarning('illegal first char attribute name');
6526 skipAttr = true;
6527 }
6528 }
6529
6530 // parse attribute name
6531 for (j = i + 1; j < l; j++) {
6532 w = s.charCodeAt(j);
6533
6534 if (
6535 w > 96 && w < 123 ||
6536 w > 64 && w < 91 ||
6537 w > 47 && w < 59 ||
6538 w === 46 || // '.'
6539 w === 45 || // '-'
6540 w === 95 // '_'
6541 ) {
6542 continue;
6543 }
6544
6545 // unexpected whitespace
6546 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
6547 handleWarning('missing attribute value');
6548 i = j;
6549
6550 continue parseAttr;
6551 }
6552
6553 // expected "="
6554 if (w === 61) { // "=" == 61
6555 break;
6556 }
6557
6558 handleWarning('illegal attribute name char');
6559 skipAttr = true;
6560 }
6561
6562 name = s.substring(i, j);
6563
6564 if (name === 'xmlns:xmlns') {
6565 handleWarning('illegal declaration of xmlns');
6566 skipAttr = true;
6567 }
6568
6569 w = s.charCodeAt(j + 1);
6570
6571 if (w === 34) { // '"'
6572 j = s.indexOf('"', i = j + 2);
6573
6574 if (j === -1) {
6575 j = s.indexOf('\'', i);
6576
6577 if (j !== -1) {
6578 handleWarning('attribute value quote missmatch');
6579 skipAttr = true;
6580 }
6581 }
6582
6583 } else if (w === 39) { // "'"
6584 j = s.indexOf('\'', i = j + 2);
6585
6586 if (j === -1) {
6587 j = s.indexOf('"', i);
6588
6589 if (j !== -1) {
6590 handleWarning('attribute value quote missmatch');
6591 skipAttr = true;
6592 }
6593 }
6594
6595 } else {
6596 handleWarning('missing attribute value quotes');
6597 skipAttr = true;
6598
6599 // skip to next space
6600 for (j = j + 1; j < l; j++) {
6601 w = s.charCodeAt(j + 1);
6602
6603 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
6604 break;
6605 }
6606 }
6607
6608 }
6609
6610 if (j === -1) {
6611 handleWarning('missing closing quotes');
6612
6613 j = l;
6614 skipAttr = true;
6615 }
6616
6617 if (!skipAttr) {
6618 value = s.substring(i, j);
6619 }
6620
6621 i = j;
6622
6623 // ensure SPACE follows attribute
6624 // skip illegal content otherwise
6625 // example a="b"c
6626 for (; j + 1 < l; j++) {
6627 w = s.charCodeAt(j + 1);
6628
6629 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
6630 break;
6631 }
6632
6633 // FIRST ILLEGAL CHAR
6634 if (i === j) {
6635 handleWarning('illegal character after attribute end');
6636 skipAttr = true;
6637 }
6638 }
6639
6640 // advance cursor to next attribute
6641 i = j + 1;
6642
6643 if (skipAttr) {
6644 continue parseAttr;
6645 }
6646
6647 // check attribute re-declaration
6648 if (name in seenAttrs) {
6649 handleWarning('attribute <' + name + '> already defined');
6650 continue;
6651 }
6652
6653 seenAttrs[name] = true;
6654
6655 if (!isNamespace) {
6656 attrs[name] = value;
6657 continue;
6658 }
6659
6660 // try to extract namespace information
6661 if (maybeNS) {
6662 newalias = (
6663 name === 'xmlns'
6664 ? 'xmlns'
6665 : (name.charCodeAt(0) === 120 && name.substr(0, 6) === 'xmlns:')
6666 ? name.substr(6)
6667 : null
6668 );
6669
6670 // handle xmlns(:alias) assignment
6671 if (newalias !== null) {
6672 nsUri = decodeEntities(value);
6673 nsUriPrefix = uriPrefix(newalias);
6674
6675 alias = nsUriToPrefix[nsUri];
6676
6677 if (!alias) {
6678 // no prefix defined or prefix collision
6679 if (
6680 (newalias === 'xmlns') ||
6681 (nsUriPrefix in nsMatrix && nsMatrix[nsUriPrefix] !== nsUri)
6682 ) {
6683 // alocate free ns prefix
6684 do {
6685 alias = 'ns' + (anonymousNsCount++);
6686 } while (typeof nsMatrix[alias] !== 'undefined');
6687 } else {
6688 alias = newalias;
6689 }
6690
6691 nsUriToPrefix[nsUri] = alias;
6692 }
6693
6694 if (nsMatrix[newalias] !== alias) {
6695 if (!hasNewMatrix) {
6696 nsMatrix = cloneNsMatrix(nsMatrix);
6697 hasNewMatrix = true;
6698 }
6699
6700 nsMatrix[newalias] = alias;
6701 if (newalias === 'xmlns') {
6702 nsMatrix[uriPrefix(alias)] = nsUri;
6703 defaultAlias = alias;
6704 }
6705
6706 nsMatrix[nsUriPrefix] = nsUri;
6707 }
6708
6709 // expose xmlns(:asd)="..." in attributes
6710 attrs[name] = value;
6711 continue;
6712 }
6713
6714 // collect attributes until all namespace
6715 // declarations are processed
6716 attrList.push(name, value);
6717 continue;
6718
6719 } /** end if (maybeNs) */
6720
6721 // handle attributes on element without
6722 // namespace declarations
6723 w = name.indexOf(':');
6724 if (w === -1) {
6725 attrs[name] = value;
6726 continue;
6727 }
6728
6729 // normalize ns attribute name
6730 if (!(nsName = nsMatrix[name.substring(0, w)])) {
6731 handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
6732 continue;
6733 }
6734
6735 name = defaultAlias === nsName
6736 ? name.substr(w + 1)
6737 : nsName + name.substr(w);
6738 // end: normalize ns attribute name
6739
6740 // normalize xsi:type ns attribute value
6741 if (name === XSI_TYPE) {
6742 w = value.indexOf(':');
6743
6744 if (w !== -1) {
6745 nsName = value.substring(0, w);
6746 // handle default prefixes, i.e. xs:String gracefully
6747 nsName = nsMatrix[nsName] || nsName;
6748 value = nsName + value.substring(w);
6749 } else {
6750 value = defaultAlias + ':' + value;
6751 }
6752 }
6753 // end: normalize xsi:type ns attribute value
6754
6755 attrs[name] = value;
6756 }
6757
6758
6759 // handle deferred, possibly namespaced attributes
6760 if (maybeNS) {
6761
6762 // normalize captured attributes
6763 for (i = 0, l = attrList.length; i < l; i++) {
6764
6765 name = attrList[i++];
6766 value = attrList[i];
6767
6768 w = name.indexOf(':');
6769
6770 if (w !== -1) {
6771 // normalize ns attribute name
6772 if (!(nsName = nsMatrix[name.substring(0, w)])) {
6773 handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
6774 continue;
6775 }
6776
6777 name = defaultAlias === nsName
6778 ? name.substr(w + 1)
6779 : nsName + name.substr(w);
6780 // end: normalize ns attribute name
6781
6782 // normalize xsi:type ns attribute value
6783 if (name === XSI_TYPE) {
6784 w = value.indexOf(':');
6785
6786 if (w !== -1) {
6787 nsName = value.substring(0, w);
6788 // handle default prefixes, i.e. xs:String gracefully
6789 nsName = nsMatrix[nsName] || nsName;
6790 value = nsName + value.substring(w);
6791 } else {
6792 value = defaultAlias + ':' + value;
6793 }
6794 }
6795 // end: normalize xsi:type ns attribute value
6796 }
6797
6798 attrs[name] = value;
6799 }
6800 // end: normalize captured attributes
6801 }
6802
6803 return cachedAttrs = attrs;
6804 }
6805
6806 /**
6807 * Extract the parse context { line, column, part }
6808 * from the current parser position.
6809 *
6810 * @return {Object} parse context
6811 */
6812 function getParseContext() {
6813 var splitsRe = /(\r\n|\r|\n)/g;
6814
6815 var line = 0;
6816 var column = 0;
6817 var startOfLine = 0;
6818 var endOfLine = j;
6819 var match;
6820 var data;
6821
6822 while (i >= startOfLine) {
6823
6824 match = splitsRe.exec(xml);
6825
6826 if (!match) {
6827 break;
6828 }
6829
6830 // end of line = (break idx + break chars)
6831 endOfLine = match[0].length + match.index;
6832
6833 if (endOfLine > i) {
6834 break;
6835 }
6836
6837 // advance to next line
6838 line += 1;
6839
6840 startOfLine = endOfLine;
6841 }
6842
6843 // EOF errors
6844 if (i == -1) {
6845 column = endOfLine;
6846 data = xml.substring(j);
6847 } else
6848 // start errors
6849 if (j === 0) {
6850 console.log(i - startOfLine);
6851 data = xml.substring(j, i);
6852 }
6853 // other errors
6854 else {
6855 column = i - startOfLine;
6856 data = (j == -1 ? xml.substring(i) : xml.substring(i, j + 1));
6857 }
6858
6859 return {
6860 'data': data,
6861 'line': line,
6862 'column': column
6863 };
6864 }
6865
6866 getContext = getParseContext;
6867
6868
6869 if (proxy) {
6870 elementProxy = Object.create({}, {
6871 'name': getter(function() {
6872 return elementName;
6873 }),
6874 'originalName': getter(function() {
6875 return _elementName;
6876 }),
6877 'attrs': getter(getAttrs),
6878 'ns': getter(function() {
6879 return nsMatrix;
6880 })
6881 });
6882 }
6883
6884 // actual parse logic
6885 while (j !== -1) {
6886
6887 if (xml.charCodeAt(j) === 60) { // "<"
6888 i = j;
6889 } else {
6890 i = xml.indexOf('<', j);
6891 }
6892
6893 // parse end
6894 if (i === -1) {
6895 if (nodeStack.length) {
6896 return handleError('unexpected end of file');
6897 }
6898
6899 if (j === 0) {
6900 return handleError('missing start tag');
6901 }
6902
6903 if (j < xml.length) {
6904 if (xml.substring(j).trim()) {
6905 handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
6906 }
6907 }
6908
6909 return;
6910 }
6911
6912 // parse text
6913 if (j !== i) {
6914
6915 if (nodeStack.length) {
6916 if (onText) {
6917 onText(xml.substring(j, i), decodeEntities, getContext);
6918
6919 if (parseStop) {
6920 return;
6921 }
6922 }
6923 } else {
6924 if (xml.substring(j, i).trim()) {
6925 handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
6926
6927 if (parseStop) {
6928 return;
6929 }
6930 }
6931 }
6932 }
6933
6934 w = xml.charCodeAt(i+1);
6935
6936 // parse comments + CDATA
6937 if (w === 33) { // "!"
6938 w = xml.charCodeAt(i+2);
6939 if (w === 91 && xml.substr(i + 3, 6) === 'CDATA[') { // 91 == "["
6940 j = xml.indexOf(']]>', i);
6941 if (j === -1) {
6942 return handleError('unclosed cdata');
6943 }
6944
6945 if (onCDATA) {
6946 onCDATA(xml.substring(i + 9, j), getContext);
6947 if (parseStop) {
6948 return;
6949 }
6950 }
6951
6952 j += 3;
6953 continue;
6954 }
6955
6956
6957 if (w === 45 && xml.charCodeAt(i + 3) === 45) { // 45 == "-"
6958 j = xml.indexOf('-->', i);
6959 if (j === -1) {
6960 return handleError('unclosed comment');
6961 }
6962
6963
6964 if (onComment) {
6965 onComment(xml.substring(i + 4, j), decodeEntities, getContext);
6966 if (parseStop) {
6967 return;
6968 }
6969 }
6970
6971 j += 3;
6972 continue;
6973 }
6974
6975 j = xml.indexOf('>', i + 1);
6976 if (j === -1) {
6977 return handleError('unclosed tag');
6978 }
6979
6980 if (onAttention) {
6981 onAttention(xml.substring(i, j + 1), decodeEntities, getContext);
6982 if (parseStop) {
6983 return;
6984 }
6985 }
6986
6987 j += 1;
6988 continue;
6989 }
6990
6991 if (w === 63) { // "?"
6992 j = xml.indexOf('?>', i);
6993 if (j === -1) {
6994 return handleError('unclosed question');
6995 }
6996
6997 if (onQuestion) {
6998 onQuestion(xml.substring(i, j + 2), getContext);
6999 if (parseStop) {
7000 return;
7001 }
7002 }
7003
7004 j += 2;
7005 continue;
7006 }
7007
7008 j = xml.indexOf('>', i + 1);
7009
7010 if (j == -1) {
7011 return handleError('unclosed tag');
7012 }
7013
7014 // don't process attributes;
7015 // there are none
7016 cachedAttrs = {};
7017
7018 // if (xml.charCodeAt(i+1) === 47) { // </...
7019 if (w === 47) { // </...
7020 tagStart = false;
7021 tagEnd = true;
7022
7023 if (!nodeStack.length) {
7024 return handleError('missing open tag');
7025 }
7026
7027 // verify open <-> close tag match
7028 x = elementName = nodeStack.pop();
7029 q = i + 2 + x.length;
7030
7031 if (xml.substring(i + 2, q) !== x) {
7032 return handleError('closing tag mismatch');
7033 }
7034
7035 // verify chars in close tag
7036 for (; q < j; q++) {
7037 w = xml.charCodeAt(q);
7038
7039 if (w === 32 || (w > 8 && w < 14)) { // \f\n\r\t\v space
7040 continue;
7041 }
7042
7043 return handleError('close tag');
7044 }
7045
7046 } else {
7047 if (xml.charCodeAt(j - 1) === 47) { // .../>
7048 x = elementName = xml.substring(i + 1, j - 1);
7049
7050 tagStart = true;
7051 tagEnd = true;
7052
7053 } else {
7054 x = elementName = xml.substring(i + 1, j);
7055
7056 tagStart = true;
7057 tagEnd = false;
7058 }
7059
7060 if (!(w > 96 && w < 123 || w > 64 && w < 91 || w === 95 || w === 58)) { // char 95"_" 58":"
7061 return handleError('illegal first char nodeName');
7062 }
7063
7064 for (q = 1, y = x.length; q < y; q++) {
7065 w = x.charCodeAt(q);
7066
7067 if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w == 46) {
7068 continue;
7069 }
7070
7071 if (w === 32 || (w < 14 && w > 8)) { // \f\n\r\t\v space
7072 elementName = x.substring(0, q);
7073 // maybe there are attributes
7074 cachedAttrs = null;
7075 break;
7076 }
7077
7078 return handleError('invalid nodeName');
7079 }
7080
7081 if (!tagEnd) {
7082 nodeStack.push(elementName);
7083 }
7084 }
7085
7086 if (isNamespace) {
7087
7088 _nsMatrix = nsMatrix;
7089
7090 if (tagStart) {
7091 // remember old namespace
7092 // unless we're self-closing
7093 if (!tagEnd) {
7094 nsMatrixStack.push(_nsMatrix);
7095 }
7096
7097 if (cachedAttrs === null) {
7098 // quick check, whether there may be namespace
7099 // declarations on the node; if that is the case
7100 // we need to eagerly parse the node attributes
7101 if ((maybeNS = x.indexOf('xmlns', q) !== -1)) {
7102 attrsStart = q;
7103 attrsString = x;
7104
7105 getAttrs();
7106
7107 maybeNS = false;
7108 }
7109 }
7110 }
7111
7112 _elementName = elementName;
7113
7114 w = elementName.indexOf(':');
7115 if (w !== -1) {
7116 xmlns = nsMatrix[elementName.substring(0, w)];
7117
7118 // prefix given; namespace must exist
7119 if (!xmlns) {
7120 return handleError('missing namespace on <' + _elementName + '>');
7121 }
7122
7123 elementName = elementName.substr(w + 1);
7124 } else {
7125 xmlns = nsMatrix['xmlns'];
7126
7127 // if no default namespace is defined,
7128 // we'll import the element as anonymous.
7129 //
7130 // it is up to users to correct that to the document defined
7131 // targetNamespace, or whatever their undersanding of the
7132 // XML spec mandates.
7133 }
7134
7135 // adjust namespace prefixs as configured
7136 if (xmlns) {
7137 elementName = xmlns + ':' + elementName;
7138 }
7139
7140 }
7141
7142 if (tagStart) {
7143 attrsStart = q;
7144 attrsString = x;
7145
7146 if (onOpenTag) {
7147 if (proxy) {
7148 onOpenTag(elementProxy, decodeEntities, tagEnd, getContext);
7149 } else {
7150 onOpenTag(elementName, getAttrs, decodeEntities, tagEnd, getContext);
7151 }
7152
7153 if (parseStop) {
7154 return;
7155 }
7156 }
7157
7158 }
7159
7160 if (tagEnd) {
7161
7162 if (onCloseTag) {
7163 onCloseTag(proxy ? elementProxy : elementName, decodeEntities, tagStart, getContext);
7164
7165 if (parseStop) {
7166 return;
7167 }
7168 }
7169
7170 // restore old namespace
7171 if (isNamespace) {
7172 if (!tagStart) {
7173 nsMatrix = nsMatrixStack.pop();
7174 } else {
7175 nsMatrix = _nsMatrix;
7176 }
7177 }
7178 }
7179
7180 j += 1;
7181 }
7182 } /** end parse */
7183
7184 }
7185
7186 function hasLowerCaseAlias(pkg) {
7187 return pkg.xml && pkg.xml.tagAlias === 'lowerCase';
7188 }
7189
7190 var DEFAULT_NS_MAP = {
7191 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'
7192 };
7193
7194 var XSI_TYPE$1 = 'xsi:type';
7195
7196 function serializeFormat(element) {
7197 return element.xml && element.xml.serialize;
7198 }
7199
7200 function serializeAsType(element) {
7201 return serializeFormat(element) === XSI_TYPE$1;
7202 }
7203
7204 function serializeAsProperty(element) {
7205 return serializeFormat(element) === 'property';
7206 }
7207
7208 function capitalize(str) {
7209 return str.charAt(0).toUpperCase() + str.slice(1);
7210 }
7211
7212 function aliasToName(aliasNs, pkg) {
7213
7214 if (!hasLowerCaseAlias(pkg)) {
7215 return aliasNs.name;
7216 }
7217
7218 return aliasNs.prefix + ':' + capitalize(aliasNs.localName);
7219 }
7220
7221 function prefixedToName(nameNs, pkg) {
7222
7223 var name = nameNs.name,
7224 localName = nameNs.localName;
7225
7226 var typePrefix = pkg.xml && pkg.xml.typePrefix;
7227
7228 if (typePrefix && localName.indexOf(typePrefix) === 0) {
7229 return nameNs.prefix + ':' + localName.slice(typePrefix.length);
7230 } else {
7231 return name;
7232 }
7233 }
7234
7235 function normalizeXsiTypeName(name, model) {
7236
7237 var nameNs = parseName(name);
7238 var pkg = model.getPackage(nameNs.prefix);
7239
7240 return prefixedToName(nameNs, pkg);
7241 }
7242
7243 function error$1(message) {
7244 return new Error(message);
7245 }
7246
7247 /**
7248 * Get the moddle descriptor for a given instance or type.
7249 *
7250 * @param {ModdleElement|Function} element
7251 *
7252 * @return {Object} the moddle descriptor
7253 */
7254 function getModdleDescriptor(element) {
7255 return element.$descriptor;
7256 }
7257
7258 function defer(fn) {
7259 setTimeout(fn, 0);
7260 }
7261
7262 /**
7263 * A parse context.
7264 *
7265 * @class
7266 *
7267 * @param {Object} options
7268 * @param {ElementHandler} options.rootHandler the root handler for parsing a document
7269 * @param {boolean} [options.lax=false] whether or not to ignore invalid elements
7270 */
7271 function Context(options) {
7272
7273 /**
7274 * @property {ElementHandler} rootHandler
7275 */
7276
7277 /**
7278 * @property {Boolean} lax
7279 */
7280
7281 assign(this, options);
7282
7283 this.elementsById = {};
7284 this.references = [];
7285 this.warnings = [];
7286
7287 /**
7288 * Add an unresolved reference.
7289 *
7290 * @param {Object} reference
7291 */
7292 this.addReference = function(reference) {
7293 this.references.push(reference);
7294 };
7295
7296 /**
7297 * Add a processed element.
7298 *
7299 * @param {ModdleElement} element
7300 */
7301 this.addElement = function(element) {
7302
7303 if (!element) {
7304 throw error$1('expected element');
7305 }
7306
7307 var elementsById = this.elementsById;
7308
7309 var descriptor = getModdleDescriptor(element);
7310
7311 var idProperty = descriptor.idProperty,
7312 id;
7313
7314 if (idProperty) {
7315 id = element.get(idProperty.name);
7316
7317 if (id) {
7318 // for QName validation as per http://www.w3.org/TR/REC-xml/#NT-NameChar
7319 if (!/^([a-z][\w-.]*:)?[a-z_][\w-.]*$/i.test(id)) {
7320 throw new Error('illegal ID <' + id + '>');
7321 }
7322
7323 if (elementsById[id]) {
7324 throw error$1('duplicate ID <' + id + '>');
7325 }
7326
7327 elementsById[id] = element;
7328 }
7329 }
7330 };
7331
7332 /**
7333 * Add an import warning.
7334 *
7335 * @param {Object} warning
7336 * @param {String} warning.message
7337 * @param {Error} [warning.error]
7338 */
7339 this.addWarning = function(warning) {
7340 this.warnings.push(warning);
7341 };
7342 }
7343
7344 function BaseHandler() {}
7345
7346 BaseHandler.prototype.handleEnd = function() {};
7347 BaseHandler.prototype.handleText = function() {};
7348 BaseHandler.prototype.handleNode = function() {};
7349
7350
7351 /**
7352 * A simple pass through handler that does nothing except for
7353 * ignoring all input it receives.
7354 *
7355 * This is used to ignore unknown elements and
7356 * attributes.
7357 */
7358 function NoopHandler() { }
7359
7360 NoopHandler.prototype = Object.create(BaseHandler.prototype);
7361
7362 NoopHandler.prototype.handleNode = function() {
7363 return this;
7364 };
7365
7366 function BodyHandler() {}
7367
7368 BodyHandler.prototype = Object.create(BaseHandler.prototype);
7369
7370 BodyHandler.prototype.handleText = function(text) {
7371 this.body = (this.body || '') + text;
7372 };
7373
7374 function ReferenceHandler(property, context) {
7375 this.property = property;
7376 this.context = context;
7377 }
7378
7379 ReferenceHandler.prototype = Object.create(BodyHandler.prototype);
7380
7381 ReferenceHandler.prototype.handleNode = function(node) {
7382
7383 if (this.element) {
7384 throw error$1('expected no sub nodes');
7385 } else {
7386 this.element = this.createReference(node);
7387 }
7388
7389 return this;
7390 };
7391
7392 ReferenceHandler.prototype.handleEnd = function() {
7393 this.element.id = this.body;
7394 };
7395
7396 ReferenceHandler.prototype.createReference = function(node) {
7397 return {
7398 property: this.property.ns.name,
7399 id: ''
7400 };
7401 };
7402
7403 function ValueHandler(propertyDesc, element) {
7404 this.element = element;
7405 this.propertyDesc = propertyDesc;
7406 }
7407
7408 ValueHandler.prototype = Object.create(BodyHandler.prototype);
7409
7410 ValueHandler.prototype.handleEnd = function() {
7411
7412 var value = this.body || '',
7413 element = this.element,
7414 propertyDesc = this.propertyDesc;
7415
7416 value = coerceType(propertyDesc.type, value);
7417
7418 if (propertyDesc.isMany) {
7419 element.get(propertyDesc.name).push(value);
7420 } else {
7421 element.set(propertyDesc.name, value);
7422 }
7423 };
7424
7425
7426 function BaseElementHandler() {}
7427
7428 BaseElementHandler.prototype = Object.create(BodyHandler.prototype);
7429
7430 BaseElementHandler.prototype.handleNode = function(node) {
7431 var parser = this,
7432 element = this.element;
7433
7434 if (!element) {
7435 element = this.element = this.createElement(node);
7436
7437 this.context.addElement(element);
7438 } else {
7439 parser = this.handleChild(node);
7440 }
7441
7442 return parser;
7443 };
7444
7445 /**
7446 * @class Reader.ElementHandler
7447 *
7448 */
7449 function ElementHandler(model, typeName, context) {
7450 this.model = model;
7451 this.type = model.getType(typeName);
7452 this.context = context;
7453 }
7454
7455 ElementHandler.prototype = Object.create(BaseElementHandler.prototype);
7456
7457 ElementHandler.prototype.addReference = function(reference) {
7458 this.context.addReference(reference);
7459 };
7460
7461 ElementHandler.prototype.handleText = function(text) {
7462
7463 var element = this.element,
7464 descriptor = getModdleDescriptor(element),
7465 bodyProperty = descriptor.bodyProperty;
7466
7467 if (!bodyProperty) {
7468 throw error$1('unexpected body text <' + text + '>');
7469 }
7470
7471 BodyHandler.prototype.handleText.call(this, text);
7472 };
7473
7474 ElementHandler.prototype.handleEnd = function() {
7475
7476 var value = this.body,
7477 element = this.element,
7478 descriptor = getModdleDescriptor(element),
7479 bodyProperty = descriptor.bodyProperty;
7480
7481 if (bodyProperty && value !== undefined) {
7482 value = coerceType(bodyProperty.type, value);
7483 element.set(bodyProperty.name, value);
7484 }
7485 };
7486
7487 /**
7488 * Create an instance of the model from the given node.
7489 *
7490 * @param {Element} node the xml node
7491 */
7492 ElementHandler.prototype.createElement = function(node) {
7493 var attributes = node.attributes,
7494 Type = this.type,
7495 descriptor = getModdleDescriptor(Type),
7496 context = this.context,
7497 instance = new Type({}),
7498 model = this.model,
7499 propNameNs;
7500
7501 forEach(attributes, function(value, name) {
7502
7503 var prop = descriptor.propertiesByName[name],
7504 values;
7505
7506 if (prop && prop.isReference) {
7507
7508 if (!prop.isMany) {
7509 context.addReference({
7510 element: instance,
7511 property: prop.ns.name,
7512 id: value
7513 });
7514 } else {
7515 // IDREFS: parse references as whitespace-separated list
7516 values = value.split(' ');
7517
7518 forEach(values, function(v) {
7519 context.addReference({
7520 element: instance,
7521 property: prop.ns.name,
7522 id: v
7523 });
7524 });
7525 }
7526
7527 } else {
7528 if (prop) {
7529 value = coerceType(prop.type, value);
7530 } else
7531 if (name !== 'xmlns') {
7532 propNameNs = parseName(name, descriptor.ns.prefix);
7533
7534 // check whether attribute is defined in a well-known namespace
7535 // if that is the case we emit a warning to indicate potential misuse
7536 if (model.getPackage(propNameNs.prefix)) {
7537
7538 context.addWarning({
7539 message: 'unknown attribute <' + name + '>',
7540 element: instance,
7541 property: name,
7542 value: value
7543 });
7544 }
7545 }
7546
7547 instance.set(name, value);
7548 }
7549 });
7550
7551 return instance;
7552 };
7553
7554 ElementHandler.prototype.getPropertyForNode = function(node) {
7555
7556 var name = node.name;
7557 var nameNs = parseName(name);
7558
7559 var type = this.type,
7560 model = this.model,
7561 descriptor = getModdleDescriptor(type);
7562
7563 var propertyName = nameNs.name,
7564 property = descriptor.propertiesByName[propertyName],
7565 elementTypeName,
7566 elementType;
7567
7568 // search for properties by name first
7569
7570 if (property) {
7571
7572 if (serializeAsType(property)) {
7573 elementTypeName = node.attributes[XSI_TYPE$1];
7574
7575 // xsi type is optional, if it does not exists the
7576 // default type is assumed
7577 if (elementTypeName) {
7578
7579 // take possible type prefixes from XML
7580 // into account, i.e.: xsi:type="t{ActualType}"
7581 elementTypeName = normalizeXsiTypeName(elementTypeName, model);
7582
7583 elementType = model.getType(elementTypeName);
7584
7585 return assign({}, property, {
7586 effectiveType: getModdleDescriptor(elementType).name
7587 });
7588 }
7589 }
7590
7591 // search for properties by name first
7592 return property;
7593 }
7594
7595 var pkg = model.getPackage(nameNs.prefix);
7596
7597 if (pkg) {
7598 elementTypeName = aliasToName(nameNs, pkg);
7599 elementType = model.getType(elementTypeName);
7600
7601 // search for collection members later
7602 property = find(descriptor.properties, function(p) {
7603 return !p.isVirtual && !p.isReference && !p.isAttribute && elementType.hasType(p.type);
7604 });
7605
7606 if (property) {
7607 return assign({}, property, {
7608 effectiveType: getModdleDescriptor(elementType).name
7609 });
7610 }
7611 } else {
7612 // parse unknown element (maybe extension)
7613 property = find(descriptor.properties, function(p) {
7614 return !p.isReference && !p.isAttribute && p.type === 'Element';
7615 });
7616
7617 if (property) {
7618 return property;
7619 }
7620 }
7621
7622 throw error$1('unrecognized element <' + nameNs.name + '>');
7623 };
7624
7625 ElementHandler.prototype.toString = function() {
7626 return 'ElementDescriptor[' + getModdleDescriptor(this.type).name + ']';
7627 };
7628
7629 ElementHandler.prototype.valueHandler = function(propertyDesc, element) {
7630 return new ValueHandler(propertyDesc, element);
7631 };
7632
7633 ElementHandler.prototype.referenceHandler = function(propertyDesc) {
7634 return new ReferenceHandler(propertyDesc, this.context);
7635 };
7636
7637 ElementHandler.prototype.handler = function(type) {
7638 if (type === 'Element') {
7639 return new GenericElementHandler(this.model, type, this.context);
7640 } else {
7641 return new ElementHandler(this.model, type, this.context);
7642 }
7643 };
7644
7645 /**
7646 * Handle the child element parsing
7647 *
7648 * @param {Element} node the xml node
7649 */
7650 ElementHandler.prototype.handleChild = function(node) {
7651 var propertyDesc, type, element, childHandler;
7652
7653 propertyDesc = this.getPropertyForNode(node);
7654 element = this.element;
7655
7656 type = propertyDesc.effectiveType || propertyDesc.type;
7657
7658 if (isSimple(type)) {
7659 return this.valueHandler(propertyDesc, element);
7660 }
7661
7662 if (propertyDesc.isReference) {
7663 childHandler = this.referenceHandler(propertyDesc).handleNode(node);
7664 } else {
7665 childHandler = this.handler(type).handleNode(node);
7666 }
7667
7668 var newElement = childHandler.element;
7669
7670 // child handles may decide to skip elements
7671 // by not returning anything
7672 if (newElement !== undefined) {
7673
7674 if (propertyDesc.isMany) {
7675 element.get(propertyDesc.name).push(newElement);
7676 } else {
7677 element.set(propertyDesc.name, newElement);
7678 }
7679
7680 if (propertyDesc.isReference) {
7681 assign(newElement, {
7682 element: element
7683 });
7684
7685 this.context.addReference(newElement);
7686 } else {
7687 // establish child -> parent relationship
7688 newElement.$parent = element;
7689 }
7690 }
7691
7692 return childHandler;
7693 };
7694
7695 /**
7696 * An element handler that performs special validation
7697 * to ensure the node it gets initialized with matches
7698 * the handlers type (namespace wise).
7699 *
7700 * @param {Moddle} model
7701 * @param {String} typeName
7702 * @param {Context} context
7703 */
7704 function RootElementHandler(model, typeName, context) {
7705 ElementHandler.call(this, model, typeName, context);
7706 }
7707
7708 RootElementHandler.prototype = Object.create(ElementHandler.prototype);
7709
7710 RootElementHandler.prototype.createElement = function(node) {
7711
7712 var name = node.name,
7713 nameNs = parseName(name),
7714 model = this.model,
7715 type = this.type,
7716 pkg = model.getPackage(nameNs.prefix),
7717 typeName = pkg && aliasToName(nameNs, pkg) || name;
7718
7719 // verify the correct namespace if we parse
7720 // the first element in the handler tree
7721 //
7722 // this ensures we don't mistakenly import wrong namespace elements
7723 if (!type.hasType(typeName)) {
7724 throw error$1('unexpected element <' + node.originalName + '>');
7725 }
7726
7727 return ElementHandler.prototype.createElement.call(this, node);
7728 };
7729
7730
7731 function GenericElementHandler(model, typeName, context) {
7732 this.model = model;
7733 this.context = context;
7734 }
7735
7736 GenericElementHandler.prototype = Object.create(BaseElementHandler.prototype);
7737
7738 GenericElementHandler.prototype.createElement = function(node) {
7739
7740 var name = node.name,
7741 ns = parseName(name),
7742 prefix = ns.prefix,
7743 uri = node.ns[prefix + '$uri'],
7744 attributes = node.attributes;
7745
7746 return this.model.createAny(name, uri, attributes);
7747 };
7748
7749 GenericElementHandler.prototype.handleChild = function(node) {
7750
7751 var handler = new GenericElementHandler(this.model, 'Element', this.context).handleNode(node),
7752 element = this.element;
7753
7754 var newElement = handler.element,
7755 children;
7756
7757 if (newElement !== undefined) {
7758 children = element.$children = element.$children || [];
7759 children.push(newElement);
7760
7761 // establish child -> parent relationship
7762 newElement.$parent = element;
7763 }
7764
7765 return handler;
7766 };
7767
7768 GenericElementHandler.prototype.handleEnd = function() {
7769 if (this.body) {
7770 this.element.$body = this.body;
7771 }
7772 };
7773
7774 /**
7775 * A reader for a meta-model
7776 *
7777 * @param {Object} options
7778 * @param {Model} options.model used to read xml files
7779 * @param {Boolean} options.lax whether to make parse errors warnings
7780 */
7781 function Reader(options) {
7782
7783 if (options instanceof Moddle) {
7784 options = {
7785 model: options
7786 };
7787 }
7788
7789 assign(this, { lax: false }, options);
7790 }
7791
7792
7793 /**
7794 * Parse the given XML into a moddle document tree.
7795 *
7796 * @param {String} xml
7797 * @param {ElementHandler|Object} options or rootHandler
7798 * @param {Function} done
7799 */
7800 Reader.prototype.fromXML = function(xml, options, done) {
7801
7802 var rootHandler = options.rootHandler;
7803
7804 if (options instanceof ElementHandler) {
7805 // root handler passed via (xml, { rootHandler: ElementHandler }, ...)
7806 rootHandler = options;
7807 options = {};
7808 } else {
7809 if (typeof options === 'string') {
7810 // rootHandler passed via (xml, 'someString', ...)
7811 rootHandler = this.handler(options);
7812 options = {};
7813 } else if (typeof rootHandler === 'string') {
7814 // rootHandler passed via (xml, { rootHandler: 'someString' }, ...)
7815 rootHandler = this.handler(rootHandler);
7816 }
7817 }
7818
7819 var model = this.model,
7820 lax = this.lax;
7821
7822 var context = new Context(assign({}, options, { rootHandler: rootHandler })),
7823 parser = new Parser({ proxy: true }),
7824 stack = createStack();
7825
7826 rootHandler.context = context;
7827
7828 // push root handler
7829 stack.push(rootHandler);
7830
7831
7832 /**
7833 * Handle error.
7834 *
7835 * @param {Error} err
7836 * @param {Function} getContext
7837 * @param {boolean} lax
7838 *
7839 * @return {boolean} true if handled
7840 */
7841 function handleError(err, getContext, lax) {
7842
7843 var ctx = getContext();
7844
7845 var line = ctx.line,
7846 column = ctx.column,
7847 data = ctx.data;
7848
7849 // we receive the full context data here,
7850 // for elements trim down the information
7851 // to the tag name, only
7852 if (data.charAt(0) === '<' && data.indexOf(' ') !== -1) {
7853 data = data.slice(0, data.indexOf(' ')) + '>';
7854 }
7855
7856 var message =
7857 'unparsable content ' + (data ? data + ' ' : '') + 'detected\n\t' +
7858 'line: ' + line + '\n\t' +
7859 'column: ' + column + '\n\t' +
7860 'nested error: ' + err.message;
7861
7862 if (lax) {
7863 context.addWarning({
7864 message: message,
7865 error: err
7866 });
7867
7868 return true;
7869 } else {
7870 throw error$1(message);
7871 }
7872 }
7873
7874 function handleWarning(err, getContext) {
7875 // just like handling errors in <lax=true> mode
7876 return handleError(err, getContext, true);
7877 }
7878
7879 /**
7880 * Resolve collected references on parse end.
7881 */
7882 function resolveReferences() {
7883
7884 var elementsById = context.elementsById;
7885 var references = context.references;
7886
7887 var i, r;
7888
7889 for (i = 0; (r = references[i]); i++) {
7890 var element = r.element;
7891 var reference = elementsById[r.id];
7892 var property = getModdleDescriptor(element).propertiesByName[r.property];
7893
7894 if (!reference) {
7895 context.addWarning({
7896 message: 'unresolved reference <' + r.id + '>',
7897 element: r.element,
7898 property: r.property,
7899 value: r.id
7900 });
7901 }
7902
7903 if (property.isMany) {
7904 var collection = element.get(property.name),
7905 idx = collection.indexOf(r);
7906
7907 // we replace an existing place holder (idx != -1) or
7908 // append to the collection instead
7909 if (idx === -1) {
7910 idx = collection.length;
7911 }
7912
7913 if (!reference) {
7914 // remove unresolvable reference
7915 collection.splice(idx, 1);
7916 } else {
7917 // add or update reference in collection
7918 collection[idx] = reference;
7919 }
7920 } else {
7921 element.set(property.name, reference);
7922 }
7923 }
7924 }
7925
7926 function handleClose() {
7927 stack.pop().handleEnd();
7928 }
7929
7930 var PREAMBLE_START_PATTERN = /^<\?xml /i;
7931
7932 var ENCODING_PATTERN = / encoding="([^"]+)"/i;
7933
7934 var UTF_8_PATTERN = /^utf-8$/i;
7935
7936 function handleQuestion(question) {
7937
7938 if (!PREAMBLE_START_PATTERN.test(question)) {
7939 return;
7940 }
7941
7942 var match = ENCODING_PATTERN.exec(question);
7943 var encoding = match && match[1];
7944
7945 if (!encoding || UTF_8_PATTERN.test(encoding)) {
7946 return;
7947 }
7948
7949 context.addWarning({
7950 message:
7951 'unsupported document encoding <' + encoding + '>, ' +
7952 'falling back to UTF-8'
7953 });
7954 }
7955
7956 function handleOpen(node, getContext) {
7957 var handler = stack.peek();
7958
7959 try {
7960 stack.push(handler.handleNode(node));
7961 } catch (err) {
7962
7963 if (handleError(err, getContext, lax)) {
7964 stack.push(new NoopHandler());
7965 }
7966 }
7967 }
7968
7969 function handleCData(text, getContext) {
7970
7971 try {
7972 stack.peek().handleText(text);
7973 } catch (err) {
7974 handleWarning(err, getContext);
7975 }
7976 }
7977
7978 function handleText(text, getContext) {
7979 // strip whitespace only nodes, i.e. before
7980 // <!CDATA[ ... ]> sections and in between tags
7981 text = text.trim();
7982
7983 if (!text) {
7984 return;
7985 }
7986
7987 handleCData(text, getContext);
7988 }
7989
7990 var uriMap = model.getPackages().reduce(function(uriMap, p) {
7991 uriMap[p.uri] = p.prefix;
7992
7993 return uriMap;
7994 }, {});
7995
7996 parser
7997 .ns(uriMap)
7998 .on('openTag', function(obj, decodeStr, selfClosing, getContext) {
7999
8000 // gracefully handle unparsable attributes (attrs=false)
8001 var attrs = obj.attrs || {};
8002
8003 var decodedAttrs = Object.keys(attrs).reduce(function(d, key) {
8004 var value = decodeStr(attrs[key]);
8005
8006 d[key] = value;
8007
8008 return d;
8009 }, {});
8010
8011 var node = {
8012 name: obj.name,
8013 originalName: obj.originalName,
8014 attributes: decodedAttrs,
8015 ns: obj.ns
8016 };
8017
8018 handleOpen(node, getContext);
8019 })
8020 .on('question', handleQuestion)
8021 .on('closeTag', handleClose)
8022 .on('cdata', handleCData)
8023 .on('text', function(text, decodeEntities, getContext) {
8024 handleText(decodeEntities(text), getContext);
8025 })
8026 .on('error', handleError)
8027 .on('warn', handleWarning);
8028
8029 // deferred parse XML to make loading really ascnchronous
8030 // this ensures the execution environment (node or browser)
8031 // is kept responsive and that certain optimization strategies
8032 // can kick in
8033 defer(function() {
8034 var err;
8035
8036 try {
8037 parser.parse(xml);
8038
8039 resolveReferences();
8040 } catch (e) {
8041 err = e;
8042 }
8043
8044 var element = rootHandler.element;
8045
8046 // handle the situation that we could not extract
8047 // the desired root element from the document
8048 if (!err && !element) {
8049 err = error$1('failed to parse document as <' + rootHandler.type.$descriptor.name + '>');
8050 }
8051
8052 done(err, err ? undefined : element, context);
8053 });
8054 };
8055
8056 Reader.prototype.handler = function(name) {
8057 return new RootElementHandler(this.model, name);
8058 };
8059
8060
8061 // helpers //////////////////////////
8062
8063 function createStack() {
8064 var stack = [];
8065
8066 Object.defineProperty(stack, 'peek', {
8067 value: function() {
8068 return this[this.length - 1];
8069 }
8070 });
8071
8072 return stack;
8073 }
8074
8075 var XML_PREAMBLE = '<?xml version="1.0" encoding="UTF-8"?>\n';
8076
8077 var ESCAPE_ATTR_CHARS = /<|>|'|"|&|\n\r|\n/g;
8078 var ESCAPE_CHARS = /<|>|&/g;
8079
8080
8081 function Namespaces(parent) {
8082
8083 var prefixMap = {};
8084 var uriMap = {};
8085 var used = {};
8086
8087 var wellknown = [];
8088 var custom = [];
8089
8090 // API
8091
8092 this.byUri = function(uri) {
8093 return uriMap[uri] || (
8094 parent && parent.byUri(uri)
8095 );
8096 };
8097
8098 this.add = function(ns, isWellknown) {
8099
8100 uriMap[ns.uri] = ns;
8101
8102 if (isWellknown) {
8103 wellknown.push(ns);
8104 } else {
8105 custom.push(ns);
8106 }
8107
8108 this.mapPrefix(ns.prefix, ns.uri);
8109 };
8110
8111 this.uriByPrefix = function(prefix) {
8112 return prefixMap[prefix || 'xmlns'];
8113 };
8114
8115 this.mapPrefix = function(prefix, uri) {
8116 prefixMap[prefix || 'xmlns'] = uri;
8117 };
8118
8119 this.logUsed = function(ns) {
8120 var uri = ns.uri;
8121
8122 used[uri] = this.byUri(uri);
8123 };
8124
8125 this.getUsed = function(ns) {
8126
8127 function isUsed(ns) {
8128 return used[ns.uri];
8129 }
8130
8131 var allNs = [].concat(wellknown, custom);
8132
8133 return allNs.filter(isUsed);
8134 };
8135
8136 }
8137
8138 function lower(string) {
8139 return string.charAt(0).toLowerCase() + string.slice(1);
8140 }
8141
8142 function nameToAlias(name, pkg) {
8143 if (hasLowerCaseAlias(pkg)) {
8144 return lower(name);
8145 } else {
8146 return name;
8147 }
8148 }
8149
8150 function inherits(ctor, superCtor) {
8151 ctor.super_ = superCtor;
8152 ctor.prototype = Object.create(superCtor.prototype, {
8153 constructor: {
8154 value: ctor,
8155 enumerable: false,
8156 writable: true,
8157 configurable: true
8158 }
8159 });
8160 }
8161
8162 function nsName(ns) {
8163 if (isString(ns)) {
8164 return ns;
8165 } else {
8166 return (ns.prefix ? ns.prefix + ':' : '') + ns.localName;
8167 }
8168 }
8169
8170 function getNsAttrs(namespaces) {
8171
8172 return map(namespaces.getUsed(), function(ns) {
8173 var name = 'xmlns' + (ns.prefix ? ':' + ns.prefix : '');
8174 return { name: name, value: ns.uri };
8175 });
8176
8177 }
8178
8179 function getElementNs(ns, descriptor) {
8180 if (descriptor.isGeneric) {
8181 return assign({ localName: descriptor.ns.localName }, ns);
8182 } else {
8183 return assign({ localName: nameToAlias(descriptor.ns.localName, descriptor.$pkg) }, ns);
8184 }
8185 }
8186
8187 function getPropertyNs(ns, descriptor) {
8188 return assign({ localName: descriptor.ns.localName }, ns);
8189 }
8190
8191 function getSerializableProperties(element) {
8192 var descriptor = element.$descriptor;
8193
8194 return filter(descriptor.properties, function(p) {
8195 var name = p.name;
8196
8197 if (p.isVirtual) {
8198 return false;
8199 }
8200
8201 // do not serialize defaults
8202 if (!element.hasOwnProperty(name)) {
8203 return false;
8204 }
8205
8206 var value = element[name];
8207
8208 // do not serialize default equals
8209 if (value === p.default) {
8210 return false;
8211 }
8212
8213 // do not serialize null properties
8214 if (value === null) {
8215 return false;
8216 }
8217
8218 return p.isMany ? value.length : true;
8219 });
8220 }
8221
8222 var ESCAPE_ATTR_MAP = {
8223 '\n': '#10',
8224 '\n\r': '#10',
8225 '"': '#34',
8226 '\'': '#39',
8227 '<': '#60',
8228 '>': '#62',
8229 '&': '#38'
8230 };
8231
8232 var ESCAPE_MAP = {
8233 '<': 'lt',
8234 '>': 'gt',
8235 '&': 'amp'
8236 };
8237
8238 function escape$1(str, charPattern, replaceMap) {
8239
8240 // ensure we are handling strings here
8241 str = isString(str) ? str : '' + str;
8242
8243 return str.replace(charPattern, function(s) {
8244 return '&' + replaceMap[s] + ';';
8245 });
8246 }
8247
8248 /**
8249 * Escape a string attribute to not contain any bad values (line breaks, '"', ...)
8250 *
8251 * @param {String} str the string to escape
8252 * @return {String} the escaped string
8253 */
8254 function escapeAttr(str) {
8255 return escape$1(str, ESCAPE_ATTR_CHARS, ESCAPE_ATTR_MAP);
8256 }
8257
8258 function escapeBody(str) {
8259 return escape$1(str, ESCAPE_CHARS, ESCAPE_MAP);
8260 }
8261
8262 function filterAttributes(props) {
8263 return filter(props, function(p) { return p.isAttr; });
8264 }
8265
8266 function filterContained(props) {
8267 return filter(props, function(p) { return !p.isAttr; });
8268 }
8269
8270
8271 function ReferenceSerializer(tagName) {
8272 this.tagName = tagName;
8273 }
8274
8275 ReferenceSerializer.prototype.build = function(element) {
8276 this.element = element;
8277 return this;
8278 };
8279
8280 ReferenceSerializer.prototype.serializeTo = function(writer) {
8281 writer
8282 .appendIndent()
8283 .append('<' + this.tagName + '>' + this.element.id + '</' + this.tagName + '>')
8284 .appendNewLine();
8285 };
8286
8287 function BodySerializer() {}
8288
8289 BodySerializer.prototype.serializeValue =
8290 BodySerializer.prototype.serializeTo = function(writer) {
8291 writer.append(
8292 this.escape
8293 ? escapeBody(this.value)
8294 : this.value
8295 );
8296 };
8297
8298 BodySerializer.prototype.build = function(prop, value) {
8299 this.value = value;
8300
8301 if (prop.type === 'String' && value.search(ESCAPE_CHARS) !== -1) {
8302 this.escape = true;
8303 }
8304
8305 return this;
8306 };
8307
8308 function ValueSerializer(tagName) {
8309 this.tagName = tagName;
8310 }
8311
8312 inherits(ValueSerializer, BodySerializer);
8313
8314 ValueSerializer.prototype.serializeTo = function(writer) {
8315
8316 writer
8317 .appendIndent()
8318 .append('<' + this.tagName + '>');
8319
8320 this.serializeValue(writer);
8321
8322 writer
8323 .append('</' + this.tagName + '>')
8324 .appendNewLine();
8325 };
8326
8327 function ElementSerializer(parent, propertyDescriptor) {
8328 this.body = [];
8329 this.attrs = [];
8330
8331 this.parent = parent;
8332 this.propertyDescriptor = propertyDescriptor;
8333 }
8334
8335 ElementSerializer.prototype.build = function(element) {
8336 this.element = element;
8337
8338 var elementDescriptor = element.$descriptor,
8339 propertyDescriptor = this.propertyDescriptor;
8340
8341 var otherAttrs,
8342 properties;
8343
8344 var isGeneric = elementDescriptor.isGeneric;
8345
8346 if (isGeneric) {
8347 otherAttrs = this.parseGeneric(element);
8348 } else {
8349 otherAttrs = this.parseNsAttributes(element);
8350 }
8351
8352 if (propertyDescriptor) {
8353 this.ns = this.nsPropertyTagName(propertyDescriptor);
8354 } else {
8355 this.ns = this.nsTagName(elementDescriptor);
8356 }
8357
8358 // compute tag name
8359 this.tagName = this.addTagName(this.ns);
8360
8361 if (!isGeneric) {
8362 properties = getSerializableProperties(element);
8363
8364 this.parseAttributes(filterAttributes(properties));
8365 this.parseContainments(filterContained(properties));
8366 }
8367
8368 this.parseGenericAttributes(element, otherAttrs);
8369
8370 return this;
8371 };
8372
8373 ElementSerializer.prototype.nsTagName = function(descriptor) {
8374 var effectiveNs = this.logNamespaceUsed(descriptor.ns);
8375 return getElementNs(effectiveNs, descriptor);
8376 };
8377
8378 ElementSerializer.prototype.nsPropertyTagName = function(descriptor) {
8379 var effectiveNs = this.logNamespaceUsed(descriptor.ns);
8380 return getPropertyNs(effectiveNs, descriptor);
8381 };
8382
8383 ElementSerializer.prototype.isLocalNs = function(ns) {
8384 return ns.uri === this.ns.uri;
8385 };
8386
8387 /**
8388 * Get the actual ns attribute name for the given element.
8389 *
8390 * @param {Object} element
8391 * @param {Boolean} [element.inherited=false]
8392 *
8393 * @return {Object} nsName
8394 */
8395 ElementSerializer.prototype.nsAttributeName = function(element) {
8396
8397 var ns;
8398
8399 if (isString(element)) {
8400 ns = parseName(element);
8401 } else {
8402 ns = element.ns;
8403 }
8404
8405 // return just local name for inherited attributes
8406 if (element.inherited) {
8407 return { localName: ns.localName };
8408 }
8409
8410 // parse + log effective ns
8411 var effectiveNs = this.logNamespaceUsed(ns);
8412
8413 // LOG ACTUAL namespace use
8414 this.getNamespaces().logUsed(effectiveNs);
8415
8416 // strip prefix if same namespace like parent
8417 if (this.isLocalNs(effectiveNs)) {
8418 return { localName: ns.localName };
8419 } else {
8420 return assign({ localName: ns.localName }, effectiveNs);
8421 }
8422 };
8423
8424 ElementSerializer.prototype.parseGeneric = function(element) {
8425
8426 var self = this,
8427 body = this.body;
8428
8429 var attributes = [];
8430
8431 forEach(element, function(val, key) {
8432
8433 var nonNsAttr;
8434
8435 if (key === '$body') {
8436 body.push(new BodySerializer().build({ type: 'String' }, val));
8437 } else
8438 if (key === '$children') {
8439 forEach(val, function(child) {
8440 body.push(new ElementSerializer(self).build(child));
8441 });
8442 } else
8443 if (key.indexOf('$') !== 0) {
8444 nonNsAttr = self.parseNsAttribute(element, key, val);
8445
8446 if (nonNsAttr) {
8447 attributes.push({ name: key, value: val });
8448 }
8449 }
8450 });
8451
8452 return attributes;
8453 };
8454
8455 ElementSerializer.prototype.parseNsAttribute = function(element, name, value) {
8456 var model = element.$model;
8457
8458 var nameNs = parseName(name);
8459
8460 var ns;
8461
8462 // parse xmlns:foo="http://foo.bar"
8463 if (nameNs.prefix === 'xmlns') {
8464 ns = { prefix: nameNs.localName, uri: value };
8465 }
8466
8467 // parse xmlns="http://foo.bar"
8468 if (!nameNs.prefix && nameNs.localName === 'xmlns') {
8469 ns = { uri: value };
8470 }
8471
8472 if (!ns) {
8473 return {
8474 name: name,
8475 value: value
8476 };
8477 }
8478
8479 if (model && model.getPackage(value)) {
8480 // register well known namespace
8481 this.logNamespace(ns, true, true);
8482 } else {
8483 // log custom namespace directly as used
8484 var actualNs = this.logNamespaceUsed(ns, true);
8485
8486 this.getNamespaces().logUsed(actualNs);
8487 }
8488 };
8489
8490
8491 /**
8492 * Parse namespaces and return a list of left over generic attributes
8493 *
8494 * @param {Object} element
8495 * @return {Array<Object>}
8496 */
8497 ElementSerializer.prototype.parseNsAttributes = function(element, attrs) {
8498 var self = this;
8499
8500 var genericAttrs = element.$attrs;
8501
8502 var attributes = [];
8503
8504 // parse namespace attributes first
8505 // and log them. push non namespace attributes to a list
8506 // and process them later
8507 forEach(genericAttrs, function(value, name) {
8508
8509 var nonNsAttr = self.parseNsAttribute(element, name, value);
8510
8511 if (nonNsAttr) {
8512 attributes.push(nonNsAttr);
8513 }
8514 });
8515
8516 return attributes;
8517 };
8518
8519 ElementSerializer.prototype.parseGenericAttributes = function(element, attributes) {
8520
8521 var self = this;
8522
8523 forEach(attributes, function(attr) {
8524
8525 // do not serialize xsi:type attribute
8526 // it is set manually based on the actual implementation type
8527 if (attr.name === XSI_TYPE$1) {
8528 return;
8529 }
8530
8531 try {
8532 self.addAttribute(self.nsAttributeName(attr.name), attr.value);
8533 } catch (e) {
8534 console.warn(
8535 'missing namespace information for ',
8536 attr.name, '=', attr.value, 'on', element,
8537 e);
8538 }
8539 });
8540 };
8541
8542 ElementSerializer.prototype.parseContainments = function(properties) {
8543
8544 var self = this,
8545 body = this.body,
8546 element = this.element;
8547
8548 forEach(properties, function(p) {
8549 var value = element.get(p.name),
8550 isReference = p.isReference,
8551 isMany = p.isMany;
8552
8553 if (!isMany) {
8554 value = [ value ];
8555 }
8556
8557 if (p.isBody) {
8558 body.push(new BodySerializer().build(p, value[0]));
8559 } else
8560 if (isSimple(p.type)) {
8561 forEach(value, function(v) {
8562 body.push(new ValueSerializer(self.addTagName(self.nsPropertyTagName(p))).build(p, v));
8563 });
8564 } else
8565 if (isReference) {
8566 forEach(value, function(v) {
8567 body.push(new ReferenceSerializer(self.addTagName(self.nsPropertyTagName(p))).build(v));
8568 });
8569 } else {
8570 // allow serialization via type
8571 // rather than element name
8572 var asType = serializeAsType(p),
8573 asProperty = serializeAsProperty(p);
8574
8575 forEach(value, function(v) {
8576 var serializer;
8577
8578 if (asType) {
8579 serializer = new TypeSerializer(self, p);
8580 } else
8581 if (asProperty) {
8582 serializer = new ElementSerializer(self, p);
8583 } else {
8584 serializer = new ElementSerializer(self);
8585 }
8586
8587 body.push(serializer.build(v));
8588 });
8589 }
8590 });
8591 };
8592
8593 ElementSerializer.prototype.getNamespaces = function(local) {
8594
8595 var namespaces = this.namespaces,
8596 parent = this.parent,
8597 parentNamespaces;
8598
8599 if (!namespaces) {
8600 parentNamespaces = parent && parent.getNamespaces();
8601
8602 if (local || !parentNamespaces) {
8603 this.namespaces = namespaces = new Namespaces(parentNamespaces);
8604 } else {
8605 namespaces = parentNamespaces;
8606 }
8607 }
8608
8609 return namespaces;
8610 };
8611
8612 ElementSerializer.prototype.logNamespace = function(ns, wellknown, local) {
8613 var namespaces = this.getNamespaces(local);
8614
8615 var nsUri = ns.uri,
8616 nsPrefix = ns.prefix;
8617
8618 var existing = namespaces.byUri(nsUri);
8619
8620 if (!existing) {
8621 namespaces.add(ns, wellknown);
8622 }
8623
8624 namespaces.mapPrefix(nsPrefix, nsUri);
8625
8626 return ns;
8627 };
8628
8629 ElementSerializer.prototype.logNamespaceUsed = function(ns, local) {
8630 var element = this.element,
8631 model = element.$model,
8632 namespaces = this.getNamespaces(local);
8633
8634 // ns may be
8635 //
8636 // * prefix only
8637 // * prefix:uri
8638 // * localName only
8639
8640 var prefix = ns.prefix,
8641 uri = ns.uri,
8642 newPrefix, idx,
8643 wellknownUri;
8644
8645 // handle anonymous namespaces (elementForm=unqualified), cf. #23
8646 if (!prefix && !uri) {
8647 return { localName: ns.localName };
8648 }
8649
8650 wellknownUri = DEFAULT_NS_MAP[prefix] || model && (model.getPackage(prefix) || {}).uri;
8651
8652 uri = uri || wellknownUri || namespaces.uriByPrefix(prefix);
8653
8654 if (!uri) {
8655 throw new Error('no namespace uri given for prefix <' + prefix + '>');
8656 }
8657
8658 ns = namespaces.byUri(uri);
8659
8660 if (!ns) {
8661 newPrefix = prefix;
8662 idx = 1;
8663
8664 // find a prefix that is not mapped yet
8665 while (namespaces.uriByPrefix(newPrefix)) {
8666 newPrefix = prefix + '_' + idx++;
8667 }
8668
8669 ns = this.logNamespace({ prefix: newPrefix, uri: uri }, wellknownUri === uri);
8670 }
8671
8672 if (prefix) {
8673 namespaces.mapPrefix(prefix, uri);
8674 }
8675
8676 return ns;
8677 };
8678
8679 ElementSerializer.prototype.parseAttributes = function(properties) {
8680 var self = this,
8681 element = this.element;
8682
8683 forEach(properties, function(p) {
8684
8685 var value = element.get(p.name);
8686
8687 if (p.isReference) {
8688
8689 if (!p.isMany) {
8690 value = value.id;
8691 }
8692 else {
8693 var values = [];
8694 forEach(value, function(v) {
8695 values.push(v.id);
8696 });
8697 // IDREFS is a whitespace-separated list of references.
8698 value = values.join(' ');
8699 }
8700
8701 }
8702
8703 self.addAttribute(self.nsAttributeName(p), value);
8704 });
8705 };
8706
8707 ElementSerializer.prototype.addTagName = function(nsTagName) {
8708 var actualNs = this.logNamespaceUsed(nsTagName);
8709
8710 this.getNamespaces().logUsed(actualNs);
8711
8712 return nsName(nsTagName);
8713 };
8714
8715 ElementSerializer.prototype.addAttribute = function(name, value) {
8716 var attrs = this.attrs;
8717
8718 if (isString(value)) {
8719 value = escapeAttr(value);
8720 }
8721
8722 attrs.push({ name: name, value: value });
8723 };
8724
8725 ElementSerializer.prototype.serializeAttributes = function(writer) {
8726 var attrs = this.attrs,
8727 namespaces = this.namespaces;
8728
8729 if (namespaces) {
8730 attrs = getNsAttrs(namespaces).concat(attrs);
8731 }
8732
8733 forEach(attrs, function(a) {
8734 writer
8735 .append(' ')
8736 .append(nsName(a.name)).append('="').append(a.value).append('"');
8737 });
8738 };
8739
8740 ElementSerializer.prototype.serializeTo = function(writer) {
8741 var firstBody = this.body[0],
8742 indent = firstBody && firstBody.constructor !== BodySerializer;
8743
8744 writer
8745 .appendIndent()
8746 .append('<' + this.tagName);
8747
8748 this.serializeAttributes(writer);
8749
8750 writer.append(firstBody ? '>' : ' />');
8751
8752 if (firstBody) {
8753
8754 if (indent) {
8755 writer
8756 .appendNewLine()
8757 .indent();
8758 }
8759
8760 forEach(this.body, function(b) {
8761 b.serializeTo(writer);
8762 });
8763
8764 if (indent) {
8765 writer
8766 .unindent()
8767 .appendIndent();
8768 }
8769
8770 writer.append('</' + this.tagName + '>');
8771 }
8772
8773 writer.appendNewLine();
8774 };
8775
8776 /**
8777 * A serializer for types that handles serialization of data types
8778 */
8779 function TypeSerializer(parent, propertyDescriptor) {
8780 ElementSerializer.call(this, parent, propertyDescriptor);
8781 }
8782
8783 inherits(TypeSerializer, ElementSerializer);
8784
8785 TypeSerializer.prototype.parseNsAttributes = function(element) {
8786
8787 // extracted attributes
8788 var attributes = ElementSerializer.prototype.parseNsAttributes.call(this, element);
8789
8790 var descriptor = element.$descriptor;
8791
8792 // only serialize xsi:type if necessary
8793 if (descriptor.name === this.propertyDescriptor.type) {
8794 return attributes;
8795 }
8796
8797 var typeNs = this.typeNs = this.nsTagName(descriptor);
8798 this.getNamespaces().logUsed(this.typeNs);
8799
8800 // add xsi:type attribute to represent the elements
8801 // actual type
8802
8803 var pkg = element.$model.getPackage(typeNs.uri),
8804 typePrefix = (pkg.xml && pkg.xml.typePrefix) || '';
8805
8806 this.addAttribute(
8807 this.nsAttributeName(XSI_TYPE$1),
8808 (typeNs.prefix ? typeNs.prefix + ':' : '') + typePrefix + descriptor.ns.localName
8809 );
8810
8811 return attributes;
8812 };
8813
8814 TypeSerializer.prototype.isLocalNs = function(ns) {
8815 return ns.uri === (this.typeNs || this.ns).uri;
8816 };
8817
8818 function SavingWriter() {
8819 this.value = '';
8820
8821 this.write = function(str) {
8822 this.value += str;
8823 };
8824 }
8825
8826 function FormatingWriter(out, format) {
8827
8828 var indent = [''];
8829
8830 this.append = function(str) {
8831 out.write(str);
8832
8833 return this;
8834 };
8835
8836 this.appendNewLine = function() {
8837 if (format) {
8838 out.write('\n');
8839 }
8840
8841 return this;
8842 };
8843
8844 this.appendIndent = function() {
8845 if (format) {
8846 out.write(indent.join(' '));
8847 }
8848
8849 return this;
8850 };
8851
8852 this.indent = function() {
8853 indent.push('');
8854 return this;
8855 };
8856
8857 this.unindent = function() {
8858 indent.pop();
8859 return this;
8860 };
8861 }
8862
8863 /**
8864 * A writer for meta-model backed document trees
8865 *
8866 * @param {Object} options output options to pass into the writer
8867 */
8868 function Writer(options) {
8869
8870 options = assign({ format: false, preamble: true }, options || {});
8871
8872 function toXML(tree, writer) {
8873 var internalWriter = writer || new SavingWriter();
8874 var formatingWriter = new FormatingWriter(internalWriter, options.format);
8875
8876 if (options.preamble) {
8877 formatingWriter.append(XML_PREAMBLE);
8878 }
8879
8880 new ElementSerializer().build(tree).serializeTo(formatingWriter);
8881
8882 if (!writer) {
8883 return internalWriter.value;
8884 }
8885 }
8886
8887 return {
8888 toXML: toXML
8889 };
8890 }
8891
8892 /**
8893 * A sub class of {@link Moddle} with support for import and export of BPMN 2.0 xml files.
8894 *
8895 * @class BpmnModdle
8896 * @extends Moddle
8897 *
8898 * @param {Object|Array} packages to use for instantiating the model
8899 * @param {Object} [options] additional options to pass over
8900 */
8901 function BpmnModdle(packages, options) {
8902 Moddle.call(this, packages, options);
8903 }
8904
8905 BpmnModdle.prototype = Object.create(Moddle.prototype);
8906
8907
8908 /**
8909 * Instantiates a BPMN model tree from a given xml string.
8910 *
8911 * @param {String} xmlStr
8912 * @param {String} [typeName='bpmn:Definitions'] name of the root element
8913 * @param {Object} [options] options to pass to the underlying reader
8914 * @param {Function} done callback that is invoked with (err, result, parseContext)
8915 * once the import completes
8916 */
8917 BpmnModdle.prototype.fromXML = function(xmlStr, typeName, options, done) {
8918
8919 if (!isString(typeName)) {
8920 done = options;
8921 options = typeName;
8922 typeName = 'bpmn:Definitions';
8923 }
8924
8925 if (isFunction(options)) {
8926 done = options;
8927 options = {};
8928 }
8929
8930 var reader = new Reader(assign({ model: this, lax: true }, options));
8931 var rootHandler = reader.handler(typeName);
8932
8933 reader.fromXML(xmlStr, rootHandler, done);
8934 };
8935
8936
8937 /**
8938 * Serializes a BPMN 2.0 object tree to XML.
8939 *
8940 * @param {String} element the root element, typically an instance of `bpmn:Definitions`
8941 * @param {Object} [options] to pass to the underlying writer
8942 * @param {Function} done callback invoked with (err, xmlStr) once the import completes
8943 */
8944 BpmnModdle.prototype.toXML = function(element, options, done) {
8945
8946 if (isFunction(options)) {
8947 done = options;
8948 options = {};
8949 }
8950
8951 var writer = new Writer(options);
8952
8953 var result;
8954 var err;
8955
8956 try {
8957 result = writer.toXML(element);
8958 } catch (e) {
8959 err = e;
8960 }
8961
8962 return done(err, result);
8963 };
8964
8965 var name = "BPMN20";
8966 var uri = "http://www.omg.org/spec/BPMN/20100524/MODEL";
8967 var associations = [
8968 ];
8969 var types$1 = [
8970 {
8971 name: "Interface",
8972 superClass: [
8973 "RootElement"
8974 ],
8975 properties: [
8976 {
8977 name: "name",
8978 isAttr: true,
8979 type: "String"
8980 },
8981 {
8982 name: "operations",
8983 type: "Operation",
8984 isMany: true
8985 },
8986 {
8987 name: "implementationRef",
8988 type: "String",
8989 isAttr: true
8990 }
8991 ]
8992 },
8993 {
8994 name: "Operation",
8995 superClass: [
8996 "BaseElement"
8997 ],
8998 properties: [
8999 {
9000 name: "name",
9001 isAttr: true,
9002 type: "String"
9003 },
9004 {
9005 name: "inMessageRef",
9006 type: "Message",
9007 isReference: true
9008 },
9009 {
9010 name: "outMessageRef",
9011 type: "Message",
9012 isReference: true
9013 },
9014 {
9015 name: "errorRef",
9016 type: "Error",
9017 isMany: true,
9018 isReference: true
9019 },
9020 {
9021 name: "implementationRef",
9022 type: "String",
9023 isAttr: true
9024 }
9025 ]
9026 },
9027 {
9028 name: "EndPoint",
9029 superClass: [
9030 "RootElement"
9031 ]
9032 },
9033 {
9034 name: "Auditing",
9035 superClass: [
9036 "BaseElement"
9037 ]
9038 },
9039 {
9040 name: "GlobalTask",
9041 superClass: [
9042 "CallableElement"
9043 ],
9044 properties: [
9045 {
9046 name: "resources",
9047 type: "ResourceRole",
9048 isMany: true
9049 }
9050 ]
9051 },
9052 {
9053 name: "Monitoring",
9054 superClass: [
9055 "BaseElement"
9056 ]
9057 },
9058 {
9059 name: "Performer",
9060 superClass: [
9061 "ResourceRole"
9062 ]
9063 },
9064 {
9065 name: "Process",
9066 superClass: [
9067 "FlowElementsContainer",
9068 "CallableElement"
9069 ],
9070 properties: [
9071 {
9072 name: "processType",
9073 type: "ProcessType",
9074 isAttr: true
9075 },
9076 {
9077 name: "isClosed",
9078 isAttr: true,
9079 type: "Boolean"
9080 },
9081 {
9082 name: "auditing",
9083 type: "Auditing"
9084 },
9085 {
9086 name: "monitoring",
9087 type: "Monitoring"
9088 },
9089 {
9090 name: "properties",
9091 type: "Property",
9092 isMany: true
9093 },
9094 {
9095 name: "laneSets",
9096 type: "LaneSet",
9097 isMany: true,
9098 replaces: "FlowElementsContainer#laneSets"
9099 },
9100 {
9101 name: "flowElements",
9102 type: "FlowElement",
9103 isMany: true,
9104 replaces: "FlowElementsContainer#flowElements"
9105 },
9106 {
9107 name: "artifacts",
9108 type: "Artifact",
9109 isMany: true
9110 },
9111 {
9112 name: "resources",
9113 type: "ResourceRole",
9114 isMany: true
9115 },
9116 {
9117 name: "correlationSubscriptions",
9118 type: "CorrelationSubscription",
9119 isMany: true
9120 },
9121 {
9122 name: "supports",
9123 type: "Process",
9124 isMany: true,
9125 isReference: true
9126 },
9127 {
9128 name: "definitionalCollaborationRef",
9129 type: "Collaboration",
9130 isAttr: true,
9131 isReference: true
9132 },
9133 {
9134 name: "isExecutable",
9135 isAttr: true,
9136 type: "Boolean"
9137 }
9138 ]
9139 },
9140 {
9141 name: "LaneSet",
9142 superClass: [
9143 "BaseElement"
9144 ],
9145 properties: [
9146 {
9147 name: "lanes",
9148 type: "Lane",
9149 isMany: true
9150 },
9151 {
9152 name: "name",
9153 isAttr: true,
9154 type: "String"
9155 }
9156 ]
9157 },
9158 {
9159 name: "Lane",
9160 superClass: [
9161 "BaseElement"
9162 ],
9163 properties: [
9164 {
9165 name: "name",
9166 isAttr: true,
9167 type: "String"
9168 },
9169 {
9170 name: "partitionElementRef",
9171 type: "BaseElement",
9172 isAttr: true,
9173 isReference: true
9174 },
9175 {
9176 name: "partitionElement",
9177 type: "BaseElement"
9178 },
9179 {
9180 name: "flowNodeRef",
9181 type: "FlowNode",
9182 isMany: true,
9183 isReference: true
9184 },
9185 {
9186 name: "childLaneSet",
9187 type: "LaneSet",
9188 xml: {
9189 serialize: "xsi:type"
9190 }
9191 }
9192 ]
9193 },
9194 {
9195 name: "GlobalManualTask",
9196 superClass: [
9197 "GlobalTask"
9198 ]
9199 },
9200 {
9201 name: "ManualTask",
9202 superClass: [
9203 "Task"
9204 ]
9205 },
9206 {
9207 name: "UserTask",
9208 superClass: [
9209 "Task"
9210 ],
9211 properties: [
9212 {
9213 name: "renderings",
9214 type: "Rendering",
9215 isMany: true
9216 },
9217 {
9218 name: "implementation",
9219 isAttr: true,
9220 type: "String"
9221 }
9222 ]
9223 },
9224 {
9225 name: "Rendering",
9226 superClass: [
9227 "BaseElement"
9228 ]
9229 },
9230 {
9231 name: "HumanPerformer",
9232 superClass: [
9233 "Performer"
9234 ]
9235 },
9236 {
9237 name: "PotentialOwner",
9238 superClass: [
9239 "HumanPerformer"
9240 ]
9241 },
9242 {
9243 name: "GlobalUserTask",
9244 superClass: [
9245 "GlobalTask"
9246 ],
9247 properties: [
9248 {
9249 name: "implementation",
9250 isAttr: true,
9251 type: "String"
9252 },
9253 {
9254 name: "renderings",
9255 type: "Rendering",
9256 isMany: true
9257 }
9258 ]
9259 },
9260 {
9261 name: "Gateway",
9262 isAbstract: true,
9263 superClass: [
9264 "FlowNode"
9265 ],
9266 properties: [
9267 {
9268 name: "gatewayDirection",
9269 type: "GatewayDirection",
9270 "default": "Unspecified",
9271 isAttr: true
9272 }
9273 ]
9274 },
9275 {
9276 name: "EventBasedGateway",
9277 superClass: [
9278 "Gateway"
9279 ],
9280 properties: [
9281 {
9282 name: "instantiate",
9283 "default": false,
9284 isAttr: true,
9285 type: "Boolean"
9286 },
9287 {
9288 name: "eventGatewayType",
9289 type: "EventBasedGatewayType",
9290 isAttr: true,
9291 "default": "Exclusive"
9292 }
9293 ]
9294 },
9295 {
9296 name: "ComplexGateway",
9297 superClass: [
9298 "Gateway"
9299 ],
9300 properties: [
9301 {
9302 name: "activationCondition",
9303 type: "Expression",
9304 xml: {
9305 serialize: "xsi:type"
9306 }
9307 },
9308 {
9309 name: "default",
9310 type: "SequenceFlow",
9311 isAttr: true,
9312 isReference: true
9313 }
9314 ]
9315 },
9316 {
9317 name: "ExclusiveGateway",
9318 superClass: [
9319 "Gateway"
9320 ],
9321 properties: [
9322 {
9323 name: "default",
9324 type: "SequenceFlow",
9325 isAttr: true,
9326 isReference: true
9327 }
9328 ]
9329 },
9330 {
9331 name: "InclusiveGateway",
9332 superClass: [
9333 "Gateway"
9334 ],
9335 properties: [
9336 {
9337 name: "default",
9338 type: "SequenceFlow",
9339 isAttr: true,
9340 isReference: true
9341 }
9342 ]
9343 },
9344 {
9345 name: "ParallelGateway",
9346 superClass: [
9347 "Gateway"
9348 ]
9349 },
9350 {
9351 name: "RootElement",
9352 isAbstract: true,
9353 superClass: [
9354 "BaseElement"
9355 ]
9356 },
9357 {
9358 name: "Relationship",
9359 superClass: [
9360 "BaseElement"
9361 ],
9362 properties: [
9363 {
9364 name: "type",
9365 isAttr: true,
9366 type: "String"
9367 },
9368 {
9369 name: "direction",
9370 type: "RelationshipDirection",
9371 isAttr: true
9372 },
9373 {
9374 name: "source",
9375 isMany: true,
9376 isReference: true,
9377 type: "Element"
9378 },
9379 {
9380 name: "target",
9381 isMany: true,
9382 isReference: true,
9383 type: "Element"
9384 }
9385 ]
9386 },
9387 {
9388 name: "BaseElement",
9389 isAbstract: true,
9390 properties: [
9391 {
9392 name: "id",
9393 isAttr: true,
9394 type: "String",
9395 isId: true
9396 },
9397 {
9398 name: "documentation",
9399 type: "Documentation",
9400 isMany: true
9401 },
9402 {
9403 name: "extensionDefinitions",
9404 type: "ExtensionDefinition",
9405 isMany: true,
9406 isReference: true
9407 },
9408 {
9409 name: "extensionElements",
9410 type: "ExtensionElements"
9411 }
9412 ]
9413 },
9414 {
9415 name: "Extension",
9416 properties: [
9417 {
9418 name: "mustUnderstand",
9419 "default": false,
9420 isAttr: true,
9421 type: "Boolean"
9422 },
9423 {
9424 name: "definition",
9425 type: "ExtensionDefinition",
9426 isAttr: true,
9427 isReference: true
9428 }
9429 ]
9430 },
9431 {
9432 name: "ExtensionDefinition",
9433 properties: [
9434 {
9435 name: "name",
9436 isAttr: true,
9437 type: "String"
9438 },
9439 {
9440 name: "extensionAttributeDefinitions",
9441 type: "ExtensionAttributeDefinition",
9442 isMany: true
9443 }
9444 ]
9445 },
9446 {
9447 name: "ExtensionAttributeDefinition",
9448 properties: [
9449 {
9450 name: "name",
9451 isAttr: true,
9452 type: "String"
9453 },
9454 {
9455 name: "type",
9456 isAttr: true,
9457 type: "String"
9458 },
9459 {
9460 name: "isReference",
9461 "default": false,
9462 isAttr: true,
9463 type: "Boolean"
9464 },
9465 {
9466 name: "extensionDefinition",
9467 type: "ExtensionDefinition",
9468 isAttr: true,
9469 isReference: true
9470 }
9471 ]
9472 },
9473 {
9474 name: "ExtensionElements",
9475 properties: [
9476 {
9477 name: "valueRef",
9478 isAttr: true,
9479 isReference: true,
9480 type: "Element"
9481 },
9482 {
9483 name: "values",
9484 type: "Element",
9485 isMany: true
9486 },
9487 {
9488 name: "extensionAttributeDefinition",
9489 type: "ExtensionAttributeDefinition",
9490 isAttr: true,
9491 isReference: true
9492 }
9493 ]
9494 },
9495 {
9496 name: "Documentation",
9497 superClass: [
9498 "BaseElement"
9499 ],
9500 properties: [
9501 {
9502 name: "text",
9503 type: "String",
9504 isBody: true
9505 },
9506 {
9507 name: "textFormat",
9508 "default": "text/plain",
9509 isAttr: true,
9510 type: "String"
9511 }
9512 ]
9513 },
9514 {
9515 name: "Event",
9516 isAbstract: true,
9517 superClass: [
9518 "FlowNode",
9519 "InteractionNode"
9520 ],
9521 properties: [
9522 {
9523 name: "properties",
9524 type: "Property",
9525 isMany: true
9526 }
9527 ]
9528 },
9529 {
9530 name: "IntermediateCatchEvent",
9531 superClass: [
9532 "CatchEvent"
9533 ]
9534 },
9535 {
9536 name: "IntermediateThrowEvent",
9537 superClass: [
9538 "ThrowEvent"
9539 ]
9540 },
9541 {
9542 name: "EndEvent",
9543 superClass: [
9544 "ThrowEvent"
9545 ]
9546 },
9547 {
9548 name: "StartEvent",
9549 superClass: [
9550 "CatchEvent"
9551 ],
9552 properties: [
9553 {
9554 name: "isInterrupting",
9555 "default": true,
9556 isAttr: true,
9557 type: "Boolean"
9558 }
9559 ]
9560 },
9561 {
9562 name: "ThrowEvent",
9563 isAbstract: true,
9564 superClass: [
9565 "Event"
9566 ],
9567 properties: [
9568 {
9569 name: "dataInputs",
9570 type: "DataInput",
9571 isMany: true
9572 },
9573 {
9574 name: "dataInputAssociations",
9575 type: "DataInputAssociation",
9576 isMany: true
9577 },
9578 {
9579 name: "inputSet",
9580 type: "InputSet"
9581 },
9582 {
9583 name: "eventDefinitions",
9584 type: "EventDefinition",
9585 isMany: true
9586 },
9587 {
9588 name: "eventDefinitionRef",
9589 type: "EventDefinition",
9590 isMany: true,
9591 isReference: true
9592 }
9593 ]
9594 },
9595 {
9596 name: "CatchEvent",
9597 isAbstract: true,
9598 superClass: [
9599 "Event"
9600 ],
9601 properties: [
9602 {
9603 name: "parallelMultiple",
9604 isAttr: true,
9605 type: "Boolean",
9606 "default": false
9607 },
9608 {
9609 name: "dataOutputs",
9610 type: "DataOutput",
9611 isMany: true
9612 },
9613 {
9614 name: "dataOutputAssociations",
9615 type: "DataOutputAssociation",
9616 isMany: true
9617 },
9618 {
9619 name: "outputSet",
9620 type: "OutputSet"
9621 },
9622 {
9623 name: "eventDefinitions",
9624 type: "EventDefinition",
9625 isMany: true
9626 },
9627 {
9628 name: "eventDefinitionRef",
9629 type: "EventDefinition",
9630 isMany: true,
9631 isReference: true
9632 }
9633 ]
9634 },
9635 {
9636 name: "BoundaryEvent",
9637 superClass: [
9638 "CatchEvent"
9639 ],
9640 properties: [
9641 {
9642 name: "cancelActivity",
9643 "default": true,
9644 isAttr: true,
9645 type: "Boolean"
9646 },
9647 {
9648 name: "attachedToRef",
9649 type: "Activity",
9650 isAttr: true,
9651 isReference: true
9652 }
9653 ]
9654 },
9655 {
9656 name: "EventDefinition",
9657 isAbstract: true,
9658 superClass: [
9659 "RootElement"
9660 ]
9661 },
9662 {
9663 name: "CancelEventDefinition",
9664 superClass: [
9665 "EventDefinition"
9666 ]
9667 },
9668 {
9669 name: "ErrorEventDefinition",
9670 superClass: [
9671 "EventDefinition"
9672 ],
9673 properties: [
9674 {
9675 name: "errorRef",
9676 type: "Error",
9677 isAttr: true,
9678 isReference: true
9679 }
9680 ]
9681 },
9682 {
9683 name: "TerminateEventDefinition",
9684 superClass: [
9685 "EventDefinition"
9686 ]
9687 },
9688 {
9689 name: "EscalationEventDefinition",
9690 superClass: [
9691 "EventDefinition"
9692 ],
9693 properties: [
9694 {
9695 name: "escalationRef",
9696 type: "Escalation",
9697 isAttr: true,
9698 isReference: true
9699 }
9700 ]
9701 },
9702 {
9703 name: "Escalation",
9704 properties: [
9705 {
9706 name: "structureRef",
9707 type: "ItemDefinition",
9708 isAttr: true,
9709 isReference: true
9710 },
9711 {
9712 name: "name",
9713 isAttr: true,
9714 type: "String"
9715 },
9716 {
9717 name: "escalationCode",
9718 isAttr: true,
9719 type: "String"
9720 }
9721 ],
9722 superClass: [
9723 "RootElement"
9724 ]
9725 },
9726 {
9727 name: "CompensateEventDefinition",
9728 superClass: [
9729 "EventDefinition"
9730 ],
9731 properties: [
9732 {
9733 name: "waitForCompletion",
9734 isAttr: true,
9735 type: "Boolean",
9736 "default": true
9737 },
9738 {
9739 name: "activityRef",
9740 type: "Activity",
9741 isAttr: true,
9742 isReference: true
9743 }
9744 ]
9745 },
9746 {
9747 name: "TimerEventDefinition",
9748 superClass: [
9749 "EventDefinition"
9750 ],
9751 properties: [
9752 {
9753 name: "timeDate",
9754 type: "Expression",
9755 xml: {
9756 serialize: "xsi:type"
9757 }
9758 },
9759 {
9760 name: "timeCycle",
9761 type: "Expression",
9762 xml: {
9763 serialize: "xsi:type"
9764 }
9765 },
9766 {
9767 name: "timeDuration",
9768 type: "Expression",
9769 xml: {
9770 serialize: "xsi:type"
9771 }
9772 }
9773 ]
9774 },
9775 {
9776 name: "LinkEventDefinition",
9777 superClass: [
9778 "EventDefinition"
9779 ],
9780 properties: [
9781 {
9782 name: "name",
9783 isAttr: true,
9784 type: "String"
9785 },
9786 {
9787 name: "target",
9788 type: "LinkEventDefinition",
9789 isAttr: true,
9790 isReference: true
9791 },
9792 {
9793 name: "source",
9794 type: "LinkEventDefinition",
9795 isMany: true,
9796 isReference: true
9797 }
9798 ]
9799 },
9800 {
9801 name: "MessageEventDefinition",
9802 superClass: [
9803 "EventDefinition"
9804 ],
9805 properties: [
9806 {
9807 name: "messageRef",
9808 type: "Message",
9809 isAttr: true,
9810 isReference: true
9811 },
9812 {
9813 name: "operationRef",
9814 type: "Operation",
9815 isAttr: true,
9816 isReference: true
9817 }
9818 ]
9819 },
9820 {
9821 name: "ConditionalEventDefinition",
9822 superClass: [
9823 "EventDefinition"
9824 ],
9825 properties: [
9826 {
9827 name: "condition",
9828 type: "Expression",
9829 xml: {
9830 serialize: "xsi:type"
9831 }
9832 }
9833 ]
9834 },
9835 {
9836 name: "SignalEventDefinition",
9837 superClass: [
9838 "EventDefinition"
9839 ],
9840 properties: [
9841 {
9842 name: "signalRef",
9843 type: "Signal",
9844 isAttr: true,
9845 isReference: true
9846 }
9847 ]
9848 },
9849 {
9850 name: "Signal",
9851 superClass: [
9852 "RootElement"
9853 ],
9854 properties: [
9855 {
9856 name: "structureRef",
9857 type: "ItemDefinition",
9858 isAttr: true,
9859 isReference: true
9860 },
9861 {
9862 name: "name",
9863 isAttr: true,
9864 type: "String"
9865 }
9866 ]
9867 },
9868 {
9869 name: "ImplicitThrowEvent",
9870 superClass: [
9871 "ThrowEvent"
9872 ]
9873 },
9874 {
9875 name: "DataState",
9876 superClass: [
9877 "BaseElement"
9878 ],
9879 properties: [
9880 {
9881 name: "name",
9882 isAttr: true,
9883 type: "String"
9884 }
9885 ]
9886 },
9887 {
9888 name: "ItemAwareElement",
9889 superClass: [
9890 "BaseElement"
9891 ],
9892 properties: [
9893 {
9894 name: "itemSubjectRef",
9895 type: "ItemDefinition",
9896 isAttr: true,
9897 isReference: true
9898 },
9899 {
9900 name: "dataState",
9901 type: "DataState"
9902 }
9903 ]
9904 },
9905 {
9906 name: "DataAssociation",
9907 superClass: [
9908 "BaseElement"
9909 ],
9910 properties: [
9911 {
9912 name: "assignment",
9913 type: "Assignment",
9914 isMany: true
9915 },
9916 {
9917 name: "sourceRef",
9918 type: "ItemAwareElement",
9919 isMany: true,
9920 isReference: true
9921 },
9922 {
9923 name: "targetRef",
9924 type: "ItemAwareElement",
9925 isReference: true
9926 },
9927 {
9928 name: "transformation",
9929 type: "FormalExpression",
9930 xml: {
9931 serialize: "property"
9932 }
9933 }
9934 ]
9935 },
9936 {
9937 name: "DataInput",
9938 superClass: [
9939 "ItemAwareElement"
9940 ],
9941 properties: [
9942 {
9943 name: "name",
9944 isAttr: true,
9945 type: "String"
9946 },
9947 {
9948 name: "isCollection",
9949 "default": false,
9950 isAttr: true,
9951 type: "Boolean"
9952 },
9953 {
9954 name: "inputSetRef",
9955 type: "InputSet",
9956 isVirtual: true,
9957 isMany: true,
9958 isReference: true
9959 },
9960 {
9961 name: "inputSetWithOptional",
9962 type: "InputSet",
9963 isVirtual: true,
9964 isMany: true,
9965 isReference: true
9966 },
9967 {
9968 name: "inputSetWithWhileExecuting",
9969 type: "InputSet",
9970 isVirtual: true,
9971 isMany: true,
9972 isReference: true
9973 }
9974 ]
9975 },
9976 {
9977 name: "DataOutput",
9978 superClass: [
9979 "ItemAwareElement"
9980 ],
9981 properties: [
9982 {
9983 name: "name",
9984 isAttr: true,
9985 type: "String"
9986 },
9987 {
9988 name: "isCollection",
9989 "default": false,
9990 isAttr: true,
9991 type: "Boolean"
9992 },
9993 {
9994 name: "outputSetRef",
9995 type: "OutputSet",
9996 isVirtual: true,
9997 isMany: true,
9998 isReference: true
9999 },
10000 {
10001 name: "outputSetWithOptional",
10002 type: "OutputSet",
10003 isVirtual: true,
10004 isMany: true,
10005 isReference: true
10006 },
10007 {
10008 name: "outputSetWithWhileExecuting",
10009 type: "OutputSet",
10010 isVirtual: true,
10011 isMany: true,
10012 isReference: true
10013 }
10014 ]
10015 },
10016 {
10017 name: "InputSet",
10018 superClass: [
10019 "BaseElement"
10020 ],
10021 properties: [
10022 {
10023 name: "name",
10024 isAttr: true,
10025 type: "String"
10026 },
10027 {
10028 name: "dataInputRefs",
10029 type: "DataInput",
10030 isMany: true,
10031 isReference: true
10032 },
10033 {
10034 name: "optionalInputRefs",
10035 type: "DataInput",
10036 isMany: true,
10037 isReference: true
10038 },
10039 {
10040 name: "whileExecutingInputRefs",
10041 type: "DataInput",
10042 isMany: true,
10043 isReference: true
10044 },
10045 {
10046 name: "outputSetRefs",
10047 type: "OutputSet",
10048 isMany: true,
10049 isReference: true
10050 }
10051 ]
10052 },
10053 {
10054 name: "OutputSet",
10055 superClass: [
10056 "BaseElement"
10057 ],
10058 properties: [
10059 {
10060 name: "dataOutputRefs",
10061 type: "DataOutput",
10062 isMany: true,
10063 isReference: true
10064 },
10065 {
10066 name: "name",
10067 isAttr: true,
10068 type: "String"
10069 },
10070 {
10071 name: "inputSetRefs",
10072 type: "InputSet",
10073 isMany: true,
10074 isReference: true
10075 },
10076 {
10077 name: "optionalOutputRefs",
10078 type: "DataOutput",
10079 isMany: true,
10080 isReference: true
10081 },
10082 {
10083 name: "whileExecutingOutputRefs",
10084 type: "DataOutput",
10085 isMany: true,
10086 isReference: true
10087 }
10088 ]
10089 },
10090 {
10091 name: "Property",
10092 superClass: [
10093 "ItemAwareElement"
10094 ],
10095 properties: [
10096 {
10097 name: "name",
10098 isAttr: true,
10099 type: "String"
10100 }
10101 ]
10102 },
10103 {
10104 name: "DataInputAssociation",
10105 superClass: [
10106 "DataAssociation"
10107 ]
10108 },
10109 {
10110 name: "DataOutputAssociation",
10111 superClass: [
10112 "DataAssociation"
10113 ]
10114 },
10115 {
10116 name: "InputOutputSpecification",
10117 superClass: [
10118 "BaseElement"
10119 ],
10120 properties: [
10121 {
10122 name: "dataInputs",
10123 type: "DataInput",
10124 isMany: true
10125 },
10126 {
10127 name: "dataOutputs",
10128 type: "DataOutput",
10129 isMany: true
10130 },
10131 {
10132 name: "inputSets",
10133 type: "InputSet",
10134 isMany: true
10135 },
10136 {
10137 name: "outputSets",
10138 type: "OutputSet",
10139 isMany: true
10140 }
10141 ]
10142 },
10143 {
10144 name: "DataObject",
10145 superClass: [
10146 "FlowElement",
10147 "ItemAwareElement"
10148 ],
10149 properties: [
10150 {
10151 name: "isCollection",
10152 "default": false,
10153 isAttr: true,
10154 type: "Boolean"
10155 }
10156 ]
10157 },
10158 {
10159 name: "InputOutputBinding",
10160 properties: [
10161 {
10162 name: "inputDataRef",
10163 type: "InputSet",
10164 isAttr: true,
10165 isReference: true
10166 },
10167 {
10168 name: "outputDataRef",
10169 type: "OutputSet",
10170 isAttr: true,
10171 isReference: true
10172 },
10173 {
10174 name: "operationRef",
10175 type: "Operation",
10176 isAttr: true,
10177 isReference: true
10178 }
10179 ]
10180 },
10181 {
10182 name: "Assignment",
10183 superClass: [
10184 "BaseElement"
10185 ],
10186 properties: [
10187 {
10188 name: "from",
10189 type: "Expression",
10190 xml: {
10191 serialize: "xsi:type"
10192 }
10193 },
10194 {
10195 name: "to",
10196 type: "Expression",
10197 xml: {
10198 serialize: "xsi:type"
10199 }
10200 }
10201 ]
10202 },
10203 {
10204 name: "DataStore",
10205 superClass: [
10206 "RootElement",
10207 "ItemAwareElement"
10208 ],
10209 properties: [
10210 {
10211 name: "name",
10212 isAttr: true,
10213 type: "String"
10214 },
10215 {
10216 name: "capacity",
10217 isAttr: true,
10218 type: "Integer"
10219 },
10220 {
10221 name: "isUnlimited",
10222 "default": true,
10223 isAttr: true,
10224 type: "Boolean"
10225 }
10226 ]
10227 },
10228 {
10229 name: "DataStoreReference",
10230 superClass: [
10231 "ItemAwareElement",
10232 "FlowElement"
10233 ],
10234 properties: [
10235 {
10236 name: "dataStoreRef",
10237 type: "DataStore",
10238 isAttr: true,
10239 isReference: true
10240 }
10241 ]
10242 },
10243 {
10244 name: "DataObjectReference",
10245 superClass: [
10246 "ItemAwareElement",
10247 "FlowElement"
10248 ],
10249 properties: [
10250 {
10251 name: "dataObjectRef",
10252 type: "DataObject",
10253 isAttr: true,
10254 isReference: true
10255 }
10256 ]
10257 },
10258 {
10259 name: "ConversationLink",
10260 superClass: [
10261 "BaseElement"
10262 ],
10263 properties: [
10264 {
10265 name: "sourceRef",
10266 type: "InteractionNode",
10267 isAttr: true,
10268 isReference: true
10269 },
10270 {
10271 name: "targetRef",
10272 type: "InteractionNode",
10273 isAttr: true,
10274 isReference: true
10275 },
10276 {
10277 name: "name",
10278 isAttr: true,
10279 type: "String"
10280 }
10281 ]
10282 },
10283 {
10284 name: "ConversationAssociation",
10285 superClass: [
10286 "BaseElement"
10287 ],
10288 properties: [
10289 {
10290 name: "innerConversationNodeRef",
10291 type: "ConversationNode",
10292 isAttr: true,
10293 isReference: true
10294 },
10295 {
10296 name: "outerConversationNodeRef",
10297 type: "ConversationNode",
10298 isAttr: true,
10299 isReference: true
10300 }
10301 ]
10302 },
10303 {
10304 name: "CallConversation",
10305 superClass: [
10306 "ConversationNode"
10307 ],
10308 properties: [
10309 {
10310 name: "calledCollaborationRef",
10311 type: "Collaboration",
10312 isAttr: true,
10313 isReference: true
10314 },
10315 {
10316 name: "participantAssociations",
10317 type: "ParticipantAssociation",
10318 isMany: true
10319 }
10320 ]
10321 },
10322 {
10323 name: "Conversation",
10324 superClass: [
10325 "ConversationNode"
10326 ]
10327 },
10328 {
10329 name: "SubConversation",
10330 superClass: [
10331 "ConversationNode"
10332 ],
10333 properties: [
10334 {
10335 name: "conversationNodes",
10336 type: "ConversationNode",
10337 isMany: true
10338 }
10339 ]
10340 },
10341 {
10342 name: "ConversationNode",
10343 isAbstract: true,
10344 superClass: [
10345 "InteractionNode",
10346 "BaseElement"
10347 ],
10348 properties: [
10349 {
10350 name: "name",
10351 isAttr: true,
10352 type: "String"
10353 },
10354 {
10355 name: "participantRef",
10356 type: "Participant",
10357 isMany: true,
10358 isReference: true
10359 },
10360 {
10361 name: "messageFlowRefs",
10362 type: "MessageFlow",
10363 isMany: true,
10364 isReference: true
10365 },
10366 {
10367 name: "correlationKeys",
10368 type: "CorrelationKey",
10369 isMany: true
10370 }
10371 ]
10372 },
10373 {
10374 name: "GlobalConversation",
10375 superClass: [
10376 "Collaboration"
10377 ]
10378 },
10379 {
10380 name: "PartnerEntity",
10381 superClass: [
10382 "RootElement"
10383 ],
10384 properties: [
10385 {
10386 name: "name",
10387 isAttr: true,
10388 type: "String"
10389 },
10390 {
10391 name: "participantRef",
10392 type: "Participant",
10393 isMany: true,
10394 isReference: true
10395 }
10396 ]
10397 },
10398 {
10399 name: "PartnerRole",
10400 superClass: [
10401 "RootElement"
10402 ],
10403 properties: [
10404 {
10405 name: "name",
10406 isAttr: true,
10407 type: "String"
10408 },
10409 {
10410 name: "participantRef",
10411 type: "Participant",
10412 isMany: true,
10413 isReference: true
10414 }
10415 ]
10416 },
10417 {
10418 name: "CorrelationProperty",
10419 superClass: [
10420 "RootElement"
10421 ],
10422 properties: [
10423 {
10424 name: "correlationPropertyRetrievalExpression",
10425 type: "CorrelationPropertyRetrievalExpression",
10426 isMany: true
10427 },
10428 {
10429 name: "name",
10430 isAttr: true,
10431 type: "String"
10432 },
10433 {
10434 name: "type",
10435 type: "ItemDefinition",
10436 isAttr: true,
10437 isReference: true
10438 }
10439 ]
10440 },
10441 {
10442 name: "Error",
10443 superClass: [
10444 "RootElement"
10445 ],
10446 properties: [
10447 {
10448 name: "structureRef",
10449 type: "ItemDefinition",
10450 isAttr: true,
10451 isReference: true
10452 },
10453 {
10454 name: "name",
10455 isAttr: true,
10456 type: "String"
10457 },
10458 {
10459 name: "errorCode",
10460 isAttr: true,
10461 type: "String"
10462 }
10463 ]
10464 },
10465 {
10466 name: "CorrelationKey",
10467 superClass: [
10468 "BaseElement"
10469 ],
10470 properties: [
10471 {
10472 name: "correlationPropertyRef",
10473 type: "CorrelationProperty",
10474 isMany: true,
10475 isReference: true
10476 },
10477 {
10478 name: "name",
10479 isAttr: true,
10480 type: "String"
10481 }
10482 ]
10483 },
10484 {
10485 name: "Expression",
10486 superClass: [
10487 "BaseElement"
10488 ],
10489 isAbstract: false,
10490 properties: [
10491 {
10492 name: "body",
10493 type: "String",
10494 isBody: true
10495 }
10496 ]
10497 },
10498 {
10499 name: "FormalExpression",
10500 superClass: [
10501 "Expression"
10502 ],
10503 properties: [
10504 {
10505 name: "language",
10506 isAttr: true,
10507 type: "String"
10508 },
10509 {
10510 name: "evaluatesToTypeRef",
10511 type: "ItemDefinition",
10512 isAttr: true,
10513 isReference: true
10514 }
10515 ]
10516 },
10517 {
10518 name: "Message",
10519 superClass: [
10520 "RootElement"
10521 ],
10522 properties: [
10523 {
10524 name: "name",
10525 isAttr: true,
10526 type: "String"
10527 },
10528 {
10529 name: "itemRef",
10530 type: "ItemDefinition",
10531 isAttr: true,
10532 isReference: true
10533 }
10534 ]
10535 },
10536 {
10537 name: "ItemDefinition",
10538 superClass: [
10539 "RootElement"
10540 ],
10541 properties: [
10542 {
10543 name: "itemKind",
10544 type: "ItemKind",
10545 isAttr: true
10546 },
10547 {
10548 name: "structureRef",
10549 type: "String",
10550 isAttr: true
10551 },
10552 {
10553 name: "isCollection",
10554 "default": false,
10555 isAttr: true,
10556 type: "Boolean"
10557 },
10558 {
10559 name: "import",
10560 type: "Import",
10561 isAttr: true,
10562 isReference: true
10563 }
10564 ]
10565 },
10566 {
10567 name: "FlowElement",
10568 isAbstract: true,
10569 superClass: [
10570 "BaseElement"
10571 ],
10572 properties: [
10573 {
10574 name: "name",
10575 isAttr: true,
10576 type: "String"
10577 },
10578 {
10579 name: "auditing",
10580 type: "Auditing"
10581 },
10582 {
10583 name: "monitoring",
10584 type: "Monitoring"
10585 },
10586 {
10587 name: "categoryValueRef",
10588 type: "CategoryValue",
10589 isMany: true,
10590 isReference: true
10591 }
10592 ]
10593 },
10594 {
10595 name: "SequenceFlow",
10596 superClass: [
10597 "FlowElement"
10598 ],
10599 properties: [
10600 {
10601 name: "isImmediate",
10602 isAttr: true,
10603 type: "Boolean"
10604 },
10605 {
10606 name: "conditionExpression",
10607 type: "Expression",
10608 xml: {
10609 serialize: "xsi:type"
10610 }
10611 },
10612 {
10613 name: "sourceRef",
10614 type: "FlowNode",
10615 isAttr: true,
10616 isReference: true
10617 },
10618 {
10619 name: "targetRef",
10620 type: "FlowNode",
10621 isAttr: true,
10622 isReference: true
10623 }
10624 ]
10625 },
10626 {
10627 name: "FlowElementsContainer",
10628 isAbstract: true,
10629 superClass: [
10630 "BaseElement"
10631 ],
10632 properties: [
10633 {
10634 name: "laneSets",
10635 type: "LaneSet",
10636 isMany: true
10637 },
10638 {
10639 name: "flowElements",
10640 type: "FlowElement",
10641 isMany: true
10642 }
10643 ]
10644 },
10645 {
10646 name: "CallableElement",
10647 isAbstract: true,
10648 superClass: [
10649 "RootElement"
10650 ],
10651 properties: [
10652 {
10653 name: "name",
10654 isAttr: true,
10655 type: "String"
10656 },
10657 {
10658 name: "ioSpecification",
10659 type: "InputOutputSpecification",
10660 xml: {
10661 serialize: "property"
10662 }
10663 },
10664 {
10665 name: "supportedInterfaceRef",
10666 type: "Interface",
10667 isMany: true,
10668 isReference: true
10669 },
10670 {
10671 name: "ioBinding",
10672 type: "InputOutputBinding",
10673 isMany: true,
10674 xml: {
10675 serialize: "property"
10676 }
10677 }
10678 ]
10679 },
10680 {
10681 name: "FlowNode",
10682 isAbstract: true,
10683 superClass: [
10684 "FlowElement"
10685 ],
10686 properties: [
10687 {
10688 name: "incoming",
10689 type: "SequenceFlow",
10690 isMany: true,
10691 isReference: true
10692 },
10693 {
10694 name: "outgoing",
10695 type: "SequenceFlow",
10696 isMany: true,
10697 isReference: true
10698 },
10699 {
10700 name: "lanes",
10701 type: "Lane",
10702 isVirtual: true,
10703 isMany: true,
10704 isReference: true
10705 }
10706 ]
10707 },
10708 {
10709 name: "CorrelationPropertyRetrievalExpression",
10710 superClass: [
10711 "BaseElement"
10712 ],
10713 properties: [
10714 {
10715 name: "messagePath",
10716 type: "FormalExpression"
10717 },
10718 {
10719 name: "messageRef",
10720 type: "Message",
10721 isAttr: true,
10722 isReference: true
10723 }
10724 ]
10725 },
10726 {
10727 name: "CorrelationPropertyBinding",
10728 superClass: [
10729 "BaseElement"
10730 ],
10731 properties: [
10732 {
10733 name: "dataPath",
10734 type: "FormalExpression"
10735 },
10736 {
10737 name: "correlationPropertyRef",
10738 type: "CorrelationProperty",
10739 isAttr: true,
10740 isReference: true
10741 }
10742 ]
10743 },
10744 {
10745 name: "Resource",
10746 superClass: [
10747 "RootElement"
10748 ],
10749 properties: [
10750 {
10751 name: "name",
10752 isAttr: true,
10753 type: "String"
10754 },
10755 {
10756 name: "resourceParameters",
10757 type: "ResourceParameter",
10758 isMany: true
10759 }
10760 ]
10761 },
10762 {
10763 name: "ResourceParameter",
10764 superClass: [
10765 "BaseElement"
10766 ],
10767 properties: [
10768 {
10769 name: "name",
10770 isAttr: true,
10771 type: "String"
10772 },
10773 {
10774 name: "isRequired",
10775 isAttr: true,
10776 type: "Boolean"
10777 },
10778 {
10779 name: "type",
10780 type: "ItemDefinition",
10781 isAttr: true,
10782 isReference: true
10783 }
10784 ]
10785 },
10786 {
10787 name: "CorrelationSubscription",
10788 superClass: [
10789 "BaseElement"
10790 ],
10791 properties: [
10792 {
10793 name: "correlationKeyRef",
10794 type: "CorrelationKey",
10795 isAttr: true,
10796 isReference: true
10797 },
10798 {
10799 name: "correlationPropertyBinding",
10800 type: "CorrelationPropertyBinding",
10801 isMany: true
10802 }
10803 ]
10804 },
10805 {
10806 name: "MessageFlow",
10807 superClass: [
10808 "BaseElement"
10809 ],
10810 properties: [
10811 {
10812 name: "name",
10813 isAttr: true,
10814 type: "String"
10815 },
10816 {
10817 name: "sourceRef",
10818 type: "InteractionNode",
10819 isAttr: true,
10820 isReference: true
10821 },
10822 {
10823 name: "targetRef",
10824 type: "InteractionNode",
10825 isAttr: true,
10826 isReference: true
10827 },
10828 {
10829 name: "messageRef",
10830 type: "Message",
10831 isAttr: true,
10832 isReference: true
10833 }
10834 ]
10835 },
10836 {
10837 name: "MessageFlowAssociation",
10838 superClass: [
10839 "BaseElement"
10840 ],
10841 properties: [
10842 {
10843 name: "innerMessageFlowRef",
10844 type: "MessageFlow",
10845 isAttr: true,
10846 isReference: true
10847 },
10848 {
10849 name: "outerMessageFlowRef",
10850 type: "MessageFlow",
10851 isAttr: true,
10852 isReference: true
10853 }
10854 ]
10855 },
10856 {
10857 name: "InteractionNode",
10858 isAbstract: true,
10859 properties: [
10860 {
10861 name: "incomingConversationLinks",
10862 type: "ConversationLink",
10863 isVirtual: true,
10864 isMany: true,
10865 isReference: true
10866 },
10867 {
10868 name: "outgoingConversationLinks",
10869 type: "ConversationLink",
10870 isVirtual: true,
10871 isMany: true,
10872 isReference: true
10873 }
10874 ]
10875 },
10876 {
10877 name: "Participant",
10878 superClass: [
10879 "InteractionNode",
10880 "BaseElement"
10881 ],
10882 properties: [
10883 {
10884 name: "name",
10885 isAttr: true,
10886 type: "String"
10887 },
10888 {
10889 name: "interfaceRef",
10890 type: "Interface",
10891 isMany: true,
10892 isReference: true
10893 },
10894 {
10895 name: "participantMultiplicity",
10896 type: "ParticipantMultiplicity"
10897 },
10898 {
10899 name: "endPointRefs",
10900 type: "EndPoint",
10901 isMany: true,
10902 isReference: true
10903 },
10904 {
10905 name: "processRef",
10906 type: "Process",
10907 isAttr: true,
10908 isReference: true
10909 }
10910 ]
10911 },
10912 {
10913 name: "ParticipantAssociation",
10914 superClass: [
10915 "BaseElement"
10916 ],
10917 properties: [
10918 {
10919 name: "innerParticipantRef",
10920 type: "Participant",
10921 isAttr: true,
10922 isReference: true
10923 },
10924 {
10925 name: "outerParticipantRef",
10926 type: "Participant",
10927 isAttr: true,
10928 isReference: true
10929 }
10930 ]
10931 },
10932 {
10933 name: "ParticipantMultiplicity",
10934 properties: [
10935 {
10936 name: "minimum",
10937 "default": 0,
10938 isAttr: true,
10939 type: "Integer"
10940 },
10941 {
10942 name: "maximum",
10943 "default": 1,
10944 isAttr: true,
10945 type: "Integer"
10946 }
10947 ],
10948 superClass: [
10949 "BaseElement"
10950 ]
10951 },
10952 {
10953 name: "Collaboration",
10954 superClass: [
10955 "RootElement"
10956 ],
10957 properties: [
10958 {
10959 name: "name",
10960 isAttr: true,
10961 type: "String"
10962 },
10963 {
10964 name: "isClosed",
10965 isAttr: true,
10966 type: "Boolean"
10967 },
10968 {
10969 name: "participants",
10970 type: "Participant",
10971 isMany: true
10972 },
10973 {
10974 name: "messageFlows",
10975 type: "MessageFlow",
10976 isMany: true
10977 },
10978 {
10979 name: "artifacts",
10980 type: "Artifact",
10981 isMany: true
10982 },
10983 {
10984 name: "conversations",
10985 type: "ConversationNode",
10986 isMany: true
10987 },
10988 {
10989 name: "conversationAssociations",
10990 type: "ConversationAssociation"
10991 },
10992 {
10993 name: "participantAssociations",
10994 type: "ParticipantAssociation",
10995 isMany: true
10996 },
10997 {
10998 name: "messageFlowAssociations",
10999 type: "MessageFlowAssociation",
11000 isMany: true
11001 },
11002 {
11003 name: "correlationKeys",
11004 type: "CorrelationKey",
11005 isMany: true
11006 },
11007 {
11008 name: "choreographyRef",
11009 type: "Choreography",
11010 isMany: true,
11011 isReference: true
11012 },
11013 {
11014 name: "conversationLinks",
11015 type: "ConversationLink",
11016 isMany: true
11017 }
11018 ]
11019 },
11020 {
11021 name: "ChoreographyActivity",
11022 isAbstract: true,
11023 superClass: [
11024 "FlowNode"
11025 ],
11026 properties: [
11027 {
11028 name: "participantRef",
11029 type: "Participant",
11030 isMany: true,
11031 isReference: true
11032 },
11033 {
11034 name: "initiatingParticipantRef",
11035 type: "Participant",
11036 isAttr: true,
11037 isReference: true
11038 },
11039 {
11040 name: "correlationKeys",
11041 type: "CorrelationKey",
11042 isMany: true
11043 },
11044 {
11045 name: "loopType",
11046 type: "ChoreographyLoopType",
11047 "default": "None",
11048 isAttr: true
11049 }
11050 ]
11051 },
11052 {
11053 name: "CallChoreography",
11054 superClass: [
11055 "ChoreographyActivity"
11056 ],
11057 properties: [
11058 {
11059 name: "calledChoreographyRef",
11060 type: "Choreography",
11061 isAttr: true,
11062 isReference: true
11063 },
11064 {
11065 name: "participantAssociations",
11066 type: "ParticipantAssociation",
11067 isMany: true
11068 }
11069 ]
11070 },
11071 {
11072 name: "SubChoreography",
11073 superClass: [
11074 "ChoreographyActivity",
11075 "FlowElementsContainer"
11076 ],
11077 properties: [
11078 {
11079 name: "artifacts",
11080 type: "Artifact",
11081 isMany: true
11082 }
11083 ]
11084 },
11085 {
11086 name: "ChoreographyTask",
11087 superClass: [
11088 "ChoreographyActivity"
11089 ],
11090 properties: [
11091 {
11092 name: "messageFlowRef",
11093 type: "MessageFlow",
11094 isMany: true,
11095 isReference: true
11096 }
11097 ]
11098 },
11099 {
11100 name: "Choreography",
11101 superClass: [
11102 "Collaboration",
11103 "FlowElementsContainer"
11104 ]
11105 },
11106 {
11107 name: "GlobalChoreographyTask",
11108 superClass: [
11109 "Choreography"
11110 ],
11111 properties: [
11112 {
11113 name: "initiatingParticipantRef",
11114 type: "Participant",
11115 isAttr: true,
11116 isReference: true
11117 }
11118 ]
11119 },
11120 {
11121 name: "TextAnnotation",
11122 superClass: [
11123 "Artifact"
11124 ],
11125 properties: [
11126 {
11127 name: "text",
11128 type: "String"
11129 },
11130 {
11131 name: "textFormat",
11132 "default": "text/plain",
11133 isAttr: true,
11134 type: "String"
11135 }
11136 ]
11137 },
11138 {
11139 name: "Group",
11140 superClass: [
11141 "Artifact"
11142 ],
11143 properties: [
11144 {
11145 name: "categoryValueRef",
11146 type: "CategoryValue",
11147 isAttr: true,
11148 isReference: true
11149 }
11150 ]
11151 },
11152 {
11153 name: "Association",
11154 superClass: [
11155 "Artifact"
11156 ],
11157 properties: [
11158 {
11159 name: "associationDirection",
11160 type: "AssociationDirection",
11161 isAttr: true
11162 },
11163 {
11164 name: "sourceRef",
11165 type: "BaseElement",
11166 isAttr: true,
11167 isReference: true
11168 },
11169 {
11170 name: "targetRef",
11171 type: "BaseElement",
11172 isAttr: true,
11173 isReference: true
11174 }
11175 ]
11176 },
11177 {
11178 name: "Category",
11179 superClass: [
11180 "RootElement"
11181 ],
11182 properties: [
11183 {
11184 name: "categoryValue",
11185 type: "CategoryValue",
11186 isMany: true
11187 },
11188 {
11189 name: "name",
11190 isAttr: true,
11191 type: "String"
11192 }
11193 ]
11194 },
11195 {
11196 name: "Artifact",
11197 isAbstract: true,
11198 superClass: [
11199 "BaseElement"
11200 ]
11201 },
11202 {
11203 name: "CategoryValue",
11204 superClass: [
11205 "BaseElement"
11206 ],
11207 properties: [
11208 {
11209 name: "categorizedFlowElements",
11210 type: "FlowElement",
11211 isVirtual: true,
11212 isMany: true,
11213 isReference: true
11214 },
11215 {
11216 name: "value",
11217 isAttr: true,
11218 type: "String"
11219 }
11220 ]
11221 },
11222 {
11223 name: "Activity",
11224 isAbstract: true,
11225 superClass: [
11226 "FlowNode"
11227 ],
11228 properties: [
11229 {
11230 name: "isForCompensation",
11231 "default": false,
11232 isAttr: true,
11233 type: "Boolean"
11234 },
11235 {
11236 name: "default",
11237 type: "SequenceFlow",
11238 isAttr: true,
11239 isReference: true
11240 },
11241 {
11242 name: "ioSpecification",
11243 type: "InputOutputSpecification",
11244 xml: {
11245 serialize: "property"
11246 }
11247 },
11248 {
11249 name: "boundaryEventRefs",
11250 type: "BoundaryEvent",
11251 isMany: true,
11252 isReference: true
11253 },
11254 {
11255 name: "properties",
11256 type: "Property",
11257 isMany: true
11258 },
11259 {
11260 name: "dataInputAssociations",
11261 type: "DataInputAssociation",
11262 isMany: true
11263 },
11264 {
11265 name: "dataOutputAssociations",
11266 type: "DataOutputAssociation",
11267 isMany: true
11268 },
11269 {
11270 name: "startQuantity",
11271 "default": 1,
11272 isAttr: true,
11273 type: "Integer"
11274 },
11275 {
11276 name: "resources",
11277 type: "ResourceRole",
11278 isMany: true
11279 },
11280 {
11281 name: "completionQuantity",
11282 "default": 1,
11283 isAttr: true,
11284 type: "Integer"
11285 },
11286 {
11287 name: "loopCharacteristics",
11288 type: "LoopCharacteristics"
11289 }
11290 ]
11291 },
11292 {
11293 name: "ServiceTask",
11294 superClass: [
11295 "Task"
11296 ],
11297 properties: [
11298 {
11299 name: "implementation",
11300 isAttr: true,
11301 type: "String"
11302 },
11303 {
11304 name: "operationRef",
11305 type: "Operation",
11306 isAttr: true,
11307 isReference: true
11308 }
11309 ]
11310 },
11311 {
11312 name: "SubProcess",
11313 superClass: [
11314 "Activity",
11315 "FlowElementsContainer",
11316 "InteractionNode"
11317 ],
11318 properties: [
11319 {
11320 name: "triggeredByEvent",
11321 "default": false,
11322 isAttr: true,
11323 type: "Boolean"
11324 },
11325 {
11326 name: "artifacts",
11327 type: "Artifact",
11328 isMany: true
11329 }
11330 ]
11331 },
11332 {
11333 name: "LoopCharacteristics",
11334 isAbstract: true,
11335 superClass: [
11336 "BaseElement"
11337 ]
11338 },
11339 {
11340 name: "MultiInstanceLoopCharacteristics",
11341 superClass: [
11342 "LoopCharacteristics"
11343 ],
11344 properties: [
11345 {
11346 name: "isSequential",
11347 "default": false,
11348 isAttr: true,
11349 type: "Boolean"
11350 },
11351 {
11352 name: "behavior",
11353 type: "MultiInstanceBehavior",
11354 "default": "All",
11355 isAttr: true
11356 },
11357 {
11358 name: "loopCardinality",
11359 type: "Expression",
11360 xml: {
11361 serialize: "xsi:type"
11362 }
11363 },
11364 {
11365 name: "loopDataInputRef",
11366 type: "ItemAwareElement",
11367 isReference: true
11368 },
11369 {
11370 name: "loopDataOutputRef",
11371 type: "ItemAwareElement",
11372 isReference: true
11373 },
11374 {
11375 name: "inputDataItem",
11376 type: "DataInput",
11377 xml: {
11378 serialize: "property"
11379 }
11380 },
11381 {
11382 name: "outputDataItem",
11383 type: "DataOutput",
11384 xml: {
11385 serialize: "property"
11386 }
11387 },
11388 {
11389 name: "complexBehaviorDefinition",
11390 type: "ComplexBehaviorDefinition",
11391 isMany: true
11392 },
11393 {
11394 name: "completionCondition",
11395 type: "Expression",
11396 xml: {
11397 serialize: "xsi:type"
11398 }
11399 },
11400 {
11401 name: "oneBehaviorEventRef",
11402 type: "EventDefinition",
11403 isAttr: true,
11404 isReference: true
11405 },
11406 {
11407 name: "noneBehaviorEventRef",
11408 type: "EventDefinition",
11409 isAttr: true,
11410 isReference: true
11411 }
11412 ]
11413 },
11414 {
11415 name: "StandardLoopCharacteristics",
11416 superClass: [
11417 "LoopCharacteristics"
11418 ],
11419 properties: [
11420 {
11421 name: "testBefore",
11422 "default": false,
11423 isAttr: true,
11424 type: "Boolean"
11425 },
11426 {
11427 name: "loopCondition",
11428 type: "Expression",
11429 xml: {
11430 serialize: "xsi:type"
11431 }
11432 },
11433 {
11434 name: "loopMaximum",
11435 type: "Integer",
11436 isAttr: true
11437 }
11438 ]
11439 },
11440 {
11441 name: "CallActivity",
11442 superClass: [
11443 "Activity"
11444 ],
11445 properties: [
11446 {
11447 name: "calledElement",
11448 type: "String",
11449 isAttr: true
11450 }
11451 ]
11452 },
11453 {
11454 name: "Task",
11455 superClass: [
11456 "Activity",
11457 "InteractionNode"
11458 ]
11459 },
11460 {
11461 name: "SendTask",
11462 superClass: [
11463 "Task"
11464 ],
11465 properties: [
11466 {
11467 name: "implementation",
11468 isAttr: true,
11469 type: "String"
11470 },
11471 {
11472 name: "operationRef",
11473 type: "Operation",
11474 isAttr: true,
11475 isReference: true
11476 },
11477 {
11478 name: "messageRef",
11479 type: "Message",
11480 isAttr: true,
11481 isReference: true
11482 }
11483 ]
11484 },
11485 {
11486 name: "ReceiveTask",
11487 superClass: [
11488 "Task"
11489 ],
11490 properties: [
11491 {
11492 name: "implementation",
11493 isAttr: true,
11494 type: "String"
11495 },
11496 {
11497 name: "instantiate",
11498 "default": false,
11499 isAttr: true,
11500 type: "Boolean"
11501 },
11502 {
11503 name: "operationRef",
11504 type: "Operation",
11505 isAttr: true,
11506 isReference: true
11507 },
11508 {
11509 name: "messageRef",
11510 type: "Message",
11511 isAttr: true,
11512 isReference: true
11513 }
11514 ]
11515 },
11516 {
11517 name: "ScriptTask",
11518 superClass: [
11519 "Task"
11520 ],
11521 properties: [
11522 {
11523 name: "scriptFormat",
11524 isAttr: true,
11525 type: "String"
11526 },
11527 {
11528 name: "script",
11529 type: "String"
11530 }
11531 ]
11532 },
11533 {
11534 name: "BusinessRuleTask",
11535 superClass: [
11536 "Task"
11537 ],
11538 properties: [
11539 {
11540 name: "implementation",
11541 isAttr: true,
11542 type: "String"
11543 }
11544 ]
11545 },
11546 {
11547 name: "AdHocSubProcess",
11548 superClass: [
11549 "SubProcess"
11550 ],
11551 properties: [
11552 {
11553 name: "completionCondition",
11554 type: "Expression",
11555 xml: {
11556 serialize: "xsi:type"
11557 }
11558 },
11559 {
11560 name: "ordering",
11561 type: "AdHocOrdering",
11562 isAttr: true
11563 },
11564 {
11565 name: "cancelRemainingInstances",
11566 "default": true,
11567 isAttr: true,
11568 type: "Boolean"
11569 }
11570 ]
11571 },
11572 {
11573 name: "Transaction",
11574 superClass: [
11575 "SubProcess"
11576 ],
11577 properties: [
11578 {
11579 name: "protocol",
11580 isAttr: true,
11581 type: "String"
11582 },
11583 {
11584 name: "method",
11585 isAttr: true,
11586 type: "String"
11587 }
11588 ]
11589 },
11590 {
11591 name: "GlobalScriptTask",
11592 superClass: [
11593 "GlobalTask"
11594 ],
11595 properties: [
11596 {
11597 name: "scriptLanguage",
11598 isAttr: true,
11599 type: "String"
11600 },
11601 {
11602 name: "script",
11603 isAttr: true,
11604 type: "String"
11605 }
11606 ]
11607 },
11608 {
11609 name: "GlobalBusinessRuleTask",
11610 superClass: [
11611 "GlobalTask"
11612 ],
11613 properties: [
11614 {
11615 name: "implementation",
11616 isAttr: true,
11617 type: "String"
11618 }
11619 ]
11620 },
11621 {
11622 name: "ComplexBehaviorDefinition",
11623 superClass: [
11624 "BaseElement"
11625 ],
11626 properties: [
11627 {
11628 name: "condition",
11629 type: "FormalExpression"
11630 },
11631 {
11632 name: "event",
11633 type: "ImplicitThrowEvent"
11634 }
11635 ]
11636 },
11637 {
11638 name: "ResourceRole",
11639 superClass: [
11640 "BaseElement"
11641 ],
11642 properties: [
11643 {
11644 name: "resourceRef",
11645 type: "Resource",
11646 isReference: true
11647 },
11648 {
11649 name: "resourceParameterBindings",
11650 type: "ResourceParameterBinding",
11651 isMany: true
11652 },
11653 {
11654 name: "resourceAssignmentExpression",
11655 type: "ResourceAssignmentExpression"
11656 },
11657 {
11658 name: "name",
11659 isAttr: true,
11660 type: "String"
11661 }
11662 ]
11663 },
11664 {
11665 name: "ResourceParameterBinding",
11666 properties: [
11667 {
11668 name: "expression",
11669 type: "Expression",
11670 xml: {
11671 serialize: "xsi:type"
11672 }
11673 },
11674 {
11675 name: "parameterRef",
11676 type: "ResourceParameter",
11677 isAttr: true,
11678 isReference: true
11679 }
11680 ],
11681 superClass: [
11682 "BaseElement"
11683 ]
11684 },
11685 {
11686 name: "ResourceAssignmentExpression",
11687 properties: [
11688 {
11689 name: "expression",
11690 type: "Expression",
11691 xml: {
11692 serialize: "xsi:type"
11693 }
11694 }
11695 ],
11696 superClass: [
11697 "BaseElement"
11698 ]
11699 },
11700 {
11701 name: "Import",
11702 properties: [
11703 {
11704 name: "importType",
11705 isAttr: true,
11706 type: "String"
11707 },
11708 {
11709 name: "location",
11710 isAttr: true,
11711 type: "String"
11712 },
11713 {
11714 name: "namespace",
11715 isAttr: true,
11716 type: "String"
11717 }
11718 ]
11719 },
11720 {
11721 name: "Definitions",
11722 superClass: [
11723 "BaseElement"
11724 ],
11725 properties: [
11726 {
11727 name: "name",
11728 isAttr: true,
11729 type: "String"
11730 },
11731 {
11732 name: "targetNamespace",
11733 isAttr: true,
11734 type: "String"
11735 },
11736 {
11737 name: "expressionLanguage",
11738 "default": "http://www.w3.org/1999/XPath",
11739 isAttr: true,
11740 type: "String"
11741 },
11742 {
11743 name: "typeLanguage",
11744 "default": "http://www.w3.org/2001/XMLSchema",
11745 isAttr: true,
11746 type: "String"
11747 },
11748 {
11749 name: "imports",
11750 type: "Import",
11751 isMany: true
11752 },
11753 {
11754 name: "extensions",
11755 type: "Extension",
11756 isMany: true
11757 },
11758 {
11759 name: "rootElements",
11760 type: "RootElement",
11761 isMany: true
11762 },
11763 {
11764 name: "diagrams",
11765 isMany: true,
11766 type: "bpmndi:BPMNDiagram"
11767 },
11768 {
11769 name: "exporter",
11770 isAttr: true,
11771 type: "String"
11772 },
11773 {
11774 name: "relationships",
11775 type: "Relationship",
11776 isMany: true
11777 },
11778 {
11779 name: "exporterVersion",
11780 isAttr: true,
11781 type: "String"
11782 }
11783 ]
11784 }
11785 ];
11786 var enumerations = [
11787 {
11788 name: "ProcessType",
11789 literalValues: [
11790 {
11791 name: "None"
11792 },
11793 {
11794 name: "Public"
11795 },
11796 {
11797 name: "Private"
11798 }
11799 ]
11800 },
11801 {
11802 name: "GatewayDirection",
11803 literalValues: [
11804 {
11805 name: "Unspecified"
11806 },
11807 {
11808 name: "Converging"
11809 },
11810 {
11811 name: "Diverging"
11812 },
11813 {
11814 name: "Mixed"
11815 }
11816 ]
11817 },
11818 {
11819 name: "EventBasedGatewayType",
11820 literalValues: [
11821 {
11822 name: "Parallel"
11823 },
11824 {
11825 name: "Exclusive"
11826 }
11827 ]
11828 },
11829 {
11830 name: "RelationshipDirection",
11831 literalValues: [
11832 {
11833 name: "None"
11834 },
11835 {
11836 name: "Forward"
11837 },
11838 {
11839 name: "Backward"
11840 },
11841 {
11842 name: "Both"
11843 }
11844 ]
11845 },
11846 {
11847 name: "ItemKind",
11848 literalValues: [
11849 {
11850 name: "Physical"
11851 },
11852 {
11853 name: "Information"
11854 }
11855 ]
11856 },
11857 {
11858 name: "ChoreographyLoopType",
11859 literalValues: [
11860 {
11861 name: "None"
11862 },
11863 {
11864 name: "Standard"
11865 },
11866 {
11867 name: "MultiInstanceSequential"
11868 },
11869 {
11870 name: "MultiInstanceParallel"
11871 }
11872 ]
11873 },
11874 {
11875 name: "AssociationDirection",
11876 literalValues: [
11877 {
11878 name: "None"
11879 },
11880 {
11881 name: "One"
11882 },
11883 {
11884 name: "Both"
11885 }
11886 ]
11887 },
11888 {
11889 name: "MultiInstanceBehavior",
11890 literalValues: [
11891 {
11892 name: "None"
11893 },
11894 {
11895 name: "One"
11896 },
11897 {
11898 name: "All"
11899 },
11900 {
11901 name: "Complex"
11902 }
11903 ]
11904 },
11905 {
11906 name: "AdHocOrdering",
11907 literalValues: [
11908 {
11909 name: "Parallel"
11910 },
11911 {
11912 name: "Sequential"
11913 }
11914 ]
11915 }
11916 ];
11917 var prefix$1 = "bpmn";
11918 var xml = {
11919 tagAlias: "lowerCase",
11920 typePrefix: "t"
11921 };
11922 var BpmnPackage = {
11923 name: name,
11924 uri: uri,
11925 associations: associations,
11926 types: types$1,
11927 enumerations: enumerations,
11928 prefix: prefix$1,
11929 xml: xml
11930 };
11931
11932 var name$1 = "BPMNDI";
11933 var uri$1 = "http://www.omg.org/spec/BPMN/20100524/DI";
11934 var types$1$1 = [
11935 {
11936 name: "BPMNDiagram",
11937 properties: [
11938 {
11939 name: "plane",
11940 type: "BPMNPlane",
11941 redefines: "di:Diagram#rootElement"
11942 },
11943 {
11944 name: "labelStyle",
11945 type: "BPMNLabelStyle",
11946 isMany: true
11947 }
11948 ],
11949 superClass: [
11950 "di:Diagram"
11951 ]
11952 },
11953 {
11954 name: "BPMNPlane",
11955 properties: [
11956 {
11957 name: "bpmnElement",
11958 isAttr: true,
11959 isReference: true,
11960 type: "bpmn:BaseElement",
11961 redefines: "di:DiagramElement#modelElement"
11962 }
11963 ],
11964 superClass: [
11965 "di:Plane"
11966 ]
11967 },
11968 {
11969 name: "BPMNShape",
11970 properties: [
11971 {
11972 name: "bpmnElement",
11973 isAttr: true,
11974 isReference: true,
11975 type: "bpmn:BaseElement",
11976 redefines: "di:DiagramElement#modelElement"
11977 },
11978 {
11979 name: "isHorizontal",
11980 isAttr: true,
11981 type: "Boolean"
11982 },
11983 {
11984 name: "isExpanded",
11985 isAttr: true,
11986 type: "Boolean"
11987 },
11988 {
11989 name: "isMarkerVisible",
11990 isAttr: true,
11991 type: "Boolean"
11992 },
11993 {
11994 name: "label",
11995 type: "BPMNLabel"
11996 },
11997 {
11998 name: "isMessageVisible",
11999 isAttr: true,
12000 type: "Boolean"
12001 },
12002 {
12003 name: "participantBandKind",
12004 type: "ParticipantBandKind",
12005 isAttr: true
12006 },
12007 {
12008 name: "choreographyActivityShape",
12009 type: "BPMNShape",
12010 isAttr: true,
12011 isReference: true
12012 }
12013 ],
12014 superClass: [
12015 "di:LabeledShape"
12016 ]
12017 },
12018 {
12019 name: "BPMNEdge",
12020 properties: [
12021 {
12022 name: "label",
12023 type: "BPMNLabel"
12024 },
12025 {
12026 name: "bpmnElement",
12027 isAttr: true,
12028 isReference: true,
12029 type: "bpmn:BaseElement",
12030 redefines: "di:DiagramElement#modelElement"
12031 },
12032 {
12033 name: "sourceElement",
12034 isAttr: true,
12035 isReference: true,
12036 type: "di:DiagramElement",
12037 redefines: "di:Edge#source"
12038 },
12039 {
12040 name: "targetElement",
12041 isAttr: true,
12042 isReference: true,
12043 type: "di:DiagramElement",
12044 redefines: "di:Edge#target"
12045 },
12046 {
12047 name: "messageVisibleKind",
12048 type: "MessageVisibleKind",
12049 isAttr: true,
12050 "default": "initiating"
12051 }
12052 ],
12053 superClass: [
12054 "di:LabeledEdge"
12055 ]
12056 },
12057 {
12058 name: "BPMNLabel",
12059 properties: [
12060 {
12061 name: "labelStyle",
12062 type: "BPMNLabelStyle",
12063 isAttr: true,
12064 isReference: true,
12065 redefines: "di:DiagramElement#style"
12066 }
12067 ],
12068 superClass: [
12069 "di:Label"
12070 ]
12071 },
12072 {
12073 name: "BPMNLabelStyle",
12074 properties: [
12075 {
12076 name: "font",
12077 type: "dc:Font"
12078 }
12079 ],
12080 superClass: [
12081 "di:Style"
12082 ]
12083 }
12084 ];
12085 var enumerations$1 = [
12086 {
12087 name: "ParticipantBandKind",
12088 literalValues: [
12089 {
12090 name: "top_initiating"
12091 },
12092 {
12093 name: "middle_initiating"
12094 },
12095 {
12096 name: "bottom_initiating"
12097 },
12098 {
12099 name: "top_non_initiating"
12100 },
12101 {
12102 name: "middle_non_initiating"
12103 },
12104 {
12105 name: "bottom_non_initiating"
12106 }
12107 ]
12108 },
12109 {
12110 name: "MessageVisibleKind",
12111 literalValues: [
12112 {
12113 name: "initiating"
12114 },
12115 {
12116 name: "non_initiating"
12117 }
12118 ]
12119 }
12120 ];
12121 var associations$1 = [
12122 ];
12123 var prefix$1$1 = "bpmndi";
12124 var BpmnDiPackage = {
12125 name: name$1,
12126 uri: uri$1,
12127 types: types$1$1,
12128 enumerations: enumerations$1,
12129 associations: associations$1,
12130 prefix: prefix$1$1
12131 };
12132
12133 var name$2 = "DC";
12134 var uri$2 = "http://www.omg.org/spec/DD/20100524/DC";
12135 var types$2 = [
12136 {
12137 name: "Boolean"
12138 },
12139 {
12140 name: "Integer"
12141 },
12142 {
12143 name: "Real"
12144 },
12145 {
12146 name: "String"
12147 },
12148 {
12149 name: "Font",
12150 properties: [
12151 {
12152 name: "name",
12153 type: "String",
12154 isAttr: true
12155 },
12156 {
12157 name: "size",
12158 type: "Real",
12159 isAttr: true
12160 },
12161 {
12162 name: "isBold",
12163 type: "Boolean",
12164 isAttr: true
12165 },
12166 {
12167 name: "isItalic",
12168 type: "Boolean",
12169 isAttr: true
12170 },
12171 {
12172 name: "isUnderline",
12173 type: "Boolean",
12174 isAttr: true
12175 },
12176 {
12177 name: "isStrikeThrough",
12178 type: "Boolean",
12179 isAttr: true
12180 }
12181 ]
12182 },
12183 {
12184 name: "Point",
12185 properties: [
12186 {
12187 name: "x",
12188 type: "Real",
12189 "default": "0",
12190 isAttr: true
12191 },
12192 {
12193 name: "y",
12194 type: "Real",
12195 "default": "0",
12196 isAttr: true
12197 }
12198 ]
12199 },
12200 {
12201 name: "Bounds",
12202 properties: [
12203 {
12204 name: "x",
12205 type: "Real",
12206 "default": "0",
12207 isAttr: true
12208 },
12209 {
12210 name: "y",
12211 type: "Real",
12212 "default": "0",
12213 isAttr: true
12214 },
12215 {
12216 name: "width",
12217 type: "Real",
12218 isAttr: true
12219 },
12220 {
12221 name: "height",
12222 type: "Real",
12223 isAttr: true
12224 }
12225 ]
12226 }
12227 ];
12228 var prefix$2 = "dc";
12229 var associations$2 = [
12230 ];
12231 var DcPackage = {
12232 name: name$2,
12233 uri: uri$2,
12234 types: types$2,
12235 prefix: prefix$2,
12236 associations: associations$2
12237 };
12238
12239 var name$3 = "DI";
12240 var uri$3 = "http://www.omg.org/spec/DD/20100524/DI";
12241 var types$3 = [
12242 {
12243 name: "DiagramElement",
12244 isAbstract: true,
12245 properties: [
12246 {
12247 name: "id",
12248 type: "String",
12249 isAttr: true,
12250 isId: true
12251 },
12252 {
12253 name: "extension",
12254 type: "Extension"
12255 },
12256 {
12257 name: "owningDiagram",
12258 type: "Diagram",
12259 isReadOnly: true,
12260 isVirtual: true,
12261 isReference: true
12262 },
12263 {
12264 name: "owningElement",
12265 type: "DiagramElement",
12266 isReadOnly: true,
12267 isVirtual: true,
12268 isReference: true
12269 },
12270 {
12271 name: "modelElement",
12272 isReadOnly: true,
12273 isVirtual: true,
12274 isReference: true,
12275 type: "Element"
12276 },
12277 {
12278 name: "style",
12279 type: "Style",
12280 isReadOnly: true,
12281 isVirtual: true,
12282 isReference: true
12283 },
12284 {
12285 name: "ownedElement",
12286 type: "DiagramElement",
12287 isReadOnly: true,
12288 isVirtual: true,
12289 isMany: true
12290 }
12291 ]
12292 },
12293 {
12294 name: "Node",
12295 isAbstract: true,
12296 superClass: [
12297 "DiagramElement"
12298 ]
12299 },
12300 {
12301 name: "Edge",
12302 isAbstract: true,
12303 superClass: [
12304 "DiagramElement"
12305 ],
12306 properties: [
12307 {
12308 name: "source",
12309 type: "DiagramElement",
12310 isReadOnly: true,
12311 isVirtual: true,
12312 isReference: true
12313 },
12314 {
12315 name: "target",
12316 type: "DiagramElement",
12317 isReadOnly: true,
12318 isVirtual: true,
12319 isReference: true
12320 },
12321 {
12322 name: "waypoint",
12323 isUnique: false,
12324 isMany: true,
12325 type: "dc:Point",
12326 xml: {
12327 serialize: "xsi:type"
12328 }
12329 }
12330 ]
12331 },
12332 {
12333 name: "Diagram",
12334 isAbstract: true,
12335 properties: [
12336 {
12337 name: "id",
12338 type: "String",
12339 isAttr: true,
12340 isId: true
12341 },
12342 {
12343 name: "rootElement",
12344 type: "DiagramElement",
12345 isReadOnly: true,
12346 isVirtual: true
12347 },
12348 {
12349 name: "name",
12350 isAttr: true,
12351 type: "String"
12352 },
12353 {
12354 name: "documentation",
12355 isAttr: true,
12356 type: "String"
12357 },
12358 {
12359 name: "resolution",
12360 isAttr: true,
12361 type: "Real"
12362 },
12363 {
12364 name: "ownedStyle",
12365 type: "Style",
12366 isReadOnly: true,
12367 isVirtual: true,
12368 isMany: true
12369 }
12370 ]
12371 },
12372 {
12373 name: "Shape",
12374 isAbstract: true,
12375 superClass: [
12376 "Node"
12377 ],
12378 properties: [
12379 {
12380 name: "bounds",
12381 type: "dc:Bounds"
12382 }
12383 ]
12384 },
12385 {
12386 name: "Plane",
12387 isAbstract: true,
12388 superClass: [
12389 "Node"
12390 ],
12391 properties: [
12392 {
12393 name: "planeElement",
12394 type: "DiagramElement",
12395 subsettedProperty: "DiagramElement-ownedElement",
12396 isMany: true
12397 }
12398 ]
12399 },
12400 {
12401 name: "LabeledEdge",
12402 isAbstract: true,
12403 superClass: [
12404 "Edge"
12405 ],
12406 properties: [
12407 {
12408 name: "ownedLabel",
12409 type: "Label",
12410 isReadOnly: true,
12411 subsettedProperty: "DiagramElement-ownedElement",
12412 isVirtual: true,
12413 isMany: true
12414 }
12415 ]
12416 },
12417 {
12418 name: "LabeledShape",
12419 isAbstract: true,
12420 superClass: [
12421 "Shape"
12422 ],
12423 properties: [
12424 {
12425 name: "ownedLabel",
12426 type: "Label",
12427 isReadOnly: true,
12428 subsettedProperty: "DiagramElement-ownedElement",
12429 isVirtual: true,
12430 isMany: true
12431 }
12432 ]
12433 },
12434 {
12435 name: "Label",
12436 isAbstract: true,
12437 superClass: [
12438 "Node"
12439 ],
12440 properties: [
12441 {
12442 name: "bounds",
12443 type: "dc:Bounds"
12444 }
12445 ]
12446 },
12447 {
12448 name: "Style",
12449 isAbstract: true,
12450 properties: [
12451 {
12452 name: "id",
12453 type: "String",
12454 isAttr: true,
12455 isId: true
12456 }
12457 ]
12458 },
12459 {
12460 name: "Extension",
12461 properties: [
12462 {
12463 name: "values",
12464 type: "Element",
12465 isMany: true
12466 }
12467 ]
12468 }
12469 ];
12470 var associations$3 = [
12471 ];
12472 var prefix$3 = "di";
12473 var xml$1 = {
12474 tagAlias: "lowerCase"
12475 };
12476 var DiPackage = {
12477 name: name$3,
12478 uri: uri$3,
12479 types: types$3,
12480 associations: associations$3,
12481 prefix: prefix$3,
12482 xml: xml$1
12483 };
12484
12485 var name$4 = "bpmn.io colors for BPMN";
12486 var uri$4 = "http://bpmn.io/schema/bpmn/biocolor/1.0";
12487 var prefix$4 = "bioc";
12488 var types$4 = [
12489 {
12490 name: "ColoredShape",
12491 "extends": [
12492 "bpmndi:BPMNShape"
12493 ],
12494 properties: [
12495 {
12496 name: "stroke",
12497 isAttr: true,
12498 type: "String"
12499 },
12500 {
12501 name: "fill",
12502 isAttr: true,
12503 type: "String"
12504 }
12505 ]
12506 },
12507 {
12508 name: "ColoredEdge",
12509 "extends": [
12510 "bpmndi:BPMNEdge"
12511 ],
12512 properties: [
12513 {
12514 name: "stroke",
12515 isAttr: true,
12516 type: "String"
12517 },
12518 {
12519 name: "fill",
12520 isAttr: true,
12521 type: "String"
12522 }
12523 ]
12524 }
12525 ];
12526 var enumerations$2 = [
12527 ];
12528 var associations$4 = [
12529 ];
12530 var BiocPackage = {
12531 name: name$4,
12532 uri: uri$4,
12533 prefix: prefix$4,
12534 types: types$4,
12535 enumerations: enumerations$2,
12536 associations: associations$4
12537 };
12538
12539 var packages = {
12540 bpmn: BpmnPackage,
12541 bpmndi: BpmnDiPackage,
12542 dc: DcPackage,
12543 di: DiPackage,
12544 bioc: BiocPackage
12545 };
12546
12547 function simple(additionalPackages, options) {
12548 var pks = assign({}, packages, additionalPackages);
12549
12550 return new BpmnModdle(pks, options);
12551 }
12552
12553 function elementToString(e) {
12554 if (!e) {
12555 return '<null>';
12556 }
12557
12558 return '<' + e.$type + (e.id ? ' id="' + e.id : '') + '" />';
12559 }
12560
12561 var diRefs = new objectRefs(
12562 { name: 'bpmnElement', enumerable: true },
12563 { name: 'di', configurable: true }
12564 );
12565
12566 /**
12567 * Returns true if an element has the given meta-model type
12568 *
12569 * @param {ModdleElement} element
12570 * @param {String} type
12571 *
12572 * @return {Boolean}
12573 */
12574 function is(element, type) {
12575 return element.$instanceOf(type);
12576 }
12577
12578
12579 /**
12580 * Find a suitable display candidate for definitions where the DI does not
12581 * correctly specify one.
12582 */
12583 function findDisplayCandidate(definitions) {
12584 return find(definitions.rootElements, function(e) {
12585 return is(e, 'bpmn:Process') || is(e, 'bpmn:Collaboration');
12586 });
12587 }
12588
12589
12590 function BpmnTreeWalker(handler, translate) {
12591
12592 // list of containers already walked
12593 var handledElements = {};
12594
12595 // list of elements to handle deferred to ensure
12596 // prerequisites are drawn
12597 var deferred = [];
12598
12599 // Helpers //////////////////////
12600
12601 function contextual(fn, ctx) {
12602 return function(e) {
12603 fn(e, ctx);
12604 };
12605 }
12606
12607 function handled(element) {
12608 handledElements[element.id] = element;
12609 }
12610
12611 function isHandled(element) {
12612 return handledElements[element.id];
12613 }
12614
12615 function visit(element, ctx) {
12616
12617 var gfx = element.gfx;
12618
12619 // avoid multiple rendering of elements
12620 if (gfx) {
12621 throw new Error(
12622 translate('already rendered {element}', { element: elementToString(element) })
12623 );
12624 }
12625
12626 // call handler
12627 return handler.element(element, ctx);
12628 }
12629
12630 function visitRoot(element, diagram) {
12631 return handler.root(element, diagram);
12632 }
12633
12634 function visitIfDi(element, ctx) {
12635
12636 try {
12637 var gfx = element.di && visit(element, ctx);
12638
12639 handled(element);
12640
12641 return gfx;
12642 } catch (e) {
12643 logError(e.message, { element: element, error: e });
12644
12645 console.error(translate('failed to import {element}', { element: elementToString(element) }));
12646 console.error(e);
12647 }
12648 }
12649
12650 function logError(message, context) {
12651 handler.error(message, context);
12652 }
12653
12654 // DI handling //////////////////////
12655
12656 function registerDi(di) {
12657 var bpmnElement = di.bpmnElement;
12658
12659 if (bpmnElement) {
12660 if (bpmnElement.di) {
12661 logError(
12662 translate('multiple DI elements defined for {element}', {
12663 element: elementToString(bpmnElement)
12664 }),
12665 { element: bpmnElement }
12666 );
12667 } else {
12668 diRefs.bind(bpmnElement, 'di');
12669 bpmnElement.di = di;
12670 }
12671 } else {
12672 logError(
12673 translate('no bpmnElement referenced in {element}', {
12674 element: elementToString(di)
12675 }),
12676 { element: di }
12677 );
12678 }
12679 }
12680
12681 function handleDiagram(diagram) {
12682 handlePlane(diagram.plane);
12683 }
12684
12685 function handlePlane(plane) {
12686 registerDi(plane);
12687
12688 forEach(plane.planeElement, handlePlaneElement);
12689 }
12690
12691 function handlePlaneElement(planeElement) {
12692 registerDi(planeElement);
12693 }
12694
12695
12696 // Semantic handling //////////////////////
12697
12698 /**
12699 * Handle definitions and return the rendered diagram (if any)
12700 *
12701 * @param {ModdleElement} definitions to walk and import
12702 * @param {ModdleElement} [diagram] specific diagram to import and display
12703 *
12704 * @throws {Error} if no diagram to display could be found
12705 */
12706 function handleDefinitions(definitions, diagram) {
12707
12708 // make sure we walk the correct bpmnElement
12709
12710 var diagrams = definitions.diagrams;
12711
12712 if (diagram && diagrams.indexOf(diagram) === -1) {
12713 throw new Error(translate('diagram not part of bpmn:Definitions'));
12714 }
12715
12716 if (!diagram && diagrams && diagrams.length) {
12717 diagram = diagrams[0];
12718 }
12719
12720 // no diagram -> nothing to import
12721 if (!diagram) {
12722 throw new Error(translate('no diagram to display'));
12723 }
12724
12725 // load DI from selected diagram only
12726 handleDiagram(diagram);
12727
12728
12729 var plane = diagram.plane;
12730
12731 if (!plane) {
12732 throw new Error(translate(
12733 'no plane for {element}',
12734 { element: elementToString(diagram) }
12735 ));
12736 }
12737
12738 var rootElement = plane.bpmnElement;
12739
12740 // ensure we default to a suitable display candidate (process or collaboration),
12741 // even if non is specified in DI
12742 if (!rootElement) {
12743 rootElement = findDisplayCandidate(definitions);
12744
12745 if (!rootElement) {
12746 throw new Error(translate('no process or collaboration to display'));
12747 } else {
12748
12749 logError(
12750 translate('correcting missing bpmnElement on {plane} to {rootElement}', {
12751 plane: elementToString(plane),
12752 rootElement: elementToString(rootElement)
12753 })
12754 );
12755
12756 // correct DI on the fly
12757 plane.bpmnElement = rootElement;
12758 registerDi(plane);
12759 }
12760 }
12761
12762
12763 var ctx = visitRoot(rootElement, plane);
12764
12765 if (is(rootElement, 'bpmn:Process')) {
12766 handleProcess(rootElement, ctx);
12767 } else if (is(rootElement, 'bpmn:Collaboration')) {
12768 handleCollaboration(rootElement);
12769
12770 // force drawing of everything not yet drawn that is part of the target DI
12771 handleUnhandledProcesses(definitions.rootElements, ctx);
12772 } else {
12773 throw new Error(
12774 translate('unsupported bpmnElement for {plane}: {rootElement}', {
12775 plane: elementToString(plane),
12776 rootElement: elementToString(rootElement)
12777 })
12778 );
12779 }
12780
12781 // handle all deferred elements
12782 handleDeferred();
12783 }
12784
12785 function handleDeferred() {
12786
12787 var fn;
12788
12789 // drain deferred until empty
12790 while (deferred.length) {
12791 fn = deferred.shift();
12792
12793 fn();
12794 }
12795 }
12796
12797 function handleProcess(process, context) {
12798 handleFlowElementsContainer(process, context);
12799 handleIoSpecification(process.ioSpecification, context);
12800
12801 handleArtifacts(process.artifacts, context);
12802
12803 // log process handled
12804 handled(process);
12805 }
12806
12807 function handleUnhandledProcesses(rootElements, ctx) {
12808
12809 // walk through all processes that have not yet been drawn and draw them
12810 // if they contain lanes with DI information.
12811 // we do this to pass the free-floating lane test cases in the MIWG test suite
12812 var processes = filter(rootElements, function(e) {
12813 return !isHandled(e) && is(e, 'bpmn:Process') && e.laneSets;
12814 });
12815
12816 processes.forEach(contextual(handleProcess, ctx));
12817 }
12818
12819 function handleMessageFlow(messageFlow, context) {
12820 visitIfDi(messageFlow, context);
12821 }
12822
12823 function handleMessageFlows(messageFlows, context) {
12824 forEach(messageFlows, contextual(handleMessageFlow, context));
12825 }
12826
12827 function handleDataAssociation(association, context) {
12828 visitIfDi(association, context);
12829 }
12830
12831 function handleDataInput(dataInput, context) {
12832 visitIfDi(dataInput, context);
12833 }
12834
12835 function handleDataOutput(dataOutput, context) {
12836 visitIfDi(dataOutput, context);
12837 }
12838
12839 function handleArtifact(artifact, context) {
12840
12841 // bpmn:TextAnnotation
12842 // bpmn:Group
12843 // bpmn:Association
12844
12845 visitIfDi(artifact, context);
12846 }
12847
12848 function handleArtifacts(artifacts, context) {
12849
12850 forEach(artifacts, function(e) {
12851 if (is(e, 'bpmn:Association')) {
12852 deferred.push(function() {
12853 handleArtifact(e, context);
12854 });
12855 } else {
12856 handleArtifact(e, context);
12857 }
12858 });
12859 }
12860
12861 function handleIoSpecification(ioSpecification, context) {
12862
12863 if (!ioSpecification) {
12864 return;
12865 }
12866
12867 forEach(ioSpecification.dataInputs, contextual(handleDataInput, context));
12868 forEach(ioSpecification.dataOutputs, contextual(handleDataOutput, context));
12869 }
12870
12871 function handleSubProcess(subProcess, context) {
12872 handleFlowElementsContainer(subProcess, context);
12873 handleArtifacts(subProcess.artifacts, context);
12874 }
12875
12876 function handleFlowNode(flowNode, context) {
12877 var childCtx = visitIfDi(flowNode, context);
12878
12879 if (is(flowNode, 'bpmn:SubProcess')) {
12880 handleSubProcess(flowNode, childCtx || context);
12881 }
12882
12883 if (is(flowNode, 'bpmn:Activity')) {
12884 handleIoSpecification(flowNode.ioSpecification, context);
12885 }
12886
12887 // defer handling of associations
12888 // affected types:
12889 //
12890 // * bpmn:Activity
12891 // * bpmn:ThrowEvent
12892 // * bpmn:CatchEvent
12893 //
12894 deferred.push(function() {
12895 forEach(flowNode.dataInputAssociations, contextual(handleDataAssociation, context));
12896 forEach(flowNode.dataOutputAssociations, contextual(handleDataAssociation, context));
12897 });
12898 }
12899
12900 function handleSequenceFlow(sequenceFlow, context) {
12901 visitIfDi(sequenceFlow, context);
12902 }
12903
12904 function handleDataElement(dataObject, context) {
12905 visitIfDi(dataObject, context);
12906 }
12907
12908 function handleLane(lane, context) {
12909
12910 deferred.push(function() {
12911
12912 var newContext = visitIfDi(lane, context);
12913
12914 if (lane.childLaneSet) {
12915 handleLaneSet(lane.childLaneSet, newContext || context);
12916 }
12917
12918 wireFlowNodeRefs(lane);
12919 });
12920 }
12921
12922 function handleLaneSet(laneSet, context) {
12923 forEach(laneSet.lanes, contextual(handleLane, context));
12924 }
12925
12926 function handleLaneSets(laneSets, context) {
12927 forEach(laneSets, contextual(handleLaneSet, context));
12928 }
12929
12930 function handleFlowElementsContainer(container, context) {
12931 handleFlowElements(container.flowElements, context);
12932
12933 if (container.laneSets) {
12934 handleLaneSets(container.laneSets, context);
12935 }
12936 }
12937
12938 function handleFlowElements(flowElements, context) {
12939 forEach(flowElements, function(e) {
12940 if (is(e, 'bpmn:SequenceFlow')) {
12941 deferred.push(function() {
12942 handleSequenceFlow(e, context);
12943 });
12944 } else if (is(e, 'bpmn:BoundaryEvent')) {
12945 deferred.unshift(function() {
12946 handleFlowNode(e, context);
12947 });
12948 } else if (is(e, 'bpmn:FlowNode')) {
12949 handleFlowNode(e, context);
12950 } else if (is(e, 'bpmn:DataObject')) ; else if (is(e, 'bpmn:DataStoreReference')) {
12951 handleDataElement(e, context);
12952 } else if (is(e, 'bpmn:DataObjectReference')) {
12953 handleDataElement(e, context);
12954 } else {
12955 logError(
12956 translate('unrecognized flowElement {element} in context {context}', {
12957 element: elementToString(e),
12958 context: (context ? elementToString(context.businessObject) : 'null')
12959 }),
12960 { element: e, context: context }
12961 );
12962 }
12963 });
12964 }
12965
12966 function handleParticipant(participant, context) {
12967 var newCtx = visitIfDi(participant, context);
12968
12969 var process = participant.processRef;
12970 if (process) {
12971 handleProcess(process, newCtx || context);
12972 }
12973 }
12974
12975 function handleCollaboration(collaboration) {
12976
12977 forEach(collaboration.participants, contextual(handleParticipant));
12978
12979 handleArtifacts(collaboration.artifacts);
12980
12981 // handle message flows latest in the process
12982 deferred.push(function() {
12983 handleMessageFlows(collaboration.messageFlows);
12984 });
12985 }
12986
12987
12988 function wireFlowNodeRefs(lane) {
12989
12990 // wire the virtual flowNodeRefs <-> relationship
12991 forEach(lane.flowNodeRef, function(flowNode) {
12992 var lanes = flowNode.get('lanes');
12993
12994 if (lanes) {
12995 lanes.push(lane);
12996 }
12997 });
12998 }
12999
13000 // API //////////////////////
13001
13002 return {
13003 handleDeferred: handleDeferred,
13004 handleDefinitions: handleDefinitions,
13005 handleSubProcess: handleSubProcess,
13006 registerDi: registerDi
13007 };
13008 }
13009
13010 /**
13011 * Import the definitions into a diagram.
13012 *
13013 * Errors and warnings are reported through the specified callback.
13014 *
13015 * @param {djs.Diagram} diagram
13016 * @param {ModdleElement<Definitions>} definitions
13017 * @param {ModdleElement<BPMNDiagram>} [bpmnDiagram] the diagram to be rendered
13018 * (if not provided, the first one will be rendered)
13019 * @param {Function} done the callback, invoked with (err, [ warning ]) once the import is done
13020 */
13021 function importBpmnDiagram(diagram, definitions, bpmnDiagram, done) {
13022
13023 if (isFunction(bpmnDiagram)) {
13024 done = bpmnDiagram;
13025 bpmnDiagram = null;
13026 }
13027
13028 var importer,
13029 eventBus,
13030 translate;
13031
13032 var error,
13033 warnings = [];
13034
13035 /**
13036 * Walk the diagram semantically, importing (=drawing)
13037 * all elements you encounter.
13038 *
13039 * @param {ModdleElement<Definitions>} definitions
13040 * @param {ModdleElement<BPMNDiagram>} bpmnDiagram
13041 */
13042 function render(definitions, bpmnDiagram) {
13043
13044 var visitor = {
13045
13046 root: function(element) {
13047 return importer.add(element);
13048 },
13049
13050 element: function(element, parentShape) {
13051 return importer.add(element, parentShape);
13052 },
13053
13054 error: function(message, context) {
13055 warnings.push({ message: message, context: context });
13056 }
13057 };
13058
13059 var walker = new BpmnTreeWalker(visitor, translate);
13060
13061 // traverse BPMN 2.0 document model,
13062 // starting at definitions
13063 walker.handleDefinitions(definitions, bpmnDiagram);
13064 }
13065
13066 try {
13067 importer = diagram.get('bpmnImporter');
13068 eventBus = diagram.get('eventBus');
13069 translate = diagram.get('translate');
13070
13071 eventBus.fire('import.render.start', { definitions: definitions });
13072
13073 render(definitions, bpmnDiagram);
13074
13075 eventBus.fire('import.render.complete', {
13076 error: error,
13077 warnings: warnings
13078 });
13079 } catch (e) {
13080 error = e;
13081 }
13082
13083 done(error, warnings);
13084 }
13085
13086 /**
13087 * Is an element of the given BPMN type?
13088 *
13089 * @param {djs.model.Base|ModdleElement} element
13090 * @param {String} type
13091 *
13092 * @return {Boolean}
13093 */
13094 function is$1(element, type) {
13095 var bo = getBusinessObject(element);
13096
13097 return bo && (typeof bo.$instanceOf === 'function') && bo.$instanceOf(type);
13098 }
13099
13100
13101 /**
13102 * Return the business object for a given element.
13103 *
13104 * @param {djs.model.Base|ModdleElement} element
13105 *
13106 * @return {ModdleElement}
13107 */
13108 function getBusinessObject(element) {
13109 return (element && element.businessObject) || element;
13110 }
13111
13112 function isExpanded(element) {
13113
13114 if (is$1(element, 'bpmn:CallActivity')) {
13115 return false;
13116 }
13117
13118 if (is$1(element, 'bpmn:SubProcess')) {
13119 return !!getBusinessObject(element).di.isExpanded;
13120 }
13121
13122 if (is$1(element, 'bpmn:Participant')) {
13123 return !!getBusinessObject(element).processRef;
13124 }
13125
13126 return true;
13127 }
13128
13129 function isEventSubProcess(element) {
13130 return element && !!getBusinessObject(element).triggeredByEvent;
13131 }
13132
13133 function getLabelAttr(semantic) {
13134 if (
13135 is$1(semantic, 'bpmn:FlowElement') ||
13136 is$1(semantic, 'bpmn:Participant') ||
13137 is$1(semantic, 'bpmn:Lane') ||
13138 is$1(semantic, 'bpmn:SequenceFlow') ||
13139 is$1(semantic, 'bpmn:MessageFlow') ||
13140 is$1(semantic, 'bpmn:DataInput') ||
13141 is$1(semantic, 'bpmn:DataOutput')
13142 ) {
13143 return 'name';
13144 }
13145
13146 if (is$1(semantic, 'bpmn:TextAnnotation')) {
13147 return 'text';
13148 }
13149
13150 if (is$1(semantic, 'bpmn:Group')) {
13151 return 'categoryValueRef';
13152 }
13153 }
13154
13155 function getCategoryValue(semantic) {
13156 var categoryValueRef = semantic['categoryValueRef'];
13157
13158 if (!categoryValueRef) {
13159 return '';
13160 }
13161
13162
13163 return categoryValueRef.value || '';
13164 }
13165
13166 function getLabel(element) {
13167 var semantic = element.businessObject,
13168 attr = getLabelAttr(semantic);
13169
13170 if (attr) {
13171
13172 if (attr === 'categoryValueRef') {
13173
13174 return getCategoryValue(semantic);
13175 }
13176
13177 return semantic[attr] || '';
13178 }
13179 }
13180
13181 // element utils //////////////////////
13182
13183 /**
13184 * Checks if eventDefinition of the given element matches with semantic type.
13185 *
13186 * @return {boolean} true if element is of the given semantic type
13187 */
13188 function isTypedEvent(event, eventDefinitionType, filter) {
13189
13190 function matches(definition, filter) {
13191 return every(filter, function(val, key) {
13192
13193 // we want a == conversion here, to be able to catch
13194 // undefined == false and friends
13195 /* jshint -W116 */
13196 return definition[key] == val;
13197 });
13198 }
13199
13200 return some(event.eventDefinitions, function(definition) {
13201 return definition.$type === eventDefinitionType && matches(event, filter);
13202 });
13203 }
13204
13205 function isThrowEvent(event) {
13206 return (event.$type === 'bpmn:IntermediateThrowEvent') || (event.$type === 'bpmn:EndEvent');
13207 }
13208
13209 function isCollection(element) {
13210 var dataObject = element.dataObjectRef;
13211
13212 return element.isCollection || (dataObject && dataObject.isCollection);
13213 }
13214
13215 function getDi(element) {
13216 return element.businessObject.di;
13217 }
13218
13219 function getSemantic(element) {
13220 return element.businessObject;
13221 }
13222
13223
13224 // color access //////////////////////
13225
13226 function getFillColor(element, defaultColor) {
13227 return getDi(element).get('bioc:fill') || defaultColor || 'white';
13228 }
13229
13230 function getStrokeColor(element, defaultColor) {
13231 return getDi(element).get('bioc:stroke') || defaultColor || 'black';
13232 }
13233
13234
13235 // cropping path customizations //////////////////////
13236
13237 function getCirclePath(shape) {
13238
13239 var cx = shape.x + shape.width / 2,
13240 cy = shape.y + shape.height / 2,
13241 radius = shape.width / 2;
13242
13243 var circlePath = [
13244 ['M', cx, cy],
13245 ['m', 0, -radius],
13246 ['a', radius, radius, 0, 1, 1, 0, 2 * radius],
13247 ['a', radius, radius, 0, 1, 1, 0, -2 * radius],
13248 ['z']
13249 ];
13250
13251 return componentsToPath(circlePath);
13252 }
13253
13254 function getRoundRectPath(shape, borderRadius) {
13255
13256 var x = shape.x,
13257 y = shape.y,
13258 width = shape.width,
13259 height = shape.height;
13260
13261 var roundRectPath = [
13262 ['M', x + borderRadius, y],
13263 ['l', width - borderRadius * 2, 0],
13264 ['a', borderRadius, borderRadius, 0, 0, 1, borderRadius, borderRadius],
13265 ['l', 0, height - borderRadius * 2],
13266 ['a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, borderRadius],
13267 ['l', borderRadius * 2 - width, 0],
13268 ['a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, -borderRadius],
13269 ['l', 0, borderRadius * 2 - height],
13270 ['a', borderRadius, borderRadius, 0, 0, 1, borderRadius, -borderRadius],
13271 ['z']
13272 ];
13273
13274 return componentsToPath(roundRectPath);
13275 }
13276
13277 function getDiamondPath(shape) {
13278
13279 var width = shape.width,
13280 height = shape.height,
13281 x = shape.x,
13282 y = shape.y,
13283 halfWidth = width / 2,
13284 halfHeight = height / 2;
13285
13286 var diamondPath = [
13287 ['M', x + halfWidth, y],
13288 ['l', halfWidth, halfHeight],
13289 ['l', -halfWidth, halfHeight],
13290 ['l', -halfWidth, -halfHeight],
13291 ['z']
13292 ];
13293
13294 return componentsToPath(diamondPath);
13295 }
13296
13297 function getRectPath(shape) {
13298 var x = shape.x,
13299 y = shape.y,
13300 width = shape.width,
13301 height = shape.height;
13302
13303 var rectPath = [
13304 ['M', x, y],
13305 ['l', width, 0],
13306 ['l', 0, height],
13307 ['l', -width, 0],
13308 ['z']
13309 ];
13310
13311 return componentsToPath(rectPath);
13312 }
13313
13314 function createCommonjsModule$1(fn, module) {
13315 return module = { exports: {} }, fn(module, module.exports), module.exports;
13316 }
13317
13318 var hat_1 = createCommonjsModule$1(function (module) {
13319 var hat = module.exports = function (bits, base) {
13320 if (!base) base = 16;
13321 if (bits === undefined) bits = 128;
13322 if (bits <= 0) return '0';
13323
13324 var digits = Math.log(Math.pow(2, bits)) / Math.log(base);
13325 for (var i = 2; digits === Infinity; i *= 2) {
13326 digits = Math.log(Math.pow(2, bits / i)) / Math.log(base) * i;
13327 }
13328
13329 var rem = digits - Math.floor(digits);
13330
13331 var res = '';
13332
13333 for (var i = 0; i < Math.floor(digits); i++) {
13334 var x = Math.floor(Math.random() * base).toString(base);
13335 res = x + res;
13336 }
13337
13338 if (rem) {
13339 var b = Math.pow(base, rem);
13340 var x = Math.floor(Math.random() * b).toString(base);
13341 res = x + res;
13342 }
13343
13344 var parsed = parseInt(res, base);
13345 if (parsed !== Infinity && parsed >= Math.pow(2, bits)) {
13346 return hat(bits, base)
13347 }
13348 else return res;
13349 };
13350
13351 hat.rack = function (bits, base, expandBy) {
13352 var fn = function (data) {
13353 var iters = 0;
13354 do {
13355 if (iters ++ > 10) {
13356 if (expandBy) bits += expandBy;
13357 else throw new Error('too many ID collisions, use more bits')
13358 }
13359
13360 var id = hat(bits, base);
13361 } while (Object.hasOwnProperty.call(hats, id));
13362
13363 hats[id] = data;
13364 return id;
13365 };
13366 var hats = fn.hats = {};
13367
13368 fn.get = function (id) {
13369 return fn.hats[id];
13370 };
13371
13372 fn.set = function (id, value) {
13373 fn.hats[id] = value;
13374 return fn;
13375 };
13376
13377 fn.bits = bits || 128;
13378 fn.base = base || 16;
13379 return fn;
13380 };
13381 });
13382
13383 /**
13384 * Create a new id generator / cache instance.
13385 *
13386 * You may optionally provide a seed that is used internally.
13387 *
13388 * @param {Seed} seed
13389 */
13390
13391 function Ids(seed) {
13392 if (!(this instanceof Ids)) {
13393 return new Ids(seed);
13394 }
13395
13396 seed = seed || [128, 36, 1];
13397 this._seed = seed.length ? hat_1.rack(seed[0], seed[1], seed[2]) : seed;
13398 }
13399 /**
13400 * Generate a next id.
13401 *
13402 * @param {Object} [element] element to bind the id to
13403 *
13404 * @return {String} id
13405 */
13406
13407 Ids.prototype.next = function (element) {
13408 return this._seed(element || true);
13409 };
13410 /**
13411 * Generate a next id with a given prefix.
13412 *
13413 * @param {Object} [element] element to bind the id to
13414 *
13415 * @return {String} id
13416 */
13417
13418
13419 Ids.prototype.nextPrefixed = function (prefix, element) {
13420 var id;
13421
13422 do {
13423 id = prefix + this.next(true);
13424 } while (this.assigned(id)); // claim {prefix}{random}
13425
13426
13427 this.claim(id, element); // return
13428
13429 return id;
13430 };
13431 /**
13432 * Manually claim an existing id.
13433 *
13434 * @param {String} id
13435 * @param {String} [element] element the id is claimed by
13436 */
13437
13438
13439 Ids.prototype.claim = function (id, element) {
13440 this._seed.set(id, element || true);
13441 };
13442 /**
13443 * Returns true if the given id has already been assigned.
13444 *
13445 * @param {String} id
13446 * @return {Boolean}
13447 */
13448
13449
13450 Ids.prototype.assigned = function (id) {
13451 return this._seed.get(id) || false;
13452 };
13453 /**
13454 * Unclaim an id.
13455 *
13456 * @param {String} id the id to unclaim
13457 */
13458
13459
13460 Ids.prototype.unclaim = function (id) {
13461 delete this._seed.hats[id];
13462 };
13463 /**
13464 * Clear all claimed ids.
13465 */
13466
13467
13468 Ids.prototype.clear = function () {
13469 var hats = this._seed.hats,
13470 id;
13471
13472 for (id in hats) {
13473 this.unclaim(id);
13474 }
13475 };
13476
13477 var RENDERER_IDS = new Ids();
13478
13479 var TASK_BORDER_RADIUS = 10;
13480 var INNER_OUTER_DIST = 3;
13481
13482 var DEFAULT_FILL_OPACITY = .95,
13483 HIGH_FILL_OPACITY = .35;
13484
13485
13486 function BpmnRenderer(
13487 config, eventBus, styles, pathMap,
13488 canvas, textRenderer, priority) {
13489
13490 BaseRenderer.call(this, eventBus, priority);
13491
13492 var defaultFillColor = config && config.defaultFillColor,
13493 defaultStrokeColor = config && config.defaultStrokeColor;
13494
13495 var rendererId = RENDERER_IDS.next();
13496
13497 var markers = {};
13498
13499 var computeStyle = styles.computeStyle;
13500
13501 function addMarker(id, options) {
13502 var attrs = assign({
13503 fill: 'black',
13504 strokeWidth: 1,
13505 strokeLinecap: 'round',
13506 strokeDasharray: 'none'
13507 }, options.attrs);
13508
13509 var ref = options.ref || { x: 0, y: 0 };
13510
13511 var scale = options.scale || 1;
13512
13513 // fix for safari / chrome / firefox bug not correctly
13514 // resetting stroke dash array
13515 if (attrs.strokeDasharray === 'none') {
13516 attrs.strokeDasharray = [10000, 1];
13517 }
13518
13519 var marker = create('marker');
13520
13521 attr$1(options.element, attrs);
13522
13523 append(marker, options.element);
13524
13525 attr$1(marker, {
13526 id: id,
13527 viewBox: '0 0 20 20',
13528 refX: ref.x,
13529 refY: ref.y,
13530 markerWidth: 20 * scale,
13531 markerHeight: 20 * scale,
13532 orient: 'auto'
13533 });
13534
13535 var defs = query('defs', canvas._svg);
13536
13537 if (!defs) {
13538 defs = create('defs');
13539
13540 append(canvas._svg, defs);
13541 }
13542
13543 append(defs, marker);
13544
13545 markers[id] = marker;
13546 }
13547
13548 function colorEscape(str) {
13549
13550 // only allow characters and numbers
13551 return str.replace(/[^0-9a-zA-z]+/g, '_');
13552 }
13553
13554 function marker(type, fill, stroke) {
13555 var id = type + '-' + colorEscape(fill) + '-' + colorEscape(stroke) + '-' + rendererId;
13556
13557 if (!markers[id]) {
13558 createMarker(id, type, fill, stroke);
13559 }
13560
13561 return 'url(#' + id + ')';
13562 }
13563
13564 function createMarker(id, type, fill, stroke) {
13565
13566 if (type === 'sequenceflow-end') {
13567 var sequenceflowEnd = create('path');
13568 attr$1(sequenceflowEnd, { d: 'M 1 5 L 11 10 L 1 15 Z' });
13569
13570 addMarker(id, {
13571 element: sequenceflowEnd,
13572 ref: { x: 11, y: 10 },
13573 scale: 0.5,
13574 attrs: {
13575 fill: stroke,
13576 stroke: stroke
13577 }
13578 });
13579 }
13580
13581 if (type === 'messageflow-start') {
13582 var messageflowStart = create('circle');
13583 attr$1(messageflowStart, { cx: 6, cy: 6, r: 3.5 });
13584
13585 addMarker(id, {
13586 element: messageflowStart,
13587 attrs: {
13588 fill: fill,
13589 stroke: stroke
13590 },
13591 ref: { x: 6, y: 6 }
13592 });
13593 }
13594
13595 if (type === 'messageflow-end') {
13596 var messageflowEnd = create('path');
13597 attr$1(messageflowEnd, { d: 'm 1 5 l 0 -3 l 7 3 l -7 3 z' });
13598
13599 addMarker(id, {
13600 element: messageflowEnd,
13601 attrs: {
13602 fill: fill,
13603 stroke: stroke,
13604 strokeLinecap: 'butt'
13605 },
13606 ref: { x: 8.5, y: 5 }
13607 });
13608 }
13609
13610 if (type === 'association-start') {
13611 var associationStart = create('path');
13612 attr$1(associationStart, { d: 'M 11 5 L 1 10 L 11 15' });
13613
13614 addMarker(id, {
13615 element: associationStart,
13616 attrs: {
13617 fill: 'none',
13618 stroke: stroke,
13619 strokeWidth: 1.5
13620 },
13621 ref: { x: 1, y: 10 },
13622 scale: 0.5
13623 });
13624 }
13625
13626 if (type === 'association-end') {
13627 var associationEnd = create('path');
13628 attr$1(associationEnd, { d: 'M 1 5 L 11 10 L 1 15' });
13629
13630 addMarker(id, {
13631 element: associationEnd,
13632 attrs: {
13633 fill: 'none',
13634 stroke: stroke,
13635 strokeWidth: 1.5
13636 },
13637 ref: { x: 12, y: 10 },
13638 scale: 0.5
13639 });
13640 }
13641
13642 if (type === 'conditional-flow-marker') {
13643 var conditionalflowMarker = create('path');
13644 attr$1(conditionalflowMarker, { d: 'M 0 10 L 8 6 L 16 10 L 8 14 Z' });
13645
13646 addMarker(id, {
13647 element: conditionalflowMarker,
13648 attrs: {
13649 fill: fill,
13650 stroke: stroke
13651 },
13652 ref: { x: -1, y: 10 },
13653 scale: 0.5
13654 });
13655 }
13656
13657 if (type === 'conditional-default-flow-marker') {
13658 var conditionaldefaultflowMarker = create('path');
13659 attr$1(conditionaldefaultflowMarker, { d: 'M 6 4 L 10 16' });
13660
13661 addMarker(id, {
13662 element: conditionaldefaultflowMarker,
13663 attrs: {
13664 stroke: stroke
13665 },
13666 ref: { x: 0, y: 10 },
13667 scale: 0.5
13668 });
13669 }
13670 }
13671
13672 function drawCircle(parentGfx, width, height, offset, attrs) {
13673
13674 if (isObject(offset)) {
13675 attrs = offset;
13676 offset = 0;
13677 }
13678
13679 offset = offset || 0;
13680
13681 attrs = computeStyle(attrs, {
13682 stroke: 'black',
13683 strokeWidth: 2,
13684 fill: 'white'
13685 });
13686
13687 if (attrs.fill === 'none') {
13688 delete attrs.fillOpacity;
13689 }
13690
13691 var cx = width / 2,
13692 cy = height / 2;
13693
13694 var circle = create('circle');
13695 attr$1(circle, {
13696 cx: cx,
13697 cy: cy,
13698 r: Math.round((width + height) / 4 - offset)
13699 });
13700 attr$1(circle, attrs);
13701
13702 append(parentGfx, circle);
13703
13704 return circle;
13705 }
13706
13707 function drawRect(parentGfx, width, height, r, offset, attrs) {
13708
13709 if (isObject(offset)) {
13710 attrs = offset;
13711 offset = 0;
13712 }
13713
13714 offset = offset || 0;
13715
13716 attrs = computeStyle(attrs, {
13717 stroke: 'black',
13718 strokeWidth: 2,
13719 fill: 'white'
13720 });
13721
13722 var rect = create('rect');
13723 attr$1(rect, {
13724 x: offset,
13725 y: offset,
13726 width: width - offset * 2,
13727 height: height - offset * 2,
13728 rx: r,
13729 ry: r
13730 });
13731 attr$1(rect, attrs);
13732
13733 append(parentGfx, rect);
13734
13735 return rect;
13736 }
13737
13738 function drawDiamond(parentGfx, width, height, attrs) {
13739
13740 var x_2 = width / 2;
13741 var y_2 = height / 2;
13742
13743 var points = [{ x: x_2, y: 0 }, { x: width, y: y_2 }, { x: x_2, y: height }, { x: 0, y: y_2 }];
13744
13745 var pointsString = points.map(function(point) {
13746 return point.x + ',' + point.y;
13747 }).join(' ');
13748
13749 attrs = computeStyle(attrs, {
13750 stroke: 'black',
13751 strokeWidth: 2,
13752 fill: 'white'
13753 });
13754
13755 var polygon = create('polygon');
13756 attr$1(polygon, {
13757 points: pointsString
13758 });
13759 attr$1(polygon, attrs);
13760
13761 append(parentGfx, polygon);
13762
13763 return polygon;
13764 }
13765
13766 function drawLine(parentGfx, waypoints, attrs) {
13767 attrs = computeStyle(attrs, [ 'no-fill' ], {
13768 stroke: 'black',
13769 strokeWidth: 2,
13770 fill: 'none'
13771 });
13772
13773 var line = createLine(waypoints, attrs);
13774
13775 append(parentGfx, line);
13776
13777 return line;
13778 }
13779
13780 function drawPath(parentGfx, d, attrs) {
13781
13782 attrs = computeStyle(attrs, [ 'no-fill' ], {
13783 strokeWidth: 2,
13784 stroke: 'black'
13785 });
13786
13787 var path = create('path');
13788 attr$1(path, { d: d });
13789 attr$1(path, attrs);
13790
13791 append(parentGfx, path);
13792
13793 return path;
13794 }
13795
13796 function drawMarker(type, parentGfx, path, attrs) {
13797 return drawPath(parentGfx, path, assign({ 'data-marker': type }, attrs));
13798 }
13799
13800 function as(type) {
13801 return function(parentGfx, element) {
13802 return handlers[type](parentGfx, element);
13803 };
13804 }
13805
13806 function renderer(type) {
13807 return handlers[type];
13808 }
13809
13810 function renderEventContent(element, parentGfx) {
13811
13812 var event = getSemantic(element);
13813 var isThrowing = isThrowEvent(event);
13814
13815 if (event.eventDefinitions && event.eventDefinitions.length>1) {
13816 if (event.parallelMultiple) {
13817 return renderer('bpmn:ParallelMultipleEventDefinition')(parentGfx, element, isThrowing);
13818 }
13819 else {
13820 return renderer('bpmn:MultipleEventDefinition')(parentGfx, element, isThrowing);
13821 }
13822 }
13823
13824 if (isTypedEvent(event, 'bpmn:MessageEventDefinition')) {
13825 return renderer('bpmn:MessageEventDefinition')(parentGfx, element, isThrowing);
13826 }
13827
13828 if (isTypedEvent(event, 'bpmn:TimerEventDefinition')) {
13829 return renderer('bpmn:TimerEventDefinition')(parentGfx, element, isThrowing);
13830 }
13831
13832 if (isTypedEvent(event, 'bpmn:ConditionalEventDefinition')) {
13833 return renderer('bpmn:ConditionalEventDefinition')(parentGfx, element);
13834 }
13835
13836 if (isTypedEvent(event, 'bpmn:SignalEventDefinition')) {
13837 return renderer('bpmn:SignalEventDefinition')(parentGfx, element, isThrowing);
13838 }
13839
13840 if (isTypedEvent(event, 'bpmn:EscalationEventDefinition')) {
13841 return renderer('bpmn:EscalationEventDefinition')(parentGfx, element, isThrowing);
13842 }
13843
13844 if (isTypedEvent(event, 'bpmn:LinkEventDefinition')) {
13845 return renderer('bpmn:LinkEventDefinition')(parentGfx, element, isThrowing);
13846 }
13847
13848 if (isTypedEvent(event, 'bpmn:ErrorEventDefinition')) {
13849 return renderer('bpmn:ErrorEventDefinition')(parentGfx, element, isThrowing);
13850 }
13851
13852 if (isTypedEvent(event, 'bpmn:CancelEventDefinition')) {
13853 return renderer('bpmn:CancelEventDefinition')(parentGfx, element, isThrowing);
13854 }
13855
13856 if (isTypedEvent(event, 'bpmn:CompensateEventDefinition')) {
13857 return renderer('bpmn:CompensateEventDefinition')(parentGfx, element, isThrowing);
13858 }
13859
13860 if (isTypedEvent(event, 'bpmn:TerminateEventDefinition')) {
13861 return renderer('bpmn:TerminateEventDefinition')(parentGfx, element, isThrowing);
13862 }
13863
13864 return null;
13865 }
13866
13867 function renderLabel(parentGfx, label, options) {
13868
13869 options = assign({
13870 size: {
13871 width: 100
13872 }
13873 }, options);
13874
13875 var text = textRenderer.createText(label || '', options);
13876
13877 classes$1(text).add('djs-label');
13878
13879 append(parentGfx, text);
13880
13881 return text;
13882 }
13883
13884 function renderEmbeddedLabel(parentGfx, element, align) {
13885 var semantic = getSemantic(element);
13886
13887 return renderLabel(parentGfx, semantic.name, {
13888 box: element,
13889 align: align,
13890 padding: 5,
13891 style: {
13892 fill: getStrokeColor(element, defaultStrokeColor)
13893 }
13894 });
13895 }
13896
13897 function renderExternalLabel(parentGfx, element) {
13898
13899 var box = {
13900 width: 90,
13901 height: 30,
13902 x: element.width / 2 + element.x,
13903 y: element.height / 2 + element.y
13904 };
13905
13906 return renderLabel(parentGfx, getLabel(element), {
13907 box: box,
13908 fitBox: true,
13909 style: assign(
13910 {},
13911 textRenderer.getExternalStyle(),
13912 {
13913 fill: getStrokeColor(element, defaultStrokeColor)
13914 }
13915 )
13916 });
13917 }
13918
13919 function renderLaneLabel(parentGfx, text, element) {
13920 var textBox = renderLabel(parentGfx, text, {
13921 box: {
13922 height: 30,
13923 width: element.height
13924 },
13925 align: 'center-middle',
13926 style: {
13927 fill: getStrokeColor(element, defaultStrokeColor)
13928 }
13929 });
13930
13931 var top = -1 * element.height;
13932
13933 transform$1(textBox, 0, -top, 270);
13934 }
13935
13936 function createPathFromConnection(connection) {
13937 var waypoints = connection.waypoints;
13938
13939 var pathData = 'm ' + waypoints[0].x + ',' + waypoints[0].y;
13940 for (var i = 1; i < waypoints.length; i++) {
13941 pathData += 'L' + waypoints[i].x + ',' + waypoints[i].y + ' ';
13942 }
13943 return pathData;
13944 }
13945
13946 var handlers = this.handlers = {
13947 'bpmn:Event': function(parentGfx, element, attrs) {
13948
13949 if (!('fillOpacity' in attrs)) {
13950 attrs.fillOpacity = DEFAULT_FILL_OPACITY;
13951 }
13952
13953 return drawCircle(parentGfx, element.width, element.height, attrs);
13954 },
13955 'bpmn:StartEvent': function(parentGfx, element) {
13956 var attrs = {
13957 fill: getFillColor(element, defaultFillColor),
13958 stroke: getStrokeColor(element, defaultStrokeColor)
13959 };
13960
13961 var semantic = getSemantic(element);
13962
13963 if (!semantic.isInterrupting) {
13964 attrs = {
13965 strokeDasharray: '6',
13966 strokeLinecap: 'round',
13967 fill: getFillColor(element, defaultFillColor),
13968 stroke: getStrokeColor(element, defaultStrokeColor)
13969 };
13970 }
13971
13972 var circle = renderer('bpmn:Event')(parentGfx, element, attrs);
13973
13974 renderEventContent(element, parentGfx);
13975
13976 return circle;
13977 },
13978 'bpmn:MessageEventDefinition': function(parentGfx, element, isThrowing) {
13979 var pathData = pathMap.getScaledPath('EVENT_MESSAGE', {
13980 xScaleFactor: 0.9,
13981 yScaleFactor: 0.9,
13982 containerWidth: element.width,
13983 containerHeight: element.height,
13984 position: {
13985 mx: 0.235,
13986 my: 0.315
13987 }
13988 });
13989
13990 var fill = isThrowing ? getStrokeColor(element, defaultStrokeColor) : getFillColor(element, defaultFillColor);
13991 var stroke = isThrowing ? getFillColor(element, defaultFillColor) : getStrokeColor(element, defaultStrokeColor);
13992
13993 var messagePath = drawPath(parentGfx, pathData, {
13994 strokeWidth: 1,
13995 fill: fill,
13996 stroke: stroke
13997 });
13998
13999 return messagePath;
14000 },
14001 'bpmn:TimerEventDefinition': function(parentGfx, element) {
14002 var circle = drawCircle(parentGfx, element.width, element.height, 0.2 * element.height, {
14003 strokeWidth: 2,
14004 fill: getFillColor(element, defaultFillColor),
14005 stroke: getStrokeColor(element, defaultStrokeColor)
14006 });
14007
14008 var pathData = pathMap.getScaledPath('EVENT_TIMER_WH', {
14009 xScaleFactor: 0.75,
14010 yScaleFactor: 0.75,
14011 containerWidth: element.width,
14012 containerHeight: element.height,
14013 position: {
14014 mx: 0.5,
14015 my: 0.5
14016 }
14017 });
14018
14019 drawPath(parentGfx, pathData, {
14020 strokeWidth: 2,
14021 strokeLinecap: 'square',
14022 stroke: getStrokeColor(element, defaultStrokeColor)
14023 });
14024
14025 for (var i = 0;i < 12; i++) {
14026
14027 var linePathData = pathMap.getScaledPath('EVENT_TIMER_LINE', {
14028 xScaleFactor: 0.75,
14029 yScaleFactor: 0.75,
14030 containerWidth: element.width,
14031 containerHeight: element.height,
14032 position: {
14033 mx: 0.5,
14034 my: 0.5
14035 }
14036 });
14037
14038 var width = element.width / 2;
14039 var height = element.height / 2;
14040
14041 drawPath(parentGfx, linePathData, {
14042 strokeWidth: 1,
14043 strokeLinecap: 'square',
14044 transform: 'rotate(' + (i * 30) + ',' + height + ',' + width + ')',
14045 stroke: getStrokeColor(element, defaultStrokeColor)
14046 });
14047 }
14048
14049 return circle;
14050 },
14051 'bpmn:EscalationEventDefinition': function(parentGfx, event, isThrowing) {
14052 var pathData = pathMap.getScaledPath('EVENT_ESCALATION', {
14053 xScaleFactor: 1,
14054 yScaleFactor: 1,
14055 containerWidth: event.width,
14056 containerHeight: event.height,
14057 position: {
14058 mx: 0.5,
14059 my: 0.2
14060 }
14061 });
14062
14063 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14064
14065 return drawPath(parentGfx, pathData, {
14066 strokeWidth: 1,
14067 fill: fill,
14068 stroke: getStrokeColor(event, defaultStrokeColor)
14069 });
14070 },
14071 'bpmn:ConditionalEventDefinition': function(parentGfx, event) {
14072 var pathData = pathMap.getScaledPath('EVENT_CONDITIONAL', {
14073 xScaleFactor: 1,
14074 yScaleFactor: 1,
14075 containerWidth: event.width,
14076 containerHeight: event.height,
14077 position: {
14078 mx: 0.5,
14079 my: 0.222
14080 }
14081 });
14082
14083 return drawPath(parentGfx, pathData, {
14084 strokeWidth: 1,
14085 stroke: getStrokeColor(event, defaultStrokeColor)
14086 });
14087 },
14088 'bpmn:LinkEventDefinition': function(parentGfx, event, isThrowing) {
14089 var pathData = pathMap.getScaledPath('EVENT_LINK', {
14090 xScaleFactor: 1,
14091 yScaleFactor: 1,
14092 containerWidth: event.width,
14093 containerHeight: event.height,
14094 position: {
14095 mx: 0.57,
14096 my: 0.263
14097 }
14098 });
14099
14100 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14101
14102 return drawPath(parentGfx, pathData, {
14103 strokeWidth: 1,
14104 fill: fill,
14105 stroke: getStrokeColor(event, defaultStrokeColor)
14106 });
14107 },
14108 'bpmn:ErrorEventDefinition': function(parentGfx, event, isThrowing) {
14109 var pathData = pathMap.getScaledPath('EVENT_ERROR', {
14110 xScaleFactor: 1.1,
14111 yScaleFactor: 1.1,
14112 containerWidth: event.width,
14113 containerHeight: event.height,
14114 position: {
14115 mx: 0.2,
14116 my: 0.722
14117 }
14118 });
14119
14120 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14121
14122 return drawPath(parentGfx, pathData, {
14123 strokeWidth: 1,
14124 fill: fill,
14125 stroke: getStrokeColor(event, defaultStrokeColor)
14126 });
14127 },
14128 'bpmn:CancelEventDefinition': function(parentGfx, event, isThrowing) {
14129 var pathData = pathMap.getScaledPath('EVENT_CANCEL_45', {
14130 xScaleFactor: 1.0,
14131 yScaleFactor: 1.0,
14132 containerWidth: event.width,
14133 containerHeight: event.height,
14134 position: {
14135 mx: 0.638,
14136 my: -0.055
14137 }
14138 });
14139
14140 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14141
14142 var path = drawPath(parentGfx, pathData, {
14143 strokeWidth: 1,
14144 fill: fill,
14145 stroke: getStrokeColor(event, defaultStrokeColor)
14146 });
14147
14148 rotate(path, 45);
14149
14150 return path;
14151 },
14152 'bpmn:CompensateEventDefinition': function(parentGfx, event, isThrowing) {
14153 var pathData = pathMap.getScaledPath('EVENT_COMPENSATION', {
14154 xScaleFactor: 1,
14155 yScaleFactor: 1,
14156 containerWidth: event.width,
14157 containerHeight: event.height,
14158 position: {
14159 mx: 0.22,
14160 my: 0.5
14161 }
14162 });
14163
14164 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14165
14166 return drawPath(parentGfx, pathData, {
14167 strokeWidth: 1,
14168 fill: fill,
14169 stroke: getStrokeColor(event, defaultStrokeColor)
14170 });
14171 },
14172 'bpmn:SignalEventDefinition': function(parentGfx, event, isThrowing) {
14173 var pathData = pathMap.getScaledPath('EVENT_SIGNAL', {
14174 xScaleFactor: 0.9,
14175 yScaleFactor: 0.9,
14176 containerWidth: event.width,
14177 containerHeight: event.height,
14178 position: {
14179 mx: 0.5,
14180 my: 0.2
14181 }
14182 });
14183
14184 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14185
14186 return drawPath(parentGfx, pathData, {
14187 strokeWidth: 1,
14188 fill: fill,
14189 stroke: getStrokeColor(event, defaultStrokeColor)
14190 });
14191 },
14192 'bpmn:MultipleEventDefinition': function(parentGfx, event, isThrowing) {
14193 var pathData = pathMap.getScaledPath('EVENT_MULTIPLE', {
14194 xScaleFactor: 1.1,
14195 yScaleFactor: 1.1,
14196 containerWidth: event.width,
14197 containerHeight: event.height,
14198 position: {
14199 mx: 0.222,
14200 my: 0.36
14201 }
14202 });
14203
14204 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14205
14206 return drawPath(parentGfx, pathData, {
14207 strokeWidth: 1,
14208 fill: fill
14209 });
14210 },
14211 'bpmn:ParallelMultipleEventDefinition': function(parentGfx, event) {
14212 var pathData = pathMap.getScaledPath('EVENT_PARALLEL_MULTIPLE', {
14213 xScaleFactor: 1.2,
14214 yScaleFactor: 1.2,
14215 containerWidth: event.width,
14216 containerHeight: event.height,
14217 position: {
14218 mx: 0.458,
14219 my: 0.194
14220 }
14221 });
14222
14223 return drawPath(parentGfx, pathData, {
14224 strokeWidth: 1,
14225 fill: getStrokeColor(event, defaultStrokeColor),
14226 stroke: getStrokeColor(event, defaultStrokeColor)
14227 });
14228 },
14229 'bpmn:EndEvent': function(parentGfx, element) {
14230 var circle = renderer('bpmn:Event')(parentGfx, element, {
14231 strokeWidth: 4,
14232 fill: getFillColor(element, defaultFillColor),
14233 stroke: getStrokeColor(element, defaultStrokeColor)
14234 });
14235
14236 renderEventContent(element, parentGfx);
14237
14238 return circle;
14239 },
14240 'bpmn:TerminateEventDefinition': function(parentGfx, element) {
14241 var circle = drawCircle(parentGfx, element.width, element.height, 8, {
14242 strokeWidth: 4,
14243 fill: getStrokeColor(element, defaultStrokeColor),
14244 stroke: getStrokeColor(element, defaultStrokeColor)
14245 });
14246
14247 return circle;
14248 },
14249 'bpmn:IntermediateEvent': function(parentGfx, element) {
14250 var outer = renderer('bpmn:Event')(parentGfx, element, {
14251 strokeWidth: 1,
14252 fill: getFillColor(element, defaultFillColor),
14253 stroke: getStrokeColor(element, defaultStrokeColor)
14254 });
14255
14256 /* inner */
14257 drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, {
14258 strokeWidth: 1,
14259 fill: getFillColor(element, 'none'),
14260 stroke: getStrokeColor(element, defaultStrokeColor)
14261 });
14262
14263 renderEventContent(element, parentGfx);
14264
14265 return outer;
14266 },
14267 'bpmn:IntermediateCatchEvent': as('bpmn:IntermediateEvent'),
14268 'bpmn:IntermediateThrowEvent': as('bpmn:IntermediateEvent'),
14269
14270 'bpmn:Activity': function(parentGfx, element, attrs) {
14271
14272 attrs = attrs || {};
14273
14274 if (!('fillOpacity' in attrs)) {
14275 attrs.fillOpacity = DEFAULT_FILL_OPACITY;
14276 }
14277
14278 return drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, attrs);
14279 },
14280
14281 'bpmn:Task': function(parentGfx, element) {
14282 var attrs = {
14283 fill: getFillColor(element, defaultFillColor),
14284 stroke: getStrokeColor(element, defaultStrokeColor)
14285 };
14286
14287 var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
14288
14289 renderEmbeddedLabel(parentGfx, element, 'center-middle');
14290 attachTaskMarkers(parentGfx, element);
14291
14292 return rect;
14293 },
14294 'bpmn:ServiceTask': function(parentGfx, element) {
14295 var task = renderer('bpmn:Task')(parentGfx, element);
14296
14297 var pathDataBG = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
14298 abspos: {
14299 x: 12,
14300 y: 18
14301 }
14302 });
14303
14304 /* service bg */ drawPath(parentGfx, pathDataBG, {
14305 strokeWidth: 1,
14306 fill: getFillColor(element, defaultFillColor),
14307 stroke: getStrokeColor(element, defaultStrokeColor)
14308 });
14309
14310 var fillPathData = pathMap.getScaledPath('TASK_TYPE_SERVICE_FILL', {
14311 abspos: {
14312 x: 17.2,
14313 y: 18
14314 }
14315 });
14316
14317 /* service fill */ drawPath(parentGfx, fillPathData, {
14318 strokeWidth: 0,
14319 fill: getFillColor(element, defaultFillColor)
14320 });
14321
14322 var pathData = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
14323 abspos: {
14324 x: 17,
14325 y: 22
14326 }
14327 });
14328
14329 /* service */ drawPath(parentGfx, pathData, {
14330 strokeWidth: 1,
14331 fill: getFillColor(element, defaultFillColor),
14332 stroke: getStrokeColor(element, defaultStrokeColor)
14333 });
14334
14335 return task;
14336 },
14337 'bpmn:UserTask': function(parentGfx, element) {
14338 var task = renderer('bpmn:Task')(parentGfx, element);
14339
14340 var x = 15;
14341 var y = 12;
14342
14343 var pathData = pathMap.getScaledPath('TASK_TYPE_USER_1', {
14344 abspos: {
14345 x: x,
14346 y: y
14347 }
14348 });
14349
14350 /* user path */ drawPath(parentGfx, pathData, {
14351 strokeWidth: 0.5,
14352 fill: getFillColor(element, defaultFillColor),
14353 stroke: getStrokeColor(element, defaultStrokeColor)
14354 });
14355
14356 var pathData2 = pathMap.getScaledPath('TASK_TYPE_USER_2', {
14357 abspos: {
14358 x: x,
14359 y: y
14360 }
14361 });
14362
14363 /* user2 path */ drawPath(parentGfx, pathData2, {
14364 strokeWidth: 0.5,
14365 fill: getFillColor(element, defaultFillColor),
14366 stroke: getStrokeColor(element, defaultStrokeColor)
14367 });
14368
14369 var pathData3 = pathMap.getScaledPath('TASK_TYPE_USER_3', {
14370 abspos: {
14371 x: x,
14372 y: y
14373 }
14374 });
14375
14376 /* user3 path */ drawPath(parentGfx, pathData3, {
14377 strokeWidth: 0.5,
14378 fill: getStrokeColor(element, defaultStrokeColor),
14379 stroke: getStrokeColor(element, defaultStrokeColor)
14380 });
14381
14382 return task;
14383 },
14384 'bpmn:ManualTask': function(parentGfx, element) {
14385 var task = renderer('bpmn:Task')(parentGfx, element);
14386
14387 var pathData = pathMap.getScaledPath('TASK_TYPE_MANUAL', {
14388 abspos: {
14389 x: 17,
14390 y: 15
14391 }
14392 });
14393
14394 /* manual path */ drawPath(parentGfx, pathData, {
14395 strokeWidth: 0.5, // 0.25,
14396 fill: getFillColor(element, defaultFillColor),
14397 stroke: getStrokeColor(element, defaultStrokeColor)
14398 });
14399
14400 return task;
14401 },
14402 'bpmn:SendTask': function(parentGfx, element) {
14403 var task = renderer('bpmn:Task')(parentGfx, element);
14404
14405 var pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
14406 xScaleFactor: 1,
14407 yScaleFactor: 1,
14408 containerWidth: 21,
14409 containerHeight: 14,
14410 position: {
14411 mx: 0.285,
14412 my: 0.357
14413 }
14414 });
14415
14416 /* send path */ drawPath(parentGfx, pathData, {
14417 strokeWidth: 1,
14418 fill: getStrokeColor(element, defaultStrokeColor),
14419 stroke: getFillColor(element, defaultFillColor)
14420 });
14421
14422 return task;
14423 },
14424 'bpmn:ReceiveTask' : function(parentGfx, element) {
14425 var semantic = getSemantic(element);
14426
14427 var task = renderer('bpmn:Task')(parentGfx, element);
14428 var pathData;
14429
14430 if (semantic.instantiate) {
14431 drawCircle(parentGfx, 28, 28, 20 * 0.22, { strokeWidth: 1 });
14432
14433 pathData = pathMap.getScaledPath('TASK_TYPE_INSTANTIATING_SEND', {
14434 abspos: {
14435 x: 7.77,
14436 y: 9.52
14437 }
14438 });
14439 } else {
14440
14441 pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
14442 xScaleFactor: 0.9,
14443 yScaleFactor: 0.9,
14444 containerWidth: 21,
14445 containerHeight: 14,
14446 position: {
14447 mx: 0.3,
14448 my: 0.4
14449 }
14450 });
14451 }
14452
14453 /* receive path */ drawPath(parentGfx, pathData, {
14454 strokeWidth: 1,
14455 fill: getFillColor(element, defaultFillColor),
14456 stroke: getStrokeColor(element, defaultStrokeColor)
14457 });
14458
14459 return task;
14460 },
14461 'bpmn:ScriptTask': function(parentGfx, element) {
14462 var task = renderer('bpmn:Task')(parentGfx, element);
14463
14464 var pathData = pathMap.getScaledPath('TASK_TYPE_SCRIPT', {
14465 abspos: {
14466 x: 15,
14467 y: 20
14468 }
14469 });
14470
14471 /* script path */ drawPath(parentGfx, pathData, {
14472 strokeWidth: 1,
14473 stroke: getStrokeColor(element, defaultStrokeColor)
14474 });
14475
14476 return task;
14477 },
14478 'bpmn:BusinessRuleTask': function(parentGfx, element) {
14479 var task = renderer('bpmn:Task')(parentGfx, element);
14480
14481 var headerPathData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_HEADER', {
14482 abspos: {
14483 x: 8,
14484 y: 8
14485 }
14486 });
14487
14488 var businessHeaderPath = drawPath(parentGfx, headerPathData);
14489 attr$1(businessHeaderPath, {
14490 strokeWidth: 1,
14491 fill: getFillColor(element, '#aaaaaa'),
14492 stroke: getStrokeColor(element, defaultStrokeColor)
14493 });
14494
14495 var headerData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_MAIN', {
14496 abspos: {
14497 x: 8,
14498 y: 8
14499 }
14500 });
14501
14502 var businessPath = drawPath(parentGfx, headerData);
14503 attr$1(businessPath, {
14504 strokeWidth: 1,
14505 stroke: getStrokeColor(element, defaultStrokeColor)
14506 });
14507
14508 return task;
14509 },
14510 'bpmn:SubProcess': function(parentGfx, element, attrs) {
14511 attrs = assign({
14512 fill: getFillColor(element, defaultFillColor),
14513 stroke: getStrokeColor(element, defaultStrokeColor)
14514 }, attrs);
14515
14516 var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
14517
14518 var expanded = isExpanded(element);
14519
14520 if (isEventSubProcess(element)) {
14521 attr$1(rect, {
14522 strokeDasharray: '1,2'
14523 });
14524 }
14525
14526 renderEmbeddedLabel(parentGfx, element, expanded ? 'center-top' : 'center-middle');
14527
14528 if (expanded) {
14529 attachTaskMarkers(parentGfx, element);
14530 } else {
14531 attachTaskMarkers(parentGfx, element, ['SubProcessMarker']);
14532 }
14533
14534 return rect;
14535 },
14536 'bpmn:AdHocSubProcess': function(parentGfx, element) {
14537 return renderer('bpmn:SubProcess')(parentGfx, element);
14538 },
14539 'bpmn:Transaction': function(parentGfx, element) {
14540 var outer = renderer('bpmn:SubProcess')(parentGfx, element);
14541
14542 var innerAttrs = styles.style([ 'no-fill', 'no-events' ], {
14543 stroke: getStrokeColor(element, defaultStrokeColor)
14544 });
14545
14546 /* inner path */ drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS - 2, INNER_OUTER_DIST, innerAttrs);
14547
14548 return outer;
14549 },
14550 'bpmn:CallActivity': function(parentGfx, element) {
14551 return renderer('bpmn:SubProcess')(parentGfx, element, {
14552 strokeWidth: 5
14553 });
14554 },
14555 'bpmn:Participant': function(parentGfx, element) {
14556
14557 var attrs = {
14558 fillOpacity: DEFAULT_FILL_OPACITY,
14559 fill: getFillColor(element, defaultFillColor),
14560 stroke: getStrokeColor(element, defaultStrokeColor)
14561 };
14562
14563 var lane = renderer('bpmn:Lane')(parentGfx, element, attrs);
14564
14565 var expandedPool = isExpanded(element);
14566
14567 if (expandedPool) {
14568 drawLine(parentGfx, [
14569 { x: 30, y: 0 },
14570 { x: 30, y: element.height }
14571 ], {
14572 stroke: getStrokeColor(element, defaultStrokeColor)
14573 });
14574 var text = getSemantic(element).name;
14575 renderLaneLabel(parentGfx, text, element);
14576 } else {
14577
14578 // Collapsed pool draw text inline
14579 var text2 = getSemantic(element).name;
14580 renderLabel(parentGfx, text2, {
14581 box: element, align: 'center-middle',
14582 style: {
14583 fill: getStrokeColor(element, defaultStrokeColor)
14584 }
14585 });
14586 }
14587
14588 var participantMultiplicity = !!(getSemantic(element).participantMultiplicity);
14589
14590 if (participantMultiplicity) {
14591 renderer('ParticipantMultiplicityMarker')(parentGfx, element);
14592 }
14593
14594 return lane;
14595 },
14596 'bpmn:Lane': function(parentGfx, element, attrs) {
14597 var rect = drawRect(parentGfx, element.width, element.height, 0, assign({
14598 fill: getFillColor(element, defaultFillColor),
14599 fillOpacity: HIGH_FILL_OPACITY,
14600 stroke: getStrokeColor(element, defaultStrokeColor)
14601 }, attrs));
14602
14603 var semantic = getSemantic(element);
14604
14605 if (semantic.$type === 'bpmn:Lane') {
14606 var text = semantic.name;
14607 renderLaneLabel(parentGfx, text, element);
14608 }
14609
14610 return rect;
14611 },
14612 'bpmn:InclusiveGateway': function(parentGfx, element) {
14613 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14614
14615 /* circle path */
14616 drawCircle(parentGfx, element.width, element.height, element.height * 0.24, {
14617 strokeWidth: 2.5,
14618 fill: getFillColor(element, defaultFillColor),
14619 stroke: getStrokeColor(element, defaultStrokeColor)
14620 });
14621
14622 return diamond;
14623 },
14624 'bpmn:ExclusiveGateway': function(parentGfx, element) {
14625 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14626
14627 var pathData = pathMap.getScaledPath('GATEWAY_EXCLUSIVE', {
14628 xScaleFactor: 0.4,
14629 yScaleFactor: 0.4,
14630 containerWidth: element.width,
14631 containerHeight: element.height,
14632 position: {
14633 mx: 0.32,
14634 my: 0.3
14635 }
14636 });
14637
14638 if ((getDi(element).isMarkerVisible)) {
14639 drawPath(parentGfx, pathData, {
14640 strokeWidth: 1,
14641 fill: getStrokeColor(element, defaultStrokeColor),
14642 stroke: getStrokeColor(element, defaultStrokeColor)
14643 });
14644 }
14645
14646 return diamond;
14647 },
14648 'bpmn:ComplexGateway': function(parentGfx, element) {
14649 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14650
14651 var pathData = pathMap.getScaledPath('GATEWAY_COMPLEX', {
14652 xScaleFactor: 0.5,
14653 yScaleFactor:0.5,
14654 containerWidth: element.width,
14655 containerHeight: element.height,
14656 position: {
14657 mx: 0.46,
14658 my: 0.26
14659 }
14660 });
14661
14662 /* complex path */ drawPath(parentGfx, pathData, {
14663 strokeWidth: 1,
14664 fill: getStrokeColor(element, defaultStrokeColor),
14665 stroke: getStrokeColor(element, defaultStrokeColor)
14666 });
14667
14668 return diamond;
14669 },
14670 'bpmn:ParallelGateway': function(parentGfx, element) {
14671 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14672
14673 var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
14674 xScaleFactor: 0.6,
14675 yScaleFactor:0.6,
14676 containerWidth: element.width,
14677 containerHeight: element.height,
14678 position: {
14679 mx: 0.46,
14680 my: 0.2
14681 }
14682 });
14683
14684 /* parallel path */ drawPath(parentGfx, pathData, {
14685 strokeWidth: 1,
14686 fill: getStrokeColor(element, defaultStrokeColor),
14687 stroke: getStrokeColor(element, defaultStrokeColor)
14688 });
14689
14690 return diamond;
14691 },
14692 'bpmn:EventBasedGateway': function(parentGfx, element) {
14693
14694 var semantic = getSemantic(element);
14695
14696 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14697
14698 /* outer circle path */ drawCircle(parentGfx, element.width, element.height, element.height * 0.20, {
14699 strokeWidth: 1,
14700 fill: 'none',
14701 stroke: getStrokeColor(element, defaultStrokeColor)
14702 });
14703
14704 var type = semantic.eventGatewayType;
14705 var instantiate = !!semantic.instantiate;
14706
14707 function drawEvent() {
14708
14709 var pathData = pathMap.getScaledPath('GATEWAY_EVENT_BASED', {
14710 xScaleFactor: 0.18,
14711 yScaleFactor: 0.18,
14712 containerWidth: element.width,
14713 containerHeight: element.height,
14714 position: {
14715 mx: 0.36,
14716 my: 0.44
14717 }
14718 });
14719
14720 var attrs = {
14721 strokeWidth: 2,
14722 fill: getFillColor(element, 'none'),
14723 stroke: getStrokeColor(element, defaultStrokeColor)
14724 };
14725
14726 /* event path */ drawPath(parentGfx, pathData, attrs);
14727 }
14728
14729 if (type === 'Parallel') {
14730
14731 var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
14732 xScaleFactor: 0.4,
14733 yScaleFactor:0.4,
14734 containerWidth: element.width,
14735 containerHeight: element.height,
14736 position: {
14737 mx: 0.474,
14738 my: 0.296
14739 }
14740 });
14741
14742 var parallelPath = drawPath(parentGfx, pathData);
14743 attr$1(parallelPath, {
14744 strokeWidth: 1,
14745 fill: 'none'
14746 });
14747 } else if (type === 'Exclusive') {
14748
14749 if (!instantiate) {
14750 var innerCircle = drawCircle(parentGfx, element.width, element.height, element.height * 0.26);
14751 attr$1(innerCircle, {
14752 strokeWidth: 1,
14753 fill: 'none',
14754 stroke: getStrokeColor(element, defaultStrokeColor)
14755 });
14756 }
14757
14758 drawEvent();
14759 }
14760
14761
14762 return diamond;
14763 },
14764 'bpmn:Gateway': function(parentGfx, element) {
14765 var attrs = {
14766 fill: getFillColor(element, defaultFillColor),
14767 fillOpacity: DEFAULT_FILL_OPACITY,
14768 stroke: getStrokeColor(element, defaultStrokeColor)
14769 };
14770
14771 return drawDiamond(parentGfx, element.width, element.height, attrs);
14772 },
14773 'bpmn:SequenceFlow': function(parentGfx, element) {
14774 var pathData = createPathFromConnection(element);
14775
14776 var fill = getFillColor(element, defaultFillColor),
14777 stroke = getStrokeColor(element, defaultStrokeColor);
14778
14779 var attrs = {
14780 strokeLinejoin: 'round',
14781 markerEnd: marker('sequenceflow-end', fill, stroke),
14782 stroke: getStrokeColor(element, defaultStrokeColor)
14783 };
14784
14785 var path = drawPath(parentGfx, pathData, attrs);
14786
14787 var sequenceFlow = getSemantic(element);
14788
14789 var source;
14790
14791 if (element.source) {
14792 source = element.source.businessObject;
14793
14794 // conditional flow marker
14795 if (sequenceFlow.conditionExpression && source.$instanceOf('bpmn:Activity')) {
14796 attr$1(path, {
14797 markerStart: marker('conditional-flow-marker', fill, stroke)
14798 });
14799 }
14800
14801 // default marker
14802 if (source.default && (source.$instanceOf('bpmn:Gateway') || source.$instanceOf('bpmn:Activity')) &&
14803 source.default === sequenceFlow) {
14804 attr$1(path, {
14805 markerStart: marker('conditional-default-flow-marker', fill, stroke)
14806 });
14807 }
14808 }
14809
14810 return path;
14811 },
14812 'bpmn:Association': function(parentGfx, element, attrs) {
14813
14814 var semantic = getSemantic(element);
14815
14816 var fill = getFillColor(element, defaultFillColor),
14817 stroke = getStrokeColor(element, defaultStrokeColor);
14818
14819 attrs = assign({
14820 strokeDasharray: '0.5, 5',
14821 strokeLinecap: 'round',
14822 strokeLinejoin: 'round',
14823 stroke: getStrokeColor(element, defaultStrokeColor)
14824 }, attrs || {});
14825
14826 if (semantic.associationDirection === 'One' ||
14827 semantic.associationDirection === 'Both') {
14828 attrs.markerEnd = marker('association-end', fill, stroke);
14829 }
14830
14831 if (semantic.associationDirection === 'Both') {
14832 attrs.markerStart = marker('association-start', fill, stroke);
14833 }
14834
14835 return drawLine(parentGfx, element.waypoints, attrs);
14836 },
14837 'bpmn:DataInputAssociation': function(parentGfx, element) {
14838 var fill = getFillColor(element, defaultFillColor),
14839 stroke = getStrokeColor(element, defaultStrokeColor);
14840
14841 return renderer('bpmn:Association')(parentGfx, element, {
14842 markerEnd: marker('association-end', fill, stroke)
14843 });
14844 },
14845 'bpmn:DataOutputAssociation': function(parentGfx, element) {
14846 var fill = getFillColor(element, defaultFillColor),
14847 stroke = getStrokeColor(element, defaultStrokeColor);
14848
14849 return renderer('bpmn:Association')(parentGfx, element, {
14850 markerEnd: marker('association-end', fill, stroke)
14851 });
14852 },
14853 'bpmn:MessageFlow': function(parentGfx, element) {
14854
14855 var semantic = getSemantic(element),
14856 di = getDi(element);
14857
14858 var fill = getFillColor(element, defaultFillColor),
14859 stroke = getStrokeColor(element, defaultStrokeColor);
14860
14861 var pathData = createPathFromConnection(element);
14862
14863 var attrs = {
14864 markerEnd: marker('messageflow-end', fill, stroke),
14865 markerStart: marker('messageflow-start', fill, stroke),
14866 strokeDasharray: '10, 12',
14867 strokeLinecap: 'round',
14868 strokeLinejoin: 'round',
14869 strokeWidth: '1.5px',
14870 stroke: getStrokeColor(element, defaultStrokeColor)
14871 };
14872
14873 var path = drawPath(parentGfx, pathData, attrs);
14874
14875 if (semantic.messageRef) {
14876 var midPoint = path.getPointAtLength(path.getTotalLength() / 2);
14877
14878 var markerPathData = pathMap.getScaledPath('MESSAGE_FLOW_MARKER', {
14879 abspos: {
14880 x: midPoint.x,
14881 y: midPoint.y
14882 }
14883 });
14884
14885 var messageAttrs = { strokeWidth: 1 };
14886
14887 if (di.messageVisibleKind === 'initiating') {
14888 messageAttrs.fill = 'white';
14889 messageAttrs.stroke = 'black';
14890 } else {
14891 messageAttrs.fill = '#888';
14892 messageAttrs.stroke = 'white';
14893 }
14894
14895 drawPath(parentGfx, markerPathData, messageAttrs);
14896 }
14897
14898 return path;
14899 },
14900 'bpmn:DataObject': function(parentGfx, element) {
14901 var pathData = pathMap.getScaledPath('DATA_OBJECT_PATH', {
14902 xScaleFactor: 1,
14903 yScaleFactor: 1,
14904 containerWidth: element.width,
14905 containerHeight: element.height,
14906 position: {
14907 mx: 0.474,
14908 my: 0.296
14909 }
14910 });
14911
14912 var elementObject = drawPath(parentGfx, pathData, {
14913 fill: getFillColor(element, defaultFillColor),
14914 fillOpacity: DEFAULT_FILL_OPACITY,
14915 stroke: getStrokeColor(element, defaultStrokeColor)
14916 });
14917
14918 var semantic = getSemantic(element);
14919
14920 if (isCollection(semantic)) {
14921 renderDataItemCollection(parentGfx, element);
14922 }
14923
14924 return elementObject;
14925 },
14926 'bpmn:DataObjectReference': as('bpmn:DataObject'),
14927 'bpmn:DataInput': function(parentGfx, element) {
14928
14929 var arrowPathData = pathMap.getRawPath('DATA_ARROW');
14930
14931 // page
14932 var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
14933
14934 /* input arrow path */ drawPath(parentGfx, arrowPathData, { strokeWidth: 1 });
14935
14936 return elementObject;
14937 },
14938 'bpmn:DataOutput': function(parentGfx, element) {
14939 var arrowPathData = pathMap.getRawPath('DATA_ARROW');
14940
14941 // page
14942 var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
14943
14944 /* output arrow path */ drawPath(parentGfx, arrowPathData, {
14945 strokeWidth: 1,
14946 fill: 'black'
14947 });
14948
14949 return elementObject;
14950 },
14951 'bpmn:DataStoreReference': function(parentGfx, element) {
14952 var DATA_STORE_PATH = pathMap.getScaledPath('DATA_STORE', {
14953 xScaleFactor: 1,
14954 yScaleFactor: 1,
14955 containerWidth: element.width,
14956 containerHeight: element.height,
14957 position: {
14958 mx: 0,
14959 my: 0.133
14960 }
14961 });
14962
14963 var elementStore = drawPath(parentGfx, DATA_STORE_PATH, {
14964 strokeWidth: 2,
14965 fill: getFillColor(element, defaultFillColor),
14966 fillOpacity: DEFAULT_FILL_OPACITY,
14967 stroke: getStrokeColor(element, defaultStrokeColor)
14968 });
14969
14970 return elementStore;
14971 },
14972 'bpmn:BoundaryEvent': function(parentGfx, element) {
14973
14974 var semantic = getSemantic(element),
14975 cancel = semantic.cancelActivity;
14976
14977 var attrs = {
14978 strokeWidth: 1,
14979 fill: getFillColor(element, defaultFillColor),
14980 stroke: getStrokeColor(element, defaultStrokeColor)
14981 };
14982
14983 if (!cancel) {
14984 attrs.strokeDasharray = '6';
14985 attrs.strokeLinecap = 'round';
14986 }
14987
14988 // apply fillOpacity
14989 var outerAttrs = assign({}, attrs, {
14990 fillOpacity: 1
14991 });
14992
14993 // apply no-fill
14994 var innerAttrs = assign({}, attrs, {
14995 fill: 'none'
14996 });
14997
14998 var outer = renderer('bpmn:Event')(parentGfx, element, outerAttrs);
14999
15000 /* inner path */ drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, innerAttrs);
15001
15002 renderEventContent(element, parentGfx);
15003
15004 return outer;
15005 },
15006 'bpmn:Group': function(parentGfx, element) {
15007
15008 var group = drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, {
15009 stroke: getStrokeColor(element, defaultStrokeColor),
15010 strokeWidth: 1,
15011 strokeDasharray: '8,3,1,3',
15012 fill: 'none',
15013 pointerEvents: 'none'
15014 });
15015
15016 return group;
15017 },
15018 'label': function(parentGfx, element) {
15019 return renderExternalLabel(parentGfx, element);
15020 },
15021 'bpmn:TextAnnotation': function(parentGfx, element) {
15022 var style = {
15023 'fill': 'none',
15024 'stroke': 'none'
15025 };
15026
15027 var textElement = drawRect(parentGfx, element.width, element.height, 0, 0, style);
15028
15029 var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', {
15030 xScaleFactor: 1,
15031 yScaleFactor: 1,
15032 containerWidth: element.width,
15033 containerHeight: element.height,
15034 position: {
15035 mx: 0.0,
15036 my: 0.0
15037 }
15038 });
15039
15040 drawPath(parentGfx, textPathData, {
15041 stroke: getStrokeColor(element, defaultStrokeColor)
15042 });
15043
15044 var text = getSemantic(element).text || '';
15045 renderLabel(parentGfx, text, {
15046 box: element,
15047 align: 'left-top',
15048 padding: 5,
15049 style: {
15050 fill: getStrokeColor(element, defaultStrokeColor)
15051 }
15052 });
15053
15054 return textElement;
15055 },
15056 'ParticipantMultiplicityMarker': function(parentGfx, element) {
15057 var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
15058 xScaleFactor: 1,
15059 yScaleFactor: 1,
15060 containerWidth: element.width,
15061 containerHeight: element.height,
15062 position: {
15063 mx: ((element.width / 2) / element.width),
15064 my: (element.height - 15) / element.height
15065 }
15066 });
15067
15068 drawMarker('participant-multiplicity', parentGfx, markerPath, {
15069 strokeWidth: 1,
15070 fill: getFillColor(element, defaultFillColor),
15071 stroke: getStrokeColor(element, defaultStrokeColor)
15072 });
15073 },
15074 'SubProcessMarker': function(parentGfx, element) {
15075 var markerRect = drawRect(parentGfx, 14, 14, 0, {
15076 strokeWidth: 1,
15077 fill: getFillColor(element, defaultFillColor),
15078 stroke: getStrokeColor(element, defaultStrokeColor)
15079 });
15080
15081 // Process marker is placed in the middle of the box
15082 // therefore fixed values can be used here
15083 translate(markerRect, element.width / 2 - 7.5, element.height - 20);
15084
15085 var markerPath = pathMap.getScaledPath('MARKER_SUB_PROCESS', {
15086 xScaleFactor: 1.5,
15087 yScaleFactor: 1.5,
15088 containerWidth: element.width,
15089 containerHeight: element.height,
15090 position: {
15091 mx: (element.width / 2 - 7.5) / element.width,
15092 my: (element.height - 20) / element.height
15093 }
15094 });
15095
15096 drawMarker('sub-process', parentGfx, markerPath, {
15097 fill: getFillColor(element, defaultFillColor),
15098 stroke: getStrokeColor(element, defaultStrokeColor)
15099 });
15100 },
15101 'ParallelMarker': function(parentGfx, element, position) {
15102 var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
15103 xScaleFactor: 1,
15104 yScaleFactor: 1,
15105 containerWidth: element.width,
15106 containerHeight: element.height,
15107 position: {
15108 mx: ((element.width / 2 + position.parallel) / element.width),
15109 my: (element.height - 20) / element.height
15110 }
15111 });
15112
15113 drawMarker('parallel', parentGfx, markerPath, {
15114 fill: getFillColor(element, defaultFillColor),
15115 stroke: getStrokeColor(element, defaultStrokeColor)
15116 });
15117 },
15118 'SequentialMarker': function(parentGfx, element, position) {
15119 var markerPath = pathMap.getScaledPath('MARKER_SEQUENTIAL', {
15120 xScaleFactor: 1,
15121 yScaleFactor: 1,
15122 containerWidth: element.width,
15123 containerHeight: element.height,
15124 position: {
15125 mx: ((element.width / 2 + position.seq) / element.width),
15126 my: (element.height - 19) / element.height
15127 }
15128 });
15129
15130 drawMarker('sequential', parentGfx, markerPath, {
15131 fill: getFillColor(element, defaultFillColor),
15132 stroke: getStrokeColor(element, defaultStrokeColor)
15133 });
15134 },
15135 'CompensationMarker': function(parentGfx, element, position) {
15136 var markerMath = pathMap.getScaledPath('MARKER_COMPENSATION', {
15137 xScaleFactor: 1,
15138 yScaleFactor: 1,
15139 containerWidth: element.width,
15140 containerHeight: element.height,
15141 position: {
15142 mx: ((element.width / 2 + position.compensation) / element.width),
15143 my: (element.height - 13) / element.height
15144 }
15145 });
15146
15147 drawMarker('compensation', parentGfx, markerMath, {
15148 strokeWidth: 1,
15149 fill: getFillColor(element, defaultFillColor),
15150 stroke: getStrokeColor(element, defaultStrokeColor)
15151 });
15152 },
15153 'LoopMarker': function(parentGfx, element, position) {
15154 var markerPath = pathMap.getScaledPath('MARKER_LOOP', {
15155 xScaleFactor: 1,
15156 yScaleFactor: 1,
15157 containerWidth: element.width,
15158 containerHeight: element.height,
15159 position: {
15160 mx: ((element.width / 2 + position.loop) / element.width),
15161 my: (element.height - 7) / element.height
15162 }
15163 });
15164
15165 drawMarker('loop', parentGfx, markerPath, {
15166 strokeWidth: 1,
15167 fill: getFillColor(element, defaultFillColor),
15168 stroke: getStrokeColor(element, defaultStrokeColor),
15169 strokeLinecap: 'round',
15170 strokeMiterlimit: 0.5
15171 });
15172 },
15173 'AdhocMarker': function(parentGfx, element, position) {
15174 var markerPath = pathMap.getScaledPath('MARKER_ADHOC', {
15175 xScaleFactor: 1,
15176 yScaleFactor: 1,
15177 containerWidth: element.width,
15178 containerHeight: element.height,
15179 position: {
15180 mx: ((element.width / 2 + position.adhoc) / element.width),
15181 my: (element.height - 15) / element.height
15182 }
15183 });
15184
15185 drawMarker('adhoc', parentGfx, markerPath, {
15186 strokeWidth: 1,
15187 fill: getStrokeColor(element, defaultStrokeColor),
15188 stroke: getStrokeColor(element, defaultStrokeColor)
15189 });
15190 }
15191 };
15192
15193 function attachTaskMarkers(parentGfx, element, taskMarkers) {
15194 var obj = getSemantic(element);
15195
15196 var subprocess = taskMarkers && taskMarkers.indexOf('SubProcessMarker') !== -1;
15197 var position;
15198
15199 if (subprocess) {
15200 position = {
15201 seq: -21,
15202 parallel: -22,
15203 compensation: -42,
15204 loop: -18,
15205 adhoc: 10
15206 };
15207 } else {
15208 position = {
15209 seq: -3,
15210 parallel: -6,
15211 compensation: -27,
15212 loop: 0,
15213 adhoc: 10
15214 };
15215 }
15216
15217 forEach(taskMarkers, function(marker) {
15218 renderer(marker)(parentGfx, element, position);
15219 });
15220
15221 if (obj.isForCompensation) {
15222 renderer('CompensationMarker')(parentGfx, element, position);
15223 }
15224
15225 if (obj.$type === 'bpmn:AdHocSubProcess') {
15226 renderer('AdhocMarker')(parentGfx, element, position);
15227 }
15228
15229 var loopCharacteristics = obj.loopCharacteristics,
15230 isSequential = loopCharacteristics && loopCharacteristics.isSequential;
15231
15232 if (loopCharacteristics) {
15233
15234 if (isSequential === undefined) {
15235 renderer('LoopMarker')(parentGfx, element, position);
15236 }
15237
15238 if (isSequential === false) {
15239 renderer('ParallelMarker')(parentGfx, element, position);
15240 }
15241
15242 if (isSequential === true) {
15243 renderer('SequentialMarker')(parentGfx, element, position);
15244 }
15245 }
15246 }
15247
15248 function renderDataItemCollection(parentGfx, element) {
15249
15250 var yPosition = (element.height - 16) / element.height;
15251
15252 var pathData = pathMap.getScaledPath('DATA_OBJECT_COLLECTION_PATH', {
15253 xScaleFactor: 1,
15254 yScaleFactor: 1,
15255 containerWidth: element.width,
15256 containerHeight: element.height,
15257 position: {
15258 mx: 0.451,
15259 my: yPosition
15260 }
15261 });
15262
15263 /* collection path */ drawPath(parentGfx, pathData, {
15264 strokeWidth: 2
15265 });
15266 }
15267
15268
15269 // extension API, use at your own risk
15270 this._drawPath = drawPath;
15271
15272 }
15273
15274
15275 inherits_browser(BpmnRenderer, BaseRenderer);
15276
15277 BpmnRenderer.$inject = [
15278 'config.bpmnRenderer',
15279 'eventBus',
15280 'styles',
15281 'pathMap',
15282 'canvas',
15283 'textRenderer'
15284 ];
15285
15286
15287 BpmnRenderer.prototype.canRender = function(element) {
15288 return is$1(element, 'bpmn:BaseElement');
15289 };
15290
15291 BpmnRenderer.prototype.drawShape = function(parentGfx, element) {
15292 var type = element.type;
15293 var h = this.handlers[type];
15294
15295 /* jshint -W040 */
15296 return h(parentGfx, element);
15297 };
15298
15299 BpmnRenderer.prototype.drawConnection = function(parentGfx, element) {
15300 var type = element.type;
15301 var h = this.handlers[type];
15302
15303 /* jshint -W040 */
15304 return h(parentGfx, element);
15305 };
15306
15307 BpmnRenderer.prototype.getShapePath = function(element) {
15308
15309 if (is$1(element, 'bpmn:Event')) {
15310 return getCirclePath(element);
15311 }
15312
15313 if (is$1(element, 'bpmn:Activity')) {
15314 return getRoundRectPath(element, TASK_BORDER_RADIUS);
15315 }
15316
15317 if (is$1(element, 'bpmn:Gateway')) {
15318 return getDiamondPath(element);
15319 }
15320
15321 return getRectPath(element);
15322 };
15323
15324 var DEFAULT_BOX_PADDING = 0;
15325
15326 var DEFAULT_LABEL_SIZE = {
15327 width: 150,
15328 height: 50
15329 };
15330
15331
15332 function parseAlign(align) {
15333
15334 var parts = align.split('-');
15335
15336 return {
15337 horizontal: parts[0] || 'center',
15338 vertical: parts[1] || 'top'
15339 };
15340 }
15341
15342 function parsePadding(padding) {
15343
15344 if (isObject(padding)) {
15345 return assign({ top: 0, left: 0, right: 0, bottom: 0 }, padding);
15346 } else {
15347 return {
15348 top: padding,
15349 left: padding,
15350 right: padding,
15351 bottom: padding
15352 };
15353 }
15354 }
15355
15356 function getTextBBox(text, fakeText) {
15357
15358 fakeText.textContent = text;
15359
15360 var textBBox;
15361
15362 try {
15363 var bbox,
15364 emptyLine = text === '';
15365
15366 // add dummy text, when line is empty to
15367 // determine correct height
15368 fakeText.textContent = emptyLine ? 'dummy' : text;
15369
15370 textBBox = fakeText.getBBox();
15371
15372 // take text rendering related horizontal
15373 // padding into account
15374 bbox = {
15375 width: textBBox.width + textBBox.x * 2,
15376 height: textBBox.height
15377 };
15378
15379 if (emptyLine) {
15380
15381 // correct width
15382 bbox.width = 0;
15383 }
15384
15385 return bbox;
15386 } catch (e) {
15387 return { width: 0, height: 0 };
15388 }
15389 }
15390
15391
15392 /**
15393 * Layout the next line and return the layouted element.
15394 *
15395 * Alters the lines passed.
15396 *
15397 * @param {Array<String>} lines
15398 * @return {Object} the line descriptor, an object { width, height, text }
15399 */
15400 function layoutNext(lines, maxWidth, fakeText) {
15401
15402 var originalLine = lines.shift(),
15403 fitLine = originalLine;
15404
15405 var textBBox;
15406
15407 for (;;) {
15408 textBBox = getTextBBox(fitLine, fakeText);
15409
15410 textBBox.width = fitLine ? textBBox.width : 0;
15411
15412 // try to fit
15413 if (fitLine === ' ' || fitLine === '' || textBBox.width < Math.round(maxWidth) || fitLine.length < 2) {
15414 return fit(lines, fitLine, originalLine, textBBox);
15415 }
15416
15417 fitLine = shortenLine(fitLine, textBBox.width, maxWidth);
15418 }
15419 }
15420
15421 function fit(lines, fitLine, originalLine, textBBox) {
15422 if (fitLine.length < originalLine.length) {
15423 var remainder = originalLine.slice(fitLine.length).trim();
15424
15425 lines.unshift(remainder);
15426 }
15427
15428 return {
15429 width: textBBox.width,
15430 height: textBBox.height,
15431 text: fitLine
15432 };
15433 }
15434
15435
15436 /**
15437 * Shortens a line based on spacing and hyphens.
15438 * Returns the shortened result on success.
15439 *
15440 * @param {String} line
15441 * @param {Number} maxLength the maximum characters of the string
15442 * @return {String} the shortened string
15443 */
15444 function semanticShorten(line, maxLength) {
15445 var parts = line.split(/(\s|-)/g),
15446 part,
15447 shortenedParts = [],
15448 length = 0;
15449
15450 // try to shorten via spaces + hyphens
15451 if (parts.length > 1) {
15452 while ((part = parts.shift())) {
15453 if (part.length + length < maxLength) {
15454 shortenedParts.push(part);
15455 length += part.length;
15456 } else {
15457
15458 // remove previous part, too if hyphen does not fit anymore
15459 if (part === '-') {
15460 shortenedParts.pop();
15461 }
15462
15463 break;
15464 }
15465 }
15466 }
15467
15468 return shortenedParts.join('');
15469 }
15470
15471
15472 function shortenLine(line, width, maxWidth) {
15473 var length = Math.max(line.length * (maxWidth / width), 1);
15474
15475 // try to shorten semantically (i.e. based on spaces and hyphens)
15476 var shortenedLine = semanticShorten(line, length);
15477
15478 if (!shortenedLine) {
15479
15480 // force shorten by cutting the long word
15481 shortenedLine = line.slice(0, Math.max(Math.round(length - 1), 1));
15482 }
15483
15484 return shortenedLine;
15485 }
15486
15487
15488 function getHelperSvg() {
15489 var helperSvg = document.getElementById('helper-svg');
15490
15491 if (!helperSvg) {
15492 helperSvg = create('svg');
15493
15494 attr$1(helperSvg, {
15495 id: 'helper-svg',
15496 width: 0,
15497 height: 0,
15498 style: 'visibility: hidden; position: fixed'
15499 });
15500
15501 document.body.appendChild(helperSvg);
15502 }
15503
15504 return helperSvg;
15505 }
15506
15507
15508 /**
15509 * Creates a new label utility
15510 *
15511 * @param {Object} config
15512 * @param {Dimensions} config.size
15513 * @param {Number} config.padding
15514 * @param {Object} config.style
15515 * @param {String} config.align
15516 */
15517 function Text(config) {
15518
15519 this._config = assign({}, {
15520 size: DEFAULT_LABEL_SIZE,
15521 padding: DEFAULT_BOX_PADDING,
15522 style: {},
15523 align: 'center-top'
15524 }, config || {});
15525 }
15526
15527 /**
15528 * Returns the layouted text as an SVG element.
15529 *
15530 * @param {String} text
15531 * @param {Object} options
15532 *
15533 * @return {SVGElement}
15534 */
15535 Text.prototype.createText = function(text, options) {
15536 return this.layoutText(text, options).element;
15537 };
15538
15539 /**
15540 * Returns a labels layouted dimensions.
15541 *
15542 * @param {String} text to layout
15543 * @param {Object} options
15544 *
15545 * @return {Dimensions}
15546 */
15547 Text.prototype.getDimensions = function(text, options) {
15548 return this.layoutText(text, options).dimensions;
15549 };
15550
15551 /**
15552 * Creates and returns a label and its bounding box.
15553 *
15554 * @method Text#createText
15555 *
15556 * @param {String} text the text to render on the label
15557 * @param {Object} options
15558 * @param {String} options.align how to align in the bounding box.
15559 * Any of { 'center-middle', 'center-top' },
15560 * defaults to 'center-top'.
15561 * @param {String} options.style style to be applied to the text
15562 * @param {boolean} options.fitBox indicates if box will be recalculated to
15563 * fit text
15564 *
15565 * @return {Object} { element, dimensions }
15566 */
15567 Text.prototype.layoutText = function(text, options) {
15568 var box = assign({}, this._config.size, options.box),
15569 style = assign({}, this._config.style, options.style),
15570 align = parseAlign(options.align || this._config.align),
15571 padding = parsePadding(options.padding !== undefined ? options.padding : this._config.padding),
15572 fitBox = options.fitBox || false;
15573
15574 var lineHeight = getLineHeight(style);
15575
15576 var lines = text.split(/\r?\n/g),
15577 layouted = [];
15578
15579 var maxWidth = box.width - padding.left - padding.right;
15580
15581 // ensure correct rendering by attaching helper text node to invisible SVG
15582 var helperText = create('text');
15583 attr$1(helperText, { x: 0, y: 0 });
15584 attr$1(helperText, style);
15585
15586 var helperSvg = getHelperSvg();
15587
15588 append(helperSvg, helperText);
15589
15590 while (lines.length) {
15591 layouted.push(layoutNext(lines, maxWidth, helperText));
15592 }
15593
15594 if (align.vertical === 'middle') {
15595 padding.top = padding.bottom = 0;
15596 }
15597
15598 var totalHeight = reduce(layouted, function(sum, line, idx) {
15599 return sum + (lineHeight || line.height);
15600 }, 0) + padding.top + padding.bottom;
15601
15602 var maxLineWidth = reduce(layouted, function(sum, line, idx) {
15603 return line.width > sum ? line.width : sum;
15604 }, 0);
15605
15606 // the y position of the next line
15607 var y = padding.top;
15608
15609 if (align.vertical === 'middle') {
15610 y += (box.height - totalHeight) / 2;
15611 }
15612
15613 // magic number initial offset
15614 y -= (lineHeight || layouted[0].height) / 4;
15615
15616
15617 var textElement = create('text');
15618
15619 attr$1(textElement, style);
15620
15621 // layout each line taking into account that parent
15622 // shape might resize to fit text size
15623 forEach(layouted, function(line) {
15624
15625 var x;
15626
15627 y += (lineHeight || line.height);
15628
15629 switch (align.horizontal) {
15630 case 'left':
15631 x = padding.left;
15632 break;
15633
15634 case 'right':
15635 x = ((fitBox ? maxLineWidth : maxWidth)
15636 - padding.right - line.width);
15637 break;
15638
15639 default:
15640
15641 // aka center
15642 x = Math.max((((fitBox ? maxLineWidth : maxWidth)
15643 - line.width) / 2 + padding.left), 0);
15644 }
15645
15646 var tspan = create('tspan');
15647 attr$1(tspan, { x: x, y: y });
15648
15649 tspan.textContent = line.text;
15650
15651 append(textElement, tspan);
15652 });
15653
15654 remove$1(helperText);
15655
15656 var dimensions = {
15657 width: maxLineWidth,
15658 height: totalHeight
15659 };
15660
15661 return {
15662 dimensions: dimensions,
15663 element: textElement
15664 };
15665 };
15666
15667
15668 function getLineHeight(style) {
15669 if ('fontSize' in style && 'lineHeight' in style) {
15670 return style.lineHeight * parseInt(style.fontSize, 10);
15671 }
15672 }
15673
15674 var DEFAULT_FONT_SIZE = 12;
15675 var LINE_HEIGHT_RATIO = 1.2;
15676
15677 var MIN_TEXT_ANNOTATION_HEIGHT = 30;
15678
15679
15680 function TextRenderer(config) {
15681
15682 var defaultStyle = assign({
15683 fontFamily: 'Arial, sans-serif',
15684 fontSize: DEFAULT_FONT_SIZE,
15685 fontWeight: 'normal',
15686 lineHeight: LINE_HEIGHT_RATIO
15687 }, config && config.defaultStyle || {});
15688
15689 var fontSize = parseInt(defaultStyle.fontSize, 10) - 1;
15690
15691 var externalStyle = assign({}, defaultStyle, {
15692 fontSize: fontSize
15693 }, config && config.externalStyle || {});
15694
15695 var textUtil = new Text({
15696 style: defaultStyle
15697 });
15698
15699 /**
15700 * Get the new bounds of an externally rendered,
15701 * layouted label.
15702 *
15703 * @param {Bounds} bounds
15704 * @param {String} text
15705 *
15706 * @return {Bounds}
15707 */
15708 this.getExternalLabelBounds = function(bounds, text) {
15709
15710 var layoutedDimensions = textUtil.getDimensions(text, {
15711 box: {
15712 width: 90,
15713 height: 30,
15714 x: bounds.width / 2 + bounds.x,
15715 y: bounds.height / 2 + bounds.y
15716 },
15717 style: externalStyle
15718 });
15719
15720 // resize label shape to fit label text
15721 return {
15722 x: Math.round(bounds.x + bounds.width / 2 - layoutedDimensions.width / 2),
15723 y: Math.round(bounds.y),
15724 width: Math.ceil(layoutedDimensions.width),
15725 height: Math.ceil(layoutedDimensions.height)
15726 };
15727
15728 };
15729
15730 /**
15731 * Get the new bounds of text annotation.
15732 *
15733 * @param {Bounds} bounds
15734 * @param {String} text
15735 *
15736 * @return {Bounds}
15737 */
15738 this.getTextAnnotationBounds = function(bounds, text) {
15739
15740 var layoutedDimensions = textUtil.getDimensions(text, {
15741 box: bounds,
15742 style: defaultStyle,
15743 align: 'left-top',
15744 padding: 5
15745 });
15746
15747 return {
15748 x: bounds.x,
15749 y: bounds.y,
15750 width: bounds.width,
15751 height: Math.max(MIN_TEXT_ANNOTATION_HEIGHT, Math.round(layoutedDimensions.height))
15752 };
15753 };
15754
15755 /**
15756 * Create a layouted text element.
15757 *
15758 * @param {String} text
15759 * @param {Object} [options]
15760 *
15761 * @return {SVGElement} rendered text
15762 */
15763 this.createText = function(text, options) {
15764 return textUtil.createText(text, options || {});
15765 };
15766
15767 /**
15768 * Get default text style.
15769 */
15770 this.getDefaultStyle = function() {
15771 return defaultStyle;
15772 };
15773
15774 /**
15775 * Get the external text style.
15776 */
15777 this.getExternalStyle = function() {
15778 return externalStyle;
15779 };
15780
15781 }
15782
15783 TextRenderer.$inject = [
15784 'config.textRenderer'
15785 ];
15786
15787 /**
15788 * Map containing SVG paths needed by BpmnRenderer.
15789 */
15790
15791 function PathMap() {
15792
15793 /**
15794 * Contains a map of path elements
15795 *
15796 * <h1>Path definition</h1>
15797 * A parameterized path is defined like this:
15798 * <pre>
15799 * 'GATEWAY_PARALLEL': {
15800 * d: 'm {mx},{my} {e.x0},0 0,{e.x1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
15801 '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
15802 * height: 17.5,
15803 * width: 17.5,
15804 * heightElements: [2.5, 7.5],
15805 * widthElements: [2.5, 7.5]
15806 * }
15807 * </pre>
15808 * <p>It's important to specify a correct <b>height and width</b> for the path as the scaling
15809 * is based on the ratio between the specified height and width in this object and the
15810 * height and width that is set as scale target (Note x,y coordinates will be scaled with
15811 * individual ratios).</p>
15812 * <p>The '<b>heightElements</b>' and '<b>widthElements</b>' array must contain the values that will be scaled.
15813 * The scaling is based on the computed ratios.
15814 * Coordinates on the y axis should be in the <b>heightElement</b>'s array, they will be scaled using
15815 * the computed ratio coefficient.
15816 * In the parameterized path the scaled values can be accessed through the 'e' object in {} brackets.
15817 * <ul>
15818 * <li>The values for the y axis can be accessed in the path string using {e.y0}, {e.y1}, ....</li>
15819 * <li>The values for the x axis can be accessed in the path string using {e.x0}, {e.x1}, ....</li>
15820 * </ul>
15821 * The numbers x0, x1 respectively y0, y1, ... map to the corresponding array index.
15822 * </p>
15823 */
15824 this.pathMap = {
15825 'EVENT_MESSAGE': {
15826 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}',
15827 height: 36,
15828 width: 36,
15829 heightElements: [6, 14],
15830 widthElements: [10.5, 21]
15831 },
15832 'EVENT_SIGNAL': {
15833 d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x1},0 Z',
15834 height: 36,
15835 width: 36,
15836 heightElements: [18],
15837 widthElements: [10, 20]
15838 },
15839 'EVENT_ESCALATION': {
15840 d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x0},-{e.y1} l -{e.x0},{e.y1} Z',
15841 height: 36,
15842 width: 36,
15843 heightElements: [20, 7],
15844 widthElements: [8]
15845 },
15846 'EVENT_CONDITIONAL': {
15847 d: 'M {e.x0},{e.y0} l {e.x1},0 l 0,{e.y2} l -{e.x1},0 Z ' +
15848 'M {e.x2},{e.y3} l {e.x0},0 ' +
15849 'M {e.x2},{e.y4} l {e.x0},0 ' +
15850 'M {e.x2},{e.y5} l {e.x0},0 ' +
15851 'M {e.x2},{e.y6} l {e.x0},0 ' +
15852 'M {e.x2},{e.y7} l {e.x0},0 ' +
15853 'M {e.x2},{e.y8} l {e.x0},0 ',
15854 height: 36,
15855 width: 36,
15856 heightElements: [8.5, 14.5, 18, 11.5, 14.5, 17.5, 20.5, 23.5, 26.5],
15857 widthElements: [10.5, 14.5, 12.5]
15858 },
15859 'EVENT_LINK': {
15860 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',
15861 height: 36,
15862 width: 36,
15863 heightElements: [4.4375, 6.75, 7.8125],
15864 widthElements: [9.84375, 13.5]
15865 },
15866 'EVENT_ERROR': {
15867 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',
15868 height: 36,
15869 width: 36,
15870 heightElements: [0.023, 8.737, 8.151, 16.564, 10.591, 8.714],
15871 widthElements: [0.085, 6.672, 6.97, 4.273, 5.337, 6.636]
15872 },
15873 'EVENT_CANCEL_45': {
15874 d: 'm {mx},{my} -{e.x1},0 0,{e.x0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
15875 '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
15876 height: 36,
15877 width: 36,
15878 heightElements: [4.75, 8.5],
15879 widthElements: [4.75, 8.5]
15880 },
15881 'EVENT_COMPENSATION': {
15882 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',
15883 height: 36,
15884 width: 36,
15885 heightElements: [6.5, 13, 0.4, 6.1],
15886 widthElements: [9, 9.3, 8.7]
15887 },
15888 'EVENT_TIMER_WH': {
15889 d: 'M {mx},{my} l {e.x0},-{e.y0} m -{e.x0},{e.y0} l {e.x1},{e.y1} ',
15890 height: 36,
15891 width: 36,
15892 heightElements: [10, 2],
15893 widthElements: [3, 7]
15894 },
15895 'EVENT_TIMER_LINE': {
15896 d: 'M {mx},{my} ' +
15897 'm {e.x0},{e.y0} l -{e.x1},{e.y1} ',
15898 height: 36,
15899 width: 36,
15900 heightElements: [10, 3],
15901 widthElements: [0, 0]
15902 },
15903 'EVENT_MULTIPLE': {
15904 d:'m {mx},{my} {e.x1},-{e.y0} {e.x1},{e.y0} -{e.x0},{e.y1} -{e.x2},0 z',
15905 height: 36,
15906 width: 36,
15907 heightElements: [6.28099, 12.56199],
15908 widthElements: [3.1405, 9.42149, 12.56198]
15909 },
15910 'EVENT_PARALLEL_MULTIPLE': {
15911 d:'m {mx},{my} {e.x0},0 0,{e.y1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
15912 '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
15913 height: 36,
15914 width: 36,
15915 heightElements: [2.56228, 7.68683],
15916 widthElements: [2.56228, 7.68683]
15917 },
15918 'GATEWAY_EXCLUSIVE': {
15919 d:'m {mx},{my} {e.x0},{e.y0} {e.x1},{e.y0} {e.x2},0 {e.x4},{e.y2} ' +
15920 '{e.x4},{e.y1} {e.x2},0 {e.x1},{e.y3} {e.x0},{e.y3} ' +
15921 '{e.x3},0 {e.x5},{e.y1} {e.x5},{e.y2} {e.x3},0 z',
15922 height: 17.5,
15923 width: 17.5,
15924 heightElements: [8.5, 6.5312, -6.5312, -8.5],
15925 widthElements: [6.5, -6.5, 3, -3, 5, -5]
15926 },
15927 'GATEWAY_PARALLEL': {
15928 d:'m {mx},{my} 0,{e.y1} -{e.x1},0 0,{e.y0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
15929 '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
15930 height: 30,
15931 width: 30,
15932 heightElements: [5, 12.5],
15933 widthElements: [5, 12.5]
15934 },
15935 'GATEWAY_EVENT_BASED': {
15936 d:'m {mx},{my} {e.x0},{e.y0} {e.x0},{e.y1} {e.x1},{e.y2} {e.x2},0 z',
15937 height: 11,
15938 width: 11,
15939 heightElements: [-6, 6, 12, -12],
15940 widthElements: [9, -3, -12]
15941 },
15942 'GATEWAY_COMPLEX': {
15943 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} ' +
15944 '{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} ' +
15945 '{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} ' +
15946 '-{e.x0},{e.y1} 0,-{e.y0} -{e.x3},0 z',
15947 height: 17.125,
15948 width: 17.125,
15949 heightElements: [4.875, 3.4375, 2.125, 3],
15950 widthElements: [3.4375, 2.125, 4.875, 3]
15951 },
15952 'DATA_OBJECT_PATH': {
15953 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',
15954 height: 61,
15955 width: 51,
15956 heightElements: [10, 50, 60],
15957 widthElements: [10, 40, 50, 60]
15958 },
15959 'DATA_OBJECT_COLLECTION_PATH': {
15960 d:'m {mx}, {my} ' +
15961 'm 0 15 l 0 -15 ' +
15962 'm 4 15 l 0 -15 ' +
15963 'm 4 15 l 0 -15 ',
15964 height: 61,
15965 width: 51,
15966 heightElements: [12],
15967 widthElements: [1, 6, 12, 15]
15968 },
15969 'DATA_ARROW': {
15970 d:'m 5,9 9,0 0,-3 5,5 -5,5 0,-3 -9,0 z',
15971 height: 61,
15972 width: 51,
15973 heightElements: [],
15974 widthElements: []
15975 },
15976 'DATA_STORE': {
15977 d:'m {mx},{my} ' +
15978 'l 0,{e.y2} ' +
15979 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' +
15980 'l 0,-{e.y2} ' +
15981 'c -{e.x0},-{e.y1} -{e.x1},-{e.y1} -{e.x2},0' +
15982 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' +
15983 'm -{e.x2},{e.y0}' +
15984 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0' +
15985 'm -{e.x2},{e.y0}' +
15986 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0',
15987 height: 61,
15988 width: 61,
15989 heightElements: [7, 10, 45],
15990 widthElements: [2, 58, 60]
15991 },
15992 'TEXT_ANNOTATION': {
15993 d: 'm {mx}, {my} m 10,0 l -10,0 l 0,{e.y0} l 10,0',
15994 height: 30,
15995 width: 10,
15996 heightElements: [30],
15997 widthElements: [10]
15998 },
15999 'MARKER_SUB_PROCESS': {
16000 d: 'm{mx},{my} m 7,2 l 0,10 m -5,-5 l 10,0',
16001 height: 10,
16002 width: 10,
16003 heightElements: [],
16004 widthElements: []
16005 },
16006 'MARKER_PARALLEL': {
16007 d: 'm{mx},{my} m 3,2 l 0,10 m 3,-10 l 0,10 m 3,-10 l 0,10',
16008 height: 10,
16009 width: 10,
16010 heightElements: [],
16011 widthElements: []
16012 },
16013 'MARKER_SEQUENTIAL': {
16014 d: 'm{mx},{my} m 0,3 l 10,0 m -10,3 l 10,0 m -10,3 l 10,0',
16015 height: 10,
16016 width: 10,
16017 heightElements: [],
16018 widthElements: []
16019 },
16020 'MARKER_COMPENSATION': {
16021 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',
16022 height: 10,
16023 width: 21,
16024 heightElements: [],
16025 widthElements: []
16026 },
16027 'MARKER_LOOP': {
16028 d: 'm {mx},{my} c 3.526979,0 6.386161,-2.829858 6.386161,-6.320661 0,-3.490806 -2.859182,-6.320661 ' +
16029 '-6.386161,-6.320661 -3.526978,0 -6.38616,2.829855 -6.38616,6.320661 0,1.745402 ' +
16030 '0.714797,3.325567 1.870463,4.469381 0.577834,0.571908 1.265885,1.034728 2.029916,1.35457 ' +
16031 'l -0.718163,-3.909793 m 0.718163,3.909793 -3.885211,0.802902',
16032 height: 13.9,
16033 width: 13.7,
16034 heightElements: [],
16035 widthElements: []
16036 },
16037 'MARKER_ADHOC': {
16038 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 ' +
16039 '3.85579,1.15803 5.76082,1.79107 1.06385,0.34139996 2.24454,0.1438 3.18759,-0.43767 0.61743,-0.33642 ' +
16040 '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 ' +
16041 '-3.6918,1.66181996 -1.24459,0.0927 -2.46671,-0.2491 -3.59505,-0.74812 -1.35789,-0.55965 ' +
16042 '-2.75133,-1.33436996 -4.27027,-1.18121996 -1.37741,0.14601 -2.41842,1.13685996 -3.44288,1.96782996 z',
16043 height: 4,
16044 width: 15,
16045 heightElements: [],
16046 widthElements: []
16047 },
16048 'TASK_TYPE_SEND': {
16049 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}',
16050 height: 14,
16051 width: 21,
16052 heightElements: [6, 14],
16053 widthElements: [10.5, 21]
16054 },
16055 'TASK_TYPE_SCRIPT': {
16056 d: 'm {mx},{my} c 9.966553,-6.27276 -8.000926,-7.91932 2.968968,-14.938 l -8.802728,0 ' +
16057 'c -10.969894,7.01868 6.997585,8.66524 -2.968967,14.938 z ' +
16058 'm -7,-12 l 5,0 ' +
16059 'm -4.5,3 l 4.5,0 ' +
16060 'm -3,3 l 5,0' +
16061 'm -4,3 l 5,0',
16062 height: 15,
16063 width: 12.6,
16064 heightElements: [6, 14],
16065 widthElements: [10.5, 21]
16066 },
16067 'TASK_TYPE_USER_1': {
16068 d: 'm {mx},{my} c 0.909,-0.845 1.594,-2.049 1.594,-3.385 0,-2.554 -1.805,-4.62199999 ' +
16069 '-4.357,-4.62199999 -2.55199998,0 -4.28799998,2.06799999 -4.28799998,4.62199999 0,1.348 ' +
16070 '0.974,2.562 1.89599998,3.405 -0.52899998,0.187 -5.669,2.097 -5.794,4.7560005 v 6.718 ' +
16071 'h 17 v -6.718 c 0,-2.2980005 -5.5279996,-4.5950005 -6.0509996,-4.7760005 z' +
16072 'm -8,6 l 0,5.5 m 11,0 l 0,-5'
16073 },
16074 'TASK_TYPE_USER_2': {
16075 d: 'm {mx},{my} m 2.162,1.009 c 0,2.4470005 -2.158,4.4310005 -4.821,4.4310005 ' +
16076 '-2.66499998,0 -4.822,-1.981 -4.822,-4.4310005 '
16077 },
16078 'TASK_TYPE_USER_3': {
16079 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 ' +
16080 '4.124,0.965 -0.098,-0.57 -0.117,-3.79099999 -4.191,-4.13599999 -3.57499998,0.001 ' +
16081 '-4.20799998,3.36699999 -4.20699998,4.34799999 z'
16082 },
16083 'TASK_TYPE_MANUAL': {
16084 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 ' +
16085 '-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 ' +
16086 '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 ' +
16087 '-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 ' +
16088 '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 ' +
16089 '-10.86,-0.003 -11.0829995,-0.003 -0.022,-0.047 -0.045,-0.094 -0.069,-0.139 0.3939995,-0.319 ' +
16090 '2.0409995,-1.626 2.4149995,-2.017 0.469,-0.4870005 0.519,-1.1650005 0.162,-1.6040005 -0.414,-0.511 ' +
16091 '-0.973,-0.5 -1.48,-0.236 -1.4609995,0.764 -6.5999995,3.6430005 -7.7329995,4.2710005 -0.9,0.499 ' +
16092 '-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 ' +
16093 '-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 ' +
16094 '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 ' +
16095 '-5.824,-0.004 -6.04,-0.004 10e-4,-0.084 0.003,-0.586 10e-4,-0.67 z'
16096 },
16097 'TASK_TYPE_INSTANTIATING_SEND': {
16098 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'
16099 },
16100 'TASK_TYPE_SERVICE': {
16101 d: 'm {mx},{my} v -1.71335 c 0.352326,-0.0705 0.703932,-0.17838 1.047628,-0.32133 ' +
16102 '0.344416,-0.14465 0.665822,-0.32133 0.966377,-0.52145 l 1.19431,1.18005 1.567487,-1.57688 ' +
16103 '-1.195028,-1.18014 c 0.403376,-0.61394 0.683079,-1.29908 0.825447,-2.01824 l 1.622133,-0.01 ' +
16104 'v -2.2196 l -1.636514,0.01 c -0.07333,-0.35153 -0.178319,-0.70024 -0.323564,-1.04372 ' +
16105 '-0.145244,-0.34406 -0.321407,-0.6644 -0.522735,-0.96217 l 1.131035,-1.13631 -1.583305,-1.56293 ' +
16106 '-1.129598,1.13589 c -0.614052,-0.40108 -1.302883,-0.68093 -2.022633,-0.82247 l 0.0093,-1.61852 ' +
16107 '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 ' +
16108 '-0.665102,0.32092 -0.9635006,0.52046 l -1.1698628,-1.15823 -1.5667691,1.5792 1.1684265,1.15669 ' +
16109 'c -0.4026573,0.61283 -0.68308,1.29797 -0.8247287,2.01713 l -1.6588041,0.003 v 2.22174 ' +
16110 'l 1.6724648,-0.006 c 0.073327,0.35077 0.1797598,0.70243 0.3242851,1.04472 0.1452428,0.34448 ' +
16111 '0.3214064,0.6644 0.5227339,0.96066 l -1.1993431,1.19723 1.5840256,1.56011 1.1964668,-1.19348 ' +
16112 'c 0.6140517,0.40346 1.3028827,0.68232 2.0233517,0.82331 l 7.19e-4,1.69892 h 2.226848 z ' +
16113 'm 0.221462,-3.9957 c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
16114 '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
16115 '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
16116 },
16117 'TASK_TYPE_SERVICE_FILL': {
16118 d: 'm {mx},{my} c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
16119 '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
16120 '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
16121 },
16122 'TASK_TYPE_BUSINESS_RULE_HEADER': {
16123 d: 'm {mx},{my} 0,4 20,0 0,-4 z'
16124 },
16125 'TASK_TYPE_BUSINESS_RULE_MAIN': {
16126 d: 'm {mx},{my} 0,12 20,0 0,-12 z' +
16127 'm 0,8 l 20,0 ' +
16128 'm -13,-4 l 0,8'
16129 },
16130 'MESSAGE_FLOW_MARKER': {
16131 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'
16132 }
16133 };
16134
16135 this.getRawPath = function getRawPath(pathId) {
16136 return this.pathMap[pathId].d;
16137 };
16138
16139 /**
16140 * Scales the path to the given height and width.
16141 * <h1>Use case</h1>
16142 * <p>Use case is to scale the content of elements (event, gateways) based
16143 * on the element bounding box's size.
16144 * </p>
16145 * <h1>Why not transform</h1>
16146 * <p>Scaling a path with transform() will also scale the stroke and IE does not support
16147 * the option 'non-scaling-stroke' to prevent this.
16148 * Also there are use cases where only some parts of a path should be
16149 * scaled.</p>
16150 *
16151 * @param {String} pathId The ID of the path.
16152 * @param {Object} param <p>
16153 * Example param object scales the path to 60% size of the container (data.width, data.height).
16154 * <pre>
16155 * {
16156 * xScaleFactor: 0.6,
16157 * yScaleFactor:0.6,
16158 * containerWidth: data.width,
16159 * containerHeight: data.height,
16160 * position: {
16161 * mx: 0.46,
16162 * my: 0.2,
16163 * }
16164 * }
16165 * </pre>
16166 * <ul>
16167 * <li>targetpathwidth = xScaleFactor * containerWidth</li>
16168 * <li>targetpathheight = yScaleFactor * containerHeight</li>
16169 * <li>Position is used to set the starting coordinate of the path. M is computed:
16170 * <ul>
16171 * <li>position.x * containerWidth</li>
16172 * <li>position.y * containerHeight</li>
16173 * </ul>
16174 * Center of the container <pre> position: {
16175 * mx: 0.5,
16176 * my: 0.5,
16177 * }</pre>
16178 * Upper left corner of the container
16179 * <pre> position: {
16180 * mx: 0.0,
16181 * my: 0.0,
16182 * }</pre>
16183 * </li>
16184 * </ul>
16185 * </p>
16186 *
16187 */
16188 this.getScaledPath = function getScaledPath(pathId, param) {
16189 var rawPath = this.pathMap[pathId];
16190
16191 // positioning
16192 // compute the start point of the path
16193 var mx, my;
16194
16195 if (param.abspos) {
16196 mx = param.abspos.x;
16197 my = param.abspos.y;
16198 } else {
16199 mx = param.containerWidth * param.position.mx;
16200 my = param.containerHeight * param.position.my;
16201 }
16202
16203 var coordinates = {}; // map for the scaled coordinates
16204 if (param.position) {
16205
16206 // path
16207 var heightRatio = (param.containerHeight / rawPath.height) * param.yScaleFactor;
16208 var widthRatio = (param.containerWidth / rawPath.width) * param.xScaleFactor;
16209
16210
16211 // Apply height ratio
16212 for (var heightIndex = 0; heightIndex < rawPath.heightElements.length; heightIndex++) {
16213 coordinates['y' + heightIndex] = rawPath.heightElements[heightIndex] * heightRatio;
16214 }
16215
16216 // Apply width ratio
16217 for (var widthIndex = 0; widthIndex < rawPath.widthElements.length; widthIndex++) {
16218 coordinates['x' + widthIndex] = rawPath.widthElements[widthIndex] * widthRatio;
16219 }
16220 }
16221
16222 // Apply value to raw path
16223 var path = format(
16224 rawPath.d, {
16225 mx: mx,
16226 my: my,
16227 e: coordinates
16228 }
16229 );
16230 return path;
16231 };
16232 }
16233
16234 // helpers //////////////////////
16235
16236 // copied from https://github.com/adobe-webplatform/Snap.svg/blob/master/src/svg.js
16237 var tokenRegex = /\{([^}]+)\}/g,
16238 objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g; // matches .xxxxx or ["xxxxx"] to run over object properties
16239
16240 function replacer(all, key, obj) {
16241 var res = obj;
16242 key.replace(objNotationRegex, function(all, name, quote, quotedName, isFunc) {
16243 name = name || quotedName;
16244 if (res) {
16245 if (name in res) {
16246 res = res[name];
16247 }
16248 typeof res == 'function' && isFunc && (res = res());
16249 }
16250 });
16251 res = (res == null || res == obj ? all : res) + '';
16252
16253 return res;
16254 }
16255
16256 function format(str, obj) {
16257 return String(str).replace(tokenRegex, function(all, key) {
16258 return replacer(all, key, obj);
16259 });
16260 }
16261
16262 var DrawModule$1 = {
16263 __init__: [ 'bpmnRenderer' ],
16264 bpmnRenderer: [ 'type', BpmnRenderer ],
16265 textRenderer: [ 'type', TextRenderer ],
16266 pathMap: [ 'type', PathMap ]
16267 };
16268
16269 /**
16270 * A simple translation stub to be used for multi-language support
16271 * in diagrams. Can be easily replaced with a more sophisticated
16272 * solution.
16273 *
16274 * @example
16275 *
16276 * // use it inside any diagram component by injecting `translate`.
16277 *
16278 * function MyService(translate) {
16279 * alert(translate('HELLO {you}', { you: 'You!' }));
16280 * }
16281 *
16282 * @param {String} template to interpolate
16283 * @param {Object} [replacements] a map with substitutes
16284 *
16285 * @return {String} the translated string
16286 */
16287 function translate$1(template, replacements) {
16288
16289 replacements = replacements || {};
16290
16291 return template.replace(/{([^}]+)}/g, function(_, key) {
16292 return replacements[key] || '{' + key + '}';
16293 });
16294 }
16295
16296 var TranslateModule = {
16297 translate: [ 'value', translate$1 ]
16298 };
16299
16300 var DEFAULT_LABEL_SIZE$1 = {
16301 width: 90,
16302 height: 20
16303 };
16304
16305 var FLOW_LABEL_INDENT = 15;
16306
16307
16308 /**
16309 * Returns true if the given semantic has an external label
16310 *
16311 * @param {BpmnElement} semantic
16312 * @return {Boolean} true if has label
16313 */
16314 function isLabelExternal(semantic) {
16315 return is$1(semantic, 'bpmn:Event') ||
16316 is$1(semantic, 'bpmn:Gateway') ||
16317 is$1(semantic, 'bpmn:DataStoreReference') ||
16318 is$1(semantic, 'bpmn:DataObjectReference') ||
16319 is$1(semantic, 'bpmn:DataInput') ||
16320 is$1(semantic, 'bpmn:DataOutput') ||
16321 is$1(semantic, 'bpmn:SequenceFlow') ||
16322 is$1(semantic, 'bpmn:MessageFlow') ||
16323 is$1(semantic, 'bpmn:Group');
16324 }
16325
16326 /**
16327 * Get the position for sequence flow labels
16328 *
16329 * @param {Array<Point>} waypoints
16330 * @return {Point} the label position
16331 */
16332 function getFlowLabelPosition(waypoints) {
16333
16334 // get the waypoints mid
16335 var mid = waypoints.length / 2 - 1;
16336
16337 var first = waypoints[Math.floor(mid)];
16338 var second = waypoints[Math.ceil(mid + 0.01)];
16339
16340 // get position
16341 var position = getWaypointsMid(waypoints);
16342
16343 // calculate angle
16344 var angle = Math.atan((second.y - first.y) / (second.x - first.x));
16345
16346 var x = position.x,
16347 y = position.y;
16348
16349 if (Math.abs(angle) < Math.PI / 2) {
16350 y -= FLOW_LABEL_INDENT;
16351 } else {
16352 x += FLOW_LABEL_INDENT;
16353 }
16354
16355 return { x: x, y: y };
16356 }
16357
16358
16359 /**
16360 * Get the middle of a number of waypoints
16361 *
16362 * @param {Array<Point>} waypoints
16363 * @return {Point} the mid point
16364 */
16365 function getWaypointsMid(waypoints) {
16366
16367 var mid = waypoints.length / 2 - 1;
16368
16369 var first = waypoints[Math.floor(mid)];
16370 var second = waypoints[Math.ceil(mid + 0.01)];
16371
16372 return {
16373 x: first.x + (second.x - first.x) / 2,
16374 y: first.y + (second.y - first.y) / 2
16375 };
16376 }
16377
16378
16379 function getExternalLabelMid(element) {
16380
16381 if (element.waypoints) {
16382 return getFlowLabelPosition(element.waypoints);
16383 } else if (is$1(element, 'bpmn:Group')) {
16384 return {
16385 x: element.x + element.width / 2,
16386 y: element.y + DEFAULT_LABEL_SIZE$1.height / 2
16387 };
16388 } else {
16389 return {
16390 x: element.x + element.width / 2,
16391 y: element.y + element.height + DEFAULT_LABEL_SIZE$1.height / 2
16392 };
16393 }
16394 }
16395
16396
16397 /**
16398 * Returns the bounds of an elements label, parsed from the elements DI or
16399 * generated from its bounds.
16400 *
16401 * @param {BpmnElement} semantic
16402 * @param {djs.model.Base} element
16403 */
16404 function getExternalLabelBounds(semantic, element) {
16405
16406 var mid,
16407 size,
16408 bounds,
16409 di = semantic.di,
16410 label = di.label;
16411
16412 if (label && label.bounds) {
16413 bounds = label.bounds;
16414
16415 size = {
16416 width: Math.max(DEFAULT_LABEL_SIZE$1.width, bounds.width),
16417 height: bounds.height
16418 };
16419
16420 mid = {
16421 x: bounds.x + bounds.width / 2,
16422 y: bounds.y + bounds.height / 2
16423 };
16424 } else {
16425
16426 mid = getExternalLabelMid(element);
16427
16428 size = DEFAULT_LABEL_SIZE$1;
16429 }
16430
16431 return assign({
16432 x: mid.x - size.width / 2,
16433 y: mid.y - size.height / 2
16434 }, size);
16435 }
16436
16437 /**
16438 * This file contains portions that got extraced from Snap.svg (licensed Apache-2.0).
16439 *
16440 * @see https://github.com/adobe-webplatform/Snap.svg/blob/master/src/path.js
16441 */
16442
16443 /* eslint no-fallthrough: "off" */
16444
16445 var math = Math,
16446 PI = math.PI;
16447
16448 function roundPoint(point) {
16449
16450 return {
16451 x: Math.round(point.x),
16452 y: Math.round(point.y)
16453 };
16454 }
16455
16456
16457 /**
16458 * Get the mid of the given bounds or point.
16459 *
16460 * @param {Bounds|Point} bounds
16461 *
16462 * @return {Point}
16463 */
16464 function getMid(bounds) {
16465 return roundPoint({
16466 x: bounds.x + (bounds.width || 0) / 2,
16467 y: bounds.y + (bounds.height || 0) / 2
16468 });
16469 }
16470
16471 function elementData(semantic, attrs) {
16472 return assign({
16473 id: semantic.id,
16474 type: semantic.$type,
16475 businessObject: semantic
16476 }, attrs);
16477 }
16478
16479 function getWaypoints(bo, source, target) {
16480
16481 var waypoints = bo.di.waypoint;
16482
16483 if (!waypoints || waypoints.length < 2) {
16484 return [ getMid(source), getMid(target) ];
16485 }
16486
16487 return waypoints.map(function(p) {
16488 return { x: p.x, y: p.y };
16489 });
16490 }
16491
16492 function notYetDrawn(translate, semantic, refSemantic, property) {
16493 return new Error(translate('element {element} referenced by {referenced}#{property} not yet drawn', {
16494 element: elementToString(refSemantic),
16495 referenced: elementToString(semantic),
16496 property: property
16497 }));
16498 }
16499
16500
16501 /**
16502 * An importer that adds bpmn elements to the canvas
16503 *
16504 * @param {EventBus} eventBus
16505 * @param {Canvas} canvas
16506 * @param {ElementFactory} elementFactory
16507 * @param {ElementRegistry} elementRegistry
16508 * @param {Function} translate
16509 * @param {TextRenderer} textRenderer
16510 */
16511 function BpmnImporter(
16512 eventBus, canvas, elementFactory,
16513 elementRegistry, translate, textRenderer) {
16514
16515 this._eventBus = eventBus;
16516 this._canvas = canvas;
16517 this._elementFactory = elementFactory;
16518 this._elementRegistry = elementRegistry;
16519 this._translate = translate;
16520 this._textRenderer = textRenderer;
16521 }
16522
16523 BpmnImporter.$inject = [
16524 'eventBus',
16525 'canvas',
16526 'elementFactory',
16527 'elementRegistry',
16528 'translate',
16529 'textRenderer'
16530 ];
16531
16532
16533 /**
16534 * Add bpmn element (semantic) to the canvas onto the
16535 * specified parent shape.
16536 */
16537 BpmnImporter.prototype.add = function(semantic, parentElement) {
16538
16539 var di = semantic.di,
16540 element,
16541 translate = this._translate,
16542 hidden;
16543
16544 var parentIndex;
16545
16546 // ROOT ELEMENT
16547 // handle the special case that we deal with a
16548 // invisible root element (process or collaboration)
16549 if (is$1(di, 'bpmndi:BPMNPlane')) {
16550
16551 // add a virtual element (not being drawn)
16552 element = this._elementFactory.createRoot(elementData(semantic));
16553
16554 this._canvas.setRootElement(element);
16555 }
16556
16557 // SHAPE
16558 else if (is$1(di, 'bpmndi:BPMNShape')) {
16559
16560 var collapsed = !isExpanded(semantic);
16561 hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
16562
16563 var bounds = semantic.di.bounds;
16564
16565 element = this._elementFactory.createShape(elementData(semantic, {
16566 collapsed: collapsed,
16567 hidden: hidden,
16568 x: Math.round(bounds.x),
16569 y: Math.round(bounds.y),
16570 width: Math.round(bounds.width),
16571 height: Math.round(bounds.height)
16572 }));
16573
16574 if (is$1(semantic, 'bpmn:BoundaryEvent')) {
16575 this._attachBoundary(semantic, element);
16576 }
16577
16578 // insert lanes behind other flow nodes (cf. #727)
16579 if (is$1(semantic, 'bpmn:Lane')) {
16580 parentIndex = 0;
16581 }
16582
16583 if (is$1(semantic, 'bpmn:DataStoreReference')) {
16584
16585 // check whether data store is inside our outside of its semantic parent
16586 if (!isPointInsideBBox(parentElement, getMid(bounds))) {
16587 parentElement = this._canvas.getRootElement();
16588 }
16589 }
16590
16591 this._canvas.addShape(element, parentElement, parentIndex);
16592 }
16593
16594 // CONNECTION
16595 else if (is$1(di, 'bpmndi:BPMNEdge')) {
16596
16597 var source = this._getSource(semantic),
16598 target = this._getTarget(semantic);
16599
16600 hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
16601
16602 element = this._elementFactory.createConnection(elementData(semantic, {
16603 hidden: hidden,
16604 source: source,
16605 target: target,
16606 waypoints: getWaypoints(semantic, source, target)
16607 }));
16608
16609 if (is$1(semantic, 'bpmn:DataAssociation')) {
16610
16611 // render always on top; this ensures DataAssociations
16612 // are rendered correctly across different "hacks" people
16613 // love to model such as cross participant / sub process
16614 // associations
16615 parentElement = null;
16616 }
16617
16618 // insert sequence flows behind other flow nodes (cf. #727)
16619 if (is$1(semantic, 'bpmn:SequenceFlow')) {
16620 parentIndex = 0;
16621 }
16622
16623 this._canvas.addConnection(element, parentElement, parentIndex);
16624 } else {
16625 throw new Error(translate('unknown di {di} for element {semantic}', {
16626 di: elementToString(di),
16627 semantic: elementToString(semantic)
16628 }));
16629 }
16630
16631 // (optional) LABEL
16632 if (isLabelExternal(semantic) && getLabel(element)) {
16633 this.addLabel(semantic, element);
16634 }
16635
16636
16637 this._eventBus.fire('bpmnElement.added', { element: element });
16638
16639 return element;
16640 };
16641
16642
16643 /**
16644 * Attach the boundary element to the given host
16645 *
16646 * @param {ModdleElement} boundarySemantic
16647 * @param {djs.model.Base} boundaryElement
16648 */
16649 BpmnImporter.prototype._attachBoundary = function(boundarySemantic, boundaryElement) {
16650 var translate = this._translate;
16651 var hostSemantic = boundarySemantic.attachedToRef;
16652
16653 if (!hostSemantic) {
16654 throw new Error(translate('missing {semantic}#attachedToRef', {
16655 semantic: elementToString(boundarySemantic)
16656 }));
16657 }
16658
16659 var host = this._elementRegistry.get(hostSemantic.id),
16660 attachers = host && host.attachers;
16661
16662 if (!host) {
16663 throw notYetDrawn(translate, boundarySemantic, hostSemantic, 'attachedToRef');
16664 }
16665
16666 // wire element.host <> host.attachers
16667 boundaryElement.host = host;
16668
16669 if (!attachers) {
16670 host.attachers = attachers = [];
16671 }
16672
16673 if (attachers.indexOf(boundaryElement) === -1) {
16674 attachers.push(boundaryElement);
16675 }
16676 };
16677
16678
16679 /**
16680 * add label for an element
16681 */
16682 BpmnImporter.prototype.addLabel = function(semantic, element) {
16683 var bounds,
16684 text,
16685 label;
16686
16687 bounds = getExternalLabelBounds(semantic, element);
16688
16689 text = getLabel(element);
16690
16691 if (text) {
16692
16693 // get corrected bounds from actual layouted text
16694 bounds = this._textRenderer.getExternalLabelBounds(bounds, text);
16695 }
16696
16697 label = this._elementFactory.createLabel(elementData(semantic, {
16698 id: semantic.id + '_label',
16699 labelTarget: element,
16700 type: 'label',
16701 hidden: element.hidden || !getLabel(element),
16702 x: Math.round(bounds.x),
16703 y: Math.round(bounds.y),
16704 width: Math.round(bounds.width),
16705 height: Math.round(bounds.height)
16706 }));
16707
16708 return this._canvas.addShape(label, element.parent);
16709 };
16710
16711 /**
16712 * Return the drawn connection end based on the given side.
16713 *
16714 * @throws {Error} if the end is not yet drawn
16715 */
16716 BpmnImporter.prototype._getEnd = function(semantic, side) {
16717
16718 var element,
16719 refSemantic,
16720 type = semantic.$type,
16721 translate = this._translate;
16722
16723 refSemantic = semantic[side + 'Ref'];
16724
16725 // handle mysterious isMany DataAssociation#sourceRef
16726 if (side === 'source' && type === 'bpmn:DataInputAssociation') {
16727 refSemantic = refSemantic && refSemantic[0];
16728 }
16729
16730 // fix source / target for DataInputAssociation / DataOutputAssociation
16731 if (side === 'source' && type === 'bpmn:DataOutputAssociation' ||
16732 side === 'target' && type === 'bpmn:DataInputAssociation') {
16733
16734 refSemantic = semantic.$parent;
16735 }
16736
16737 element = refSemantic && this._getElement(refSemantic);
16738
16739 if (element) {
16740 return element;
16741 }
16742
16743 if (refSemantic) {
16744 throw notYetDrawn(translate, semantic, refSemantic, side + 'Ref');
16745 } else {
16746 throw new Error(translate('{semantic}#{side} Ref not specified', {
16747 semantic: elementToString(semantic),
16748 side: side
16749 }));
16750 }
16751 };
16752
16753 BpmnImporter.prototype._getSource = function(semantic) {
16754 return this._getEnd(semantic, 'source');
16755 };
16756
16757 BpmnImporter.prototype._getTarget = function(semantic) {
16758 return this._getEnd(semantic, 'target');
16759 };
16760
16761
16762 BpmnImporter.prototype._getElement = function(semantic) {
16763 return this._elementRegistry.get(semantic.id);
16764 };
16765
16766
16767 // helpers ////////////////////
16768
16769 function isPointInsideBBox(bbox, point) {
16770 var x = point.x,
16771 y = point.y;
16772
16773 return x >= bbox.x &&
16774 x <= bbox.x + bbox.width &&
16775 y >= bbox.y &&
16776 y <= bbox.y + bbox.height;
16777 }
16778
16779 var ImportModule = {
16780 __depends__: [
16781 TranslateModule
16782 ],
16783 bpmnImporter: [ 'type', BpmnImporter ]
16784 };
16785
16786 var CoreModule$1 = {
16787 __depends__: [
16788 DrawModule$1,
16789 ImportModule
16790 ]
16791 };
16792
16793 function getOriginal(event) {
16794 return event.originalEvent || event.srcEvent;
16795 }
16796
16797 function isMac() {
16798 return (/mac/i).test(navigator.platform);
16799 }
16800
16801 function isPrimaryButton(event) {
16802
16803 // button === 0 -> left áka primary mouse button
16804 return !(getOriginal(event) || event).button;
16805 }
16806
16807 function hasPrimaryModifier(event) {
16808 var originalEvent = getOriginal(event) || event;
16809
16810 if (!isPrimaryButton(event)) {
16811 return false;
16812 }
16813
16814 // Use alt as primary modifier key for mac OS
16815 if (isMac()) {
16816 return originalEvent.metaKey;
16817 } else {
16818 return originalEvent.ctrlKey;
16819 }
16820 }
16821
16822 function allowAll(e) { return true; }
16823
16824 var LOW_PRIORITY = 500;
16825
16826
16827 /**
16828 * A plugin that provides interaction events for diagram elements.
16829 *
16830 * It emits the following events:
16831 *
16832 * * element.click
16833 * * element.contextmenu
16834 * * element.dblclick
16835 * * element.hover
16836 * * element.mousedown
16837 * * element.mousemove
16838 * * element.mouseup
16839 * * element.out
16840 *
16841 * Each event is a tuple { element, gfx, originalEvent }.
16842 *
16843 * Canceling the event via Event#preventDefault()
16844 * prevents the original DOM operation.
16845 *
16846 * @param {EventBus} eventBus
16847 */
16848 function InteractionEvents(eventBus, elementRegistry, styles) {
16849
16850 var self = this;
16851
16852 /**
16853 * Fire an interaction event.
16854 *
16855 * @param {String} type local event name, e.g. element.click.
16856 * @param {DOMEvent} event native event
16857 * @param {djs.model.Base} [element] the diagram element to emit the event on;
16858 * defaults to the event target
16859 */
16860 function fire(type, event, element) {
16861
16862 if (isIgnored(type, event)) {
16863 return;
16864 }
16865
16866 var target, gfx, returnValue;
16867
16868 if (!element) {
16869 target = event.delegateTarget || event.target;
16870
16871 if (target) {
16872 gfx = target;
16873 element = elementRegistry.get(gfx);
16874 }
16875 } else {
16876 gfx = elementRegistry.getGraphics(element);
16877 }
16878
16879 if (!gfx || !element) {
16880 return;
16881 }
16882
16883 returnValue = eventBus.fire(type, {
16884 element: element,
16885 gfx: gfx,
16886 originalEvent: event
16887 });
16888
16889 if (returnValue === false) {
16890 event.stopPropagation();
16891 event.preventDefault();
16892 }
16893 }
16894
16895 // TODO(nikku): document this
16896 var handlers = {};
16897
16898 function mouseHandler(localEventName) {
16899 return handlers[localEventName];
16900 }
16901
16902 function isIgnored(localEventName, event) {
16903
16904 var filter = ignoredFilters[localEventName] || isPrimaryButton;
16905
16906 // only react on left mouse button interactions
16907 // except for interaction events that are enabled
16908 // for secundary mouse button
16909 return !filter(event);
16910 }
16911
16912 var bindings = {
16913 click: 'element.click',
16914 contextmenu: 'element.contextmenu',
16915 dblclick: 'element.dblclick',
16916 mousedown: 'element.mousedown',
16917 mousemove: 'element.mousemove',
16918 mouseover: 'element.hover',
16919 mouseout: 'element.out',
16920 mouseup: 'element.mouseup',
16921 };
16922
16923 var ignoredFilters = {
16924 'element.contextmenu': allowAll
16925 };
16926
16927
16928 // manual event trigger //////////
16929
16930 /**
16931 * Trigger an interaction event (based on a native dom event)
16932 * on the target shape or connection.
16933 *
16934 * @param {String} eventName the name of the triggered DOM event
16935 * @param {MouseEvent} event
16936 * @param {djs.model.Base} targetElement
16937 */
16938 function triggerMouseEvent(eventName, event, targetElement) {
16939
16940 // i.e. element.mousedown...
16941 var localEventName = bindings[eventName];
16942
16943 if (!localEventName) {
16944 throw new Error('unmapped DOM event name <' + eventName + '>');
16945 }
16946
16947 return fire(localEventName, event, targetElement);
16948 }
16949
16950
16951 var ELEMENT_SELECTOR = 'svg, .djs-element';
16952
16953 // event handling ///////
16954
16955 function registerEvent(node, event, localEvent, ignoredFilter) {
16956
16957 var handler = handlers[localEvent] = function(event) {
16958 fire(localEvent, event);
16959 };
16960
16961 if (ignoredFilter) {
16962 ignoredFilters[localEvent] = ignoredFilter;
16963 }
16964
16965 handler.$delegate = delegateEvents.bind(node, ELEMENT_SELECTOR, event, handler);
16966 }
16967
16968 function unregisterEvent(node, event, localEvent) {
16969
16970 var handler = mouseHandler(localEvent);
16971
16972 if (!handler) {
16973 return;
16974 }
16975
16976 delegateEvents.unbind(node, event, handler.$delegate);
16977 }
16978
16979 function registerEvents(svg) {
16980 forEach(bindings, function(val, key) {
16981 registerEvent(svg, key, val);
16982 });
16983 }
16984
16985 function unregisterEvents(svg) {
16986 forEach(bindings, function(val, key) {
16987 unregisterEvent(svg, key, val);
16988 });
16989 }
16990
16991 eventBus.on('canvas.destroy', function(event) {
16992 unregisterEvents(event.svg);
16993 });
16994
16995 eventBus.on('canvas.init', function(event) {
16996 registerEvents(event.svg);
16997 });
16998
16999
17000 // hit box updating ////////////////
17001
17002 eventBus.on([ 'shape.added', 'connection.added' ], function(event) {
17003 var element = event.element,
17004 gfx = event.gfx;
17005
17006 eventBus.fire('interactionEvents.createHit', { element: element, gfx: gfx });
17007 });
17008
17009 // Update djs-hit on change.
17010 // A low priortity is necessary, because djs-hit of labels has to be updated
17011 // after the label bounds have been updated in the renderer.
17012 eventBus.on([
17013 'shape.changed',
17014 'connection.changed'
17015 ], LOW_PRIORITY, function(event) {
17016
17017 var element = event.element,
17018 gfx = event.gfx;
17019
17020 eventBus.fire('interactionEvents.updateHit', { element: element, gfx: gfx });
17021 });
17022
17023 eventBus.on('interactionEvents.createHit', LOW_PRIORITY, function(event) {
17024 var element = event.element,
17025 gfx = event.gfx;
17026
17027 self.createDefaultHit(element, gfx);
17028 });
17029
17030 eventBus.on('interactionEvents.updateHit', function(event) {
17031 var element = event.element,
17032 gfx = event.gfx;
17033
17034 self.updateDefaultHit(element, gfx);
17035 });
17036
17037
17038 // hit styles ////////////
17039
17040 var STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-stroke');
17041
17042 var CLICK_STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-click-stroke');
17043
17044 var ALL_HIT_STYLE = createHitStyle('djs-hit djs-hit-all');
17045
17046 var HIT_TYPES = {
17047 'all': ALL_HIT_STYLE,
17048 'click-stroke': CLICK_STROKE_HIT_STYLE,
17049 'stroke': STROKE_HIT_STYLE
17050 };
17051
17052 function createHitStyle(classNames, attrs) {
17053
17054 attrs = assign({
17055 stroke: 'white',
17056 strokeWidth: 15
17057 }, attrs || {});
17058
17059 return styles.cls(classNames, [ 'no-fill', 'no-border' ], attrs);
17060 }
17061
17062
17063 // style helpers ///////////////
17064
17065 function applyStyle(hit, type) {
17066
17067 var attrs = HIT_TYPES[type];
17068
17069 if (!attrs) {
17070 throw new Error('invalid hit type <' + type + '>');
17071 }
17072
17073 attr$1(hit, attrs);
17074
17075 return hit;
17076 }
17077
17078 function appendHit(gfx, hit) {
17079 append(gfx, hit);
17080 }
17081
17082
17083 // API
17084
17085 /**
17086 * Remove hints on the given graphics.
17087 *
17088 * @param {SVGElement} gfx
17089 */
17090 this.removeHits = function(gfx) {
17091 var hits = all('.djs-hit', gfx);
17092
17093 forEach(hits, remove$1);
17094 };
17095
17096 /**
17097 * Create default hit for the given element.
17098 *
17099 * @param {djs.model.Base} element
17100 * @param {SVGElement} gfx
17101 *
17102 * @return {SVGElement} created hit
17103 */
17104 this.createDefaultHit = function(element, gfx) {
17105 var waypoints = element.waypoints,
17106 isFrame = element.isFrame,
17107 boxType;
17108
17109 if (waypoints) {
17110 return this.createWaypointsHit(gfx, waypoints);
17111 } else {
17112
17113 boxType = isFrame ? 'stroke' : 'all';
17114
17115 return this.createBoxHit(gfx, boxType, {
17116 width: element.width,
17117 height: element.height
17118 });
17119 }
17120 };
17121
17122 /**
17123 * Create hits for the given waypoints.
17124 *
17125 * @param {SVGElement} gfx
17126 * @param {Array<Point>} waypoints
17127 *
17128 * @return {SVGElement}
17129 */
17130 this.createWaypointsHit = function(gfx, waypoints) {
17131
17132 var hit = createLine(waypoints);
17133
17134 applyStyle(hit, 'stroke');
17135
17136 appendHit(gfx, hit);
17137
17138 return hit;
17139 };
17140
17141 /**
17142 * Create hits for a box.
17143 *
17144 * @param {SVGElement} gfx
17145 * @param {String} hitType
17146 * @param {Object} attrs
17147 *
17148 * @return {SVGElement}
17149 */
17150 this.createBoxHit = function(gfx, type, attrs) {
17151
17152 attrs = assign({
17153 x: 0,
17154 y: 0
17155 }, attrs);
17156
17157 var hit = create('rect');
17158
17159 applyStyle(hit, type);
17160
17161 attr$1(hit, attrs);
17162
17163 appendHit(gfx, hit);
17164
17165 return hit;
17166 };
17167
17168 /**
17169 * Update default hit of the element.
17170 *
17171 * @param {djs.model.Base} element
17172 * @param {SVGElement} gfx
17173 *
17174 * @return {SVGElement} updated hit
17175 */
17176 this.updateDefaultHit = function(element, gfx) {
17177
17178 var hit = query('.djs-hit', gfx);
17179
17180 if (!hit) {
17181 return;
17182 }
17183
17184 if (element.waypoints) {
17185 updateLine(hit, element.waypoints);
17186 } else {
17187 attr$1(hit, {
17188 width: element.width,
17189 height: element.height
17190 });
17191 }
17192
17193 return hit;
17194 };
17195
17196 this.fire = fire;
17197
17198 this.triggerMouseEvent = triggerMouseEvent;
17199
17200 this.mouseHandler = mouseHandler;
17201
17202 this.registerEvent = registerEvent;
17203 this.unregisterEvent = unregisterEvent;
17204 }
17205
17206
17207 InteractionEvents.$inject = [
17208 'eventBus',
17209 'elementRegistry',
17210 'styles'
17211 ];
17212
17213
17214 /**
17215 * An event indicating that the mouse hovered over an element
17216 *
17217 * @event element.hover
17218 *
17219 * @type {Object}
17220 * @property {djs.model.Base} element
17221 * @property {SVGElement} gfx
17222 * @property {Event} originalEvent
17223 */
17224
17225 /**
17226 * An event indicating that the mouse has left an element
17227 *
17228 * @event element.out
17229 *
17230 * @type {Object}
17231 * @property {djs.model.Base} element
17232 * @property {SVGElement} gfx
17233 * @property {Event} originalEvent
17234 */
17235
17236 /**
17237 * An event indicating that the mouse has clicked an element
17238 *
17239 * @event element.click
17240 *
17241 * @type {Object}
17242 * @property {djs.model.Base} element
17243 * @property {SVGElement} gfx
17244 * @property {Event} originalEvent
17245 */
17246
17247 /**
17248 * An event indicating that the mouse has double clicked an element
17249 *
17250 * @event element.dblclick
17251 *
17252 * @type {Object}
17253 * @property {djs.model.Base} element
17254 * @property {SVGElement} gfx
17255 * @property {Event} originalEvent
17256 */
17257
17258 /**
17259 * An event indicating that the mouse has gone down on an element.
17260 *
17261 * @event element.mousedown
17262 *
17263 * @type {Object}
17264 * @property {djs.model.Base} element
17265 * @property {SVGElement} gfx
17266 * @property {Event} originalEvent
17267 */
17268
17269 /**
17270 * An event indicating that the mouse has gone up on an element.
17271 *
17272 * @event element.mouseup
17273 *
17274 * @type {Object}
17275 * @property {djs.model.Base} element
17276 * @property {SVGElement} gfx
17277 * @property {Event} originalEvent
17278 */
17279
17280 /**
17281 * An event indicating that the context menu action is triggered
17282 * via mouse or touch controls.
17283 *
17284 * @event element.contextmenu
17285 *
17286 * @type {Object}
17287 * @property {djs.model.Base} element
17288 * @property {SVGElement} gfx
17289 * @property {Event} originalEvent
17290 */
17291
17292 var InteractionEventsModule = {
17293 __init__: [ 'interactionEvents' ],
17294 interactionEvents: [ 'type', InteractionEvents ]
17295 };
17296
17297 var LOW_PRIORITY$1 = 500;
17298
17299
17300 /**
17301 * @class
17302 *
17303 * A plugin that adds an outline to shapes and connections that may be activated and styled
17304 * via CSS classes.
17305 *
17306 * @param {EventBus} eventBus
17307 * @param {Styles} styles
17308 * @param {ElementRegistry} elementRegistry
17309 */
17310 function Outline(eventBus, styles, elementRegistry) {
17311
17312 this.offset = 6;
17313
17314 var OUTLINE_STYLE = styles.cls('djs-outline', [ 'no-fill' ]);
17315
17316 var self = this;
17317
17318 function createOutline(gfx, bounds) {
17319 var outline = create('rect');
17320
17321 attr$1(outline, assign({
17322 x: 10,
17323 y: 10,
17324 width: 100,
17325 height: 100
17326 }, OUTLINE_STYLE));
17327
17328 append(gfx, outline);
17329
17330 return outline;
17331 }
17332
17333 // A low priortity is necessary, because outlines of labels have to be updated
17334 // after the label bounds have been updated in the renderer.
17335 eventBus.on([ 'shape.added', 'shape.changed' ], LOW_PRIORITY$1, function(event) {
17336 var element = event.element,
17337 gfx = event.gfx;
17338
17339 var outline = query('.djs-outline', gfx);
17340
17341 if (!outline) {
17342 outline = createOutline(gfx);
17343 }
17344
17345 self.updateShapeOutline(outline, element);
17346 });
17347
17348 eventBus.on([ 'connection.added', 'connection.changed' ], function(event) {
17349 var element = event.element,
17350 gfx = event.gfx;
17351
17352 var outline = query('.djs-outline', gfx);
17353
17354 if (!outline) {
17355 outline = createOutline(gfx);
17356 }
17357
17358 self.updateConnectionOutline(outline, element);
17359 });
17360 }
17361
17362
17363 /**
17364 * Updates the outline of a shape respecting the dimension of the
17365 * element and an outline offset.
17366 *
17367 * @param {SVGElement} outline
17368 * @param {djs.model.Base} element
17369 */
17370 Outline.prototype.updateShapeOutline = function(outline, element) {
17371
17372 attr$1(outline, {
17373 x: -this.offset,
17374 y: -this.offset,
17375 width: element.width + this.offset * 2,
17376 height: element.height + this.offset * 2
17377 });
17378
17379 };
17380
17381
17382 /**
17383 * Updates the outline of a connection respecting the bounding box of
17384 * the connection and an outline offset.
17385 *
17386 * @param {SVGElement} outline
17387 * @param {djs.model.Base} element
17388 */
17389 Outline.prototype.updateConnectionOutline = function(outline, connection) {
17390
17391 var bbox = getBBox(connection);
17392
17393 attr$1(outline, {
17394 x: bbox.x - this.offset,
17395 y: bbox.y - this.offset,
17396 width: bbox.width + this.offset * 2,
17397 height: bbox.height + this.offset * 2
17398 });
17399
17400 };
17401
17402
17403 Outline.$inject = ['eventBus', 'styles', 'elementRegistry'];
17404
17405 var OutlineModule = {
17406 __init__: [ 'outline' ],
17407 outline: [ 'type', Outline ]
17408 };
17409
17410 /**
17411 * A service that offers the current selection in a diagram.
17412 * Offers the api to control the selection, too.
17413 *
17414 * @class
17415 *
17416 * @param {EventBus} eventBus the event bus
17417 */
17418 function Selection(eventBus) {
17419
17420 this._eventBus = eventBus;
17421
17422 this._selectedElements = [];
17423
17424 var self = this;
17425
17426 eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
17427 var element = e.element;
17428 self.deselect(element);
17429 });
17430
17431 eventBus.on([ 'diagram.clear' ], function(e) {
17432 self.select(null);
17433 });
17434 }
17435
17436 Selection.$inject = [ 'eventBus' ];
17437
17438
17439 Selection.prototype.deselect = function(element) {
17440 var selectedElements = this._selectedElements;
17441
17442 var idx = selectedElements.indexOf(element);
17443
17444 if (idx !== -1) {
17445 var oldSelection = selectedElements.slice();
17446
17447 selectedElements.splice(idx, 1);
17448
17449 this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
17450 }
17451 };
17452
17453
17454 Selection.prototype.get = function() {
17455 return this._selectedElements;
17456 };
17457
17458 Selection.prototype.isSelected = function(element) {
17459 return this._selectedElements.indexOf(element) !== -1;
17460 };
17461
17462
17463 /**
17464 * This method selects one or more elements on the diagram.
17465 *
17466 * By passing an additional add parameter you can decide whether or not the element(s)
17467 * should be added to the already existing selection or not.
17468 *
17469 * @method Selection#select
17470 *
17471 * @param {Object|Object[]} elements element or array of elements to be selected
17472 * @param {boolean} [add] whether the element(s) should be appended to the current selection, defaults to false
17473 */
17474 Selection.prototype.select = function(elements, add) {
17475 var selectedElements = this._selectedElements,
17476 oldSelection = selectedElements.slice();
17477
17478 if (!isArray(elements)) {
17479 elements = elements ? [ elements ] : [];
17480 }
17481
17482 // selection may be cleared by passing an empty array or null
17483 // to the method
17484 if (add) {
17485 forEach(elements, function(element) {
17486 if (selectedElements.indexOf(element) !== -1) {
17487
17488 // already selected
17489 return;
17490 } else {
17491 selectedElements.push(element);
17492 }
17493 });
17494 } else {
17495 this._selectedElements = selectedElements = elements.slice();
17496 }
17497
17498 this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
17499 };
17500
17501 var MARKER_HOVER = 'hover',
17502 MARKER_SELECTED = 'selected';
17503
17504
17505 /**
17506 * A plugin that adds a visible selection UI to shapes and connections
17507 * by appending the <code>hover</code> and <code>selected</code> classes to them.
17508 *
17509 * @class
17510 *
17511 * Makes elements selectable, too.
17512 *
17513 * @param {EventBus} events
17514 * @param {SelectionService} selection
17515 * @param {Canvas} canvas
17516 */
17517 function SelectionVisuals(events, canvas, selection, styles) {
17518
17519 this._multiSelectionBox = null;
17520
17521 function addMarker(e, cls) {
17522 canvas.addMarker(e, cls);
17523 }
17524
17525 function removeMarker(e, cls) {
17526 canvas.removeMarker(e, cls);
17527 }
17528
17529 events.on('element.hover', function(event) {
17530 addMarker(event.element, MARKER_HOVER);
17531 });
17532
17533 events.on('element.out', function(event) {
17534 removeMarker(event.element, MARKER_HOVER);
17535 });
17536
17537 events.on('selection.changed', function(event) {
17538
17539 function deselect(s) {
17540 removeMarker(s, MARKER_SELECTED);
17541 }
17542
17543 function select(s) {
17544 addMarker(s, MARKER_SELECTED);
17545 }
17546
17547 var oldSelection = event.oldSelection,
17548 newSelection = event.newSelection;
17549
17550 forEach(oldSelection, function(e) {
17551 if (newSelection.indexOf(e) === -1) {
17552 deselect(e);
17553 }
17554 });
17555
17556 forEach(newSelection, function(e) {
17557 if (oldSelection.indexOf(e) === -1) {
17558 select(e);
17559 }
17560 });
17561 });
17562 }
17563
17564 SelectionVisuals.$inject = [
17565 'eventBus',
17566 'canvas',
17567 'selection',
17568 'styles'
17569 ];
17570
17571 function SelectionBehavior(
17572 eventBus, selection, canvas,
17573 elementRegistry) {
17574
17575 eventBus.on('create.end', 500, function(e) {
17576
17577 var context = e.context,
17578 canExecute = context.canExecute,
17579 elements = context.elements,
17580 hints = context.hints || {},
17581 autoSelect = hints.autoSelect;
17582
17583 // select elements after they have been created
17584 if (canExecute) {
17585 if (autoSelect === false) {
17586
17587 // select no elements
17588 return;
17589 }
17590
17591 if (isArray(autoSelect)) {
17592 selection.select(autoSelect);
17593 } else {
17594
17595 // select all elements by default
17596 selection.select(elements);
17597 }
17598 }
17599 });
17600
17601 eventBus.on('connect.end', 500, function(e) {
17602
17603 // select the connect end target
17604 // after a connect operation
17605 if (e.context.canExecute && e.context.target) {
17606 selection.select(e.context.target);
17607 }
17608 });
17609
17610 eventBus.on('shape.move.end', 500, function(e) {
17611 var previousSelection = e.previousSelection || [];
17612
17613 var shape = elementRegistry.get(e.context.shape.id);
17614
17615 // make sure at least the main moved element is being
17616 // selected after a move operation
17617 var inSelection = find(previousSelection, function(selectedShape) {
17618 return shape.id === selectedShape.id;
17619 });
17620
17621 if (!inSelection) {
17622 selection.select(shape);
17623 }
17624 });
17625
17626 // Shift + click selection
17627 eventBus.on('element.click', function(event) {
17628
17629 var element = event.element;
17630
17631 // do not select the root element
17632 // or connections
17633 if (element === canvas.getRootElement()) {
17634 element = null;
17635 }
17636
17637 var isSelected = selection.isSelected(element),
17638 isMultiSelect = selection.get().length > 1;
17639
17640 // mouse-event: SELECTION_KEY
17641 var add = hasPrimaryModifier(event);
17642
17643 // select OR deselect element in multi selection
17644 if (isSelected && isMultiSelect) {
17645 if (add) {
17646 return selection.deselect(element);
17647 } else {
17648 return selection.select(element);
17649 }
17650 } else
17651 if (!isSelected) {
17652 selection.select(element, add);
17653 } else {
17654 selection.deselect(element);
17655 }
17656 });
17657 }
17658
17659 SelectionBehavior.$inject = [
17660 'eventBus',
17661 'selection',
17662 'canvas',
17663 'elementRegistry'
17664 ];
17665
17666 var SelectionModule = {
17667 __init__: [ 'selectionVisuals', 'selectionBehavior' ],
17668 __depends__: [
17669 InteractionEventsModule,
17670 OutlineModule
17671 ],
17672 selection: [ 'type', Selection ],
17673 selectionVisuals: [ 'type', SelectionVisuals ],
17674 selectionBehavior: [ 'type', SelectionBehavior ]
17675 };
17676
17677 /**
17678 * Util that provides unique IDs.
17679 *
17680 * @class djs.util.IdGenerator
17681 * @constructor
17682 * @memberOf djs.util
17683 *
17684 * The ids can be customized via a given prefix and contain a random value to avoid collisions.
17685 *
17686 * @param {String} prefix a prefix to prepend to generated ids (for better readability)
17687 */
17688 function IdGenerator(prefix) {
17689
17690 this._counter = 0;
17691 this._prefix = (prefix ? prefix + '-' : '') + Math.floor(Math.random() * 1000000000) + '-';
17692 }
17693
17694 /**
17695 * Returns a next unique ID.
17696 *
17697 * @method djs.util.IdGenerator#next
17698 *
17699 * @returns {String} the id
17700 */
17701 IdGenerator.prototype.next = function() {
17702 return this._prefix + (++this._counter);
17703 };
17704
17705 // document wide unique overlay ids
17706 var ids = new IdGenerator('ov');
17707
17708 var LOW_PRIORITY$2 = 500;
17709
17710
17711 /**
17712 * A service that allows users to attach overlays to diagram elements.
17713 *
17714 * The overlay service will take care of overlay positioning during updates.
17715 *
17716 * @example
17717 *
17718 * // add a pink badge on the top left of the shape
17719 * overlays.add(someShape, {
17720 * position: {
17721 * top: -5,
17722 * left: -5
17723 * },
17724 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
17725 * });
17726 *
17727 * // or add via shape id
17728 *
17729 * overlays.add('some-element-id', {
17730 * position: {
17731 * top: -5,
17732 * left: -5
17733 * }
17734 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
17735 * });
17736 *
17737 * // or add with optional type
17738 *
17739 * overlays.add(someShape, 'badge', {
17740 * position: {
17741 * top: -5,
17742 * left: -5
17743 * }
17744 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
17745 * });
17746 *
17747 *
17748 * // remove an overlay
17749 *
17750 * var id = overlays.add(...);
17751 * overlays.remove(id);
17752 *
17753 *
17754 * You may configure overlay defaults during tool by providing a `config` module
17755 * with `overlays.defaults` as an entry:
17756 *
17757 * {
17758 * overlays: {
17759 * defaults: {
17760 * show: {
17761 * minZoom: 0.7,
17762 * maxZoom: 5.0
17763 * },
17764 * scale: {
17765 * min: 1
17766 * }
17767 * }
17768 * }
17769 *
17770 * @param {Object} config
17771 * @param {EventBus} eventBus
17772 * @param {Canvas} canvas
17773 * @param {ElementRegistry} elementRegistry
17774 */
17775 function Overlays(config, eventBus, canvas, elementRegistry) {
17776
17777 this._eventBus = eventBus;
17778 this._canvas = canvas;
17779 this._elementRegistry = elementRegistry;
17780
17781 this._ids = ids;
17782
17783 this._overlayDefaults = assign({
17784
17785 // no show constraints
17786 show: null,
17787
17788 // always scale
17789 scale: true
17790 }, config && config.defaults);
17791
17792 /**
17793 * Mapping overlayId -> overlay
17794 */
17795 this._overlays = {};
17796
17797 /**
17798 * Mapping elementId -> overlay container
17799 */
17800 this._overlayContainers = [];
17801
17802 // root html element for all overlays
17803 this._overlayRoot = createRoot(canvas.getContainer());
17804
17805 this._init();
17806 }
17807
17808
17809 Overlays.$inject = [
17810 'config.overlays',
17811 'eventBus',
17812 'canvas',
17813 'elementRegistry'
17814 ];
17815
17816
17817 /**
17818 * Returns the overlay with the specified id or a list of overlays
17819 * for an element with a given type.
17820 *
17821 * @example
17822 *
17823 * // return the single overlay with the given id
17824 * overlays.get('some-id');
17825 *
17826 * // return all overlays for the shape
17827 * overlays.get({ element: someShape });
17828 *
17829 * // return all overlays on shape with type 'badge'
17830 * overlays.get({ element: someShape, type: 'badge' });
17831 *
17832 * // shape can also be specified as id
17833 * overlays.get({ element: 'element-id', type: 'badge' });
17834 *
17835 *
17836 * @param {Object} search
17837 * @param {String} [search.id]
17838 * @param {String|djs.model.Base} [search.element]
17839 * @param {String} [search.type]
17840 *
17841 * @return {Object|Array<Object>} the overlay(s)
17842 */
17843 Overlays.prototype.get = function(search) {
17844
17845 if (isString(search)) {
17846 search = { id: search };
17847 }
17848
17849 if (isString(search.element)) {
17850 search.element = this._elementRegistry.get(search.element);
17851 }
17852
17853 if (search.element) {
17854 var container = this._getOverlayContainer(search.element, true);
17855
17856 // return a list of overlays when searching by element (+type)
17857 if (container) {
17858 return search.type ? filter(container.overlays, matchPattern({ type: search.type })) : container.overlays.slice();
17859 } else {
17860 return [];
17861 }
17862 } else
17863 if (search.type) {
17864 return filter(this._overlays, matchPattern({ type: search.type }));
17865 } else {
17866
17867 // return single element when searching by id
17868 return search.id ? this._overlays[search.id] : null;
17869 }
17870 };
17871
17872 /**
17873 * Adds a HTML overlay to an element.
17874 *
17875 * @param {String|djs.model.Base} element attach overlay to this shape
17876 * @param {String} [type] optional type to assign to the overlay
17877 * @param {Object} overlay the overlay configuration
17878 *
17879 * @param {String|DOMElement} overlay.html html element to use as an overlay
17880 * @param {Object} [overlay.show] show configuration
17881 * @param {Number} [overlay.show.minZoom] minimal zoom level to show the overlay
17882 * @param {Number} [overlay.show.maxZoom] maximum zoom level to show the overlay
17883 * @param {Object} overlay.position where to attach the overlay
17884 * @param {Number} [overlay.position.left] relative to element bbox left attachment
17885 * @param {Number} [overlay.position.top] relative to element bbox top attachment
17886 * @param {Number} [overlay.position.bottom] relative to element bbox bottom attachment
17887 * @param {Number} [overlay.position.right] relative to element bbox right attachment
17888 * @param {Boolean|Object} [overlay.scale=true] false to preserve the same size regardless of
17889 * diagram zoom
17890 * @param {Number} [overlay.scale.min]
17891 * @param {Number} [overlay.scale.max]
17892 *
17893 * @return {String} id that may be used to reference the overlay for update or removal
17894 */
17895 Overlays.prototype.add = function(element, type, overlay) {
17896
17897 if (isObject(type)) {
17898 overlay = type;
17899 type = null;
17900 }
17901
17902 if (!element.id) {
17903 element = this._elementRegistry.get(element);
17904 }
17905
17906 if (!overlay.position) {
17907 throw new Error('must specifiy overlay position');
17908 }
17909
17910 if (!overlay.html) {
17911 throw new Error('must specifiy overlay html');
17912 }
17913
17914 if (!element) {
17915 throw new Error('invalid element specified');
17916 }
17917
17918 var id = this._ids.next();
17919
17920 overlay = assign({}, this._overlayDefaults, overlay, {
17921 id: id,
17922 type: type,
17923 element: element,
17924 html: overlay.html
17925 });
17926
17927 this._addOverlay(overlay);
17928
17929 return id;
17930 };
17931
17932
17933 /**
17934 * Remove an overlay with the given id or all overlays matching the given filter.
17935 *
17936 * @see Overlays#get for filter options.
17937 *
17938 * @param {String} [id]
17939 * @param {Object} [filter]
17940 */
17941 Overlays.prototype.remove = function(filter) {
17942
17943 var overlays = this.get(filter) || [];
17944
17945 if (!isArray(overlays)) {
17946 overlays = [ overlays ];
17947 }
17948
17949 var self = this;
17950
17951 forEach(overlays, function(overlay) {
17952
17953 var container = self._getOverlayContainer(overlay.element, true);
17954
17955 if (overlay) {
17956 remove(overlay.html);
17957 remove(overlay.htmlContainer);
17958
17959 delete overlay.htmlContainer;
17960 delete overlay.element;
17961
17962 delete self._overlays[overlay.id];
17963 }
17964
17965 if (container) {
17966 var idx = container.overlays.indexOf(overlay);
17967 if (idx !== -1) {
17968 container.overlays.splice(idx, 1);
17969 }
17970 }
17971 });
17972
17973 };
17974
17975
17976 Overlays.prototype.show = function() {
17977 setVisible(this._overlayRoot);
17978 };
17979
17980
17981 Overlays.prototype.hide = function() {
17982 setVisible(this._overlayRoot, false);
17983 };
17984
17985 Overlays.prototype.clear = function() {
17986 this._overlays = {};
17987
17988 this._overlayContainers = [];
17989
17990 clear(this._overlayRoot);
17991 };
17992
17993 Overlays.prototype._updateOverlayContainer = function(container) {
17994 var element = container.element,
17995 html = container.html;
17996
17997 // update container left,top according to the elements x,y coordinates
17998 // this ensures we can attach child elements relative to this container
17999
18000 var x = element.x,
18001 y = element.y;
18002
18003 if (element.waypoints) {
18004 var bbox = getBBox(element);
18005 x = bbox.x;
18006 y = bbox.y;
18007 }
18008
18009 setPosition(html, x, y);
18010
18011 attr(container.html, 'data-container-id', element.id);
18012 };
18013
18014
18015 Overlays.prototype._updateOverlay = function(overlay) {
18016
18017 var position = overlay.position,
18018 htmlContainer = overlay.htmlContainer,
18019 element = overlay.element;
18020
18021 // update overlay html relative to shape because
18022 // it is already positioned on the element
18023
18024 // update relative
18025 var left = position.left,
18026 top = position.top;
18027
18028 if (position.right !== undefined) {
18029
18030 var width;
18031
18032 if (element.waypoints) {
18033 width = getBBox(element).width;
18034 } else {
18035 width = element.width;
18036 }
18037
18038 left = position.right * -1 + width;
18039 }
18040
18041 if (position.bottom !== undefined) {
18042
18043 var height;
18044
18045 if (element.waypoints) {
18046 height = getBBox(element).height;
18047 } else {
18048 height = element.height;
18049 }
18050
18051 top = position.bottom * -1 + height;
18052 }
18053
18054 setPosition(htmlContainer, left || 0, top || 0);
18055 };
18056
18057
18058 Overlays.prototype._createOverlayContainer = function(element) {
18059 var html = domify('<div class="djs-overlays" style="position: absolute" />');
18060
18061 this._overlayRoot.appendChild(html);
18062
18063 var container = {
18064 html: html,
18065 element: element,
18066 overlays: []
18067 };
18068
18069 this._updateOverlayContainer(container);
18070
18071 this._overlayContainers.push(container);
18072
18073 return container;
18074 };
18075
18076
18077 Overlays.prototype._updateRoot = function(viewbox) {
18078 var scale = viewbox.scale || 1;
18079
18080 var matrix = 'matrix(' +
18081 [
18082 scale,
18083 0,
18084 0,
18085 scale,
18086 -1 * viewbox.x * scale,
18087 -1 * viewbox.y * scale
18088 ].join(',') +
18089 ')';
18090
18091 setTransform(this._overlayRoot, matrix);
18092 };
18093
18094
18095 Overlays.prototype._getOverlayContainer = function(element, raw) {
18096 var container = find(this._overlayContainers, function(c) {
18097 return c.element === element;
18098 });
18099
18100
18101 if (!container && !raw) {
18102 return this._createOverlayContainer(element);
18103 }
18104
18105 return container;
18106 };
18107
18108
18109 Overlays.prototype._addOverlay = function(overlay) {
18110
18111 var id = overlay.id,
18112 element = overlay.element,
18113 html = overlay.html,
18114 htmlContainer,
18115 overlayContainer;
18116
18117 // unwrap jquery (for those who need it)
18118 if (html.get && html.constructor.prototype.jquery) {
18119 html = html.get(0);
18120 }
18121
18122 // create proper html elements from
18123 // overlay HTML strings
18124 if (isString(html)) {
18125 html = domify(html);
18126 }
18127
18128 overlayContainer = this._getOverlayContainer(element);
18129
18130 htmlContainer = domify('<div class="djs-overlay" data-overlay-id="' + id + '" style="position: absolute">');
18131
18132 htmlContainer.appendChild(html);
18133
18134 if (overlay.type) {
18135 classes(htmlContainer).add('djs-overlay-' + overlay.type);
18136 }
18137
18138 overlay.htmlContainer = htmlContainer;
18139
18140 overlayContainer.overlays.push(overlay);
18141 overlayContainer.html.appendChild(htmlContainer);
18142
18143 this._overlays[id] = overlay;
18144
18145 this._updateOverlay(overlay);
18146 this._updateOverlayVisibilty(overlay, this._canvas.viewbox());
18147 };
18148
18149
18150 Overlays.prototype._updateOverlayVisibilty = function(overlay, viewbox) {
18151 var show = overlay.show,
18152 minZoom = show && show.minZoom,
18153 maxZoom = show && show.maxZoom,
18154 htmlContainer = overlay.htmlContainer,
18155 visible = true;
18156
18157 if (show) {
18158 if (
18159 (isDefined(minZoom) && minZoom > viewbox.scale) ||
18160 (isDefined(maxZoom) && maxZoom < viewbox.scale)
18161 ) {
18162 visible = false;
18163 }
18164
18165 setVisible(htmlContainer, visible);
18166 }
18167
18168 this._updateOverlayScale(overlay, viewbox);
18169 };
18170
18171
18172 Overlays.prototype._updateOverlayScale = function(overlay, viewbox) {
18173 var shouldScale = overlay.scale,
18174 minScale,
18175 maxScale,
18176 htmlContainer = overlay.htmlContainer;
18177
18178 var scale, transform = '';
18179
18180 if (shouldScale !== true) {
18181
18182 if (shouldScale === false) {
18183 minScale = 1;
18184 maxScale = 1;
18185 } else {
18186 minScale = shouldScale.min;
18187 maxScale = shouldScale.max;
18188 }
18189
18190 if (isDefined(minScale) && viewbox.scale < minScale) {
18191 scale = (1 / viewbox.scale || 1) * minScale;
18192 }
18193
18194 if (isDefined(maxScale) && viewbox.scale > maxScale) {
18195 scale = (1 / viewbox.scale || 1) * maxScale;
18196 }
18197 }
18198
18199 if (isDefined(scale)) {
18200 transform = 'scale(' + scale + ',' + scale + ')';
18201 }
18202
18203 setTransform(htmlContainer, transform);
18204 };
18205
18206
18207 Overlays.prototype._updateOverlaysVisibilty = function(viewbox) {
18208
18209 var self = this;
18210
18211 forEach(this._overlays, function(overlay) {
18212 self._updateOverlayVisibilty(overlay, viewbox);
18213 });
18214 };
18215
18216
18217 Overlays.prototype._init = function() {
18218
18219 var eventBus = this._eventBus;
18220
18221 var self = this;
18222
18223
18224 // scroll/zoom integration
18225
18226 function updateViewbox(viewbox) {
18227 self._updateRoot(viewbox);
18228 self._updateOverlaysVisibilty(viewbox);
18229
18230 self.show();
18231 }
18232
18233 eventBus.on('canvas.viewbox.changing', function(event) {
18234 self.hide();
18235 });
18236
18237 eventBus.on('canvas.viewbox.changed', function(event) {
18238 updateViewbox(event.viewbox);
18239 });
18240
18241
18242 // remove integration
18243
18244 eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
18245 var element = e.element;
18246 var overlays = self.get({ element: element });
18247
18248 forEach(overlays, function(o) {
18249 self.remove(o.id);
18250 });
18251
18252 var container = self._getOverlayContainer(element);
18253
18254 if (container) {
18255 remove(container.html);
18256 var i = self._overlayContainers.indexOf(container);
18257 if (i !== -1) {
18258 self._overlayContainers.splice(i, 1);
18259 }
18260 }
18261 });
18262
18263
18264 // move integration
18265
18266 eventBus.on('element.changed', LOW_PRIORITY$2, function(e) {
18267 var element = e.element;
18268
18269 var container = self._getOverlayContainer(element, true);
18270
18271 if (container) {
18272 forEach(container.overlays, function(overlay) {
18273 self._updateOverlay(overlay);
18274 });
18275
18276 self._updateOverlayContainer(container);
18277 }
18278 });
18279
18280
18281 // marker integration, simply add them on the overlays as classes, too.
18282
18283 eventBus.on('element.marker.update', function(e) {
18284 var container = self._getOverlayContainer(e.element, true);
18285 if (container) {
18286 classes(container.html)[e.add ? 'add' : 'remove'](e.marker);
18287 }
18288 });
18289
18290
18291 // clear overlays with diagram
18292
18293 eventBus.on('diagram.clear', this.clear, this);
18294 };
18295
18296
18297
18298 // helpers /////////////////////////////
18299
18300 function createRoot(parentNode) {
18301 var root = domify(
18302 '<div class="djs-overlay-container" style="position: absolute; width: 0; height: 0;" />'
18303 );
18304
18305 parentNode.insertBefore(root, parentNode.firstChild);
18306
18307 return root;
18308 }
18309
18310 function setPosition(el, x, y) {
18311 assign(el.style, { left: x + 'px', top: y + 'px' });
18312 }
18313
18314 function setVisible(el, visible) {
18315 el.style.display = visible === false ? 'none' : '';
18316 }
18317
18318 function setTransform(el, transform) {
18319
18320 el.style['transform-origin'] = 'top left';
18321
18322 [ '', '-ms-', '-webkit-' ].forEach(function(prefix) {
18323 el.style[prefix + 'transform'] = transform;
18324 });
18325 }
18326
18327 var OverlaysModule = {
18328 __init__: [ 'overlays' ],
18329 overlays: [ 'type', Overlays ]
18330 };
18331
18332 /**
18333 * This file must not be changed or exchanged.
18334 *
18335 * @see http://bpmn.io/license for more information.
18336 */
18337
18338
18339 // inlined ../../resources/logo.svg
18340 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>';
18341
18342 var BPMNIO_LOGO_URL = 'data:image/svg+xml,' + encodeURIComponent(BPMNIO_LOGO_SVG);
18343
18344 var BPMNIO_IMG = '<img width="52" height="52" src="' + BPMNIO_LOGO_URL + '" />';
18345
18346 function css(attrs) {
18347 return attrs.join(';');
18348 }
18349
18350 var LIGHTBOX_STYLES = css([
18351 'z-index: 1001',
18352 'position: fixed',
18353 'top: 0',
18354 'left: 0',
18355 'right: 0',
18356 'bottom: 0'
18357 ]);
18358
18359 var BACKDROP_STYLES = css([
18360 'width: 100%',
18361 'height: 100%',
18362 'background: rgba(0,0,0,0.2)'
18363 ]);
18364
18365 var NOTICE_STYLES = css([
18366 'position: absolute',
18367 'left: 50%',
18368 'top: 40%',
18369 'margin: 0 -130px',
18370 'width: 260px',
18371 'padding: 10px',
18372 'background: white',
18373 'border: solid 1px #AAA',
18374 'border-radius: 3px',
18375 'font-family: Helvetica, Arial, sans-serif',
18376 'font-size: 14px',
18377 'line-height: 1.2em'
18378 ]);
18379
18380 var LIGHTBOX_MARKUP =
18381 '<div class="bjs-powered-by-lightbox" style="' + LIGHTBOX_STYLES + '">' +
18382 '<div class="backdrop" style="' + BACKDROP_STYLES + '"></div>' +
18383 '<div class="notice" style="' + NOTICE_STYLES + '">' +
18384 '<a href="http://bpmn.io" target="_blank" style="float: left; margin-right: 10px">' +
18385 BPMNIO_IMG +
18386 '</a>' +
18387 'Web-based tooling for BPMN, DMN and CMMN diagrams ' +
18388 'powered by <a href="http://bpmn.io" target="_blank">bpmn.io</a>.' +
18389 '</div>' +
18390 '</div>';
18391
18392
18393 var lightbox;
18394
18395 function open() {
18396
18397 if (!lightbox) {
18398 lightbox = domify(LIGHTBOX_MARKUP);
18399
18400 delegateEvents.bind(lightbox, '.backdrop', 'click', function(event) {
18401 document.body.removeChild(lightbox);
18402 });
18403 }
18404
18405 document.body.appendChild(lightbox);
18406 }
18407
18408 /**
18409 * The code in the <project-logo></project-logo> area
18410 * must not be changed.
18411 *
18412 * @see http://bpmn.io/license for more information.
18413 */
18414
18415
18416 function checkValidationError(err) {
18417
18418 // check if we can help the user by indicating wrong BPMN 2.0 xml
18419 // (in case he or the exporting tool did not get that right)
18420
18421 var pattern = /unparsable content <([^>]+)> detected([\s\S]*)$/;
18422 var match = pattern.exec(err.message);
18423
18424 if (match) {
18425 err.message =
18426 'unparsable content <' + match[1] + '> detected; ' +
18427 'this may indicate an invalid BPMN 2.0 diagram file' + match[2];
18428 }
18429
18430 return err;
18431 }
18432
18433 var DEFAULT_OPTIONS = {
18434 width: '100%',
18435 height: '100%',
18436 position: 'relative'
18437 };
18438
18439
18440 /**
18441 * Ensure the passed argument is a proper unit (defaulting to px)
18442 */
18443 function ensureUnit(val) {
18444 return val + (isNumber(val) ? 'px' : '');
18445 }
18446
18447
18448 /**
18449 * Find BPMNDiagram in definitions by ID
18450 *
18451 * @param {ModdleElement<Definitions>} definitions
18452 * @param {String} diagramId
18453 *
18454 * @return {ModdleElement<BPMNDiagram>|null}
18455 */
18456 function findBPMNDiagram(definitions, diagramId) {
18457 if (!diagramId) {
18458 return null;
18459 }
18460
18461 return find(definitions.diagrams, function(element) {
18462 return element.id === diagramId;
18463 }) || null;
18464 }
18465
18466 /**
18467 * A viewer for BPMN 2.0 diagrams.
18468 *
18469 * Have a look at {@link NavigatedViewer} or {@link Modeler} for bundles that include
18470 * additional features.
18471 *
18472 *
18473 * ## Extending the Viewer
18474 *
18475 * In order to extend the viewer pass extension modules to bootstrap via the
18476 * `additionalModules` option. An extension module is an object that exposes
18477 * named services.
18478 *
18479 * The following example depicts the integration of a simple
18480 * logging component that integrates with interaction events:
18481 *
18482 *
18483 * ```javascript
18484 *
18485 * // logging component
18486 * function InteractionLogger(eventBus) {
18487 * eventBus.on('element.hover', function(event) {
18488 * console.log()
18489 * })
18490 * }
18491 *
18492 * InteractionLogger.$inject = [ 'eventBus' ]; // minification save
18493 *
18494 * // extension module
18495 * var extensionModule = {
18496 * __init__: [ 'interactionLogger' ],
18497 * interactionLogger: [ 'type', InteractionLogger ]
18498 * };
18499 *
18500 * // extend the viewer
18501 * var bpmnViewer = new Viewer({ additionalModules: [ extensionModule ] });
18502 * bpmnViewer.importXML(...);
18503 * ```
18504 *
18505 * @param {Object} [options] configuration options to pass to the viewer
18506 * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
18507 * @param {String|Number} [options.width] the width of the viewer
18508 * @param {String|Number} [options.height] the height of the viewer
18509 * @param {Object} [options.moddleExtensions] extension packages to provide
18510 * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
18511 * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
18512 */
18513 function Viewer(options) {
18514
18515 options = assign({}, DEFAULT_OPTIONS, options);
18516
18517 this._moddle = this._createModdle(options);
18518
18519 this._container = this._createContainer(options);
18520
18521 /* <project-logo> */
18522
18523 addProjectLogo(this._container);
18524
18525 /* </project-logo> */
18526
18527 this._init(this._container, this._moddle, options);
18528 }
18529
18530 inherits_browser(Viewer, Diagram);
18531
18532
18533 /**
18534 * Parse and render a BPMN 2.0 diagram.
18535 *
18536 * Once finished the viewer reports back the result to the
18537 * provided callback function with (err, warnings).
18538 *
18539 * ## Life-Cycle Events
18540 *
18541 * During import the viewer will fire life-cycle events:
18542 *
18543 * * import.parse.start (about to read model from xml)
18544 * * import.parse.complete (model read; may have worked or not)
18545 * * import.render.start (graphical import start)
18546 * * import.render.complete (graphical import finished)
18547 * * import.done (everything done)
18548 *
18549 * You can use these events to hook into the life-cycle.
18550 *
18551 * @param {String} xml the BPMN 2.0 xml
18552 * @param {ModdleElement<BPMNDiagram>|String} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
18553 * @param {Function} [done] invoked with (err, warnings=[])
18554 */
18555 Viewer.prototype.importXML = function(xml, bpmnDiagram, done) {
18556
18557 if (isFunction(bpmnDiagram)) {
18558 done = bpmnDiagram;
18559 bpmnDiagram = null;
18560 }
18561
18562 // done is optional
18563 done = done || function() {};
18564
18565 var self = this;
18566
18567 // hook in pre-parse listeners +
18568 // allow xml manipulation
18569 xml = this._emit('import.parse.start', { xml: xml }) || xml;
18570
18571 this._moddle.fromXML(xml, 'bpmn:Definitions', function(err, definitions, context) {
18572
18573 // hook in post parse listeners +
18574 // allow definitions manipulation
18575 definitions = self._emit('import.parse.complete', {
18576 error: err,
18577 definitions: definitions,
18578 context: context
18579 }) || definitions;
18580
18581 var parseWarnings = context.warnings;
18582
18583 if (err) {
18584 err = checkValidationError(err);
18585
18586 self._emit('import.done', { error: err, warnings: parseWarnings });
18587
18588 return done(err, parseWarnings);
18589 }
18590
18591 self.importDefinitions(definitions, bpmnDiagram, function(err, importWarnings) {
18592 var allWarnings = [].concat(parseWarnings, importWarnings || []);
18593
18594 self._emit('import.done', { error: err, warnings: allWarnings });
18595
18596 done(err, allWarnings);
18597 });
18598 });
18599 };
18600
18601 /**
18602 * Import parsed definitions and render a BPMN 2.0 diagram.
18603 *
18604 * Once finished the viewer reports back the result to the
18605 * provided callback function with (err, warnings).
18606 *
18607 * ## Life-Cycle Events
18608 *
18609 * During import the viewer will fire life-cycle events:
18610 *
18611 * * import.render.start (graphical import start)
18612 * * import.render.complete (graphical import finished)
18613 *
18614 * You can use these events to hook into the life-cycle.
18615 *
18616 * @param {ModdleElement<Definitions>} definitions parsed BPMN 2.0 definitions
18617 * @param {ModdleElement<BPMNDiagram>|String} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
18618 * @param {Function} [done] invoked with (err, warnings=[])
18619 */
18620 Viewer.prototype.importDefinitions = function(definitions, bpmnDiagram, done) {
18621
18622 if (isFunction(bpmnDiagram)) {
18623 done = bpmnDiagram;
18624 bpmnDiagram = null;
18625 }
18626
18627 // done is optional
18628 done = done || function() {};
18629
18630 this._setDefinitions(definitions);
18631
18632 return this.open(bpmnDiagram, done);
18633 };
18634
18635 /**
18636 * Open diagram of previously imported XML.
18637 *
18638 * Once finished the viewer reports back the result to the
18639 * provided callback function with (err, warnings).
18640 *
18641 * ## Life-Cycle Events
18642 *
18643 * During switch the viewer will fire life-cycle events:
18644 *
18645 * * import.render.start (graphical import start)
18646 * * import.render.complete (graphical import finished)
18647 *
18648 * You can use these events to hook into the life-cycle.
18649 *
18650 * @param {String|ModdleElement<BPMNDiagram>} [bpmnDiagramOrId] id or the diagram to open
18651 * @param {Function} [done] invoked with (err, warnings=[])
18652 */
18653 Viewer.prototype.open = function(bpmnDiagramOrId, done) {
18654
18655 if (isFunction(bpmnDiagramOrId)) {
18656 done = bpmnDiagramOrId;
18657 bpmnDiagramOrId = null;
18658 }
18659
18660 var definitions = this._definitions;
18661 var bpmnDiagram = bpmnDiagramOrId;
18662
18663 // done is optional
18664 done = done || function() {};
18665
18666 if (!definitions) {
18667 return done(new Error('no XML imported'));
18668 }
18669
18670 if (typeof bpmnDiagramOrId === 'string') {
18671 bpmnDiagram = findBPMNDiagram(definitions, bpmnDiagramOrId);
18672
18673 if (!bpmnDiagram) {
18674 return done(new Error('BPMNDiagram <' + bpmnDiagramOrId + '> not found'));
18675 }
18676 }
18677
18678 // clear existing rendered diagram
18679 // catch synchronous exceptions during #clear()
18680 try {
18681 this.clear();
18682 } catch (error) {
18683 return done(error);
18684 }
18685
18686 // perform graphical import
18687 return importBpmnDiagram(this, definitions, bpmnDiagram, done);
18688 };
18689
18690 /**
18691 * Export the currently displayed BPMN 2.0 diagram as
18692 * a BPMN 2.0 XML document.
18693 *
18694 * ## Life-Cycle Events
18695 *
18696 * During XML saving the viewer will fire life-cycle events:
18697 *
18698 * * saveXML.start (before serialization)
18699 * * saveXML.serialized (after xml generation)
18700 * * saveXML.done (everything done)
18701 *
18702 * You can use these events to hook into the life-cycle.
18703 *
18704 * @param {Object} [options] export options
18705 * @param {Boolean} [options.format=false] output formatted XML
18706 * @param {Boolean} [options.preamble=true] output preamble
18707 *
18708 * @param {Function} done invoked with (err, xml)
18709 */
18710 Viewer.prototype.saveXML = function(options, done) {
18711
18712 if (!done) {
18713 done = options;
18714 options = {};
18715 }
18716
18717 var self = this;
18718
18719 var definitions = this._definitions;
18720
18721 if (!definitions) {
18722 return done(new Error('no definitions loaded'));
18723 }
18724
18725 // allow to fiddle around with definitions
18726 definitions = this._emit('saveXML.start', {
18727 definitions: definitions
18728 }) || definitions;
18729
18730 this._moddle.toXML(definitions, options, function(err, xml) {
18731
18732 try {
18733 xml = self._emit('saveXML.serialized', {
18734 error: err,
18735 xml: xml
18736 }) || xml;
18737
18738 self._emit('saveXML.done', {
18739 error: err,
18740 xml: xml
18741 });
18742 } catch (e) {
18743 console.error('error in saveXML life-cycle listener', e);
18744 }
18745
18746 done(err, xml);
18747 });
18748 };
18749
18750 /**
18751 * Export the currently displayed BPMN 2.0 diagram as
18752 * an SVG image.
18753 *
18754 * ## Life-Cycle Events
18755 *
18756 * During SVG saving the viewer will fire life-cycle events:
18757 *
18758 * * saveSVG.start (before serialization)
18759 * * saveSVG.done (everything done)
18760 *
18761 * You can use these events to hook into the life-cycle.
18762 *
18763 * @param {Object} [options]
18764 * @param {Function} done invoked with (err, svgStr)
18765 */
18766 Viewer.prototype.saveSVG = function(options, done) {
18767
18768 if (!done) {
18769 done = options;
18770 options = {};
18771 }
18772
18773 this._emit('saveSVG.start');
18774
18775 var svg, err;
18776
18777 try {
18778 var canvas = this.get('canvas');
18779
18780 var contentNode = canvas.getDefaultLayer(),
18781 defsNode = query('defs', canvas._svg);
18782
18783 var contents = innerSVG(contentNode),
18784 defs = defsNode ? '<defs>' + innerSVG(defsNode) + '</defs>' : '';
18785
18786 var bbox = contentNode.getBBox();
18787
18788 svg =
18789 '<?xml version="1.0" encoding="utf-8"?>\n' +
18790 '<!-- created with bpmn-js / http://bpmn.io -->\n' +
18791 '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
18792 '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
18793 'width="' + bbox.width + '" height="' + bbox.height + '" ' +
18794 'viewBox="' + bbox.x + ' ' + bbox.y + ' ' + bbox.width + ' ' + bbox.height + '" version="1.1">' +
18795 defs + contents +
18796 '</svg>';
18797 } catch (e) {
18798 err = e;
18799 }
18800
18801 this._emit('saveSVG.done', {
18802 error: err,
18803 svg: svg
18804 });
18805
18806 done(err, svg);
18807 };
18808
18809 /**
18810 * Get a named diagram service.
18811 *
18812 * @example
18813 *
18814 * var elementRegistry = viewer.get('elementRegistry');
18815 * var startEventShape = elementRegistry.get('StartEvent_1');
18816 *
18817 * @param {String} name
18818 *
18819 * @return {Object} diagram service instance
18820 *
18821 * @method Viewer#get
18822 */
18823
18824 /**
18825 * Invoke a function in the context of this viewer.
18826 *
18827 * @example
18828 *
18829 * viewer.invoke(function(elementRegistry) {
18830 * var startEventShape = elementRegistry.get('StartEvent_1');
18831 * });
18832 *
18833 * @param {Function} fn to be invoked
18834 *
18835 * @return {Object} the functions return value
18836 *
18837 * @method Viewer#invoke
18838 */
18839
18840
18841 Viewer.prototype._setDefinitions = function(definitions) {
18842 this._definitions = definitions;
18843 };
18844
18845 Viewer.prototype.getModules = function() {
18846 return this._modules;
18847 };
18848
18849 /**
18850 * Remove all drawn elements from the viewer.
18851 *
18852 * After calling this method the viewer can still
18853 * be reused for opening another diagram.
18854 *
18855 * @method Viewer#clear
18856 */
18857 Viewer.prototype.clear = function() {
18858 if (!this.getDefinitions()) {
18859
18860 // no diagram to clear
18861 return;
18862 }
18863
18864 // remove businessObject#di binding
18865 //
18866 // this is necessary, as we establish the bindings
18867 // in the BpmnTreeWalker (and assume none are given
18868 // on reimport)
18869 this.get('elementRegistry').forEach(function(element) {
18870 var bo = element.businessObject;
18871
18872 if (bo && bo.di) {
18873 delete bo.di;
18874 }
18875 });
18876
18877 // remove drawn elements
18878 Diagram.prototype.clear.call(this);
18879 };
18880
18881 /**
18882 * Destroy the viewer instance and remove all its
18883 * remainders from the document tree.
18884 */
18885 Viewer.prototype.destroy = function() {
18886
18887 // diagram destroy
18888 Diagram.prototype.destroy.call(this);
18889
18890 // dom detach
18891 remove(this._container);
18892 };
18893
18894 /**
18895 * Register an event listener
18896 *
18897 * Remove a previously added listener via {@link #off(event, callback)}.
18898 *
18899 * @param {String} event
18900 * @param {Number} [priority]
18901 * @param {Function} callback
18902 * @param {Object} [that]
18903 */
18904 Viewer.prototype.on = function(event, priority, callback, target) {
18905 return this.get('eventBus').on(event, priority, callback, target);
18906 };
18907
18908 /**
18909 * De-register an event listener
18910 *
18911 * @param {String} event
18912 * @param {Function} callback
18913 */
18914 Viewer.prototype.off = function(event, callback) {
18915 this.get('eventBus').off(event, callback);
18916 };
18917
18918 Viewer.prototype.attachTo = function(parentNode) {
18919
18920 if (!parentNode) {
18921 throw new Error('parentNode required');
18922 }
18923
18924 // ensure we detach from the
18925 // previous, old parent
18926 this.detach();
18927
18928 // unwrap jQuery if provided
18929 if (parentNode.get && parentNode.constructor.prototype.jquery) {
18930 parentNode = parentNode.get(0);
18931 }
18932
18933 if (typeof parentNode === 'string') {
18934 parentNode = query(parentNode);
18935 }
18936
18937 parentNode.appendChild(this._container);
18938
18939 this._emit('attach', {});
18940
18941 this.get('canvas').resized();
18942 };
18943
18944 Viewer.prototype.getDefinitions = function() {
18945 return this._definitions;
18946 };
18947
18948 Viewer.prototype.detach = function() {
18949
18950 var container = this._container,
18951 parentNode = container.parentNode;
18952
18953 if (!parentNode) {
18954 return;
18955 }
18956
18957 this._emit('detach', {});
18958
18959 parentNode.removeChild(container);
18960 };
18961
18962 Viewer.prototype._init = function(container, moddle, options) {
18963
18964 var baseModules = options.modules || this.getModules(),
18965 additionalModules = options.additionalModules || [],
18966 staticModules = [
18967 {
18968 bpmnjs: [ 'value', this ],
18969 moddle: [ 'value', moddle ]
18970 }
18971 ];
18972
18973 var diagramModules = [].concat(staticModules, baseModules, additionalModules);
18974
18975 var diagramOptions = assign(omit(options, [ 'additionalModules' ]), {
18976 canvas: assign({}, options.canvas, { container: container }),
18977 modules: diagramModules
18978 });
18979
18980 // invoke diagram constructor
18981 Diagram.call(this, diagramOptions);
18982
18983 if (options && options.container) {
18984 this.attachTo(options.container);
18985 }
18986 };
18987
18988 /**
18989 * Emit an event on the underlying {@link EventBus}
18990 *
18991 * @param {String} type
18992 * @param {Object} event
18993 *
18994 * @return {Object} event processing result (if any)
18995 */
18996 Viewer.prototype._emit = function(type, event) {
18997 return this.get('eventBus').fire(type, event);
18998 };
18999
19000 Viewer.prototype._createContainer = function(options) {
19001
19002 var container = domify('<div class="bjs-container"></div>');
19003
19004 assign(container.style, {
19005 width: ensureUnit(options.width),
19006 height: ensureUnit(options.height),
19007 position: options.position
19008 });
19009
19010 return container;
19011 };
19012
19013 Viewer.prototype._createModdle = function(options) {
19014 var moddleOptions = assign({}, this._moddleExtensions, options.moddleExtensions);
19015
19016 return new simple(moddleOptions);
19017 };
19018
19019 // modules the viewer is composed of
19020 Viewer.prototype._modules = [
19021 CoreModule$1,
19022 TranslateModule,
19023 SelectionModule,
19024 OverlaysModule
19025 ];
19026
19027 // default moddle extensions the viewer is composed of
19028 Viewer.prototype._moddleExtensions = {};
19029
19030 /**
19031 * Adds the project logo to the diagram container as
19032 * required by the bpmn.io license.
19033 *
19034 * @see http://bpmn.io/license
19035 *
19036 * @param {Element} container
19037 */
19038 function addProjectLogo(container) {
19039 var img = BPMNIO_IMG;
19040
19041 var linkMarkup =
19042 '<a href="http://bpmn.io" ' +
19043 'target="_blank" ' +
19044 'class="bjs-powered-by" ' +
19045 'title="Powered by bpmn.io" ' +
19046 'style="position: absolute; bottom: 15px; right: 15px; z-index: 100">' +
19047 img +
19048 '</a>';
19049
19050 var linkElement = domify(linkMarkup);
19051
19052 container.appendChild(linkElement);
19053
19054 componentEvent.bind(linkElement, 'click', function(event) {
19055 open();
19056
19057 event.preventDefault();
19058 });
19059 }
19060
19061 /* </project-logo> */
19062
19063 return Viewer;
19064
19065}));