UNPKG

449 kBJavaScriptView Raw
1/*!
2 * bpmn-js - bpmn-viewer v5.0.2
3 *
4 * Copyright (c) 2014-present, camunda Services GmbH
5 *
6 * Released under the bpmn.io license
7 * http://bpmn.io/license
8 *
9 * Source Code: https://github.com/bpmn-io/bpmn-js
10 *
11 * Date: 2019-08-21
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 event = type;
4507 type = event.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 return str.replace(/[()\s,#]+/g, '_');
13550 }
13551
13552 function marker(type, fill, stroke) {
13553 var id = type + '-' + colorEscape(fill) + '-' + colorEscape(stroke) + '-' + rendererId;
13554
13555 if (!markers[id]) {
13556 createMarker(id, type, fill, stroke);
13557 }
13558
13559 return 'url(#' + id + ')';
13560 }
13561
13562 function createMarker(id, type, fill, stroke) {
13563
13564 if (type === 'sequenceflow-end') {
13565 var sequenceflowEnd = create('path');
13566 attr$1(sequenceflowEnd, { d: 'M 1 5 L 11 10 L 1 15 Z' });
13567
13568 addMarker(id, {
13569 element: sequenceflowEnd,
13570 ref: { x: 11, y: 10 },
13571 scale: 0.5,
13572 attrs: {
13573 fill: stroke,
13574 stroke: stroke
13575 }
13576 });
13577 }
13578
13579 if (type === 'messageflow-start') {
13580 var messageflowStart = create('circle');
13581 attr$1(messageflowStart, { cx: 6, cy: 6, r: 3.5 });
13582
13583 addMarker(id, {
13584 element: messageflowStart,
13585 attrs: {
13586 fill: fill,
13587 stroke: stroke
13588 },
13589 ref: { x: 6, y: 6 }
13590 });
13591 }
13592
13593 if (type === 'messageflow-end') {
13594 var messageflowEnd = create('path');
13595 attr$1(messageflowEnd, { d: 'm 1 5 l 0 -3 l 7 3 l -7 3 z' });
13596
13597 addMarker(id, {
13598 element: messageflowEnd,
13599 attrs: {
13600 fill: fill,
13601 stroke: stroke,
13602 strokeLinecap: 'butt'
13603 },
13604 ref: { x: 8.5, y: 5 }
13605 });
13606 }
13607
13608 if (type === 'association-start') {
13609 var associationStart = create('path');
13610 attr$1(associationStart, { d: 'M 11 5 L 1 10 L 11 15' });
13611
13612 addMarker(id, {
13613 element: associationStart,
13614 attrs: {
13615 fill: 'none',
13616 stroke: stroke,
13617 strokeWidth: 1.5
13618 },
13619 ref: { x: 1, y: 10 },
13620 scale: 0.5
13621 });
13622 }
13623
13624 if (type === 'association-end') {
13625 var associationEnd = create('path');
13626 attr$1(associationEnd, { d: 'M 1 5 L 11 10 L 1 15' });
13627
13628 addMarker(id, {
13629 element: associationEnd,
13630 attrs: {
13631 fill: 'none',
13632 stroke: stroke,
13633 strokeWidth: 1.5
13634 },
13635 ref: { x: 12, y: 10 },
13636 scale: 0.5
13637 });
13638 }
13639
13640 if (type === 'conditional-flow-marker') {
13641 var conditionalflowMarker = create('path');
13642 attr$1(conditionalflowMarker, { d: 'M 0 10 L 8 6 L 16 10 L 8 14 Z' });
13643
13644 addMarker(id, {
13645 element: conditionalflowMarker,
13646 attrs: {
13647 fill: fill,
13648 stroke: stroke
13649 },
13650 ref: { x: -1, y: 10 },
13651 scale: 0.5
13652 });
13653 }
13654
13655 if (type === 'conditional-default-flow-marker') {
13656 var conditionaldefaultflowMarker = create('path');
13657 attr$1(conditionaldefaultflowMarker, { d: 'M 6 4 L 10 16' });
13658
13659 addMarker(id, {
13660 element: conditionaldefaultflowMarker,
13661 attrs: {
13662 stroke: stroke
13663 },
13664 ref: { x: 0, y: 10 },
13665 scale: 0.5
13666 });
13667 }
13668 }
13669
13670 function drawCircle(parentGfx, width, height, offset, attrs) {
13671
13672 if (isObject(offset)) {
13673 attrs = offset;
13674 offset = 0;
13675 }
13676
13677 offset = offset || 0;
13678
13679 attrs = computeStyle(attrs, {
13680 stroke: 'black',
13681 strokeWidth: 2,
13682 fill: 'white'
13683 });
13684
13685 if (attrs.fill === 'none') {
13686 delete attrs.fillOpacity;
13687 }
13688
13689 var cx = width / 2,
13690 cy = height / 2;
13691
13692 var circle = create('circle');
13693 attr$1(circle, {
13694 cx: cx,
13695 cy: cy,
13696 r: Math.round((width + height) / 4 - offset)
13697 });
13698 attr$1(circle, attrs);
13699
13700 append(parentGfx, circle);
13701
13702 return circle;
13703 }
13704
13705 function drawRect(parentGfx, width, height, r, offset, attrs) {
13706
13707 if (isObject(offset)) {
13708 attrs = offset;
13709 offset = 0;
13710 }
13711
13712 offset = offset || 0;
13713
13714 attrs = computeStyle(attrs, {
13715 stroke: 'black',
13716 strokeWidth: 2,
13717 fill: 'white'
13718 });
13719
13720 var rect = create('rect');
13721 attr$1(rect, {
13722 x: offset,
13723 y: offset,
13724 width: width - offset * 2,
13725 height: height - offset * 2,
13726 rx: r,
13727 ry: r
13728 });
13729 attr$1(rect, attrs);
13730
13731 append(parentGfx, rect);
13732
13733 return rect;
13734 }
13735
13736 function drawDiamond(parentGfx, width, height, attrs) {
13737
13738 var x_2 = width / 2;
13739 var y_2 = height / 2;
13740
13741 var points = [{ x: x_2, y: 0 }, { x: width, y: y_2 }, { x: x_2, y: height }, { x: 0, y: y_2 }];
13742
13743 var pointsString = points.map(function(point) {
13744 return point.x + ',' + point.y;
13745 }).join(' ');
13746
13747 attrs = computeStyle(attrs, {
13748 stroke: 'black',
13749 strokeWidth: 2,
13750 fill: 'white'
13751 });
13752
13753 var polygon = create('polygon');
13754 attr$1(polygon, {
13755 points: pointsString
13756 });
13757 attr$1(polygon, attrs);
13758
13759 append(parentGfx, polygon);
13760
13761 return polygon;
13762 }
13763
13764 function drawLine(parentGfx, waypoints, attrs) {
13765 attrs = computeStyle(attrs, [ 'no-fill' ], {
13766 stroke: 'black',
13767 strokeWidth: 2,
13768 fill: 'none'
13769 });
13770
13771 var line = createLine(waypoints, attrs);
13772
13773 append(parentGfx, line);
13774
13775 return line;
13776 }
13777
13778 function drawPath(parentGfx, d, attrs) {
13779
13780 attrs = computeStyle(attrs, [ 'no-fill' ], {
13781 strokeWidth: 2,
13782 stroke: 'black'
13783 });
13784
13785 var path = create('path');
13786 attr$1(path, { d: d });
13787 attr$1(path, attrs);
13788
13789 append(parentGfx, path);
13790
13791 return path;
13792 }
13793
13794 function drawMarker(type, parentGfx, path, attrs) {
13795 return drawPath(parentGfx, path, assign({ 'data-marker': type }, attrs));
13796 }
13797
13798 function as(type) {
13799 return function(parentGfx, element) {
13800 return handlers[type](parentGfx, element);
13801 };
13802 }
13803
13804 function renderer(type) {
13805 return handlers[type];
13806 }
13807
13808 function renderEventContent(element, parentGfx) {
13809
13810 var event = getSemantic(element);
13811 var isThrowing = isThrowEvent(event);
13812
13813 if (event.eventDefinitions && event.eventDefinitions.length>1) {
13814 if (event.parallelMultiple) {
13815 return renderer('bpmn:ParallelMultipleEventDefinition')(parentGfx, element, isThrowing);
13816 }
13817 else {
13818 return renderer('bpmn:MultipleEventDefinition')(parentGfx, element, isThrowing);
13819 }
13820 }
13821
13822 if (isTypedEvent(event, 'bpmn:MessageEventDefinition')) {
13823 return renderer('bpmn:MessageEventDefinition')(parentGfx, element, isThrowing);
13824 }
13825
13826 if (isTypedEvent(event, 'bpmn:TimerEventDefinition')) {
13827 return renderer('bpmn:TimerEventDefinition')(parentGfx, element, isThrowing);
13828 }
13829
13830 if (isTypedEvent(event, 'bpmn:ConditionalEventDefinition')) {
13831 return renderer('bpmn:ConditionalEventDefinition')(parentGfx, element);
13832 }
13833
13834 if (isTypedEvent(event, 'bpmn:SignalEventDefinition')) {
13835 return renderer('bpmn:SignalEventDefinition')(parentGfx, element, isThrowing);
13836 }
13837
13838 if (isTypedEvent(event, 'bpmn:EscalationEventDefinition')) {
13839 return renderer('bpmn:EscalationEventDefinition')(parentGfx, element, isThrowing);
13840 }
13841
13842 if (isTypedEvent(event, 'bpmn:LinkEventDefinition')) {
13843 return renderer('bpmn:LinkEventDefinition')(parentGfx, element, isThrowing);
13844 }
13845
13846 if (isTypedEvent(event, 'bpmn:ErrorEventDefinition')) {
13847 return renderer('bpmn:ErrorEventDefinition')(parentGfx, element, isThrowing);
13848 }
13849
13850 if (isTypedEvent(event, 'bpmn:CancelEventDefinition')) {
13851 return renderer('bpmn:CancelEventDefinition')(parentGfx, element, isThrowing);
13852 }
13853
13854 if (isTypedEvent(event, 'bpmn:CompensateEventDefinition')) {
13855 return renderer('bpmn:CompensateEventDefinition')(parentGfx, element, isThrowing);
13856 }
13857
13858 if (isTypedEvent(event, 'bpmn:TerminateEventDefinition')) {
13859 return renderer('bpmn:TerminateEventDefinition')(parentGfx, element, isThrowing);
13860 }
13861
13862 return null;
13863 }
13864
13865 function renderLabel(parentGfx, label, options) {
13866
13867 options = assign({
13868 size: {
13869 width: 100
13870 }
13871 }, options);
13872
13873 var text = textRenderer.createText(label || '', options);
13874
13875 classes$1(text).add('djs-label');
13876
13877 append(parentGfx, text);
13878
13879 return text;
13880 }
13881
13882 function renderEmbeddedLabel(parentGfx, element, align) {
13883 var semantic = getSemantic(element);
13884
13885 return renderLabel(parentGfx, semantic.name, {
13886 box: element,
13887 align: align,
13888 padding: 5,
13889 style: {
13890 fill: getStrokeColor(element, defaultStrokeColor)
13891 }
13892 });
13893 }
13894
13895 function renderExternalLabel(parentGfx, element) {
13896
13897 var box = {
13898 width: 90,
13899 height: 30,
13900 x: element.width / 2 + element.x,
13901 y: element.height / 2 + element.y
13902 };
13903
13904 return renderLabel(parentGfx, getLabel(element), {
13905 box: box,
13906 fitBox: true,
13907 style: assign(
13908 {},
13909 textRenderer.getExternalStyle(),
13910 {
13911 fill: getStrokeColor(element, defaultStrokeColor)
13912 }
13913 )
13914 });
13915 }
13916
13917 function renderLaneLabel(parentGfx, text, element) {
13918 var textBox = renderLabel(parentGfx, text, {
13919 box: {
13920 height: 30,
13921 width: element.height
13922 },
13923 align: 'center-middle',
13924 style: {
13925 fill: getStrokeColor(element, defaultStrokeColor)
13926 }
13927 });
13928
13929 var top = -1 * element.height;
13930
13931 transform$1(textBox, 0, -top, 270);
13932 }
13933
13934 function createPathFromConnection(connection) {
13935 var waypoints = connection.waypoints;
13936
13937 var pathData = 'm ' + waypoints[0].x + ',' + waypoints[0].y;
13938 for (var i = 1; i < waypoints.length; i++) {
13939 pathData += 'L' + waypoints[i].x + ',' + waypoints[i].y + ' ';
13940 }
13941 return pathData;
13942 }
13943
13944 var handlers = this.handlers = {
13945 'bpmn:Event': function(parentGfx, element, attrs) {
13946
13947 if (!('fillOpacity' in attrs)) {
13948 attrs.fillOpacity = DEFAULT_FILL_OPACITY;
13949 }
13950
13951 return drawCircle(parentGfx, element.width, element.height, attrs);
13952 },
13953 'bpmn:StartEvent': function(parentGfx, element) {
13954 var attrs = {
13955 fill: getFillColor(element, defaultFillColor),
13956 stroke: getStrokeColor(element, defaultStrokeColor)
13957 };
13958
13959 var semantic = getSemantic(element);
13960
13961 if (!semantic.isInterrupting) {
13962 attrs = {
13963 strokeDasharray: '6',
13964 strokeLinecap: 'round',
13965 fill: getFillColor(element, defaultFillColor),
13966 stroke: getStrokeColor(element, defaultStrokeColor)
13967 };
13968 }
13969
13970 var circle = renderer('bpmn:Event')(parentGfx, element, attrs);
13971
13972 renderEventContent(element, parentGfx);
13973
13974 return circle;
13975 },
13976 'bpmn:MessageEventDefinition': function(parentGfx, element, isThrowing) {
13977 var pathData = pathMap.getScaledPath('EVENT_MESSAGE', {
13978 xScaleFactor: 0.9,
13979 yScaleFactor: 0.9,
13980 containerWidth: element.width,
13981 containerHeight: element.height,
13982 position: {
13983 mx: 0.235,
13984 my: 0.315
13985 }
13986 });
13987
13988 var fill = isThrowing ? getStrokeColor(element, defaultStrokeColor) : getFillColor(element, defaultFillColor);
13989 var stroke = isThrowing ? getFillColor(element, defaultFillColor) : getStrokeColor(element, defaultStrokeColor);
13990
13991 var messagePath = drawPath(parentGfx, pathData, {
13992 strokeWidth: 1,
13993 fill: fill,
13994 stroke: stroke
13995 });
13996
13997 return messagePath;
13998 },
13999 'bpmn:TimerEventDefinition': function(parentGfx, element) {
14000 var circle = drawCircle(parentGfx, element.width, element.height, 0.2 * element.height, {
14001 strokeWidth: 2,
14002 fill: getFillColor(element, defaultFillColor),
14003 stroke: getStrokeColor(element, defaultStrokeColor)
14004 });
14005
14006 var pathData = pathMap.getScaledPath('EVENT_TIMER_WH', {
14007 xScaleFactor: 0.75,
14008 yScaleFactor: 0.75,
14009 containerWidth: element.width,
14010 containerHeight: element.height,
14011 position: {
14012 mx: 0.5,
14013 my: 0.5
14014 }
14015 });
14016
14017 drawPath(parentGfx, pathData, {
14018 strokeWidth: 2,
14019 strokeLinecap: 'square',
14020 stroke: getStrokeColor(element, defaultStrokeColor)
14021 });
14022
14023 for (var i = 0;i < 12; i++) {
14024
14025 var linePathData = pathMap.getScaledPath('EVENT_TIMER_LINE', {
14026 xScaleFactor: 0.75,
14027 yScaleFactor: 0.75,
14028 containerWidth: element.width,
14029 containerHeight: element.height,
14030 position: {
14031 mx: 0.5,
14032 my: 0.5
14033 }
14034 });
14035
14036 var width = element.width / 2;
14037 var height = element.height / 2;
14038
14039 drawPath(parentGfx, linePathData, {
14040 strokeWidth: 1,
14041 strokeLinecap: 'square',
14042 transform: 'rotate(' + (i * 30) + ',' + height + ',' + width + ')',
14043 stroke: getStrokeColor(element, defaultStrokeColor)
14044 });
14045 }
14046
14047 return circle;
14048 },
14049 'bpmn:EscalationEventDefinition': function(parentGfx, event, isThrowing) {
14050 var pathData = pathMap.getScaledPath('EVENT_ESCALATION', {
14051 xScaleFactor: 1,
14052 yScaleFactor: 1,
14053 containerWidth: event.width,
14054 containerHeight: event.height,
14055 position: {
14056 mx: 0.5,
14057 my: 0.2
14058 }
14059 });
14060
14061 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14062
14063 return drawPath(parentGfx, pathData, {
14064 strokeWidth: 1,
14065 fill: fill,
14066 stroke: getStrokeColor(event, defaultStrokeColor)
14067 });
14068 },
14069 'bpmn:ConditionalEventDefinition': function(parentGfx, event) {
14070 var pathData = pathMap.getScaledPath('EVENT_CONDITIONAL', {
14071 xScaleFactor: 1,
14072 yScaleFactor: 1,
14073 containerWidth: event.width,
14074 containerHeight: event.height,
14075 position: {
14076 mx: 0.5,
14077 my: 0.222
14078 }
14079 });
14080
14081 return drawPath(parentGfx, pathData, {
14082 strokeWidth: 1,
14083 stroke: getStrokeColor(event, defaultStrokeColor)
14084 });
14085 },
14086 'bpmn:LinkEventDefinition': function(parentGfx, event, isThrowing) {
14087 var pathData = pathMap.getScaledPath('EVENT_LINK', {
14088 xScaleFactor: 1,
14089 yScaleFactor: 1,
14090 containerWidth: event.width,
14091 containerHeight: event.height,
14092 position: {
14093 mx: 0.57,
14094 my: 0.263
14095 }
14096 });
14097
14098 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14099
14100 return drawPath(parentGfx, pathData, {
14101 strokeWidth: 1,
14102 fill: fill,
14103 stroke: getStrokeColor(event, defaultStrokeColor)
14104 });
14105 },
14106 'bpmn:ErrorEventDefinition': function(parentGfx, event, isThrowing) {
14107 var pathData = pathMap.getScaledPath('EVENT_ERROR', {
14108 xScaleFactor: 1.1,
14109 yScaleFactor: 1.1,
14110 containerWidth: event.width,
14111 containerHeight: event.height,
14112 position: {
14113 mx: 0.2,
14114 my: 0.722
14115 }
14116 });
14117
14118 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14119
14120 return drawPath(parentGfx, pathData, {
14121 strokeWidth: 1,
14122 fill: fill,
14123 stroke: getStrokeColor(event, defaultStrokeColor)
14124 });
14125 },
14126 'bpmn:CancelEventDefinition': function(parentGfx, event, isThrowing) {
14127 var pathData = pathMap.getScaledPath('EVENT_CANCEL_45', {
14128 xScaleFactor: 1.0,
14129 yScaleFactor: 1.0,
14130 containerWidth: event.width,
14131 containerHeight: event.height,
14132 position: {
14133 mx: 0.638,
14134 my: -0.055
14135 }
14136 });
14137
14138 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14139
14140 var path = drawPath(parentGfx, pathData, {
14141 strokeWidth: 1,
14142 fill: fill,
14143 stroke: getStrokeColor(event, defaultStrokeColor)
14144 });
14145
14146 rotate(path, 45);
14147
14148 return path;
14149 },
14150 'bpmn:CompensateEventDefinition': function(parentGfx, event, isThrowing) {
14151 var pathData = pathMap.getScaledPath('EVENT_COMPENSATION', {
14152 xScaleFactor: 1,
14153 yScaleFactor: 1,
14154 containerWidth: event.width,
14155 containerHeight: event.height,
14156 position: {
14157 mx: 0.22,
14158 my: 0.5
14159 }
14160 });
14161
14162 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14163
14164 return drawPath(parentGfx, pathData, {
14165 strokeWidth: 1,
14166 fill: fill,
14167 stroke: getStrokeColor(event, defaultStrokeColor)
14168 });
14169 },
14170 'bpmn:SignalEventDefinition': function(parentGfx, event, isThrowing) {
14171 var pathData = pathMap.getScaledPath('EVENT_SIGNAL', {
14172 xScaleFactor: 0.9,
14173 yScaleFactor: 0.9,
14174 containerWidth: event.width,
14175 containerHeight: event.height,
14176 position: {
14177 mx: 0.5,
14178 my: 0.2
14179 }
14180 });
14181
14182 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14183
14184 return drawPath(parentGfx, pathData, {
14185 strokeWidth: 1,
14186 fill: fill,
14187 stroke: getStrokeColor(event, defaultStrokeColor)
14188 });
14189 },
14190 'bpmn:MultipleEventDefinition': function(parentGfx, event, isThrowing) {
14191 var pathData = pathMap.getScaledPath('EVENT_MULTIPLE', {
14192 xScaleFactor: 1.1,
14193 yScaleFactor: 1.1,
14194 containerWidth: event.width,
14195 containerHeight: event.height,
14196 position: {
14197 mx: 0.222,
14198 my: 0.36
14199 }
14200 });
14201
14202 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14203
14204 return drawPath(parentGfx, pathData, {
14205 strokeWidth: 1,
14206 fill: fill
14207 });
14208 },
14209 'bpmn:ParallelMultipleEventDefinition': function(parentGfx, event) {
14210 var pathData = pathMap.getScaledPath('EVENT_PARALLEL_MULTIPLE', {
14211 xScaleFactor: 1.2,
14212 yScaleFactor: 1.2,
14213 containerWidth: event.width,
14214 containerHeight: event.height,
14215 position: {
14216 mx: 0.458,
14217 my: 0.194
14218 }
14219 });
14220
14221 return drawPath(parentGfx, pathData, {
14222 strokeWidth: 1,
14223 fill: getStrokeColor(event, defaultStrokeColor),
14224 stroke: getStrokeColor(event, defaultStrokeColor)
14225 });
14226 },
14227 'bpmn:EndEvent': function(parentGfx, element) {
14228 var circle = renderer('bpmn:Event')(parentGfx, element, {
14229 strokeWidth: 4,
14230 fill: getFillColor(element, defaultFillColor),
14231 stroke: getStrokeColor(element, defaultStrokeColor)
14232 });
14233
14234 renderEventContent(element, parentGfx);
14235
14236 return circle;
14237 },
14238 'bpmn:TerminateEventDefinition': function(parentGfx, element) {
14239 var circle = drawCircle(parentGfx, element.width, element.height, 8, {
14240 strokeWidth: 4,
14241 fill: getStrokeColor(element, defaultStrokeColor),
14242 stroke: getStrokeColor(element, defaultStrokeColor)
14243 });
14244
14245 return circle;
14246 },
14247 'bpmn:IntermediateEvent': function(parentGfx, element) {
14248 var outer = renderer('bpmn:Event')(parentGfx, element, {
14249 strokeWidth: 1,
14250 fill: getFillColor(element, defaultFillColor),
14251 stroke: getStrokeColor(element, defaultStrokeColor)
14252 });
14253
14254 /* inner */
14255 drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, {
14256 strokeWidth: 1,
14257 fill: getFillColor(element, 'none'),
14258 stroke: getStrokeColor(element, defaultStrokeColor)
14259 });
14260
14261 renderEventContent(element, parentGfx);
14262
14263 return outer;
14264 },
14265 'bpmn:IntermediateCatchEvent': as('bpmn:IntermediateEvent'),
14266 'bpmn:IntermediateThrowEvent': as('bpmn:IntermediateEvent'),
14267
14268 'bpmn:Activity': function(parentGfx, element, attrs) {
14269
14270 attrs = attrs || {};
14271
14272 if (!('fillOpacity' in attrs)) {
14273 attrs.fillOpacity = DEFAULT_FILL_OPACITY;
14274 }
14275
14276 return drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, attrs);
14277 },
14278
14279 'bpmn:Task': function(parentGfx, element) {
14280 var attrs = {
14281 fill: getFillColor(element, defaultFillColor),
14282 stroke: getStrokeColor(element, defaultStrokeColor)
14283 };
14284
14285 var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
14286
14287 renderEmbeddedLabel(parentGfx, element, 'center-middle');
14288 attachTaskMarkers(parentGfx, element);
14289
14290 return rect;
14291 },
14292 'bpmn:ServiceTask': function(parentGfx, element) {
14293 var task = renderer('bpmn:Task')(parentGfx, element);
14294
14295 var pathDataBG = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
14296 abspos: {
14297 x: 12,
14298 y: 18
14299 }
14300 });
14301
14302 /* service bg */ drawPath(parentGfx, pathDataBG, {
14303 strokeWidth: 1,
14304 fill: getFillColor(element, defaultFillColor),
14305 stroke: getStrokeColor(element, defaultStrokeColor)
14306 });
14307
14308 var fillPathData = pathMap.getScaledPath('TASK_TYPE_SERVICE_FILL', {
14309 abspos: {
14310 x: 17.2,
14311 y: 18
14312 }
14313 });
14314
14315 /* service fill */ drawPath(parentGfx, fillPathData, {
14316 strokeWidth: 0,
14317 fill: getFillColor(element, defaultFillColor)
14318 });
14319
14320 var pathData = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
14321 abspos: {
14322 x: 17,
14323 y: 22
14324 }
14325 });
14326
14327 /* service */ drawPath(parentGfx, pathData, {
14328 strokeWidth: 1,
14329 fill: getFillColor(element, defaultFillColor),
14330 stroke: getStrokeColor(element, defaultStrokeColor)
14331 });
14332
14333 return task;
14334 },
14335 'bpmn:UserTask': function(parentGfx, element) {
14336 var task = renderer('bpmn:Task')(parentGfx, element);
14337
14338 var x = 15;
14339 var y = 12;
14340
14341 var pathData = pathMap.getScaledPath('TASK_TYPE_USER_1', {
14342 abspos: {
14343 x: x,
14344 y: y
14345 }
14346 });
14347
14348 /* user path */ drawPath(parentGfx, pathData, {
14349 strokeWidth: 0.5,
14350 fill: getFillColor(element, defaultFillColor),
14351 stroke: getStrokeColor(element, defaultStrokeColor)
14352 });
14353
14354 var pathData2 = pathMap.getScaledPath('TASK_TYPE_USER_2', {
14355 abspos: {
14356 x: x,
14357 y: y
14358 }
14359 });
14360
14361 /* user2 path */ drawPath(parentGfx, pathData2, {
14362 strokeWidth: 0.5,
14363 fill: getFillColor(element, defaultFillColor),
14364 stroke: getStrokeColor(element, defaultStrokeColor)
14365 });
14366
14367 var pathData3 = pathMap.getScaledPath('TASK_TYPE_USER_3', {
14368 abspos: {
14369 x: x,
14370 y: y
14371 }
14372 });
14373
14374 /* user3 path */ drawPath(parentGfx, pathData3, {
14375 strokeWidth: 0.5,
14376 fill: getStrokeColor(element, defaultStrokeColor),
14377 stroke: getStrokeColor(element, defaultStrokeColor)
14378 });
14379
14380 return task;
14381 },
14382 'bpmn:ManualTask': function(parentGfx, element) {
14383 var task = renderer('bpmn:Task')(parentGfx, element);
14384
14385 var pathData = pathMap.getScaledPath('TASK_TYPE_MANUAL', {
14386 abspos: {
14387 x: 17,
14388 y: 15
14389 }
14390 });
14391
14392 /* manual path */ drawPath(parentGfx, pathData, {
14393 strokeWidth: 0.5, // 0.25,
14394 fill: getFillColor(element, defaultFillColor),
14395 stroke: getStrokeColor(element, defaultStrokeColor)
14396 });
14397
14398 return task;
14399 },
14400 'bpmn:SendTask': function(parentGfx, element) {
14401 var task = renderer('bpmn:Task')(parentGfx, element);
14402
14403 var pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
14404 xScaleFactor: 1,
14405 yScaleFactor: 1,
14406 containerWidth: 21,
14407 containerHeight: 14,
14408 position: {
14409 mx: 0.285,
14410 my: 0.357
14411 }
14412 });
14413
14414 /* send path */ drawPath(parentGfx, pathData, {
14415 strokeWidth: 1,
14416 fill: getStrokeColor(element, defaultStrokeColor),
14417 stroke: getFillColor(element, defaultFillColor)
14418 });
14419
14420 return task;
14421 },
14422 'bpmn:ReceiveTask' : function(parentGfx, element) {
14423 var semantic = getSemantic(element);
14424
14425 var task = renderer('bpmn:Task')(parentGfx, element);
14426 var pathData;
14427
14428 if (semantic.instantiate) {
14429 drawCircle(parentGfx, 28, 28, 20 * 0.22, { strokeWidth: 1 });
14430
14431 pathData = pathMap.getScaledPath('TASK_TYPE_INSTANTIATING_SEND', {
14432 abspos: {
14433 x: 7.77,
14434 y: 9.52
14435 }
14436 });
14437 } else {
14438
14439 pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
14440 xScaleFactor: 0.9,
14441 yScaleFactor: 0.9,
14442 containerWidth: 21,
14443 containerHeight: 14,
14444 position: {
14445 mx: 0.3,
14446 my: 0.4
14447 }
14448 });
14449 }
14450
14451 /* receive path */ drawPath(parentGfx, pathData, {
14452 strokeWidth: 1,
14453 fill: getFillColor(element, defaultFillColor),
14454 stroke: getStrokeColor(element, defaultStrokeColor)
14455 });
14456
14457 return task;
14458 },
14459 'bpmn:ScriptTask': function(parentGfx, element) {
14460 var task = renderer('bpmn:Task')(parentGfx, element);
14461
14462 var pathData = pathMap.getScaledPath('TASK_TYPE_SCRIPT', {
14463 abspos: {
14464 x: 15,
14465 y: 20
14466 }
14467 });
14468
14469 /* script path */ drawPath(parentGfx, pathData, {
14470 strokeWidth: 1,
14471 stroke: getStrokeColor(element, defaultStrokeColor)
14472 });
14473
14474 return task;
14475 },
14476 'bpmn:BusinessRuleTask': function(parentGfx, element) {
14477 var task = renderer('bpmn:Task')(parentGfx, element);
14478
14479 var headerPathData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_HEADER', {
14480 abspos: {
14481 x: 8,
14482 y: 8
14483 }
14484 });
14485
14486 var businessHeaderPath = drawPath(parentGfx, headerPathData);
14487 attr$1(businessHeaderPath, {
14488 strokeWidth: 1,
14489 fill: getFillColor(element, '#aaaaaa'),
14490 stroke: getStrokeColor(element, defaultStrokeColor)
14491 });
14492
14493 var headerData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_MAIN', {
14494 abspos: {
14495 x: 8,
14496 y: 8
14497 }
14498 });
14499
14500 var businessPath = drawPath(parentGfx, headerData);
14501 attr$1(businessPath, {
14502 strokeWidth: 1,
14503 stroke: getStrokeColor(element, defaultStrokeColor)
14504 });
14505
14506 return task;
14507 },
14508 'bpmn:SubProcess': function(parentGfx, element, attrs) {
14509 attrs = assign({
14510 fill: getFillColor(element, defaultFillColor),
14511 stroke: getStrokeColor(element, defaultStrokeColor)
14512 }, attrs);
14513
14514 var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
14515
14516 var expanded = isExpanded(element);
14517
14518 if (isEventSubProcess(element)) {
14519 attr$1(rect, {
14520 strokeDasharray: '1,2'
14521 });
14522 }
14523
14524 renderEmbeddedLabel(parentGfx, element, expanded ? 'center-top' : 'center-middle');
14525
14526 if (expanded) {
14527 attachTaskMarkers(parentGfx, element);
14528 } else {
14529 attachTaskMarkers(parentGfx, element, ['SubProcessMarker']);
14530 }
14531
14532 return rect;
14533 },
14534 'bpmn:AdHocSubProcess': function(parentGfx, element) {
14535 return renderer('bpmn:SubProcess')(parentGfx, element);
14536 },
14537 'bpmn:Transaction': function(parentGfx, element) {
14538 var outer = renderer('bpmn:SubProcess')(parentGfx, element);
14539
14540 var innerAttrs = styles.style([ 'no-fill', 'no-events' ], {
14541 stroke: getStrokeColor(element, defaultStrokeColor)
14542 });
14543
14544 /* inner path */ drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS - 2, INNER_OUTER_DIST, innerAttrs);
14545
14546 return outer;
14547 },
14548 'bpmn:CallActivity': function(parentGfx, element) {
14549 return renderer('bpmn:SubProcess')(parentGfx, element, {
14550 strokeWidth: 5
14551 });
14552 },
14553 'bpmn:Participant': function(parentGfx, element) {
14554
14555 var attrs = {
14556 fillOpacity: DEFAULT_FILL_OPACITY,
14557 fill: getFillColor(element, defaultFillColor),
14558 stroke: getStrokeColor(element, defaultStrokeColor)
14559 };
14560
14561 var lane = renderer('bpmn:Lane')(parentGfx, element, attrs);
14562
14563 var expandedPool = isExpanded(element);
14564
14565 if (expandedPool) {
14566 drawLine(parentGfx, [
14567 { x: 30, y: 0 },
14568 { x: 30, y: element.height }
14569 ], {
14570 stroke: getStrokeColor(element, defaultStrokeColor)
14571 });
14572 var text = getSemantic(element).name;
14573 renderLaneLabel(parentGfx, text, element);
14574 } else {
14575
14576 // Collapsed pool draw text inline
14577 var text2 = getSemantic(element).name;
14578 renderLabel(parentGfx, text2, {
14579 box: element, align: 'center-middle',
14580 style: {
14581 fill: getStrokeColor(element, defaultStrokeColor)
14582 }
14583 });
14584 }
14585
14586 var participantMultiplicity = !!(getSemantic(element).participantMultiplicity);
14587
14588 if (participantMultiplicity) {
14589 renderer('ParticipantMultiplicityMarker')(parentGfx, element);
14590 }
14591
14592 return lane;
14593 },
14594 'bpmn:Lane': function(parentGfx, element, attrs) {
14595 var rect = drawRect(parentGfx, element.width, element.height, 0, assign({
14596 fill: getFillColor(element, defaultFillColor),
14597 fillOpacity: HIGH_FILL_OPACITY,
14598 stroke: getStrokeColor(element, defaultStrokeColor)
14599 }, attrs));
14600
14601 var semantic = getSemantic(element);
14602
14603 if (semantic.$type === 'bpmn:Lane') {
14604 var text = semantic.name;
14605 renderLaneLabel(parentGfx, text, element);
14606 }
14607
14608 return rect;
14609 },
14610 'bpmn:InclusiveGateway': function(parentGfx, element) {
14611 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14612
14613 /* circle path */
14614 drawCircle(parentGfx, element.width, element.height, element.height * 0.24, {
14615 strokeWidth: 2.5,
14616 fill: getFillColor(element, defaultFillColor),
14617 stroke: getStrokeColor(element, defaultStrokeColor)
14618 });
14619
14620 return diamond;
14621 },
14622 'bpmn:ExclusiveGateway': function(parentGfx, element) {
14623 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14624
14625 var pathData = pathMap.getScaledPath('GATEWAY_EXCLUSIVE', {
14626 xScaleFactor: 0.4,
14627 yScaleFactor: 0.4,
14628 containerWidth: element.width,
14629 containerHeight: element.height,
14630 position: {
14631 mx: 0.32,
14632 my: 0.3
14633 }
14634 });
14635
14636 if ((getDi(element).isMarkerVisible)) {
14637 drawPath(parentGfx, pathData, {
14638 strokeWidth: 1,
14639 fill: getStrokeColor(element, defaultStrokeColor),
14640 stroke: getStrokeColor(element, defaultStrokeColor)
14641 });
14642 }
14643
14644 return diamond;
14645 },
14646 'bpmn:ComplexGateway': function(parentGfx, element) {
14647 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14648
14649 var pathData = pathMap.getScaledPath('GATEWAY_COMPLEX', {
14650 xScaleFactor: 0.5,
14651 yScaleFactor:0.5,
14652 containerWidth: element.width,
14653 containerHeight: element.height,
14654 position: {
14655 mx: 0.46,
14656 my: 0.26
14657 }
14658 });
14659
14660 /* complex path */ drawPath(parentGfx, pathData, {
14661 strokeWidth: 1,
14662 fill: getStrokeColor(element, defaultStrokeColor),
14663 stroke: getStrokeColor(element, defaultStrokeColor)
14664 });
14665
14666 return diamond;
14667 },
14668 'bpmn:ParallelGateway': function(parentGfx, element) {
14669 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14670
14671 var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
14672 xScaleFactor: 0.6,
14673 yScaleFactor:0.6,
14674 containerWidth: element.width,
14675 containerHeight: element.height,
14676 position: {
14677 mx: 0.46,
14678 my: 0.2
14679 }
14680 });
14681
14682 /* parallel path */ drawPath(parentGfx, pathData, {
14683 strokeWidth: 1,
14684 fill: getStrokeColor(element, defaultStrokeColor),
14685 stroke: getStrokeColor(element, defaultStrokeColor)
14686 });
14687
14688 return diamond;
14689 },
14690 'bpmn:EventBasedGateway': function(parentGfx, element) {
14691
14692 var semantic = getSemantic(element);
14693
14694 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14695
14696 /* outer circle path */ drawCircle(parentGfx, element.width, element.height, element.height * 0.20, {
14697 strokeWidth: 1,
14698 fill: 'none',
14699 stroke: getStrokeColor(element, defaultStrokeColor)
14700 });
14701
14702 var type = semantic.eventGatewayType;
14703 var instantiate = !!semantic.instantiate;
14704
14705 function drawEvent() {
14706
14707 var pathData = pathMap.getScaledPath('GATEWAY_EVENT_BASED', {
14708 xScaleFactor: 0.18,
14709 yScaleFactor: 0.18,
14710 containerWidth: element.width,
14711 containerHeight: element.height,
14712 position: {
14713 mx: 0.36,
14714 my: 0.44
14715 }
14716 });
14717
14718 var attrs = {
14719 strokeWidth: 2,
14720 fill: getFillColor(element, 'none'),
14721 stroke: getStrokeColor(element, defaultStrokeColor)
14722 };
14723
14724 /* event path */ drawPath(parentGfx, pathData, attrs);
14725 }
14726
14727 if (type === 'Parallel') {
14728
14729 var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
14730 xScaleFactor: 0.4,
14731 yScaleFactor:0.4,
14732 containerWidth: element.width,
14733 containerHeight: element.height,
14734 position: {
14735 mx: 0.474,
14736 my: 0.296
14737 }
14738 });
14739
14740 var parallelPath = drawPath(parentGfx, pathData);
14741 attr$1(parallelPath, {
14742 strokeWidth: 1,
14743 fill: 'none'
14744 });
14745 } else if (type === 'Exclusive') {
14746
14747 if (!instantiate) {
14748 var innerCircle = drawCircle(parentGfx, element.width, element.height, element.height * 0.26);
14749 attr$1(innerCircle, {
14750 strokeWidth: 1,
14751 fill: 'none',
14752 stroke: getStrokeColor(element, defaultStrokeColor)
14753 });
14754 }
14755
14756 drawEvent();
14757 }
14758
14759
14760 return diamond;
14761 },
14762 'bpmn:Gateway': function(parentGfx, element) {
14763 var attrs = {
14764 fill: getFillColor(element, defaultFillColor),
14765 fillOpacity: DEFAULT_FILL_OPACITY,
14766 stroke: getStrokeColor(element, defaultStrokeColor)
14767 };
14768
14769 return drawDiamond(parentGfx, element.width, element.height, attrs);
14770 },
14771 'bpmn:SequenceFlow': function(parentGfx, element) {
14772 var pathData = createPathFromConnection(element);
14773
14774 var fill = getFillColor(element, defaultFillColor),
14775 stroke = getStrokeColor(element, defaultStrokeColor);
14776
14777 var attrs = {
14778 strokeLinejoin: 'round',
14779 markerEnd: marker('sequenceflow-end', fill, stroke),
14780 stroke: getStrokeColor(element, defaultStrokeColor)
14781 };
14782
14783 var path = drawPath(parentGfx, pathData, attrs);
14784
14785 var sequenceFlow = getSemantic(element);
14786
14787 var source;
14788
14789 if (element.source) {
14790 source = element.source.businessObject;
14791
14792 // conditional flow marker
14793 if (sequenceFlow.conditionExpression && source.$instanceOf('bpmn:Activity')) {
14794 attr$1(path, {
14795 markerStart: marker('conditional-flow-marker', fill, stroke)
14796 });
14797 }
14798
14799 // default marker
14800 if (source.default && (source.$instanceOf('bpmn:Gateway') || source.$instanceOf('bpmn:Activity')) &&
14801 source.default === sequenceFlow) {
14802 attr$1(path, {
14803 markerStart: marker('conditional-default-flow-marker', fill, stroke)
14804 });
14805 }
14806 }
14807
14808 return path;
14809 },
14810 'bpmn:Association': function(parentGfx, element, attrs) {
14811
14812 var semantic = getSemantic(element);
14813
14814 var fill = getFillColor(element, defaultFillColor),
14815 stroke = getStrokeColor(element, defaultStrokeColor);
14816
14817 attrs = assign({
14818 strokeDasharray: '0.5, 5',
14819 strokeLinecap: 'round',
14820 strokeLinejoin: 'round',
14821 stroke: getStrokeColor(element, defaultStrokeColor)
14822 }, attrs || {});
14823
14824 if (semantic.associationDirection === 'One' ||
14825 semantic.associationDirection === 'Both') {
14826 attrs.markerEnd = marker('association-end', fill, stroke);
14827 }
14828
14829 if (semantic.associationDirection === 'Both') {
14830 attrs.markerStart = marker('association-start', fill, stroke);
14831 }
14832
14833 return drawLine(parentGfx, element.waypoints, attrs);
14834 },
14835 'bpmn:DataInputAssociation': function(parentGfx, element) {
14836 var fill = getFillColor(element, defaultFillColor),
14837 stroke = getStrokeColor(element, defaultStrokeColor);
14838
14839 return renderer('bpmn:Association')(parentGfx, element, {
14840 markerEnd: marker('association-end', fill, stroke)
14841 });
14842 },
14843 'bpmn:DataOutputAssociation': function(parentGfx, element) {
14844 var fill = getFillColor(element, defaultFillColor),
14845 stroke = getStrokeColor(element, defaultStrokeColor);
14846
14847 return renderer('bpmn:Association')(parentGfx, element, {
14848 markerEnd: marker('association-end', fill, stroke)
14849 });
14850 },
14851 'bpmn:MessageFlow': function(parentGfx, element) {
14852
14853 var semantic = getSemantic(element),
14854 di = getDi(element);
14855
14856 var fill = getFillColor(element, defaultFillColor),
14857 stroke = getStrokeColor(element, defaultStrokeColor);
14858
14859 var pathData = createPathFromConnection(element);
14860
14861 var attrs = {
14862 markerEnd: marker('messageflow-end', fill, stroke),
14863 markerStart: marker('messageflow-start', fill, stroke),
14864 strokeDasharray: '10, 12',
14865 strokeLinecap: 'round',
14866 strokeLinejoin: 'round',
14867 strokeWidth: '1.5px',
14868 stroke: getStrokeColor(element, defaultStrokeColor)
14869 };
14870
14871 var path = drawPath(parentGfx, pathData, attrs);
14872
14873 if (semantic.messageRef) {
14874 var midPoint = path.getPointAtLength(path.getTotalLength() / 2);
14875
14876 var markerPathData = pathMap.getScaledPath('MESSAGE_FLOW_MARKER', {
14877 abspos: {
14878 x: midPoint.x,
14879 y: midPoint.y
14880 }
14881 });
14882
14883 var messageAttrs = { strokeWidth: 1 };
14884
14885 if (di.messageVisibleKind === 'initiating') {
14886 messageAttrs.fill = 'white';
14887 messageAttrs.stroke = 'black';
14888 } else {
14889 messageAttrs.fill = '#888';
14890 messageAttrs.stroke = 'white';
14891 }
14892
14893 drawPath(parentGfx, markerPathData, messageAttrs);
14894 }
14895
14896 return path;
14897 },
14898 'bpmn:DataObject': function(parentGfx, element) {
14899 var pathData = pathMap.getScaledPath('DATA_OBJECT_PATH', {
14900 xScaleFactor: 1,
14901 yScaleFactor: 1,
14902 containerWidth: element.width,
14903 containerHeight: element.height,
14904 position: {
14905 mx: 0.474,
14906 my: 0.296
14907 }
14908 });
14909
14910 var elementObject = drawPath(parentGfx, pathData, {
14911 fill: getFillColor(element, defaultFillColor),
14912 fillOpacity: DEFAULT_FILL_OPACITY,
14913 stroke: getStrokeColor(element, defaultStrokeColor)
14914 });
14915
14916 var semantic = getSemantic(element);
14917
14918 if (isCollection(semantic)) {
14919 renderDataItemCollection(parentGfx, element);
14920 }
14921
14922 return elementObject;
14923 },
14924 'bpmn:DataObjectReference': as('bpmn:DataObject'),
14925 'bpmn:DataInput': function(parentGfx, element) {
14926
14927 var arrowPathData = pathMap.getRawPath('DATA_ARROW');
14928
14929 // page
14930 var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
14931
14932 /* input arrow path */ drawPath(parentGfx, arrowPathData, { strokeWidth: 1 });
14933
14934 return elementObject;
14935 },
14936 'bpmn:DataOutput': function(parentGfx, element) {
14937 var arrowPathData = pathMap.getRawPath('DATA_ARROW');
14938
14939 // page
14940 var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
14941
14942 /* output arrow path */ drawPath(parentGfx, arrowPathData, {
14943 strokeWidth: 1,
14944 fill: 'black'
14945 });
14946
14947 return elementObject;
14948 },
14949 'bpmn:DataStoreReference': function(parentGfx, element) {
14950 var DATA_STORE_PATH = pathMap.getScaledPath('DATA_STORE', {
14951 xScaleFactor: 1,
14952 yScaleFactor: 1,
14953 containerWidth: element.width,
14954 containerHeight: element.height,
14955 position: {
14956 mx: 0,
14957 my: 0.133
14958 }
14959 });
14960
14961 var elementStore = drawPath(parentGfx, DATA_STORE_PATH, {
14962 strokeWidth: 2,
14963 fill: getFillColor(element, defaultFillColor),
14964 fillOpacity: DEFAULT_FILL_OPACITY,
14965 stroke: getStrokeColor(element, defaultStrokeColor)
14966 });
14967
14968 return elementStore;
14969 },
14970 'bpmn:BoundaryEvent': function(parentGfx, element) {
14971
14972 var semantic = getSemantic(element),
14973 cancel = semantic.cancelActivity;
14974
14975 var attrs = {
14976 strokeWidth: 1,
14977 fill: getFillColor(element, defaultFillColor),
14978 stroke: getStrokeColor(element, defaultStrokeColor)
14979 };
14980
14981 if (!cancel) {
14982 attrs.strokeDasharray = '6';
14983 attrs.strokeLinecap = 'round';
14984 }
14985
14986 // apply fillOpacity
14987 var outerAttrs = assign({}, attrs, {
14988 fillOpacity: 1
14989 });
14990
14991 // apply no-fill
14992 var innerAttrs = assign({}, attrs, {
14993 fill: 'none'
14994 });
14995
14996 var outer = renderer('bpmn:Event')(parentGfx, element, outerAttrs);
14997
14998 /* inner path */ drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, innerAttrs);
14999
15000 renderEventContent(element, parentGfx);
15001
15002 return outer;
15003 },
15004 'bpmn:Group': function(parentGfx, element) {
15005
15006 var group = drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, {
15007 strokeWidth: 1,
15008 strokeDasharray: '8,3,1,3',
15009 fill: 'none',
15010 pointerEvents: 'none'
15011 });
15012
15013 return group;
15014 },
15015 'label': function(parentGfx, element) {
15016 return renderExternalLabel(parentGfx, element);
15017 },
15018 'bpmn:TextAnnotation': function(parentGfx, element) {
15019 var style = {
15020 'fill': 'none',
15021 'stroke': 'none'
15022 };
15023
15024 var textElement = drawRect(parentGfx, element.width, element.height, 0, 0, style);
15025
15026 var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', {
15027 xScaleFactor: 1,
15028 yScaleFactor: 1,
15029 containerWidth: element.width,
15030 containerHeight: element.height,
15031 position: {
15032 mx: 0.0,
15033 my: 0.0
15034 }
15035 });
15036
15037 drawPath(parentGfx, textPathData, {
15038 stroke: getStrokeColor(element, defaultStrokeColor)
15039 });
15040
15041 var text = getSemantic(element).text || '';
15042 renderLabel(parentGfx, text, {
15043 box: element,
15044 align: 'left-top',
15045 padding: 5,
15046 style: {
15047 fill: getStrokeColor(element, defaultStrokeColor)
15048 }
15049 });
15050
15051 return textElement;
15052 },
15053 'ParticipantMultiplicityMarker': function(parentGfx, element) {
15054 var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
15055 xScaleFactor: 1,
15056 yScaleFactor: 1,
15057 containerWidth: element.width,
15058 containerHeight: element.height,
15059 position: {
15060 mx: ((element.width / 2) / element.width),
15061 my: (element.height - 15) / element.height
15062 }
15063 });
15064
15065 drawMarker('participant-multiplicity', parentGfx, markerPath, {
15066 strokeWidth: 1,
15067 fill: getFillColor(element, defaultFillColor),
15068 stroke: getStrokeColor(element, defaultStrokeColor)
15069 });
15070 },
15071 'SubProcessMarker': function(parentGfx, element) {
15072 var markerRect = drawRect(parentGfx, 14, 14, 0, {
15073 strokeWidth: 1,
15074 fill: getFillColor(element, defaultFillColor),
15075 stroke: getStrokeColor(element, defaultStrokeColor)
15076 });
15077
15078 // Process marker is placed in the middle of the box
15079 // therefore fixed values can be used here
15080 translate(markerRect, element.width / 2 - 7.5, element.height - 20);
15081
15082 var markerPath = pathMap.getScaledPath('MARKER_SUB_PROCESS', {
15083 xScaleFactor: 1.5,
15084 yScaleFactor: 1.5,
15085 containerWidth: element.width,
15086 containerHeight: element.height,
15087 position: {
15088 mx: (element.width / 2 - 7.5) / element.width,
15089 my: (element.height - 20) / element.height
15090 }
15091 });
15092
15093 drawMarker('sub-process', parentGfx, markerPath, {
15094 fill: getFillColor(element, defaultFillColor),
15095 stroke: getStrokeColor(element, defaultStrokeColor)
15096 });
15097 },
15098 'ParallelMarker': function(parentGfx, element, position) {
15099 var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
15100 xScaleFactor: 1,
15101 yScaleFactor: 1,
15102 containerWidth: element.width,
15103 containerHeight: element.height,
15104 position: {
15105 mx: ((element.width / 2 + position.parallel) / element.width),
15106 my: (element.height - 20) / element.height
15107 }
15108 });
15109
15110 drawMarker('parallel', parentGfx, markerPath, {
15111 fill: getFillColor(element, defaultFillColor),
15112 stroke: getStrokeColor(element, defaultStrokeColor)
15113 });
15114 },
15115 'SequentialMarker': function(parentGfx, element, position) {
15116 var markerPath = pathMap.getScaledPath('MARKER_SEQUENTIAL', {
15117 xScaleFactor: 1,
15118 yScaleFactor: 1,
15119 containerWidth: element.width,
15120 containerHeight: element.height,
15121 position: {
15122 mx: ((element.width / 2 + position.seq) / element.width),
15123 my: (element.height - 19) / element.height
15124 }
15125 });
15126
15127 drawMarker('sequential', parentGfx, markerPath, {
15128 fill: getFillColor(element, defaultFillColor),
15129 stroke: getStrokeColor(element, defaultStrokeColor)
15130 });
15131 },
15132 'CompensationMarker': function(parentGfx, element, position) {
15133 var markerMath = pathMap.getScaledPath('MARKER_COMPENSATION', {
15134 xScaleFactor: 1,
15135 yScaleFactor: 1,
15136 containerWidth: element.width,
15137 containerHeight: element.height,
15138 position: {
15139 mx: ((element.width / 2 + position.compensation) / element.width),
15140 my: (element.height - 13) / element.height
15141 }
15142 });
15143
15144 drawMarker('compensation', parentGfx, markerMath, {
15145 strokeWidth: 1,
15146 fill: getFillColor(element, defaultFillColor),
15147 stroke: getStrokeColor(element, defaultStrokeColor)
15148 });
15149 },
15150 'LoopMarker': function(parentGfx, element, position) {
15151 var markerPath = pathMap.getScaledPath('MARKER_LOOP', {
15152 xScaleFactor: 1,
15153 yScaleFactor: 1,
15154 containerWidth: element.width,
15155 containerHeight: element.height,
15156 position: {
15157 mx: ((element.width / 2 + position.loop) / element.width),
15158 my: (element.height - 7) / element.height
15159 }
15160 });
15161
15162 drawMarker('loop', parentGfx, markerPath, {
15163 strokeWidth: 1,
15164 fill: getFillColor(element, defaultFillColor),
15165 stroke: getStrokeColor(element, defaultStrokeColor),
15166 strokeLinecap: 'round',
15167 strokeMiterlimit: 0.5
15168 });
15169 },
15170 'AdhocMarker': function(parentGfx, element, position) {
15171 var markerPath = pathMap.getScaledPath('MARKER_ADHOC', {
15172 xScaleFactor: 1,
15173 yScaleFactor: 1,
15174 containerWidth: element.width,
15175 containerHeight: element.height,
15176 position: {
15177 mx: ((element.width / 2 + position.adhoc) / element.width),
15178 my: (element.height - 15) / element.height
15179 }
15180 });
15181
15182 drawMarker('adhoc', parentGfx, markerPath, {
15183 strokeWidth: 1,
15184 fill: getStrokeColor(element, defaultStrokeColor),
15185 stroke: getStrokeColor(element, defaultStrokeColor)
15186 });
15187 }
15188 };
15189
15190 function attachTaskMarkers(parentGfx, element, taskMarkers) {
15191 var obj = getSemantic(element);
15192
15193 var subprocess = taskMarkers && taskMarkers.indexOf('SubProcessMarker') !== -1;
15194 var position;
15195
15196 if (subprocess) {
15197 position = {
15198 seq: -21,
15199 parallel: -22,
15200 compensation: -42,
15201 loop: -18,
15202 adhoc: 10
15203 };
15204 } else {
15205 position = {
15206 seq: -3,
15207 parallel: -6,
15208 compensation: -27,
15209 loop: 0,
15210 adhoc: 10
15211 };
15212 }
15213
15214 forEach(taskMarkers, function(marker) {
15215 renderer(marker)(parentGfx, element, position);
15216 });
15217
15218 if (obj.isForCompensation) {
15219 renderer('CompensationMarker')(parentGfx, element, position);
15220 }
15221
15222 if (obj.$type === 'bpmn:AdHocSubProcess') {
15223 renderer('AdhocMarker')(parentGfx, element, position);
15224 }
15225
15226 var loopCharacteristics = obj.loopCharacteristics,
15227 isSequential = loopCharacteristics && loopCharacteristics.isSequential;
15228
15229 if (loopCharacteristics) {
15230
15231 if (isSequential === undefined) {
15232 renderer('LoopMarker')(parentGfx, element, position);
15233 }
15234
15235 if (isSequential === false) {
15236 renderer('ParallelMarker')(parentGfx, element, position);
15237 }
15238
15239 if (isSequential === true) {
15240 renderer('SequentialMarker')(parentGfx, element, position);
15241 }
15242 }
15243 }
15244
15245 function renderDataItemCollection(parentGfx, element) {
15246
15247 var yPosition = (element.height - 16) / element.height;
15248
15249 var pathData = pathMap.getScaledPath('DATA_OBJECT_COLLECTION_PATH', {
15250 xScaleFactor: 1,
15251 yScaleFactor: 1,
15252 containerWidth: element.width,
15253 containerHeight: element.height,
15254 position: {
15255 mx: 0.451,
15256 my: yPosition
15257 }
15258 });
15259
15260 /* collection path */ drawPath(parentGfx, pathData, {
15261 strokeWidth: 2
15262 });
15263 }
15264
15265
15266 // extension API, use at your own risk
15267 this._drawPath = drawPath;
15268
15269 }
15270
15271
15272 inherits_browser(BpmnRenderer, BaseRenderer);
15273
15274 BpmnRenderer.$inject = [
15275 'config.bpmnRenderer',
15276 'eventBus',
15277 'styles',
15278 'pathMap',
15279 'canvas',
15280 'textRenderer'
15281 ];
15282
15283
15284 BpmnRenderer.prototype.canRender = function(element) {
15285 return is$1(element, 'bpmn:BaseElement');
15286 };
15287
15288 BpmnRenderer.prototype.drawShape = function(parentGfx, element) {
15289 var type = element.type;
15290 var h = this.handlers[type];
15291
15292 /* jshint -W040 */
15293 return h(parentGfx, element);
15294 };
15295
15296 BpmnRenderer.prototype.drawConnection = function(parentGfx, element) {
15297 var type = element.type;
15298 var h = this.handlers[type];
15299
15300 /* jshint -W040 */
15301 return h(parentGfx, element);
15302 };
15303
15304 BpmnRenderer.prototype.getShapePath = function(element) {
15305
15306 if (is$1(element, 'bpmn:Event')) {
15307 return getCirclePath(element);
15308 }
15309
15310 if (is$1(element, 'bpmn:Activity')) {
15311 return getRoundRectPath(element, TASK_BORDER_RADIUS);
15312 }
15313
15314 if (is$1(element, 'bpmn:Gateway')) {
15315 return getDiamondPath(element);
15316 }
15317
15318 return getRectPath(element);
15319 };
15320
15321 var DEFAULT_BOX_PADDING = 0;
15322
15323 var DEFAULT_LABEL_SIZE = {
15324 width: 150,
15325 height: 50
15326 };
15327
15328
15329 function parseAlign(align) {
15330
15331 var parts = align.split('-');
15332
15333 return {
15334 horizontal: parts[0] || 'center',
15335 vertical: parts[1] || 'top'
15336 };
15337 }
15338
15339 function parsePadding(padding) {
15340
15341 if (isObject(padding)) {
15342 return assign({ top: 0, left: 0, right: 0, bottom: 0 }, padding);
15343 } else {
15344 return {
15345 top: padding,
15346 left: padding,
15347 right: padding,
15348 bottom: padding
15349 };
15350 }
15351 }
15352
15353 function getTextBBox(text, fakeText) {
15354
15355 fakeText.textContent = text;
15356
15357 var textBBox;
15358
15359 try {
15360 var bbox,
15361 emptyLine = text === '';
15362
15363 // add dummy text, when line is empty to
15364 // determine correct height
15365 fakeText.textContent = emptyLine ? 'dummy' : text;
15366
15367 textBBox = fakeText.getBBox();
15368
15369 // take text rendering related horizontal
15370 // padding into account
15371 bbox = {
15372 width: textBBox.width + textBBox.x * 2,
15373 height: textBBox.height
15374 };
15375
15376 if (emptyLine) {
15377
15378 // correct width
15379 bbox.width = 0;
15380 }
15381
15382 return bbox;
15383 } catch (e) {
15384 return { width: 0, height: 0 };
15385 }
15386 }
15387
15388
15389 /**
15390 * Layout the next line and return the layouted element.
15391 *
15392 * Alters the lines passed.
15393 *
15394 * @param {Array<String>} lines
15395 * @return {Object} the line descriptor, an object { width, height, text }
15396 */
15397 function layoutNext(lines, maxWidth, fakeText) {
15398
15399 var originalLine = lines.shift(),
15400 fitLine = originalLine;
15401
15402 var textBBox;
15403
15404 for (;;) {
15405 textBBox = getTextBBox(fitLine, fakeText);
15406
15407 textBBox.width = fitLine ? textBBox.width : 0;
15408
15409 // try to fit
15410 if (fitLine === ' ' || fitLine === '' || textBBox.width < Math.round(maxWidth) || fitLine.length < 2) {
15411 return fit(lines, fitLine, originalLine, textBBox);
15412 }
15413
15414 fitLine = shortenLine(fitLine, textBBox.width, maxWidth);
15415 }
15416 }
15417
15418 function fit(lines, fitLine, originalLine, textBBox) {
15419 if (fitLine.length < originalLine.length) {
15420 var remainder = originalLine.slice(fitLine.length).trim();
15421
15422 lines.unshift(remainder);
15423 }
15424
15425 return {
15426 width: textBBox.width,
15427 height: textBBox.height,
15428 text: fitLine
15429 };
15430 }
15431
15432
15433 /**
15434 * Shortens a line based on spacing and hyphens.
15435 * Returns the shortened result on success.
15436 *
15437 * @param {String} line
15438 * @param {Number} maxLength the maximum characters of the string
15439 * @return {String} the shortened string
15440 */
15441 function semanticShorten(line, maxLength) {
15442 var parts = line.split(/(\s|-)/g),
15443 part,
15444 shortenedParts = [],
15445 length = 0;
15446
15447 // try to shorten via spaces + hyphens
15448 if (parts.length > 1) {
15449 while ((part = parts.shift())) {
15450 if (part.length + length < maxLength) {
15451 shortenedParts.push(part);
15452 length += part.length;
15453 } else {
15454
15455 // remove previous part, too if hyphen does not fit anymore
15456 if (part === '-') {
15457 shortenedParts.pop();
15458 }
15459
15460 break;
15461 }
15462 }
15463 }
15464
15465 return shortenedParts.join('');
15466 }
15467
15468
15469 function shortenLine(line, width, maxWidth) {
15470 var length = Math.max(line.length * (maxWidth / width), 1);
15471
15472 // try to shorten semantically (i.e. based on spaces and hyphens)
15473 var shortenedLine = semanticShorten(line, length);
15474
15475 if (!shortenedLine) {
15476
15477 // force shorten by cutting the long word
15478 shortenedLine = line.slice(0, Math.max(Math.round(length - 1), 1));
15479 }
15480
15481 return shortenedLine;
15482 }
15483
15484
15485 function getHelperSvg() {
15486 var helperSvg = document.getElementById('helper-svg');
15487
15488 if (!helperSvg) {
15489 helperSvg = create('svg');
15490
15491 attr$1(helperSvg, {
15492 id: 'helper-svg',
15493 width: 0,
15494 height: 0,
15495 style: 'visibility: hidden; position: fixed'
15496 });
15497
15498 document.body.appendChild(helperSvg);
15499 }
15500
15501 return helperSvg;
15502 }
15503
15504
15505 /**
15506 * Creates a new label utility
15507 *
15508 * @param {Object} config
15509 * @param {Dimensions} config.size
15510 * @param {Number} config.padding
15511 * @param {Object} config.style
15512 * @param {String} config.align
15513 */
15514 function Text(config) {
15515
15516 this._config = assign({}, {
15517 size: DEFAULT_LABEL_SIZE,
15518 padding: DEFAULT_BOX_PADDING,
15519 style: {},
15520 align: 'center-top'
15521 }, config || {});
15522 }
15523
15524 /**
15525 * Returns the layouted text as an SVG element.
15526 *
15527 * @param {String} text
15528 * @param {Object} options
15529 *
15530 * @return {SVGElement}
15531 */
15532 Text.prototype.createText = function(text, options) {
15533 return this.layoutText(text, options).element;
15534 };
15535
15536 /**
15537 * Returns a labels layouted dimensions.
15538 *
15539 * @param {String} text to layout
15540 * @param {Object} options
15541 *
15542 * @return {Dimensions}
15543 */
15544 Text.prototype.getDimensions = function(text, options) {
15545 return this.layoutText(text, options).dimensions;
15546 };
15547
15548 /**
15549 * Creates and returns a label and its bounding box.
15550 *
15551 * @method Text#createText
15552 *
15553 * @param {String} text the text to render on the label
15554 * @param {Object} options
15555 * @param {String} options.align how to align in the bounding box.
15556 * Any of { 'center-middle', 'center-top' },
15557 * defaults to 'center-top'.
15558 * @param {String} options.style style to be applied to the text
15559 * @param {boolean} options.fitBox indicates if box will be recalculated to
15560 * fit text
15561 *
15562 * @return {Object} { element, dimensions }
15563 */
15564 Text.prototype.layoutText = function(text, options) {
15565 var box = assign({}, this._config.size, options.box),
15566 style = assign({}, this._config.style, options.style),
15567 align = parseAlign(options.align || this._config.align),
15568 padding = parsePadding(options.padding !== undefined ? options.padding : this._config.padding),
15569 fitBox = options.fitBox || false;
15570
15571 var lineHeight = getLineHeight(style);
15572
15573 var lines = text.split(/\r?\n/g),
15574 layouted = [];
15575
15576 var maxWidth = box.width - padding.left - padding.right;
15577
15578 // ensure correct rendering by attaching helper text node to invisible SVG
15579 var helperText = create('text');
15580 attr$1(helperText, { x: 0, y: 0 });
15581 attr$1(helperText, style);
15582
15583 var helperSvg = getHelperSvg();
15584
15585 append(helperSvg, helperText);
15586
15587 while (lines.length) {
15588 layouted.push(layoutNext(lines, maxWidth, helperText));
15589 }
15590
15591 if (align.vertical === 'middle') {
15592 padding.top = padding.bottom = 0;
15593 }
15594
15595 var totalHeight = reduce(layouted, function(sum, line, idx) {
15596 return sum + (lineHeight || line.height);
15597 }, 0) + padding.top + padding.bottom;
15598
15599 var maxLineWidth = reduce(layouted, function(sum, line, idx) {
15600 return line.width > sum ? line.width : sum;
15601 }, 0);
15602
15603 // the y position of the next line
15604 var y = padding.top;
15605
15606 if (align.vertical === 'middle') {
15607 y += (box.height - totalHeight) / 2;
15608 }
15609
15610 // magic number initial offset
15611 y -= (lineHeight || layouted[0].height) / 4;
15612
15613
15614 var textElement = create('text');
15615
15616 attr$1(textElement, style);
15617
15618 // layout each line taking into account that parent
15619 // shape might resize to fit text size
15620 forEach(layouted, function(line) {
15621
15622 var x;
15623
15624 y += (lineHeight || line.height);
15625
15626 switch (align.horizontal) {
15627 case 'left':
15628 x = padding.left;
15629 break;
15630
15631 case 'right':
15632 x = ((fitBox ? maxLineWidth : maxWidth)
15633 - padding.right - line.width);
15634 break;
15635
15636 default:
15637
15638 // aka center
15639 x = Math.max((((fitBox ? maxLineWidth : maxWidth)
15640 - line.width) / 2 + padding.left), 0);
15641 }
15642
15643 var tspan = create('tspan');
15644 attr$1(tspan, { x: x, y: y });
15645
15646 tspan.textContent = line.text;
15647
15648 append(textElement, tspan);
15649 });
15650
15651 remove$1(helperText);
15652
15653 var dimensions = {
15654 width: maxLineWidth,
15655 height: totalHeight
15656 };
15657
15658 return {
15659 dimensions: dimensions,
15660 element: textElement
15661 };
15662 };
15663
15664
15665 function getLineHeight(style) {
15666 if ('fontSize' in style && 'lineHeight' in style) {
15667 return style.lineHeight * parseInt(style.fontSize, 10);
15668 }
15669 }
15670
15671 var DEFAULT_FONT_SIZE = 12;
15672 var LINE_HEIGHT_RATIO = 1.2;
15673
15674 var MIN_TEXT_ANNOTATION_HEIGHT = 30;
15675
15676
15677 function TextRenderer(config) {
15678
15679 var defaultStyle = assign({
15680 fontFamily: 'Arial, sans-serif',
15681 fontSize: DEFAULT_FONT_SIZE,
15682 fontWeight: 'normal',
15683 lineHeight: LINE_HEIGHT_RATIO
15684 }, config && config.defaultStyle || {});
15685
15686 var fontSize = parseInt(defaultStyle.fontSize, 10) - 1;
15687
15688 var externalStyle = assign({}, defaultStyle, {
15689 fontSize: fontSize
15690 }, config && config.externalStyle || {});
15691
15692 var textUtil = new Text({
15693 style: defaultStyle
15694 });
15695
15696 /**
15697 * Get the new bounds of an externally rendered,
15698 * layouted label.
15699 *
15700 * @param {Bounds} bounds
15701 * @param {String} text
15702 *
15703 * @return {Bounds}
15704 */
15705 this.getExternalLabelBounds = function(bounds, text) {
15706
15707 var layoutedDimensions = textUtil.getDimensions(text, {
15708 box: {
15709 width: 90,
15710 height: 30,
15711 x: bounds.width / 2 + bounds.x,
15712 y: bounds.height / 2 + bounds.y
15713 },
15714 style: externalStyle
15715 });
15716
15717 // resize label shape to fit label text
15718 return {
15719 x: Math.round(bounds.x + bounds.width / 2 - layoutedDimensions.width / 2),
15720 y: Math.round(bounds.y),
15721 width: Math.ceil(layoutedDimensions.width),
15722 height: Math.ceil(layoutedDimensions.height)
15723 };
15724
15725 };
15726
15727 /**
15728 * Get the new bounds of text annotation.
15729 *
15730 * @param {Bounds} bounds
15731 * @param {String} text
15732 *
15733 * @return {Bounds}
15734 */
15735 this.getTextAnnotationBounds = function(bounds, text) {
15736
15737 var layoutedDimensions = textUtil.getDimensions(text, {
15738 box: bounds,
15739 style: defaultStyle,
15740 align: 'left-top',
15741 padding: 5
15742 });
15743
15744 return {
15745 x: bounds.x,
15746 y: bounds.y,
15747 width: bounds.width,
15748 height: Math.max(MIN_TEXT_ANNOTATION_HEIGHT, Math.round(layoutedDimensions.height))
15749 };
15750 };
15751
15752 /**
15753 * Create a layouted text element.
15754 *
15755 * @param {String} text
15756 * @param {Object} [options]
15757 *
15758 * @return {SVGElement} rendered text
15759 */
15760 this.createText = function(text, options) {
15761 return textUtil.createText(text, options || {});
15762 };
15763
15764 /**
15765 * Get default text style.
15766 */
15767 this.getDefaultStyle = function() {
15768 return defaultStyle;
15769 };
15770
15771 /**
15772 * Get the external text style.
15773 */
15774 this.getExternalStyle = function() {
15775 return externalStyle;
15776 };
15777
15778 }
15779
15780 TextRenderer.$inject = [
15781 'config.textRenderer'
15782 ];
15783
15784 /**
15785 * Map containing SVG paths needed by BpmnRenderer.
15786 */
15787
15788 function PathMap() {
15789
15790 /**
15791 * Contains a map of path elements
15792 *
15793 * <h1>Path definition</h1>
15794 * A parameterized path is defined like this:
15795 * <pre>
15796 * 'GATEWAY_PARALLEL': {
15797 * d: 'm {mx},{my} {e.x0},0 0,{e.x1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
15798 '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
15799 * height: 17.5,
15800 * width: 17.5,
15801 * heightElements: [2.5, 7.5],
15802 * widthElements: [2.5, 7.5]
15803 * }
15804 * </pre>
15805 * <p>It's important to specify a correct <b>height and width</b> for the path as the scaling
15806 * is based on the ratio between the specified height and width in this object and the
15807 * height and width that is set as scale target (Note x,y coordinates will be scaled with
15808 * individual ratios).</p>
15809 * <p>The '<b>heightElements</b>' and '<b>widthElements</b>' array must contain the values that will be scaled.
15810 * The scaling is based on the computed ratios.
15811 * Coordinates on the y axis should be in the <b>heightElement</b>'s array, they will be scaled using
15812 * the computed ratio coefficient.
15813 * In the parameterized path the scaled values can be accessed through the 'e' object in {} brackets.
15814 * <ul>
15815 * <li>The values for the y axis can be accessed in the path string using {e.y0}, {e.y1}, ....</li>
15816 * <li>The values for the x axis can be accessed in the path string using {e.x0}, {e.x1}, ....</li>
15817 * </ul>
15818 * The numbers x0, x1 respectively y0, y1, ... map to the corresponding array index.
15819 * </p>
15820 */
15821 this.pathMap = {
15822 'EVENT_MESSAGE': {
15823 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}',
15824 height: 36,
15825 width: 36,
15826 heightElements: [6, 14],
15827 widthElements: [10.5, 21]
15828 },
15829 'EVENT_SIGNAL': {
15830 d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x1},0 Z',
15831 height: 36,
15832 width: 36,
15833 heightElements: [18],
15834 widthElements: [10, 20]
15835 },
15836 'EVENT_ESCALATION': {
15837 d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x0},-{e.y1} l -{e.x0},{e.y1} Z',
15838 height: 36,
15839 width: 36,
15840 heightElements: [20, 7],
15841 widthElements: [8]
15842 },
15843 'EVENT_CONDITIONAL': {
15844 d: 'M {e.x0},{e.y0} l {e.x1},0 l 0,{e.y2} l -{e.x1},0 Z ' +
15845 'M {e.x2},{e.y3} l {e.x0},0 ' +
15846 'M {e.x2},{e.y4} l {e.x0},0 ' +
15847 'M {e.x2},{e.y5} l {e.x0},0 ' +
15848 'M {e.x2},{e.y6} l {e.x0},0 ' +
15849 'M {e.x2},{e.y7} l {e.x0},0 ' +
15850 'M {e.x2},{e.y8} l {e.x0},0 ',
15851 height: 36,
15852 width: 36,
15853 heightElements: [8.5, 14.5, 18, 11.5, 14.5, 17.5, 20.5, 23.5, 26.5],
15854 widthElements: [10.5, 14.5, 12.5]
15855 },
15856 'EVENT_LINK': {
15857 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',
15858 height: 36,
15859 width: 36,
15860 heightElements: [4.4375, 6.75, 7.8125],
15861 widthElements: [9.84375, 13.5]
15862 },
15863 'EVENT_ERROR': {
15864 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',
15865 height: 36,
15866 width: 36,
15867 heightElements: [0.023, 8.737, 8.151, 16.564, 10.591, 8.714],
15868 widthElements: [0.085, 6.672, 6.97, 4.273, 5.337, 6.636]
15869 },
15870 'EVENT_CANCEL_45': {
15871 d: 'm {mx},{my} -{e.x1},0 0,{e.x0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
15872 '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
15873 height: 36,
15874 width: 36,
15875 heightElements: [4.75, 8.5],
15876 widthElements: [4.75, 8.5]
15877 },
15878 'EVENT_COMPENSATION': {
15879 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',
15880 height: 36,
15881 width: 36,
15882 heightElements: [6.5, 13, 0.4, 6.1],
15883 widthElements: [9, 9.3, 8.7]
15884 },
15885 'EVENT_TIMER_WH': {
15886 d: 'M {mx},{my} l {e.x0},-{e.y0} m -{e.x0},{e.y0} l {e.x1},{e.y1} ',
15887 height: 36,
15888 width: 36,
15889 heightElements: [10, 2],
15890 widthElements: [3, 7]
15891 },
15892 'EVENT_TIMER_LINE': {
15893 d: 'M {mx},{my} ' +
15894 'm {e.x0},{e.y0} l -{e.x1},{e.y1} ',
15895 height: 36,
15896 width: 36,
15897 heightElements: [10, 3],
15898 widthElements: [0, 0]
15899 },
15900 'EVENT_MULTIPLE': {
15901 d:'m {mx},{my} {e.x1},-{e.y0} {e.x1},{e.y0} -{e.x0},{e.y1} -{e.x2},0 z',
15902 height: 36,
15903 width: 36,
15904 heightElements: [6.28099, 12.56199],
15905 widthElements: [3.1405, 9.42149, 12.56198]
15906 },
15907 'EVENT_PARALLEL_MULTIPLE': {
15908 d:'m {mx},{my} {e.x0},0 0,{e.y1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
15909 '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
15910 height: 36,
15911 width: 36,
15912 heightElements: [2.56228, 7.68683],
15913 widthElements: [2.56228, 7.68683]
15914 },
15915 'GATEWAY_EXCLUSIVE': {
15916 d:'m {mx},{my} {e.x0},{e.y0} {e.x1},{e.y0} {e.x2},0 {e.x4},{e.y2} ' +
15917 '{e.x4},{e.y1} {e.x2},0 {e.x1},{e.y3} {e.x0},{e.y3} ' +
15918 '{e.x3},0 {e.x5},{e.y1} {e.x5},{e.y2} {e.x3},0 z',
15919 height: 17.5,
15920 width: 17.5,
15921 heightElements: [8.5, 6.5312, -6.5312, -8.5],
15922 widthElements: [6.5, -6.5, 3, -3, 5, -5]
15923 },
15924 'GATEWAY_PARALLEL': {
15925 d:'m {mx},{my} 0,{e.y1} -{e.x1},0 0,{e.y0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
15926 '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
15927 height: 30,
15928 width: 30,
15929 heightElements: [5, 12.5],
15930 widthElements: [5, 12.5]
15931 },
15932 'GATEWAY_EVENT_BASED': {
15933 d:'m {mx},{my} {e.x0},{e.y0} {e.x0},{e.y1} {e.x1},{e.y2} {e.x2},0 z',
15934 height: 11,
15935 width: 11,
15936 heightElements: [-6, 6, 12, -12],
15937 widthElements: [9, -3, -12]
15938 },
15939 'GATEWAY_COMPLEX': {
15940 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} ' +
15941 '{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} ' +
15942 '{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} ' +
15943 '-{e.x0},{e.y1} 0,-{e.y0} -{e.x3},0 z',
15944 height: 17.125,
15945 width: 17.125,
15946 heightElements: [4.875, 3.4375, 2.125, 3],
15947 widthElements: [3.4375, 2.125, 4.875, 3]
15948 },
15949 'DATA_OBJECT_PATH': {
15950 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',
15951 height: 61,
15952 width: 51,
15953 heightElements: [10, 50, 60],
15954 widthElements: [10, 40, 50, 60]
15955 },
15956 'DATA_OBJECT_COLLECTION_PATH': {
15957 d:'m {mx}, {my} ' +
15958 'm 0 15 l 0 -15 ' +
15959 'm 4 15 l 0 -15 ' +
15960 'm 4 15 l 0 -15 ',
15961 height: 61,
15962 width: 51,
15963 heightElements: [12],
15964 widthElements: [1, 6, 12, 15]
15965 },
15966 'DATA_ARROW': {
15967 d:'m 5,9 9,0 0,-3 5,5 -5,5 0,-3 -9,0 z',
15968 height: 61,
15969 width: 51,
15970 heightElements: [],
15971 widthElements: []
15972 },
15973 'DATA_STORE': {
15974 d:'m {mx},{my} ' +
15975 'l 0,{e.y2} ' +
15976 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' +
15977 'l 0,-{e.y2} ' +
15978 'c -{e.x0},-{e.y1} -{e.x1},-{e.y1} -{e.x2},0' +
15979 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' +
15980 'm -{e.x2},{e.y0}' +
15981 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0' +
15982 'm -{e.x2},{e.y0}' +
15983 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0',
15984 height: 61,
15985 width: 61,
15986 heightElements: [7, 10, 45],
15987 widthElements: [2, 58, 60]
15988 },
15989 'TEXT_ANNOTATION': {
15990 d: 'm {mx}, {my} m 10,0 l -10,0 l 0,{e.y0} l 10,0',
15991 height: 30,
15992 width: 10,
15993 heightElements: [30],
15994 widthElements: [10]
15995 },
15996 'MARKER_SUB_PROCESS': {
15997 d: 'm{mx},{my} m 7,2 l 0,10 m -5,-5 l 10,0',
15998 height: 10,
15999 width: 10,
16000 heightElements: [],
16001 widthElements: []
16002 },
16003 'MARKER_PARALLEL': {
16004 d: 'm{mx},{my} m 3,2 l 0,10 m 3,-10 l 0,10 m 3,-10 l 0,10',
16005 height: 10,
16006 width: 10,
16007 heightElements: [],
16008 widthElements: []
16009 },
16010 'MARKER_SEQUENTIAL': {
16011 d: 'm{mx},{my} m 0,3 l 10,0 m -10,3 l 10,0 m -10,3 l 10,0',
16012 height: 10,
16013 width: 10,
16014 heightElements: [],
16015 widthElements: []
16016 },
16017 'MARKER_COMPENSATION': {
16018 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',
16019 height: 10,
16020 width: 21,
16021 heightElements: [],
16022 widthElements: []
16023 },
16024 'MARKER_LOOP': {
16025 d: 'm {mx},{my} c 3.526979,0 6.386161,-2.829858 6.386161,-6.320661 0,-3.490806 -2.859182,-6.320661 ' +
16026 '-6.386161,-6.320661 -3.526978,0 -6.38616,2.829855 -6.38616,6.320661 0,1.745402 ' +
16027 '0.714797,3.325567 1.870463,4.469381 0.577834,0.571908 1.265885,1.034728 2.029916,1.35457 ' +
16028 'l -0.718163,-3.909793 m 0.718163,3.909793 -3.885211,0.802902',
16029 height: 13.9,
16030 width: 13.7,
16031 heightElements: [],
16032 widthElements: []
16033 },
16034 'MARKER_ADHOC': {
16035 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 ' +
16036 '3.85579,1.15803 5.76082,1.79107 1.06385,0.34139996 2.24454,0.1438 3.18759,-0.43767 0.61743,-0.33642 ' +
16037 '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 ' +
16038 '-3.6918,1.66181996 -1.24459,0.0927 -2.46671,-0.2491 -3.59505,-0.74812 -1.35789,-0.55965 ' +
16039 '-2.75133,-1.33436996 -4.27027,-1.18121996 -1.37741,0.14601 -2.41842,1.13685996 -3.44288,1.96782996 z',
16040 height: 4,
16041 width: 15,
16042 heightElements: [],
16043 widthElements: []
16044 },
16045 'TASK_TYPE_SEND': {
16046 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}',
16047 height: 14,
16048 width: 21,
16049 heightElements: [6, 14],
16050 widthElements: [10.5, 21]
16051 },
16052 'TASK_TYPE_SCRIPT': {
16053 d: 'm {mx},{my} c 9.966553,-6.27276 -8.000926,-7.91932 2.968968,-14.938 l -8.802728,0 ' +
16054 'c -10.969894,7.01868 6.997585,8.66524 -2.968967,14.938 z ' +
16055 'm -7,-12 l 5,0 ' +
16056 'm -4.5,3 l 4.5,0 ' +
16057 'm -3,3 l 5,0' +
16058 'm -4,3 l 5,0',
16059 height: 15,
16060 width: 12.6,
16061 heightElements: [6, 14],
16062 widthElements: [10.5, 21]
16063 },
16064 'TASK_TYPE_USER_1': {
16065 d: 'm {mx},{my} c 0.909,-0.845 1.594,-2.049 1.594,-3.385 0,-2.554 -1.805,-4.62199999 ' +
16066 '-4.357,-4.62199999 -2.55199998,0 -4.28799998,2.06799999 -4.28799998,4.62199999 0,1.348 ' +
16067 '0.974,2.562 1.89599998,3.405 -0.52899998,0.187 -5.669,2.097 -5.794,4.7560005 v 6.718 ' +
16068 'h 17 v -6.718 c 0,-2.2980005 -5.5279996,-4.5950005 -6.0509996,-4.7760005 z' +
16069 'm -8,6 l 0,5.5 m 11,0 l 0,-5'
16070 },
16071 'TASK_TYPE_USER_2': {
16072 d: 'm {mx},{my} m 2.162,1.009 c 0,2.4470005 -2.158,4.4310005 -4.821,4.4310005 ' +
16073 '-2.66499998,0 -4.822,-1.981 -4.822,-4.4310005 '
16074 },
16075 'TASK_TYPE_USER_3': {
16076 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 ' +
16077 '4.124,0.965 -0.098,-0.57 -0.117,-3.79099999 -4.191,-4.13599999 -3.57499998,0.001 ' +
16078 '-4.20799998,3.36699999 -4.20699998,4.34799999 z'
16079 },
16080 'TASK_TYPE_MANUAL': {
16081 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 ' +
16082 '-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 ' +
16083 '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 ' +
16084 '-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 ' +
16085 '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 ' +
16086 '-10.86,-0.003 -11.0829995,-0.003 -0.022,-0.047 -0.045,-0.094 -0.069,-0.139 0.3939995,-0.319 ' +
16087 '2.0409995,-1.626 2.4149995,-2.017 0.469,-0.4870005 0.519,-1.1650005 0.162,-1.6040005 -0.414,-0.511 ' +
16088 '-0.973,-0.5 -1.48,-0.236 -1.4609995,0.764 -6.5999995,3.6430005 -7.7329995,4.2710005 -0.9,0.499 ' +
16089 '-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 ' +
16090 '-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 ' +
16091 '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 ' +
16092 '-5.824,-0.004 -6.04,-0.004 10e-4,-0.084 0.003,-0.586 10e-4,-0.67 z'
16093 },
16094 'TASK_TYPE_INSTANTIATING_SEND': {
16095 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'
16096 },
16097 'TASK_TYPE_SERVICE': {
16098 d: 'm {mx},{my} v -1.71335 c 0.352326,-0.0705 0.703932,-0.17838 1.047628,-0.32133 ' +
16099 '0.344416,-0.14465 0.665822,-0.32133 0.966377,-0.52145 l 1.19431,1.18005 1.567487,-1.57688 ' +
16100 '-1.195028,-1.18014 c 0.403376,-0.61394 0.683079,-1.29908 0.825447,-2.01824 l 1.622133,-0.01 ' +
16101 'v -2.2196 l -1.636514,0.01 c -0.07333,-0.35153 -0.178319,-0.70024 -0.323564,-1.04372 ' +
16102 '-0.145244,-0.34406 -0.321407,-0.6644 -0.522735,-0.96217 l 1.131035,-1.13631 -1.583305,-1.56293 ' +
16103 '-1.129598,1.13589 c -0.614052,-0.40108 -1.302883,-0.68093 -2.022633,-0.82247 l 0.0093,-1.61852 ' +
16104 '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 ' +
16105 '-0.665102,0.32092 -0.9635006,0.52046 l -1.1698628,-1.15823 -1.5667691,1.5792 1.1684265,1.15669 ' +
16106 'c -0.4026573,0.61283 -0.68308,1.29797 -0.8247287,2.01713 l -1.6588041,0.003 v 2.22174 ' +
16107 'l 1.6724648,-0.006 c 0.073327,0.35077 0.1797598,0.70243 0.3242851,1.04472 0.1452428,0.34448 ' +
16108 '0.3214064,0.6644 0.5227339,0.96066 l -1.1993431,1.19723 1.5840256,1.56011 1.1964668,-1.19348 ' +
16109 'c 0.6140517,0.40346 1.3028827,0.68232 2.0233517,0.82331 l 7.19e-4,1.69892 h 2.226848 z ' +
16110 'm 0.221462,-3.9957 c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
16111 '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
16112 '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
16113 },
16114 'TASK_TYPE_SERVICE_FILL': {
16115 d: 'm {mx},{my} c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
16116 '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
16117 '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
16118 },
16119 'TASK_TYPE_BUSINESS_RULE_HEADER': {
16120 d: 'm {mx},{my} 0,4 20,0 0,-4 z'
16121 },
16122 'TASK_TYPE_BUSINESS_RULE_MAIN': {
16123 d: 'm {mx},{my} 0,12 20,0 0,-12 z' +
16124 'm 0,8 l 20,0 ' +
16125 'm -13,-4 l 0,8'
16126 },
16127 'MESSAGE_FLOW_MARKER': {
16128 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'
16129 }
16130 };
16131
16132 this.getRawPath = function getRawPath(pathId) {
16133 return this.pathMap[pathId].d;
16134 };
16135
16136 /**
16137 * Scales the path to the given height and width.
16138 * <h1>Use case</h1>
16139 * <p>Use case is to scale the content of elements (event, gateways) based
16140 * on the element bounding box's size.
16141 * </p>
16142 * <h1>Why not transform</h1>
16143 * <p>Scaling a path with transform() will also scale the stroke and IE does not support
16144 * the option 'non-scaling-stroke' to prevent this.
16145 * Also there are use cases where only some parts of a path should be
16146 * scaled.</p>
16147 *
16148 * @param {String} pathId The ID of the path.
16149 * @param {Object} param <p>
16150 * Example param object scales the path to 60% size of the container (data.width, data.height).
16151 * <pre>
16152 * {
16153 * xScaleFactor: 0.6,
16154 * yScaleFactor:0.6,
16155 * containerWidth: data.width,
16156 * containerHeight: data.height,
16157 * position: {
16158 * mx: 0.46,
16159 * my: 0.2,
16160 * }
16161 * }
16162 * </pre>
16163 * <ul>
16164 * <li>targetpathwidth = xScaleFactor * containerWidth</li>
16165 * <li>targetpathheight = yScaleFactor * containerHeight</li>
16166 * <li>Position is used to set the starting coordinate of the path. M is computed:
16167 * <ul>
16168 * <li>position.x * containerWidth</li>
16169 * <li>position.y * containerHeight</li>
16170 * </ul>
16171 * Center of the container <pre> position: {
16172 * mx: 0.5,
16173 * my: 0.5,
16174 * }</pre>
16175 * Upper left corner of the container
16176 * <pre> position: {
16177 * mx: 0.0,
16178 * my: 0.0,
16179 * }</pre>
16180 * </li>
16181 * </ul>
16182 * </p>
16183 *
16184 */
16185 this.getScaledPath = function getScaledPath(pathId, param) {
16186 var rawPath = this.pathMap[pathId];
16187
16188 // positioning
16189 // compute the start point of the path
16190 var mx, my;
16191
16192 if (param.abspos) {
16193 mx = param.abspos.x;
16194 my = param.abspos.y;
16195 } else {
16196 mx = param.containerWidth * param.position.mx;
16197 my = param.containerHeight * param.position.my;
16198 }
16199
16200 var coordinates = {}; // map for the scaled coordinates
16201 if (param.position) {
16202
16203 // path
16204 var heightRatio = (param.containerHeight / rawPath.height) * param.yScaleFactor;
16205 var widthRatio = (param.containerWidth / rawPath.width) * param.xScaleFactor;
16206
16207
16208 // Apply height ratio
16209 for (var heightIndex = 0; heightIndex < rawPath.heightElements.length; heightIndex++) {
16210 coordinates['y' + heightIndex] = rawPath.heightElements[heightIndex] * heightRatio;
16211 }
16212
16213 // Apply width ratio
16214 for (var widthIndex = 0; widthIndex < rawPath.widthElements.length; widthIndex++) {
16215 coordinates['x' + widthIndex] = rawPath.widthElements[widthIndex] * widthRatio;
16216 }
16217 }
16218
16219 // Apply value to raw path
16220 var path = format(
16221 rawPath.d, {
16222 mx: mx,
16223 my: my,
16224 e: coordinates
16225 }
16226 );
16227 return path;
16228 };
16229 }
16230
16231 // helpers //////////////////////
16232
16233 // copied from https://github.com/adobe-webplatform/Snap.svg/blob/master/src/svg.js
16234 var tokenRegex = /\{([^}]+)\}/g,
16235 objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g; // matches .xxxxx or ["xxxxx"] to run over object properties
16236
16237 function replacer(all, key, obj) {
16238 var res = obj;
16239 key.replace(objNotationRegex, function(all, name, quote, quotedName, isFunc) {
16240 name = name || quotedName;
16241 if (res) {
16242 if (name in res) {
16243 res = res[name];
16244 }
16245 typeof res == 'function' && isFunc && (res = res());
16246 }
16247 });
16248 res = (res == null || res == obj ? all : res) + '';
16249
16250 return res;
16251 }
16252
16253 function format(str, obj) {
16254 return String(str).replace(tokenRegex, function(all, key) {
16255 return replacer(all, key, obj);
16256 });
16257 }
16258
16259 var DrawModule$1 = {
16260 __init__: [ 'bpmnRenderer' ],
16261 bpmnRenderer: [ 'type', BpmnRenderer ],
16262 textRenderer: [ 'type', TextRenderer ],
16263 pathMap: [ 'type', PathMap ]
16264 };
16265
16266 /**
16267 * A simple translation stub to be used for multi-language support
16268 * in diagrams. Can be easily replaced with a more sophisticated
16269 * solution.
16270 *
16271 * @example
16272 *
16273 * // use it inside any diagram component by injecting `translate`.
16274 *
16275 * function MyService(translate) {
16276 * alert(translate('HELLO {you}', { you: 'You!' }));
16277 * }
16278 *
16279 * @param {String} template to interpolate
16280 * @param {Object} [replacements] a map with substitutes
16281 *
16282 * @return {String} the translated string
16283 */
16284 function translate$1(template, replacements) {
16285
16286 replacements = replacements || {};
16287
16288 return template.replace(/{([^}]+)}/g, function(_, key) {
16289 return replacements[key] || '{' + key + '}';
16290 });
16291 }
16292
16293 var TranslateModule = {
16294 translate: [ 'value', translate$1 ]
16295 };
16296
16297 var DEFAULT_LABEL_SIZE$1 = {
16298 width: 90,
16299 height: 20
16300 };
16301
16302 var FLOW_LABEL_INDENT = 15;
16303
16304
16305 /**
16306 * Returns true if the given semantic has an external label
16307 *
16308 * @param {BpmnElement} semantic
16309 * @return {Boolean} true if has label
16310 */
16311 function isLabelExternal(semantic) {
16312 return is$1(semantic, 'bpmn:Event') ||
16313 is$1(semantic, 'bpmn:Gateway') ||
16314 is$1(semantic, 'bpmn:DataStoreReference') ||
16315 is$1(semantic, 'bpmn:DataObjectReference') ||
16316 is$1(semantic, 'bpmn:DataInput') ||
16317 is$1(semantic, 'bpmn:DataOutput') ||
16318 is$1(semantic, 'bpmn:SequenceFlow') ||
16319 is$1(semantic, 'bpmn:MessageFlow') ||
16320 is$1(semantic, 'bpmn:Group');
16321 }
16322
16323 /**
16324 * Get the position for sequence flow labels
16325 *
16326 * @param {Array<Point>} waypoints
16327 * @return {Point} the label position
16328 */
16329 function getFlowLabelPosition(waypoints) {
16330
16331 // get the waypoints mid
16332 var mid = waypoints.length / 2 - 1;
16333
16334 var first = waypoints[Math.floor(mid)];
16335 var second = waypoints[Math.ceil(mid + 0.01)];
16336
16337 // get position
16338 var position = getWaypointsMid(waypoints);
16339
16340 // calculate angle
16341 var angle = Math.atan((second.y - first.y) / (second.x - first.x));
16342
16343 var x = position.x,
16344 y = position.y;
16345
16346 if (Math.abs(angle) < Math.PI / 2) {
16347 y -= FLOW_LABEL_INDENT;
16348 } else {
16349 x += FLOW_LABEL_INDENT;
16350 }
16351
16352 return { x: x, y: y };
16353 }
16354
16355
16356 /**
16357 * Get the middle of a number of waypoints
16358 *
16359 * @param {Array<Point>} waypoints
16360 * @return {Point} the mid point
16361 */
16362 function getWaypointsMid(waypoints) {
16363
16364 var mid = waypoints.length / 2 - 1;
16365
16366 var first = waypoints[Math.floor(mid)];
16367 var second = waypoints[Math.ceil(mid + 0.01)];
16368
16369 return {
16370 x: first.x + (second.x - first.x) / 2,
16371 y: first.y + (second.y - first.y) / 2
16372 };
16373 }
16374
16375
16376 function getExternalLabelMid(element) {
16377
16378 if (element.waypoints) {
16379 return getFlowLabelPosition(element.waypoints);
16380 } else if (is$1(element, 'bpmn:Group')) {
16381 return {
16382 x: element.x + element.width / 2,
16383 y: element.y + DEFAULT_LABEL_SIZE$1.height / 2
16384 };
16385 } else {
16386 return {
16387 x: element.x + element.width / 2,
16388 y: element.y + element.height + DEFAULT_LABEL_SIZE$1.height / 2
16389 };
16390 }
16391 }
16392
16393
16394 /**
16395 * Returns the bounds of an elements label, parsed from the elements DI or
16396 * generated from its bounds.
16397 *
16398 * @param {BpmnElement} semantic
16399 * @param {djs.model.Base} element
16400 */
16401 function getExternalLabelBounds(semantic, element) {
16402
16403 var mid,
16404 size,
16405 bounds,
16406 di = semantic.di,
16407 label = di.label;
16408
16409 if (label && label.bounds) {
16410 bounds = label.bounds;
16411
16412 size = {
16413 width: Math.max(DEFAULT_LABEL_SIZE$1.width, bounds.width),
16414 height: bounds.height
16415 };
16416
16417 mid = {
16418 x: bounds.x + bounds.width / 2,
16419 y: bounds.y + bounds.height / 2
16420 };
16421 } else {
16422
16423 mid = getExternalLabelMid(element);
16424
16425 size = DEFAULT_LABEL_SIZE$1;
16426 }
16427
16428 return assign({
16429 x: mid.x - size.width / 2,
16430 y: mid.y - size.height / 2
16431 }, size);
16432 }
16433
16434 /**
16435 * This file contains portions that got extraced from Snap.svg (licensed Apache-2.0).
16436 *
16437 * @see https://github.com/adobe-webplatform/Snap.svg/blob/master/src/path.js
16438 */
16439
16440 /* eslint no-fallthrough: "off" */
16441
16442 var math = Math,
16443 PI = math.PI;
16444
16445 function roundPoint(point) {
16446
16447 return {
16448 x: Math.round(point.x),
16449 y: Math.round(point.y)
16450 };
16451 }
16452
16453
16454 /**
16455 * Get the mid of the given bounds or point.
16456 *
16457 * @param {Bounds|Point} bounds
16458 *
16459 * @return {Point}
16460 */
16461 function getMid(bounds) {
16462 return roundPoint({
16463 x: bounds.x + (bounds.width || 0) / 2,
16464 y: bounds.y + (bounds.height || 0) / 2
16465 });
16466 }
16467
16468 function elementData(semantic, attrs) {
16469 return assign({
16470 id: semantic.id,
16471 type: semantic.$type,
16472 businessObject: semantic
16473 }, attrs);
16474 }
16475
16476 function getWaypoints(bo, source, target) {
16477
16478 var waypoints = bo.di.waypoint;
16479
16480 if (!waypoints || waypoints.length < 2) {
16481 return [ getMid(source), getMid(target) ];
16482 }
16483
16484 return waypoints.map(function(p) {
16485 return { x: p.x, y: p.y };
16486 });
16487 }
16488
16489 function notYetDrawn(translate, semantic, refSemantic, property) {
16490 return new Error(translate('element {element} referenced by {referenced}#{property} not yet drawn', {
16491 element: elementToString(refSemantic),
16492 referenced: elementToString(semantic),
16493 property: property
16494 }));
16495 }
16496
16497
16498 /**
16499 * An importer that adds bpmn elements to the canvas
16500 *
16501 * @param {EventBus} eventBus
16502 * @param {Canvas} canvas
16503 * @param {ElementFactory} elementFactory
16504 * @param {ElementRegistry} elementRegistry
16505 * @param {Function} translate
16506 * @param {TextRenderer} textRenderer
16507 */
16508 function BpmnImporter(
16509 eventBus, canvas, elementFactory,
16510 elementRegistry, translate, textRenderer) {
16511
16512 this._eventBus = eventBus;
16513 this._canvas = canvas;
16514 this._elementFactory = elementFactory;
16515 this._elementRegistry = elementRegistry;
16516 this._translate = translate;
16517 this._textRenderer = textRenderer;
16518 }
16519
16520 BpmnImporter.$inject = [
16521 'eventBus',
16522 'canvas',
16523 'elementFactory',
16524 'elementRegistry',
16525 'translate',
16526 'textRenderer'
16527 ];
16528
16529
16530 /**
16531 * Add bpmn element (semantic) to the canvas onto the
16532 * specified parent shape.
16533 */
16534 BpmnImporter.prototype.add = function(semantic, parentElement) {
16535
16536 var di = semantic.di,
16537 element,
16538 translate = this._translate,
16539 hidden;
16540
16541 var parentIndex;
16542
16543 // ROOT ELEMENT
16544 // handle the special case that we deal with a
16545 // invisible root element (process or collaboration)
16546 if (is$1(di, 'bpmndi:BPMNPlane')) {
16547
16548 // add a virtual element (not being drawn)
16549 element = this._elementFactory.createRoot(elementData(semantic));
16550
16551 this._canvas.setRootElement(element);
16552 }
16553
16554 // SHAPE
16555 else if (is$1(di, 'bpmndi:BPMNShape')) {
16556
16557 var collapsed = !isExpanded(semantic);
16558 hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
16559
16560 var bounds = semantic.di.bounds;
16561
16562 element = this._elementFactory.createShape(elementData(semantic, {
16563 collapsed: collapsed,
16564 hidden: hidden,
16565 x: Math.round(bounds.x),
16566 y: Math.round(bounds.y),
16567 width: Math.round(bounds.width),
16568 height: Math.round(bounds.height)
16569 }));
16570
16571 if (is$1(semantic, 'bpmn:BoundaryEvent')) {
16572 this._attachBoundary(semantic, element);
16573 }
16574
16575 // insert lanes behind other flow nodes (cf. #727)
16576 if (is$1(semantic, 'bpmn:Lane')) {
16577 parentIndex = 0;
16578 }
16579
16580 if (is$1(semantic, 'bpmn:DataStoreReference')) {
16581
16582 // check wether data store is inside our outside of its semantic parent
16583 if (!isPointInsideBBox(parentElement, getMid(bounds))) {
16584 parentElement = this._canvas.getRootElement();
16585 }
16586 }
16587
16588 this._canvas.addShape(element, parentElement, parentIndex);
16589 }
16590
16591 // CONNECTION
16592 else if (is$1(di, 'bpmndi:BPMNEdge')) {
16593
16594 var source = this._getSource(semantic),
16595 target = this._getTarget(semantic);
16596
16597 hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
16598
16599 element = this._elementFactory.createConnection(elementData(semantic, {
16600 hidden: hidden,
16601 source: source,
16602 target: target,
16603 waypoints: getWaypoints(semantic, source, target)
16604 }));
16605
16606 if (is$1(semantic, 'bpmn:DataAssociation')) {
16607
16608 // render always on top; this ensures DataAssociations
16609 // are rendered correctly across different "hacks" people
16610 // love to model such as cross participant / sub process
16611 // associations
16612 parentElement = null;
16613 }
16614
16615 // insert sequence flows behind other flow nodes (cf. #727)
16616 if (is$1(semantic, 'bpmn:SequenceFlow')) {
16617 parentIndex = 0;
16618 }
16619
16620 this._canvas.addConnection(element, parentElement, parentIndex);
16621 } else {
16622 throw new Error(translate('unknown di {di} for element {semantic}', {
16623 di: elementToString(di),
16624 semantic: elementToString(semantic)
16625 }));
16626 }
16627
16628 // (optional) LABEL
16629 if (isLabelExternal(semantic) && getLabel(element)) {
16630 this.addLabel(semantic, element);
16631 }
16632
16633
16634 this._eventBus.fire('bpmnElement.added', { element: element });
16635
16636 return element;
16637 };
16638
16639
16640 /**
16641 * Attach the boundary element to the given host
16642 *
16643 * @param {ModdleElement} boundarySemantic
16644 * @param {djs.model.Base} boundaryElement
16645 */
16646 BpmnImporter.prototype._attachBoundary = function(boundarySemantic, boundaryElement) {
16647 var translate = this._translate;
16648 var hostSemantic = boundarySemantic.attachedToRef;
16649
16650 if (!hostSemantic) {
16651 throw new Error(translate('missing {semantic}#attachedToRef', {
16652 semantic: elementToString(boundarySemantic)
16653 }));
16654 }
16655
16656 var host = this._elementRegistry.get(hostSemantic.id),
16657 attachers = host && host.attachers;
16658
16659 if (!host) {
16660 throw notYetDrawn(translate, boundarySemantic, hostSemantic, 'attachedToRef');
16661 }
16662
16663 // wire element.host <> host.attachers
16664 boundaryElement.host = host;
16665
16666 if (!attachers) {
16667 host.attachers = attachers = [];
16668 }
16669
16670 if (attachers.indexOf(boundaryElement) === -1) {
16671 attachers.push(boundaryElement);
16672 }
16673 };
16674
16675
16676 /**
16677 * add label for an element
16678 */
16679 BpmnImporter.prototype.addLabel = function(semantic, element) {
16680 var bounds,
16681 text,
16682 label;
16683
16684 bounds = getExternalLabelBounds(semantic, element);
16685
16686 text = getLabel(element);
16687
16688 if (text) {
16689
16690 // get corrected bounds from actual layouted text
16691 bounds = this._textRenderer.getExternalLabelBounds(bounds, text);
16692 }
16693
16694 label = this._elementFactory.createLabel(elementData(semantic, {
16695 id: semantic.id + '_label',
16696 labelTarget: element,
16697 type: 'label',
16698 hidden: element.hidden || !getLabel(element),
16699 x: Math.round(bounds.x),
16700 y: Math.round(bounds.y),
16701 width: Math.round(bounds.width),
16702 height: Math.round(bounds.height)
16703 }));
16704
16705 return this._canvas.addShape(label, element.parent);
16706 };
16707
16708 /**
16709 * Return the drawn connection end based on the given side.
16710 *
16711 * @throws {Error} if the end is not yet drawn
16712 */
16713 BpmnImporter.prototype._getEnd = function(semantic, side) {
16714
16715 var element,
16716 refSemantic,
16717 type = semantic.$type,
16718 translate = this._translate;
16719
16720 refSemantic = semantic[side + 'Ref'];
16721
16722 // handle mysterious isMany DataAssociation#sourceRef
16723 if (side === 'source' && type === 'bpmn:DataInputAssociation') {
16724 refSemantic = refSemantic && refSemantic[0];
16725 }
16726
16727 // fix source / target for DataInputAssociation / DataOutputAssociation
16728 if (side === 'source' && type === 'bpmn:DataOutputAssociation' ||
16729 side === 'target' && type === 'bpmn:DataInputAssociation') {
16730
16731 refSemantic = semantic.$parent;
16732 }
16733
16734 element = refSemantic && this._getElement(refSemantic);
16735
16736 if (element) {
16737 return element;
16738 }
16739
16740 if (refSemantic) {
16741 throw notYetDrawn(translate, semantic, refSemantic, side + 'Ref');
16742 } else {
16743 throw new Error(translate('{semantic}#{side} Ref not specified', {
16744 semantic: elementToString(semantic),
16745 side: side
16746 }));
16747 }
16748 };
16749
16750 BpmnImporter.prototype._getSource = function(semantic) {
16751 return this._getEnd(semantic, 'source');
16752 };
16753
16754 BpmnImporter.prototype._getTarget = function(semantic) {
16755 return this._getEnd(semantic, 'target');
16756 };
16757
16758
16759 BpmnImporter.prototype._getElement = function(semantic) {
16760 return this._elementRegistry.get(semantic.id);
16761 };
16762
16763
16764 // helpers ////////////////////
16765
16766 function isPointInsideBBox(bbox, point) {
16767 var x = point.x,
16768 y = point.y;
16769
16770 return x >= bbox.x &&
16771 x <= bbox.x + bbox.width &&
16772 y >= bbox.y &&
16773 y <= bbox.y + bbox.height;
16774 }
16775
16776 var ImportModule = {
16777 __depends__: [
16778 TranslateModule
16779 ],
16780 bpmnImporter: [ 'type', BpmnImporter ]
16781 };
16782
16783 var CoreModule$1 = {
16784 __depends__: [
16785 DrawModule$1,
16786 ImportModule
16787 ]
16788 };
16789
16790 function getOriginal(event) {
16791 return event.originalEvent || event.srcEvent;
16792 }
16793
16794 function isMac() {
16795 return (/mac/i).test(navigator.platform);
16796 }
16797
16798 function isPrimaryButton(event) {
16799
16800 // button === 0 -> left áka primary mouse button
16801 return !(getOriginal(event) || event).button;
16802 }
16803
16804 function hasPrimaryModifier(event) {
16805 var originalEvent = getOriginal(event) || event;
16806
16807 if (!isPrimaryButton(event)) {
16808 return false;
16809 }
16810
16811 // Use alt as primary modifier key for mac OS
16812 if (isMac()) {
16813 return originalEvent.metaKey;
16814 } else {
16815 return originalEvent.ctrlKey;
16816 }
16817 }
16818
16819 function allowAll(e) { return true; }
16820
16821 var LOW_PRIORITY = 500;
16822
16823
16824 /**
16825 * A plugin that provides interaction events for diagram elements.
16826 *
16827 * It emits the following events:
16828 *
16829 * * element.click
16830 * * element.contextmenu
16831 * * element.dblclick
16832 * * element.hover
16833 * * element.mousedown
16834 * * element.mousemove
16835 * * element.mouseup
16836 * * element.out
16837 *
16838 * Each event is a tuple { element, gfx, originalEvent }.
16839 *
16840 * Canceling the event via Event#preventDefault()
16841 * prevents the original DOM operation.
16842 *
16843 * @param {EventBus} eventBus
16844 */
16845 function InteractionEvents(eventBus, elementRegistry, styles) {
16846
16847 var self = this;
16848
16849 /**
16850 * Fire an interaction event.
16851 *
16852 * @param {String} type local event name, e.g. element.click.
16853 * @param {DOMEvent} event native event
16854 * @param {djs.model.Base} [element] the diagram element to emit the event on;
16855 * defaults to the event target
16856 */
16857 function fire(type, event, element) {
16858
16859 if (isIgnored(type, event)) {
16860 return;
16861 }
16862
16863 var target, gfx, returnValue;
16864
16865 if (!element) {
16866 target = event.delegateTarget || event.target;
16867
16868 if (target) {
16869 gfx = target;
16870 element = elementRegistry.get(gfx);
16871 }
16872 } else {
16873 gfx = elementRegistry.getGraphics(element);
16874 }
16875
16876 if (!gfx || !element) {
16877 return;
16878 }
16879
16880 returnValue = eventBus.fire(type, {
16881 element: element,
16882 gfx: gfx,
16883 originalEvent: event
16884 });
16885
16886 if (returnValue === false) {
16887 event.stopPropagation();
16888 event.preventDefault();
16889 }
16890 }
16891
16892 // TODO(nikku): document this
16893 var handlers = {};
16894
16895 function mouseHandler(localEventName) {
16896 return handlers[localEventName];
16897 }
16898
16899 function isIgnored(localEventName, event) {
16900
16901 var filter = ignoredFilters[localEventName] || isPrimaryButton;
16902
16903 // only react on left mouse button interactions
16904 // except for interaction events that are enabled
16905 // for secundary mouse button
16906 return !filter(event);
16907 }
16908
16909 var bindings = {
16910 click: 'element.click',
16911 contextmenu: 'element.contextmenu',
16912 dblclick: 'element.dblclick',
16913 mousedown: 'element.mousedown',
16914 mousemove: 'element.mousemove',
16915 mouseover: 'element.hover',
16916 mouseout: 'element.out',
16917 mouseup: 'element.mouseup',
16918 };
16919
16920 var ignoredFilters = {
16921 'element.contextmenu': allowAll
16922 };
16923
16924
16925 // manual event trigger //////////
16926
16927 /**
16928 * Trigger an interaction event (based on a native dom event)
16929 * on the target shape or connection.
16930 *
16931 * @param {String} eventName the name of the triggered DOM event
16932 * @param {MouseEvent} event
16933 * @param {djs.model.Base} targetElement
16934 */
16935 function triggerMouseEvent(eventName, event, targetElement) {
16936
16937 // i.e. element.mousedown...
16938 var localEventName = bindings[eventName];
16939
16940 if (!localEventName) {
16941 throw new Error('unmapped DOM event name <' + eventName + '>');
16942 }
16943
16944 return fire(localEventName, event, targetElement);
16945 }
16946
16947
16948 var ELEMENT_SELECTOR = 'svg, .djs-element';
16949
16950 // event handling ///////
16951
16952 function registerEvent(node, event, localEvent, ignoredFilter) {
16953
16954 var handler = handlers[localEvent] = function(event) {
16955 fire(localEvent, event);
16956 };
16957
16958 if (ignoredFilter) {
16959 ignoredFilters[localEvent] = ignoredFilter;
16960 }
16961
16962 handler.$delegate = delegateEvents.bind(node, ELEMENT_SELECTOR, event, handler);
16963 }
16964
16965 function unregisterEvent(node, event, localEvent) {
16966
16967 var handler = mouseHandler(localEvent);
16968
16969 if (!handler) {
16970 return;
16971 }
16972
16973 delegateEvents.unbind(node, event, handler.$delegate);
16974 }
16975
16976 function registerEvents(svg) {
16977 forEach(bindings, function(val, key) {
16978 registerEvent(svg, key, val);
16979 });
16980 }
16981
16982 function unregisterEvents(svg) {
16983 forEach(bindings, function(val, key) {
16984 unregisterEvent(svg, key, val);
16985 });
16986 }
16987
16988 eventBus.on('canvas.destroy', function(event) {
16989 unregisterEvents(event.svg);
16990 });
16991
16992 eventBus.on('canvas.init', function(event) {
16993 registerEvents(event.svg);
16994 });
16995
16996
16997 // hit box updating ////////////////
16998
16999 eventBus.on([ 'shape.added', 'connection.added' ], function(event) {
17000 var element = event.element,
17001 gfx = event.gfx;
17002
17003 eventBus.fire('interactionEvents.createHit', { element: element, gfx: gfx });
17004 });
17005
17006 // Update djs-hit on change.
17007 // A low priortity is necessary, because djs-hit of labels has to be updated
17008 // after the label bounds have been updated in the renderer.
17009 eventBus.on([
17010 'shape.changed',
17011 'connection.changed'
17012 ], LOW_PRIORITY, function(event) {
17013
17014 var element = event.element,
17015 gfx = event.gfx;
17016
17017 eventBus.fire('interactionEvents.updateHit', { element: element, gfx: gfx });
17018 });
17019
17020 eventBus.on('interactionEvents.createHit', LOW_PRIORITY, function(event) {
17021 var element = event.element,
17022 gfx = event.gfx;
17023
17024 self.createDefaultHit(element, gfx);
17025 });
17026
17027 eventBus.on('interactionEvents.updateHit', function(event) {
17028 var element = event.element,
17029 gfx = event.gfx;
17030
17031 self.updateDefaultHit(element, gfx);
17032 });
17033
17034
17035 // hit styles ////////////
17036
17037 var STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-stroke');
17038
17039 var CLICK_STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-click-stroke');
17040
17041 var ALL_HIT_STYLE = createHitStyle('djs-hit djs-hit-all');
17042
17043 var HIT_TYPES = {
17044 'all': ALL_HIT_STYLE,
17045 'click-stroke': CLICK_STROKE_HIT_STYLE,
17046 'stroke': STROKE_HIT_STYLE
17047 };
17048
17049 function createHitStyle(classNames, attrs) {
17050
17051 attrs = assign({
17052 stroke: 'white',
17053 strokeWidth: 15
17054 }, attrs || {});
17055
17056 return styles.cls(classNames, [ 'no-fill', 'no-border' ], attrs);
17057 }
17058
17059
17060 // style helpers ///////////////
17061
17062 function applyStyle(hit, type) {
17063
17064 var attrs = HIT_TYPES[type];
17065
17066 if (!attrs) {
17067 throw new Error('invalid hit type <' + type + '>');
17068 }
17069
17070 attr$1(hit, attrs);
17071
17072 return hit;
17073 }
17074
17075 function appendHit(gfx, hit) {
17076 append(gfx, hit);
17077 }
17078
17079
17080 // API
17081
17082 /**
17083 * Remove hints on the given graphics.
17084 *
17085 * @param {SVGElement} gfx
17086 */
17087 this.removeHits = function(gfx) {
17088 var hits = all('.djs-hit', gfx);
17089
17090 forEach(hits, remove$1);
17091 };
17092
17093 /**
17094 * Create default hit for the given element.
17095 *
17096 * @param {djs.model.Base} element
17097 * @param {SVGElement} gfx
17098 *
17099 * @return {SVGElement} created hit
17100 */
17101 this.createDefaultHit = function(element, gfx) {
17102 var waypoints = element.waypoints,
17103 isFrame = element.isFrame,
17104 boxType;
17105
17106 if (waypoints) {
17107 return this.createWaypointsHit(gfx, waypoints);
17108 } else {
17109
17110 boxType = isFrame ? 'stroke' : 'all';
17111
17112 return this.createBoxHit(gfx, boxType, {
17113 width: element.width,
17114 height: element.height
17115 });
17116 }
17117 };
17118
17119 /**
17120 * Create hits for the given waypoints.
17121 *
17122 * @param {SVGElement} gfx
17123 * @param {Array<Point>} waypoints
17124 *
17125 * @return {SVGElement}
17126 */
17127 this.createWaypointsHit = function(gfx, waypoints) {
17128
17129 var hit = createLine(waypoints);
17130
17131 applyStyle(hit, 'stroke');
17132
17133 appendHit(gfx, hit);
17134
17135 return hit;
17136 };
17137
17138 /**
17139 * Create hits for a box.
17140 *
17141 * @param {SVGElement} gfx
17142 * @param {String} hitType
17143 * @param {Object} attrs
17144 *
17145 * @return {SVGElement}
17146 */
17147 this.createBoxHit = function(gfx, type, attrs) {
17148
17149 attrs = assign({
17150 x: 0,
17151 y: 0
17152 }, attrs);
17153
17154 var hit = create('rect');
17155
17156 applyStyle(hit, type);
17157
17158 attr$1(hit, attrs);
17159
17160 appendHit(gfx, hit);
17161
17162 return hit;
17163 };
17164
17165 /**
17166 * Update default hit of the element.
17167 *
17168 * @param {djs.model.Base} element
17169 * @param {SVGElement} gfx
17170 *
17171 * @return {SVGElement} updated hit
17172 */
17173 this.updateDefaultHit = function(element, gfx) {
17174
17175 var hit = query('.djs-hit', gfx);
17176
17177 if (!hit) {
17178 return;
17179 }
17180
17181 if (element.waypoints) {
17182 updateLine(hit, element.waypoints);
17183 } else {
17184 attr$1(hit, {
17185 width: element.width,
17186 height: element.height
17187 });
17188 }
17189
17190 return hit;
17191 };
17192
17193 this.fire = fire;
17194
17195 this.triggerMouseEvent = triggerMouseEvent;
17196
17197 this.mouseHandler = mouseHandler;
17198
17199 this.registerEvent = registerEvent;
17200 this.unregisterEvent = unregisterEvent;
17201 }
17202
17203
17204 InteractionEvents.$inject = [
17205 'eventBus',
17206 'elementRegistry',
17207 'styles'
17208 ];
17209
17210
17211 /**
17212 * An event indicating that the mouse hovered over an element
17213 *
17214 * @event element.hover
17215 *
17216 * @type {Object}
17217 * @property {djs.model.Base} element
17218 * @property {SVGElement} gfx
17219 * @property {Event} originalEvent
17220 */
17221
17222 /**
17223 * An event indicating that the mouse has left an element
17224 *
17225 * @event element.out
17226 *
17227 * @type {Object}
17228 * @property {djs.model.Base} element
17229 * @property {SVGElement} gfx
17230 * @property {Event} originalEvent
17231 */
17232
17233 /**
17234 * An event indicating that the mouse has clicked an element
17235 *
17236 * @event element.click
17237 *
17238 * @type {Object}
17239 * @property {djs.model.Base} element
17240 * @property {SVGElement} gfx
17241 * @property {Event} originalEvent
17242 */
17243
17244 /**
17245 * An event indicating that the mouse has double clicked an element
17246 *
17247 * @event element.dblclick
17248 *
17249 * @type {Object}
17250 * @property {djs.model.Base} element
17251 * @property {SVGElement} gfx
17252 * @property {Event} originalEvent
17253 */
17254
17255 /**
17256 * An event indicating that the mouse has gone down on an element.
17257 *
17258 * @event element.mousedown
17259 *
17260 * @type {Object}
17261 * @property {djs.model.Base} element
17262 * @property {SVGElement} gfx
17263 * @property {Event} originalEvent
17264 */
17265
17266 /**
17267 * An event indicating that the mouse has gone up on an element.
17268 *
17269 * @event element.mouseup
17270 *
17271 * @type {Object}
17272 * @property {djs.model.Base} element
17273 * @property {SVGElement} gfx
17274 * @property {Event} originalEvent
17275 */
17276
17277 /**
17278 * An event indicating that the context menu action is triggered
17279 * via mouse or touch controls.
17280 *
17281 * @event element.contextmenu
17282 *
17283 * @type {Object}
17284 * @property {djs.model.Base} element
17285 * @property {SVGElement} gfx
17286 * @property {Event} originalEvent
17287 */
17288
17289 var InteractionEventsModule = {
17290 __init__: [ 'interactionEvents' ],
17291 interactionEvents: [ 'type', InteractionEvents ]
17292 };
17293
17294 var LOW_PRIORITY$1 = 500;
17295
17296
17297 /**
17298 * @class
17299 *
17300 * A plugin that adds an outline to shapes and connections that may be activated and styled
17301 * via CSS classes.
17302 *
17303 * @param {EventBus} eventBus
17304 * @param {Styles} styles
17305 * @param {ElementRegistry} elementRegistry
17306 */
17307 function Outline(eventBus, styles, elementRegistry) {
17308
17309 this.offset = 6;
17310
17311 var OUTLINE_STYLE = styles.cls('djs-outline', [ 'no-fill' ]);
17312
17313 var self = this;
17314
17315 function createOutline(gfx, bounds) {
17316 var outline = create('rect');
17317
17318 attr$1(outline, assign({
17319 x: 10,
17320 y: 10,
17321 width: 100,
17322 height: 100
17323 }, OUTLINE_STYLE));
17324
17325 append(gfx, outline);
17326
17327 return outline;
17328 }
17329
17330 // A low priortity is necessary, because outlines of labels have to be updated
17331 // after the label bounds have been updated in the renderer.
17332 eventBus.on([ 'shape.added', 'shape.changed' ], LOW_PRIORITY$1, function(event) {
17333 var element = event.element,
17334 gfx = event.gfx;
17335
17336 var outline = query('.djs-outline', gfx);
17337
17338 if (!outline) {
17339 outline = createOutline(gfx);
17340 }
17341
17342 self.updateShapeOutline(outline, element);
17343 });
17344
17345 eventBus.on([ 'connection.added', 'connection.changed' ], function(event) {
17346 var element = event.element,
17347 gfx = event.gfx;
17348
17349 var outline = query('.djs-outline', gfx);
17350
17351 if (!outline) {
17352 outline = createOutline(gfx);
17353 }
17354
17355 self.updateConnectionOutline(outline, element);
17356 });
17357 }
17358
17359
17360 /**
17361 * Updates the outline of a shape respecting the dimension of the
17362 * element and an outline offset.
17363 *
17364 * @param {SVGElement} outline
17365 * @param {djs.model.Base} element
17366 */
17367 Outline.prototype.updateShapeOutline = function(outline, element) {
17368
17369 attr$1(outline, {
17370 x: -this.offset,
17371 y: -this.offset,
17372 width: element.width + this.offset * 2,
17373 height: element.height + this.offset * 2
17374 });
17375
17376 };
17377
17378
17379 /**
17380 * Updates the outline of a connection respecting the bounding box of
17381 * the connection and an outline offset.
17382 *
17383 * @param {SVGElement} outline
17384 * @param {djs.model.Base} element
17385 */
17386 Outline.prototype.updateConnectionOutline = function(outline, connection) {
17387
17388 var bbox = getBBox(connection);
17389
17390 attr$1(outline, {
17391 x: bbox.x - this.offset,
17392 y: bbox.y - this.offset,
17393 width: bbox.width + this.offset * 2,
17394 height: bbox.height + this.offset * 2
17395 });
17396
17397 };
17398
17399
17400 Outline.$inject = ['eventBus', 'styles', 'elementRegistry'];
17401
17402 var OutlineModule = {
17403 __init__: [ 'outline' ],
17404 outline: [ 'type', Outline ]
17405 };
17406
17407 /**
17408 * A service that offers the current selection in a diagram.
17409 * Offers the api to control the selection, too.
17410 *
17411 * @class
17412 *
17413 * @param {EventBus} eventBus the event bus
17414 */
17415 function Selection(eventBus) {
17416
17417 this._eventBus = eventBus;
17418
17419 this._selectedElements = [];
17420
17421 var self = this;
17422
17423 eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
17424 var element = e.element;
17425 self.deselect(element);
17426 });
17427
17428 eventBus.on([ 'diagram.clear' ], function(e) {
17429 self.select(null);
17430 });
17431 }
17432
17433 Selection.$inject = [ 'eventBus' ];
17434
17435
17436 Selection.prototype.deselect = function(element) {
17437 var selectedElements = this._selectedElements;
17438
17439 var idx = selectedElements.indexOf(element);
17440
17441 if (idx !== -1) {
17442 var oldSelection = selectedElements.slice();
17443
17444 selectedElements.splice(idx, 1);
17445
17446 this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
17447 }
17448 };
17449
17450
17451 Selection.prototype.get = function() {
17452 return this._selectedElements;
17453 };
17454
17455 Selection.prototype.isSelected = function(element) {
17456 return this._selectedElements.indexOf(element) !== -1;
17457 };
17458
17459
17460 /**
17461 * This method selects one or more elements on the diagram.
17462 *
17463 * By passing an additional add parameter you can decide whether or not the element(s)
17464 * should be added to the already existing selection or not.
17465 *
17466 * @method Selection#select
17467 *
17468 * @param {Object|Object[]} elements element or array of elements to be selected
17469 * @param {boolean} [add] whether the element(s) should be appended to the current selection, defaults to false
17470 */
17471 Selection.prototype.select = function(elements, add) {
17472 var selectedElements = this._selectedElements,
17473 oldSelection = selectedElements.slice();
17474
17475 if (!isArray(elements)) {
17476 elements = elements ? [ elements ] : [];
17477 }
17478
17479 // selection may be cleared by passing an empty array or null
17480 // to the method
17481 if (add) {
17482 forEach(elements, function(element) {
17483 if (selectedElements.indexOf(element) !== -1) {
17484
17485 // already selected
17486 return;
17487 } else {
17488 selectedElements.push(element);
17489 }
17490 });
17491 } else {
17492 this._selectedElements = selectedElements = elements.slice();
17493 }
17494
17495 this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
17496 };
17497
17498 var MARKER_HOVER = 'hover',
17499 MARKER_SELECTED = 'selected';
17500
17501
17502 /**
17503 * A plugin that adds a visible selection UI to shapes and connections
17504 * by appending the <code>hover</code> and <code>selected</code> classes to them.
17505 *
17506 * @class
17507 *
17508 * Makes elements selectable, too.
17509 *
17510 * @param {EventBus} events
17511 * @param {SelectionService} selection
17512 * @param {Canvas} canvas
17513 */
17514 function SelectionVisuals(events, canvas, selection, styles) {
17515
17516 this._multiSelectionBox = null;
17517
17518 function addMarker(e, cls) {
17519 canvas.addMarker(e, cls);
17520 }
17521
17522 function removeMarker(e, cls) {
17523 canvas.removeMarker(e, cls);
17524 }
17525
17526 events.on('element.hover', function(event) {
17527 addMarker(event.element, MARKER_HOVER);
17528 });
17529
17530 events.on('element.out', function(event) {
17531 removeMarker(event.element, MARKER_HOVER);
17532 });
17533
17534 events.on('selection.changed', function(event) {
17535
17536 function deselect(s) {
17537 removeMarker(s, MARKER_SELECTED);
17538 }
17539
17540 function select(s) {
17541 addMarker(s, MARKER_SELECTED);
17542 }
17543
17544 var oldSelection = event.oldSelection,
17545 newSelection = event.newSelection;
17546
17547 forEach(oldSelection, function(e) {
17548 if (newSelection.indexOf(e) === -1) {
17549 deselect(e);
17550 }
17551 });
17552
17553 forEach(newSelection, function(e) {
17554 if (oldSelection.indexOf(e) === -1) {
17555 select(e);
17556 }
17557 });
17558 });
17559 }
17560
17561 SelectionVisuals.$inject = [
17562 'eventBus',
17563 'canvas',
17564 'selection',
17565 'styles'
17566 ];
17567
17568 function SelectionBehavior(
17569 eventBus, selection, canvas,
17570 elementRegistry) {
17571
17572 eventBus.on('create.end', 500, function(e) {
17573
17574 var context = e.context,
17575 canExecute = context.canExecute,
17576 elements = context.elements,
17577 hints = context.hints || {},
17578 autoSelect = hints.autoSelect;
17579
17580 // select elements after they have been created
17581 if (canExecute) {
17582 if (autoSelect === false) {
17583
17584 // select no elements
17585 return;
17586 }
17587
17588 if (isArray(autoSelect)) {
17589 selection.select(autoSelect);
17590 } else {
17591
17592 // select all elements by default
17593 selection.select(elements);
17594 }
17595 }
17596 });
17597
17598 eventBus.on('connect.end', 500, function(e) {
17599
17600 // select the connect end target
17601 // after a connect operation
17602 if (e.context.canExecute && e.context.target) {
17603 selection.select(e.context.target);
17604 }
17605 });
17606
17607 eventBus.on('shape.move.end', 500, function(e) {
17608 var previousSelection = e.previousSelection || [];
17609
17610 var shape = elementRegistry.get(e.context.shape.id);
17611
17612 // make sure at least the main moved element is being
17613 // selected after a move operation
17614 var inSelection = find(previousSelection, function(selectedShape) {
17615 return shape.id === selectedShape.id;
17616 });
17617
17618 if (!inSelection) {
17619 selection.select(shape);
17620 }
17621 });
17622
17623 // Shift + click selection
17624 eventBus.on('element.click', function(event) {
17625
17626 var element = event.element;
17627
17628 // do not select the root element
17629 // or connections
17630 if (element === canvas.getRootElement()) {
17631 element = null;
17632 }
17633
17634 var isSelected = selection.isSelected(element),
17635 isMultiSelect = selection.get().length > 1;
17636
17637 // mouse-event: SELECTION_KEY
17638 var add = hasPrimaryModifier(event);
17639
17640 // select OR deselect element in multi selection
17641 if (isSelected && isMultiSelect) {
17642 if (add) {
17643 return selection.deselect(element);
17644 } else {
17645 return selection.select(element);
17646 }
17647 } else
17648 if (!isSelected) {
17649 selection.select(element, add);
17650 } else {
17651 selection.deselect(element);
17652 }
17653 });
17654 }
17655
17656 SelectionBehavior.$inject = [
17657 'eventBus',
17658 'selection',
17659 'canvas',
17660 'elementRegistry'
17661 ];
17662
17663 var SelectionModule = {
17664 __init__: [ 'selectionVisuals', 'selectionBehavior' ],
17665 __depends__: [
17666 InteractionEventsModule,
17667 OutlineModule
17668 ],
17669 selection: [ 'type', Selection ],
17670 selectionVisuals: [ 'type', SelectionVisuals ],
17671 selectionBehavior: [ 'type', SelectionBehavior ]
17672 };
17673
17674 /**
17675 * Util that provides unique IDs.
17676 *
17677 * @class djs.util.IdGenerator
17678 * @constructor
17679 * @memberOf djs.util
17680 *
17681 * The ids can be customized via a given prefix and contain a random value to avoid collisions.
17682 *
17683 * @param {String} prefix a prefix to prepend to generated ids (for better readability)
17684 */
17685 function IdGenerator(prefix) {
17686
17687 this._counter = 0;
17688 this._prefix = (prefix ? prefix + '-' : '') + Math.floor(Math.random() * 1000000000) + '-';
17689 }
17690
17691 /**
17692 * Returns a next unique ID.
17693 *
17694 * @method djs.util.IdGenerator#next
17695 *
17696 * @returns {String} the id
17697 */
17698 IdGenerator.prototype.next = function() {
17699 return this._prefix + (++this._counter);
17700 };
17701
17702 // document wide unique overlay ids
17703 var ids = new IdGenerator('ov');
17704
17705 var LOW_PRIORITY$2 = 500;
17706
17707
17708 /**
17709 * A service that allows users to attach overlays to diagram elements.
17710 *
17711 * The overlay service will take care of overlay positioning during updates.
17712 *
17713 * @example
17714 *
17715 * // add a pink badge on the top left of the shape
17716 * overlays.add(someShape, {
17717 * position: {
17718 * top: -5,
17719 * left: -5
17720 * },
17721 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
17722 * });
17723 *
17724 * // or add via shape id
17725 *
17726 * overlays.add('some-element-id', {
17727 * position: {
17728 * top: -5,
17729 * left: -5
17730 * }
17731 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
17732 * });
17733 *
17734 * // or add with optional type
17735 *
17736 * overlays.add(someShape, 'badge', {
17737 * position: {
17738 * top: -5,
17739 * left: -5
17740 * }
17741 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
17742 * });
17743 *
17744 *
17745 * // remove an overlay
17746 *
17747 * var id = overlays.add(...);
17748 * overlays.remove(id);
17749 *
17750 *
17751 * You may configure overlay defaults during tool by providing a `config` module
17752 * with `overlays.defaults` as an entry:
17753 *
17754 * {
17755 * overlays: {
17756 * defaults: {
17757 * show: {
17758 * minZoom: 0.7,
17759 * maxZoom: 5.0
17760 * },
17761 * scale: {
17762 * min: 1
17763 * }
17764 * }
17765 * }
17766 *
17767 * @param {Object} config
17768 * @param {EventBus} eventBus
17769 * @param {Canvas} canvas
17770 * @param {ElementRegistry} elementRegistry
17771 */
17772 function Overlays(config, eventBus, canvas, elementRegistry) {
17773
17774 this._eventBus = eventBus;
17775 this._canvas = canvas;
17776 this._elementRegistry = elementRegistry;
17777
17778 this._ids = ids;
17779
17780 this._overlayDefaults = assign({
17781
17782 // no show constraints
17783 show: null,
17784
17785 // always scale
17786 scale: true
17787 }, config && config.defaults);
17788
17789 /**
17790 * Mapping overlayId -> overlay
17791 */
17792 this._overlays = {};
17793
17794 /**
17795 * Mapping elementId -> overlay container
17796 */
17797 this._overlayContainers = [];
17798
17799 // root html element for all overlays
17800 this._overlayRoot = createRoot(canvas.getContainer());
17801
17802 this._init();
17803 }
17804
17805
17806 Overlays.$inject = [
17807 'config.overlays',
17808 'eventBus',
17809 'canvas',
17810 'elementRegistry'
17811 ];
17812
17813
17814 /**
17815 * Returns the overlay with the specified id or a list of overlays
17816 * for an element with a given type.
17817 *
17818 * @example
17819 *
17820 * // return the single overlay with the given id
17821 * overlays.get('some-id');
17822 *
17823 * // return all overlays for the shape
17824 * overlays.get({ element: someShape });
17825 *
17826 * // return all overlays on shape with type 'badge'
17827 * overlays.get({ element: someShape, type: 'badge' });
17828 *
17829 * // shape can also be specified as id
17830 * overlays.get({ element: 'element-id', type: 'badge' });
17831 *
17832 *
17833 * @param {Object} search
17834 * @param {String} [search.id]
17835 * @param {String|djs.model.Base} [search.element]
17836 * @param {String} [search.type]
17837 *
17838 * @return {Object|Array<Object>} the overlay(s)
17839 */
17840 Overlays.prototype.get = function(search) {
17841
17842 if (isString(search)) {
17843 search = { id: search };
17844 }
17845
17846 if (isString(search.element)) {
17847 search.element = this._elementRegistry.get(search.element);
17848 }
17849
17850 if (search.element) {
17851 var container = this._getOverlayContainer(search.element, true);
17852
17853 // return a list of overlays when searching by element (+type)
17854 if (container) {
17855 return search.type ? filter(container.overlays, matchPattern({ type: search.type })) : container.overlays.slice();
17856 } else {
17857 return [];
17858 }
17859 } else
17860 if (search.type) {
17861 return filter(this._overlays, matchPattern({ type: search.type }));
17862 } else {
17863
17864 // return single element when searching by id
17865 return search.id ? this._overlays[search.id] : null;
17866 }
17867 };
17868
17869 /**
17870 * Adds a HTML overlay to an element.
17871 *
17872 * @param {String|djs.model.Base} element attach overlay to this shape
17873 * @param {String} [type] optional type to assign to the overlay
17874 * @param {Object} overlay the overlay configuration
17875 *
17876 * @param {String|DOMElement} overlay.html html element to use as an overlay
17877 * @param {Object} [overlay.show] show configuration
17878 * @param {Number} [overlay.show.minZoom] minimal zoom level to show the overlay
17879 * @param {Number} [overlay.show.maxZoom] maximum zoom level to show the overlay
17880 * @param {Object} overlay.position where to attach the overlay
17881 * @param {Number} [overlay.position.left] relative to element bbox left attachment
17882 * @param {Number} [overlay.position.top] relative to element bbox top attachment
17883 * @param {Number} [overlay.position.bottom] relative to element bbox bottom attachment
17884 * @param {Number} [overlay.position.right] relative to element bbox right attachment
17885 * @param {Boolean|Object} [overlay.scale=true] false to preserve the same size regardless of
17886 * diagram zoom
17887 * @param {Number} [overlay.scale.min]
17888 * @param {Number} [overlay.scale.max]
17889 *
17890 * @return {String} id that may be used to reference the overlay for update or removal
17891 */
17892 Overlays.prototype.add = function(element, type, overlay) {
17893
17894 if (isObject(type)) {
17895 overlay = type;
17896 type = null;
17897 }
17898
17899 if (!element.id) {
17900 element = this._elementRegistry.get(element);
17901 }
17902
17903 if (!overlay.position) {
17904 throw new Error('must specifiy overlay position');
17905 }
17906
17907 if (!overlay.html) {
17908 throw new Error('must specifiy overlay html');
17909 }
17910
17911 if (!element) {
17912 throw new Error('invalid element specified');
17913 }
17914
17915 var id = this._ids.next();
17916
17917 overlay = assign({}, this._overlayDefaults, overlay, {
17918 id: id,
17919 type: type,
17920 element: element,
17921 html: overlay.html
17922 });
17923
17924 this._addOverlay(overlay);
17925
17926 return id;
17927 };
17928
17929
17930 /**
17931 * Remove an overlay with the given id or all overlays matching the given filter.
17932 *
17933 * @see Overlays#get for filter options.
17934 *
17935 * @param {String} [id]
17936 * @param {Object} [filter]
17937 */
17938 Overlays.prototype.remove = function(filter) {
17939
17940 var overlays = this.get(filter) || [];
17941
17942 if (!isArray(overlays)) {
17943 overlays = [ overlays ];
17944 }
17945
17946 var self = this;
17947
17948 forEach(overlays, function(overlay) {
17949
17950 var container = self._getOverlayContainer(overlay.element, true);
17951
17952 if (overlay) {
17953 remove(overlay.html);
17954 remove(overlay.htmlContainer);
17955
17956 delete overlay.htmlContainer;
17957 delete overlay.element;
17958
17959 delete self._overlays[overlay.id];
17960 }
17961
17962 if (container) {
17963 var idx = container.overlays.indexOf(overlay);
17964 if (idx !== -1) {
17965 container.overlays.splice(idx, 1);
17966 }
17967 }
17968 });
17969
17970 };
17971
17972
17973 Overlays.prototype.show = function() {
17974 setVisible(this._overlayRoot);
17975 };
17976
17977
17978 Overlays.prototype.hide = function() {
17979 setVisible(this._overlayRoot, false);
17980 };
17981
17982 Overlays.prototype.clear = function() {
17983 this._overlays = {};
17984
17985 this._overlayContainers = [];
17986
17987 clear(this._overlayRoot);
17988 };
17989
17990 Overlays.prototype._updateOverlayContainer = function(container) {
17991 var element = container.element,
17992 html = container.html;
17993
17994 // update container left,top according to the elements x,y coordinates
17995 // this ensures we can attach child elements relative to this container
17996
17997 var x = element.x,
17998 y = element.y;
17999
18000 if (element.waypoints) {
18001 var bbox = getBBox(element);
18002 x = bbox.x;
18003 y = bbox.y;
18004 }
18005
18006 setPosition(html, x, y);
18007
18008 attr(container.html, 'data-container-id', element.id);
18009 };
18010
18011
18012 Overlays.prototype._updateOverlay = function(overlay) {
18013
18014 var position = overlay.position,
18015 htmlContainer = overlay.htmlContainer,
18016 element = overlay.element;
18017
18018 // update overlay html relative to shape because
18019 // it is already positioned on the element
18020
18021 // update relative
18022 var left = position.left,
18023 top = position.top;
18024
18025 if (position.right !== undefined) {
18026
18027 var width;
18028
18029 if (element.waypoints) {
18030 width = getBBox(element).width;
18031 } else {
18032 width = element.width;
18033 }
18034
18035 left = position.right * -1 + width;
18036 }
18037
18038 if (position.bottom !== undefined) {
18039
18040 var height;
18041
18042 if (element.waypoints) {
18043 height = getBBox(element).height;
18044 } else {
18045 height = element.height;
18046 }
18047
18048 top = position.bottom * -1 + height;
18049 }
18050
18051 setPosition(htmlContainer, left || 0, top || 0);
18052 };
18053
18054
18055 Overlays.prototype._createOverlayContainer = function(element) {
18056 var html = domify('<div class="djs-overlays" style="position: absolute" />');
18057
18058 this._overlayRoot.appendChild(html);
18059
18060 var container = {
18061 html: html,
18062 element: element,
18063 overlays: []
18064 };
18065
18066 this._updateOverlayContainer(container);
18067
18068 this._overlayContainers.push(container);
18069
18070 return container;
18071 };
18072
18073
18074 Overlays.prototype._updateRoot = function(viewbox) {
18075 var scale = viewbox.scale || 1;
18076
18077 var matrix = 'matrix(' +
18078 [
18079 scale,
18080 0,
18081 0,
18082 scale,
18083 -1 * viewbox.x * scale,
18084 -1 * viewbox.y * scale
18085 ].join(',') +
18086 ')';
18087
18088 setTransform(this._overlayRoot, matrix);
18089 };
18090
18091
18092 Overlays.prototype._getOverlayContainer = function(element, raw) {
18093 var container = find(this._overlayContainers, function(c) {
18094 return c.element === element;
18095 });
18096
18097
18098 if (!container && !raw) {
18099 return this._createOverlayContainer(element);
18100 }
18101
18102 return container;
18103 };
18104
18105
18106 Overlays.prototype._addOverlay = function(overlay) {
18107
18108 var id = overlay.id,
18109 element = overlay.element,
18110 html = overlay.html,
18111 htmlContainer,
18112 overlayContainer;
18113
18114 // unwrap jquery (for those who need it)
18115 if (html.get && html.constructor.prototype.jquery) {
18116 html = html.get(0);
18117 }
18118
18119 // create proper html elements from
18120 // overlay HTML strings
18121 if (isString(html)) {
18122 html = domify(html);
18123 }
18124
18125 overlayContainer = this._getOverlayContainer(element);
18126
18127 htmlContainer = domify('<div class="djs-overlay" data-overlay-id="' + id + '" style="position: absolute">');
18128
18129 htmlContainer.appendChild(html);
18130
18131 if (overlay.type) {
18132 classes(htmlContainer).add('djs-overlay-' + overlay.type);
18133 }
18134
18135 overlay.htmlContainer = htmlContainer;
18136
18137 overlayContainer.overlays.push(overlay);
18138 overlayContainer.html.appendChild(htmlContainer);
18139
18140 this._overlays[id] = overlay;
18141
18142 this._updateOverlay(overlay);
18143 this._updateOverlayVisibilty(overlay, this._canvas.viewbox());
18144 };
18145
18146
18147 Overlays.prototype._updateOverlayVisibilty = function(overlay, viewbox) {
18148 var show = overlay.show,
18149 minZoom = show && show.minZoom,
18150 maxZoom = show && show.maxZoom,
18151 htmlContainer = overlay.htmlContainer,
18152 visible = true;
18153
18154 if (show) {
18155 if (
18156 (isDefined(minZoom) && minZoom > viewbox.scale) ||
18157 (isDefined(maxZoom) && maxZoom < viewbox.scale)
18158 ) {
18159 visible = false;
18160 }
18161
18162 setVisible(htmlContainer, visible);
18163 }
18164
18165 this._updateOverlayScale(overlay, viewbox);
18166 };
18167
18168
18169 Overlays.prototype._updateOverlayScale = function(overlay, viewbox) {
18170 var shouldScale = overlay.scale,
18171 minScale,
18172 maxScale,
18173 htmlContainer = overlay.htmlContainer;
18174
18175 var scale, transform = '';
18176
18177 if (shouldScale !== true) {
18178
18179 if (shouldScale === false) {
18180 minScale = 1;
18181 maxScale = 1;
18182 } else {
18183 minScale = shouldScale.min;
18184 maxScale = shouldScale.max;
18185 }
18186
18187 if (isDefined(minScale) && viewbox.scale < minScale) {
18188 scale = (1 / viewbox.scale || 1) * minScale;
18189 }
18190
18191 if (isDefined(maxScale) && viewbox.scale > maxScale) {
18192 scale = (1 / viewbox.scale || 1) * maxScale;
18193 }
18194 }
18195
18196 if (isDefined(scale)) {
18197 transform = 'scale(' + scale + ',' + scale + ')';
18198 }
18199
18200 setTransform(htmlContainer, transform);
18201 };
18202
18203
18204 Overlays.prototype._updateOverlaysVisibilty = function(viewbox) {
18205
18206 var self = this;
18207
18208 forEach(this._overlays, function(overlay) {
18209 self._updateOverlayVisibilty(overlay, viewbox);
18210 });
18211 };
18212
18213
18214 Overlays.prototype._init = function() {
18215
18216 var eventBus = this._eventBus;
18217
18218 var self = this;
18219
18220
18221 // scroll/zoom integration
18222
18223 function updateViewbox(viewbox) {
18224 self._updateRoot(viewbox);
18225 self._updateOverlaysVisibilty(viewbox);
18226
18227 self.show();
18228 }
18229
18230 eventBus.on('canvas.viewbox.changing', function(event) {
18231 self.hide();
18232 });
18233
18234 eventBus.on('canvas.viewbox.changed', function(event) {
18235 updateViewbox(event.viewbox);
18236 });
18237
18238
18239 // remove integration
18240
18241 eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
18242 var element = e.element;
18243 var overlays = self.get({ element: element });
18244
18245 forEach(overlays, function(o) {
18246 self.remove(o.id);
18247 });
18248
18249 var container = self._getOverlayContainer(element);
18250
18251 if (container) {
18252 remove(container.html);
18253 var i = self._overlayContainers.indexOf(container);
18254 if (i !== -1) {
18255 self._overlayContainers.splice(i, 1);
18256 }
18257 }
18258 });
18259
18260
18261 // move integration
18262
18263 eventBus.on('element.changed', LOW_PRIORITY$2, function(e) {
18264 var element = e.element;
18265
18266 var container = self._getOverlayContainer(element, true);
18267
18268 if (container) {
18269 forEach(container.overlays, function(overlay) {
18270 self._updateOverlay(overlay);
18271 });
18272
18273 self._updateOverlayContainer(container);
18274 }
18275 });
18276
18277
18278 // marker integration, simply add them on the overlays as classes, too.
18279
18280 eventBus.on('element.marker.update', function(e) {
18281 var container = self._getOverlayContainer(e.element, true);
18282 if (container) {
18283 classes(container.html)[e.add ? 'add' : 'remove'](e.marker);
18284 }
18285 });
18286
18287
18288 // clear overlays with diagram
18289
18290 eventBus.on('diagram.clear', this.clear, this);
18291 };
18292
18293
18294
18295 // helpers /////////////////////////////
18296
18297 function createRoot(parentNode) {
18298 var root = domify(
18299 '<div class="djs-overlay-container" style="position: absolute; width: 0; height: 0;" />'
18300 );
18301
18302 parentNode.insertBefore(root, parentNode.firstChild);
18303
18304 return root;
18305 }
18306
18307 function setPosition(el, x, y) {
18308 assign(el.style, { left: x + 'px', top: y + 'px' });
18309 }
18310
18311 function setVisible(el, visible) {
18312 el.style.display = visible === false ? 'none' : '';
18313 }
18314
18315 function setTransform(el, transform) {
18316
18317 el.style['transform-origin'] = 'top left';
18318
18319 [ '', '-ms-', '-webkit-' ].forEach(function(prefix) {
18320 el.style[prefix + 'transform'] = transform;
18321 });
18322 }
18323
18324 var OverlaysModule = {
18325 __init__: [ 'overlays' ],
18326 overlays: [ 'type', Overlays ]
18327 };
18328
18329 /**
18330 * This file must not be changed or exchanged.
18331 *
18332 * @see http://bpmn.io/license for more information.
18333 */
18334
18335
18336 // inlined ../../resources/logo.svg
18337 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>';
18338
18339 var BPMNIO_LOGO_URL = 'data:image/svg+xml,' + encodeURIComponent(BPMNIO_LOGO_SVG);
18340
18341 var BPMNIO_IMG = '<img width="52" height="52" src="' + BPMNIO_LOGO_URL + '" />';
18342
18343 function css(attrs) {
18344 return attrs.join(';');
18345 }
18346
18347 var LIGHTBOX_STYLES = css([
18348 'z-index: 1001',
18349 'position: fixed',
18350 'top: 0',
18351 'left: 0',
18352 'right: 0',
18353 'bottom: 0'
18354 ]);
18355
18356 var BACKDROP_STYLES = css([
18357 'width: 100%',
18358 'height: 100%',
18359 'background: rgba(0,0,0,0.2)'
18360 ]);
18361
18362 var NOTICE_STYLES = css([
18363 'position: absolute',
18364 'left: 50%',
18365 'top: 40%',
18366 'margin: 0 -130px',
18367 'width: 260px',
18368 'padding: 10px',
18369 'background: white',
18370 'border: solid 1px #AAA',
18371 'border-radius: 3px',
18372 'font-family: Helvetica, Arial, sans-serif',
18373 'font-size: 14px',
18374 'line-height: 1.2em'
18375 ]);
18376
18377 var LIGHTBOX_MARKUP =
18378 '<div class="bjs-powered-by-lightbox" style="' + LIGHTBOX_STYLES + '">' +
18379 '<div class="backdrop" style="' + BACKDROP_STYLES + '"></div>' +
18380 '<div class="notice" style="' + NOTICE_STYLES + '">' +
18381 '<a href="http://bpmn.io" target="_blank" style="float: left; margin-right: 10px">' +
18382 BPMNIO_IMG +
18383 '</a>' +
18384 'Web-based tooling for BPMN, DMN and CMMN diagrams ' +
18385 'powered by <a href="http://bpmn.io" target="_blank">bpmn.io</a>.' +
18386 '</div>' +
18387 '</div>';
18388
18389
18390 var lightbox;
18391
18392 function open() {
18393
18394 if (!lightbox) {
18395 lightbox = domify(LIGHTBOX_MARKUP);
18396
18397 delegateEvents.bind(lightbox, '.backdrop', 'click', function(event) {
18398 document.body.removeChild(lightbox);
18399 });
18400 }
18401
18402 document.body.appendChild(lightbox);
18403 }
18404
18405 /**
18406 * The code in the <project-logo></project-logo> area
18407 * must not be changed.
18408 *
18409 * @see http://bpmn.io/license for more information.
18410 */
18411
18412
18413 function checkValidationError(err) {
18414
18415 // check if we can help the user by indicating wrong BPMN 2.0 xml
18416 // (in case he or the exporting tool did not get that right)
18417
18418 var pattern = /unparsable content <([^>]+)> detected([\s\S]*)$/;
18419 var match = pattern.exec(err.message);
18420
18421 if (match) {
18422 err.message =
18423 'unparsable content <' + match[1] + '> detected; ' +
18424 'this may indicate an invalid BPMN 2.0 diagram file' + match[2];
18425 }
18426
18427 return err;
18428 }
18429
18430 var DEFAULT_OPTIONS = {
18431 width: '100%',
18432 height: '100%',
18433 position: 'relative'
18434 };
18435
18436
18437 /**
18438 * Ensure the passed argument is a proper unit (defaulting to px)
18439 */
18440 function ensureUnit(val) {
18441 return val + (isNumber(val) ? 'px' : '');
18442 }
18443
18444
18445 /**
18446 * Find BPMNDiagram in definitions by ID
18447 *
18448 * @param {ModdleElement<Definitions>} definitions
18449 * @param {String} diagramId
18450 *
18451 * @return {ModdleElement<BPMNDiagram>|null}
18452 */
18453 function findBPMNDiagram(definitions, diagramId) {
18454 if (!diagramId) {
18455 return null;
18456 }
18457
18458 return find(definitions.diagrams, function(element) {
18459 return element.id === diagramId;
18460 }) || null;
18461 }
18462
18463 /**
18464 * A viewer for BPMN 2.0 diagrams.
18465 *
18466 * Have a look at {@link NavigatedViewer} or {@link Modeler} for bundles that include
18467 * additional features.
18468 *
18469 *
18470 * ## Extending the Viewer
18471 *
18472 * In order to extend the viewer pass extension modules to bootstrap via the
18473 * `additionalModules` option. An extension module is an object that exposes
18474 * named services.
18475 *
18476 * The following example depicts the integration of a simple
18477 * logging component that integrates with interaction events:
18478 *
18479 *
18480 * ```javascript
18481 *
18482 * // logging component
18483 * function InteractionLogger(eventBus) {
18484 * eventBus.on('element.hover', function(event) {
18485 * console.log()
18486 * })
18487 * }
18488 *
18489 * InteractionLogger.$inject = [ 'eventBus' ]; // minification save
18490 *
18491 * // extension module
18492 * var extensionModule = {
18493 * __init__: [ 'interactionLogger' ],
18494 * interactionLogger: [ 'type', InteractionLogger ]
18495 * };
18496 *
18497 * // extend the viewer
18498 * var bpmnViewer = new Viewer({ additionalModules: [ extensionModule ] });
18499 * bpmnViewer.importXML(...);
18500 * ```
18501 *
18502 * @param {Object} [options] configuration options to pass to the viewer
18503 * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
18504 * @param {String|Number} [options.width] the width of the viewer
18505 * @param {String|Number} [options.height] the height of the viewer
18506 * @param {Object} [options.moddleExtensions] extension packages to provide
18507 * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
18508 * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
18509 */
18510 function Viewer(options) {
18511
18512 options = assign({}, DEFAULT_OPTIONS, options);
18513
18514 this._moddle = this._createModdle(options);
18515
18516 this._container = this._createContainer(options);
18517
18518 /* <project-logo> */
18519
18520 addProjectLogo(this._container);
18521
18522 /* </project-logo> */
18523
18524 this._init(this._container, this._moddle, options);
18525 }
18526
18527 inherits_browser(Viewer, Diagram);
18528
18529
18530 /**
18531 * Parse and render a BPMN 2.0 diagram.
18532 *
18533 * Once finished the viewer reports back the result to the
18534 * provided callback function with (err, warnings).
18535 *
18536 * ## Life-Cycle Events
18537 *
18538 * During import the viewer will fire life-cycle events:
18539 *
18540 * * import.parse.start (about to read model from xml)
18541 * * import.parse.complete (model read; may have worked or not)
18542 * * import.render.start (graphical import start)
18543 * * import.render.complete (graphical import finished)
18544 * * import.done (everything done)
18545 *
18546 * You can use these events to hook into the life-cycle.
18547 *
18548 * @param {String} xml the BPMN 2.0 xml
18549 * @param {ModdleElement<BPMNDiagram>|String} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
18550 * @param {Function} [done] invoked with (err, warnings=[])
18551 */
18552 Viewer.prototype.importXML = function(xml, bpmnDiagram, done) {
18553
18554 if (isFunction(bpmnDiagram)) {
18555 done = bpmnDiagram;
18556 bpmnDiagram = null;
18557 }
18558
18559 // done is optional
18560 done = done || function() {};
18561
18562 var self = this;
18563
18564 // hook in pre-parse listeners +
18565 // allow xml manipulation
18566 xml = this._emit('import.parse.start', { xml: xml }) || xml;
18567
18568 this._moddle.fromXML(xml, 'bpmn:Definitions', function(err, definitions, context) {
18569
18570 // hook in post parse listeners +
18571 // allow definitions manipulation
18572 definitions = self._emit('import.parse.complete', {
18573 error: err,
18574 definitions: definitions,
18575 context: context
18576 }) || definitions;
18577
18578 var parseWarnings = context.warnings;
18579
18580 if (err) {
18581 err = checkValidationError(err);
18582
18583 self._emit('import.done', { error: err, warnings: parseWarnings });
18584
18585 return done(err, parseWarnings);
18586 }
18587
18588 self.importDefinitions(definitions, bpmnDiagram, function(err, importWarnings) {
18589 var allWarnings = [].concat(parseWarnings, importWarnings || []);
18590
18591 self._emit('import.done', { error: err, warnings: allWarnings });
18592
18593 done(err, allWarnings);
18594 });
18595 });
18596 };
18597
18598 /**
18599 * Import parsed definitions and render a BPMN 2.0 diagram.
18600 *
18601 * Once finished the viewer reports back the result to the
18602 * provided callback function with (err, warnings).
18603 *
18604 * ## Life-Cycle Events
18605 *
18606 * During import the viewer will fire life-cycle events:
18607 *
18608 * * import.render.start (graphical import start)
18609 * * import.render.complete (graphical import finished)
18610 *
18611 * You can use these events to hook into the life-cycle.
18612 *
18613 * @param {ModdleElement<Definitions>} definitions parsed BPMN 2.0 definitions
18614 * @param {ModdleElement<BPMNDiagram>|String} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
18615 * @param {Function} [done] invoked with (err, warnings=[])
18616 */
18617 Viewer.prototype.importDefinitions = function(definitions, bpmnDiagram, done) {
18618
18619 if (isFunction(bpmnDiagram)) {
18620 done = bpmnDiagram;
18621 bpmnDiagram = null;
18622 }
18623
18624 // done is optional
18625 done = done || function() {};
18626
18627 this._setDefinitions(definitions);
18628
18629 return this.open(bpmnDiagram, done);
18630 };
18631
18632 /**
18633 * Open diagram of previously imported XML.
18634 *
18635 * Once finished the viewer reports back the result to the
18636 * provided callback function with (err, warnings).
18637 *
18638 * ## Life-Cycle Events
18639 *
18640 * During switch the viewer will fire life-cycle events:
18641 *
18642 * * import.render.start (graphical import start)
18643 * * import.render.complete (graphical import finished)
18644 *
18645 * You can use these events to hook into the life-cycle.
18646 *
18647 * @param {String|ModdleElement<BPMNDiagram>} [bpmnDiagramOrId] id or the diagram to open
18648 * @param {Function} [done] invoked with (err, warnings=[])
18649 */
18650 Viewer.prototype.open = function(bpmnDiagramOrId, done) {
18651
18652 if (isFunction(bpmnDiagramOrId)) {
18653 done = bpmnDiagramOrId;
18654 bpmnDiagramOrId = null;
18655 }
18656
18657 var definitions = this._definitions;
18658 var bpmnDiagram = bpmnDiagramOrId;
18659
18660 // done is optional
18661 done = done || function() {};
18662
18663 if (!definitions) {
18664 return done(new Error('no XML imported'));
18665 }
18666
18667 if (typeof bpmnDiagramOrId === 'string') {
18668 bpmnDiagram = findBPMNDiagram(definitions, bpmnDiagramOrId);
18669
18670 if (!bpmnDiagram) {
18671 return done(new Error('BPMNDiagram <' + bpmnDiagramOrId + '> not found'));
18672 }
18673 }
18674
18675 // clear existing rendered diagram
18676 // catch synchronous exceptions during #clear()
18677 try {
18678 this.clear();
18679 } catch (error) {
18680 return done(error);
18681 }
18682
18683 // perform graphical import
18684 return importBpmnDiagram(this, definitions, bpmnDiagram, done);
18685 };
18686
18687 /**
18688 * Export the currently displayed BPMN 2.0 diagram as
18689 * a BPMN 2.0 XML document.
18690 *
18691 * ## Life-Cycle Events
18692 *
18693 * During XML saving the viewer will fire life-cycle events:
18694 *
18695 * * saveXML.start (before serialization)
18696 * * saveXML.serialized (after xml generation)
18697 * * saveXML.done (everything done)
18698 *
18699 * You can use these events to hook into the life-cycle.
18700 *
18701 * @param {Object} [options] export options
18702 * @param {Boolean} [options.format=false] output formated XML
18703 * @param {Boolean} [options.preamble=true] output preamble
18704 *
18705 * @param {Function} done invoked with (err, xml)
18706 */
18707 Viewer.prototype.saveXML = function(options, done) {
18708
18709 if (!done) {
18710 done = options;
18711 options = {};
18712 }
18713
18714 var self = this;
18715
18716 var definitions = this._definitions;
18717
18718 if (!definitions) {
18719 return done(new Error('no definitions loaded'));
18720 }
18721
18722 // allow to fiddle around with definitions
18723 definitions = this._emit('saveXML.start', {
18724 definitions: definitions
18725 }) || definitions;
18726
18727 this._moddle.toXML(definitions, options, function(err, xml) {
18728
18729 try {
18730 xml = self._emit('saveXML.serialized', {
18731 error: err,
18732 xml: xml
18733 }) || xml;
18734
18735 self._emit('saveXML.done', {
18736 error: err,
18737 xml: xml
18738 });
18739 } catch (e) {
18740 console.error('error in saveXML life-cycle listener', e);
18741 }
18742
18743 done(err, xml);
18744 });
18745 };
18746
18747 /**
18748 * Export the currently displayed BPMN 2.0 diagram as
18749 * an SVG image.
18750 *
18751 * ## Life-Cycle Events
18752 *
18753 * During SVG saving the viewer will fire life-cycle events:
18754 *
18755 * * saveSVG.start (before serialization)
18756 * * saveSVG.done (everything done)
18757 *
18758 * You can use these events to hook into the life-cycle.
18759 *
18760 * @param {Object} [options]
18761 * @param {Function} done invoked with (err, svgStr)
18762 */
18763 Viewer.prototype.saveSVG = function(options, done) {
18764
18765 if (!done) {
18766 done = options;
18767 options = {};
18768 }
18769
18770 this._emit('saveSVG.start');
18771
18772 var svg, err;
18773
18774 try {
18775 var canvas = this.get('canvas');
18776
18777 var contentNode = canvas.getDefaultLayer(),
18778 defsNode = query('defs', canvas._svg);
18779
18780 var contents = innerSVG(contentNode),
18781 defs = defsNode ? '<defs>' + innerSVG(defsNode) + '</defs>' : '';
18782
18783 var bbox = contentNode.getBBox();
18784
18785 svg =
18786 '<?xml version="1.0" encoding="utf-8"?>\n' +
18787 '<!-- created with bpmn-js / http://bpmn.io -->\n' +
18788 '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
18789 '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
18790 'width="' + bbox.width + '" height="' + bbox.height + '" ' +
18791 'viewBox="' + bbox.x + ' ' + bbox.y + ' ' + bbox.width + ' ' + bbox.height + '" version="1.1">' +
18792 defs + contents +
18793 '</svg>';
18794 } catch (e) {
18795 err = e;
18796 }
18797
18798 this._emit('saveSVG.done', {
18799 error: err,
18800 svg: svg
18801 });
18802
18803 done(err, svg);
18804 };
18805
18806 /**
18807 * Get a named diagram service.
18808 *
18809 * @example
18810 *
18811 * var elementRegistry = viewer.get('elementRegistry');
18812 * var startEventShape = elementRegistry.get('StartEvent_1');
18813 *
18814 * @param {String} name
18815 *
18816 * @return {Object} diagram service instance
18817 *
18818 * @method Viewer#get
18819 */
18820
18821 /**
18822 * Invoke a function in the context of this viewer.
18823 *
18824 * @example
18825 *
18826 * viewer.invoke(function(elementRegistry) {
18827 * var startEventShape = elementRegistry.get('StartEvent_1');
18828 * });
18829 *
18830 * @param {Function} fn to be invoked
18831 *
18832 * @return {Object} the functions return value
18833 *
18834 * @method Viewer#invoke
18835 */
18836
18837
18838 Viewer.prototype._setDefinitions = function(definitions) {
18839 this._definitions = definitions;
18840 };
18841
18842 Viewer.prototype.getModules = function() {
18843 return this._modules;
18844 };
18845
18846 /**
18847 * Remove all drawn elements from the viewer.
18848 *
18849 * After calling this method the viewer can still
18850 * be reused for opening another diagram.
18851 *
18852 * @method Viewer#clear
18853 */
18854 Viewer.prototype.clear = function() {
18855
18856 // remove businessObject#di binding
18857 //
18858 // this is necessary, as we establish the bindings
18859 // in the BpmnTreeWalker (and assume none are given
18860 // on reimport)
18861 this.get('elementRegistry').forEach(function(element) {
18862 var bo = element.businessObject;
18863
18864 if (bo && bo.di) {
18865 delete bo.di;
18866 }
18867 });
18868
18869 // remove drawn elements
18870 Diagram.prototype.clear.call(this);
18871 };
18872
18873 /**
18874 * Destroy the viewer instance and remove all its
18875 * remainders from the document tree.
18876 */
18877 Viewer.prototype.destroy = function() {
18878
18879 // diagram destroy
18880 Diagram.prototype.destroy.call(this);
18881
18882 // dom detach
18883 remove(this._container);
18884 };
18885
18886 /**
18887 * Register an event listener
18888 *
18889 * Remove a previously added listener via {@link #off(event, callback)}.
18890 *
18891 * @param {String} event
18892 * @param {Number} [priority]
18893 * @param {Function} callback
18894 * @param {Object} [that]
18895 */
18896 Viewer.prototype.on = function(event, priority, callback, target) {
18897 return this.get('eventBus').on(event, priority, callback, target);
18898 };
18899
18900 /**
18901 * De-register an event listener
18902 *
18903 * @param {String} event
18904 * @param {Function} callback
18905 */
18906 Viewer.prototype.off = function(event, callback) {
18907 this.get('eventBus').off(event, callback);
18908 };
18909
18910 Viewer.prototype.attachTo = function(parentNode) {
18911
18912 if (!parentNode) {
18913 throw new Error('parentNode required');
18914 }
18915
18916 // ensure we detach from the
18917 // previous, old parent
18918 this.detach();
18919
18920 // unwrap jQuery if provided
18921 if (parentNode.get && parentNode.constructor.prototype.jquery) {
18922 parentNode = parentNode.get(0);
18923 }
18924
18925 if (typeof parentNode === 'string') {
18926 parentNode = query(parentNode);
18927 }
18928
18929 parentNode.appendChild(this._container);
18930
18931 this._emit('attach', {});
18932
18933 this.get('canvas').resized();
18934 };
18935
18936 Viewer.prototype.getDefinitions = function() {
18937 return this._definitions;
18938 };
18939
18940 Viewer.prototype.detach = function() {
18941
18942 var container = this._container,
18943 parentNode = container.parentNode;
18944
18945 if (!parentNode) {
18946 return;
18947 }
18948
18949 this._emit('detach', {});
18950
18951 parentNode.removeChild(container);
18952 };
18953
18954 Viewer.prototype._init = function(container, moddle, options) {
18955
18956 var baseModules = options.modules || this.getModules(),
18957 additionalModules = options.additionalModules || [],
18958 staticModules = [
18959 {
18960 bpmnjs: [ 'value', this ],
18961 moddle: [ 'value', moddle ]
18962 }
18963 ];
18964
18965 var diagramModules = [].concat(staticModules, baseModules, additionalModules);
18966
18967 var diagramOptions = assign(omit(options, [ 'additionalModules' ]), {
18968 canvas: assign({}, options.canvas, { container: container }),
18969 modules: diagramModules
18970 });
18971
18972 // invoke diagram constructor
18973 Diagram.call(this, diagramOptions);
18974
18975 if (options && options.container) {
18976 this.attachTo(options.container);
18977 }
18978 };
18979
18980 /**
18981 * Emit an event on the underlying {@link EventBus}
18982 *
18983 * @param {String} type
18984 * @param {Object} event
18985 *
18986 * @return {Object} event processing result (if any)
18987 */
18988 Viewer.prototype._emit = function(type, event) {
18989 return this.get('eventBus').fire(type, event);
18990 };
18991
18992 Viewer.prototype._createContainer = function(options) {
18993
18994 var container = domify('<div class="bjs-container"></div>');
18995
18996 assign(container.style, {
18997 width: ensureUnit(options.width),
18998 height: ensureUnit(options.height),
18999 position: options.position
19000 });
19001
19002 return container;
19003 };
19004
19005 Viewer.prototype._createModdle = function(options) {
19006 var moddleOptions = assign({}, this._moddleExtensions, options.moddleExtensions);
19007
19008 return new simple(moddleOptions);
19009 };
19010
19011 // modules the viewer is composed of
19012 Viewer.prototype._modules = [
19013 CoreModule$1,
19014 TranslateModule,
19015 SelectionModule,
19016 OverlaysModule
19017 ];
19018
19019 // default moddle extensions the viewer is composed of
19020 Viewer.prototype._moddleExtensions = {};
19021
19022 /**
19023 * Adds the project logo to the diagram container as
19024 * required by the bpmn.io license.
19025 *
19026 * @see http://bpmn.io/license
19027 *
19028 * @param {Element} container
19029 */
19030 function addProjectLogo(container) {
19031 var img = BPMNIO_IMG;
19032
19033 var linkMarkup =
19034 '<a href="http://bpmn.io" ' +
19035 'target="_blank" ' +
19036 'class="bjs-powered-by" ' +
19037 'title="Powered by bpmn.io" ' +
19038 'style="position: absolute; bottom: 15px; right: 15px; z-index: 100">' +
19039 img +
19040 '</a>';
19041
19042 var linkElement = domify(linkMarkup);
19043
19044 container.appendChild(linkElement);
19045
19046 componentEvent.bind(linkElement, 'click', function(event) {
19047 open();
19048
19049 event.preventDefault();
19050 });
19051 }
19052
19053 /* </project-logo> */
19054
19055 return Viewer;
19056
19057}));