UNPKG

454 kBJavaScriptView Raw
1/*!
2 * bpmn-js - bpmn-navigated-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 function createCommonjsModule(fn, module) {
20 return module = { exports: {} }, fn(module, module.exports), module.exports;
21 }
22
23 var inherits_browser = createCommonjsModule(function (module) {
24 if (typeof Object.create === 'function') {
25 // implementation from standard node.js 'util' module
26 module.exports = function inherits(ctor, superCtor) {
27 ctor.super_ = superCtor;
28 ctor.prototype = Object.create(superCtor.prototype, {
29 constructor: {
30 value: ctor,
31 enumerable: false,
32 writable: true,
33 configurable: true
34 }
35 });
36 };
37 } else {
38 // old school shim for old browsers
39 module.exports = function inherits(ctor, superCtor) {
40 ctor.super_ = superCtor;
41 var TempCtor = function () {};
42 TempCtor.prototype = superCtor.prototype;
43 ctor.prototype = new TempCtor();
44 ctor.prototype.constructor = ctor;
45 };
46 }
47 });
48
49 /**
50 * Flatten array, one level deep.
51 *
52 * @param {Array<?>} arr
53 *
54 * @return {Array<?>}
55 */
56
57 var nativeToString = Object.prototype.toString;
58 var nativeHasOwnProperty = Object.prototype.hasOwnProperty;
59 function isUndefined(obj) {
60 return obj === undefined;
61 }
62 function isDefined(obj) {
63 return obj !== undefined;
64 }
65 function isArray(obj) {
66 return nativeToString.call(obj) === '[object Array]';
67 }
68 function isObject(obj) {
69 return nativeToString.call(obj) === '[object Object]';
70 }
71 function isNumber(obj) {
72 return nativeToString.call(obj) === '[object Number]';
73 }
74 function isFunction(obj) {
75 var tag = nativeToString.call(obj);
76 return tag === '[object Function]' || tag === '[object AsyncFunction]' || tag === '[object GeneratorFunction]' || tag === '[object AsyncGeneratorFunction]' || tag === '[object Proxy]';
77 }
78 function isString(obj) {
79 return nativeToString.call(obj) === '[object String]';
80 }
81 /**
82 * Return true, if target owns a property with the given key.
83 *
84 * @param {Object} target
85 * @param {String} key
86 *
87 * @return {Boolean}
88 */
89
90 function has(target, key) {
91 return nativeHasOwnProperty.call(target, key);
92 }
93
94 /**
95 * Find element in collection.
96 *
97 * @param {Array|Object} collection
98 * @param {Function|Object} matcher
99 *
100 * @return {Object}
101 */
102
103 function find(collection, matcher) {
104 matcher = toMatcher(matcher);
105 var match;
106 forEach(collection, function (val, key) {
107 if (matcher(val, key)) {
108 match = val;
109 return false;
110 }
111 });
112 return match;
113 }
114 /**
115 * Find element in collection.
116 *
117 * @param {Array|Object} collection
118 * @param {Function} matcher
119 *
120 * @return {Array} result
121 */
122
123 function filter(collection, matcher) {
124 var result = [];
125 forEach(collection, function (val, key) {
126 if (matcher(val, key)) {
127 result.push(val);
128 }
129 });
130 return result;
131 }
132 /**
133 * Iterate over collection; returning something
134 * (non-undefined) will stop iteration.
135 *
136 * @param {Array|Object} collection
137 * @param {Function} iterator
138 *
139 * @return {Object} return result that stopped the iteration
140 */
141
142 function forEach(collection, iterator) {
143 var val, result;
144
145 if (isUndefined(collection)) {
146 return;
147 }
148
149 var convertKey = isArray(collection) ? toNum : identity;
150
151 for (var key in collection) {
152 if (has(collection, key)) {
153 val = collection[key];
154 result = iterator(val, convertKey(key));
155
156 if (result === false) {
157 return val;
158 }
159 }
160 }
161 }
162 /**
163 * Reduce collection, returning a single result.
164 *
165 * @param {Object|Array} collection
166 * @param {Function} iterator
167 * @param {Any} result
168 *
169 * @return {Any} result returned from last iterator
170 */
171
172 function reduce(collection, iterator, result) {
173 forEach(collection, function (value, idx) {
174 result = iterator(result, value, idx);
175 });
176 return result;
177 }
178 /**
179 * Return true if every element in the collection
180 * matches the criteria.
181 *
182 * @param {Object|Array} collection
183 * @param {Function} matcher
184 *
185 * @return {Boolean}
186 */
187
188 function every(collection, matcher) {
189 return !!reduce(collection, function (matches, val, key) {
190 return matches && matcher(val, key);
191 }, true);
192 }
193 /**
194 * Return true if some elements in the collection
195 * match the criteria.
196 *
197 * @param {Object|Array} collection
198 * @param {Function} matcher
199 *
200 * @return {Boolean}
201 */
202
203 function some(collection, matcher) {
204 return !!find(collection, matcher);
205 }
206 /**
207 * Transform a collection into another collection
208 * by piping each member through the given fn.
209 *
210 * @param {Object|Array} collection
211 * @param {Function} fn
212 *
213 * @return {Array} transformed collection
214 */
215
216 function map(collection, fn) {
217 var result = [];
218 forEach(collection, function (val, key) {
219 result.push(fn(val, key));
220 });
221 return result;
222 }
223 /**
224 * Create an object pattern matcher.
225 *
226 * @example
227 *
228 * const matcher = matchPattern({ id: 1 });
229 *
230 * var element = find(elements, matcher);
231 *
232 * @param {Object} pattern
233 *
234 * @return {Function} matcherFn
235 */
236
237 function matchPattern(pattern) {
238 return function (el) {
239 return every(pattern, function (val, key) {
240 return el[key] === val;
241 });
242 };
243 }
244
245 function toMatcher(matcher) {
246 return isFunction(matcher) ? matcher : function (e) {
247 return e === matcher;
248 };
249 }
250
251 function identity(arg) {
252 return arg;
253 }
254
255 function toNum(arg) {
256 return Number(arg);
257 }
258
259 /**
260 * Debounce fn, calling it only once if
261 * the given time elapsed between calls.
262 *
263 * @param {Function} fn
264 * @param {Number} timeout
265 *
266 * @return {Function} debounced function
267 */
268 function debounce(fn, timeout) {
269 var timer;
270 var lastArgs;
271 var lastThis;
272 var lastNow;
273
274 function fire() {
275 var now = Date.now();
276 var scheduledDiff = lastNow + timeout - now;
277
278 if (scheduledDiff > 0) {
279 return schedule(scheduledDiff);
280 }
281
282 fn.apply(lastThis, lastArgs);
283 timer = lastNow = lastArgs = lastThis = undefined;
284 }
285
286 function schedule(timeout) {
287 timer = setTimeout(fire, timeout);
288 }
289
290 return function () {
291 lastNow = Date.now();
292
293 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
294 args[_key] = arguments[_key];
295 }
296
297 lastArgs = args;
298 lastThis = this; // ensure an execution is scheduled
299
300 if (!timer) {
301 schedule(timeout);
302 }
303 };
304 }
305 /**
306 * Bind function against target <this>.
307 *
308 * @param {Function} fn
309 * @param {Object} target
310 *
311 * @return {Function} bound function
312 */
313
314 function bind(fn, target) {
315 return fn.bind(target);
316 }
317
318 function _extends() {
319 _extends = Object.assign || function (target) {
320 for (var i = 1; i < arguments.length; i++) {
321 var source = arguments[i];
322
323 for (var key in source) {
324 if (Object.prototype.hasOwnProperty.call(source, key)) {
325 target[key] = source[key];
326 }
327 }
328 }
329
330 return target;
331 };
332
333 return _extends.apply(this, arguments);
334 }
335
336 /**
337 * Convenience wrapper for `Object.assign`.
338 *
339 * @param {Object} target
340 * @param {...Object} others
341 *
342 * @return {Object} the target
343 */
344
345 function assign(target) {
346 for (var _len = arguments.length, others = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
347 others[_key - 1] = arguments[_key];
348 }
349
350 return _extends.apply(void 0, [target].concat(others));
351 }
352 /**
353 * Pick given properties from the target object.
354 *
355 * @param {Object} target
356 * @param {Array} properties
357 *
358 * @return {Object} target
359 */
360
361 function pick(target, properties) {
362 var result = {};
363 var obj = Object(target);
364 forEach(properties, function (prop) {
365 if (prop in obj) {
366 result[prop] = target[prop];
367 }
368 });
369 return result;
370 }
371 /**
372 * Pick all target properties, excluding the given ones.
373 *
374 * @param {Object} target
375 * @param {Array} properties
376 *
377 * @return {Object} target
378 */
379
380 function omit(target, properties) {
381 var result = {};
382 var obj = Object(target);
383 forEach(obj, function (prop, key) {
384 if (properties.indexOf(key) === -1) {
385 result[key] = prop;
386 }
387 });
388 return result;
389 }
390
391 /**
392 * Set attribute `name` to `val`, or get attr `name`.
393 *
394 * @param {Element} el
395 * @param {String} name
396 * @param {String} [val]
397 * @api public
398 */
399 function attr(el, name, val) {
400 // get
401 if (arguments.length == 2) {
402 return el.getAttribute(name);
403 }
404
405 // remove
406 if (val === null) {
407 return el.removeAttribute(name);
408 }
409
410 // set
411 el.setAttribute(name, val);
412
413 return el;
414 }
415
416 var indexOf = [].indexOf;
417
418 var indexof = function(arr, obj){
419 if (indexOf) return arr.indexOf(obj);
420 for (var i = 0; i < arr.length; ++i) {
421 if (arr[i] === obj) return i;
422 }
423 return -1;
424 };
425
426 /**
427 * Taken from https://github.com/component/classes
428 *
429 * Without the component bits.
430 */
431
432 /**
433 * Whitespace regexp.
434 */
435
436 var re = /\s+/;
437
438 /**
439 * toString reference.
440 */
441
442 var toString = Object.prototype.toString;
443
444 /**
445 * Wrap `el` in a `ClassList`.
446 *
447 * @param {Element} el
448 * @return {ClassList}
449 * @api public
450 */
451
452 function classes(el) {
453 return new ClassList(el);
454 }
455
456 /**
457 * Initialize a new ClassList for `el`.
458 *
459 * @param {Element} el
460 * @api private
461 */
462
463 function ClassList(el) {
464 if (!el || !el.nodeType) {
465 throw new Error('A DOM element reference is required');
466 }
467 this.el = el;
468 this.list = el.classList;
469 }
470
471 /**
472 * Add class `name` if not already present.
473 *
474 * @param {String} name
475 * @return {ClassList}
476 * @api public
477 */
478
479 ClassList.prototype.add = function (name) {
480 // classList
481 if (this.list) {
482 this.list.add(name);
483 return this;
484 }
485
486 // fallback
487 var arr = this.array();
488 var i = indexof(arr, name);
489 if (!~i) arr.push(name);
490 this.el.className = arr.join(' ');
491 return this;
492 };
493
494 /**
495 * Remove class `name` when present, or
496 * pass a regular expression to remove
497 * any which match.
498 *
499 * @param {String|RegExp} name
500 * @return {ClassList}
501 * @api public
502 */
503
504 ClassList.prototype.remove = function (name) {
505 if ('[object RegExp]' == toString.call(name)) {
506 return this.removeMatching(name);
507 }
508
509 // classList
510 if (this.list) {
511 this.list.remove(name);
512 return this;
513 }
514
515 // fallback
516 var arr = this.array();
517 var i = indexof(arr, name);
518 if (~i) arr.splice(i, 1);
519 this.el.className = arr.join(' ');
520 return this;
521 };
522
523 /**
524 * Remove all classes matching `re`.
525 *
526 * @param {RegExp} re
527 * @return {ClassList}
528 * @api private
529 */
530
531 ClassList.prototype.removeMatching = function (re) {
532 var arr = this.array();
533 for (var i = 0; i < arr.length; i++) {
534 if (re.test(arr[i])) {
535 this.remove(arr[i]);
536 }
537 }
538 return this;
539 };
540
541 /**
542 * Toggle class `name`, can force state via `force`.
543 *
544 * For browsers that support classList, but do not support `force` yet,
545 * the mistake will be detected and corrected.
546 *
547 * @param {String} name
548 * @param {Boolean} force
549 * @return {ClassList}
550 * @api public
551 */
552
553 ClassList.prototype.toggle = function (name, force) {
554 // classList
555 if (this.list) {
556 if ('undefined' !== typeof force) {
557 if (force !== this.list.toggle(name, force)) {
558 this.list.toggle(name); // toggle again to correct
559 }
560 } else {
561 this.list.toggle(name);
562 }
563 return this;
564 }
565
566 // fallback
567 if ('undefined' !== typeof force) {
568 if (!force) {
569 this.remove(name);
570 } else {
571 this.add(name);
572 }
573 } else {
574 if (this.has(name)) {
575 this.remove(name);
576 } else {
577 this.add(name);
578 }
579 }
580
581 return this;
582 };
583
584 /**
585 * Return an array of classes.
586 *
587 * @return {Array}
588 * @api public
589 */
590
591 ClassList.prototype.array = function () {
592 var className = this.el.getAttribute('class') || '';
593 var str = className.replace(/^\s+|\s+$/g, '');
594 var arr = str.split(re);
595 if ('' === arr[0]) arr.shift();
596 return arr;
597 };
598
599 /**
600 * Check if class `name` is present.
601 *
602 * @param {String} name
603 * @return {ClassList}
604 * @api public
605 */
606
607 ClassList.prototype.has = ClassList.prototype.contains = function (name) {
608 return this.list ? this.list.contains(name) : !!~indexof(this.array(), name);
609 };
610
611 /**
612 * Remove all children from the given element.
613 */
614 function clear(el) {
615
616 var c;
617
618 while (el.childNodes.length) {
619 c = el.childNodes[0];
620 el.removeChild(c);
621 }
622
623 return el;
624 }
625
626 /**
627 * Element prototype.
628 */
629
630 var proto = Element.prototype;
631
632 /**
633 * Vendor function.
634 */
635
636 var vendor = proto.matchesSelector
637 || proto.webkitMatchesSelector
638 || proto.mozMatchesSelector
639 || proto.msMatchesSelector
640 || proto.oMatchesSelector;
641
642 /**
643 * Expose `match()`.
644 */
645
646 var matchesSelector = match;
647
648 /**
649 * Match `el` to `selector`.
650 *
651 * @param {Element} el
652 * @param {String} selector
653 * @return {Boolean}
654 * @api public
655 */
656
657 function match(el, selector) {
658 if (vendor) return vendor.call(el, selector);
659 var nodes = el.parentNode.querySelectorAll(selector);
660 for (var i = 0; i < nodes.length; ++i) {
661 if (nodes[i] == el) return true;
662 }
663 return false;
664 }
665
666 var closest = function (element, selector, checkYoSelf) {
667 var parent = checkYoSelf ? element : element.parentNode;
668
669 while (parent && parent !== document) {
670 if (matchesSelector(parent, selector)) return parent;
671 parent = parent.parentNode;
672 }
673 };
674
675 var bind$1 = window.addEventListener ? 'addEventListener' : 'attachEvent',
676 unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
677 prefix = bind$1 !== 'addEventListener' ? 'on' : '';
678
679 /**
680 * Bind `el` event `type` to `fn`.
681 *
682 * @param {Element} el
683 * @param {String} type
684 * @param {Function} fn
685 * @param {Boolean} capture
686 * @return {Function}
687 * @api public
688 */
689
690 var bind_1 = function(el, type, fn, capture){
691 el[bind$1](prefix + type, fn, capture || false);
692 return fn;
693 };
694
695 /**
696 * Unbind `el` event `type`'s callback `fn`.
697 *
698 * @param {Element} el
699 * @param {String} type
700 * @param {Function} fn
701 * @param {Boolean} capture
702 * @return {Function}
703 * @api public
704 */
705
706 var unbind_1 = function(el, type, fn, capture){
707 el[unbind](prefix + type, fn, capture || false);
708 return fn;
709 };
710
711 var componentEvent = {
712 bind: bind_1,
713 unbind: unbind_1
714 };
715
716 /**
717 * Module dependencies.
718 */
719
720
721
722 /**
723 * Delegate event `type` to `selector`
724 * and invoke `fn(e)`. A callback function
725 * is returned which may be passed to `.unbind()`.
726 *
727 * @param {Element} el
728 * @param {String} selector
729 * @param {String} type
730 * @param {Function} fn
731 * @param {Boolean} capture
732 * @return {Function}
733 * @api public
734 */
735
736 // Some events don't bubble, so we want to bind to the capture phase instead
737 // when delegating.
738 var forceCaptureEvents = ['focus', 'blur'];
739
740 var bind$1$1 = function(el, selector, type, fn, capture){
741 if (forceCaptureEvents.indexOf(type) !== -1) capture = true;
742
743 return componentEvent.bind(el, type, function(e){
744 var target = e.target || e.srcElement;
745 e.delegateTarget = closest(target, selector, true);
746 if (e.delegateTarget) fn.call(el, e);
747 }, capture);
748 };
749
750 /**
751 * Unbind event `type`'s callback `fn`.
752 *
753 * @param {Element} el
754 * @param {String} type
755 * @param {Function} fn
756 * @param {Boolean} capture
757 * @api public
758 */
759
760 var unbind$1 = function(el, type, fn, capture){
761 if (forceCaptureEvents.indexOf(type) !== -1) capture = true;
762
763 componentEvent.unbind(el, type, fn, capture);
764 };
765
766 var delegateEvents = {
767 bind: bind$1$1,
768 unbind: unbind$1
769 };
770
771 /**
772 * Expose `parse`.
773 */
774
775 var domify = parse;
776
777 /**
778 * Tests for browser support.
779 */
780
781 var innerHTMLBug = false;
782 var bugTestDiv;
783 if (typeof document !== 'undefined') {
784 bugTestDiv = document.createElement('div');
785 // Setup
786 bugTestDiv.innerHTML = ' <link/><table></table><a href="/a">a</a><input type="checkbox"/>';
787 // Make sure that link elements get serialized correctly by innerHTML
788 // This requires a wrapper element in IE
789 innerHTMLBug = !bugTestDiv.getElementsByTagName('link').length;
790 bugTestDiv = undefined;
791 }
792
793 /**
794 * Wrap map from jquery.
795 */
796
797 var map$1 = {
798 legend: [1, '<fieldset>', '</fieldset>'],
799 tr: [2, '<table><tbody>', '</tbody></table>'],
800 col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
801 // for script/link/style tags to work in IE6-8, you have to wrap
802 // in a div with a non-whitespace character in front, ha!
803 _default: innerHTMLBug ? [1, 'X<div>', '</div>'] : [0, '', '']
804 };
805
806 map$1.td =
807 map$1.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
808
809 map$1.option =
810 map$1.optgroup = [1, '<select multiple="multiple">', '</select>'];
811
812 map$1.thead =
813 map$1.tbody =
814 map$1.colgroup =
815 map$1.caption =
816 map$1.tfoot = [1, '<table>', '</table>'];
817
818 map$1.polyline =
819 map$1.ellipse =
820 map$1.polygon =
821 map$1.circle =
822 map$1.text =
823 map$1.line =
824 map$1.path =
825 map$1.rect =
826 map$1.g = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>'];
827
828 /**
829 * Parse `html` and return a DOM Node instance, which could be a TextNode,
830 * HTML DOM Node of some kind (<div> for example), or a DocumentFragment
831 * instance, depending on the contents of the `html` string.
832 *
833 * @param {String} html - HTML string to "domify"
834 * @param {Document} doc - The `document` instance to create the Node for
835 * @return {DOMNode} the TextNode, DOM Node, or DocumentFragment instance
836 * @api private
837 */
838
839 function parse(html, doc) {
840 if ('string' != typeof html) throw new TypeError('String expected');
841
842 // default to the global `document` object
843 if (!doc) doc = document;
844
845 // tag name
846 var m = /<([\w:]+)/.exec(html);
847 if (!m) return doc.createTextNode(html);
848
849 html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace
850
851 var tag = m[1];
852
853 // body support
854 if (tag == 'body') {
855 var el = doc.createElement('html');
856 el.innerHTML = html;
857 return el.removeChild(el.lastChild);
858 }
859
860 // wrap map
861 var wrap = map$1[tag] || map$1._default;
862 var depth = wrap[0];
863 var prefix = wrap[1];
864 var suffix = wrap[2];
865 var el = doc.createElement('div');
866 el.innerHTML = prefix + html + suffix;
867 while (depth--) el = el.lastChild;
868
869 // one element
870 if (el.firstChild == el.lastChild) {
871 return el.removeChild(el.firstChild);
872 }
873
874 // several elements
875 var fragment = doc.createDocumentFragment();
876 while (el.firstChild) {
877 fragment.appendChild(el.removeChild(el.firstChild));
878 }
879
880 return fragment;
881 }
882
883 var proto$1 = typeof Element !== 'undefined' ? Element.prototype : {};
884 var vendor$1 = proto$1.matches
885 || proto$1.matchesSelector
886 || proto$1.webkitMatchesSelector
887 || proto$1.mozMatchesSelector
888 || proto$1.msMatchesSelector
889 || proto$1.oMatchesSelector;
890
891 var matchesSelector$1 = match$1;
892
893 /**
894 * Match `el` to `selector`.
895 *
896 * @param {Element} el
897 * @param {String} selector
898 * @return {Boolean}
899 * @api public
900 */
901
902 function match$1(el, selector) {
903 if (!el || el.nodeType !== 1) return false;
904 if (vendor$1) return vendor$1.call(el, selector);
905 var nodes = el.parentNode.querySelectorAll(selector);
906 for (var i = 0; i < nodes.length; i++) {
907 if (nodes[i] == el) return true;
908 }
909 return false;
910 }
911
912 function query(selector, el) {
913 el = el || document;
914
915 return el.querySelector(selector);
916 }
917
918 function all(selector, el) {
919 el = el || document;
920
921 return el.querySelectorAll(selector);
922 }
923
924 function remove(el) {
925 el.parentNode && el.parentNode.removeChild(el);
926 }
927
928 function ensureImported(element, target) {
929
930 if (element.ownerDocument !== target.ownerDocument) {
931 try {
932 // may fail on webkit
933 return target.ownerDocument.importNode(element, true);
934 } catch (e) {
935 // ignore
936 }
937 }
938
939 return element;
940 }
941
942 /**
943 * appendTo utility
944 */
945
946 /**
947 * Append a node to a target element and return the appended node.
948 *
949 * @param {SVGElement} element
950 * @param {SVGElement} target
951 *
952 * @return {SVGElement} the appended node
953 */
954 function appendTo(element, target) {
955 return target.appendChild(ensureImported(element, target));
956 }
957
958 /**
959 * append utility
960 */
961
962 /**
963 * Append a node to an element
964 *
965 * @param {SVGElement} element
966 * @param {SVGElement} node
967 *
968 * @return {SVGElement} the element
969 */
970 function append(target, node) {
971 appendTo(node, target);
972 return target;
973 }
974
975 /**
976 * attribute accessor utility
977 */
978
979 var LENGTH_ATTR = 2;
980
981 var CSS_PROPERTIES = {
982 'alignment-baseline': 1,
983 'baseline-shift': 1,
984 'clip': 1,
985 'clip-path': 1,
986 'clip-rule': 1,
987 'color': 1,
988 'color-interpolation': 1,
989 'color-interpolation-filters': 1,
990 'color-profile': 1,
991 'color-rendering': 1,
992 'cursor': 1,
993 'direction': 1,
994 'display': 1,
995 'dominant-baseline': 1,
996 'enable-background': 1,
997 'fill': 1,
998 'fill-opacity': 1,
999 'fill-rule': 1,
1000 'filter': 1,
1001 'flood-color': 1,
1002 'flood-opacity': 1,
1003 'font': 1,
1004 'font-family': 1,
1005 'font-size': LENGTH_ATTR,
1006 'font-size-adjust': 1,
1007 'font-stretch': 1,
1008 'font-style': 1,
1009 'font-variant': 1,
1010 'font-weight': 1,
1011 'glyph-orientation-horizontal': 1,
1012 'glyph-orientation-vertical': 1,
1013 'image-rendering': 1,
1014 'kerning': 1,
1015 'letter-spacing': 1,
1016 'lighting-color': 1,
1017 'marker': 1,
1018 'marker-end': 1,
1019 'marker-mid': 1,
1020 'marker-start': 1,
1021 'mask': 1,
1022 'opacity': 1,
1023 'overflow': 1,
1024 'pointer-events': 1,
1025 'shape-rendering': 1,
1026 'stop-color': 1,
1027 'stop-opacity': 1,
1028 'stroke': 1,
1029 'stroke-dasharray': 1,
1030 'stroke-dashoffset': 1,
1031 'stroke-linecap': 1,
1032 'stroke-linejoin': 1,
1033 'stroke-miterlimit': 1,
1034 'stroke-opacity': 1,
1035 'stroke-width': LENGTH_ATTR,
1036 'text-anchor': 1,
1037 'text-decoration': 1,
1038 'text-rendering': 1,
1039 'unicode-bidi': 1,
1040 'visibility': 1,
1041 'word-spacing': 1,
1042 'writing-mode': 1
1043 };
1044
1045
1046 function getAttribute(node, name) {
1047 if (CSS_PROPERTIES[name]) {
1048 return node.style[name];
1049 } else {
1050 return node.getAttributeNS(null, name);
1051 }
1052 }
1053
1054 function setAttribute(node, name, value) {
1055 var hyphenated = name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
1056
1057 var type = CSS_PROPERTIES[hyphenated];
1058
1059 if (type) {
1060 // append pixel unit, unless present
1061 if (type === LENGTH_ATTR && typeof value === 'number') {
1062 value = String(value) + 'px';
1063 }
1064
1065 node.style[hyphenated] = value;
1066 } else {
1067 node.setAttributeNS(null, name, value);
1068 }
1069 }
1070
1071 function setAttributes(node, attrs) {
1072
1073 var names = Object.keys(attrs), i, name;
1074
1075 for (i = 0, name; (name = names[i]); i++) {
1076 setAttribute(node, name, attrs[name]);
1077 }
1078 }
1079
1080 /**
1081 * Gets or sets raw attributes on a node.
1082 *
1083 * @param {SVGElement} node
1084 * @param {Object} [attrs]
1085 * @param {String} [name]
1086 * @param {String} [value]
1087 *
1088 * @return {String}
1089 */
1090 function attr$1(node, name, value) {
1091 if (typeof name === 'string') {
1092 if (value !== undefined) {
1093 setAttribute(node, name, value);
1094 } else {
1095 return getAttribute(node, name);
1096 }
1097 } else {
1098 setAttributes(node, name);
1099 }
1100
1101 return node;
1102 }
1103
1104 /**
1105 * Clear utility
1106 */
1107 function index(arr, obj) {
1108 if (arr.indexOf) {
1109 return arr.indexOf(obj);
1110 }
1111
1112
1113 for (var i = 0; i < arr.length; ++i) {
1114 if (arr[i] === obj) {
1115 return i;
1116 }
1117 }
1118
1119 return -1;
1120 }
1121
1122 var re$1 = /\s+/;
1123
1124 var toString$1 = Object.prototype.toString;
1125
1126 function defined(o) {
1127 return typeof o !== 'undefined';
1128 }
1129
1130 /**
1131 * Wrap `el` in a `ClassList`.
1132 *
1133 * @param {Element} el
1134 * @return {ClassList}
1135 * @api public
1136 */
1137
1138 function classes$1(el) {
1139 return new ClassList$1(el);
1140 }
1141
1142 function ClassList$1(el) {
1143 if (!el || !el.nodeType) {
1144 throw new Error('A DOM element reference is required');
1145 }
1146 this.el = el;
1147 this.list = el.classList;
1148 }
1149
1150 /**
1151 * Add class `name` if not already present.
1152 *
1153 * @param {String} name
1154 * @return {ClassList}
1155 * @api public
1156 */
1157
1158 ClassList$1.prototype.add = function(name) {
1159
1160 // classList
1161 if (this.list) {
1162 this.list.add(name);
1163 return this;
1164 }
1165
1166 // fallback
1167 var arr = this.array();
1168 var i = index(arr, name);
1169 if (!~i) {
1170 arr.push(name);
1171 }
1172
1173 if (defined(this.el.className.baseVal)) {
1174 this.el.className.baseVal = arr.join(' ');
1175 } else {
1176 this.el.className = arr.join(' ');
1177 }
1178
1179 return this;
1180 };
1181
1182 /**
1183 * Remove class `name` when present, or
1184 * pass a regular expression to remove
1185 * any which match.
1186 *
1187 * @param {String|RegExp} name
1188 * @return {ClassList}
1189 * @api public
1190 */
1191
1192 ClassList$1.prototype.remove = function(name) {
1193 if ('[object RegExp]' === toString$1.call(name)) {
1194 return this.removeMatching(name);
1195 }
1196
1197 // classList
1198 if (this.list) {
1199 this.list.remove(name);
1200 return this;
1201 }
1202
1203 // fallback
1204 var arr = this.array();
1205 var i = index(arr, name);
1206 if (~i) {
1207 arr.splice(i, 1);
1208 }
1209 this.el.className.baseVal = arr.join(' ');
1210 return this;
1211 };
1212
1213 /**
1214 * Remove all classes matching `re`.
1215 *
1216 * @param {RegExp} re
1217 * @return {ClassList}
1218 * @api private
1219 */
1220
1221 ClassList$1.prototype.removeMatching = function(re) {
1222 var arr = this.array();
1223 for (var i = 0; i < arr.length; i++) {
1224 if (re.test(arr[i])) {
1225 this.remove(arr[i]);
1226 }
1227 }
1228 return this;
1229 };
1230
1231 /**
1232 * Toggle class `name`, can force state via `force`.
1233 *
1234 * For browsers that support classList, but do not support `force` yet,
1235 * the mistake will be detected and corrected.
1236 *
1237 * @param {String} name
1238 * @param {Boolean} force
1239 * @return {ClassList}
1240 * @api public
1241 */
1242
1243 ClassList$1.prototype.toggle = function(name, force) {
1244 // classList
1245 if (this.list) {
1246 if (defined(force)) {
1247 if (force !== this.list.toggle(name, force)) {
1248 this.list.toggle(name); // toggle again to correct
1249 }
1250 } else {
1251 this.list.toggle(name);
1252 }
1253 return this;
1254 }
1255
1256 // fallback
1257 if (defined(force)) {
1258 if (!force) {
1259 this.remove(name);
1260 } else {
1261 this.add(name);
1262 }
1263 } else {
1264 if (this.has(name)) {
1265 this.remove(name);
1266 } else {
1267 this.add(name);
1268 }
1269 }
1270
1271 return this;
1272 };
1273
1274 /**
1275 * Return an array of classes.
1276 *
1277 * @return {Array}
1278 * @api public
1279 */
1280
1281 ClassList$1.prototype.array = function() {
1282 var className = this.el.getAttribute('class') || '';
1283 var str = className.replace(/^\s+|\s+$/g, '');
1284 var arr = str.split(re$1);
1285 if ('' === arr[0]) {
1286 arr.shift();
1287 }
1288 return arr;
1289 };
1290
1291 /**
1292 * Check if class `name` is present.
1293 *
1294 * @param {String} name
1295 * @return {ClassList}
1296 * @api public
1297 */
1298
1299 ClassList$1.prototype.has =
1300 ClassList$1.prototype.contains = function(name) {
1301 return (
1302 this.list ?
1303 this.list.contains(name) :
1304 !! ~index(this.array(), name)
1305 );
1306 };
1307
1308 function remove$1(element) {
1309 var parent = element.parentNode;
1310
1311 if (parent) {
1312 parent.removeChild(element);
1313 }
1314
1315 return element;
1316 }
1317
1318 /**
1319 * Clear utility
1320 */
1321
1322 /**
1323 * Removes all children from the given element
1324 *
1325 * @param {DOMElement} element
1326 * @return {DOMElement} the element (for chaining)
1327 */
1328 function clear$1(element) {
1329 var child;
1330
1331 while ((child = element.firstChild)) {
1332 remove$1(child);
1333 }
1334
1335 return element;
1336 }
1337
1338 var ns = {
1339 svg: 'http://www.w3.org/2000/svg'
1340 };
1341
1342 /**
1343 * DOM parsing utility
1344 */
1345
1346 var SVG_START = '<svg xmlns="' + ns.svg + '"';
1347
1348 function parse$1(svg) {
1349
1350 var unwrap = false;
1351
1352 // ensure we import a valid svg document
1353 if (svg.substring(0, 4) === '<svg') {
1354 if (svg.indexOf(ns.svg) === -1) {
1355 svg = SVG_START + svg.substring(4);
1356 }
1357 } else {
1358 // namespace svg
1359 svg = SVG_START + '>' + svg + '</svg>';
1360 unwrap = true;
1361 }
1362
1363 var parsed = parseDocument(svg);
1364
1365 if (!unwrap) {
1366 return parsed;
1367 }
1368
1369 var fragment = document.createDocumentFragment();
1370
1371 var parent = parsed.firstChild;
1372
1373 while (parent.firstChild) {
1374 fragment.appendChild(parent.firstChild);
1375 }
1376
1377 return fragment;
1378 }
1379
1380 function parseDocument(svg) {
1381
1382 var parser;
1383
1384 // parse
1385 parser = new DOMParser();
1386 parser.async = false;
1387
1388 return parser.parseFromString(svg, 'text/xml');
1389 }
1390
1391 /**
1392 * Create utility for SVG elements
1393 */
1394
1395
1396 /**
1397 * Create a specific type from name or SVG markup.
1398 *
1399 * @param {String} name the name or markup of the element
1400 * @param {Object} [attrs] attributes to set on the element
1401 *
1402 * @returns {SVGElement}
1403 */
1404 function create(name, attrs) {
1405 var element;
1406
1407 if (name.charAt(0) === '<') {
1408 element = parse$1(name).firstChild;
1409 element = document.importNode(element, true);
1410 } else {
1411 element = document.createElementNS(ns.svg, name);
1412 }
1413
1414 if (attrs) {
1415 attr$1(element, attrs);
1416 }
1417
1418 return element;
1419 }
1420
1421 /**
1422 * Geometry helpers
1423 */
1424
1425 // fake node used to instantiate svg geometry elements
1426 var node = create('svg');
1427
1428 function extend(object, props) {
1429 var i, k, keys = Object.keys(props);
1430
1431 for (i = 0; (k = keys[i]); i++) {
1432 object[k] = props[k];
1433 }
1434
1435 return object;
1436 }
1437
1438 /**
1439 * Create matrix via args.
1440 *
1441 * @example
1442 *
1443 * createMatrix({ a: 1, b: 1 });
1444 * createMatrix();
1445 * createMatrix(1, 2, 0, 0, 30, 20);
1446 *
1447 * @return {SVGMatrix}
1448 */
1449 function createMatrix(a, b, c, d, e, f) {
1450 var matrix = node.createSVGMatrix();
1451
1452 switch (arguments.length) {
1453 case 0:
1454 return matrix;
1455 case 1:
1456 return extend(matrix, a);
1457 case 6:
1458 return extend(matrix, {
1459 a: a,
1460 b: b,
1461 c: c,
1462 d: d,
1463 e: e,
1464 f: f
1465 });
1466 }
1467 }
1468
1469 function createTransform(matrix) {
1470 if (matrix) {
1471 return node.createSVGTransformFromMatrix(matrix);
1472 } else {
1473 return node.createSVGTransform();
1474 }
1475 }
1476
1477 /**
1478 * Serialization util
1479 */
1480
1481 var TEXT_ENTITIES = /([&<>]{1})/g;
1482 var ATTR_ENTITIES = /([\n\r"]{1})/g;
1483
1484 var ENTITY_REPLACEMENT = {
1485 '&': '&amp;',
1486 '<': '&lt;',
1487 '>': '&gt;',
1488 '"': '\''
1489 };
1490
1491 function escape(str, pattern) {
1492
1493 function replaceFn(match, entity) {
1494 return ENTITY_REPLACEMENT[entity] || entity;
1495 }
1496
1497 return str.replace(pattern, replaceFn);
1498 }
1499
1500 function serialize(node, output) {
1501
1502 var i, len, attrMap, attrNode, childNodes;
1503
1504 switch (node.nodeType) {
1505 // TEXT
1506 case 3:
1507 // replace special XML characters
1508 output.push(escape(node.textContent, TEXT_ENTITIES));
1509 break;
1510
1511 // ELEMENT
1512 case 1:
1513 output.push('<', node.tagName);
1514
1515 if (node.hasAttributes()) {
1516 attrMap = node.attributes;
1517 for (i = 0, len = attrMap.length; i < len; ++i) {
1518 attrNode = attrMap.item(i);
1519 output.push(' ', attrNode.name, '="', escape(attrNode.value, ATTR_ENTITIES), '"');
1520 }
1521 }
1522
1523 if (node.hasChildNodes()) {
1524 output.push('>');
1525 childNodes = node.childNodes;
1526 for (i = 0, len = childNodes.length; i < len; ++i) {
1527 serialize(childNodes.item(i), output);
1528 }
1529 output.push('</', node.tagName, '>');
1530 } else {
1531 output.push('/>');
1532 }
1533 break;
1534
1535 // COMMENT
1536 case 8:
1537 output.push('<!--', escape(node.nodeValue, TEXT_ENTITIES), '-->');
1538 break;
1539
1540 // CDATA
1541 case 4:
1542 output.push('<![CDATA[', node.nodeValue, ']]>');
1543 break;
1544
1545 default:
1546 throw new Error('unable to handle node ' + node.nodeType);
1547 }
1548
1549 return output;
1550 }
1551
1552 /**
1553 * innerHTML like functionality for SVG elements.
1554 * based on innerSVG (https://code.google.com/p/innersvg)
1555 */
1556
1557
1558 function set(element, svg) {
1559
1560 var parsed = parse$1(svg);
1561
1562 // clear element contents
1563 clear$1(element);
1564
1565 if (!svg) {
1566 return;
1567 }
1568
1569 if (!isFragment(parsed)) {
1570 // extract <svg> from parsed document
1571 parsed = parsed.documentElement;
1572 }
1573
1574 var nodes = slice(parsed.childNodes);
1575
1576 // import + append each node
1577 for (var i = 0; i < nodes.length; i++) {
1578 appendTo(nodes[i], element);
1579 }
1580
1581 }
1582
1583 function get(element) {
1584 var child = element.firstChild,
1585 output = [];
1586
1587 while (child) {
1588 serialize(child, output);
1589 child = child.nextSibling;
1590 }
1591
1592 return output.join('');
1593 }
1594
1595 function isFragment(node) {
1596 return node.nodeName === '#document-fragment';
1597 }
1598
1599 function innerSVG(element, svg) {
1600
1601 if (svg !== undefined) {
1602
1603 try {
1604 set(element, svg);
1605 } catch (e) {
1606 throw new Error('error parsing SVG: ' + e.message);
1607 }
1608
1609 return element;
1610 } else {
1611 return get(element);
1612 }
1613 }
1614
1615
1616 function slice(arr) {
1617 return Array.prototype.slice.call(arr);
1618 }
1619
1620 /**
1621 * transform accessor utility
1622 */
1623
1624 function wrapMatrix(transformList, transform) {
1625 if (transform instanceof SVGMatrix) {
1626 return transformList.createSVGTransformFromMatrix(transform);
1627 }
1628
1629 return transform;
1630 }
1631
1632
1633 function setTransforms(transformList, transforms) {
1634 var i, t;
1635
1636 transformList.clear();
1637
1638 for (i = 0; (t = transforms[i]); i++) {
1639 transformList.appendItem(wrapMatrix(transformList, t));
1640 }
1641 }
1642
1643 /**
1644 * Get or set the transforms on the given node.
1645 *
1646 * @param {SVGElement} node
1647 * @param {SVGTransform|SVGMatrix|Array<SVGTransform|SVGMatrix>} [transforms]
1648 *
1649 * @return {SVGTransform} the consolidated transform
1650 */
1651 function transform(node, transforms) {
1652 var transformList = node.transform.baseVal;
1653
1654 if (transforms) {
1655
1656 if (!Array.isArray(transforms)) {
1657 transforms = [ transforms ];
1658 }
1659
1660 setTransforms(transformList, transforms);
1661 }
1662
1663 return transformList.consolidate();
1664 }
1665
1666 var CLASS_PATTERN = /^class /;
1667
1668 function isClass(fn) {
1669 return CLASS_PATTERN.test(fn.toString());
1670 }
1671
1672 function isArray$1(obj) {
1673 return Object.prototype.toString.call(obj) === '[object Array]';
1674 }
1675
1676 function annotate() {
1677 var args = Array.prototype.slice.call(arguments);
1678
1679 if (args.length === 1 && isArray$1(args[0])) {
1680 args = args[0];
1681 }
1682
1683 var fn = args.pop();
1684
1685 fn.$inject = args;
1686
1687 return fn;
1688 }
1689
1690 // Current limitations:
1691 // - can't put into "function arg" comments
1692 // function /* (no parenthesis like this) */ (){}
1693 // function abc( /* xx (no parenthesis like this) */ a, b) {}
1694 //
1695 // Just put the comment before function or inside:
1696 // /* (((this is fine))) */ function(a, b) {}
1697 // function abc(a) { /* (((this is fine))) */}
1698 //
1699 // - can't reliably auto-annotate constructor; we'll match the
1700 // first constructor(...) pattern found which may be the one
1701 // of a nested class, too.
1702
1703 var CONSTRUCTOR_ARGS = /constructor\s*[^(]*\(\s*([^)]*)\)/m;
1704 var FN_ARGS = /^function\s*[^(]*\(\s*([^)]*)\)/m;
1705 var FN_ARG = /\/\*([^*]*)\*\//m;
1706
1707 function parse$2(fn) {
1708
1709 if (typeof fn !== 'function') {
1710 throw new Error('Cannot annotate "' + fn + '". Expected a function!');
1711 }
1712
1713 var match = fn.toString().match(isClass(fn) ? CONSTRUCTOR_ARGS : FN_ARGS);
1714
1715 // may parse class without constructor
1716 if (!match) {
1717 return [];
1718 }
1719
1720 return match[1] && match[1].split(',').map(function (arg) {
1721 match = arg.match(FN_ARG);
1722 return match ? match[1].trim() : arg.trim();
1723 }) || [];
1724 }
1725
1726 function Module() {
1727 var providers = [];
1728
1729 this.factory = function (name, factory) {
1730 providers.push([name, 'factory', factory]);
1731 return this;
1732 };
1733
1734 this.value = function (name, value) {
1735 providers.push([name, 'value', value]);
1736 return this;
1737 };
1738
1739 this.type = function (name, type) {
1740 providers.push([name, 'type', type]);
1741 return this;
1742 };
1743
1744 this.forEach = function (iterator) {
1745 providers.forEach(iterator);
1746 };
1747 }
1748
1749 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; };
1750
1751 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); } }
1752
1753 function Injector(modules, parent) {
1754 parent = parent || {
1755 get: function get(name, strict) {
1756 currentlyResolving.push(name);
1757
1758 if (strict === false) {
1759 return null;
1760 } else {
1761 throw error('No provider for "' + name + '"!');
1762 }
1763 }
1764 };
1765
1766 var currentlyResolving = [];
1767 var providers = this._providers = Object.create(parent._providers || null);
1768 var instances = this._instances = Object.create(null);
1769
1770 var self = instances.injector = this;
1771
1772 var error = function error(msg) {
1773 var stack = currentlyResolving.join(' -> ');
1774 currentlyResolving.length = 0;
1775 return new Error(stack ? msg + ' (Resolving: ' + stack + ')' : msg);
1776 };
1777
1778 /**
1779 * Return a named service.
1780 *
1781 * @param {String} name
1782 * @param {Boolean} [strict=true] if false, resolve missing services to null
1783 *
1784 * @return {Object}
1785 */
1786 var get = function get(name, strict) {
1787 if (!providers[name] && name.indexOf('.') !== -1) {
1788 var parts = name.split('.');
1789 var pivot = get(parts.shift());
1790
1791 while (parts.length) {
1792 pivot = pivot[parts.shift()];
1793 }
1794
1795 return pivot;
1796 }
1797
1798 if (hasProp(instances, name)) {
1799 return instances[name];
1800 }
1801
1802 if (hasProp(providers, name)) {
1803 if (currentlyResolving.indexOf(name) !== -1) {
1804 currentlyResolving.push(name);
1805 throw error('Cannot resolve circular dependency!');
1806 }
1807
1808 currentlyResolving.push(name);
1809 instances[name] = providers[name][0](providers[name][1]);
1810 currentlyResolving.pop();
1811
1812 return instances[name];
1813 }
1814
1815 return parent.get(name, strict);
1816 };
1817
1818 var fnDef = function fnDef(fn) {
1819 var locals = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1820
1821 if (typeof fn !== 'function') {
1822 if (isArray$1(fn)) {
1823 fn = annotate(fn.slice());
1824 } else {
1825 throw new Error('Cannot invoke "' + fn + '". Expected a function!');
1826 }
1827 }
1828
1829 var inject = fn.$inject || parse$2(fn);
1830 var dependencies = inject.map(function (dep) {
1831 if (hasProp(locals, dep)) {
1832 return locals[dep];
1833 } else {
1834 return get(dep);
1835 }
1836 });
1837
1838 return {
1839 fn: fn,
1840 dependencies: dependencies
1841 };
1842 };
1843
1844 var instantiate = function instantiate(Type) {
1845 var _fnDef = fnDef(Type),
1846 dependencies = _fnDef.dependencies,
1847 fn = _fnDef.fn;
1848
1849 return new (Function.prototype.bind.apply(fn, [null].concat(_toConsumableArray(dependencies))))();
1850 };
1851
1852 var invoke = function invoke(func, context, locals) {
1853 var _fnDef2 = fnDef(func, locals),
1854 dependencies = _fnDef2.dependencies,
1855 fn = _fnDef2.fn;
1856
1857 return fn.call.apply(fn, [context].concat(_toConsumableArray(dependencies)));
1858 };
1859
1860 var createPrivateInjectorFactory = function createPrivateInjectorFactory(privateChildInjector) {
1861 return annotate(function (key) {
1862 return privateChildInjector.get(key);
1863 });
1864 };
1865
1866 var createChild = function createChild(modules, forceNewInstances) {
1867 if (forceNewInstances && forceNewInstances.length) {
1868 var fromParentModule = Object.create(null);
1869 var matchedScopes = Object.create(null);
1870
1871 var privateInjectorsCache = [];
1872 var privateChildInjectors = [];
1873 var privateChildFactories = [];
1874
1875 var provider;
1876 var cacheIdx;
1877 var privateChildInjector;
1878 var privateChildInjectorFactory;
1879 for (var name in providers) {
1880 provider = providers[name];
1881
1882 if (forceNewInstances.indexOf(name) !== -1) {
1883 if (provider[2] === 'private') {
1884 cacheIdx = privateInjectorsCache.indexOf(provider[3]);
1885 if (cacheIdx === -1) {
1886 privateChildInjector = provider[3].createChild([], forceNewInstances);
1887 privateChildInjectorFactory = createPrivateInjectorFactory(privateChildInjector);
1888 privateInjectorsCache.push(provider[3]);
1889 privateChildInjectors.push(privateChildInjector);
1890 privateChildFactories.push(privateChildInjectorFactory);
1891 fromParentModule[name] = [privateChildInjectorFactory, name, 'private', privateChildInjector];
1892 } else {
1893 fromParentModule[name] = [privateChildFactories[cacheIdx], name, 'private', privateChildInjectors[cacheIdx]];
1894 }
1895 } else {
1896 fromParentModule[name] = [provider[2], provider[1]];
1897 }
1898 matchedScopes[name] = true;
1899 }
1900
1901 if ((provider[2] === 'factory' || provider[2] === 'type') && provider[1].$scope) {
1902 /* jshint -W083 */
1903 forceNewInstances.forEach(function (scope) {
1904 if (provider[1].$scope.indexOf(scope) !== -1) {
1905 fromParentModule[name] = [provider[2], provider[1]];
1906 matchedScopes[scope] = true;
1907 }
1908 });
1909 }
1910 }
1911
1912 forceNewInstances.forEach(function (scope) {
1913 if (!matchedScopes[scope]) {
1914 throw new Error('No provider for "' + scope + '". Cannot use provider from the parent!');
1915 }
1916 });
1917
1918 modules.unshift(fromParentModule);
1919 }
1920
1921 return new Injector(modules, self);
1922 };
1923
1924 var factoryMap = {
1925 factory: invoke,
1926 type: instantiate,
1927 value: function value(_value) {
1928 return _value;
1929 }
1930 };
1931
1932 modules.forEach(function (module) {
1933
1934 function arrayUnwrap(type, value) {
1935 if (type !== 'value' && isArray$1(value)) {
1936 value = annotate(value.slice());
1937 }
1938
1939 return value;
1940 }
1941
1942 // TODO(vojta): handle wrong inputs (modules)
1943 if (module instanceof Module) {
1944 module.forEach(function (provider) {
1945 var name = provider[0];
1946 var type = provider[1];
1947 var value = provider[2];
1948
1949 providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
1950 });
1951 } else if ((typeof module === 'undefined' ? 'undefined' : _typeof(module)) === 'object') {
1952 if (module.__exports__) {
1953 var clonedModule = Object.keys(module).reduce(function (m, key) {
1954 if (key.substring(0, 2) !== '__') {
1955 m[key] = module[key];
1956 }
1957 return m;
1958 }, Object.create(null));
1959
1960 var privateInjector = new Injector((module.__modules__ || []).concat([clonedModule]), self);
1961 var getFromPrivateInjector = annotate(function (key) {
1962 return privateInjector.get(key);
1963 });
1964 module.__exports__.forEach(function (key) {
1965 providers[key] = [getFromPrivateInjector, key, 'private', privateInjector];
1966 });
1967 } else {
1968 Object.keys(module).forEach(function (name) {
1969 if (module[name][2] === 'private') {
1970 providers[name] = module[name];
1971 return;
1972 }
1973
1974 var type = module[name][0];
1975 var value = module[name][1];
1976
1977 providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
1978 });
1979 }
1980 }
1981 });
1982
1983 // public API
1984 this.get = get;
1985 this.invoke = invoke;
1986 this.instantiate = instantiate;
1987 this.createChild = createChild;
1988 }
1989
1990 // helpers /////////////////
1991
1992 function hasProp(obj, prop) {
1993 return Object.hasOwnProperty.call(obj, prop);
1994 }
1995
1996 var DEFAULT_RENDER_PRIORITY = 1000;
1997
1998 /**
1999 * The base implementation of shape and connection renderers.
2000 *
2001 * @param {EventBus} eventBus
2002 * @param {Number} [renderPriority=1000]
2003 */
2004 function BaseRenderer(eventBus, renderPriority) {
2005 var self = this;
2006
2007 renderPriority = renderPriority || DEFAULT_RENDER_PRIORITY;
2008
2009 eventBus.on([ 'render.shape', 'render.connection' ], renderPriority, function(evt, context) {
2010 var type = evt.type,
2011 element = context.element,
2012 visuals = context.gfx;
2013
2014 if (self.canRender(element)) {
2015 if (type === 'render.shape') {
2016 return self.drawShape(visuals, element);
2017 } else {
2018 return self.drawConnection(visuals, element);
2019 }
2020 }
2021 });
2022
2023 eventBus.on([ 'render.getShapePath', 'render.getConnectionPath'], renderPriority, function(evt, element) {
2024 if (self.canRender(element)) {
2025 if (evt.type === 'render.getShapePath') {
2026 return self.getShapePath(element);
2027 } else {
2028 return self.getConnectionPath(element);
2029 }
2030 }
2031 });
2032 }
2033
2034 /**
2035 * Should check whether *this* renderer can render
2036 * the element/connection.
2037 *
2038 * @param {element} element
2039 *
2040 * @returns {Boolean}
2041 */
2042 BaseRenderer.prototype.canRender = function() {};
2043
2044 /**
2045 * Provides the shape's snap svg element to be drawn on the `canvas`.
2046 *
2047 * @param {djs.Graphics} visuals
2048 * @param {Shape} shape
2049 *
2050 * @returns {Snap.svg} [returns a Snap.svg paper element ]
2051 */
2052 BaseRenderer.prototype.drawShape = function() {};
2053
2054 /**
2055 * Provides the shape's snap svg element to be drawn on the `canvas`.
2056 *
2057 * @param {djs.Graphics} visuals
2058 * @param {Connection} connection
2059 *
2060 * @returns {Snap.svg} [returns a Snap.svg paper element ]
2061 */
2062 BaseRenderer.prototype.drawConnection = function() {};
2063
2064 /**
2065 * Gets the SVG path of a shape that represents it's visual bounds.
2066 *
2067 * @param {Shape} shape
2068 *
2069 * @return {string} svg path
2070 */
2071 BaseRenderer.prototype.getShapePath = function() {};
2072
2073 /**
2074 * Gets the SVG path of a connection that represents it's visual bounds.
2075 *
2076 * @param {Connection} connection
2077 *
2078 * @return {string} svg path
2079 */
2080 BaseRenderer.prototype.getConnectionPath = function() {};
2081
2082 function componentsToPath(elements) {
2083 return elements.join(',').replace(/,?([A-z]),?/g, '$1');
2084 }
2085
2086 function toSVGPoints(points) {
2087 var result = '';
2088
2089 for (var i = 0, p; (p = points[i]); i++) {
2090 result += p.x + ',' + p.y + ' ';
2091 }
2092
2093 return result;
2094 }
2095
2096 function createLine(points, attrs) {
2097
2098 var line = create('polyline');
2099 attr$1(line, { points: toSVGPoints(points) });
2100
2101 if (attrs) {
2102 attr$1(line, attrs);
2103 }
2104
2105 return line;
2106 }
2107
2108 function updateLine(gfx, points) {
2109 attr$1(gfx, { points: toSVGPoints(points) });
2110
2111 return gfx;
2112 }
2113
2114 /**
2115 * Returns the surrounding bbox for all elements in
2116 * the array or the element primitive.
2117 *
2118 * @param {Array<djs.model.Shape>|djs.model.Shape} elements
2119 * @param {Boolean} stopRecursion
2120 */
2121 function getBBox(elements, stopRecursion) {
2122
2123 stopRecursion = !!stopRecursion;
2124 if (!isArray(elements)) {
2125 elements = [elements];
2126 }
2127
2128 var minX,
2129 minY,
2130 maxX,
2131 maxY;
2132
2133 forEach(elements, function(element) {
2134
2135 // If element is a connection the bbox must be computed first
2136 var bbox = element;
2137 if (element.waypoints && !stopRecursion) {
2138 bbox = getBBox(element.waypoints, true);
2139 }
2140
2141 var x = bbox.x,
2142 y = bbox.y,
2143 height = bbox.height || 0,
2144 width = bbox.width || 0;
2145
2146 if (x < minX || minX === undefined) {
2147 minX = x;
2148 }
2149 if (y < minY || minY === undefined) {
2150 minY = y;
2151 }
2152
2153 if ((x + width) > maxX || maxX === undefined) {
2154 maxX = x + width;
2155 }
2156 if ((y + height) > maxY || maxY === undefined) {
2157 maxY = y + height;
2158 }
2159 });
2160
2161 return {
2162 x: minX,
2163 y: minY,
2164 height: maxY - minY,
2165 width: maxX - minX
2166 };
2167 }
2168
2169
2170 function getType(element) {
2171
2172 if ('waypoints' in element) {
2173 return 'connection';
2174 }
2175
2176 if ('x' in element) {
2177 return 'shape';
2178 }
2179
2180 return 'root';
2181 }
2182
2183 function isFrameElement(element) {
2184
2185 return !!(element && element.isFrame);
2186 }
2187
2188 // apply default renderer with lowest possible priority
2189 // so that it only kicks in if noone else could render
2190 var DEFAULT_RENDER_PRIORITY$1 = 1;
2191
2192 /**
2193 * The default renderer used for shapes and connections.
2194 *
2195 * @param {EventBus} eventBus
2196 * @param {Styles} styles
2197 */
2198 function DefaultRenderer(eventBus, styles) {
2199
2200 //
2201 BaseRenderer.call(this, eventBus, DEFAULT_RENDER_PRIORITY$1);
2202
2203 this.CONNECTION_STYLE = styles.style([ 'no-fill' ], { strokeWidth: 5, stroke: 'fuchsia' });
2204 this.SHAPE_STYLE = styles.style({ fill: 'white', stroke: 'fuchsia', strokeWidth: 2 });
2205 this.FRAME_STYLE = styles.style([ 'no-fill' ], { stroke: 'fuchsia', strokeDasharray: 4, strokeWidth: 2 });
2206 }
2207
2208 inherits_browser(DefaultRenderer, BaseRenderer);
2209
2210
2211 DefaultRenderer.prototype.canRender = function() {
2212 return true;
2213 };
2214
2215 DefaultRenderer.prototype.drawShape = function drawShape(visuals, element) {
2216 var rect = create('rect');
2217
2218 attr$1(rect, {
2219 x: 0,
2220 y: 0,
2221 width: element.width || 0,
2222 height: element.height || 0
2223 });
2224
2225 if (isFrameElement(element)) {
2226 attr$1(rect, this.FRAME_STYLE);
2227 } else {
2228 attr$1(rect, this.SHAPE_STYLE);
2229 }
2230
2231 append(visuals, rect);
2232
2233 return rect;
2234 };
2235
2236 DefaultRenderer.prototype.drawConnection = function drawConnection(visuals, connection) {
2237
2238 var line = createLine(connection.waypoints, this.CONNECTION_STYLE);
2239 append(visuals, line);
2240
2241 return line;
2242 };
2243
2244 DefaultRenderer.prototype.getShapePath = function getShapePath(shape) {
2245
2246 var x = shape.x,
2247 y = shape.y,
2248 width = shape.width,
2249 height = shape.height;
2250
2251 var shapePath = [
2252 ['M', x, y],
2253 ['l', width, 0],
2254 ['l', 0, height],
2255 ['l', -width, 0],
2256 ['z']
2257 ];
2258
2259 return componentsToPath(shapePath);
2260 };
2261
2262 DefaultRenderer.prototype.getConnectionPath = function getConnectionPath(connection) {
2263 var waypoints = connection.waypoints;
2264
2265 var idx, point, connectionPath = [];
2266
2267 for (idx = 0; (point = waypoints[idx]); idx++) {
2268
2269 // take invisible docking into account
2270 // when creating the path
2271 point = point.original || point;
2272
2273 connectionPath.push([ idx === 0 ? 'M' : 'L', point.x, point.y ]);
2274 }
2275
2276 return componentsToPath(connectionPath);
2277 };
2278
2279
2280 DefaultRenderer.$inject = [ 'eventBus', 'styles' ];
2281
2282 /**
2283 * A component that manages shape styles
2284 */
2285 function Styles() {
2286
2287 var defaultTraits = {
2288
2289 'no-fill': {
2290 fill: 'none'
2291 },
2292 'no-border': {
2293 strokeOpacity: 0.0
2294 },
2295 'no-events': {
2296 pointerEvents: 'none'
2297 }
2298 };
2299
2300 var self = this;
2301
2302 /**
2303 * Builds a style definition from a className, a list of traits and an object of additional attributes.
2304 *
2305 * @param {String} className
2306 * @param {Array<String>} traits
2307 * @param {Object} additionalAttrs
2308 *
2309 * @return {Object} the style defintion
2310 */
2311 this.cls = function(className, traits, additionalAttrs) {
2312 var attrs = this.style(traits, additionalAttrs);
2313
2314 return assign(attrs, { 'class': className });
2315 };
2316
2317 /**
2318 * Builds a style definition from a list of traits and an object of additional attributes.
2319 *
2320 * @param {Array<String>} traits
2321 * @param {Object} additionalAttrs
2322 *
2323 * @return {Object} the style defintion
2324 */
2325 this.style = function(traits, additionalAttrs) {
2326
2327 if (!isArray(traits) && !additionalAttrs) {
2328 additionalAttrs = traits;
2329 traits = [];
2330 }
2331
2332 var attrs = reduce(traits, function(attrs, t) {
2333 return assign(attrs, defaultTraits[t] || {});
2334 }, {});
2335
2336 return additionalAttrs ? assign(attrs, additionalAttrs) : attrs;
2337 };
2338
2339 this.computeStyle = function(custom, traits, defaultStyles) {
2340 if (!isArray(traits)) {
2341 defaultStyles = traits;
2342 traits = [];
2343 }
2344
2345 return self.style(traits || [], assign({}, defaultStyles, custom || {}));
2346 };
2347 }
2348
2349 var DrawModule = {
2350 __init__: [ 'defaultRenderer' ],
2351 defaultRenderer: [ 'type', DefaultRenderer ],
2352 styles: [ 'type', Styles ]
2353 };
2354
2355 /**
2356 * Failsafe remove an element from a collection
2357 *
2358 * @param {Array<Object>} [collection]
2359 * @param {Object} [element]
2360 *
2361 * @return {Number} the previous index of the element
2362 */
2363 function remove$2(collection, element) {
2364
2365 if (!collection || !element) {
2366 return -1;
2367 }
2368
2369 var idx = collection.indexOf(element);
2370
2371 if (idx !== -1) {
2372 collection.splice(idx, 1);
2373 }
2374
2375 return idx;
2376 }
2377
2378 /**
2379 * Fail save add an element to the given connection, ensuring
2380 * it does not yet exist.
2381 *
2382 * @param {Array<Object>} collection
2383 * @param {Object} element
2384 * @param {Number} idx
2385 */
2386 function add(collection, element, idx) {
2387
2388 if (!collection || !element) {
2389 return;
2390 }
2391
2392 if (typeof idx !== 'number') {
2393 idx = -1;
2394 }
2395
2396 var currentIdx = collection.indexOf(element);
2397
2398 if (currentIdx !== -1) {
2399
2400 if (currentIdx === idx) {
2401
2402 // nothing to do, position has not changed
2403 return;
2404 } else {
2405
2406 if (idx !== -1) {
2407
2408 // remove from current position
2409 collection.splice(currentIdx, 1);
2410 } else {
2411
2412 // already exists in collection
2413 return;
2414 }
2415 }
2416 }
2417
2418 if (idx !== -1) {
2419
2420 // insert at specified position
2421 collection.splice(idx, 0, element);
2422 } else {
2423
2424 // push to end
2425 collection.push(element);
2426 }
2427 }
2428
2429 function round(number, resolution) {
2430 return Math.round(number * resolution) / resolution;
2431 }
2432
2433 function ensurePx(number) {
2434 return isNumber(number) ? number + 'px' : number;
2435 }
2436
2437 /**
2438 * Creates a HTML container element for a SVG element with
2439 * the given configuration
2440 *
2441 * @param {Object} options
2442 * @return {HTMLElement} the container element
2443 */
2444 function createContainer(options) {
2445
2446 options = assign({}, { width: '100%', height: '100%' }, options);
2447
2448 var container = options.container || document.body;
2449
2450 // create a <div> around the svg element with the respective size
2451 // this way we can always get the correct container size
2452 // (this is impossible for <svg> elements at the moment)
2453 var parent = document.createElement('div');
2454 parent.setAttribute('class', 'djs-container');
2455
2456 assign(parent.style, {
2457 position: 'relative',
2458 overflow: 'hidden',
2459 width: ensurePx(options.width),
2460 height: ensurePx(options.height)
2461 });
2462
2463 container.appendChild(parent);
2464
2465 return parent;
2466 }
2467
2468 function createGroup(parent, cls, childIndex) {
2469 var group = create('g');
2470 classes$1(group).add(cls);
2471
2472 var index = childIndex !== undefined ? childIndex : parent.childNodes.length - 1;
2473
2474 // must ensure second argument is node or _null_
2475 // cf. https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore
2476 parent.insertBefore(group, parent.childNodes[index] || null);
2477
2478 return group;
2479 }
2480
2481 var BASE_LAYER = 'base';
2482
2483
2484 var REQUIRED_MODEL_ATTRS = {
2485 shape: [ 'x', 'y', 'width', 'height' ],
2486 connection: [ 'waypoints' ]
2487 };
2488
2489 /**
2490 * The main drawing canvas.
2491 *
2492 * @class
2493 * @constructor
2494 *
2495 * @emits Canvas#canvas.init
2496 *
2497 * @param {Object} config
2498 * @param {EventBus} eventBus
2499 * @param {GraphicsFactory} graphicsFactory
2500 * @param {ElementRegistry} elementRegistry
2501 */
2502 function Canvas(config, eventBus, graphicsFactory, elementRegistry) {
2503
2504 this._eventBus = eventBus;
2505 this._elementRegistry = elementRegistry;
2506 this._graphicsFactory = graphicsFactory;
2507
2508 this._init(config || {});
2509 }
2510
2511 Canvas.$inject = [
2512 'config.canvas',
2513 'eventBus',
2514 'graphicsFactory',
2515 'elementRegistry'
2516 ];
2517
2518
2519 Canvas.prototype._init = function(config) {
2520
2521 var eventBus = this._eventBus;
2522
2523 // Creates a <svg> element that is wrapped into a <div>.
2524 // This way we are always able to correctly figure out the size of the svg element
2525 // by querying the parent node.
2526 //
2527 // (It is not possible to get the size of a svg element cross browser @ 2014-04-01)
2528 //
2529 // <div class="djs-container" style="width: {desired-width}, height: {desired-height}">
2530 // <svg width="100%" height="100%">
2531 // ...
2532 // </svg>
2533 // </div>
2534
2535 // html container
2536 var container = this._container = createContainer(config);
2537
2538 var svg = this._svg = create('svg');
2539 attr$1(svg, { width: '100%', height: '100%' });
2540
2541 append(container, svg);
2542
2543 var viewport = this._viewport = createGroup(svg, 'viewport');
2544
2545 this._layers = {};
2546
2547 // debounce canvas.viewbox.changed events
2548 // for smoother diagram interaction
2549 if (config.deferUpdate !== false) {
2550 this._viewboxChanged = debounce(bind(this._viewboxChanged, this), 300);
2551 }
2552
2553 eventBus.on('diagram.init', function() {
2554
2555 /**
2556 * An event indicating that the canvas is ready to be drawn on.
2557 *
2558 * @memberOf Canvas
2559 *
2560 * @event canvas.init
2561 *
2562 * @type {Object}
2563 * @property {SVGElement} svg the created svg element
2564 * @property {SVGElement} viewport the direct parent of diagram elements and shapes
2565 */
2566 eventBus.fire('canvas.init', {
2567 svg: svg,
2568 viewport: viewport
2569 });
2570
2571 }, this);
2572
2573 // reset viewbox on shape changes to
2574 // recompute the viewbox
2575 eventBus.on([
2576 'shape.added',
2577 'connection.added',
2578 'shape.removed',
2579 'connection.removed',
2580 'elements.changed'
2581 ], function() {
2582 delete this._cachedViewbox;
2583 }, this);
2584
2585 eventBus.on('diagram.destroy', 500, this._destroy, this);
2586 eventBus.on('diagram.clear', 500, this._clear, this);
2587 };
2588
2589 Canvas.prototype._destroy = function(emit) {
2590 this._eventBus.fire('canvas.destroy', {
2591 svg: this._svg,
2592 viewport: this._viewport
2593 });
2594
2595 var parent = this._container.parentNode;
2596
2597 if (parent) {
2598 parent.removeChild(this._container);
2599 }
2600
2601 delete this._svg;
2602 delete this._container;
2603 delete this._layers;
2604 delete this._rootElement;
2605 delete this._viewport;
2606 };
2607
2608 Canvas.prototype._clear = function() {
2609
2610 var self = this;
2611
2612 var allElements = this._elementRegistry.getAll();
2613
2614 // remove all elements
2615 allElements.forEach(function(element) {
2616 var type = getType(element);
2617
2618 if (type === 'root') {
2619 self.setRootElement(null, true);
2620 } else {
2621 self._removeElement(element, type);
2622 }
2623 });
2624
2625 // force recomputation of view box
2626 delete this._cachedViewbox;
2627 };
2628
2629 /**
2630 * Returns the default layer on which
2631 * all elements are drawn.
2632 *
2633 * @returns {SVGElement}
2634 */
2635 Canvas.prototype.getDefaultLayer = function() {
2636 return this.getLayer(BASE_LAYER, 0);
2637 };
2638
2639 /**
2640 * Returns a layer that is used to draw elements
2641 * or annotations on it.
2642 *
2643 * Non-existing layers retrieved through this method
2644 * will be created. During creation, the optional index
2645 * may be used to create layers below or above existing layers.
2646 * A layer with a certain index is always created above all
2647 * existing layers with the same index.
2648 *
2649 * @param {String} name
2650 * @param {Number} index
2651 *
2652 * @returns {SVGElement}
2653 */
2654 Canvas.prototype.getLayer = function(name, index) {
2655
2656 if (!name) {
2657 throw new Error('must specify a name');
2658 }
2659
2660 var layer = this._layers[name];
2661
2662 if (!layer) {
2663 layer = this._layers[name] = this._createLayer(name, index);
2664 }
2665
2666 // throw an error if layer creation / retrival is
2667 // requested on different index
2668 if (typeof index !== 'undefined' && layer.index !== index) {
2669 throw new Error('layer <' + name + '> already created at index <' + index + '>');
2670 }
2671
2672 return layer.group;
2673 };
2674
2675 /**
2676 * Creates a given layer and returns it.
2677 *
2678 * @param {String} name
2679 * @param {Number} [index=0]
2680 *
2681 * @return {Object} layer descriptor with { index, group: SVGGroup }
2682 */
2683 Canvas.prototype._createLayer = function(name, index) {
2684
2685 if (!index) {
2686 index = 0;
2687 }
2688
2689 var childIndex = reduce(this._layers, function(childIndex, layer) {
2690 if (index >= layer.index) {
2691 childIndex++;
2692 }
2693
2694 return childIndex;
2695 }, 0);
2696
2697 return {
2698 group: createGroup(this._viewport, 'layer-' + name, childIndex),
2699 index: index
2700 };
2701
2702 };
2703
2704 /**
2705 * Returns the html element that encloses the
2706 * drawing canvas.
2707 *
2708 * @return {DOMNode}
2709 */
2710 Canvas.prototype.getContainer = function() {
2711 return this._container;
2712 };
2713
2714
2715 // markers //////////////////////
2716
2717 Canvas.prototype._updateMarker = function(element, marker, add) {
2718 var container;
2719
2720 if (!element.id) {
2721 element = this._elementRegistry.get(element);
2722 }
2723
2724 // we need to access all
2725 container = this._elementRegistry._elements[element.id];
2726
2727 if (!container) {
2728 return;
2729 }
2730
2731 forEach([ container.gfx, container.secondaryGfx ], function(gfx) {
2732 if (gfx) {
2733
2734 // invoke either addClass or removeClass based on mode
2735 if (add) {
2736 classes$1(gfx).add(marker);
2737 } else {
2738 classes$1(gfx).remove(marker);
2739 }
2740 }
2741 });
2742
2743 /**
2744 * An event indicating that a marker has been updated for an element
2745 *
2746 * @event element.marker.update
2747 * @type {Object}
2748 * @property {djs.model.Element} element the shape
2749 * @property {Object} gfx the graphical representation of the shape
2750 * @property {String} marker
2751 * @property {Boolean} add true if the marker was added, false if it got removed
2752 */
2753 this._eventBus.fire('element.marker.update', { element: element, gfx: container.gfx, marker: marker, add: !!add });
2754 };
2755
2756
2757 /**
2758 * Adds a marker to an element (basically a css class).
2759 *
2760 * Fires the element.marker.update event, making it possible to
2761 * integrate extension into the marker life-cycle, too.
2762 *
2763 * @example
2764 * canvas.addMarker('foo', 'some-marker');
2765 *
2766 * var fooGfx = canvas.getGraphics('foo');
2767 *
2768 * fooGfx; // <g class="... some-marker"> ... </g>
2769 *
2770 * @param {String|djs.model.Base} element
2771 * @param {String} marker
2772 */
2773 Canvas.prototype.addMarker = function(element, marker) {
2774 this._updateMarker(element, marker, true);
2775 };
2776
2777
2778 /**
2779 * Remove a marker from an element.
2780 *
2781 * Fires the element.marker.update event, making it possible to
2782 * integrate extension into the marker life-cycle, too.
2783 *
2784 * @param {String|djs.model.Base} element
2785 * @param {String} marker
2786 */
2787 Canvas.prototype.removeMarker = function(element, marker) {
2788 this._updateMarker(element, marker, false);
2789 };
2790
2791 /**
2792 * Check the existence of a marker on element.
2793 *
2794 * @param {String|djs.model.Base} element
2795 * @param {String} marker
2796 */
2797 Canvas.prototype.hasMarker = function(element, marker) {
2798 if (!element.id) {
2799 element = this._elementRegistry.get(element);
2800 }
2801
2802 var gfx = this.getGraphics(element);
2803
2804 return classes$1(gfx).has(marker);
2805 };
2806
2807 /**
2808 * Toggles a marker on an element.
2809 *
2810 * Fires the element.marker.update event, making it possible to
2811 * integrate extension into the marker life-cycle, too.
2812 *
2813 * @param {String|djs.model.Base} element
2814 * @param {String} marker
2815 */
2816 Canvas.prototype.toggleMarker = function(element, marker) {
2817 if (this.hasMarker(element, marker)) {
2818 this.removeMarker(element, marker);
2819 } else {
2820 this.addMarker(element, marker);
2821 }
2822 };
2823
2824 Canvas.prototype.getRootElement = function() {
2825 if (!this._rootElement) {
2826 this.setRootElement({ id: '__implicitroot', children: [] });
2827 }
2828
2829 return this._rootElement;
2830 };
2831
2832
2833
2834 // root element handling //////////////////////
2835
2836 /**
2837 * Sets a given element as the new root element for the canvas
2838 * and returns the new root element.
2839 *
2840 * @param {Object|djs.model.Root} element
2841 * @param {Boolean} [override] whether to override the current root element, if any
2842 *
2843 * @return {Object|djs.model.Root} new root element
2844 */
2845 Canvas.prototype.setRootElement = function(element, override) {
2846
2847 if (element) {
2848 this._ensureValid('root', element);
2849 }
2850
2851 var currentRoot = this._rootElement,
2852 elementRegistry = this._elementRegistry,
2853 eventBus = this._eventBus;
2854
2855 if (currentRoot) {
2856 if (!override) {
2857 throw new Error('rootElement already set, need to specify override');
2858 }
2859
2860 // simulate element remove event sequence
2861 eventBus.fire('root.remove', { element: currentRoot });
2862 eventBus.fire('root.removed', { element: currentRoot });
2863
2864 elementRegistry.remove(currentRoot);
2865 }
2866
2867 if (element) {
2868 var gfx = this.getDefaultLayer();
2869
2870 // resemble element add event sequence
2871 eventBus.fire('root.add', { element: element });
2872
2873 elementRegistry.add(element, gfx, this._svg);
2874
2875 eventBus.fire('root.added', { element: element, gfx: gfx });
2876 }
2877
2878 this._rootElement = element;
2879
2880 return element;
2881 };
2882
2883
2884
2885 // add functionality //////////////////////
2886
2887 Canvas.prototype._ensureValid = function(type, element) {
2888 if (!element.id) {
2889 throw new Error('element must have an id');
2890 }
2891
2892 if (this._elementRegistry.get(element.id)) {
2893 throw new Error('element with id ' + element.id + ' already exists');
2894 }
2895
2896 var requiredAttrs = REQUIRED_MODEL_ATTRS[type];
2897
2898 var valid = every(requiredAttrs, function(attr) {
2899 return typeof element[attr] !== 'undefined';
2900 });
2901
2902 if (!valid) {
2903 throw new Error(
2904 'must supply { ' + requiredAttrs.join(', ') + ' } with ' + type);
2905 }
2906 };
2907
2908 Canvas.prototype._setParent = function(element, parent, parentIndex) {
2909 add(parent.children, element, parentIndex);
2910 element.parent = parent;
2911 };
2912
2913 /**
2914 * Adds an element to the canvas.
2915 *
2916 * This wires the parent <-> child relationship between the element and
2917 * a explicitly specified parent or an implicit root element.
2918 *
2919 * During add it emits the events
2920 *
2921 * * <{type}.add> (element, parent)
2922 * * <{type}.added> (element, gfx)
2923 *
2924 * Extensions may hook into these events to perform their magic.
2925 *
2926 * @param {String} type
2927 * @param {Object|djs.model.Base} element
2928 * @param {Object|djs.model.Base} [parent]
2929 * @param {Number} [parentIndex]
2930 *
2931 * @return {Object|djs.model.Base} the added element
2932 */
2933 Canvas.prototype._addElement = function(type, element, parent, parentIndex) {
2934
2935 parent = parent || this.getRootElement();
2936
2937 var eventBus = this._eventBus,
2938 graphicsFactory = this._graphicsFactory;
2939
2940 this._ensureValid(type, element);
2941
2942 eventBus.fire(type + '.add', { element: element, parent: parent });
2943
2944 this._setParent(element, parent, parentIndex);
2945
2946 // create graphics
2947 var gfx = graphicsFactory.create(type, element, parentIndex);
2948
2949 this._elementRegistry.add(element, gfx);
2950
2951 // update its visual
2952 graphicsFactory.update(type, element, gfx);
2953
2954 eventBus.fire(type + '.added', { element: element, gfx: gfx });
2955
2956 return element;
2957 };
2958
2959 /**
2960 * Adds a shape to the canvas
2961 *
2962 * @param {Object|djs.model.Shape} shape to add to the diagram
2963 * @param {djs.model.Base} [parent]
2964 * @param {Number} [parentIndex]
2965 *
2966 * @return {djs.model.Shape} the added shape
2967 */
2968 Canvas.prototype.addShape = function(shape, parent, parentIndex) {
2969 return this._addElement('shape', shape, parent, parentIndex);
2970 };
2971
2972 /**
2973 * Adds a connection to the canvas
2974 *
2975 * @param {Object|djs.model.Connection} connection to add to the diagram
2976 * @param {djs.model.Base} [parent]
2977 * @param {Number} [parentIndex]
2978 *
2979 * @return {djs.model.Connection} the added connection
2980 */
2981 Canvas.prototype.addConnection = function(connection, parent, parentIndex) {
2982 return this._addElement('connection', connection, parent, parentIndex);
2983 };
2984
2985
2986 /**
2987 * Internal remove element
2988 */
2989 Canvas.prototype._removeElement = function(element, type) {
2990
2991 var elementRegistry = this._elementRegistry,
2992 graphicsFactory = this._graphicsFactory,
2993 eventBus = this._eventBus;
2994
2995 element = elementRegistry.get(element.id || element);
2996
2997 if (!element) {
2998
2999 // element was removed already
3000 return;
3001 }
3002
3003 eventBus.fire(type + '.remove', { element: element });
3004
3005 graphicsFactory.remove(element);
3006
3007 // unset parent <-> child relationship
3008 remove$2(element.parent && element.parent.children, element);
3009 element.parent = null;
3010
3011 eventBus.fire(type + '.removed', { element: element });
3012
3013 elementRegistry.remove(element);
3014
3015 return element;
3016 };
3017
3018
3019 /**
3020 * Removes a shape from the canvas
3021 *
3022 * @param {String|djs.model.Shape} shape or shape id to be removed
3023 *
3024 * @return {djs.model.Shape} the removed shape
3025 */
3026 Canvas.prototype.removeShape = function(shape) {
3027
3028 /**
3029 * An event indicating that a shape is about to be removed from the canvas.
3030 *
3031 * @memberOf Canvas
3032 *
3033 * @event shape.remove
3034 * @type {Object}
3035 * @property {djs.model.Shape} element the shape descriptor
3036 * @property {Object} gfx the graphical representation of the shape
3037 */
3038
3039 /**
3040 * An event indicating that a shape has been removed from the canvas.
3041 *
3042 * @memberOf Canvas
3043 *
3044 * @event shape.removed
3045 * @type {Object}
3046 * @property {djs.model.Shape} element the shape descriptor
3047 * @property {Object} gfx the graphical representation of the shape
3048 */
3049 return this._removeElement(shape, 'shape');
3050 };
3051
3052
3053 /**
3054 * Removes a connection from the canvas
3055 *
3056 * @param {String|djs.model.Connection} connection or connection id to be removed
3057 *
3058 * @return {djs.model.Connection} the removed connection
3059 */
3060 Canvas.prototype.removeConnection = function(connection) {
3061
3062 /**
3063 * An event indicating that a connection is about to be removed from the canvas.
3064 *
3065 * @memberOf Canvas
3066 *
3067 * @event connection.remove
3068 * @type {Object}
3069 * @property {djs.model.Connection} element the connection descriptor
3070 * @property {Object} gfx the graphical representation of the connection
3071 */
3072
3073 /**
3074 * An event indicating that a connection has been removed from the canvas.
3075 *
3076 * @memberOf Canvas
3077 *
3078 * @event connection.removed
3079 * @type {Object}
3080 * @property {djs.model.Connection} element the connection descriptor
3081 * @property {Object} gfx the graphical representation of the connection
3082 */
3083 return this._removeElement(connection, 'connection');
3084 };
3085
3086
3087 /**
3088 * Return the graphical object underlaying a certain diagram element
3089 *
3090 * @param {String|djs.model.Base} element descriptor of the element
3091 * @param {Boolean} [secondary=false] whether to return the secondary connected element
3092 *
3093 * @return {SVGElement}
3094 */
3095 Canvas.prototype.getGraphics = function(element, secondary) {
3096 return this._elementRegistry.getGraphics(element, secondary);
3097 };
3098
3099
3100 /**
3101 * Perform a viewbox update via a given change function.
3102 *
3103 * @param {Function} changeFn
3104 */
3105 Canvas.prototype._changeViewbox = function(changeFn) {
3106
3107 // notify others of the upcoming viewbox change
3108 this._eventBus.fire('canvas.viewbox.changing');
3109
3110 // perform actual change
3111 changeFn.apply(this);
3112
3113 // reset the cached viewbox so that
3114 // a new get operation on viewbox or zoom
3115 // triggers a viewbox re-computation
3116 this._cachedViewbox = null;
3117
3118 // notify others of the change; this step
3119 // may or may not be debounced
3120 this._viewboxChanged();
3121 };
3122
3123 Canvas.prototype._viewboxChanged = function() {
3124 this._eventBus.fire('canvas.viewbox.changed', { viewbox: this.viewbox() });
3125 };
3126
3127
3128 /**
3129 * Gets or sets the view box of the canvas, i.e. the
3130 * area that is currently displayed.
3131 *
3132 * The getter may return a cached viewbox (if it is currently
3133 * changing). To force a recomputation, pass `false` as the first argument.
3134 *
3135 * @example
3136 *
3137 * canvas.viewbox({ x: 100, y: 100, width: 500, height: 500 })
3138 *
3139 * // sets the visible area of the diagram to (100|100) -> (600|100)
3140 * // and and scales it according to the diagram width
3141 *
3142 * var viewbox = canvas.viewbox(); // pass `false` to force recomputing the box.
3143 *
3144 * console.log(viewbox);
3145 * // {
3146 * // inner: Dimensions,
3147 * // outer: Dimensions,
3148 * // scale,
3149 * // x, y,
3150 * // width, height
3151 * // }
3152 *
3153 * // if the current diagram is zoomed and scrolled, you may reset it to the
3154 * // default zoom via this method, too:
3155 *
3156 * var zoomedAndScrolledViewbox = canvas.viewbox();
3157 *
3158 * canvas.viewbox({
3159 * x: 0,
3160 * y: 0,
3161 * width: zoomedAndScrolledViewbox.outer.width,
3162 * height: zoomedAndScrolledViewbox.outer.height
3163 * });
3164 *
3165 * @param {Object} [box] the new view box to set
3166 * @param {Number} box.x the top left X coordinate of the canvas visible in view box
3167 * @param {Number} box.y the top left Y coordinate of the canvas visible in view box
3168 * @param {Number} box.width the visible width
3169 * @param {Number} box.height
3170 *
3171 * @return {Object} the current view box
3172 */
3173 Canvas.prototype.viewbox = function(box) {
3174
3175 if (box === undefined && this._cachedViewbox) {
3176 return this._cachedViewbox;
3177 }
3178
3179 var viewport = this._viewport,
3180 innerBox,
3181 outerBox = this.getSize(),
3182 matrix,
3183 transform$1,
3184 scale,
3185 x, y;
3186
3187 if (!box) {
3188
3189 // compute the inner box based on the
3190 // diagrams default layer. This allows us to exclude
3191 // external components, such as overlays
3192 innerBox = this.getDefaultLayer().getBBox();
3193
3194 transform$1 = transform(viewport);
3195 matrix = transform$1 ? transform$1.matrix : createMatrix();
3196 scale = round(matrix.a, 1000);
3197
3198 x = round(-matrix.e || 0, 1000);
3199 y = round(-matrix.f || 0, 1000);
3200
3201 box = this._cachedViewbox = {
3202 x: x ? x / scale : 0,
3203 y: y ? y / scale : 0,
3204 width: outerBox.width / scale,
3205 height: outerBox.height / scale,
3206 scale: scale,
3207 inner: {
3208 width: innerBox.width,
3209 height: innerBox.height,
3210 x: innerBox.x,
3211 y: innerBox.y
3212 },
3213 outer: outerBox
3214 };
3215
3216 return box;
3217 } else {
3218
3219 this._changeViewbox(function() {
3220 scale = Math.min(outerBox.width / box.width, outerBox.height / box.height);
3221
3222 var matrix = this._svg.createSVGMatrix()
3223 .scale(scale)
3224 .translate(-box.x, -box.y);
3225
3226 transform(viewport, matrix);
3227 });
3228 }
3229
3230 return box;
3231 };
3232
3233
3234 /**
3235 * Gets or sets the scroll of the canvas.
3236 *
3237 * @param {Object} [delta] the new scroll to apply.
3238 *
3239 * @param {Number} [delta.dx]
3240 * @param {Number} [delta.dy]
3241 */
3242 Canvas.prototype.scroll = function(delta) {
3243
3244 var node = this._viewport;
3245 var matrix = node.getCTM();
3246
3247 if (delta) {
3248 this._changeViewbox(function() {
3249 delta = assign({ dx: 0, dy: 0 }, delta || {});
3250
3251 matrix = this._svg.createSVGMatrix().translate(delta.dx, delta.dy).multiply(matrix);
3252
3253 setCTM(node, matrix);
3254 });
3255 }
3256
3257 return { x: matrix.e, y: matrix.f };
3258 };
3259
3260
3261 /**
3262 * Gets or sets the current zoom of the canvas, optionally zooming
3263 * to the specified position.
3264 *
3265 * The getter may return a cached zoom level. Call it with `false` as
3266 * the first argument to force recomputation of the current level.
3267 *
3268 * @param {String|Number} [newScale] the new zoom level, either a number, i.e. 0.9,
3269 * or `fit-viewport` to adjust the size to fit the current viewport
3270 * @param {String|Point} [center] the reference point { x: .., y: ..} to zoom to, 'auto' to zoom into mid or null
3271 *
3272 * @return {Number} the current scale
3273 */
3274 Canvas.prototype.zoom = function(newScale, center) {
3275
3276 if (!newScale) {
3277 return this.viewbox(newScale).scale;
3278 }
3279
3280 if (newScale === 'fit-viewport') {
3281 return this._fitViewport(center);
3282 }
3283
3284 var outer,
3285 matrix;
3286
3287 this._changeViewbox(function() {
3288
3289 if (typeof center !== 'object') {
3290 outer = this.viewbox().outer;
3291
3292 center = {
3293 x: outer.width / 2,
3294 y: outer.height / 2
3295 };
3296 }
3297
3298 matrix = this._setZoom(newScale, center);
3299 });
3300
3301 return round(matrix.a, 1000);
3302 };
3303
3304 function setCTM(node, m) {
3305 var mstr = 'matrix(' + m.a + ',' + m.b + ',' + m.c + ',' + m.d + ',' + m.e + ',' + m.f + ')';
3306 node.setAttribute('transform', mstr);
3307 }
3308
3309 Canvas.prototype._fitViewport = function(center) {
3310
3311 var vbox = this.viewbox(),
3312 outer = vbox.outer,
3313 inner = vbox.inner,
3314 newScale,
3315 newViewbox;
3316
3317 // display the complete diagram without zooming in.
3318 // instead of relying on internal zoom, we perform a
3319 // hard reset on the canvas viewbox to realize this
3320 //
3321 // if diagram does not need to be zoomed in, we focus it around
3322 // the diagram origin instead
3323
3324 if (inner.x >= 0 &&
3325 inner.y >= 0 &&
3326 inner.x + inner.width <= outer.width &&
3327 inner.y + inner.height <= outer.height &&
3328 !center) {
3329
3330 newViewbox = {
3331 x: 0,
3332 y: 0,
3333 width: Math.max(inner.width + inner.x, outer.width),
3334 height: Math.max(inner.height + inner.y, outer.height)
3335 };
3336 } else {
3337
3338 newScale = Math.min(1, outer.width / inner.width, outer.height / inner.height);
3339 newViewbox = {
3340 x: inner.x + (center ? inner.width / 2 - outer.width / newScale / 2 : 0),
3341 y: inner.y + (center ? inner.height / 2 - outer.height / newScale / 2 : 0),
3342 width: outer.width / newScale,
3343 height: outer.height / newScale
3344 };
3345 }
3346
3347 this.viewbox(newViewbox);
3348
3349 return this.viewbox(false).scale;
3350 };
3351
3352
3353 Canvas.prototype._setZoom = function(scale, center) {
3354
3355 var svg = this._svg,
3356 viewport = this._viewport;
3357
3358 var matrix = svg.createSVGMatrix();
3359 var point = svg.createSVGPoint();
3360
3361 var centerPoint,
3362 originalPoint,
3363 currentMatrix,
3364 scaleMatrix,
3365 newMatrix;
3366
3367 currentMatrix = viewport.getCTM();
3368
3369 var currentScale = currentMatrix.a;
3370
3371 if (center) {
3372 centerPoint = assign(point, center);
3373
3374 // revert applied viewport transformations
3375 originalPoint = centerPoint.matrixTransform(currentMatrix.inverse());
3376
3377 // create scale matrix
3378 scaleMatrix = matrix
3379 .translate(originalPoint.x, originalPoint.y)
3380 .scale(1 / currentScale * scale)
3381 .translate(-originalPoint.x, -originalPoint.y);
3382
3383 newMatrix = currentMatrix.multiply(scaleMatrix);
3384 } else {
3385 newMatrix = matrix.scale(scale);
3386 }
3387
3388 setCTM(this._viewport, newMatrix);
3389
3390 return newMatrix;
3391 };
3392
3393
3394 /**
3395 * Returns the size of the canvas
3396 *
3397 * @return {Dimensions}
3398 */
3399 Canvas.prototype.getSize = function() {
3400 return {
3401 width: this._container.clientWidth,
3402 height: this._container.clientHeight
3403 };
3404 };
3405
3406
3407 /**
3408 * Return the absolute bounding box for the given element
3409 *
3410 * The absolute bounding box may be used to display overlays in the
3411 * callers (browser) coordinate system rather than the zoomed in/out
3412 * canvas coordinates.
3413 *
3414 * @param {ElementDescriptor} element
3415 * @return {Bounds} the absolute bounding box
3416 */
3417 Canvas.prototype.getAbsoluteBBox = function(element) {
3418 var vbox = this.viewbox();
3419 var bbox;
3420
3421 // connection
3422 // use svg bbox
3423 if (element.waypoints) {
3424 var gfx = this.getGraphics(element);
3425
3426 bbox = gfx.getBBox();
3427 }
3428
3429 // shapes
3430 // use data
3431 else {
3432 bbox = element;
3433 }
3434
3435 var x = bbox.x * vbox.scale - vbox.x * vbox.scale;
3436 var y = bbox.y * vbox.scale - vbox.y * vbox.scale;
3437
3438 var width = bbox.width * vbox.scale;
3439 var height = bbox.height * vbox.scale;
3440
3441 return {
3442 x: x,
3443 y: y,
3444 width: width,
3445 height: height
3446 };
3447 };
3448
3449 /**
3450 * Fires an event in order other modules can react to the
3451 * canvas resizing
3452 */
3453 Canvas.prototype.resized = function() {
3454
3455 // force recomputation of view box
3456 delete this._cachedViewbox;
3457
3458 this._eventBus.fire('canvas.resized');
3459 };
3460
3461 var ELEMENT_ID = 'data-element-id';
3462
3463
3464 /**
3465 * @class
3466 *
3467 * A registry that keeps track of all shapes in the diagram.
3468 */
3469 function ElementRegistry(eventBus) {
3470 this._elements = {};
3471
3472 this._eventBus = eventBus;
3473 }
3474
3475 ElementRegistry.$inject = [ 'eventBus' ];
3476
3477 /**
3478 * Register a pair of (element, gfx, (secondaryGfx)).
3479 *
3480 * @param {djs.model.Base} element
3481 * @param {SVGElement} gfx
3482 * @param {SVGElement} [secondaryGfx] optional other element to register, too
3483 */
3484 ElementRegistry.prototype.add = function(element, gfx, secondaryGfx) {
3485
3486 var id = element.id;
3487
3488 this._validateId(id);
3489
3490 // associate dom node with element
3491 attr$1(gfx, ELEMENT_ID, id);
3492
3493 if (secondaryGfx) {
3494 attr$1(secondaryGfx, ELEMENT_ID, id);
3495 }
3496
3497 this._elements[id] = { element: element, gfx: gfx, secondaryGfx: secondaryGfx };
3498 };
3499
3500 /**
3501 * Removes an element from the registry.
3502 *
3503 * @param {djs.model.Base} element
3504 */
3505 ElementRegistry.prototype.remove = function(element) {
3506 var elements = this._elements,
3507 id = element.id || element,
3508 container = id && elements[id];
3509
3510 if (container) {
3511
3512 // unset element id on gfx
3513 attr$1(container.gfx, ELEMENT_ID, '');
3514
3515 if (container.secondaryGfx) {
3516 attr$1(container.secondaryGfx, ELEMENT_ID, '');
3517 }
3518
3519 delete elements[id];
3520 }
3521 };
3522
3523 /**
3524 * Update the id of an element
3525 *
3526 * @param {djs.model.Base} element
3527 * @param {String} newId
3528 */
3529 ElementRegistry.prototype.updateId = function(element, newId) {
3530
3531 this._validateId(newId);
3532
3533 if (typeof element === 'string') {
3534 element = this.get(element);
3535 }
3536
3537 this._eventBus.fire('element.updateId', {
3538 element: element,
3539 newId: newId
3540 });
3541
3542 var gfx = this.getGraphics(element),
3543 secondaryGfx = this.getGraphics(element, true);
3544
3545 this.remove(element);
3546
3547 element.id = newId;
3548
3549 this.add(element, gfx, secondaryGfx);
3550 };
3551
3552 /**
3553 * Return the model element for a given id or graphics.
3554 *
3555 * @example
3556 *
3557 * elementRegistry.get('SomeElementId_1');
3558 * elementRegistry.get(gfx);
3559 *
3560 *
3561 * @param {String|SVGElement} filter for selecting the element
3562 *
3563 * @return {djs.model.Base}
3564 */
3565 ElementRegistry.prototype.get = function(filter) {
3566 var id;
3567
3568 if (typeof filter === 'string') {
3569 id = filter;
3570 } else {
3571 id = filter && attr$1(filter, ELEMENT_ID);
3572 }
3573
3574 var container = this._elements[id];
3575 return container && container.element;
3576 };
3577
3578 /**
3579 * Return all elements that match a given filter function.
3580 *
3581 * @param {Function} fn
3582 *
3583 * @return {Array<djs.model.Base>}
3584 */
3585 ElementRegistry.prototype.filter = function(fn) {
3586
3587 var filtered = [];
3588
3589 this.forEach(function(element, gfx) {
3590 if (fn(element, gfx)) {
3591 filtered.push(element);
3592 }
3593 });
3594
3595 return filtered;
3596 };
3597
3598 /**
3599 * Return all rendered model elements.
3600 *
3601 * @return {Array<djs.model.Base>}
3602 */
3603 ElementRegistry.prototype.getAll = function() {
3604 return this.filter(function(e) { return e; });
3605 };
3606
3607 /**
3608 * Iterate over all diagram elements.
3609 *
3610 * @param {Function} fn
3611 */
3612 ElementRegistry.prototype.forEach = function(fn) {
3613
3614 var map = this._elements;
3615
3616 Object.keys(map).forEach(function(id) {
3617 var container = map[id],
3618 element = container.element,
3619 gfx = container.gfx;
3620
3621 return fn(element, gfx);
3622 });
3623 };
3624
3625 /**
3626 * Return the graphical representation of an element or its id.
3627 *
3628 * @example
3629 * elementRegistry.getGraphics('SomeElementId_1');
3630 * elementRegistry.getGraphics(rootElement); // <g ...>
3631 *
3632 * elementRegistry.getGraphics(rootElement, true); // <svg ...>
3633 *
3634 *
3635 * @param {String|djs.model.Base} filter
3636 * @param {Boolean} [secondary=false] whether to return the secondary connected element
3637 *
3638 * @return {SVGElement}
3639 */
3640 ElementRegistry.prototype.getGraphics = function(filter, secondary) {
3641 var id = filter.id || filter;
3642
3643 var container = this._elements[id];
3644 return container && (secondary ? container.secondaryGfx : container.gfx);
3645 };
3646
3647 /**
3648 * Validate the suitability of the given id and signals a problem
3649 * with an exception.
3650 *
3651 * @param {String} id
3652 *
3653 * @throws {Error} if id is empty or already assigned
3654 */
3655 ElementRegistry.prototype._validateId = function(id) {
3656 if (!id) {
3657 throw new Error('element must have an id');
3658 }
3659
3660 if (this._elements[id]) {
3661 throw new Error('element with id ' + id + ' already added');
3662 }
3663 };
3664
3665 /**
3666 * An empty collection stub. Use {@link RefsCollection.extend} to extend a
3667 * collection with ref semantics.
3668 *
3669 * @class RefsCollection
3670 */
3671
3672 /**
3673 * Extends a collection with {@link Refs} aware methods
3674 *
3675 * @memberof RefsCollection
3676 * @static
3677 *
3678 * @param {Array<Object>} collection
3679 * @param {Refs} refs instance
3680 * @param {Object} property represented by the collection
3681 * @param {Object} target object the collection is attached to
3682 *
3683 * @return {RefsCollection<Object>} the extended array
3684 */
3685 function extend$1(collection, refs, property, target) {
3686
3687 var inverseProperty = property.inverse;
3688
3689 /**
3690 * Removes the given element from the array and returns it.
3691 *
3692 * @method RefsCollection#remove
3693 *
3694 * @param {Object} element the element to remove
3695 */
3696 Object.defineProperty(collection, 'remove', {
3697 value: function(element) {
3698 var idx = this.indexOf(element);
3699 if (idx !== -1) {
3700 this.splice(idx, 1);
3701
3702 // unset inverse
3703 refs.unset(element, inverseProperty, target);
3704 }
3705
3706 return element;
3707 }
3708 });
3709
3710 /**
3711 * Returns true if the collection contains the given element
3712 *
3713 * @method RefsCollection#contains
3714 *
3715 * @param {Object} element the element to check for
3716 */
3717 Object.defineProperty(collection, 'contains', {
3718 value: function(element) {
3719 return this.indexOf(element) !== -1;
3720 }
3721 });
3722
3723 /**
3724 * Adds an element to the array, unless it exists already (set semantics).
3725 *
3726 * @method RefsCollection#add
3727 *
3728 * @param {Object} element the element to add
3729 * @param {Number} optional index to add element to
3730 * (possibly moving other elements around)
3731 */
3732 Object.defineProperty(collection, 'add', {
3733 value: function(element, idx) {
3734
3735 var currentIdx = this.indexOf(element);
3736
3737 if (typeof idx === 'undefined') {
3738
3739 if (currentIdx !== -1) {
3740 // element already in collection (!)
3741 return;
3742 }
3743
3744 // add to end of array, as no idx is specified
3745 idx = this.length;
3746 }
3747
3748 // handle already in collection
3749 if (currentIdx !== -1) {
3750
3751 // remove element from currentIdx
3752 this.splice(currentIdx, 1);
3753 }
3754
3755 // add element at idx
3756 this.splice(idx, 0, element);
3757
3758 if (currentIdx === -1) {
3759 // set inverse, unless element was
3760 // in collection already
3761 refs.set(element, inverseProperty, target);
3762 }
3763 }
3764 });
3765
3766 // a simple marker, identifying this element
3767 // as being a refs collection
3768 Object.defineProperty(collection, '__refs_collection', {
3769 value: true
3770 });
3771
3772 return collection;
3773 }
3774
3775
3776 function isExtended(collection) {
3777 return collection.__refs_collection === true;
3778 }
3779
3780 var extend_1 = extend$1;
3781
3782 var isExtended_1 = isExtended;
3783
3784 var collection = {
3785 extend: extend_1,
3786 isExtended: isExtended_1
3787 };
3788
3789 function hasOwnProperty(e, property) {
3790 return Object.prototype.hasOwnProperty.call(e, property.name || property);
3791 }
3792
3793 function defineCollectionProperty(ref, property, target) {
3794
3795 var collection$1 = collection.extend(target[property.name] || [], ref, property, target);
3796
3797 Object.defineProperty(target, property.name, {
3798 enumerable: property.enumerable,
3799 value: collection$1
3800 });
3801
3802 if (collection$1.length) {
3803
3804 collection$1.forEach(function(o) {
3805 ref.set(o, property.inverse, target);
3806 });
3807 }
3808 }
3809
3810
3811 function defineProperty(ref, property, target) {
3812
3813 var inverseProperty = property.inverse;
3814
3815 var _value = target[property.name];
3816
3817 Object.defineProperty(target, property.name, {
3818 configurable: property.configurable,
3819 enumerable: property.enumerable,
3820
3821 get: function() {
3822 return _value;
3823 },
3824
3825 set: function(value) {
3826
3827 // return if we already performed all changes
3828 if (value === _value) {
3829 return;
3830 }
3831
3832 var old = _value;
3833
3834 // temporary set null
3835 _value = null;
3836
3837 if (old) {
3838 ref.unset(old, inverseProperty, target);
3839 }
3840
3841 // set new value
3842 _value = value;
3843
3844 // set inverse value
3845 ref.set(_value, inverseProperty, target);
3846 }
3847 });
3848
3849 }
3850
3851 /**
3852 * Creates a new references object defining two inversly related
3853 * attribute descriptors a and b.
3854 *
3855 * <p>
3856 * When bound to an object using {@link Refs#bind} the references
3857 * get activated and ensure that add and remove operations are applied
3858 * reversely, too.
3859 * </p>
3860 *
3861 * <p>
3862 * For attributes represented as collections {@link Refs} provides the
3863 * {@link RefsCollection#add}, {@link RefsCollection#remove} and {@link RefsCollection#contains} extensions
3864 * that must be used to properly hook into the inverse change mechanism.
3865 * </p>
3866 *
3867 * @class Refs
3868 *
3869 * @classdesc A bi-directional reference between two attributes.
3870 *
3871 * @param {Refs.AttributeDescriptor} a property descriptor
3872 * @param {Refs.AttributeDescriptor} b property descriptor
3873 *
3874 * @example
3875 *
3876 * var refs = Refs({ name: 'wheels', collection: true, enumerable: true }, { name: 'car' });
3877 *
3878 * var car = { name: 'toyota' };
3879 * var wheels = [{ pos: 'front-left' }, { pos: 'front-right' }];
3880 *
3881 * refs.bind(car, 'wheels');
3882 *
3883 * car.wheels // []
3884 * car.wheels.add(wheels[0]);
3885 * car.wheels.add(wheels[1]);
3886 *
3887 * car.wheels // [{ pos: 'front-left' }, { pos: 'front-right' }]
3888 *
3889 * wheels[0].car // { name: 'toyota' };
3890 * car.wheels.remove(wheels[0]);
3891 *
3892 * wheels[0].car // undefined
3893 */
3894 function Refs(a, b) {
3895
3896 if (!(this instanceof Refs)) {
3897 return new Refs(a, b);
3898 }
3899
3900 // link
3901 a.inverse = b;
3902 b.inverse = a;
3903
3904 this.props = {};
3905 this.props[a.name] = a;
3906 this.props[b.name] = b;
3907 }
3908
3909 /**
3910 * Binds one side of a bi-directional reference to a
3911 * target object.
3912 *
3913 * @memberOf Refs
3914 *
3915 * @param {Object} target
3916 * @param {String} property
3917 */
3918 Refs.prototype.bind = function(target, property) {
3919 if (typeof property === 'string') {
3920 if (!this.props[property]) {
3921 throw new Error('no property <' + property + '> in ref');
3922 }
3923 property = this.props[property];
3924 }
3925
3926 if (property.collection) {
3927 defineCollectionProperty(this, property, target);
3928 } else {
3929 defineProperty(this, property, target);
3930 }
3931 };
3932
3933 Refs.prototype.ensureRefsCollection = function(target, property) {
3934
3935 var collection$1 = target[property.name];
3936
3937 if (!collection.isExtended(collection$1)) {
3938 defineCollectionProperty(this, property, target);
3939 }
3940
3941 return collection$1;
3942 };
3943
3944 Refs.prototype.ensureBound = function(target, property) {
3945 if (!hasOwnProperty(target, property)) {
3946 this.bind(target, property);
3947 }
3948 };
3949
3950 Refs.prototype.unset = function(target, property, value) {
3951
3952 if (target) {
3953 this.ensureBound(target, property);
3954
3955 if (property.collection) {
3956 this.ensureRefsCollection(target, property).remove(value);
3957 } else {
3958 target[property.name] = undefined;
3959 }
3960 }
3961 };
3962
3963 Refs.prototype.set = function(target, property, value) {
3964
3965 if (target) {
3966 this.ensureBound(target, property);
3967
3968 if (property.collection) {
3969 this.ensureRefsCollection(target, property).add(value);
3970 } else {
3971 target[property.name] = value;
3972 }
3973 }
3974 };
3975
3976 var refs = Refs;
3977
3978 var objectRefs = refs;
3979
3980 var Collection = collection;
3981 objectRefs.Collection = Collection;
3982
3983 var parentRefs = new objectRefs({ name: 'children', enumerable: true, collection: true }, { name: 'parent' }),
3984 labelRefs = new objectRefs({ name: 'labels', enumerable: true, collection: true }, { name: 'labelTarget' }),
3985 attacherRefs = new objectRefs({ name: 'attachers', collection: true }, { name: 'host' }),
3986 outgoingRefs = new objectRefs({ name: 'outgoing', collection: true }, { name: 'source' }),
3987 incomingRefs = new objectRefs({ name: 'incoming', collection: true }, { name: 'target' });
3988
3989 /**
3990 * @namespace djs.model
3991 */
3992
3993 /**
3994 * @memberOf djs.model
3995 */
3996
3997 /**
3998 * The basic graphical representation
3999 *
4000 * @class
4001 *
4002 * @abstract
4003 */
4004 function Base() {
4005
4006 /**
4007 * The object that backs up the shape
4008 *
4009 * @name Base#businessObject
4010 * @type Object
4011 */
4012 Object.defineProperty(this, 'businessObject', {
4013 writable: true
4014 });
4015
4016
4017 /**
4018 * Single label support, will mapped to multi label array
4019 *
4020 * @name Base#label
4021 * @type Object
4022 */
4023 Object.defineProperty(this, 'label', {
4024 get: function() {
4025 return this.labels[0];
4026 },
4027 set: function(newLabel) {
4028
4029 var label = this.label,
4030 labels = this.labels;
4031
4032 if (!newLabel && label) {
4033 labels.remove(label);
4034 } else {
4035 labels.add(newLabel, 0);
4036 }
4037 }
4038 });
4039
4040 /**
4041 * The parent shape
4042 *
4043 * @name Base#parent
4044 * @type Shape
4045 */
4046 parentRefs.bind(this, 'parent');
4047
4048 /**
4049 * The list of labels
4050 *
4051 * @name Base#labels
4052 * @type Label
4053 */
4054 labelRefs.bind(this, 'labels');
4055
4056 /**
4057 * The list of outgoing connections
4058 *
4059 * @name Base#outgoing
4060 * @type Array<Connection>
4061 */
4062 outgoingRefs.bind(this, 'outgoing');
4063
4064 /**
4065 * The list of incoming connections
4066 *
4067 * @name Base#incoming
4068 * @type Array<Connection>
4069 */
4070 incomingRefs.bind(this, 'incoming');
4071 }
4072
4073
4074 /**
4075 * A graphical object
4076 *
4077 * @class
4078 * @constructor
4079 *
4080 * @extends Base
4081 */
4082 function Shape() {
4083 Base.call(this);
4084
4085 /**
4086 * Indicates frame shapes
4087 *
4088 * @name Shape#isFrame
4089 * @type Boolean
4090 */
4091
4092 /**
4093 * The list of children
4094 *
4095 * @name Shape#children
4096 * @type Array<Base>
4097 */
4098 parentRefs.bind(this, 'children');
4099
4100 /**
4101 * @name Shape#host
4102 * @type Shape
4103 */
4104 attacherRefs.bind(this, 'host');
4105
4106 /**
4107 * @name Shape#attachers
4108 * @type Shape
4109 */
4110 attacherRefs.bind(this, 'attachers');
4111 }
4112
4113 inherits_browser(Shape, Base);
4114
4115
4116 /**
4117 * A root graphical object
4118 *
4119 * @class
4120 * @constructor
4121 *
4122 * @extends Shape
4123 */
4124 function Root() {
4125 Shape.call(this);
4126 }
4127
4128 inherits_browser(Root, Shape);
4129
4130
4131 /**
4132 * A label for an element
4133 *
4134 * @class
4135 * @constructor
4136 *
4137 * @extends Shape
4138 */
4139 function Label() {
4140 Shape.call(this);
4141
4142 /**
4143 * The labeled element
4144 *
4145 * @name Label#labelTarget
4146 * @type Base
4147 */
4148 labelRefs.bind(this, 'labelTarget');
4149 }
4150
4151 inherits_browser(Label, Shape);
4152
4153
4154 /**
4155 * A connection between two elements
4156 *
4157 * @class
4158 * @constructor
4159 *
4160 * @extends Base
4161 */
4162 function Connection() {
4163 Base.call(this);
4164
4165 /**
4166 * The element this connection originates from
4167 *
4168 * @name Connection#source
4169 * @type Base
4170 */
4171 outgoingRefs.bind(this, 'source');
4172
4173 /**
4174 * The element this connection points to
4175 *
4176 * @name Connection#target
4177 * @type Base
4178 */
4179 incomingRefs.bind(this, 'target');
4180 }
4181
4182 inherits_browser(Connection, Base);
4183
4184
4185 var types = {
4186 connection: Connection,
4187 shape: Shape,
4188 label: Label,
4189 root: Root
4190 };
4191
4192 /**
4193 * Creates a new model element of the specified type
4194 *
4195 * @method create
4196 *
4197 * @example
4198 *
4199 * var shape1 = Model.create('shape', { x: 10, y: 10, width: 100, height: 100 });
4200 * var shape2 = Model.create('shape', { x: 210, y: 210, width: 100, height: 100 });
4201 *
4202 * var connection = Model.create('connection', { waypoints: [ { x: 110, y: 55 }, {x: 210, y: 55 } ] });
4203 *
4204 * @param {String} type lower-cased model name
4205 * @param {Object} attrs attributes to initialize the new model instance with
4206 *
4207 * @return {Base} the new model instance
4208 */
4209 function create$1(type, attrs) {
4210 var Type = types[type];
4211 if (!Type) {
4212 throw new Error('unknown type: <' + type + '>');
4213 }
4214 return assign(new Type(), attrs);
4215 }
4216
4217 /**
4218 * A factory for diagram-js shapes
4219 */
4220 function ElementFactory() {
4221 this._uid = 12;
4222 }
4223
4224
4225 ElementFactory.prototype.createRoot = function(attrs) {
4226 return this.create('root', attrs);
4227 };
4228
4229 ElementFactory.prototype.createLabel = function(attrs) {
4230 return this.create('label', attrs);
4231 };
4232
4233 ElementFactory.prototype.createShape = function(attrs) {
4234 return this.create('shape', attrs);
4235 };
4236
4237 ElementFactory.prototype.createConnection = function(attrs) {
4238 return this.create('connection', attrs);
4239 };
4240
4241 /**
4242 * Create a model element with the given type and
4243 * a number of pre-set attributes.
4244 *
4245 * @param {String} type
4246 * @param {Object} attrs
4247 * @return {djs.model.Base} the newly created model instance
4248 */
4249 ElementFactory.prototype.create = function(type, attrs) {
4250
4251 attrs = assign({}, attrs || {});
4252
4253 if (!attrs.id) {
4254 attrs.id = type + '_' + (this._uid++);
4255 }
4256
4257 return create$1(type, attrs);
4258 };
4259
4260 var FN_REF = '__fn';
4261
4262 var DEFAULT_PRIORITY = 1000;
4263
4264 var slice$1 = Array.prototype.slice;
4265
4266 /**
4267 * A general purpose event bus.
4268 *
4269 * This component is used to communicate across a diagram instance.
4270 * Other parts of a diagram can use it to listen to and broadcast events.
4271 *
4272 *
4273 * ## Registering for Events
4274 *
4275 * The event bus provides the {@link EventBus#on} and {@link EventBus#once}
4276 * methods to register for events. {@link EventBus#off} can be used to
4277 * remove event registrations. Listeners receive an instance of {@link Event}
4278 * as the first argument. It allows them to hook into the event execution.
4279 *
4280 * ```javascript
4281 *
4282 * // listen for event
4283 * eventBus.on('foo', function(event) {
4284 *
4285 * // access event type
4286 * event.type; // 'foo'
4287 *
4288 * // stop propagation to other listeners
4289 * event.stopPropagation();
4290 *
4291 * // prevent event default
4292 * event.preventDefault();
4293 * });
4294 *
4295 * // listen for event with custom payload
4296 * eventBus.on('bar', function(event, payload) {
4297 * console.log(payload);
4298 * });
4299 *
4300 * // listen for event returning value
4301 * eventBus.on('foobar', function(event) {
4302 *
4303 * // stop event propagation + prevent default
4304 * return false;
4305 *
4306 * // stop event propagation + return custom result
4307 * return {
4308 * complex: 'listening result'
4309 * };
4310 * });
4311 *
4312 *
4313 * // listen with custom priority (default=1000, higher is better)
4314 * eventBus.on('priorityfoo', 1500, function(event) {
4315 * console.log('invoked first!');
4316 * });
4317 *
4318 *
4319 * // listen for event and pass the context (`this`)
4320 * eventBus.on('foobar', function(event) {
4321 * this.foo();
4322 * }, this);
4323 * ```
4324 *
4325 *
4326 * ## Emitting Events
4327 *
4328 * Events can be emitted via the event bus using {@link EventBus#fire}.
4329 *
4330 * ```javascript
4331 *
4332 * // false indicates that the default action
4333 * // was prevented by listeners
4334 * if (eventBus.fire('foo') === false) {
4335 * console.log('default has been prevented!');
4336 * };
4337 *
4338 *
4339 * // custom args + return value listener
4340 * eventBus.on('sum', function(event, a, b) {
4341 * return a + b;
4342 * });
4343 *
4344 * // you can pass custom arguments + retrieve result values.
4345 * var sum = eventBus.fire('sum', 1, 2);
4346 * console.log(sum); // 3
4347 * ```
4348 */
4349 function EventBus() {
4350 this._listeners = {};
4351
4352 // cleanup on destroy on lowest priority to allow
4353 // message passing until the bitter end
4354 this.on('diagram.destroy', 1, this._destroy, this);
4355 }
4356
4357
4358 /**
4359 * Register an event listener for events with the given name.
4360 *
4361 * The callback will be invoked with `event, ...additionalArguments`
4362 * that have been passed to {@link EventBus#fire}.
4363 *
4364 * Returning false from a listener will prevent the events default action
4365 * (if any is specified). To stop an event from being processed further in
4366 * other listeners execute {@link Event#stopPropagation}.
4367 *
4368 * Returning anything but `undefined` from a listener will stop the listener propagation.
4369 *
4370 * @param {String|Array<String>} events
4371 * @param {Number} [priority=1000] the priority in which this listener is called, larger is higher
4372 * @param {Function} callback
4373 * @param {Object} [that] Pass context (`this`) to the callback
4374 */
4375 EventBus.prototype.on = function(events, priority, callback, that) {
4376
4377 events = isArray(events) ? events : [ events ];
4378
4379 if (isFunction(priority)) {
4380 that = callback;
4381 callback = priority;
4382 priority = DEFAULT_PRIORITY;
4383 }
4384
4385 if (!isNumber(priority)) {
4386 throw new Error('priority must be a number');
4387 }
4388
4389 var actualCallback = callback;
4390
4391 if (that) {
4392 actualCallback = bind(callback, that);
4393
4394 // make sure we remember and are able to remove
4395 // bound callbacks via {@link #off} using the original
4396 // callback
4397 actualCallback[FN_REF] = callback[FN_REF] || callback;
4398 }
4399
4400 var self = this;
4401
4402 events.forEach(function(e) {
4403 self._addListener(e, {
4404 priority: priority,
4405 callback: actualCallback,
4406 next: null
4407 });
4408 });
4409 };
4410
4411
4412 /**
4413 * Register an event listener that is executed only once.
4414 *
4415 * @param {String} event the event name to register for
4416 * @param {Number} [priority=1000] the priority in which this listener is called, larger is higher
4417 * @param {Function} callback the callback to execute
4418 * @param {Object} [that] Pass context (`this`) to the callback
4419 */
4420 EventBus.prototype.once = function(event, priority, callback, that) {
4421 var self = this;
4422
4423 if (isFunction(priority)) {
4424 that = callback;
4425 callback = priority;
4426 priority = DEFAULT_PRIORITY;
4427 }
4428
4429 if (!isNumber(priority)) {
4430 throw new Error('priority must be a number');
4431 }
4432
4433 function wrappedCallback() {
4434 var result = callback.apply(that, arguments);
4435
4436 self.off(event, wrappedCallback);
4437
4438 return result;
4439 }
4440
4441 // make sure we remember and are able to remove
4442 // bound callbacks via {@link #off} using the original
4443 // callback
4444 wrappedCallback[FN_REF] = callback;
4445
4446 this.on(event, priority, wrappedCallback);
4447 };
4448
4449
4450 /**
4451 * Removes event listeners by event and callback.
4452 *
4453 * If no callback is given, all listeners for a given event name are being removed.
4454 *
4455 * @param {String|Array<String>} events
4456 * @param {Function} [callback]
4457 */
4458 EventBus.prototype.off = function(events, callback) {
4459
4460 events = isArray(events) ? events : [ events ];
4461
4462 var self = this;
4463
4464 events.forEach(function(event) {
4465 self._removeListener(event, callback);
4466 });
4467
4468 };
4469
4470
4471 /**
4472 * Create an EventBus event.
4473 *
4474 * @param {Object} data
4475 *
4476 * @return {Object} event, recognized by the eventBus
4477 */
4478 EventBus.prototype.createEvent = function(data) {
4479 var event = new InternalEvent();
4480
4481 event.init(data);
4482
4483 return event;
4484 };
4485
4486
4487 /**
4488 * Fires a named event.
4489 *
4490 * @example
4491 *
4492 * // fire event by name
4493 * events.fire('foo');
4494 *
4495 * // fire event object with nested type
4496 * var event = { type: 'foo' };
4497 * events.fire(event);
4498 *
4499 * // fire event with explicit type
4500 * var event = { x: 10, y: 20 };
4501 * events.fire('element.moved', event);
4502 *
4503 * // pass additional arguments to the event
4504 * events.on('foo', function(event, bar) {
4505 * alert(bar);
4506 * });
4507 *
4508 * events.fire({ type: 'foo' }, 'I am bar!');
4509 *
4510 * @param {String} [name] the optional event name
4511 * @param {Object} [event] the event object
4512 * @param {...Object} additional arguments to be passed to the callback functions
4513 *
4514 * @return {Boolean} the events return value, if specified or false if the
4515 * default action was prevented by listeners
4516 */
4517 EventBus.prototype.fire = function(type, data) {
4518
4519 var event,
4520 firstListener,
4521 returnValue,
4522 args;
4523
4524 args = slice$1.call(arguments);
4525
4526 if (typeof type === 'object') {
4527 event = type;
4528 type = event.type;
4529 }
4530
4531 if (!type) {
4532 throw new Error('no event type specified');
4533 }
4534
4535 firstListener = this._listeners[type];
4536
4537 if (!firstListener) {
4538 return;
4539 }
4540
4541 // we make sure we fire instances of our home made
4542 // events here. We wrap them only once, though
4543 if (data instanceof InternalEvent) {
4544
4545 // we are fine, we alread have an event
4546 event = data;
4547 } else {
4548 event = this.createEvent(data);
4549 }
4550
4551 // ensure we pass the event as the first parameter
4552 args[0] = event;
4553
4554 // original event type (in case we delegate)
4555 var originalType = event.type;
4556
4557 // update event type before delegation
4558 if (type !== originalType) {
4559 event.type = type;
4560 }
4561
4562 try {
4563 returnValue = this._invokeListeners(event, args, firstListener);
4564 } finally {
4565
4566 // reset event type after delegation
4567 if (type !== originalType) {
4568 event.type = originalType;
4569 }
4570 }
4571
4572 // set the return value to false if the event default
4573 // got prevented and no other return value exists
4574 if (returnValue === undefined && event.defaultPrevented) {
4575 returnValue = false;
4576 }
4577
4578 return returnValue;
4579 };
4580
4581
4582 EventBus.prototype.handleError = function(error) {
4583 return this.fire('error', { error: error }) === false;
4584 };
4585
4586
4587 EventBus.prototype._destroy = function() {
4588 this._listeners = {};
4589 };
4590
4591 EventBus.prototype._invokeListeners = function(event, args, listener) {
4592
4593 var returnValue;
4594
4595 while (listener) {
4596
4597 // handle stopped propagation
4598 if (event.cancelBubble) {
4599 break;
4600 }
4601
4602 returnValue = this._invokeListener(event, args, listener);
4603
4604 listener = listener.next;
4605 }
4606
4607 return returnValue;
4608 };
4609
4610 EventBus.prototype._invokeListener = function(event, args, listener) {
4611
4612 var returnValue;
4613
4614 try {
4615
4616 // returning false prevents the default action
4617 returnValue = invokeFunction(listener.callback, args);
4618
4619 // stop propagation on return value
4620 if (returnValue !== undefined) {
4621 event.returnValue = returnValue;
4622 event.stopPropagation();
4623 }
4624
4625 // prevent default on return false
4626 if (returnValue === false) {
4627 event.preventDefault();
4628 }
4629 } catch (e) {
4630 if (!this.handleError(e)) {
4631 console.error('unhandled error in event listener');
4632 console.error(e.stack);
4633
4634 throw e;
4635 }
4636 }
4637
4638 return returnValue;
4639 };
4640
4641 /*
4642 * Add new listener with a certain priority to the list
4643 * of listeners (for the given event).
4644 *
4645 * The semantics of listener registration / listener execution are
4646 * first register, first serve: New listeners will always be inserted
4647 * after existing listeners with the same priority.
4648 *
4649 * Example: Inserting two listeners with priority 1000 and 1300
4650 *
4651 * * before: [ 1500, 1500, 1000, 1000 ]
4652 * * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ]
4653 *
4654 * @param {String} event
4655 * @param {Object} listener { priority, callback }
4656 */
4657 EventBus.prototype._addListener = function(event, newListener) {
4658
4659 var listener = this._getListeners(event),
4660 previousListener;
4661
4662 // no prior listeners
4663 if (!listener) {
4664 this._setListeners(event, newListener);
4665
4666 return;
4667 }
4668
4669 // ensure we order listeners by priority from
4670 // 0 (high) to n > 0 (low)
4671 while (listener) {
4672
4673 if (listener.priority < newListener.priority) {
4674
4675 newListener.next = listener;
4676
4677 if (previousListener) {
4678 previousListener.next = newListener;
4679 } else {
4680 this._setListeners(event, newListener);
4681 }
4682
4683 return;
4684 }
4685
4686 previousListener = listener;
4687 listener = listener.next;
4688 }
4689
4690 // add new listener to back
4691 previousListener.next = newListener;
4692 };
4693
4694
4695 EventBus.prototype._getListeners = function(name) {
4696 return this._listeners[name];
4697 };
4698
4699 EventBus.prototype._setListeners = function(name, listener) {
4700 this._listeners[name] = listener;
4701 };
4702
4703 EventBus.prototype._removeListener = function(event, callback) {
4704
4705 var listener = this._getListeners(event),
4706 nextListener,
4707 previousListener,
4708 listenerCallback;
4709
4710 if (!callback) {
4711
4712 // clear listeners
4713 this._setListeners(event, null);
4714
4715 return;
4716 }
4717
4718 while (listener) {
4719
4720 nextListener = listener.next;
4721
4722 listenerCallback = listener.callback;
4723
4724 if (listenerCallback === callback || listenerCallback[FN_REF] === callback) {
4725 if (previousListener) {
4726 previousListener.next = nextListener;
4727 } else {
4728
4729 // new first listener
4730 this._setListeners(event, nextListener);
4731 }
4732 }
4733
4734 previousListener = listener;
4735 listener = nextListener;
4736 }
4737 };
4738
4739 /**
4740 * A event that is emitted via the event bus.
4741 */
4742 function InternalEvent() { }
4743
4744 InternalEvent.prototype.stopPropagation = function() {
4745 this.cancelBubble = true;
4746 };
4747
4748 InternalEvent.prototype.preventDefault = function() {
4749 this.defaultPrevented = true;
4750 };
4751
4752 InternalEvent.prototype.init = function(data) {
4753 assign(this, data || {});
4754 };
4755
4756
4757 /**
4758 * Invoke function. Be fast...
4759 *
4760 * @param {Function} fn
4761 * @param {Array<Object>} args
4762 *
4763 * @return {Any}
4764 */
4765 function invokeFunction(fn, args) {
4766 return fn.apply(null, args);
4767 }
4768
4769 /**
4770 * SVGs for elements are generated by the {@link GraphicsFactory}.
4771 *
4772 * This utility gives quick access to the important semantic
4773 * parts of an element.
4774 */
4775
4776 /**
4777 * Returns the visual part of a diagram element
4778 *
4779 * @param {Snap<SVGElement>} gfx
4780 *
4781 * @return {Snap<SVGElement>}
4782 */
4783 function getVisual(gfx) {
4784 return gfx.childNodes[0];
4785 }
4786
4787 /**
4788 * Returns the children for a given diagram element.
4789 *
4790 * @param {Snap<SVGElement>} gfx
4791 * @return {Snap<SVGElement>}
4792 */
4793 function getChildren(gfx) {
4794 return gfx.parentNode.childNodes[1];
4795 }
4796
4797 /**
4798 * @param {<SVGElement>} element
4799 * @param {Number} x
4800 * @param {Number} y
4801 * @param {Number} angle
4802 * @param {Number} amount
4803 */
4804 function transform$1(gfx, x, y, angle, amount) {
4805 var translate = createTransform();
4806 translate.setTranslate(x, y);
4807
4808 var rotate = createTransform();
4809 rotate.setRotate(angle, 0, 0);
4810
4811 var scale = createTransform();
4812 scale.setScale(amount || 1, amount || 1);
4813
4814 transform(gfx, [ translate, rotate, scale ]);
4815 }
4816
4817
4818 /**
4819 * @param {SVGElement} element
4820 * @param {Number} x
4821 * @param {Number} y
4822 */
4823 function translate(gfx, x, y) {
4824 var translate = createTransform();
4825 translate.setTranslate(x, y);
4826
4827 transform(gfx, translate);
4828 }
4829
4830
4831 /**
4832 * @param {SVGElement} element
4833 * @param {Number} angle
4834 */
4835 function rotate(gfx, angle) {
4836 var rotate = createTransform();
4837 rotate.setRotate(angle, 0, 0);
4838
4839 transform(gfx, rotate);
4840 }
4841
4842 /**
4843 * A factory that creates graphical elements
4844 *
4845 * @param {EventBus} eventBus
4846 * @param {ElementRegistry} elementRegistry
4847 */
4848 function GraphicsFactory(eventBus, elementRegistry) {
4849 this._eventBus = eventBus;
4850 this._elementRegistry = elementRegistry;
4851 }
4852
4853 GraphicsFactory.$inject = [ 'eventBus' , 'elementRegistry' ];
4854
4855
4856 GraphicsFactory.prototype._getChildren = function(element) {
4857
4858 var gfx = this._elementRegistry.getGraphics(element);
4859
4860 var childrenGfx;
4861
4862 // root element
4863 if (!element.parent) {
4864 childrenGfx = gfx;
4865 } else {
4866 childrenGfx = getChildren(gfx);
4867 if (!childrenGfx) {
4868 childrenGfx = create('g');
4869 classes$1(childrenGfx).add('djs-children');
4870
4871 append(gfx.parentNode, childrenGfx);
4872 }
4873 }
4874
4875 return childrenGfx;
4876 };
4877
4878 /**
4879 * Clears the graphical representation of the element and returns the
4880 * cleared visual (the <g class="djs-visual" /> element).
4881 */
4882 GraphicsFactory.prototype._clear = function(gfx) {
4883 var visual = getVisual(gfx);
4884
4885 clear(visual);
4886
4887 return visual;
4888 };
4889
4890 /**
4891 * Creates a gfx container for shapes and connections
4892 *
4893 * The layout is as follows:
4894 *
4895 * <g class="djs-group">
4896 *
4897 * <!-- the gfx -->
4898 * <g class="djs-element djs-(shape|connection|frame)">
4899 * <g class="djs-visual">
4900 * <!-- the renderer draws in here -->
4901 * </g>
4902 *
4903 * <!-- extensions (overlays, click box, ...) goes here
4904 * </g>
4905 *
4906 * <!-- the gfx child nodes -->
4907 * <g class="djs-children"></g>
4908 * </g>
4909 *
4910 * @param {String} type the type of the element, i.e. shape | connection
4911 * @param {SVGElement} [childrenGfx]
4912 * @param {Number} [parentIndex] position to create container in parent
4913 * @param {Boolean} [isFrame] is frame element
4914 *
4915 * @return {SVGElement}
4916 */
4917 GraphicsFactory.prototype._createContainer = function(
4918 type, childrenGfx, parentIndex, isFrame
4919 ) {
4920 var outerGfx = create('g');
4921 classes$1(outerGfx).add('djs-group');
4922
4923 // insert node at position
4924 if (typeof parentIndex !== 'undefined') {
4925 prependTo(outerGfx, childrenGfx, childrenGfx.childNodes[parentIndex]);
4926 } else {
4927 append(childrenGfx, outerGfx);
4928 }
4929
4930 var gfx = create('g');
4931 classes$1(gfx).add('djs-element');
4932 classes$1(gfx).add('djs-' + type);
4933
4934 if (isFrame) {
4935 classes$1(gfx).add('djs-frame');
4936 }
4937
4938 append(outerGfx, gfx);
4939
4940 // create visual
4941 var visual = create('g');
4942 classes$1(visual).add('djs-visual');
4943
4944 append(gfx, visual);
4945
4946 return gfx;
4947 };
4948
4949 GraphicsFactory.prototype.create = function(type, element, parentIndex) {
4950 var childrenGfx = this._getChildren(element.parent);
4951 return this._createContainer(type, childrenGfx, parentIndex, isFrameElement(element));
4952 };
4953
4954 GraphicsFactory.prototype.updateContainments = function(elements) {
4955
4956 var self = this,
4957 elementRegistry = this._elementRegistry,
4958 parents;
4959
4960 parents = reduce(elements, function(map, e) {
4961
4962 if (e.parent) {
4963 map[e.parent.id] = e.parent;
4964 }
4965
4966 return map;
4967 }, {});
4968
4969 // update all parents of changed and reorganized their children
4970 // in the correct order (as indicated in our model)
4971 forEach(parents, function(parent) {
4972
4973 var children = parent.children;
4974
4975 if (!children) {
4976 return;
4977 }
4978
4979 var childGfx = self._getChildren(parent);
4980
4981 forEach(children.slice().reverse(), function(c) {
4982 var gfx = elementRegistry.getGraphics(c);
4983
4984 prependTo(gfx.parentNode, childGfx);
4985 });
4986 });
4987 };
4988
4989 GraphicsFactory.prototype.drawShape = function(visual, element) {
4990 var eventBus = this._eventBus;
4991
4992 return eventBus.fire('render.shape', { gfx: visual, element: element });
4993 };
4994
4995 GraphicsFactory.prototype.getShapePath = function(element) {
4996 var eventBus = this._eventBus;
4997
4998 return eventBus.fire('render.getShapePath', element);
4999 };
5000
5001 GraphicsFactory.prototype.drawConnection = function(visual, element) {
5002 var eventBus = this._eventBus;
5003
5004 return eventBus.fire('render.connection', { gfx: visual, element: element });
5005 };
5006
5007 GraphicsFactory.prototype.getConnectionPath = function(waypoints) {
5008 var eventBus = this._eventBus;
5009
5010 return eventBus.fire('render.getConnectionPath', waypoints);
5011 };
5012
5013 GraphicsFactory.prototype.update = function(type, element, gfx) {
5014
5015 // do NOT update root element
5016 if (!element.parent) {
5017 return;
5018 }
5019
5020 var visual = this._clear(gfx);
5021
5022 // redraw
5023 if (type === 'shape') {
5024 this.drawShape(visual, element);
5025
5026 // update positioning
5027 translate(gfx, element.x, element.y);
5028 } else
5029 if (type === 'connection') {
5030 this.drawConnection(visual, element);
5031 } else {
5032 throw new Error('unknown type: ' + type);
5033 }
5034
5035 if (element.hidden) {
5036 attr$1(gfx, 'display', 'none');
5037 } else {
5038 attr$1(gfx, 'display', 'block');
5039 }
5040 };
5041
5042 GraphicsFactory.prototype.remove = function(element) {
5043 var gfx = this._elementRegistry.getGraphics(element);
5044
5045 // remove
5046 remove$1(gfx.parentNode);
5047 };
5048
5049
5050 // helpers //////////
5051
5052 function prependTo(newNode, parentNode, siblingNode) {
5053 var node = siblingNode || parentNode.firstChild;
5054
5055 // do not prepend node to itself to prevent IE from crashing
5056 // https://github.com/bpmn-io/bpmn-js/issues/746
5057 if (newNode === node) {
5058 return;
5059 }
5060
5061 parentNode.insertBefore(newNode, node);
5062 }
5063
5064 var CoreModule = {
5065 __depends__: [ DrawModule ],
5066 __init__: [ 'canvas' ],
5067 canvas: [ 'type', Canvas ],
5068 elementRegistry: [ 'type', ElementRegistry ],
5069 elementFactory: [ 'type', ElementFactory ],
5070 eventBus: [ 'type', EventBus ],
5071 graphicsFactory: [ 'type', GraphicsFactory ]
5072 };
5073
5074 /**
5075 * Bootstrap an injector from a list of modules, instantiating a number of default components
5076 *
5077 * @ignore
5078 * @param {Array<didi.Module>} bootstrapModules
5079 *
5080 * @return {didi.Injector} a injector to use to access the components
5081 */
5082 function bootstrap(bootstrapModules) {
5083
5084 var modules = [],
5085 components = [];
5086
5087 function hasModule(m) {
5088 return modules.indexOf(m) >= 0;
5089 }
5090
5091 function addModule(m) {
5092 modules.push(m);
5093 }
5094
5095 function visit(m) {
5096 if (hasModule(m)) {
5097 return;
5098 }
5099
5100 (m.__depends__ || []).forEach(visit);
5101
5102 if (hasModule(m)) {
5103 return;
5104 }
5105
5106 addModule(m);
5107
5108 (m.__init__ || []).forEach(function(c) {
5109 components.push(c);
5110 });
5111 }
5112
5113 bootstrapModules.forEach(visit);
5114
5115 var injector = new Injector(modules);
5116
5117 components.forEach(function(c) {
5118
5119 try {
5120
5121 // eagerly resolve component (fn or string)
5122 injector[typeof c === 'string' ? 'get' : 'invoke'](c);
5123 } catch (e) {
5124 console.error('Failed to instantiate component');
5125 console.error(e.stack);
5126
5127 throw e;
5128 }
5129 });
5130
5131 return injector;
5132 }
5133
5134 /**
5135 * Creates an injector from passed options.
5136 *
5137 * @ignore
5138 * @param {Object} options
5139 * @return {didi.Injector}
5140 */
5141 function createInjector(options) {
5142
5143 options = options || {};
5144
5145 var configModule = {
5146 'config': ['value', options]
5147 };
5148
5149 var modules = [ configModule, CoreModule ].concat(options.modules || []);
5150
5151 return bootstrap(modules);
5152 }
5153
5154
5155 /**
5156 * The main diagram-js entry point that bootstraps the diagram with the given
5157 * configuration.
5158 *
5159 * To register extensions with the diagram, pass them as Array<didi.Module> to the constructor.
5160 *
5161 * @class djs.Diagram
5162 * @memberOf djs
5163 * @constructor
5164 *
5165 * @example
5166 *
5167 * <caption>Creating a plug-in that logs whenever a shape is added to the canvas.</caption>
5168 *
5169 * // plug-in implemenentation
5170 * function MyLoggingPlugin(eventBus) {
5171 * eventBus.on('shape.added', function(event) {
5172 * console.log('shape ', event.shape, ' was added to the diagram');
5173 * });
5174 * }
5175 *
5176 * // export as module
5177 * export default {
5178 * __init__: [ 'myLoggingPlugin' ],
5179 * myLoggingPlugin: [ 'type', MyLoggingPlugin ]
5180 * };
5181 *
5182 *
5183 * // instantiate the diagram with the new plug-in
5184 *
5185 * import MyLoggingModule from 'path-to-my-logging-plugin';
5186 *
5187 * var diagram = new Diagram({
5188 * modules: [
5189 * MyLoggingModule
5190 * ]
5191 * });
5192 *
5193 * diagram.invoke([ 'canvas', function(canvas) {
5194 * // add shape to drawing canvas
5195 * canvas.addShape({ x: 10, y: 10 });
5196 * });
5197 *
5198 * // 'shape ... was added to the diagram' logged to console
5199 *
5200 * @param {Object} options
5201 * @param {Array<didi.Module>} [options.modules] external modules to instantiate with the diagram
5202 * @param {didi.Injector} [injector] an (optional) injector to bootstrap the diagram with
5203 */
5204 function Diagram(options, injector) {
5205
5206 // create injector unless explicitly specified
5207 this.injector = injector = injector || createInjector(options);
5208
5209 // API
5210
5211 /**
5212 * Resolves a diagram service
5213 *
5214 * @method Diagram#get
5215 *
5216 * @param {String} name the name of the diagram service to be retrieved
5217 * @param {Boolean} [strict=true] if false, resolve missing services to null
5218 */
5219 this.get = injector.get;
5220
5221 /**
5222 * Executes a function into which diagram services are injected
5223 *
5224 * @method Diagram#invoke
5225 *
5226 * @param {Function|Object[]} fn the function to resolve
5227 * @param {Object} locals a number of locals to use to resolve certain dependencies
5228 */
5229 this.invoke = injector.invoke;
5230
5231 // init
5232
5233 // indicate via event
5234
5235
5236 /**
5237 * An event indicating that all plug-ins are loaded.
5238 *
5239 * Use this event to fire other events to interested plug-ins
5240 *
5241 * @memberOf Diagram
5242 *
5243 * @event diagram.init
5244 *
5245 * @example
5246 *
5247 * eventBus.on('diagram.init', function() {
5248 * eventBus.fire('my-custom-event', { foo: 'BAR' });
5249 * });
5250 *
5251 * @type {Object}
5252 */
5253 this.get('eventBus').fire('diagram.init');
5254 }
5255
5256
5257 /**
5258 * Destroys the diagram
5259 *
5260 * @method Diagram#destroy
5261 */
5262 Diagram.prototype.destroy = function() {
5263 this.get('eventBus').fire('diagram.destroy');
5264 };
5265
5266 /**
5267 * Clear the diagram, removing all contents.
5268 */
5269 Diagram.prototype.clear = function() {
5270 this.get('eventBus').fire('diagram.clear');
5271 };
5272
5273 /**
5274 * Moddle base element.
5275 */
5276 function Base$1() { }
5277
5278 Base$1.prototype.get = function(name) {
5279 return this.$model.properties.get(this, name);
5280 };
5281
5282 Base$1.prototype.set = function(name, value) {
5283 this.$model.properties.set(this, name, value);
5284 };
5285
5286 /**
5287 * A model element factory.
5288 *
5289 * @param {Moddle} model
5290 * @param {Properties} properties
5291 */
5292 function Factory(model, properties) {
5293 this.model = model;
5294 this.properties = properties;
5295 }
5296
5297
5298 Factory.prototype.createType = function(descriptor) {
5299
5300 var model = this.model;
5301
5302 var props = this.properties,
5303 prototype = Object.create(Base$1.prototype);
5304
5305 // initialize default values
5306 forEach(descriptor.properties, function(p) {
5307 if (!p.isMany && p.default !== undefined) {
5308 prototype[p.name] = p.default;
5309 }
5310 });
5311
5312 props.defineModel(prototype, model);
5313 props.defineDescriptor(prototype, descriptor);
5314
5315 var name = descriptor.ns.name;
5316
5317 /**
5318 * The new type constructor
5319 */
5320 function ModdleElement(attrs) {
5321 props.define(this, '$type', { value: name, enumerable: true });
5322 props.define(this, '$attrs', { value: {} });
5323 props.define(this, '$parent', { writable: true });
5324
5325 forEach(attrs, bind(function(val, key) {
5326 this.set(key, val);
5327 }, this));
5328 }
5329
5330 ModdleElement.prototype = prototype;
5331
5332 ModdleElement.hasType = prototype.$instanceOf = this.model.hasType;
5333
5334 // static links
5335 props.defineModel(ModdleElement, model);
5336 props.defineDescriptor(ModdleElement, descriptor);
5337
5338 return ModdleElement;
5339 };
5340
5341 /**
5342 * Built-in moddle types
5343 */
5344 var BUILTINS = {
5345 String: true,
5346 Boolean: true,
5347 Integer: true,
5348 Real: true,
5349 Element: true
5350 };
5351
5352 /**
5353 * Converters for built in types from string representations
5354 */
5355 var TYPE_CONVERTERS = {
5356 String: function(s) { return s; },
5357 Boolean: function(s) { return s === 'true'; },
5358 Integer: function(s) { return parseInt(s, 10); },
5359 Real: function(s) { return parseFloat(s, 10); }
5360 };
5361
5362 /**
5363 * Convert a type to its real representation
5364 */
5365 function coerceType(type, value) {
5366
5367 var converter = TYPE_CONVERTERS[type];
5368
5369 if (converter) {
5370 return converter(value);
5371 } else {
5372 return value;
5373 }
5374 }
5375
5376 /**
5377 * Return whether the given type is built-in
5378 */
5379 function isBuiltIn(type) {
5380 return !!BUILTINS[type];
5381 }
5382
5383 /**
5384 * Return whether the given type is simple
5385 */
5386 function isSimple(type) {
5387 return !!TYPE_CONVERTERS[type];
5388 }
5389
5390 /**
5391 * Parses a namespaced attribute name of the form (ns:)localName to an object,
5392 * given a default prefix to assume in case no explicit namespace is given.
5393 *
5394 * @param {String} name
5395 * @param {String} [defaultPrefix] the default prefix to take, if none is present.
5396 *
5397 * @return {Object} the parsed name
5398 */
5399 function parseName(name, defaultPrefix) {
5400 var parts = name.split(/:/),
5401 localName, prefix;
5402
5403 // no prefix (i.e. only local name)
5404 if (parts.length === 1) {
5405 localName = name;
5406 prefix = defaultPrefix;
5407 } else
5408 // prefix + local name
5409 if (parts.length === 2) {
5410 localName = parts[1];
5411 prefix = parts[0];
5412 } else {
5413 throw new Error('expected <prefix:localName> or <localName>, got ' + name);
5414 }
5415
5416 name = (prefix ? prefix + ':' : '') + localName;
5417
5418 return {
5419 name: name,
5420 prefix: prefix,
5421 localName: localName
5422 };
5423 }
5424
5425 /**
5426 * A utility to build element descriptors.
5427 */
5428 function DescriptorBuilder(nameNs) {
5429 this.ns = nameNs;
5430 this.name = nameNs.name;
5431 this.allTypes = [];
5432 this.allTypesByName = {};
5433 this.properties = [];
5434 this.propertiesByName = {};
5435 }
5436
5437
5438 DescriptorBuilder.prototype.build = function() {
5439 return pick(this, [
5440 'ns',
5441 'name',
5442 'allTypes',
5443 'allTypesByName',
5444 'properties',
5445 'propertiesByName',
5446 'bodyProperty',
5447 'idProperty'
5448 ]);
5449 };
5450
5451 /**
5452 * Add property at given index.
5453 *
5454 * @param {Object} p
5455 * @param {Number} [idx]
5456 * @param {Boolean} [validate=true]
5457 */
5458 DescriptorBuilder.prototype.addProperty = function(p, idx, validate) {
5459
5460 if (typeof idx === 'boolean') {
5461 validate = idx;
5462 idx = undefined;
5463 }
5464
5465 this.addNamedProperty(p, validate !== false);
5466
5467 var properties = this.properties;
5468
5469 if (idx !== undefined) {
5470 properties.splice(idx, 0, p);
5471 } else {
5472 properties.push(p);
5473 }
5474 };
5475
5476
5477 DescriptorBuilder.prototype.replaceProperty = function(oldProperty, newProperty, replace) {
5478 var oldNameNs = oldProperty.ns;
5479
5480 var props = this.properties,
5481 propertiesByName = this.propertiesByName,
5482 rename = oldProperty.name !== newProperty.name;
5483
5484 if (oldProperty.isId) {
5485 if (!newProperty.isId) {
5486 throw new Error(
5487 'property <' + newProperty.ns.name + '> must be id property ' +
5488 'to refine <' + oldProperty.ns.name + '>');
5489 }
5490
5491 this.setIdProperty(newProperty, false);
5492 }
5493
5494 if (oldProperty.isBody) {
5495
5496 if (!newProperty.isBody) {
5497 throw new Error(
5498 'property <' + newProperty.ns.name + '> must be body property ' +
5499 'to refine <' + oldProperty.ns.name + '>');
5500 }
5501
5502 // TODO: Check compatibility
5503 this.setBodyProperty(newProperty, false);
5504 }
5505
5506 // validate existence and get location of old property
5507 var idx = props.indexOf(oldProperty);
5508 if (idx === -1) {
5509 throw new Error('property <' + oldNameNs.name + '> not found in property list');
5510 }
5511
5512 // remove old property
5513 props.splice(idx, 1);
5514
5515 // replacing the named property is intentional
5516 //
5517 // * validate only if this is a "rename" operation
5518 // * add at specific index unless we "replace"
5519 //
5520 this.addProperty(newProperty, replace ? undefined : idx, rename);
5521
5522 // make new property available under old name
5523 propertiesByName[oldNameNs.name] = propertiesByName[oldNameNs.localName] = newProperty;
5524 };
5525
5526
5527 DescriptorBuilder.prototype.redefineProperty = function(p, targetPropertyName, replace) {
5528
5529 var nsPrefix = p.ns.prefix;
5530 var parts = targetPropertyName.split('#');
5531
5532 var name = parseName(parts[0], nsPrefix);
5533 var attrName = parseName(parts[1], name.prefix).name;
5534
5535 var redefinedProperty = this.propertiesByName[attrName];
5536 if (!redefinedProperty) {
5537 throw new Error('refined property <' + attrName + '> not found');
5538 } else {
5539 this.replaceProperty(redefinedProperty, p, replace);
5540 }
5541
5542 delete p.redefines;
5543 };
5544
5545 DescriptorBuilder.prototype.addNamedProperty = function(p, validate) {
5546 var ns = p.ns,
5547 propsByName = this.propertiesByName;
5548
5549 if (validate) {
5550 this.assertNotDefined(p, ns.name);
5551 this.assertNotDefined(p, ns.localName);
5552 }
5553
5554 propsByName[ns.name] = propsByName[ns.localName] = p;
5555 };
5556
5557 DescriptorBuilder.prototype.removeNamedProperty = function(p) {
5558 var ns = p.ns,
5559 propsByName = this.propertiesByName;
5560
5561 delete propsByName[ns.name];
5562 delete propsByName[ns.localName];
5563 };
5564
5565 DescriptorBuilder.prototype.setBodyProperty = function(p, validate) {
5566
5567 if (validate && this.bodyProperty) {
5568 throw new Error(
5569 'body property defined multiple times ' +
5570 '(<' + this.bodyProperty.ns.name + '>, <' + p.ns.name + '>)');
5571 }
5572
5573 this.bodyProperty = p;
5574 };
5575
5576 DescriptorBuilder.prototype.setIdProperty = function(p, validate) {
5577
5578 if (validate && this.idProperty) {
5579 throw new Error(
5580 'id property defined multiple times ' +
5581 '(<' + this.idProperty.ns.name + '>, <' + p.ns.name + '>)');
5582 }
5583
5584 this.idProperty = p;
5585 };
5586
5587 DescriptorBuilder.prototype.assertNotDefined = function(p, name) {
5588 var propertyName = p.name,
5589 definedProperty = this.propertiesByName[propertyName];
5590
5591 if (definedProperty) {
5592 throw new Error(
5593 'property <' + propertyName + '> already defined; ' +
5594 'override of <' + definedProperty.definedBy.ns.name + '#' + definedProperty.ns.name + '> by ' +
5595 '<' + p.definedBy.ns.name + '#' + p.ns.name + '> not allowed without redefines');
5596 }
5597 };
5598
5599 DescriptorBuilder.prototype.hasProperty = function(name) {
5600 return this.propertiesByName[name];
5601 };
5602
5603 DescriptorBuilder.prototype.addTrait = function(t, inherited) {
5604
5605 var typesByName = this.allTypesByName,
5606 types = this.allTypes;
5607
5608 var typeName = t.name;
5609
5610 if (typeName in typesByName) {
5611 return;
5612 }
5613
5614 forEach(t.properties, bind(function(p) {
5615
5616 // clone property to allow extensions
5617 p = assign({}, p, {
5618 name: p.ns.localName,
5619 inherited: inherited
5620 });
5621
5622 Object.defineProperty(p, 'definedBy', {
5623 value: t
5624 });
5625
5626 var replaces = p.replaces,
5627 redefines = p.redefines;
5628
5629 // add replace/redefine support
5630 if (replaces || redefines) {
5631 this.redefineProperty(p, replaces || redefines, replaces);
5632 } else {
5633 if (p.isBody) {
5634 this.setBodyProperty(p);
5635 }
5636 if (p.isId) {
5637 this.setIdProperty(p);
5638 }
5639 this.addProperty(p);
5640 }
5641 }, this));
5642
5643 types.push(t);
5644 typesByName[typeName] = t;
5645 };
5646
5647 /**
5648 * A registry of Moddle packages.
5649 *
5650 * @param {Array<Package>} packages
5651 * @param {Properties} properties
5652 */
5653 function Registry(packages, properties) {
5654 this.packageMap = {};
5655 this.typeMap = {};
5656
5657 this.packages = [];
5658
5659 this.properties = properties;
5660
5661 forEach(packages, bind(this.registerPackage, this));
5662 }
5663
5664
5665 Registry.prototype.getPackage = function(uriOrPrefix) {
5666 return this.packageMap[uriOrPrefix];
5667 };
5668
5669 Registry.prototype.getPackages = function() {
5670 return this.packages;
5671 };
5672
5673
5674 Registry.prototype.registerPackage = function(pkg) {
5675
5676 // copy package
5677 pkg = assign({}, pkg);
5678
5679 var pkgMap = this.packageMap;
5680
5681 ensureAvailable(pkgMap, pkg, 'prefix');
5682 ensureAvailable(pkgMap, pkg, 'uri');
5683
5684 // register types
5685 forEach(pkg.types, bind(function(descriptor) {
5686 this.registerType(descriptor, pkg);
5687 }, this));
5688
5689 pkgMap[pkg.uri] = pkgMap[pkg.prefix] = pkg;
5690 this.packages.push(pkg);
5691 };
5692
5693
5694 /**
5695 * Register a type from a specific package with us
5696 */
5697 Registry.prototype.registerType = function(type, pkg) {
5698
5699 type = assign({}, type, {
5700 superClass: (type.superClass || []).slice(),
5701 extends: (type.extends || []).slice(),
5702 properties: (type.properties || []).slice(),
5703 meta: assign((type.meta || {}))
5704 });
5705
5706 var ns = parseName(type.name, pkg.prefix),
5707 name = ns.name,
5708 propertiesByName = {};
5709
5710 // parse properties
5711 forEach(type.properties, bind(function(p) {
5712
5713 // namespace property names
5714 var propertyNs = parseName(p.name, ns.prefix),
5715 propertyName = propertyNs.name;
5716
5717 // namespace property types
5718 if (!isBuiltIn(p.type)) {
5719 p.type = parseName(p.type, propertyNs.prefix).name;
5720 }
5721
5722 assign(p, {
5723 ns: propertyNs,
5724 name: propertyName
5725 });
5726
5727 propertiesByName[propertyName] = p;
5728 }, this));
5729
5730 // update ns + name
5731 assign(type, {
5732 ns: ns,
5733 name: name,
5734 propertiesByName: propertiesByName
5735 });
5736
5737 forEach(type.extends, bind(function(extendsName) {
5738 var extended = this.typeMap[extendsName];
5739
5740 extended.traits = extended.traits || [];
5741 extended.traits.push(name);
5742 }, this));
5743
5744 // link to package
5745 this.definePackage(type, pkg);
5746
5747 // register
5748 this.typeMap[name] = type;
5749 };
5750
5751
5752 /**
5753 * Traverse the type hierarchy from bottom to top,
5754 * calling iterator with (type, inherited) for all elements in
5755 * the inheritance chain.
5756 *
5757 * @param {Object} nsName
5758 * @param {Function} iterator
5759 * @param {Boolean} [trait=false]
5760 */
5761 Registry.prototype.mapTypes = function(nsName, iterator, trait) {
5762
5763 var type = isBuiltIn(nsName.name) ? { name: nsName.name } : this.typeMap[nsName.name];
5764
5765 var self = this;
5766
5767 /**
5768 * Traverse the selected trait.
5769 *
5770 * @param {String} cls
5771 */
5772 function traverseTrait(cls) {
5773 return traverseSuper(cls, true);
5774 }
5775
5776 /**
5777 * Traverse the selected super type or trait
5778 *
5779 * @param {String} cls
5780 * @param {Boolean} [trait=false]
5781 */
5782 function traverseSuper(cls, trait) {
5783 var parentNs = parseName(cls, isBuiltIn(cls) ? '' : nsName.prefix);
5784 self.mapTypes(parentNs, iterator, trait);
5785 }
5786
5787 if (!type) {
5788 throw new Error('unknown type <' + nsName.name + '>');
5789 }
5790
5791 forEach(type.superClass, trait ? traverseTrait : traverseSuper);
5792
5793 // call iterator with (type, inherited=!trait)
5794 iterator(type, !trait);
5795
5796 forEach(type.traits, traverseTrait);
5797 };
5798
5799
5800 /**
5801 * Returns the effective descriptor for a type.
5802 *
5803 * @param {String} type the namespaced name (ns:localName) of the type
5804 *
5805 * @return {Descriptor} the resulting effective descriptor
5806 */
5807 Registry.prototype.getEffectiveDescriptor = function(name) {
5808
5809 var nsName = parseName(name);
5810
5811 var builder = new DescriptorBuilder(nsName);
5812
5813 this.mapTypes(nsName, function(type, inherited) {
5814 builder.addTrait(type, inherited);
5815 });
5816
5817 var descriptor = builder.build();
5818
5819 // define package link
5820 this.definePackage(descriptor, descriptor.allTypes[descriptor.allTypes.length - 1].$pkg);
5821
5822 return descriptor;
5823 };
5824
5825
5826 Registry.prototype.definePackage = function(target, pkg) {
5827 this.properties.define(target, '$pkg', { value: pkg });
5828 };
5829
5830
5831
5832 ///////// helpers ////////////////////////////
5833
5834 function ensureAvailable(packageMap, pkg, identifierKey) {
5835
5836 var value = pkg[identifierKey];
5837
5838 if (value in packageMap) {
5839 throw new Error('package with ' + identifierKey + ' <' + value + '> already defined');
5840 }
5841 }
5842
5843 /**
5844 * A utility that gets and sets properties of model elements.
5845 *
5846 * @param {Model} model
5847 */
5848 function Properties(model) {
5849 this.model = model;
5850 }
5851
5852
5853 /**
5854 * Sets a named property on the target element.
5855 * If the value is undefined, the property gets deleted.
5856 *
5857 * @param {Object} target
5858 * @param {String} name
5859 * @param {Object} value
5860 */
5861 Properties.prototype.set = function(target, name, value) {
5862
5863 var property = this.model.getPropertyDescriptor(target, name);
5864
5865 var propertyName = property && property.name;
5866
5867 if (isUndefined$1(value)) {
5868 // unset the property, if the specified value is undefined;
5869 // delete from $attrs (for extensions) or the target itself
5870 if (property) {
5871 delete target[propertyName];
5872 } else {
5873 delete target.$attrs[name];
5874 }
5875 } else {
5876 // set the property, defining well defined properties on the fly
5877 // or simply updating them in target.$attrs (for extensions)
5878 if (property) {
5879 if (propertyName in target) {
5880 target[propertyName] = value;
5881 } else {
5882 defineProperty$1(target, property, value);
5883 }
5884 } else {
5885 target.$attrs[name] = value;
5886 }
5887 }
5888 };
5889
5890 /**
5891 * Returns the named property of the given element
5892 *
5893 * @param {Object} target
5894 * @param {String} name
5895 *
5896 * @return {Object}
5897 */
5898 Properties.prototype.get = function(target, name) {
5899
5900 var property = this.model.getPropertyDescriptor(target, name);
5901
5902 if (!property) {
5903 return target.$attrs[name];
5904 }
5905
5906 var propertyName = property.name;
5907
5908 // check if access to collection property and lazily initialize it
5909 if (!target[propertyName] && property.isMany) {
5910 defineProperty$1(target, property, []);
5911 }
5912
5913 return target[propertyName];
5914 };
5915
5916
5917 /**
5918 * Define a property on the target element
5919 *
5920 * @param {Object} target
5921 * @param {String} name
5922 * @param {Object} options
5923 */
5924 Properties.prototype.define = function(target, name, options) {
5925 Object.defineProperty(target, name, options);
5926 };
5927
5928
5929 /**
5930 * Define the descriptor for an element
5931 */
5932 Properties.prototype.defineDescriptor = function(target, descriptor) {
5933 this.define(target, '$descriptor', { value: descriptor });
5934 };
5935
5936 /**
5937 * Define the model for an element
5938 */
5939 Properties.prototype.defineModel = function(target, model) {
5940 this.define(target, '$model', { value: model });
5941 };
5942
5943
5944 function isUndefined$1(val) {
5945 return typeof val === 'undefined';
5946 }
5947
5948 function defineProperty$1(target, property, value) {
5949 Object.defineProperty(target, property.name, {
5950 enumerable: !property.isReference,
5951 writable: true,
5952 value: value,
5953 configurable: true
5954 });
5955 }
5956
5957 //// Moddle implementation /////////////////////////////////////////////////
5958
5959 /**
5960 * @class Moddle
5961 *
5962 * A model that can be used to create elements of a specific type.
5963 *
5964 * @example
5965 *
5966 * var Moddle = require('moddle');
5967 *
5968 * var pkg = {
5969 * name: 'mypackage',
5970 * prefix: 'my',
5971 * types: [
5972 * { name: 'Root' }
5973 * ]
5974 * };
5975 *
5976 * var moddle = new Moddle([pkg]);
5977 *
5978 * @param {Array<Package>} packages the packages to contain
5979 */
5980 function Moddle(packages) {
5981
5982 this.properties = new Properties(this);
5983
5984 this.factory = new Factory(this, this.properties);
5985 this.registry = new Registry(packages, this.properties);
5986
5987 this.typeCache = {};
5988 }
5989
5990
5991 /**
5992 * Create an instance of the specified type.
5993 *
5994 * @method Moddle#create
5995 *
5996 * @example
5997 *
5998 * var foo = moddle.create('my:Foo');
5999 * var bar = moddle.create('my:Bar', { id: 'BAR_1' });
6000 *
6001 * @param {String|Object} descriptor the type descriptor or name know to the model
6002 * @param {Object} attrs a number of attributes to initialize the model instance with
6003 * @return {Object} model instance
6004 */
6005 Moddle.prototype.create = function(descriptor, attrs) {
6006 var Type = this.getType(descriptor);
6007
6008 if (!Type) {
6009 throw new Error('unknown type <' + descriptor + '>');
6010 }
6011
6012 return new Type(attrs);
6013 };
6014
6015
6016 /**
6017 * Returns the type representing a given descriptor
6018 *
6019 * @method Moddle#getType
6020 *
6021 * @example
6022 *
6023 * var Foo = moddle.getType('my:Foo');
6024 * var foo = new Foo({ 'id' : 'FOO_1' });
6025 *
6026 * @param {String|Object} descriptor the type descriptor or name know to the model
6027 * @return {Object} the type representing the descriptor
6028 */
6029 Moddle.prototype.getType = function(descriptor) {
6030
6031 var cache = this.typeCache;
6032
6033 var name = isString(descriptor) ? descriptor : descriptor.ns.name;
6034
6035 var type = cache[name];
6036
6037 if (!type) {
6038 descriptor = this.registry.getEffectiveDescriptor(name);
6039 type = cache[name] = this.factory.createType(descriptor);
6040 }
6041
6042 return type;
6043 };
6044
6045
6046 /**
6047 * Creates an any-element type to be used within model instances.
6048 *
6049 * This can be used to create custom elements that lie outside the meta-model.
6050 * The created element contains all the meta-data required to serialize it
6051 * as part of meta-model elements.
6052 *
6053 * @method Moddle#createAny
6054 *
6055 * @example
6056 *
6057 * var foo = moddle.createAny('vendor:Foo', 'http://vendor', {
6058 * value: 'bar'
6059 * });
6060 *
6061 * var container = moddle.create('my:Container', 'http://my', {
6062 * any: [ foo ]
6063 * });
6064 *
6065 * // go ahead and serialize the stuff
6066 *
6067 *
6068 * @param {String} name the name of the element
6069 * @param {String} nsUri the namespace uri of the element
6070 * @param {Object} [properties] a map of properties to initialize the instance with
6071 * @return {Object} the any type instance
6072 */
6073 Moddle.prototype.createAny = function(name, nsUri, properties) {
6074
6075 var nameNs = parseName(name);
6076
6077 var element = {
6078 $type: name,
6079 $instanceOf: function(type) {
6080 return type === this.$type;
6081 }
6082 };
6083
6084 var descriptor = {
6085 name: name,
6086 isGeneric: true,
6087 ns: {
6088 prefix: nameNs.prefix,
6089 localName: nameNs.localName,
6090 uri: nsUri
6091 }
6092 };
6093
6094 this.properties.defineDescriptor(element, descriptor);
6095 this.properties.defineModel(element, this);
6096 this.properties.define(element, '$parent', { enumerable: false, writable: true });
6097
6098 forEach(properties, function(a, key) {
6099 if (isObject(a) && a.value !== undefined) {
6100 element[a.name] = a.value;
6101 } else {
6102 element[key] = a;
6103 }
6104 });
6105
6106 return element;
6107 };
6108
6109 /**
6110 * Returns a registered package by uri or prefix
6111 *
6112 * @return {Object} the package
6113 */
6114 Moddle.prototype.getPackage = function(uriOrPrefix) {
6115 return this.registry.getPackage(uriOrPrefix);
6116 };
6117
6118 /**
6119 * Returns a snapshot of all known packages
6120 *
6121 * @return {Object} the package
6122 */
6123 Moddle.prototype.getPackages = function() {
6124 return this.registry.getPackages();
6125 };
6126
6127 /**
6128 * Returns the descriptor for an element
6129 */
6130 Moddle.prototype.getElementDescriptor = function(element) {
6131 return element.$descriptor;
6132 };
6133
6134 /**
6135 * Returns true if the given descriptor or instance
6136 * represents the given type.
6137 *
6138 * May be applied to this, if element is omitted.
6139 */
6140 Moddle.prototype.hasType = function(element, type) {
6141 if (type === undefined) {
6142 type = element;
6143 element = this;
6144 }
6145
6146 var descriptor = element.$model.getElementDescriptor(element);
6147
6148 return (type in descriptor.allTypesByName);
6149 };
6150
6151 /**
6152 * Returns the descriptor of an elements named property
6153 */
6154 Moddle.prototype.getPropertyDescriptor = function(element, property) {
6155 return this.getElementDescriptor(element).propertiesByName[property];
6156 };
6157
6158 /**
6159 * Returns a mapped type's descriptor
6160 */
6161 Moddle.prototype.getTypeDescriptor = function(type) {
6162 return this.registry.typeMap[type];
6163 };
6164
6165 var fromCharCode = String.fromCharCode;
6166
6167 var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
6168
6169 var ENTITY_PATTERN = /&#(\d+);|&#x([0-9a-f]+);|&(\w+);/ig;
6170
6171 var ENTITY_MAPPING = {
6172 'amp': '&',
6173 'apos': '\'',
6174 'gt': '>',
6175 'lt': '<',
6176 'quot': '"'
6177 };
6178
6179 // map UPPERCASE variants of supported special chars
6180 Object.keys(ENTITY_MAPPING).forEach(function(k) {
6181 ENTITY_MAPPING[k.toUpperCase()] = ENTITY_MAPPING[k];
6182 });
6183
6184
6185 function replaceEntities(_, d, x, z) {
6186
6187 // reserved names, i.e. &nbsp;
6188 if (z) {
6189 if (hasOwnProperty$1.call(ENTITY_MAPPING, z)) {
6190 return ENTITY_MAPPING[z];
6191 } else {
6192 // fall back to original value
6193 return '&' + z + ';';
6194 }
6195 }
6196
6197 // decimal encoded char
6198 if (d) {
6199 return fromCharCode(d);
6200 }
6201
6202 // hex encoded char
6203 return fromCharCode(parseInt(x, 16));
6204 }
6205
6206
6207 /**
6208 * A basic entity decoder that can decode a minimal
6209 * sub-set of reserved names (&amp;) as well as
6210 * hex (&#xaaf;) and decimal (&#1231;) encoded characters.
6211 *
6212 * @param {string} str
6213 *
6214 * @return {string} decoded string
6215 */
6216 function decodeEntities(s) {
6217 if (s.length > 3 && s.indexOf('&') !== -1) {
6218 return s.replace(ENTITY_PATTERN, replaceEntities);
6219 }
6220
6221 return s;
6222 }
6223
6224 var XSI_URI = 'http://www.w3.org/2001/XMLSchema-instance';
6225 var XSI_PREFIX = 'xsi';
6226 var XSI_TYPE = 'xsi:type';
6227
6228 var NON_WHITESPACE_OUTSIDE_ROOT_NODE = 'non-whitespace outside of root node';
6229
6230 function error(msg) {
6231 return new Error(msg);
6232 }
6233
6234 function missingNamespaceForPrefix(prefix) {
6235 return 'missing namespace for prefix <' + prefix + '>';
6236 }
6237
6238 function getter(getFn) {
6239 return {
6240 'get': getFn,
6241 'enumerable': true
6242 };
6243 }
6244
6245 function cloneNsMatrix(nsMatrix) {
6246 var clone = {}, key;
6247 for (key in nsMatrix) {
6248 clone[key] = nsMatrix[key];
6249 }
6250 return clone;
6251 }
6252
6253 function uriPrefix(prefix) {
6254 return prefix + '$uri';
6255 }
6256
6257 function buildNsMatrix(nsUriToPrefix) {
6258 var nsMatrix = {},
6259 uri,
6260 prefix;
6261
6262 for (uri in nsUriToPrefix) {
6263 prefix = nsUriToPrefix[uri];
6264 nsMatrix[prefix] = prefix;
6265 nsMatrix[uriPrefix(prefix)] = uri;
6266 }
6267
6268 return nsMatrix;
6269 }
6270
6271 function noopGetContext() {
6272 return { 'line': 0, 'column': 0 };
6273 }
6274
6275 function throwFunc(err) {
6276 throw err;
6277 }
6278
6279 /**
6280 * Creates a new parser with the given options.
6281 *
6282 * @constructor
6283 *
6284 * @param {!Object<string, ?>=} options
6285 */
6286 function Parser(options) {
6287
6288 if (!this) {
6289 return new Parser(options);
6290 }
6291
6292 var proxy = options && options['proxy'];
6293
6294 var onText,
6295 onOpenTag,
6296 onCloseTag,
6297 onCDATA,
6298 onError = throwFunc,
6299 onWarning,
6300 onComment,
6301 onQuestion,
6302 onAttention;
6303
6304 var getContext = noopGetContext;
6305
6306 /**
6307 * Do we need to parse the current elements attributes for namespaces?
6308 *
6309 * @type {boolean}
6310 */
6311 var maybeNS = false;
6312
6313 /**
6314 * Do we process namespaces at all?
6315 *
6316 * @type {boolean}
6317 */
6318 var isNamespace = false;
6319
6320 /**
6321 * The caught error returned on parse end
6322 *
6323 * @type {Error}
6324 */
6325 var returnError = null;
6326
6327 /**
6328 * Should we stop parsing?
6329 *
6330 * @type {boolean}
6331 */
6332 var parseStop = false;
6333
6334 /**
6335 * A map of { uri: prefix } used by the parser.
6336 *
6337 * This map will ensure we can normalize prefixes during processing;
6338 * for each uri, only one prefix will be exposed to the handlers.
6339 *
6340 * @type {!Object<string, string>}}
6341 */
6342 var nsUriToPrefix;
6343
6344 /**
6345 * Handle parse error.
6346 *
6347 * @param {string|Error} err
6348 */
6349 function handleError(err) {
6350 if (!(err instanceof Error)) {
6351 err = error(err);
6352 }
6353
6354 returnError = err;
6355
6356 onError(err, getContext);
6357 }
6358
6359 /**
6360 * Handle parse error.
6361 *
6362 * @param {string|Error} err
6363 */
6364 function handleWarning(err) {
6365
6366 if (!onWarning) {
6367 return;
6368 }
6369
6370 if (!(err instanceof Error)) {
6371 err = error(err);
6372 }
6373
6374 onWarning(err, getContext);
6375 }
6376
6377 /**
6378 * Register parse listener.
6379 *
6380 * @param {string} name
6381 * @param {Function} cb
6382 *
6383 * @return {Parser}
6384 */
6385 this['on'] = function(name, cb) {
6386
6387 if (typeof cb !== 'function') {
6388 throw error('required args <name, cb>');
6389 }
6390
6391 switch (name) {
6392 case 'openTag': onOpenTag = cb; break;
6393 case 'text': onText = cb; break;
6394 case 'closeTag': onCloseTag = cb; break;
6395 case 'error': onError = cb; break;
6396 case 'warn': onWarning = cb; break;
6397 case 'cdata': onCDATA = cb; break;
6398 case 'attention': onAttention = cb; break; // <!XXXXX zzzz="eeee">
6399 case 'question': onQuestion = cb; break; // <? .... ?>
6400 case 'comment': onComment = cb; break;
6401 default:
6402 throw error('unsupported event: ' + name);
6403 }
6404
6405 return this;
6406 };
6407
6408 /**
6409 * Set the namespace to prefix mapping.
6410 *
6411 * @example
6412 *
6413 * parser.ns({
6414 * 'http://foo': 'foo',
6415 * 'http://bar': 'bar'
6416 * });
6417 *
6418 * @param {!Object<string, string>} nsMap
6419 *
6420 * @return {Parser}
6421 */
6422 this['ns'] = function(nsMap) {
6423
6424 if (typeof nsMap === 'undefined') {
6425 nsMap = {};
6426 }
6427
6428 if (typeof nsMap !== 'object') {
6429 throw error('required args <nsMap={}>');
6430 }
6431
6432 var _nsUriToPrefix = {}, k;
6433
6434 for (k in nsMap) {
6435 _nsUriToPrefix[k] = nsMap[k];
6436 }
6437
6438 // FORCE default mapping for schema instance
6439 _nsUriToPrefix[XSI_URI] = XSI_PREFIX;
6440
6441 isNamespace = true;
6442 nsUriToPrefix = _nsUriToPrefix;
6443
6444 return this;
6445 };
6446
6447 /**
6448 * Parse xml string.
6449 *
6450 * @param {string} xml
6451 *
6452 * @return {Error} returnError, if not thrown
6453 */
6454 this['parse'] = function(xml) {
6455 if (typeof xml !== 'string') {
6456 throw error('required args <xml=string>');
6457 }
6458
6459 returnError = null;
6460
6461 parse(xml);
6462
6463 getContext = noopGetContext;
6464 parseStop = false;
6465
6466 return returnError;
6467 };
6468
6469 /**
6470 * Stop parsing.
6471 */
6472 this['stop'] = function() {
6473 parseStop = true;
6474 };
6475
6476 /**
6477 * Parse string, invoking configured listeners on element.
6478 *
6479 * @param {string} xml
6480 */
6481 function parse(xml) {
6482 var nsMatrixStack = isNamespace ? [] : null,
6483 nsMatrix = isNamespace ? buildNsMatrix(nsUriToPrefix) : null,
6484 _nsMatrix,
6485 nodeStack = [],
6486 anonymousNsCount = 0,
6487 tagStart = false,
6488 tagEnd = false,
6489 i = 0, j = 0,
6490 x, y, q, w,
6491 xmlns,
6492 elementName,
6493 _elementName,
6494 elementProxy
6495 ;
6496
6497 var attrsString = '',
6498 attrsStart = 0,
6499 cachedAttrs // false = parsed with errors, null = needs parsing
6500 ;
6501
6502 /**
6503 * Parse attributes on demand and returns the parsed attributes.
6504 *
6505 * Return semantics: (1) `false` on attribute parse error,
6506 * (2) object hash on extracted attrs.
6507 *
6508 * @return {boolean|Object}
6509 */
6510 function getAttrs() {
6511 if (cachedAttrs !== null) {
6512 return cachedAttrs;
6513 }
6514
6515 var nsUri,
6516 nsUriPrefix,
6517 nsName,
6518 defaultAlias = isNamespace && nsMatrix['xmlns'],
6519 attrList = isNamespace && maybeNS ? [] : null,
6520 i = attrsStart,
6521 s = attrsString,
6522 l = s.length,
6523 hasNewMatrix,
6524 newalias,
6525 value,
6526 alias,
6527 name,
6528 attrs = {},
6529 seenAttrs = {},
6530 skipAttr,
6531 w,
6532 j;
6533
6534 parseAttr:
6535 for (; i < l; i++) {
6536 skipAttr = false;
6537 w = s.charCodeAt(i);
6538
6539 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE={ \f\n\r\t\v}
6540 continue;
6541 }
6542
6543 // wait for non whitespace character
6544 if (w < 65 || w > 122 || (w > 90 && w < 97)) {
6545 if (w !== 95 && w !== 58) { // char 95"_" 58":"
6546 handleWarning('illegal first char attribute name');
6547 skipAttr = true;
6548 }
6549 }
6550
6551 // parse attribute name
6552 for (j = i + 1; j < l; j++) {
6553 w = s.charCodeAt(j);
6554
6555 if (
6556 w > 96 && w < 123 ||
6557 w > 64 && w < 91 ||
6558 w > 47 && w < 59 ||
6559 w === 46 || // '.'
6560 w === 45 || // '-'
6561 w === 95 // '_'
6562 ) {
6563 continue;
6564 }
6565
6566 // unexpected whitespace
6567 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
6568 handleWarning('missing attribute value');
6569 i = j;
6570
6571 continue parseAttr;
6572 }
6573
6574 // expected "="
6575 if (w === 61) { // "=" == 61
6576 break;
6577 }
6578
6579 handleWarning('illegal attribute name char');
6580 skipAttr = true;
6581 }
6582
6583 name = s.substring(i, j);
6584
6585 if (name === 'xmlns:xmlns') {
6586 handleWarning('illegal declaration of xmlns');
6587 skipAttr = true;
6588 }
6589
6590 w = s.charCodeAt(j + 1);
6591
6592 if (w === 34) { // '"'
6593 j = s.indexOf('"', i = j + 2);
6594
6595 if (j === -1) {
6596 j = s.indexOf('\'', i);
6597
6598 if (j !== -1) {
6599 handleWarning('attribute value quote missmatch');
6600 skipAttr = true;
6601 }
6602 }
6603
6604 } else if (w === 39) { // "'"
6605 j = s.indexOf('\'', i = j + 2);
6606
6607 if (j === -1) {
6608 j = s.indexOf('"', i);
6609
6610 if (j !== -1) {
6611 handleWarning('attribute value quote missmatch');
6612 skipAttr = true;
6613 }
6614 }
6615
6616 } else {
6617 handleWarning('missing attribute value quotes');
6618 skipAttr = true;
6619
6620 // skip to next space
6621 for (j = j + 1; j < l; j++) {
6622 w = s.charCodeAt(j + 1);
6623
6624 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
6625 break;
6626 }
6627 }
6628
6629 }
6630
6631 if (j === -1) {
6632 handleWarning('missing closing quotes');
6633
6634 j = l;
6635 skipAttr = true;
6636 }
6637
6638 if (!skipAttr) {
6639 value = s.substring(i, j);
6640 }
6641
6642 i = j;
6643
6644 // ensure SPACE follows attribute
6645 // skip illegal content otherwise
6646 // example a="b"c
6647 for (; j + 1 < l; j++) {
6648 w = s.charCodeAt(j + 1);
6649
6650 if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
6651 break;
6652 }
6653
6654 // FIRST ILLEGAL CHAR
6655 if (i === j) {
6656 handleWarning('illegal character after attribute end');
6657 skipAttr = true;
6658 }
6659 }
6660
6661 // advance cursor to next attribute
6662 i = j + 1;
6663
6664 if (skipAttr) {
6665 continue parseAttr;
6666 }
6667
6668 // check attribute re-declaration
6669 if (name in seenAttrs) {
6670 handleWarning('attribute <' + name + '> already defined');
6671 continue;
6672 }
6673
6674 seenAttrs[name] = true;
6675
6676 if (!isNamespace) {
6677 attrs[name] = value;
6678 continue;
6679 }
6680
6681 // try to extract namespace information
6682 if (maybeNS) {
6683 newalias = (
6684 name === 'xmlns'
6685 ? 'xmlns'
6686 : (name.charCodeAt(0) === 120 && name.substr(0, 6) === 'xmlns:')
6687 ? name.substr(6)
6688 : null
6689 );
6690
6691 // handle xmlns(:alias) assignment
6692 if (newalias !== null) {
6693 nsUri = decodeEntities(value);
6694 nsUriPrefix = uriPrefix(newalias);
6695
6696 alias = nsUriToPrefix[nsUri];
6697
6698 if (!alias) {
6699 // no prefix defined or prefix collision
6700 if (
6701 (newalias === 'xmlns') ||
6702 (nsUriPrefix in nsMatrix && nsMatrix[nsUriPrefix] !== nsUri)
6703 ) {
6704 // alocate free ns prefix
6705 do {
6706 alias = 'ns' + (anonymousNsCount++);
6707 } while (typeof nsMatrix[alias] !== 'undefined');
6708 } else {
6709 alias = newalias;
6710 }
6711
6712 nsUriToPrefix[nsUri] = alias;
6713 }
6714
6715 if (nsMatrix[newalias] !== alias) {
6716 if (!hasNewMatrix) {
6717 nsMatrix = cloneNsMatrix(nsMatrix);
6718 hasNewMatrix = true;
6719 }
6720
6721 nsMatrix[newalias] = alias;
6722 if (newalias === 'xmlns') {
6723 nsMatrix[uriPrefix(alias)] = nsUri;
6724 defaultAlias = alias;
6725 }
6726
6727 nsMatrix[nsUriPrefix] = nsUri;
6728 }
6729
6730 // expose xmlns(:asd)="..." in attributes
6731 attrs[name] = value;
6732 continue;
6733 }
6734
6735 // collect attributes until all namespace
6736 // declarations are processed
6737 attrList.push(name, value);
6738 continue;
6739
6740 } /** end if (maybeNs) */
6741
6742 // handle attributes on element without
6743 // namespace declarations
6744 w = name.indexOf(':');
6745 if (w === -1) {
6746 attrs[name] = value;
6747 continue;
6748 }
6749
6750 // normalize ns attribute name
6751 if (!(nsName = nsMatrix[name.substring(0, w)])) {
6752 handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
6753 continue;
6754 }
6755
6756 name = defaultAlias === nsName
6757 ? name.substr(w + 1)
6758 : nsName + name.substr(w);
6759 // end: normalize ns attribute name
6760
6761 // normalize xsi:type ns attribute value
6762 if (name === XSI_TYPE) {
6763 w = value.indexOf(':');
6764
6765 if (w !== -1) {
6766 nsName = value.substring(0, w);
6767 // handle default prefixes, i.e. xs:String gracefully
6768 nsName = nsMatrix[nsName] || nsName;
6769 value = nsName + value.substring(w);
6770 } else {
6771 value = defaultAlias + ':' + value;
6772 }
6773 }
6774 // end: normalize xsi:type ns attribute value
6775
6776 attrs[name] = value;
6777 }
6778
6779
6780 // handle deferred, possibly namespaced attributes
6781 if (maybeNS) {
6782
6783 // normalize captured attributes
6784 for (i = 0, l = attrList.length; i < l; i++) {
6785
6786 name = attrList[i++];
6787 value = attrList[i];
6788
6789 w = name.indexOf(':');
6790
6791 if (w !== -1) {
6792 // normalize ns attribute name
6793 if (!(nsName = nsMatrix[name.substring(0, w)])) {
6794 handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
6795 continue;
6796 }
6797
6798 name = defaultAlias === nsName
6799 ? name.substr(w + 1)
6800 : nsName + name.substr(w);
6801 // end: normalize ns attribute name
6802
6803 // normalize xsi:type ns attribute value
6804 if (name === XSI_TYPE) {
6805 w = value.indexOf(':');
6806
6807 if (w !== -1) {
6808 nsName = value.substring(0, w);
6809 // handle default prefixes, i.e. xs:String gracefully
6810 nsName = nsMatrix[nsName] || nsName;
6811 value = nsName + value.substring(w);
6812 } else {
6813 value = defaultAlias + ':' + value;
6814 }
6815 }
6816 // end: normalize xsi:type ns attribute value
6817 }
6818
6819 attrs[name] = value;
6820 }
6821 // end: normalize captured attributes
6822 }
6823
6824 return cachedAttrs = attrs;
6825 }
6826
6827 /**
6828 * Extract the parse context { line, column, part }
6829 * from the current parser position.
6830 *
6831 * @return {Object} parse context
6832 */
6833 function getParseContext() {
6834 var splitsRe = /(\r\n|\r|\n)/g;
6835
6836 var line = 0;
6837 var column = 0;
6838 var startOfLine = 0;
6839 var endOfLine = j;
6840 var match;
6841 var data;
6842
6843 while (i >= startOfLine) {
6844
6845 match = splitsRe.exec(xml);
6846
6847 if (!match) {
6848 break;
6849 }
6850
6851 // end of line = (break idx + break chars)
6852 endOfLine = match[0].length + match.index;
6853
6854 if (endOfLine > i) {
6855 break;
6856 }
6857
6858 // advance to next line
6859 line += 1;
6860
6861 startOfLine = endOfLine;
6862 }
6863
6864 // EOF errors
6865 if (i == -1) {
6866 column = endOfLine;
6867 data = xml.substring(j);
6868 } else
6869 // start errors
6870 if (j === 0) {
6871 console.log(i - startOfLine);
6872 data = xml.substring(j, i);
6873 }
6874 // other errors
6875 else {
6876 column = i - startOfLine;
6877 data = (j == -1 ? xml.substring(i) : xml.substring(i, j + 1));
6878 }
6879
6880 return {
6881 'data': data,
6882 'line': line,
6883 'column': column
6884 };
6885 }
6886
6887 getContext = getParseContext;
6888
6889
6890 if (proxy) {
6891 elementProxy = Object.create({}, {
6892 'name': getter(function() {
6893 return elementName;
6894 }),
6895 'originalName': getter(function() {
6896 return _elementName;
6897 }),
6898 'attrs': getter(getAttrs),
6899 'ns': getter(function() {
6900 return nsMatrix;
6901 })
6902 });
6903 }
6904
6905 // actual parse logic
6906 while (j !== -1) {
6907
6908 if (xml.charCodeAt(j) === 60) { // "<"
6909 i = j;
6910 } else {
6911 i = xml.indexOf('<', j);
6912 }
6913
6914 // parse end
6915 if (i === -1) {
6916 if (nodeStack.length) {
6917 return handleError('unexpected end of file');
6918 }
6919
6920 if (j === 0) {
6921 return handleError('missing start tag');
6922 }
6923
6924 if (j < xml.length) {
6925 if (xml.substring(j).trim()) {
6926 handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
6927 }
6928 }
6929
6930 return;
6931 }
6932
6933 // parse text
6934 if (j !== i) {
6935
6936 if (nodeStack.length) {
6937 if (onText) {
6938 onText(xml.substring(j, i), decodeEntities, getContext);
6939
6940 if (parseStop) {
6941 return;
6942 }
6943 }
6944 } else {
6945 if (xml.substring(j, i).trim()) {
6946 handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
6947
6948 if (parseStop) {
6949 return;
6950 }
6951 }
6952 }
6953 }
6954
6955 w = xml.charCodeAt(i+1);
6956
6957 // parse comments + CDATA
6958 if (w === 33) { // "!"
6959 w = xml.charCodeAt(i+2);
6960 if (w === 91 && xml.substr(i + 3, 6) === 'CDATA[') { // 91 == "["
6961 j = xml.indexOf(']]>', i);
6962 if (j === -1) {
6963 return handleError('unclosed cdata');
6964 }
6965
6966 if (onCDATA) {
6967 onCDATA(xml.substring(i + 9, j), getContext);
6968 if (parseStop) {
6969 return;
6970 }
6971 }
6972
6973 j += 3;
6974 continue;
6975 }
6976
6977
6978 if (w === 45 && xml.charCodeAt(i + 3) === 45) { // 45 == "-"
6979 j = xml.indexOf('-->', i);
6980 if (j === -1) {
6981 return handleError('unclosed comment');
6982 }
6983
6984
6985 if (onComment) {
6986 onComment(xml.substring(i + 4, j), decodeEntities, getContext);
6987 if (parseStop) {
6988 return;
6989 }
6990 }
6991
6992 j += 3;
6993 continue;
6994 }
6995
6996 j = xml.indexOf('>', i + 1);
6997 if (j === -1) {
6998 return handleError('unclosed tag');
6999 }
7000
7001 if (onAttention) {
7002 onAttention(xml.substring(i, j + 1), decodeEntities, getContext);
7003 if (parseStop) {
7004 return;
7005 }
7006 }
7007
7008 j += 1;
7009 continue;
7010 }
7011
7012 if (w === 63) { // "?"
7013 j = xml.indexOf('?>', i);
7014 if (j === -1) {
7015 return handleError('unclosed question');
7016 }
7017
7018 if (onQuestion) {
7019 onQuestion(xml.substring(i, j + 2), getContext);
7020 if (parseStop) {
7021 return;
7022 }
7023 }
7024
7025 j += 2;
7026 continue;
7027 }
7028
7029 j = xml.indexOf('>', i + 1);
7030
7031 if (j == -1) {
7032 return handleError('unclosed tag');
7033 }
7034
7035 // don't process attributes;
7036 // there are none
7037 cachedAttrs = {};
7038
7039 // if (xml.charCodeAt(i+1) === 47) { // </...
7040 if (w === 47) { // </...
7041 tagStart = false;
7042 tagEnd = true;
7043
7044 if (!nodeStack.length) {
7045 return handleError('missing open tag');
7046 }
7047
7048 // verify open <-> close tag match
7049 x = elementName = nodeStack.pop();
7050 q = i + 2 + x.length;
7051
7052 if (xml.substring(i + 2, q) !== x) {
7053 return handleError('closing tag mismatch');
7054 }
7055
7056 // verify chars in close tag
7057 for (; q < j; q++) {
7058 w = xml.charCodeAt(q);
7059
7060 if (w === 32 || (w > 8 && w < 14)) { // \f\n\r\t\v space
7061 continue;
7062 }
7063
7064 return handleError('close tag');
7065 }
7066
7067 } else {
7068 if (xml.charCodeAt(j - 1) === 47) { // .../>
7069 x = elementName = xml.substring(i + 1, j - 1);
7070
7071 tagStart = true;
7072 tagEnd = true;
7073
7074 } else {
7075 x = elementName = xml.substring(i + 1, j);
7076
7077 tagStart = true;
7078 tagEnd = false;
7079 }
7080
7081 if (!(w > 96 && w < 123 || w > 64 && w < 91 || w === 95 || w === 58)) { // char 95"_" 58":"
7082 return handleError('illegal first char nodeName');
7083 }
7084
7085 for (q = 1, y = x.length; q < y; q++) {
7086 w = x.charCodeAt(q);
7087
7088 if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w == 46) {
7089 continue;
7090 }
7091
7092 if (w === 32 || (w < 14 && w > 8)) { // \f\n\r\t\v space
7093 elementName = x.substring(0, q);
7094 // maybe there are attributes
7095 cachedAttrs = null;
7096 break;
7097 }
7098
7099 return handleError('invalid nodeName');
7100 }
7101
7102 if (!tagEnd) {
7103 nodeStack.push(elementName);
7104 }
7105 }
7106
7107 if (isNamespace) {
7108
7109 _nsMatrix = nsMatrix;
7110
7111 if (tagStart) {
7112 // remember old namespace
7113 // unless we're self-closing
7114 if (!tagEnd) {
7115 nsMatrixStack.push(_nsMatrix);
7116 }
7117
7118 if (cachedAttrs === null) {
7119 // quick check, whether there may be namespace
7120 // declarations on the node; if that is the case
7121 // we need to eagerly parse the node attributes
7122 if ((maybeNS = x.indexOf('xmlns', q) !== -1)) {
7123 attrsStart = q;
7124 attrsString = x;
7125
7126 getAttrs();
7127
7128 maybeNS = false;
7129 }
7130 }
7131 }
7132
7133 _elementName = elementName;
7134
7135 w = elementName.indexOf(':');
7136 if (w !== -1) {
7137 xmlns = nsMatrix[elementName.substring(0, w)];
7138
7139 // prefix given; namespace must exist
7140 if (!xmlns) {
7141 return handleError('missing namespace on <' + _elementName + '>');
7142 }
7143
7144 elementName = elementName.substr(w + 1);
7145 } else {
7146 xmlns = nsMatrix['xmlns'];
7147
7148 // if no default namespace is defined,
7149 // we'll import the element as anonymous.
7150 //
7151 // it is up to users to correct that to the document defined
7152 // targetNamespace, or whatever their undersanding of the
7153 // XML spec mandates.
7154 }
7155
7156 // adjust namespace prefixs as configured
7157 if (xmlns) {
7158 elementName = xmlns + ':' + elementName;
7159 }
7160
7161 }
7162
7163 if (tagStart) {
7164 attrsStart = q;
7165 attrsString = x;
7166
7167 if (onOpenTag) {
7168 if (proxy) {
7169 onOpenTag(elementProxy, decodeEntities, tagEnd, getContext);
7170 } else {
7171 onOpenTag(elementName, getAttrs, decodeEntities, tagEnd, getContext);
7172 }
7173
7174 if (parseStop) {
7175 return;
7176 }
7177 }
7178
7179 }
7180
7181 if (tagEnd) {
7182
7183 if (onCloseTag) {
7184 onCloseTag(proxy ? elementProxy : elementName, decodeEntities, tagStart, getContext);
7185
7186 if (parseStop) {
7187 return;
7188 }
7189 }
7190
7191 // restore old namespace
7192 if (isNamespace) {
7193 if (!tagStart) {
7194 nsMatrix = nsMatrixStack.pop();
7195 } else {
7196 nsMatrix = _nsMatrix;
7197 }
7198 }
7199 }
7200
7201 j += 1;
7202 }
7203 } /** end parse */
7204
7205 }
7206
7207 function hasLowerCaseAlias(pkg) {
7208 return pkg.xml && pkg.xml.tagAlias === 'lowerCase';
7209 }
7210
7211 var DEFAULT_NS_MAP = {
7212 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'
7213 };
7214
7215 var XSI_TYPE$1 = 'xsi:type';
7216
7217 function serializeFormat(element) {
7218 return element.xml && element.xml.serialize;
7219 }
7220
7221 function serializeAsType(element) {
7222 return serializeFormat(element) === XSI_TYPE$1;
7223 }
7224
7225 function serializeAsProperty(element) {
7226 return serializeFormat(element) === 'property';
7227 }
7228
7229 function capitalize(str) {
7230 return str.charAt(0).toUpperCase() + str.slice(1);
7231 }
7232
7233 function aliasToName(aliasNs, pkg) {
7234
7235 if (!hasLowerCaseAlias(pkg)) {
7236 return aliasNs.name;
7237 }
7238
7239 return aliasNs.prefix + ':' + capitalize(aliasNs.localName);
7240 }
7241
7242 function prefixedToName(nameNs, pkg) {
7243
7244 var name = nameNs.name,
7245 localName = nameNs.localName;
7246
7247 var typePrefix = pkg.xml && pkg.xml.typePrefix;
7248
7249 if (typePrefix && localName.indexOf(typePrefix) === 0) {
7250 return nameNs.prefix + ':' + localName.slice(typePrefix.length);
7251 } else {
7252 return name;
7253 }
7254 }
7255
7256 function normalizeXsiTypeName(name, model) {
7257
7258 var nameNs = parseName(name);
7259 var pkg = model.getPackage(nameNs.prefix);
7260
7261 return prefixedToName(nameNs, pkg);
7262 }
7263
7264 function error$1(message) {
7265 return new Error(message);
7266 }
7267
7268 /**
7269 * Get the moddle descriptor for a given instance or type.
7270 *
7271 * @param {ModdleElement|Function} element
7272 *
7273 * @return {Object} the moddle descriptor
7274 */
7275 function getModdleDescriptor(element) {
7276 return element.$descriptor;
7277 }
7278
7279 function defer(fn) {
7280 setTimeout(fn, 0);
7281 }
7282
7283 /**
7284 * A parse context.
7285 *
7286 * @class
7287 *
7288 * @param {Object} options
7289 * @param {ElementHandler} options.rootHandler the root handler for parsing a document
7290 * @param {boolean} [options.lax=false] whether or not to ignore invalid elements
7291 */
7292 function Context(options) {
7293
7294 /**
7295 * @property {ElementHandler} rootHandler
7296 */
7297
7298 /**
7299 * @property {Boolean} lax
7300 */
7301
7302 assign(this, options);
7303
7304 this.elementsById = {};
7305 this.references = [];
7306 this.warnings = [];
7307
7308 /**
7309 * Add an unresolved reference.
7310 *
7311 * @param {Object} reference
7312 */
7313 this.addReference = function(reference) {
7314 this.references.push(reference);
7315 };
7316
7317 /**
7318 * Add a processed element.
7319 *
7320 * @param {ModdleElement} element
7321 */
7322 this.addElement = function(element) {
7323
7324 if (!element) {
7325 throw error$1('expected element');
7326 }
7327
7328 var elementsById = this.elementsById;
7329
7330 var descriptor = getModdleDescriptor(element);
7331
7332 var idProperty = descriptor.idProperty,
7333 id;
7334
7335 if (idProperty) {
7336 id = element.get(idProperty.name);
7337
7338 if (id) {
7339 // for QName validation as per http://www.w3.org/TR/REC-xml/#NT-NameChar
7340 if (!/^([a-z][\w-.]*:)?[a-z_][\w-.]*$/i.test(id)) {
7341 throw new Error('illegal ID <' + id + '>');
7342 }
7343
7344 if (elementsById[id]) {
7345 throw error$1('duplicate ID <' + id + '>');
7346 }
7347
7348 elementsById[id] = element;
7349 }
7350 }
7351 };
7352
7353 /**
7354 * Add an import warning.
7355 *
7356 * @param {Object} warning
7357 * @param {String} warning.message
7358 * @param {Error} [warning.error]
7359 */
7360 this.addWarning = function(warning) {
7361 this.warnings.push(warning);
7362 };
7363 }
7364
7365 function BaseHandler() {}
7366
7367 BaseHandler.prototype.handleEnd = function() {};
7368 BaseHandler.prototype.handleText = function() {};
7369 BaseHandler.prototype.handleNode = function() {};
7370
7371
7372 /**
7373 * A simple pass through handler that does nothing except for
7374 * ignoring all input it receives.
7375 *
7376 * This is used to ignore unknown elements and
7377 * attributes.
7378 */
7379 function NoopHandler() { }
7380
7381 NoopHandler.prototype = Object.create(BaseHandler.prototype);
7382
7383 NoopHandler.prototype.handleNode = function() {
7384 return this;
7385 };
7386
7387 function BodyHandler() {}
7388
7389 BodyHandler.prototype = Object.create(BaseHandler.prototype);
7390
7391 BodyHandler.prototype.handleText = function(text) {
7392 this.body = (this.body || '') + text;
7393 };
7394
7395 function ReferenceHandler(property, context) {
7396 this.property = property;
7397 this.context = context;
7398 }
7399
7400 ReferenceHandler.prototype = Object.create(BodyHandler.prototype);
7401
7402 ReferenceHandler.prototype.handleNode = function(node) {
7403
7404 if (this.element) {
7405 throw error$1('expected no sub nodes');
7406 } else {
7407 this.element = this.createReference(node);
7408 }
7409
7410 return this;
7411 };
7412
7413 ReferenceHandler.prototype.handleEnd = function() {
7414 this.element.id = this.body;
7415 };
7416
7417 ReferenceHandler.prototype.createReference = function(node) {
7418 return {
7419 property: this.property.ns.name,
7420 id: ''
7421 };
7422 };
7423
7424 function ValueHandler(propertyDesc, element) {
7425 this.element = element;
7426 this.propertyDesc = propertyDesc;
7427 }
7428
7429 ValueHandler.prototype = Object.create(BodyHandler.prototype);
7430
7431 ValueHandler.prototype.handleEnd = function() {
7432
7433 var value = this.body || '',
7434 element = this.element,
7435 propertyDesc = this.propertyDesc;
7436
7437 value = coerceType(propertyDesc.type, value);
7438
7439 if (propertyDesc.isMany) {
7440 element.get(propertyDesc.name).push(value);
7441 } else {
7442 element.set(propertyDesc.name, value);
7443 }
7444 };
7445
7446
7447 function BaseElementHandler() {}
7448
7449 BaseElementHandler.prototype = Object.create(BodyHandler.prototype);
7450
7451 BaseElementHandler.prototype.handleNode = function(node) {
7452 var parser = this,
7453 element = this.element;
7454
7455 if (!element) {
7456 element = this.element = this.createElement(node);
7457
7458 this.context.addElement(element);
7459 } else {
7460 parser = this.handleChild(node);
7461 }
7462
7463 return parser;
7464 };
7465
7466 /**
7467 * @class Reader.ElementHandler
7468 *
7469 */
7470 function ElementHandler(model, typeName, context) {
7471 this.model = model;
7472 this.type = model.getType(typeName);
7473 this.context = context;
7474 }
7475
7476 ElementHandler.prototype = Object.create(BaseElementHandler.prototype);
7477
7478 ElementHandler.prototype.addReference = function(reference) {
7479 this.context.addReference(reference);
7480 };
7481
7482 ElementHandler.prototype.handleText = function(text) {
7483
7484 var element = this.element,
7485 descriptor = getModdleDescriptor(element),
7486 bodyProperty = descriptor.bodyProperty;
7487
7488 if (!bodyProperty) {
7489 throw error$1('unexpected body text <' + text + '>');
7490 }
7491
7492 BodyHandler.prototype.handleText.call(this, text);
7493 };
7494
7495 ElementHandler.prototype.handleEnd = function() {
7496
7497 var value = this.body,
7498 element = this.element,
7499 descriptor = getModdleDescriptor(element),
7500 bodyProperty = descriptor.bodyProperty;
7501
7502 if (bodyProperty && value !== undefined) {
7503 value = coerceType(bodyProperty.type, value);
7504 element.set(bodyProperty.name, value);
7505 }
7506 };
7507
7508 /**
7509 * Create an instance of the model from the given node.
7510 *
7511 * @param {Element} node the xml node
7512 */
7513 ElementHandler.prototype.createElement = function(node) {
7514 var attributes = node.attributes,
7515 Type = this.type,
7516 descriptor = getModdleDescriptor(Type),
7517 context = this.context,
7518 instance = new Type({}),
7519 model = this.model,
7520 propNameNs;
7521
7522 forEach(attributes, function(value, name) {
7523
7524 var prop = descriptor.propertiesByName[name],
7525 values;
7526
7527 if (prop && prop.isReference) {
7528
7529 if (!prop.isMany) {
7530 context.addReference({
7531 element: instance,
7532 property: prop.ns.name,
7533 id: value
7534 });
7535 } else {
7536 // IDREFS: parse references as whitespace-separated list
7537 values = value.split(' ');
7538
7539 forEach(values, function(v) {
7540 context.addReference({
7541 element: instance,
7542 property: prop.ns.name,
7543 id: v
7544 });
7545 });
7546 }
7547
7548 } else {
7549 if (prop) {
7550 value = coerceType(prop.type, value);
7551 } else
7552 if (name !== 'xmlns') {
7553 propNameNs = parseName(name, descriptor.ns.prefix);
7554
7555 // check whether attribute is defined in a well-known namespace
7556 // if that is the case we emit a warning to indicate potential misuse
7557 if (model.getPackage(propNameNs.prefix)) {
7558
7559 context.addWarning({
7560 message: 'unknown attribute <' + name + '>',
7561 element: instance,
7562 property: name,
7563 value: value
7564 });
7565 }
7566 }
7567
7568 instance.set(name, value);
7569 }
7570 });
7571
7572 return instance;
7573 };
7574
7575 ElementHandler.prototype.getPropertyForNode = function(node) {
7576
7577 var name = node.name;
7578 var nameNs = parseName(name);
7579
7580 var type = this.type,
7581 model = this.model,
7582 descriptor = getModdleDescriptor(type);
7583
7584 var propertyName = nameNs.name,
7585 property = descriptor.propertiesByName[propertyName],
7586 elementTypeName,
7587 elementType;
7588
7589 // search for properties by name first
7590
7591 if (property) {
7592
7593 if (serializeAsType(property)) {
7594 elementTypeName = node.attributes[XSI_TYPE$1];
7595
7596 // xsi type is optional, if it does not exists the
7597 // default type is assumed
7598 if (elementTypeName) {
7599
7600 // take possible type prefixes from XML
7601 // into account, i.e.: xsi:type="t{ActualType}"
7602 elementTypeName = normalizeXsiTypeName(elementTypeName, model);
7603
7604 elementType = model.getType(elementTypeName);
7605
7606 return assign({}, property, {
7607 effectiveType: getModdleDescriptor(elementType).name
7608 });
7609 }
7610 }
7611
7612 // search for properties by name first
7613 return property;
7614 }
7615
7616 var pkg = model.getPackage(nameNs.prefix);
7617
7618 if (pkg) {
7619 elementTypeName = aliasToName(nameNs, pkg);
7620 elementType = model.getType(elementTypeName);
7621
7622 // search for collection members later
7623 property = find(descriptor.properties, function(p) {
7624 return !p.isVirtual && !p.isReference && !p.isAttribute && elementType.hasType(p.type);
7625 });
7626
7627 if (property) {
7628 return assign({}, property, {
7629 effectiveType: getModdleDescriptor(elementType).name
7630 });
7631 }
7632 } else {
7633 // parse unknown element (maybe extension)
7634 property = find(descriptor.properties, function(p) {
7635 return !p.isReference && !p.isAttribute && p.type === 'Element';
7636 });
7637
7638 if (property) {
7639 return property;
7640 }
7641 }
7642
7643 throw error$1('unrecognized element <' + nameNs.name + '>');
7644 };
7645
7646 ElementHandler.prototype.toString = function() {
7647 return 'ElementDescriptor[' + getModdleDescriptor(this.type).name + ']';
7648 };
7649
7650 ElementHandler.prototype.valueHandler = function(propertyDesc, element) {
7651 return new ValueHandler(propertyDesc, element);
7652 };
7653
7654 ElementHandler.prototype.referenceHandler = function(propertyDesc) {
7655 return new ReferenceHandler(propertyDesc, this.context);
7656 };
7657
7658 ElementHandler.prototype.handler = function(type) {
7659 if (type === 'Element') {
7660 return new GenericElementHandler(this.model, type, this.context);
7661 } else {
7662 return new ElementHandler(this.model, type, this.context);
7663 }
7664 };
7665
7666 /**
7667 * Handle the child element parsing
7668 *
7669 * @param {Element} node the xml node
7670 */
7671 ElementHandler.prototype.handleChild = function(node) {
7672 var propertyDesc, type, element, childHandler;
7673
7674 propertyDesc = this.getPropertyForNode(node);
7675 element = this.element;
7676
7677 type = propertyDesc.effectiveType || propertyDesc.type;
7678
7679 if (isSimple(type)) {
7680 return this.valueHandler(propertyDesc, element);
7681 }
7682
7683 if (propertyDesc.isReference) {
7684 childHandler = this.referenceHandler(propertyDesc).handleNode(node);
7685 } else {
7686 childHandler = this.handler(type).handleNode(node);
7687 }
7688
7689 var newElement = childHandler.element;
7690
7691 // child handles may decide to skip elements
7692 // by not returning anything
7693 if (newElement !== undefined) {
7694
7695 if (propertyDesc.isMany) {
7696 element.get(propertyDesc.name).push(newElement);
7697 } else {
7698 element.set(propertyDesc.name, newElement);
7699 }
7700
7701 if (propertyDesc.isReference) {
7702 assign(newElement, {
7703 element: element
7704 });
7705
7706 this.context.addReference(newElement);
7707 } else {
7708 // establish child -> parent relationship
7709 newElement.$parent = element;
7710 }
7711 }
7712
7713 return childHandler;
7714 };
7715
7716 /**
7717 * An element handler that performs special validation
7718 * to ensure the node it gets initialized with matches
7719 * the handlers type (namespace wise).
7720 *
7721 * @param {Moddle} model
7722 * @param {String} typeName
7723 * @param {Context} context
7724 */
7725 function RootElementHandler(model, typeName, context) {
7726 ElementHandler.call(this, model, typeName, context);
7727 }
7728
7729 RootElementHandler.prototype = Object.create(ElementHandler.prototype);
7730
7731 RootElementHandler.prototype.createElement = function(node) {
7732
7733 var name = node.name,
7734 nameNs = parseName(name),
7735 model = this.model,
7736 type = this.type,
7737 pkg = model.getPackage(nameNs.prefix),
7738 typeName = pkg && aliasToName(nameNs, pkg) || name;
7739
7740 // verify the correct namespace if we parse
7741 // the first element in the handler tree
7742 //
7743 // this ensures we don't mistakenly import wrong namespace elements
7744 if (!type.hasType(typeName)) {
7745 throw error$1('unexpected element <' + node.originalName + '>');
7746 }
7747
7748 return ElementHandler.prototype.createElement.call(this, node);
7749 };
7750
7751
7752 function GenericElementHandler(model, typeName, context) {
7753 this.model = model;
7754 this.context = context;
7755 }
7756
7757 GenericElementHandler.prototype = Object.create(BaseElementHandler.prototype);
7758
7759 GenericElementHandler.prototype.createElement = function(node) {
7760
7761 var name = node.name,
7762 ns = parseName(name),
7763 prefix = ns.prefix,
7764 uri = node.ns[prefix + '$uri'],
7765 attributes = node.attributes;
7766
7767 return this.model.createAny(name, uri, attributes);
7768 };
7769
7770 GenericElementHandler.prototype.handleChild = function(node) {
7771
7772 var handler = new GenericElementHandler(this.model, 'Element', this.context).handleNode(node),
7773 element = this.element;
7774
7775 var newElement = handler.element,
7776 children;
7777
7778 if (newElement !== undefined) {
7779 children = element.$children = element.$children || [];
7780 children.push(newElement);
7781
7782 // establish child -> parent relationship
7783 newElement.$parent = element;
7784 }
7785
7786 return handler;
7787 };
7788
7789 GenericElementHandler.prototype.handleEnd = function() {
7790 if (this.body) {
7791 this.element.$body = this.body;
7792 }
7793 };
7794
7795 /**
7796 * A reader for a meta-model
7797 *
7798 * @param {Object} options
7799 * @param {Model} options.model used to read xml files
7800 * @param {Boolean} options.lax whether to make parse errors warnings
7801 */
7802 function Reader(options) {
7803
7804 if (options instanceof Moddle) {
7805 options = {
7806 model: options
7807 };
7808 }
7809
7810 assign(this, { lax: false }, options);
7811 }
7812
7813
7814 /**
7815 * Parse the given XML into a moddle document tree.
7816 *
7817 * @param {String} xml
7818 * @param {ElementHandler|Object} options or rootHandler
7819 * @param {Function} done
7820 */
7821 Reader.prototype.fromXML = function(xml, options, done) {
7822
7823 var rootHandler = options.rootHandler;
7824
7825 if (options instanceof ElementHandler) {
7826 // root handler passed via (xml, { rootHandler: ElementHandler }, ...)
7827 rootHandler = options;
7828 options = {};
7829 } else {
7830 if (typeof options === 'string') {
7831 // rootHandler passed via (xml, 'someString', ...)
7832 rootHandler = this.handler(options);
7833 options = {};
7834 } else if (typeof rootHandler === 'string') {
7835 // rootHandler passed via (xml, { rootHandler: 'someString' }, ...)
7836 rootHandler = this.handler(rootHandler);
7837 }
7838 }
7839
7840 var model = this.model,
7841 lax = this.lax;
7842
7843 var context = new Context(assign({}, options, { rootHandler: rootHandler })),
7844 parser = new Parser({ proxy: true }),
7845 stack = createStack();
7846
7847 rootHandler.context = context;
7848
7849 // push root handler
7850 stack.push(rootHandler);
7851
7852
7853 /**
7854 * Handle error.
7855 *
7856 * @param {Error} err
7857 * @param {Function} getContext
7858 * @param {boolean} lax
7859 *
7860 * @return {boolean} true if handled
7861 */
7862 function handleError(err, getContext, lax) {
7863
7864 var ctx = getContext();
7865
7866 var line = ctx.line,
7867 column = ctx.column,
7868 data = ctx.data;
7869
7870 // we receive the full context data here,
7871 // for elements trim down the information
7872 // to the tag name, only
7873 if (data.charAt(0) === '<' && data.indexOf(' ') !== -1) {
7874 data = data.slice(0, data.indexOf(' ')) + '>';
7875 }
7876
7877 var message =
7878 'unparsable content ' + (data ? data + ' ' : '') + 'detected\n\t' +
7879 'line: ' + line + '\n\t' +
7880 'column: ' + column + '\n\t' +
7881 'nested error: ' + err.message;
7882
7883 if (lax) {
7884 context.addWarning({
7885 message: message,
7886 error: err
7887 });
7888
7889 return true;
7890 } else {
7891 throw error$1(message);
7892 }
7893 }
7894
7895 function handleWarning(err, getContext) {
7896 // just like handling errors in <lax=true> mode
7897 return handleError(err, getContext, true);
7898 }
7899
7900 /**
7901 * Resolve collected references on parse end.
7902 */
7903 function resolveReferences() {
7904
7905 var elementsById = context.elementsById;
7906 var references = context.references;
7907
7908 var i, r;
7909
7910 for (i = 0; (r = references[i]); i++) {
7911 var element = r.element;
7912 var reference = elementsById[r.id];
7913 var property = getModdleDescriptor(element).propertiesByName[r.property];
7914
7915 if (!reference) {
7916 context.addWarning({
7917 message: 'unresolved reference <' + r.id + '>',
7918 element: r.element,
7919 property: r.property,
7920 value: r.id
7921 });
7922 }
7923
7924 if (property.isMany) {
7925 var collection = element.get(property.name),
7926 idx = collection.indexOf(r);
7927
7928 // we replace an existing place holder (idx != -1) or
7929 // append to the collection instead
7930 if (idx === -1) {
7931 idx = collection.length;
7932 }
7933
7934 if (!reference) {
7935 // remove unresolvable reference
7936 collection.splice(idx, 1);
7937 } else {
7938 // add or update reference in collection
7939 collection[idx] = reference;
7940 }
7941 } else {
7942 element.set(property.name, reference);
7943 }
7944 }
7945 }
7946
7947 function handleClose() {
7948 stack.pop().handleEnd();
7949 }
7950
7951 var PREAMBLE_START_PATTERN = /^<\?xml /i;
7952
7953 var ENCODING_PATTERN = / encoding="([^"]+)"/i;
7954
7955 var UTF_8_PATTERN = /^utf-8$/i;
7956
7957 function handleQuestion(question) {
7958
7959 if (!PREAMBLE_START_PATTERN.test(question)) {
7960 return;
7961 }
7962
7963 var match = ENCODING_PATTERN.exec(question);
7964 var encoding = match && match[1];
7965
7966 if (!encoding || UTF_8_PATTERN.test(encoding)) {
7967 return;
7968 }
7969
7970 context.addWarning({
7971 message:
7972 'unsupported document encoding <' + encoding + '>, ' +
7973 'falling back to UTF-8'
7974 });
7975 }
7976
7977 function handleOpen(node, getContext) {
7978 var handler = stack.peek();
7979
7980 try {
7981 stack.push(handler.handleNode(node));
7982 } catch (err) {
7983
7984 if (handleError(err, getContext, lax)) {
7985 stack.push(new NoopHandler());
7986 }
7987 }
7988 }
7989
7990 function handleCData(text, getContext) {
7991
7992 try {
7993 stack.peek().handleText(text);
7994 } catch (err) {
7995 handleWarning(err, getContext);
7996 }
7997 }
7998
7999 function handleText(text, getContext) {
8000 // strip whitespace only nodes, i.e. before
8001 // <!CDATA[ ... ]> sections and in between tags
8002 text = text.trim();
8003
8004 if (!text) {
8005 return;
8006 }
8007
8008 handleCData(text, getContext);
8009 }
8010
8011 var uriMap = model.getPackages().reduce(function(uriMap, p) {
8012 uriMap[p.uri] = p.prefix;
8013
8014 return uriMap;
8015 }, {});
8016
8017 parser
8018 .ns(uriMap)
8019 .on('openTag', function(obj, decodeStr, selfClosing, getContext) {
8020
8021 // gracefully handle unparsable attributes (attrs=false)
8022 var attrs = obj.attrs || {};
8023
8024 var decodedAttrs = Object.keys(attrs).reduce(function(d, key) {
8025 var value = decodeStr(attrs[key]);
8026
8027 d[key] = value;
8028
8029 return d;
8030 }, {});
8031
8032 var node = {
8033 name: obj.name,
8034 originalName: obj.originalName,
8035 attributes: decodedAttrs,
8036 ns: obj.ns
8037 };
8038
8039 handleOpen(node, getContext);
8040 })
8041 .on('question', handleQuestion)
8042 .on('closeTag', handleClose)
8043 .on('cdata', handleCData)
8044 .on('text', function(text, decodeEntities, getContext) {
8045 handleText(decodeEntities(text), getContext);
8046 })
8047 .on('error', handleError)
8048 .on('warn', handleWarning);
8049
8050 // deferred parse XML to make loading really ascnchronous
8051 // this ensures the execution environment (node or browser)
8052 // is kept responsive and that certain optimization strategies
8053 // can kick in
8054 defer(function() {
8055 var err;
8056
8057 try {
8058 parser.parse(xml);
8059
8060 resolveReferences();
8061 } catch (e) {
8062 err = e;
8063 }
8064
8065 var element = rootHandler.element;
8066
8067 // handle the situation that we could not extract
8068 // the desired root element from the document
8069 if (!err && !element) {
8070 err = error$1('failed to parse document as <' + rootHandler.type.$descriptor.name + '>');
8071 }
8072
8073 done(err, err ? undefined : element, context);
8074 });
8075 };
8076
8077 Reader.prototype.handler = function(name) {
8078 return new RootElementHandler(this.model, name);
8079 };
8080
8081
8082 // helpers //////////////////////////
8083
8084 function createStack() {
8085 var stack = [];
8086
8087 Object.defineProperty(stack, 'peek', {
8088 value: function() {
8089 return this[this.length - 1];
8090 }
8091 });
8092
8093 return stack;
8094 }
8095
8096 var XML_PREAMBLE = '<?xml version="1.0" encoding="UTF-8"?>\n';
8097
8098 var ESCAPE_ATTR_CHARS = /<|>|'|"|&|\n\r|\n/g;
8099 var ESCAPE_CHARS = /<|>|&/g;
8100
8101
8102 function Namespaces(parent) {
8103
8104 var prefixMap = {};
8105 var uriMap = {};
8106 var used = {};
8107
8108 var wellknown = [];
8109 var custom = [];
8110
8111 // API
8112
8113 this.byUri = function(uri) {
8114 return uriMap[uri] || (
8115 parent && parent.byUri(uri)
8116 );
8117 };
8118
8119 this.add = function(ns, isWellknown) {
8120
8121 uriMap[ns.uri] = ns;
8122
8123 if (isWellknown) {
8124 wellknown.push(ns);
8125 } else {
8126 custom.push(ns);
8127 }
8128
8129 this.mapPrefix(ns.prefix, ns.uri);
8130 };
8131
8132 this.uriByPrefix = function(prefix) {
8133 return prefixMap[prefix || 'xmlns'];
8134 };
8135
8136 this.mapPrefix = function(prefix, uri) {
8137 prefixMap[prefix || 'xmlns'] = uri;
8138 };
8139
8140 this.logUsed = function(ns) {
8141 var uri = ns.uri;
8142
8143 used[uri] = this.byUri(uri);
8144 };
8145
8146 this.getUsed = function(ns) {
8147
8148 function isUsed(ns) {
8149 return used[ns.uri];
8150 }
8151
8152 var allNs = [].concat(wellknown, custom);
8153
8154 return allNs.filter(isUsed);
8155 };
8156
8157 }
8158
8159 function lower(string) {
8160 return string.charAt(0).toLowerCase() + string.slice(1);
8161 }
8162
8163 function nameToAlias(name, pkg) {
8164 if (hasLowerCaseAlias(pkg)) {
8165 return lower(name);
8166 } else {
8167 return name;
8168 }
8169 }
8170
8171 function inherits(ctor, superCtor) {
8172 ctor.super_ = superCtor;
8173 ctor.prototype = Object.create(superCtor.prototype, {
8174 constructor: {
8175 value: ctor,
8176 enumerable: false,
8177 writable: true,
8178 configurable: true
8179 }
8180 });
8181 }
8182
8183 function nsName(ns) {
8184 if (isString(ns)) {
8185 return ns;
8186 } else {
8187 return (ns.prefix ? ns.prefix + ':' : '') + ns.localName;
8188 }
8189 }
8190
8191 function getNsAttrs(namespaces) {
8192
8193 return map(namespaces.getUsed(), function(ns) {
8194 var name = 'xmlns' + (ns.prefix ? ':' + ns.prefix : '');
8195 return { name: name, value: ns.uri };
8196 });
8197
8198 }
8199
8200 function getElementNs(ns, descriptor) {
8201 if (descriptor.isGeneric) {
8202 return assign({ localName: descriptor.ns.localName }, ns);
8203 } else {
8204 return assign({ localName: nameToAlias(descriptor.ns.localName, descriptor.$pkg) }, ns);
8205 }
8206 }
8207
8208 function getPropertyNs(ns, descriptor) {
8209 return assign({ localName: descriptor.ns.localName }, ns);
8210 }
8211
8212 function getSerializableProperties(element) {
8213 var descriptor = element.$descriptor;
8214
8215 return filter(descriptor.properties, function(p) {
8216 var name = p.name;
8217
8218 if (p.isVirtual) {
8219 return false;
8220 }
8221
8222 // do not serialize defaults
8223 if (!element.hasOwnProperty(name)) {
8224 return false;
8225 }
8226
8227 var value = element[name];
8228
8229 // do not serialize default equals
8230 if (value === p.default) {
8231 return false;
8232 }
8233
8234 // do not serialize null properties
8235 if (value === null) {
8236 return false;
8237 }
8238
8239 return p.isMany ? value.length : true;
8240 });
8241 }
8242
8243 var ESCAPE_ATTR_MAP = {
8244 '\n': '#10',
8245 '\n\r': '#10',
8246 '"': '#34',
8247 '\'': '#39',
8248 '<': '#60',
8249 '>': '#62',
8250 '&': '#38'
8251 };
8252
8253 var ESCAPE_MAP = {
8254 '<': 'lt',
8255 '>': 'gt',
8256 '&': 'amp'
8257 };
8258
8259 function escape$1(str, charPattern, replaceMap) {
8260
8261 // ensure we are handling strings here
8262 str = isString(str) ? str : '' + str;
8263
8264 return str.replace(charPattern, function(s) {
8265 return '&' + replaceMap[s] + ';';
8266 });
8267 }
8268
8269 /**
8270 * Escape a string attribute to not contain any bad values (line breaks, '"', ...)
8271 *
8272 * @param {String} str the string to escape
8273 * @return {String} the escaped string
8274 */
8275 function escapeAttr(str) {
8276 return escape$1(str, ESCAPE_ATTR_CHARS, ESCAPE_ATTR_MAP);
8277 }
8278
8279 function escapeBody(str) {
8280 return escape$1(str, ESCAPE_CHARS, ESCAPE_MAP);
8281 }
8282
8283 function filterAttributes(props) {
8284 return filter(props, function(p) { return p.isAttr; });
8285 }
8286
8287 function filterContained(props) {
8288 return filter(props, function(p) { return !p.isAttr; });
8289 }
8290
8291
8292 function ReferenceSerializer(tagName) {
8293 this.tagName = tagName;
8294 }
8295
8296 ReferenceSerializer.prototype.build = function(element) {
8297 this.element = element;
8298 return this;
8299 };
8300
8301 ReferenceSerializer.prototype.serializeTo = function(writer) {
8302 writer
8303 .appendIndent()
8304 .append('<' + this.tagName + '>' + this.element.id + '</' + this.tagName + '>')
8305 .appendNewLine();
8306 };
8307
8308 function BodySerializer() {}
8309
8310 BodySerializer.prototype.serializeValue =
8311 BodySerializer.prototype.serializeTo = function(writer) {
8312 writer.append(
8313 this.escape
8314 ? escapeBody(this.value)
8315 : this.value
8316 );
8317 };
8318
8319 BodySerializer.prototype.build = function(prop, value) {
8320 this.value = value;
8321
8322 if (prop.type === 'String' && value.search(ESCAPE_CHARS) !== -1) {
8323 this.escape = true;
8324 }
8325
8326 return this;
8327 };
8328
8329 function ValueSerializer(tagName) {
8330 this.tagName = tagName;
8331 }
8332
8333 inherits(ValueSerializer, BodySerializer);
8334
8335 ValueSerializer.prototype.serializeTo = function(writer) {
8336
8337 writer
8338 .appendIndent()
8339 .append('<' + this.tagName + '>');
8340
8341 this.serializeValue(writer);
8342
8343 writer
8344 .append('</' + this.tagName + '>')
8345 .appendNewLine();
8346 };
8347
8348 function ElementSerializer(parent, propertyDescriptor) {
8349 this.body = [];
8350 this.attrs = [];
8351
8352 this.parent = parent;
8353 this.propertyDescriptor = propertyDescriptor;
8354 }
8355
8356 ElementSerializer.prototype.build = function(element) {
8357 this.element = element;
8358
8359 var elementDescriptor = element.$descriptor,
8360 propertyDescriptor = this.propertyDescriptor;
8361
8362 var otherAttrs,
8363 properties;
8364
8365 var isGeneric = elementDescriptor.isGeneric;
8366
8367 if (isGeneric) {
8368 otherAttrs = this.parseGeneric(element);
8369 } else {
8370 otherAttrs = this.parseNsAttributes(element);
8371 }
8372
8373 if (propertyDescriptor) {
8374 this.ns = this.nsPropertyTagName(propertyDescriptor);
8375 } else {
8376 this.ns = this.nsTagName(elementDescriptor);
8377 }
8378
8379 // compute tag name
8380 this.tagName = this.addTagName(this.ns);
8381
8382 if (!isGeneric) {
8383 properties = getSerializableProperties(element);
8384
8385 this.parseAttributes(filterAttributes(properties));
8386 this.parseContainments(filterContained(properties));
8387 }
8388
8389 this.parseGenericAttributes(element, otherAttrs);
8390
8391 return this;
8392 };
8393
8394 ElementSerializer.prototype.nsTagName = function(descriptor) {
8395 var effectiveNs = this.logNamespaceUsed(descriptor.ns);
8396 return getElementNs(effectiveNs, descriptor);
8397 };
8398
8399 ElementSerializer.prototype.nsPropertyTagName = function(descriptor) {
8400 var effectiveNs = this.logNamespaceUsed(descriptor.ns);
8401 return getPropertyNs(effectiveNs, descriptor);
8402 };
8403
8404 ElementSerializer.prototype.isLocalNs = function(ns) {
8405 return ns.uri === this.ns.uri;
8406 };
8407
8408 /**
8409 * Get the actual ns attribute name for the given element.
8410 *
8411 * @param {Object} element
8412 * @param {Boolean} [element.inherited=false]
8413 *
8414 * @return {Object} nsName
8415 */
8416 ElementSerializer.prototype.nsAttributeName = function(element) {
8417
8418 var ns;
8419
8420 if (isString(element)) {
8421 ns = parseName(element);
8422 } else {
8423 ns = element.ns;
8424 }
8425
8426 // return just local name for inherited attributes
8427 if (element.inherited) {
8428 return { localName: ns.localName };
8429 }
8430
8431 // parse + log effective ns
8432 var effectiveNs = this.logNamespaceUsed(ns);
8433
8434 // LOG ACTUAL namespace use
8435 this.getNamespaces().logUsed(effectiveNs);
8436
8437 // strip prefix if same namespace like parent
8438 if (this.isLocalNs(effectiveNs)) {
8439 return { localName: ns.localName };
8440 } else {
8441 return assign({ localName: ns.localName }, effectiveNs);
8442 }
8443 };
8444
8445 ElementSerializer.prototype.parseGeneric = function(element) {
8446
8447 var self = this,
8448 body = this.body;
8449
8450 var attributes = [];
8451
8452 forEach(element, function(val, key) {
8453
8454 var nonNsAttr;
8455
8456 if (key === '$body') {
8457 body.push(new BodySerializer().build({ type: 'String' }, val));
8458 } else
8459 if (key === '$children') {
8460 forEach(val, function(child) {
8461 body.push(new ElementSerializer(self).build(child));
8462 });
8463 } else
8464 if (key.indexOf('$') !== 0) {
8465 nonNsAttr = self.parseNsAttribute(element, key, val);
8466
8467 if (nonNsAttr) {
8468 attributes.push({ name: key, value: val });
8469 }
8470 }
8471 });
8472
8473 return attributes;
8474 };
8475
8476 ElementSerializer.prototype.parseNsAttribute = function(element, name, value) {
8477 var model = element.$model;
8478
8479 var nameNs = parseName(name);
8480
8481 var ns;
8482
8483 // parse xmlns:foo="http://foo.bar"
8484 if (nameNs.prefix === 'xmlns') {
8485 ns = { prefix: nameNs.localName, uri: value };
8486 }
8487
8488 // parse xmlns="http://foo.bar"
8489 if (!nameNs.prefix && nameNs.localName === 'xmlns') {
8490 ns = { uri: value };
8491 }
8492
8493 if (!ns) {
8494 return {
8495 name: name,
8496 value: value
8497 };
8498 }
8499
8500 if (model && model.getPackage(value)) {
8501 // register well known namespace
8502 this.logNamespace(ns, true, true);
8503 } else {
8504 // log custom namespace directly as used
8505 var actualNs = this.logNamespaceUsed(ns, true);
8506
8507 this.getNamespaces().logUsed(actualNs);
8508 }
8509 };
8510
8511
8512 /**
8513 * Parse namespaces and return a list of left over generic attributes
8514 *
8515 * @param {Object} element
8516 * @return {Array<Object>}
8517 */
8518 ElementSerializer.prototype.parseNsAttributes = function(element, attrs) {
8519 var self = this;
8520
8521 var genericAttrs = element.$attrs;
8522
8523 var attributes = [];
8524
8525 // parse namespace attributes first
8526 // and log them. push non namespace attributes to a list
8527 // and process them later
8528 forEach(genericAttrs, function(value, name) {
8529
8530 var nonNsAttr = self.parseNsAttribute(element, name, value);
8531
8532 if (nonNsAttr) {
8533 attributes.push(nonNsAttr);
8534 }
8535 });
8536
8537 return attributes;
8538 };
8539
8540 ElementSerializer.prototype.parseGenericAttributes = function(element, attributes) {
8541
8542 var self = this;
8543
8544 forEach(attributes, function(attr) {
8545
8546 // do not serialize xsi:type attribute
8547 // it is set manually based on the actual implementation type
8548 if (attr.name === XSI_TYPE$1) {
8549 return;
8550 }
8551
8552 try {
8553 self.addAttribute(self.nsAttributeName(attr.name), attr.value);
8554 } catch (e) {
8555 console.warn(
8556 'missing namespace information for ',
8557 attr.name, '=', attr.value, 'on', element,
8558 e);
8559 }
8560 });
8561 };
8562
8563 ElementSerializer.prototype.parseContainments = function(properties) {
8564
8565 var self = this,
8566 body = this.body,
8567 element = this.element;
8568
8569 forEach(properties, function(p) {
8570 var value = element.get(p.name),
8571 isReference = p.isReference,
8572 isMany = p.isMany;
8573
8574 if (!isMany) {
8575 value = [ value ];
8576 }
8577
8578 if (p.isBody) {
8579 body.push(new BodySerializer().build(p, value[0]));
8580 } else
8581 if (isSimple(p.type)) {
8582 forEach(value, function(v) {
8583 body.push(new ValueSerializer(self.addTagName(self.nsPropertyTagName(p))).build(p, v));
8584 });
8585 } else
8586 if (isReference) {
8587 forEach(value, function(v) {
8588 body.push(new ReferenceSerializer(self.addTagName(self.nsPropertyTagName(p))).build(v));
8589 });
8590 } else {
8591 // allow serialization via type
8592 // rather than element name
8593 var asType = serializeAsType(p),
8594 asProperty = serializeAsProperty(p);
8595
8596 forEach(value, function(v) {
8597 var serializer;
8598
8599 if (asType) {
8600 serializer = new TypeSerializer(self, p);
8601 } else
8602 if (asProperty) {
8603 serializer = new ElementSerializer(self, p);
8604 } else {
8605 serializer = new ElementSerializer(self);
8606 }
8607
8608 body.push(serializer.build(v));
8609 });
8610 }
8611 });
8612 };
8613
8614 ElementSerializer.prototype.getNamespaces = function(local) {
8615
8616 var namespaces = this.namespaces,
8617 parent = this.parent,
8618 parentNamespaces;
8619
8620 if (!namespaces) {
8621 parentNamespaces = parent && parent.getNamespaces();
8622
8623 if (local || !parentNamespaces) {
8624 this.namespaces = namespaces = new Namespaces(parentNamespaces);
8625 } else {
8626 namespaces = parentNamespaces;
8627 }
8628 }
8629
8630 return namespaces;
8631 };
8632
8633 ElementSerializer.prototype.logNamespace = function(ns, wellknown, local) {
8634 var namespaces = this.getNamespaces(local);
8635
8636 var nsUri = ns.uri,
8637 nsPrefix = ns.prefix;
8638
8639 var existing = namespaces.byUri(nsUri);
8640
8641 if (!existing) {
8642 namespaces.add(ns, wellknown);
8643 }
8644
8645 namespaces.mapPrefix(nsPrefix, nsUri);
8646
8647 return ns;
8648 };
8649
8650 ElementSerializer.prototype.logNamespaceUsed = function(ns, local) {
8651 var element = this.element,
8652 model = element.$model,
8653 namespaces = this.getNamespaces(local);
8654
8655 // ns may be
8656 //
8657 // * prefix only
8658 // * prefix:uri
8659 // * localName only
8660
8661 var prefix = ns.prefix,
8662 uri = ns.uri,
8663 newPrefix, idx,
8664 wellknownUri;
8665
8666 // handle anonymous namespaces (elementForm=unqualified), cf. #23
8667 if (!prefix && !uri) {
8668 return { localName: ns.localName };
8669 }
8670
8671 wellknownUri = DEFAULT_NS_MAP[prefix] || model && (model.getPackage(prefix) || {}).uri;
8672
8673 uri = uri || wellknownUri || namespaces.uriByPrefix(prefix);
8674
8675 if (!uri) {
8676 throw new Error('no namespace uri given for prefix <' + prefix + '>');
8677 }
8678
8679 ns = namespaces.byUri(uri);
8680
8681 if (!ns) {
8682 newPrefix = prefix;
8683 idx = 1;
8684
8685 // find a prefix that is not mapped yet
8686 while (namespaces.uriByPrefix(newPrefix)) {
8687 newPrefix = prefix + '_' + idx++;
8688 }
8689
8690 ns = this.logNamespace({ prefix: newPrefix, uri: uri }, wellknownUri === uri);
8691 }
8692
8693 if (prefix) {
8694 namespaces.mapPrefix(prefix, uri);
8695 }
8696
8697 return ns;
8698 };
8699
8700 ElementSerializer.prototype.parseAttributes = function(properties) {
8701 var self = this,
8702 element = this.element;
8703
8704 forEach(properties, function(p) {
8705
8706 var value = element.get(p.name);
8707
8708 if (p.isReference) {
8709
8710 if (!p.isMany) {
8711 value = value.id;
8712 }
8713 else {
8714 var values = [];
8715 forEach(value, function(v) {
8716 values.push(v.id);
8717 });
8718 // IDREFS is a whitespace-separated list of references.
8719 value = values.join(' ');
8720 }
8721
8722 }
8723
8724 self.addAttribute(self.nsAttributeName(p), value);
8725 });
8726 };
8727
8728 ElementSerializer.prototype.addTagName = function(nsTagName) {
8729 var actualNs = this.logNamespaceUsed(nsTagName);
8730
8731 this.getNamespaces().logUsed(actualNs);
8732
8733 return nsName(nsTagName);
8734 };
8735
8736 ElementSerializer.prototype.addAttribute = function(name, value) {
8737 var attrs = this.attrs;
8738
8739 if (isString(value)) {
8740 value = escapeAttr(value);
8741 }
8742
8743 attrs.push({ name: name, value: value });
8744 };
8745
8746 ElementSerializer.prototype.serializeAttributes = function(writer) {
8747 var attrs = this.attrs,
8748 namespaces = this.namespaces;
8749
8750 if (namespaces) {
8751 attrs = getNsAttrs(namespaces).concat(attrs);
8752 }
8753
8754 forEach(attrs, function(a) {
8755 writer
8756 .append(' ')
8757 .append(nsName(a.name)).append('="').append(a.value).append('"');
8758 });
8759 };
8760
8761 ElementSerializer.prototype.serializeTo = function(writer) {
8762 var firstBody = this.body[0],
8763 indent = firstBody && firstBody.constructor !== BodySerializer;
8764
8765 writer
8766 .appendIndent()
8767 .append('<' + this.tagName);
8768
8769 this.serializeAttributes(writer);
8770
8771 writer.append(firstBody ? '>' : ' />');
8772
8773 if (firstBody) {
8774
8775 if (indent) {
8776 writer
8777 .appendNewLine()
8778 .indent();
8779 }
8780
8781 forEach(this.body, function(b) {
8782 b.serializeTo(writer);
8783 });
8784
8785 if (indent) {
8786 writer
8787 .unindent()
8788 .appendIndent();
8789 }
8790
8791 writer.append('</' + this.tagName + '>');
8792 }
8793
8794 writer.appendNewLine();
8795 };
8796
8797 /**
8798 * A serializer for types that handles serialization of data types
8799 */
8800 function TypeSerializer(parent, propertyDescriptor) {
8801 ElementSerializer.call(this, parent, propertyDescriptor);
8802 }
8803
8804 inherits(TypeSerializer, ElementSerializer);
8805
8806 TypeSerializer.prototype.parseNsAttributes = function(element) {
8807
8808 // extracted attributes
8809 var attributes = ElementSerializer.prototype.parseNsAttributes.call(this, element);
8810
8811 var descriptor = element.$descriptor;
8812
8813 // only serialize xsi:type if necessary
8814 if (descriptor.name === this.propertyDescriptor.type) {
8815 return attributes;
8816 }
8817
8818 var typeNs = this.typeNs = this.nsTagName(descriptor);
8819 this.getNamespaces().logUsed(this.typeNs);
8820
8821 // add xsi:type attribute to represent the elements
8822 // actual type
8823
8824 var pkg = element.$model.getPackage(typeNs.uri),
8825 typePrefix = (pkg.xml && pkg.xml.typePrefix) || '';
8826
8827 this.addAttribute(
8828 this.nsAttributeName(XSI_TYPE$1),
8829 (typeNs.prefix ? typeNs.prefix + ':' : '') + typePrefix + descriptor.ns.localName
8830 );
8831
8832 return attributes;
8833 };
8834
8835 TypeSerializer.prototype.isLocalNs = function(ns) {
8836 return ns.uri === (this.typeNs || this.ns).uri;
8837 };
8838
8839 function SavingWriter() {
8840 this.value = '';
8841
8842 this.write = function(str) {
8843 this.value += str;
8844 };
8845 }
8846
8847 function FormatingWriter(out, format) {
8848
8849 var indent = [''];
8850
8851 this.append = function(str) {
8852 out.write(str);
8853
8854 return this;
8855 };
8856
8857 this.appendNewLine = function() {
8858 if (format) {
8859 out.write('\n');
8860 }
8861
8862 return this;
8863 };
8864
8865 this.appendIndent = function() {
8866 if (format) {
8867 out.write(indent.join(' '));
8868 }
8869
8870 return this;
8871 };
8872
8873 this.indent = function() {
8874 indent.push('');
8875 return this;
8876 };
8877
8878 this.unindent = function() {
8879 indent.pop();
8880 return this;
8881 };
8882 }
8883
8884 /**
8885 * A writer for meta-model backed document trees
8886 *
8887 * @param {Object} options output options to pass into the writer
8888 */
8889 function Writer(options) {
8890
8891 options = assign({ format: false, preamble: true }, options || {});
8892
8893 function toXML(tree, writer) {
8894 var internalWriter = writer || new SavingWriter();
8895 var formatingWriter = new FormatingWriter(internalWriter, options.format);
8896
8897 if (options.preamble) {
8898 formatingWriter.append(XML_PREAMBLE);
8899 }
8900
8901 new ElementSerializer().build(tree).serializeTo(formatingWriter);
8902
8903 if (!writer) {
8904 return internalWriter.value;
8905 }
8906 }
8907
8908 return {
8909 toXML: toXML
8910 };
8911 }
8912
8913 /**
8914 * A sub class of {@link Moddle} with support for import and export of BPMN 2.0 xml files.
8915 *
8916 * @class BpmnModdle
8917 * @extends Moddle
8918 *
8919 * @param {Object|Array} packages to use for instantiating the model
8920 * @param {Object} [options] additional options to pass over
8921 */
8922 function BpmnModdle(packages, options) {
8923 Moddle.call(this, packages, options);
8924 }
8925
8926 BpmnModdle.prototype = Object.create(Moddle.prototype);
8927
8928
8929 /**
8930 * Instantiates a BPMN model tree from a given xml string.
8931 *
8932 * @param {String} xmlStr
8933 * @param {String} [typeName='bpmn:Definitions'] name of the root element
8934 * @param {Object} [options] options to pass to the underlying reader
8935 * @param {Function} done callback that is invoked with (err, result, parseContext)
8936 * once the import completes
8937 */
8938 BpmnModdle.prototype.fromXML = function(xmlStr, typeName, options, done) {
8939
8940 if (!isString(typeName)) {
8941 done = options;
8942 options = typeName;
8943 typeName = 'bpmn:Definitions';
8944 }
8945
8946 if (isFunction(options)) {
8947 done = options;
8948 options = {};
8949 }
8950
8951 var reader = new Reader(assign({ model: this, lax: true }, options));
8952 var rootHandler = reader.handler(typeName);
8953
8954 reader.fromXML(xmlStr, rootHandler, done);
8955 };
8956
8957
8958 /**
8959 * Serializes a BPMN 2.0 object tree to XML.
8960 *
8961 * @param {String} element the root element, typically an instance of `bpmn:Definitions`
8962 * @param {Object} [options] to pass to the underlying writer
8963 * @param {Function} done callback invoked with (err, xmlStr) once the import completes
8964 */
8965 BpmnModdle.prototype.toXML = function(element, options, done) {
8966
8967 if (isFunction(options)) {
8968 done = options;
8969 options = {};
8970 }
8971
8972 var writer = new Writer(options);
8973
8974 var result;
8975 var err;
8976
8977 try {
8978 result = writer.toXML(element);
8979 } catch (e) {
8980 err = e;
8981 }
8982
8983 return done(err, result);
8984 };
8985
8986 var name = "BPMN20";
8987 var uri = "http://www.omg.org/spec/BPMN/20100524/MODEL";
8988 var associations = [
8989 ];
8990 var types$1 = [
8991 {
8992 name: "Interface",
8993 superClass: [
8994 "RootElement"
8995 ],
8996 properties: [
8997 {
8998 name: "name",
8999 isAttr: true,
9000 type: "String"
9001 },
9002 {
9003 name: "operations",
9004 type: "Operation",
9005 isMany: true
9006 },
9007 {
9008 name: "implementationRef",
9009 type: "String",
9010 isAttr: true
9011 }
9012 ]
9013 },
9014 {
9015 name: "Operation",
9016 superClass: [
9017 "BaseElement"
9018 ],
9019 properties: [
9020 {
9021 name: "name",
9022 isAttr: true,
9023 type: "String"
9024 },
9025 {
9026 name: "inMessageRef",
9027 type: "Message",
9028 isReference: true
9029 },
9030 {
9031 name: "outMessageRef",
9032 type: "Message",
9033 isReference: true
9034 },
9035 {
9036 name: "errorRef",
9037 type: "Error",
9038 isMany: true,
9039 isReference: true
9040 },
9041 {
9042 name: "implementationRef",
9043 type: "String",
9044 isAttr: true
9045 }
9046 ]
9047 },
9048 {
9049 name: "EndPoint",
9050 superClass: [
9051 "RootElement"
9052 ]
9053 },
9054 {
9055 name: "Auditing",
9056 superClass: [
9057 "BaseElement"
9058 ]
9059 },
9060 {
9061 name: "GlobalTask",
9062 superClass: [
9063 "CallableElement"
9064 ],
9065 properties: [
9066 {
9067 name: "resources",
9068 type: "ResourceRole",
9069 isMany: true
9070 }
9071 ]
9072 },
9073 {
9074 name: "Monitoring",
9075 superClass: [
9076 "BaseElement"
9077 ]
9078 },
9079 {
9080 name: "Performer",
9081 superClass: [
9082 "ResourceRole"
9083 ]
9084 },
9085 {
9086 name: "Process",
9087 superClass: [
9088 "FlowElementsContainer",
9089 "CallableElement"
9090 ],
9091 properties: [
9092 {
9093 name: "processType",
9094 type: "ProcessType",
9095 isAttr: true
9096 },
9097 {
9098 name: "isClosed",
9099 isAttr: true,
9100 type: "Boolean"
9101 },
9102 {
9103 name: "auditing",
9104 type: "Auditing"
9105 },
9106 {
9107 name: "monitoring",
9108 type: "Monitoring"
9109 },
9110 {
9111 name: "properties",
9112 type: "Property",
9113 isMany: true
9114 },
9115 {
9116 name: "laneSets",
9117 type: "LaneSet",
9118 isMany: true,
9119 replaces: "FlowElementsContainer#laneSets"
9120 },
9121 {
9122 name: "flowElements",
9123 type: "FlowElement",
9124 isMany: true,
9125 replaces: "FlowElementsContainer#flowElements"
9126 },
9127 {
9128 name: "artifacts",
9129 type: "Artifact",
9130 isMany: true
9131 },
9132 {
9133 name: "resources",
9134 type: "ResourceRole",
9135 isMany: true
9136 },
9137 {
9138 name: "correlationSubscriptions",
9139 type: "CorrelationSubscription",
9140 isMany: true
9141 },
9142 {
9143 name: "supports",
9144 type: "Process",
9145 isMany: true,
9146 isReference: true
9147 },
9148 {
9149 name: "definitionalCollaborationRef",
9150 type: "Collaboration",
9151 isAttr: true,
9152 isReference: true
9153 },
9154 {
9155 name: "isExecutable",
9156 isAttr: true,
9157 type: "Boolean"
9158 }
9159 ]
9160 },
9161 {
9162 name: "LaneSet",
9163 superClass: [
9164 "BaseElement"
9165 ],
9166 properties: [
9167 {
9168 name: "lanes",
9169 type: "Lane",
9170 isMany: true
9171 },
9172 {
9173 name: "name",
9174 isAttr: true,
9175 type: "String"
9176 }
9177 ]
9178 },
9179 {
9180 name: "Lane",
9181 superClass: [
9182 "BaseElement"
9183 ],
9184 properties: [
9185 {
9186 name: "name",
9187 isAttr: true,
9188 type: "String"
9189 },
9190 {
9191 name: "partitionElementRef",
9192 type: "BaseElement",
9193 isAttr: true,
9194 isReference: true
9195 },
9196 {
9197 name: "partitionElement",
9198 type: "BaseElement"
9199 },
9200 {
9201 name: "flowNodeRef",
9202 type: "FlowNode",
9203 isMany: true,
9204 isReference: true
9205 },
9206 {
9207 name: "childLaneSet",
9208 type: "LaneSet",
9209 xml: {
9210 serialize: "xsi:type"
9211 }
9212 }
9213 ]
9214 },
9215 {
9216 name: "GlobalManualTask",
9217 superClass: [
9218 "GlobalTask"
9219 ]
9220 },
9221 {
9222 name: "ManualTask",
9223 superClass: [
9224 "Task"
9225 ]
9226 },
9227 {
9228 name: "UserTask",
9229 superClass: [
9230 "Task"
9231 ],
9232 properties: [
9233 {
9234 name: "renderings",
9235 type: "Rendering",
9236 isMany: true
9237 },
9238 {
9239 name: "implementation",
9240 isAttr: true,
9241 type: "String"
9242 }
9243 ]
9244 },
9245 {
9246 name: "Rendering",
9247 superClass: [
9248 "BaseElement"
9249 ]
9250 },
9251 {
9252 name: "HumanPerformer",
9253 superClass: [
9254 "Performer"
9255 ]
9256 },
9257 {
9258 name: "PotentialOwner",
9259 superClass: [
9260 "HumanPerformer"
9261 ]
9262 },
9263 {
9264 name: "GlobalUserTask",
9265 superClass: [
9266 "GlobalTask"
9267 ],
9268 properties: [
9269 {
9270 name: "implementation",
9271 isAttr: true,
9272 type: "String"
9273 },
9274 {
9275 name: "renderings",
9276 type: "Rendering",
9277 isMany: true
9278 }
9279 ]
9280 },
9281 {
9282 name: "Gateway",
9283 isAbstract: true,
9284 superClass: [
9285 "FlowNode"
9286 ],
9287 properties: [
9288 {
9289 name: "gatewayDirection",
9290 type: "GatewayDirection",
9291 "default": "Unspecified",
9292 isAttr: true
9293 }
9294 ]
9295 },
9296 {
9297 name: "EventBasedGateway",
9298 superClass: [
9299 "Gateway"
9300 ],
9301 properties: [
9302 {
9303 name: "instantiate",
9304 "default": false,
9305 isAttr: true,
9306 type: "Boolean"
9307 },
9308 {
9309 name: "eventGatewayType",
9310 type: "EventBasedGatewayType",
9311 isAttr: true,
9312 "default": "Exclusive"
9313 }
9314 ]
9315 },
9316 {
9317 name: "ComplexGateway",
9318 superClass: [
9319 "Gateway"
9320 ],
9321 properties: [
9322 {
9323 name: "activationCondition",
9324 type: "Expression",
9325 xml: {
9326 serialize: "xsi:type"
9327 }
9328 },
9329 {
9330 name: "default",
9331 type: "SequenceFlow",
9332 isAttr: true,
9333 isReference: true
9334 }
9335 ]
9336 },
9337 {
9338 name: "ExclusiveGateway",
9339 superClass: [
9340 "Gateway"
9341 ],
9342 properties: [
9343 {
9344 name: "default",
9345 type: "SequenceFlow",
9346 isAttr: true,
9347 isReference: true
9348 }
9349 ]
9350 },
9351 {
9352 name: "InclusiveGateway",
9353 superClass: [
9354 "Gateway"
9355 ],
9356 properties: [
9357 {
9358 name: "default",
9359 type: "SequenceFlow",
9360 isAttr: true,
9361 isReference: true
9362 }
9363 ]
9364 },
9365 {
9366 name: "ParallelGateway",
9367 superClass: [
9368 "Gateway"
9369 ]
9370 },
9371 {
9372 name: "RootElement",
9373 isAbstract: true,
9374 superClass: [
9375 "BaseElement"
9376 ]
9377 },
9378 {
9379 name: "Relationship",
9380 superClass: [
9381 "BaseElement"
9382 ],
9383 properties: [
9384 {
9385 name: "type",
9386 isAttr: true,
9387 type: "String"
9388 },
9389 {
9390 name: "direction",
9391 type: "RelationshipDirection",
9392 isAttr: true
9393 },
9394 {
9395 name: "source",
9396 isMany: true,
9397 isReference: true,
9398 type: "Element"
9399 },
9400 {
9401 name: "target",
9402 isMany: true,
9403 isReference: true,
9404 type: "Element"
9405 }
9406 ]
9407 },
9408 {
9409 name: "BaseElement",
9410 isAbstract: true,
9411 properties: [
9412 {
9413 name: "id",
9414 isAttr: true,
9415 type: "String",
9416 isId: true
9417 },
9418 {
9419 name: "documentation",
9420 type: "Documentation",
9421 isMany: true
9422 },
9423 {
9424 name: "extensionDefinitions",
9425 type: "ExtensionDefinition",
9426 isMany: true,
9427 isReference: true
9428 },
9429 {
9430 name: "extensionElements",
9431 type: "ExtensionElements"
9432 }
9433 ]
9434 },
9435 {
9436 name: "Extension",
9437 properties: [
9438 {
9439 name: "mustUnderstand",
9440 "default": false,
9441 isAttr: true,
9442 type: "Boolean"
9443 },
9444 {
9445 name: "definition",
9446 type: "ExtensionDefinition",
9447 isAttr: true,
9448 isReference: true
9449 }
9450 ]
9451 },
9452 {
9453 name: "ExtensionDefinition",
9454 properties: [
9455 {
9456 name: "name",
9457 isAttr: true,
9458 type: "String"
9459 },
9460 {
9461 name: "extensionAttributeDefinitions",
9462 type: "ExtensionAttributeDefinition",
9463 isMany: true
9464 }
9465 ]
9466 },
9467 {
9468 name: "ExtensionAttributeDefinition",
9469 properties: [
9470 {
9471 name: "name",
9472 isAttr: true,
9473 type: "String"
9474 },
9475 {
9476 name: "type",
9477 isAttr: true,
9478 type: "String"
9479 },
9480 {
9481 name: "isReference",
9482 "default": false,
9483 isAttr: true,
9484 type: "Boolean"
9485 },
9486 {
9487 name: "extensionDefinition",
9488 type: "ExtensionDefinition",
9489 isAttr: true,
9490 isReference: true
9491 }
9492 ]
9493 },
9494 {
9495 name: "ExtensionElements",
9496 properties: [
9497 {
9498 name: "valueRef",
9499 isAttr: true,
9500 isReference: true,
9501 type: "Element"
9502 },
9503 {
9504 name: "values",
9505 type: "Element",
9506 isMany: true
9507 },
9508 {
9509 name: "extensionAttributeDefinition",
9510 type: "ExtensionAttributeDefinition",
9511 isAttr: true,
9512 isReference: true
9513 }
9514 ]
9515 },
9516 {
9517 name: "Documentation",
9518 superClass: [
9519 "BaseElement"
9520 ],
9521 properties: [
9522 {
9523 name: "text",
9524 type: "String",
9525 isBody: true
9526 },
9527 {
9528 name: "textFormat",
9529 "default": "text/plain",
9530 isAttr: true,
9531 type: "String"
9532 }
9533 ]
9534 },
9535 {
9536 name: "Event",
9537 isAbstract: true,
9538 superClass: [
9539 "FlowNode",
9540 "InteractionNode"
9541 ],
9542 properties: [
9543 {
9544 name: "properties",
9545 type: "Property",
9546 isMany: true
9547 }
9548 ]
9549 },
9550 {
9551 name: "IntermediateCatchEvent",
9552 superClass: [
9553 "CatchEvent"
9554 ]
9555 },
9556 {
9557 name: "IntermediateThrowEvent",
9558 superClass: [
9559 "ThrowEvent"
9560 ]
9561 },
9562 {
9563 name: "EndEvent",
9564 superClass: [
9565 "ThrowEvent"
9566 ]
9567 },
9568 {
9569 name: "StartEvent",
9570 superClass: [
9571 "CatchEvent"
9572 ],
9573 properties: [
9574 {
9575 name: "isInterrupting",
9576 "default": true,
9577 isAttr: true,
9578 type: "Boolean"
9579 }
9580 ]
9581 },
9582 {
9583 name: "ThrowEvent",
9584 isAbstract: true,
9585 superClass: [
9586 "Event"
9587 ],
9588 properties: [
9589 {
9590 name: "dataInputs",
9591 type: "DataInput",
9592 isMany: true
9593 },
9594 {
9595 name: "dataInputAssociations",
9596 type: "DataInputAssociation",
9597 isMany: true
9598 },
9599 {
9600 name: "inputSet",
9601 type: "InputSet"
9602 },
9603 {
9604 name: "eventDefinitions",
9605 type: "EventDefinition",
9606 isMany: true
9607 },
9608 {
9609 name: "eventDefinitionRef",
9610 type: "EventDefinition",
9611 isMany: true,
9612 isReference: true
9613 }
9614 ]
9615 },
9616 {
9617 name: "CatchEvent",
9618 isAbstract: true,
9619 superClass: [
9620 "Event"
9621 ],
9622 properties: [
9623 {
9624 name: "parallelMultiple",
9625 isAttr: true,
9626 type: "Boolean",
9627 "default": false
9628 },
9629 {
9630 name: "dataOutputs",
9631 type: "DataOutput",
9632 isMany: true
9633 },
9634 {
9635 name: "dataOutputAssociations",
9636 type: "DataOutputAssociation",
9637 isMany: true
9638 },
9639 {
9640 name: "outputSet",
9641 type: "OutputSet"
9642 },
9643 {
9644 name: "eventDefinitions",
9645 type: "EventDefinition",
9646 isMany: true
9647 },
9648 {
9649 name: "eventDefinitionRef",
9650 type: "EventDefinition",
9651 isMany: true,
9652 isReference: true
9653 }
9654 ]
9655 },
9656 {
9657 name: "BoundaryEvent",
9658 superClass: [
9659 "CatchEvent"
9660 ],
9661 properties: [
9662 {
9663 name: "cancelActivity",
9664 "default": true,
9665 isAttr: true,
9666 type: "Boolean"
9667 },
9668 {
9669 name: "attachedToRef",
9670 type: "Activity",
9671 isAttr: true,
9672 isReference: true
9673 }
9674 ]
9675 },
9676 {
9677 name: "EventDefinition",
9678 isAbstract: true,
9679 superClass: [
9680 "RootElement"
9681 ]
9682 },
9683 {
9684 name: "CancelEventDefinition",
9685 superClass: [
9686 "EventDefinition"
9687 ]
9688 },
9689 {
9690 name: "ErrorEventDefinition",
9691 superClass: [
9692 "EventDefinition"
9693 ],
9694 properties: [
9695 {
9696 name: "errorRef",
9697 type: "Error",
9698 isAttr: true,
9699 isReference: true
9700 }
9701 ]
9702 },
9703 {
9704 name: "TerminateEventDefinition",
9705 superClass: [
9706 "EventDefinition"
9707 ]
9708 },
9709 {
9710 name: "EscalationEventDefinition",
9711 superClass: [
9712 "EventDefinition"
9713 ],
9714 properties: [
9715 {
9716 name: "escalationRef",
9717 type: "Escalation",
9718 isAttr: true,
9719 isReference: true
9720 }
9721 ]
9722 },
9723 {
9724 name: "Escalation",
9725 properties: [
9726 {
9727 name: "structureRef",
9728 type: "ItemDefinition",
9729 isAttr: true,
9730 isReference: true
9731 },
9732 {
9733 name: "name",
9734 isAttr: true,
9735 type: "String"
9736 },
9737 {
9738 name: "escalationCode",
9739 isAttr: true,
9740 type: "String"
9741 }
9742 ],
9743 superClass: [
9744 "RootElement"
9745 ]
9746 },
9747 {
9748 name: "CompensateEventDefinition",
9749 superClass: [
9750 "EventDefinition"
9751 ],
9752 properties: [
9753 {
9754 name: "waitForCompletion",
9755 isAttr: true,
9756 type: "Boolean",
9757 "default": true
9758 },
9759 {
9760 name: "activityRef",
9761 type: "Activity",
9762 isAttr: true,
9763 isReference: true
9764 }
9765 ]
9766 },
9767 {
9768 name: "TimerEventDefinition",
9769 superClass: [
9770 "EventDefinition"
9771 ],
9772 properties: [
9773 {
9774 name: "timeDate",
9775 type: "Expression",
9776 xml: {
9777 serialize: "xsi:type"
9778 }
9779 },
9780 {
9781 name: "timeCycle",
9782 type: "Expression",
9783 xml: {
9784 serialize: "xsi:type"
9785 }
9786 },
9787 {
9788 name: "timeDuration",
9789 type: "Expression",
9790 xml: {
9791 serialize: "xsi:type"
9792 }
9793 }
9794 ]
9795 },
9796 {
9797 name: "LinkEventDefinition",
9798 superClass: [
9799 "EventDefinition"
9800 ],
9801 properties: [
9802 {
9803 name: "name",
9804 isAttr: true,
9805 type: "String"
9806 },
9807 {
9808 name: "target",
9809 type: "LinkEventDefinition",
9810 isAttr: true,
9811 isReference: true
9812 },
9813 {
9814 name: "source",
9815 type: "LinkEventDefinition",
9816 isMany: true,
9817 isReference: true
9818 }
9819 ]
9820 },
9821 {
9822 name: "MessageEventDefinition",
9823 superClass: [
9824 "EventDefinition"
9825 ],
9826 properties: [
9827 {
9828 name: "messageRef",
9829 type: "Message",
9830 isAttr: true,
9831 isReference: true
9832 },
9833 {
9834 name: "operationRef",
9835 type: "Operation",
9836 isAttr: true,
9837 isReference: true
9838 }
9839 ]
9840 },
9841 {
9842 name: "ConditionalEventDefinition",
9843 superClass: [
9844 "EventDefinition"
9845 ],
9846 properties: [
9847 {
9848 name: "condition",
9849 type: "Expression",
9850 xml: {
9851 serialize: "xsi:type"
9852 }
9853 }
9854 ]
9855 },
9856 {
9857 name: "SignalEventDefinition",
9858 superClass: [
9859 "EventDefinition"
9860 ],
9861 properties: [
9862 {
9863 name: "signalRef",
9864 type: "Signal",
9865 isAttr: true,
9866 isReference: true
9867 }
9868 ]
9869 },
9870 {
9871 name: "Signal",
9872 superClass: [
9873 "RootElement"
9874 ],
9875 properties: [
9876 {
9877 name: "structureRef",
9878 type: "ItemDefinition",
9879 isAttr: true,
9880 isReference: true
9881 },
9882 {
9883 name: "name",
9884 isAttr: true,
9885 type: "String"
9886 }
9887 ]
9888 },
9889 {
9890 name: "ImplicitThrowEvent",
9891 superClass: [
9892 "ThrowEvent"
9893 ]
9894 },
9895 {
9896 name: "DataState",
9897 superClass: [
9898 "BaseElement"
9899 ],
9900 properties: [
9901 {
9902 name: "name",
9903 isAttr: true,
9904 type: "String"
9905 }
9906 ]
9907 },
9908 {
9909 name: "ItemAwareElement",
9910 superClass: [
9911 "BaseElement"
9912 ],
9913 properties: [
9914 {
9915 name: "itemSubjectRef",
9916 type: "ItemDefinition",
9917 isAttr: true,
9918 isReference: true
9919 },
9920 {
9921 name: "dataState",
9922 type: "DataState"
9923 }
9924 ]
9925 },
9926 {
9927 name: "DataAssociation",
9928 superClass: [
9929 "BaseElement"
9930 ],
9931 properties: [
9932 {
9933 name: "assignment",
9934 type: "Assignment",
9935 isMany: true
9936 },
9937 {
9938 name: "sourceRef",
9939 type: "ItemAwareElement",
9940 isMany: true,
9941 isReference: true
9942 },
9943 {
9944 name: "targetRef",
9945 type: "ItemAwareElement",
9946 isReference: true
9947 },
9948 {
9949 name: "transformation",
9950 type: "FormalExpression",
9951 xml: {
9952 serialize: "property"
9953 }
9954 }
9955 ]
9956 },
9957 {
9958 name: "DataInput",
9959 superClass: [
9960 "ItemAwareElement"
9961 ],
9962 properties: [
9963 {
9964 name: "name",
9965 isAttr: true,
9966 type: "String"
9967 },
9968 {
9969 name: "isCollection",
9970 "default": false,
9971 isAttr: true,
9972 type: "Boolean"
9973 },
9974 {
9975 name: "inputSetRef",
9976 type: "InputSet",
9977 isVirtual: true,
9978 isMany: true,
9979 isReference: true
9980 },
9981 {
9982 name: "inputSetWithOptional",
9983 type: "InputSet",
9984 isVirtual: true,
9985 isMany: true,
9986 isReference: true
9987 },
9988 {
9989 name: "inputSetWithWhileExecuting",
9990 type: "InputSet",
9991 isVirtual: true,
9992 isMany: true,
9993 isReference: true
9994 }
9995 ]
9996 },
9997 {
9998 name: "DataOutput",
9999 superClass: [
10000 "ItemAwareElement"
10001 ],
10002 properties: [
10003 {
10004 name: "name",
10005 isAttr: true,
10006 type: "String"
10007 },
10008 {
10009 name: "isCollection",
10010 "default": false,
10011 isAttr: true,
10012 type: "Boolean"
10013 },
10014 {
10015 name: "outputSetRef",
10016 type: "OutputSet",
10017 isVirtual: true,
10018 isMany: true,
10019 isReference: true
10020 },
10021 {
10022 name: "outputSetWithOptional",
10023 type: "OutputSet",
10024 isVirtual: true,
10025 isMany: true,
10026 isReference: true
10027 },
10028 {
10029 name: "outputSetWithWhileExecuting",
10030 type: "OutputSet",
10031 isVirtual: true,
10032 isMany: true,
10033 isReference: true
10034 }
10035 ]
10036 },
10037 {
10038 name: "InputSet",
10039 superClass: [
10040 "BaseElement"
10041 ],
10042 properties: [
10043 {
10044 name: "name",
10045 isAttr: true,
10046 type: "String"
10047 },
10048 {
10049 name: "dataInputRefs",
10050 type: "DataInput",
10051 isMany: true,
10052 isReference: true
10053 },
10054 {
10055 name: "optionalInputRefs",
10056 type: "DataInput",
10057 isMany: true,
10058 isReference: true
10059 },
10060 {
10061 name: "whileExecutingInputRefs",
10062 type: "DataInput",
10063 isMany: true,
10064 isReference: true
10065 },
10066 {
10067 name: "outputSetRefs",
10068 type: "OutputSet",
10069 isMany: true,
10070 isReference: true
10071 }
10072 ]
10073 },
10074 {
10075 name: "OutputSet",
10076 superClass: [
10077 "BaseElement"
10078 ],
10079 properties: [
10080 {
10081 name: "dataOutputRefs",
10082 type: "DataOutput",
10083 isMany: true,
10084 isReference: true
10085 },
10086 {
10087 name: "name",
10088 isAttr: true,
10089 type: "String"
10090 },
10091 {
10092 name: "inputSetRefs",
10093 type: "InputSet",
10094 isMany: true,
10095 isReference: true
10096 },
10097 {
10098 name: "optionalOutputRefs",
10099 type: "DataOutput",
10100 isMany: true,
10101 isReference: true
10102 },
10103 {
10104 name: "whileExecutingOutputRefs",
10105 type: "DataOutput",
10106 isMany: true,
10107 isReference: true
10108 }
10109 ]
10110 },
10111 {
10112 name: "Property",
10113 superClass: [
10114 "ItemAwareElement"
10115 ],
10116 properties: [
10117 {
10118 name: "name",
10119 isAttr: true,
10120 type: "String"
10121 }
10122 ]
10123 },
10124 {
10125 name: "DataInputAssociation",
10126 superClass: [
10127 "DataAssociation"
10128 ]
10129 },
10130 {
10131 name: "DataOutputAssociation",
10132 superClass: [
10133 "DataAssociation"
10134 ]
10135 },
10136 {
10137 name: "InputOutputSpecification",
10138 superClass: [
10139 "BaseElement"
10140 ],
10141 properties: [
10142 {
10143 name: "dataInputs",
10144 type: "DataInput",
10145 isMany: true
10146 },
10147 {
10148 name: "dataOutputs",
10149 type: "DataOutput",
10150 isMany: true
10151 },
10152 {
10153 name: "inputSets",
10154 type: "InputSet",
10155 isMany: true
10156 },
10157 {
10158 name: "outputSets",
10159 type: "OutputSet",
10160 isMany: true
10161 }
10162 ]
10163 },
10164 {
10165 name: "DataObject",
10166 superClass: [
10167 "FlowElement",
10168 "ItemAwareElement"
10169 ],
10170 properties: [
10171 {
10172 name: "isCollection",
10173 "default": false,
10174 isAttr: true,
10175 type: "Boolean"
10176 }
10177 ]
10178 },
10179 {
10180 name: "InputOutputBinding",
10181 properties: [
10182 {
10183 name: "inputDataRef",
10184 type: "InputSet",
10185 isAttr: true,
10186 isReference: true
10187 },
10188 {
10189 name: "outputDataRef",
10190 type: "OutputSet",
10191 isAttr: true,
10192 isReference: true
10193 },
10194 {
10195 name: "operationRef",
10196 type: "Operation",
10197 isAttr: true,
10198 isReference: true
10199 }
10200 ]
10201 },
10202 {
10203 name: "Assignment",
10204 superClass: [
10205 "BaseElement"
10206 ],
10207 properties: [
10208 {
10209 name: "from",
10210 type: "Expression",
10211 xml: {
10212 serialize: "xsi:type"
10213 }
10214 },
10215 {
10216 name: "to",
10217 type: "Expression",
10218 xml: {
10219 serialize: "xsi:type"
10220 }
10221 }
10222 ]
10223 },
10224 {
10225 name: "DataStore",
10226 superClass: [
10227 "RootElement",
10228 "ItemAwareElement"
10229 ],
10230 properties: [
10231 {
10232 name: "name",
10233 isAttr: true,
10234 type: "String"
10235 },
10236 {
10237 name: "capacity",
10238 isAttr: true,
10239 type: "Integer"
10240 },
10241 {
10242 name: "isUnlimited",
10243 "default": true,
10244 isAttr: true,
10245 type: "Boolean"
10246 }
10247 ]
10248 },
10249 {
10250 name: "DataStoreReference",
10251 superClass: [
10252 "ItemAwareElement",
10253 "FlowElement"
10254 ],
10255 properties: [
10256 {
10257 name: "dataStoreRef",
10258 type: "DataStore",
10259 isAttr: true,
10260 isReference: true
10261 }
10262 ]
10263 },
10264 {
10265 name: "DataObjectReference",
10266 superClass: [
10267 "ItemAwareElement",
10268 "FlowElement"
10269 ],
10270 properties: [
10271 {
10272 name: "dataObjectRef",
10273 type: "DataObject",
10274 isAttr: true,
10275 isReference: true
10276 }
10277 ]
10278 },
10279 {
10280 name: "ConversationLink",
10281 superClass: [
10282 "BaseElement"
10283 ],
10284 properties: [
10285 {
10286 name: "sourceRef",
10287 type: "InteractionNode",
10288 isAttr: true,
10289 isReference: true
10290 },
10291 {
10292 name: "targetRef",
10293 type: "InteractionNode",
10294 isAttr: true,
10295 isReference: true
10296 },
10297 {
10298 name: "name",
10299 isAttr: true,
10300 type: "String"
10301 }
10302 ]
10303 },
10304 {
10305 name: "ConversationAssociation",
10306 superClass: [
10307 "BaseElement"
10308 ],
10309 properties: [
10310 {
10311 name: "innerConversationNodeRef",
10312 type: "ConversationNode",
10313 isAttr: true,
10314 isReference: true
10315 },
10316 {
10317 name: "outerConversationNodeRef",
10318 type: "ConversationNode",
10319 isAttr: true,
10320 isReference: true
10321 }
10322 ]
10323 },
10324 {
10325 name: "CallConversation",
10326 superClass: [
10327 "ConversationNode"
10328 ],
10329 properties: [
10330 {
10331 name: "calledCollaborationRef",
10332 type: "Collaboration",
10333 isAttr: true,
10334 isReference: true
10335 },
10336 {
10337 name: "participantAssociations",
10338 type: "ParticipantAssociation",
10339 isMany: true
10340 }
10341 ]
10342 },
10343 {
10344 name: "Conversation",
10345 superClass: [
10346 "ConversationNode"
10347 ]
10348 },
10349 {
10350 name: "SubConversation",
10351 superClass: [
10352 "ConversationNode"
10353 ],
10354 properties: [
10355 {
10356 name: "conversationNodes",
10357 type: "ConversationNode",
10358 isMany: true
10359 }
10360 ]
10361 },
10362 {
10363 name: "ConversationNode",
10364 isAbstract: true,
10365 superClass: [
10366 "InteractionNode",
10367 "BaseElement"
10368 ],
10369 properties: [
10370 {
10371 name: "name",
10372 isAttr: true,
10373 type: "String"
10374 },
10375 {
10376 name: "participantRef",
10377 type: "Participant",
10378 isMany: true,
10379 isReference: true
10380 },
10381 {
10382 name: "messageFlowRefs",
10383 type: "MessageFlow",
10384 isMany: true,
10385 isReference: true
10386 },
10387 {
10388 name: "correlationKeys",
10389 type: "CorrelationKey",
10390 isMany: true
10391 }
10392 ]
10393 },
10394 {
10395 name: "GlobalConversation",
10396 superClass: [
10397 "Collaboration"
10398 ]
10399 },
10400 {
10401 name: "PartnerEntity",
10402 superClass: [
10403 "RootElement"
10404 ],
10405 properties: [
10406 {
10407 name: "name",
10408 isAttr: true,
10409 type: "String"
10410 },
10411 {
10412 name: "participantRef",
10413 type: "Participant",
10414 isMany: true,
10415 isReference: true
10416 }
10417 ]
10418 },
10419 {
10420 name: "PartnerRole",
10421 superClass: [
10422 "RootElement"
10423 ],
10424 properties: [
10425 {
10426 name: "name",
10427 isAttr: true,
10428 type: "String"
10429 },
10430 {
10431 name: "participantRef",
10432 type: "Participant",
10433 isMany: true,
10434 isReference: true
10435 }
10436 ]
10437 },
10438 {
10439 name: "CorrelationProperty",
10440 superClass: [
10441 "RootElement"
10442 ],
10443 properties: [
10444 {
10445 name: "correlationPropertyRetrievalExpression",
10446 type: "CorrelationPropertyRetrievalExpression",
10447 isMany: true
10448 },
10449 {
10450 name: "name",
10451 isAttr: true,
10452 type: "String"
10453 },
10454 {
10455 name: "type",
10456 type: "ItemDefinition",
10457 isAttr: true,
10458 isReference: true
10459 }
10460 ]
10461 },
10462 {
10463 name: "Error",
10464 superClass: [
10465 "RootElement"
10466 ],
10467 properties: [
10468 {
10469 name: "structureRef",
10470 type: "ItemDefinition",
10471 isAttr: true,
10472 isReference: true
10473 },
10474 {
10475 name: "name",
10476 isAttr: true,
10477 type: "String"
10478 },
10479 {
10480 name: "errorCode",
10481 isAttr: true,
10482 type: "String"
10483 }
10484 ]
10485 },
10486 {
10487 name: "CorrelationKey",
10488 superClass: [
10489 "BaseElement"
10490 ],
10491 properties: [
10492 {
10493 name: "correlationPropertyRef",
10494 type: "CorrelationProperty",
10495 isMany: true,
10496 isReference: true
10497 },
10498 {
10499 name: "name",
10500 isAttr: true,
10501 type: "String"
10502 }
10503 ]
10504 },
10505 {
10506 name: "Expression",
10507 superClass: [
10508 "BaseElement"
10509 ],
10510 isAbstract: false,
10511 properties: [
10512 {
10513 name: "body",
10514 type: "String",
10515 isBody: true
10516 }
10517 ]
10518 },
10519 {
10520 name: "FormalExpression",
10521 superClass: [
10522 "Expression"
10523 ],
10524 properties: [
10525 {
10526 name: "language",
10527 isAttr: true,
10528 type: "String"
10529 },
10530 {
10531 name: "evaluatesToTypeRef",
10532 type: "ItemDefinition",
10533 isAttr: true,
10534 isReference: true
10535 }
10536 ]
10537 },
10538 {
10539 name: "Message",
10540 superClass: [
10541 "RootElement"
10542 ],
10543 properties: [
10544 {
10545 name: "name",
10546 isAttr: true,
10547 type: "String"
10548 },
10549 {
10550 name: "itemRef",
10551 type: "ItemDefinition",
10552 isAttr: true,
10553 isReference: true
10554 }
10555 ]
10556 },
10557 {
10558 name: "ItemDefinition",
10559 superClass: [
10560 "RootElement"
10561 ],
10562 properties: [
10563 {
10564 name: "itemKind",
10565 type: "ItemKind",
10566 isAttr: true
10567 },
10568 {
10569 name: "structureRef",
10570 type: "String",
10571 isAttr: true
10572 },
10573 {
10574 name: "isCollection",
10575 "default": false,
10576 isAttr: true,
10577 type: "Boolean"
10578 },
10579 {
10580 name: "import",
10581 type: "Import",
10582 isAttr: true,
10583 isReference: true
10584 }
10585 ]
10586 },
10587 {
10588 name: "FlowElement",
10589 isAbstract: true,
10590 superClass: [
10591 "BaseElement"
10592 ],
10593 properties: [
10594 {
10595 name: "name",
10596 isAttr: true,
10597 type: "String"
10598 },
10599 {
10600 name: "auditing",
10601 type: "Auditing"
10602 },
10603 {
10604 name: "monitoring",
10605 type: "Monitoring"
10606 },
10607 {
10608 name: "categoryValueRef",
10609 type: "CategoryValue",
10610 isMany: true,
10611 isReference: true
10612 }
10613 ]
10614 },
10615 {
10616 name: "SequenceFlow",
10617 superClass: [
10618 "FlowElement"
10619 ],
10620 properties: [
10621 {
10622 name: "isImmediate",
10623 isAttr: true,
10624 type: "Boolean"
10625 },
10626 {
10627 name: "conditionExpression",
10628 type: "Expression",
10629 xml: {
10630 serialize: "xsi:type"
10631 }
10632 },
10633 {
10634 name: "sourceRef",
10635 type: "FlowNode",
10636 isAttr: true,
10637 isReference: true
10638 },
10639 {
10640 name: "targetRef",
10641 type: "FlowNode",
10642 isAttr: true,
10643 isReference: true
10644 }
10645 ]
10646 },
10647 {
10648 name: "FlowElementsContainer",
10649 isAbstract: true,
10650 superClass: [
10651 "BaseElement"
10652 ],
10653 properties: [
10654 {
10655 name: "laneSets",
10656 type: "LaneSet",
10657 isMany: true
10658 },
10659 {
10660 name: "flowElements",
10661 type: "FlowElement",
10662 isMany: true
10663 }
10664 ]
10665 },
10666 {
10667 name: "CallableElement",
10668 isAbstract: true,
10669 superClass: [
10670 "RootElement"
10671 ],
10672 properties: [
10673 {
10674 name: "name",
10675 isAttr: true,
10676 type: "String"
10677 },
10678 {
10679 name: "ioSpecification",
10680 type: "InputOutputSpecification",
10681 xml: {
10682 serialize: "property"
10683 }
10684 },
10685 {
10686 name: "supportedInterfaceRef",
10687 type: "Interface",
10688 isMany: true,
10689 isReference: true
10690 },
10691 {
10692 name: "ioBinding",
10693 type: "InputOutputBinding",
10694 isMany: true,
10695 xml: {
10696 serialize: "property"
10697 }
10698 }
10699 ]
10700 },
10701 {
10702 name: "FlowNode",
10703 isAbstract: true,
10704 superClass: [
10705 "FlowElement"
10706 ],
10707 properties: [
10708 {
10709 name: "incoming",
10710 type: "SequenceFlow",
10711 isMany: true,
10712 isReference: true
10713 },
10714 {
10715 name: "outgoing",
10716 type: "SequenceFlow",
10717 isMany: true,
10718 isReference: true
10719 },
10720 {
10721 name: "lanes",
10722 type: "Lane",
10723 isVirtual: true,
10724 isMany: true,
10725 isReference: true
10726 }
10727 ]
10728 },
10729 {
10730 name: "CorrelationPropertyRetrievalExpression",
10731 superClass: [
10732 "BaseElement"
10733 ],
10734 properties: [
10735 {
10736 name: "messagePath",
10737 type: "FormalExpression"
10738 },
10739 {
10740 name: "messageRef",
10741 type: "Message",
10742 isAttr: true,
10743 isReference: true
10744 }
10745 ]
10746 },
10747 {
10748 name: "CorrelationPropertyBinding",
10749 superClass: [
10750 "BaseElement"
10751 ],
10752 properties: [
10753 {
10754 name: "dataPath",
10755 type: "FormalExpression"
10756 },
10757 {
10758 name: "correlationPropertyRef",
10759 type: "CorrelationProperty",
10760 isAttr: true,
10761 isReference: true
10762 }
10763 ]
10764 },
10765 {
10766 name: "Resource",
10767 superClass: [
10768 "RootElement"
10769 ],
10770 properties: [
10771 {
10772 name: "name",
10773 isAttr: true,
10774 type: "String"
10775 },
10776 {
10777 name: "resourceParameters",
10778 type: "ResourceParameter",
10779 isMany: true
10780 }
10781 ]
10782 },
10783 {
10784 name: "ResourceParameter",
10785 superClass: [
10786 "BaseElement"
10787 ],
10788 properties: [
10789 {
10790 name: "name",
10791 isAttr: true,
10792 type: "String"
10793 },
10794 {
10795 name: "isRequired",
10796 isAttr: true,
10797 type: "Boolean"
10798 },
10799 {
10800 name: "type",
10801 type: "ItemDefinition",
10802 isAttr: true,
10803 isReference: true
10804 }
10805 ]
10806 },
10807 {
10808 name: "CorrelationSubscription",
10809 superClass: [
10810 "BaseElement"
10811 ],
10812 properties: [
10813 {
10814 name: "correlationKeyRef",
10815 type: "CorrelationKey",
10816 isAttr: true,
10817 isReference: true
10818 },
10819 {
10820 name: "correlationPropertyBinding",
10821 type: "CorrelationPropertyBinding",
10822 isMany: true
10823 }
10824 ]
10825 },
10826 {
10827 name: "MessageFlow",
10828 superClass: [
10829 "BaseElement"
10830 ],
10831 properties: [
10832 {
10833 name: "name",
10834 isAttr: true,
10835 type: "String"
10836 },
10837 {
10838 name: "sourceRef",
10839 type: "InteractionNode",
10840 isAttr: true,
10841 isReference: true
10842 },
10843 {
10844 name: "targetRef",
10845 type: "InteractionNode",
10846 isAttr: true,
10847 isReference: true
10848 },
10849 {
10850 name: "messageRef",
10851 type: "Message",
10852 isAttr: true,
10853 isReference: true
10854 }
10855 ]
10856 },
10857 {
10858 name: "MessageFlowAssociation",
10859 superClass: [
10860 "BaseElement"
10861 ],
10862 properties: [
10863 {
10864 name: "innerMessageFlowRef",
10865 type: "MessageFlow",
10866 isAttr: true,
10867 isReference: true
10868 },
10869 {
10870 name: "outerMessageFlowRef",
10871 type: "MessageFlow",
10872 isAttr: true,
10873 isReference: true
10874 }
10875 ]
10876 },
10877 {
10878 name: "InteractionNode",
10879 isAbstract: true,
10880 properties: [
10881 {
10882 name: "incomingConversationLinks",
10883 type: "ConversationLink",
10884 isVirtual: true,
10885 isMany: true,
10886 isReference: true
10887 },
10888 {
10889 name: "outgoingConversationLinks",
10890 type: "ConversationLink",
10891 isVirtual: true,
10892 isMany: true,
10893 isReference: true
10894 }
10895 ]
10896 },
10897 {
10898 name: "Participant",
10899 superClass: [
10900 "InteractionNode",
10901 "BaseElement"
10902 ],
10903 properties: [
10904 {
10905 name: "name",
10906 isAttr: true,
10907 type: "String"
10908 },
10909 {
10910 name: "interfaceRef",
10911 type: "Interface",
10912 isMany: true,
10913 isReference: true
10914 },
10915 {
10916 name: "participantMultiplicity",
10917 type: "ParticipantMultiplicity"
10918 },
10919 {
10920 name: "endPointRefs",
10921 type: "EndPoint",
10922 isMany: true,
10923 isReference: true
10924 },
10925 {
10926 name: "processRef",
10927 type: "Process",
10928 isAttr: true,
10929 isReference: true
10930 }
10931 ]
10932 },
10933 {
10934 name: "ParticipantAssociation",
10935 superClass: [
10936 "BaseElement"
10937 ],
10938 properties: [
10939 {
10940 name: "innerParticipantRef",
10941 type: "Participant",
10942 isAttr: true,
10943 isReference: true
10944 },
10945 {
10946 name: "outerParticipantRef",
10947 type: "Participant",
10948 isAttr: true,
10949 isReference: true
10950 }
10951 ]
10952 },
10953 {
10954 name: "ParticipantMultiplicity",
10955 properties: [
10956 {
10957 name: "minimum",
10958 "default": 0,
10959 isAttr: true,
10960 type: "Integer"
10961 },
10962 {
10963 name: "maximum",
10964 "default": 1,
10965 isAttr: true,
10966 type: "Integer"
10967 }
10968 ],
10969 superClass: [
10970 "BaseElement"
10971 ]
10972 },
10973 {
10974 name: "Collaboration",
10975 superClass: [
10976 "RootElement"
10977 ],
10978 properties: [
10979 {
10980 name: "name",
10981 isAttr: true,
10982 type: "String"
10983 },
10984 {
10985 name: "isClosed",
10986 isAttr: true,
10987 type: "Boolean"
10988 },
10989 {
10990 name: "participants",
10991 type: "Participant",
10992 isMany: true
10993 },
10994 {
10995 name: "messageFlows",
10996 type: "MessageFlow",
10997 isMany: true
10998 },
10999 {
11000 name: "artifacts",
11001 type: "Artifact",
11002 isMany: true
11003 },
11004 {
11005 name: "conversations",
11006 type: "ConversationNode",
11007 isMany: true
11008 },
11009 {
11010 name: "conversationAssociations",
11011 type: "ConversationAssociation"
11012 },
11013 {
11014 name: "participantAssociations",
11015 type: "ParticipantAssociation",
11016 isMany: true
11017 },
11018 {
11019 name: "messageFlowAssociations",
11020 type: "MessageFlowAssociation",
11021 isMany: true
11022 },
11023 {
11024 name: "correlationKeys",
11025 type: "CorrelationKey",
11026 isMany: true
11027 },
11028 {
11029 name: "choreographyRef",
11030 type: "Choreography",
11031 isMany: true,
11032 isReference: true
11033 },
11034 {
11035 name: "conversationLinks",
11036 type: "ConversationLink",
11037 isMany: true
11038 }
11039 ]
11040 },
11041 {
11042 name: "ChoreographyActivity",
11043 isAbstract: true,
11044 superClass: [
11045 "FlowNode"
11046 ],
11047 properties: [
11048 {
11049 name: "participantRef",
11050 type: "Participant",
11051 isMany: true,
11052 isReference: true
11053 },
11054 {
11055 name: "initiatingParticipantRef",
11056 type: "Participant",
11057 isAttr: true,
11058 isReference: true
11059 },
11060 {
11061 name: "correlationKeys",
11062 type: "CorrelationKey",
11063 isMany: true
11064 },
11065 {
11066 name: "loopType",
11067 type: "ChoreographyLoopType",
11068 "default": "None",
11069 isAttr: true
11070 }
11071 ]
11072 },
11073 {
11074 name: "CallChoreography",
11075 superClass: [
11076 "ChoreographyActivity"
11077 ],
11078 properties: [
11079 {
11080 name: "calledChoreographyRef",
11081 type: "Choreography",
11082 isAttr: true,
11083 isReference: true
11084 },
11085 {
11086 name: "participantAssociations",
11087 type: "ParticipantAssociation",
11088 isMany: true
11089 }
11090 ]
11091 },
11092 {
11093 name: "SubChoreography",
11094 superClass: [
11095 "ChoreographyActivity",
11096 "FlowElementsContainer"
11097 ],
11098 properties: [
11099 {
11100 name: "artifacts",
11101 type: "Artifact",
11102 isMany: true
11103 }
11104 ]
11105 },
11106 {
11107 name: "ChoreographyTask",
11108 superClass: [
11109 "ChoreographyActivity"
11110 ],
11111 properties: [
11112 {
11113 name: "messageFlowRef",
11114 type: "MessageFlow",
11115 isMany: true,
11116 isReference: true
11117 }
11118 ]
11119 },
11120 {
11121 name: "Choreography",
11122 superClass: [
11123 "Collaboration",
11124 "FlowElementsContainer"
11125 ]
11126 },
11127 {
11128 name: "GlobalChoreographyTask",
11129 superClass: [
11130 "Choreography"
11131 ],
11132 properties: [
11133 {
11134 name: "initiatingParticipantRef",
11135 type: "Participant",
11136 isAttr: true,
11137 isReference: true
11138 }
11139 ]
11140 },
11141 {
11142 name: "TextAnnotation",
11143 superClass: [
11144 "Artifact"
11145 ],
11146 properties: [
11147 {
11148 name: "text",
11149 type: "String"
11150 },
11151 {
11152 name: "textFormat",
11153 "default": "text/plain",
11154 isAttr: true,
11155 type: "String"
11156 }
11157 ]
11158 },
11159 {
11160 name: "Group",
11161 superClass: [
11162 "Artifact"
11163 ],
11164 properties: [
11165 {
11166 name: "categoryValueRef",
11167 type: "CategoryValue",
11168 isAttr: true,
11169 isReference: true
11170 }
11171 ]
11172 },
11173 {
11174 name: "Association",
11175 superClass: [
11176 "Artifact"
11177 ],
11178 properties: [
11179 {
11180 name: "associationDirection",
11181 type: "AssociationDirection",
11182 isAttr: true
11183 },
11184 {
11185 name: "sourceRef",
11186 type: "BaseElement",
11187 isAttr: true,
11188 isReference: true
11189 },
11190 {
11191 name: "targetRef",
11192 type: "BaseElement",
11193 isAttr: true,
11194 isReference: true
11195 }
11196 ]
11197 },
11198 {
11199 name: "Category",
11200 superClass: [
11201 "RootElement"
11202 ],
11203 properties: [
11204 {
11205 name: "categoryValue",
11206 type: "CategoryValue",
11207 isMany: true
11208 },
11209 {
11210 name: "name",
11211 isAttr: true,
11212 type: "String"
11213 }
11214 ]
11215 },
11216 {
11217 name: "Artifact",
11218 isAbstract: true,
11219 superClass: [
11220 "BaseElement"
11221 ]
11222 },
11223 {
11224 name: "CategoryValue",
11225 superClass: [
11226 "BaseElement"
11227 ],
11228 properties: [
11229 {
11230 name: "categorizedFlowElements",
11231 type: "FlowElement",
11232 isVirtual: true,
11233 isMany: true,
11234 isReference: true
11235 },
11236 {
11237 name: "value",
11238 isAttr: true,
11239 type: "String"
11240 }
11241 ]
11242 },
11243 {
11244 name: "Activity",
11245 isAbstract: true,
11246 superClass: [
11247 "FlowNode"
11248 ],
11249 properties: [
11250 {
11251 name: "isForCompensation",
11252 "default": false,
11253 isAttr: true,
11254 type: "Boolean"
11255 },
11256 {
11257 name: "default",
11258 type: "SequenceFlow",
11259 isAttr: true,
11260 isReference: true
11261 },
11262 {
11263 name: "ioSpecification",
11264 type: "InputOutputSpecification",
11265 xml: {
11266 serialize: "property"
11267 }
11268 },
11269 {
11270 name: "boundaryEventRefs",
11271 type: "BoundaryEvent",
11272 isMany: true,
11273 isReference: true
11274 },
11275 {
11276 name: "properties",
11277 type: "Property",
11278 isMany: true
11279 },
11280 {
11281 name: "dataInputAssociations",
11282 type: "DataInputAssociation",
11283 isMany: true
11284 },
11285 {
11286 name: "dataOutputAssociations",
11287 type: "DataOutputAssociation",
11288 isMany: true
11289 },
11290 {
11291 name: "startQuantity",
11292 "default": 1,
11293 isAttr: true,
11294 type: "Integer"
11295 },
11296 {
11297 name: "resources",
11298 type: "ResourceRole",
11299 isMany: true
11300 },
11301 {
11302 name: "completionQuantity",
11303 "default": 1,
11304 isAttr: true,
11305 type: "Integer"
11306 },
11307 {
11308 name: "loopCharacteristics",
11309 type: "LoopCharacteristics"
11310 }
11311 ]
11312 },
11313 {
11314 name: "ServiceTask",
11315 superClass: [
11316 "Task"
11317 ],
11318 properties: [
11319 {
11320 name: "implementation",
11321 isAttr: true,
11322 type: "String"
11323 },
11324 {
11325 name: "operationRef",
11326 type: "Operation",
11327 isAttr: true,
11328 isReference: true
11329 }
11330 ]
11331 },
11332 {
11333 name: "SubProcess",
11334 superClass: [
11335 "Activity",
11336 "FlowElementsContainer",
11337 "InteractionNode"
11338 ],
11339 properties: [
11340 {
11341 name: "triggeredByEvent",
11342 "default": false,
11343 isAttr: true,
11344 type: "Boolean"
11345 },
11346 {
11347 name: "artifacts",
11348 type: "Artifact",
11349 isMany: true
11350 }
11351 ]
11352 },
11353 {
11354 name: "LoopCharacteristics",
11355 isAbstract: true,
11356 superClass: [
11357 "BaseElement"
11358 ]
11359 },
11360 {
11361 name: "MultiInstanceLoopCharacteristics",
11362 superClass: [
11363 "LoopCharacteristics"
11364 ],
11365 properties: [
11366 {
11367 name: "isSequential",
11368 "default": false,
11369 isAttr: true,
11370 type: "Boolean"
11371 },
11372 {
11373 name: "behavior",
11374 type: "MultiInstanceBehavior",
11375 "default": "All",
11376 isAttr: true
11377 },
11378 {
11379 name: "loopCardinality",
11380 type: "Expression",
11381 xml: {
11382 serialize: "xsi:type"
11383 }
11384 },
11385 {
11386 name: "loopDataInputRef",
11387 type: "ItemAwareElement",
11388 isReference: true
11389 },
11390 {
11391 name: "loopDataOutputRef",
11392 type: "ItemAwareElement",
11393 isReference: true
11394 },
11395 {
11396 name: "inputDataItem",
11397 type: "DataInput",
11398 xml: {
11399 serialize: "property"
11400 }
11401 },
11402 {
11403 name: "outputDataItem",
11404 type: "DataOutput",
11405 xml: {
11406 serialize: "property"
11407 }
11408 },
11409 {
11410 name: "complexBehaviorDefinition",
11411 type: "ComplexBehaviorDefinition",
11412 isMany: true
11413 },
11414 {
11415 name: "completionCondition",
11416 type: "Expression",
11417 xml: {
11418 serialize: "xsi:type"
11419 }
11420 },
11421 {
11422 name: "oneBehaviorEventRef",
11423 type: "EventDefinition",
11424 isAttr: true,
11425 isReference: true
11426 },
11427 {
11428 name: "noneBehaviorEventRef",
11429 type: "EventDefinition",
11430 isAttr: true,
11431 isReference: true
11432 }
11433 ]
11434 },
11435 {
11436 name: "StandardLoopCharacteristics",
11437 superClass: [
11438 "LoopCharacteristics"
11439 ],
11440 properties: [
11441 {
11442 name: "testBefore",
11443 "default": false,
11444 isAttr: true,
11445 type: "Boolean"
11446 },
11447 {
11448 name: "loopCondition",
11449 type: "Expression",
11450 xml: {
11451 serialize: "xsi:type"
11452 }
11453 },
11454 {
11455 name: "loopMaximum",
11456 type: "Integer",
11457 isAttr: true
11458 }
11459 ]
11460 },
11461 {
11462 name: "CallActivity",
11463 superClass: [
11464 "Activity"
11465 ],
11466 properties: [
11467 {
11468 name: "calledElement",
11469 type: "String",
11470 isAttr: true
11471 }
11472 ]
11473 },
11474 {
11475 name: "Task",
11476 superClass: [
11477 "Activity",
11478 "InteractionNode"
11479 ]
11480 },
11481 {
11482 name: "SendTask",
11483 superClass: [
11484 "Task"
11485 ],
11486 properties: [
11487 {
11488 name: "implementation",
11489 isAttr: true,
11490 type: "String"
11491 },
11492 {
11493 name: "operationRef",
11494 type: "Operation",
11495 isAttr: true,
11496 isReference: true
11497 },
11498 {
11499 name: "messageRef",
11500 type: "Message",
11501 isAttr: true,
11502 isReference: true
11503 }
11504 ]
11505 },
11506 {
11507 name: "ReceiveTask",
11508 superClass: [
11509 "Task"
11510 ],
11511 properties: [
11512 {
11513 name: "implementation",
11514 isAttr: true,
11515 type: "String"
11516 },
11517 {
11518 name: "instantiate",
11519 "default": false,
11520 isAttr: true,
11521 type: "Boolean"
11522 },
11523 {
11524 name: "operationRef",
11525 type: "Operation",
11526 isAttr: true,
11527 isReference: true
11528 },
11529 {
11530 name: "messageRef",
11531 type: "Message",
11532 isAttr: true,
11533 isReference: true
11534 }
11535 ]
11536 },
11537 {
11538 name: "ScriptTask",
11539 superClass: [
11540 "Task"
11541 ],
11542 properties: [
11543 {
11544 name: "scriptFormat",
11545 isAttr: true,
11546 type: "String"
11547 },
11548 {
11549 name: "script",
11550 type: "String"
11551 }
11552 ]
11553 },
11554 {
11555 name: "BusinessRuleTask",
11556 superClass: [
11557 "Task"
11558 ],
11559 properties: [
11560 {
11561 name: "implementation",
11562 isAttr: true,
11563 type: "String"
11564 }
11565 ]
11566 },
11567 {
11568 name: "AdHocSubProcess",
11569 superClass: [
11570 "SubProcess"
11571 ],
11572 properties: [
11573 {
11574 name: "completionCondition",
11575 type: "Expression",
11576 xml: {
11577 serialize: "xsi:type"
11578 }
11579 },
11580 {
11581 name: "ordering",
11582 type: "AdHocOrdering",
11583 isAttr: true
11584 },
11585 {
11586 name: "cancelRemainingInstances",
11587 "default": true,
11588 isAttr: true,
11589 type: "Boolean"
11590 }
11591 ]
11592 },
11593 {
11594 name: "Transaction",
11595 superClass: [
11596 "SubProcess"
11597 ],
11598 properties: [
11599 {
11600 name: "protocol",
11601 isAttr: true,
11602 type: "String"
11603 },
11604 {
11605 name: "method",
11606 isAttr: true,
11607 type: "String"
11608 }
11609 ]
11610 },
11611 {
11612 name: "GlobalScriptTask",
11613 superClass: [
11614 "GlobalTask"
11615 ],
11616 properties: [
11617 {
11618 name: "scriptLanguage",
11619 isAttr: true,
11620 type: "String"
11621 },
11622 {
11623 name: "script",
11624 isAttr: true,
11625 type: "String"
11626 }
11627 ]
11628 },
11629 {
11630 name: "GlobalBusinessRuleTask",
11631 superClass: [
11632 "GlobalTask"
11633 ],
11634 properties: [
11635 {
11636 name: "implementation",
11637 isAttr: true,
11638 type: "String"
11639 }
11640 ]
11641 },
11642 {
11643 name: "ComplexBehaviorDefinition",
11644 superClass: [
11645 "BaseElement"
11646 ],
11647 properties: [
11648 {
11649 name: "condition",
11650 type: "FormalExpression"
11651 },
11652 {
11653 name: "event",
11654 type: "ImplicitThrowEvent"
11655 }
11656 ]
11657 },
11658 {
11659 name: "ResourceRole",
11660 superClass: [
11661 "BaseElement"
11662 ],
11663 properties: [
11664 {
11665 name: "resourceRef",
11666 type: "Resource",
11667 isReference: true
11668 },
11669 {
11670 name: "resourceParameterBindings",
11671 type: "ResourceParameterBinding",
11672 isMany: true
11673 },
11674 {
11675 name: "resourceAssignmentExpression",
11676 type: "ResourceAssignmentExpression"
11677 },
11678 {
11679 name: "name",
11680 isAttr: true,
11681 type: "String"
11682 }
11683 ]
11684 },
11685 {
11686 name: "ResourceParameterBinding",
11687 properties: [
11688 {
11689 name: "expression",
11690 type: "Expression",
11691 xml: {
11692 serialize: "xsi:type"
11693 }
11694 },
11695 {
11696 name: "parameterRef",
11697 type: "ResourceParameter",
11698 isAttr: true,
11699 isReference: true
11700 }
11701 ],
11702 superClass: [
11703 "BaseElement"
11704 ]
11705 },
11706 {
11707 name: "ResourceAssignmentExpression",
11708 properties: [
11709 {
11710 name: "expression",
11711 type: "Expression",
11712 xml: {
11713 serialize: "xsi:type"
11714 }
11715 }
11716 ],
11717 superClass: [
11718 "BaseElement"
11719 ]
11720 },
11721 {
11722 name: "Import",
11723 properties: [
11724 {
11725 name: "importType",
11726 isAttr: true,
11727 type: "String"
11728 },
11729 {
11730 name: "location",
11731 isAttr: true,
11732 type: "String"
11733 },
11734 {
11735 name: "namespace",
11736 isAttr: true,
11737 type: "String"
11738 }
11739 ]
11740 },
11741 {
11742 name: "Definitions",
11743 superClass: [
11744 "BaseElement"
11745 ],
11746 properties: [
11747 {
11748 name: "name",
11749 isAttr: true,
11750 type: "String"
11751 },
11752 {
11753 name: "targetNamespace",
11754 isAttr: true,
11755 type: "String"
11756 },
11757 {
11758 name: "expressionLanguage",
11759 "default": "http://www.w3.org/1999/XPath",
11760 isAttr: true,
11761 type: "String"
11762 },
11763 {
11764 name: "typeLanguage",
11765 "default": "http://www.w3.org/2001/XMLSchema",
11766 isAttr: true,
11767 type: "String"
11768 },
11769 {
11770 name: "imports",
11771 type: "Import",
11772 isMany: true
11773 },
11774 {
11775 name: "extensions",
11776 type: "Extension",
11777 isMany: true
11778 },
11779 {
11780 name: "rootElements",
11781 type: "RootElement",
11782 isMany: true
11783 },
11784 {
11785 name: "diagrams",
11786 isMany: true,
11787 type: "bpmndi:BPMNDiagram"
11788 },
11789 {
11790 name: "exporter",
11791 isAttr: true,
11792 type: "String"
11793 },
11794 {
11795 name: "relationships",
11796 type: "Relationship",
11797 isMany: true
11798 },
11799 {
11800 name: "exporterVersion",
11801 isAttr: true,
11802 type: "String"
11803 }
11804 ]
11805 }
11806 ];
11807 var enumerations = [
11808 {
11809 name: "ProcessType",
11810 literalValues: [
11811 {
11812 name: "None"
11813 },
11814 {
11815 name: "Public"
11816 },
11817 {
11818 name: "Private"
11819 }
11820 ]
11821 },
11822 {
11823 name: "GatewayDirection",
11824 literalValues: [
11825 {
11826 name: "Unspecified"
11827 },
11828 {
11829 name: "Converging"
11830 },
11831 {
11832 name: "Diverging"
11833 },
11834 {
11835 name: "Mixed"
11836 }
11837 ]
11838 },
11839 {
11840 name: "EventBasedGatewayType",
11841 literalValues: [
11842 {
11843 name: "Parallel"
11844 },
11845 {
11846 name: "Exclusive"
11847 }
11848 ]
11849 },
11850 {
11851 name: "RelationshipDirection",
11852 literalValues: [
11853 {
11854 name: "None"
11855 },
11856 {
11857 name: "Forward"
11858 },
11859 {
11860 name: "Backward"
11861 },
11862 {
11863 name: "Both"
11864 }
11865 ]
11866 },
11867 {
11868 name: "ItemKind",
11869 literalValues: [
11870 {
11871 name: "Physical"
11872 },
11873 {
11874 name: "Information"
11875 }
11876 ]
11877 },
11878 {
11879 name: "ChoreographyLoopType",
11880 literalValues: [
11881 {
11882 name: "None"
11883 },
11884 {
11885 name: "Standard"
11886 },
11887 {
11888 name: "MultiInstanceSequential"
11889 },
11890 {
11891 name: "MultiInstanceParallel"
11892 }
11893 ]
11894 },
11895 {
11896 name: "AssociationDirection",
11897 literalValues: [
11898 {
11899 name: "None"
11900 },
11901 {
11902 name: "One"
11903 },
11904 {
11905 name: "Both"
11906 }
11907 ]
11908 },
11909 {
11910 name: "MultiInstanceBehavior",
11911 literalValues: [
11912 {
11913 name: "None"
11914 },
11915 {
11916 name: "One"
11917 },
11918 {
11919 name: "All"
11920 },
11921 {
11922 name: "Complex"
11923 }
11924 ]
11925 },
11926 {
11927 name: "AdHocOrdering",
11928 literalValues: [
11929 {
11930 name: "Parallel"
11931 },
11932 {
11933 name: "Sequential"
11934 }
11935 ]
11936 }
11937 ];
11938 var prefix$1 = "bpmn";
11939 var xml = {
11940 tagAlias: "lowerCase",
11941 typePrefix: "t"
11942 };
11943 var BpmnPackage = {
11944 name: name,
11945 uri: uri,
11946 associations: associations,
11947 types: types$1,
11948 enumerations: enumerations,
11949 prefix: prefix$1,
11950 xml: xml
11951 };
11952
11953 var name$1 = "BPMNDI";
11954 var uri$1 = "http://www.omg.org/spec/BPMN/20100524/DI";
11955 var types$1$1 = [
11956 {
11957 name: "BPMNDiagram",
11958 properties: [
11959 {
11960 name: "plane",
11961 type: "BPMNPlane",
11962 redefines: "di:Diagram#rootElement"
11963 },
11964 {
11965 name: "labelStyle",
11966 type: "BPMNLabelStyle",
11967 isMany: true
11968 }
11969 ],
11970 superClass: [
11971 "di:Diagram"
11972 ]
11973 },
11974 {
11975 name: "BPMNPlane",
11976 properties: [
11977 {
11978 name: "bpmnElement",
11979 isAttr: true,
11980 isReference: true,
11981 type: "bpmn:BaseElement",
11982 redefines: "di:DiagramElement#modelElement"
11983 }
11984 ],
11985 superClass: [
11986 "di:Plane"
11987 ]
11988 },
11989 {
11990 name: "BPMNShape",
11991 properties: [
11992 {
11993 name: "bpmnElement",
11994 isAttr: true,
11995 isReference: true,
11996 type: "bpmn:BaseElement",
11997 redefines: "di:DiagramElement#modelElement"
11998 },
11999 {
12000 name: "isHorizontal",
12001 isAttr: true,
12002 type: "Boolean"
12003 },
12004 {
12005 name: "isExpanded",
12006 isAttr: true,
12007 type: "Boolean"
12008 },
12009 {
12010 name: "isMarkerVisible",
12011 isAttr: true,
12012 type: "Boolean"
12013 },
12014 {
12015 name: "label",
12016 type: "BPMNLabel"
12017 },
12018 {
12019 name: "isMessageVisible",
12020 isAttr: true,
12021 type: "Boolean"
12022 },
12023 {
12024 name: "participantBandKind",
12025 type: "ParticipantBandKind",
12026 isAttr: true
12027 },
12028 {
12029 name: "choreographyActivityShape",
12030 type: "BPMNShape",
12031 isAttr: true,
12032 isReference: true
12033 }
12034 ],
12035 superClass: [
12036 "di:LabeledShape"
12037 ]
12038 },
12039 {
12040 name: "BPMNEdge",
12041 properties: [
12042 {
12043 name: "label",
12044 type: "BPMNLabel"
12045 },
12046 {
12047 name: "bpmnElement",
12048 isAttr: true,
12049 isReference: true,
12050 type: "bpmn:BaseElement",
12051 redefines: "di:DiagramElement#modelElement"
12052 },
12053 {
12054 name: "sourceElement",
12055 isAttr: true,
12056 isReference: true,
12057 type: "di:DiagramElement",
12058 redefines: "di:Edge#source"
12059 },
12060 {
12061 name: "targetElement",
12062 isAttr: true,
12063 isReference: true,
12064 type: "di:DiagramElement",
12065 redefines: "di:Edge#target"
12066 },
12067 {
12068 name: "messageVisibleKind",
12069 type: "MessageVisibleKind",
12070 isAttr: true,
12071 "default": "initiating"
12072 }
12073 ],
12074 superClass: [
12075 "di:LabeledEdge"
12076 ]
12077 },
12078 {
12079 name: "BPMNLabel",
12080 properties: [
12081 {
12082 name: "labelStyle",
12083 type: "BPMNLabelStyle",
12084 isAttr: true,
12085 isReference: true,
12086 redefines: "di:DiagramElement#style"
12087 }
12088 ],
12089 superClass: [
12090 "di:Label"
12091 ]
12092 },
12093 {
12094 name: "BPMNLabelStyle",
12095 properties: [
12096 {
12097 name: "font",
12098 type: "dc:Font"
12099 }
12100 ],
12101 superClass: [
12102 "di:Style"
12103 ]
12104 }
12105 ];
12106 var enumerations$1 = [
12107 {
12108 name: "ParticipantBandKind",
12109 literalValues: [
12110 {
12111 name: "top_initiating"
12112 },
12113 {
12114 name: "middle_initiating"
12115 },
12116 {
12117 name: "bottom_initiating"
12118 },
12119 {
12120 name: "top_non_initiating"
12121 },
12122 {
12123 name: "middle_non_initiating"
12124 },
12125 {
12126 name: "bottom_non_initiating"
12127 }
12128 ]
12129 },
12130 {
12131 name: "MessageVisibleKind",
12132 literalValues: [
12133 {
12134 name: "initiating"
12135 },
12136 {
12137 name: "non_initiating"
12138 }
12139 ]
12140 }
12141 ];
12142 var associations$1 = [
12143 ];
12144 var prefix$1$1 = "bpmndi";
12145 var BpmnDiPackage = {
12146 name: name$1,
12147 uri: uri$1,
12148 types: types$1$1,
12149 enumerations: enumerations$1,
12150 associations: associations$1,
12151 prefix: prefix$1$1
12152 };
12153
12154 var name$2 = "DC";
12155 var uri$2 = "http://www.omg.org/spec/DD/20100524/DC";
12156 var types$2 = [
12157 {
12158 name: "Boolean"
12159 },
12160 {
12161 name: "Integer"
12162 },
12163 {
12164 name: "Real"
12165 },
12166 {
12167 name: "String"
12168 },
12169 {
12170 name: "Font",
12171 properties: [
12172 {
12173 name: "name",
12174 type: "String",
12175 isAttr: true
12176 },
12177 {
12178 name: "size",
12179 type: "Real",
12180 isAttr: true
12181 },
12182 {
12183 name: "isBold",
12184 type: "Boolean",
12185 isAttr: true
12186 },
12187 {
12188 name: "isItalic",
12189 type: "Boolean",
12190 isAttr: true
12191 },
12192 {
12193 name: "isUnderline",
12194 type: "Boolean",
12195 isAttr: true
12196 },
12197 {
12198 name: "isStrikeThrough",
12199 type: "Boolean",
12200 isAttr: true
12201 }
12202 ]
12203 },
12204 {
12205 name: "Point",
12206 properties: [
12207 {
12208 name: "x",
12209 type: "Real",
12210 "default": "0",
12211 isAttr: true
12212 },
12213 {
12214 name: "y",
12215 type: "Real",
12216 "default": "0",
12217 isAttr: true
12218 }
12219 ]
12220 },
12221 {
12222 name: "Bounds",
12223 properties: [
12224 {
12225 name: "x",
12226 type: "Real",
12227 "default": "0",
12228 isAttr: true
12229 },
12230 {
12231 name: "y",
12232 type: "Real",
12233 "default": "0",
12234 isAttr: true
12235 },
12236 {
12237 name: "width",
12238 type: "Real",
12239 isAttr: true
12240 },
12241 {
12242 name: "height",
12243 type: "Real",
12244 isAttr: true
12245 }
12246 ]
12247 }
12248 ];
12249 var prefix$2 = "dc";
12250 var associations$2 = [
12251 ];
12252 var DcPackage = {
12253 name: name$2,
12254 uri: uri$2,
12255 types: types$2,
12256 prefix: prefix$2,
12257 associations: associations$2
12258 };
12259
12260 var name$3 = "DI";
12261 var uri$3 = "http://www.omg.org/spec/DD/20100524/DI";
12262 var types$3 = [
12263 {
12264 name: "DiagramElement",
12265 isAbstract: true,
12266 properties: [
12267 {
12268 name: "id",
12269 type: "String",
12270 isAttr: true,
12271 isId: true
12272 },
12273 {
12274 name: "extension",
12275 type: "Extension"
12276 },
12277 {
12278 name: "owningDiagram",
12279 type: "Diagram",
12280 isReadOnly: true,
12281 isVirtual: true,
12282 isReference: true
12283 },
12284 {
12285 name: "owningElement",
12286 type: "DiagramElement",
12287 isReadOnly: true,
12288 isVirtual: true,
12289 isReference: true
12290 },
12291 {
12292 name: "modelElement",
12293 isReadOnly: true,
12294 isVirtual: true,
12295 isReference: true,
12296 type: "Element"
12297 },
12298 {
12299 name: "style",
12300 type: "Style",
12301 isReadOnly: true,
12302 isVirtual: true,
12303 isReference: true
12304 },
12305 {
12306 name: "ownedElement",
12307 type: "DiagramElement",
12308 isReadOnly: true,
12309 isVirtual: true,
12310 isMany: true
12311 }
12312 ]
12313 },
12314 {
12315 name: "Node",
12316 isAbstract: true,
12317 superClass: [
12318 "DiagramElement"
12319 ]
12320 },
12321 {
12322 name: "Edge",
12323 isAbstract: true,
12324 superClass: [
12325 "DiagramElement"
12326 ],
12327 properties: [
12328 {
12329 name: "source",
12330 type: "DiagramElement",
12331 isReadOnly: true,
12332 isVirtual: true,
12333 isReference: true
12334 },
12335 {
12336 name: "target",
12337 type: "DiagramElement",
12338 isReadOnly: true,
12339 isVirtual: true,
12340 isReference: true
12341 },
12342 {
12343 name: "waypoint",
12344 isUnique: false,
12345 isMany: true,
12346 type: "dc:Point",
12347 xml: {
12348 serialize: "xsi:type"
12349 }
12350 }
12351 ]
12352 },
12353 {
12354 name: "Diagram",
12355 isAbstract: true,
12356 properties: [
12357 {
12358 name: "id",
12359 type: "String",
12360 isAttr: true,
12361 isId: true
12362 },
12363 {
12364 name: "rootElement",
12365 type: "DiagramElement",
12366 isReadOnly: true,
12367 isVirtual: true
12368 },
12369 {
12370 name: "name",
12371 isAttr: true,
12372 type: "String"
12373 },
12374 {
12375 name: "documentation",
12376 isAttr: true,
12377 type: "String"
12378 },
12379 {
12380 name: "resolution",
12381 isAttr: true,
12382 type: "Real"
12383 },
12384 {
12385 name: "ownedStyle",
12386 type: "Style",
12387 isReadOnly: true,
12388 isVirtual: true,
12389 isMany: true
12390 }
12391 ]
12392 },
12393 {
12394 name: "Shape",
12395 isAbstract: true,
12396 superClass: [
12397 "Node"
12398 ],
12399 properties: [
12400 {
12401 name: "bounds",
12402 type: "dc:Bounds"
12403 }
12404 ]
12405 },
12406 {
12407 name: "Plane",
12408 isAbstract: true,
12409 superClass: [
12410 "Node"
12411 ],
12412 properties: [
12413 {
12414 name: "planeElement",
12415 type: "DiagramElement",
12416 subsettedProperty: "DiagramElement-ownedElement",
12417 isMany: true
12418 }
12419 ]
12420 },
12421 {
12422 name: "LabeledEdge",
12423 isAbstract: true,
12424 superClass: [
12425 "Edge"
12426 ],
12427 properties: [
12428 {
12429 name: "ownedLabel",
12430 type: "Label",
12431 isReadOnly: true,
12432 subsettedProperty: "DiagramElement-ownedElement",
12433 isVirtual: true,
12434 isMany: true
12435 }
12436 ]
12437 },
12438 {
12439 name: "LabeledShape",
12440 isAbstract: true,
12441 superClass: [
12442 "Shape"
12443 ],
12444 properties: [
12445 {
12446 name: "ownedLabel",
12447 type: "Label",
12448 isReadOnly: true,
12449 subsettedProperty: "DiagramElement-ownedElement",
12450 isVirtual: true,
12451 isMany: true
12452 }
12453 ]
12454 },
12455 {
12456 name: "Label",
12457 isAbstract: true,
12458 superClass: [
12459 "Node"
12460 ],
12461 properties: [
12462 {
12463 name: "bounds",
12464 type: "dc:Bounds"
12465 }
12466 ]
12467 },
12468 {
12469 name: "Style",
12470 isAbstract: true,
12471 properties: [
12472 {
12473 name: "id",
12474 type: "String",
12475 isAttr: true,
12476 isId: true
12477 }
12478 ]
12479 },
12480 {
12481 name: "Extension",
12482 properties: [
12483 {
12484 name: "values",
12485 type: "Element",
12486 isMany: true
12487 }
12488 ]
12489 }
12490 ];
12491 var associations$3 = [
12492 ];
12493 var prefix$3 = "di";
12494 var xml$1 = {
12495 tagAlias: "lowerCase"
12496 };
12497 var DiPackage = {
12498 name: name$3,
12499 uri: uri$3,
12500 types: types$3,
12501 associations: associations$3,
12502 prefix: prefix$3,
12503 xml: xml$1
12504 };
12505
12506 var name$4 = "bpmn.io colors for BPMN";
12507 var uri$4 = "http://bpmn.io/schema/bpmn/biocolor/1.0";
12508 var prefix$4 = "bioc";
12509 var types$4 = [
12510 {
12511 name: "ColoredShape",
12512 "extends": [
12513 "bpmndi:BPMNShape"
12514 ],
12515 properties: [
12516 {
12517 name: "stroke",
12518 isAttr: true,
12519 type: "String"
12520 },
12521 {
12522 name: "fill",
12523 isAttr: true,
12524 type: "String"
12525 }
12526 ]
12527 },
12528 {
12529 name: "ColoredEdge",
12530 "extends": [
12531 "bpmndi:BPMNEdge"
12532 ],
12533 properties: [
12534 {
12535 name: "stroke",
12536 isAttr: true,
12537 type: "String"
12538 },
12539 {
12540 name: "fill",
12541 isAttr: true,
12542 type: "String"
12543 }
12544 ]
12545 }
12546 ];
12547 var enumerations$2 = [
12548 ];
12549 var associations$4 = [
12550 ];
12551 var BiocPackage = {
12552 name: name$4,
12553 uri: uri$4,
12554 prefix: prefix$4,
12555 types: types$4,
12556 enumerations: enumerations$2,
12557 associations: associations$4
12558 };
12559
12560 var packages = {
12561 bpmn: BpmnPackage,
12562 bpmndi: BpmnDiPackage,
12563 dc: DcPackage,
12564 di: DiPackage,
12565 bioc: BiocPackage
12566 };
12567
12568 function simple(additionalPackages, options) {
12569 var pks = assign({}, packages, additionalPackages);
12570
12571 return new BpmnModdle(pks, options);
12572 }
12573
12574 function elementToString(e) {
12575 if (!e) {
12576 return '<null>';
12577 }
12578
12579 return '<' + e.$type + (e.id ? ' id="' + e.id : '') + '" />';
12580 }
12581
12582 var diRefs = new objectRefs(
12583 { name: 'bpmnElement', enumerable: true },
12584 { name: 'di', configurable: true }
12585 );
12586
12587 /**
12588 * Returns true if an element has the given meta-model type
12589 *
12590 * @param {ModdleElement} element
12591 * @param {String} type
12592 *
12593 * @return {Boolean}
12594 */
12595 function is(element, type) {
12596 return element.$instanceOf(type);
12597 }
12598
12599
12600 /**
12601 * Find a suitable display candidate for definitions where the DI does not
12602 * correctly specify one.
12603 */
12604 function findDisplayCandidate(definitions) {
12605 return find(definitions.rootElements, function(e) {
12606 return is(e, 'bpmn:Process') || is(e, 'bpmn:Collaboration');
12607 });
12608 }
12609
12610
12611 function BpmnTreeWalker(handler, translate) {
12612
12613 // list of containers already walked
12614 var handledElements = {};
12615
12616 // list of elements to handle deferred to ensure
12617 // prerequisites are drawn
12618 var deferred = [];
12619
12620 // Helpers //////////////////////
12621
12622 function contextual(fn, ctx) {
12623 return function(e) {
12624 fn(e, ctx);
12625 };
12626 }
12627
12628 function handled(element) {
12629 handledElements[element.id] = element;
12630 }
12631
12632 function isHandled(element) {
12633 return handledElements[element.id];
12634 }
12635
12636 function visit(element, ctx) {
12637
12638 var gfx = element.gfx;
12639
12640 // avoid multiple rendering of elements
12641 if (gfx) {
12642 throw new Error(
12643 translate('already rendered {element}', { element: elementToString(element) })
12644 );
12645 }
12646
12647 // call handler
12648 return handler.element(element, ctx);
12649 }
12650
12651 function visitRoot(element, diagram) {
12652 return handler.root(element, diagram);
12653 }
12654
12655 function visitIfDi(element, ctx) {
12656
12657 try {
12658 var gfx = element.di && visit(element, ctx);
12659
12660 handled(element);
12661
12662 return gfx;
12663 } catch (e) {
12664 logError(e.message, { element: element, error: e });
12665
12666 console.error(translate('failed to import {element}', { element: elementToString(element) }));
12667 console.error(e);
12668 }
12669 }
12670
12671 function logError(message, context) {
12672 handler.error(message, context);
12673 }
12674
12675 // DI handling //////////////////////
12676
12677 function registerDi(di) {
12678 var bpmnElement = di.bpmnElement;
12679
12680 if (bpmnElement) {
12681 if (bpmnElement.di) {
12682 logError(
12683 translate('multiple DI elements defined for {element}', {
12684 element: elementToString(bpmnElement)
12685 }),
12686 { element: bpmnElement }
12687 );
12688 } else {
12689 diRefs.bind(bpmnElement, 'di');
12690 bpmnElement.di = di;
12691 }
12692 } else {
12693 logError(
12694 translate('no bpmnElement referenced in {element}', {
12695 element: elementToString(di)
12696 }),
12697 { element: di }
12698 );
12699 }
12700 }
12701
12702 function handleDiagram(diagram) {
12703 handlePlane(diagram.plane);
12704 }
12705
12706 function handlePlane(plane) {
12707 registerDi(plane);
12708
12709 forEach(plane.planeElement, handlePlaneElement);
12710 }
12711
12712 function handlePlaneElement(planeElement) {
12713 registerDi(planeElement);
12714 }
12715
12716
12717 // Semantic handling //////////////////////
12718
12719 /**
12720 * Handle definitions and return the rendered diagram (if any)
12721 *
12722 * @param {ModdleElement} definitions to walk and import
12723 * @param {ModdleElement} [diagram] specific diagram to import and display
12724 *
12725 * @throws {Error} if no diagram to display could be found
12726 */
12727 function handleDefinitions(definitions, diagram) {
12728
12729 // make sure we walk the correct bpmnElement
12730
12731 var diagrams = definitions.diagrams;
12732
12733 if (diagram && diagrams.indexOf(diagram) === -1) {
12734 throw new Error(translate('diagram not part of bpmn:Definitions'));
12735 }
12736
12737 if (!diagram && diagrams && diagrams.length) {
12738 diagram = diagrams[0];
12739 }
12740
12741 // no diagram -> nothing to import
12742 if (!diagram) {
12743 throw new Error(translate('no diagram to display'));
12744 }
12745
12746 // load DI from selected diagram only
12747 handleDiagram(diagram);
12748
12749
12750 var plane = diagram.plane;
12751
12752 if (!plane) {
12753 throw new Error(translate(
12754 'no plane for {element}',
12755 { element: elementToString(diagram) }
12756 ));
12757 }
12758
12759 var rootElement = plane.bpmnElement;
12760
12761 // ensure we default to a suitable display candidate (process or collaboration),
12762 // even if non is specified in DI
12763 if (!rootElement) {
12764 rootElement = findDisplayCandidate(definitions);
12765
12766 if (!rootElement) {
12767 throw new Error(translate('no process or collaboration to display'));
12768 } else {
12769
12770 logError(
12771 translate('correcting missing bpmnElement on {plane} to {rootElement}', {
12772 plane: elementToString(plane),
12773 rootElement: elementToString(rootElement)
12774 })
12775 );
12776
12777 // correct DI on the fly
12778 plane.bpmnElement = rootElement;
12779 registerDi(plane);
12780 }
12781 }
12782
12783
12784 var ctx = visitRoot(rootElement, plane);
12785
12786 if (is(rootElement, 'bpmn:Process')) {
12787 handleProcess(rootElement, ctx);
12788 } else if (is(rootElement, 'bpmn:Collaboration')) {
12789 handleCollaboration(rootElement);
12790
12791 // force drawing of everything not yet drawn that is part of the target DI
12792 handleUnhandledProcesses(definitions.rootElements, ctx);
12793 } else {
12794 throw new Error(
12795 translate('unsupported bpmnElement for {plane}: {rootElement}', {
12796 plane: elementToString(plane),
12797 rootElement: elementToString(rootElement)
12798 })
12799 );
12800 }
12801
12802 // handle all deferred elements
12803 handleDeferred();
12804 }
12805
12806 function handleDeferred() {
12807
12808 var fn;
12809
12810 // drain deferred until empty
12811 while (deferred.length) {
12812 fn = deferred.shift();
12813
12814 fn();
12815 }
12816 }
12817
12818 function handleProcess(process, context) {
12819 handleFlowElementsContainer(process, context);
12820 handleIoSpecification(process.ioSpecification, context);
12821
12822 handleArtifacts(process.artifacts, context);
12823
12824 // log process handled
12825 handled(process);
12826 }
12827
12828 function handleUnhandledProcesses(rootElements, ctx) {
12829
12830 // walk through all processes that have not yet been drawn and draw them
12831 // if they contain lanes with DI information.
12832 // we do this to pass the free-floating lane test cases in the MIWG test suite
12833 var processes = filter(rootElements, function(e) {
12834 return !isHandled(e) && is(e, 'bpmn:Process') && e.laneSets;
12835 });
12836
12837 processes.forEach(contextual(handleProcess, ctx));
12838 }
12839
12840 function handleMessageFlow(messageFlow, context) {
12841 visitIfDi(messageFlow, context);
12842 }
12843
12844 function handleMessageFlows(messageFlows, context) {
12845 forEach(messageFlows, contextual(handleMessageFlow, context));
12846 }
12847
12848 function handleDataAssociation(association, context) {
12849 visitIfDi(association, context);
12850 }
12851
12852 function handleDataInput(dataInput, context) {
12853 visitIfDi(dataInput, context);
12854 }
12855
12856 function handleDataOutput(dataOutput, context) {
12857 visitIfDi(dataOutput, context);
12858 }
12859
12860 function handleArtifact(artifact, context) {
12861
12862 // bpmn:TextAnnotation
12863 // bpmn:Group
12864 // bpmn:Association
12865
12866 visitIfDi(artifact, context);
12867 }
12868
12869 function handleArtifacts(artifacts, context) {
12870
12871 forEach(artifacts, function(e) {
12872 if (is(e, 'bpmn:Association')) {
12873 deferred.push(function() {
12874 handleArtifact(e, context);
12875 });
12876 } else {
12877 handleArtifact(e, context);
12878 }
12879 });
12880 }
12881
12882 function handleIoSpecification(ioSpecification, context) {
12883
12884 if (!ioSpecification) {
12885 return;
12886 }
12887
12888 forEach(ioSpecification.dataInputs, contextual(handleDataInput, context));
12889 forEach(ioSpecification.dataOutputs, contextual(handleDataOutput, context));
12890 }
12891
12892 function handleSubProcess(subProcess, context) {
12893 handleFlowElementsContainer(subProcess, context);
12894 handleArtifacts(subProcess.artifacts, context);
12895 }
12896
12897 function handleFlowNode(flowNode, context) {
12898 var childCtx = visitIfDi(flowNode, context);
12899
12900 if (is(flowNode, 'bpmn:SubProcess')) {
12901 handleSubProcess(flowNode, childCtx || context);
12902 }
12903
12904 if (is(flowNode, 'bpmn:Activity')) {
12905 handleIoSpecification(flowNode.ioSpecification, context);
12906 }
12907
12908 // defer handling of associations
12909 // affected types:
12910 //
12911 // * bpmn:Activity
12912 // * bpmn:ThrowEvent
12913 // * bpmn:CatchEvent
12914 //
12915 deferred.push(function() {
12916 forEach(flowNode.dataInputAssociations, contextual(handleDataAssociation, context));
12917 forEach(flowNode.dataOutputAssociations, contextual(handleDataAssociation, context));
12918 });
12919 }
12920
12921 function handleSequenceFlow(sequenceFlow, context) {
12922 visitIfDi(sequenceFlow, context);
12923 }
12924
12925 function handleDataElement(dataObject, context) {
12926 visitIfDi(dataObject, context);
12927 }
12928
12929 function handleLane(lane, context) {
12930
12931 deferred.push(function() {
12932
12933 var newContext = visitIfDi(lane, context);
12934
12935 if (lane.childLaneSet) {
12936 handleLaneSet(lane.childLaneSet, newContext || context);
12937 }
12938
12939 wireFlowNodeRefs(lane);
12940 });
12941 }
12942
12943 function handleLaneSet(laneSet, context) {
12944 forEach(laneSet.lanes, contextual(handleLane, context));
12945 }
12946
12947 function handleLaneSets(laneSets, context) {
12948 forEach(laneSets, contextual(handleLaneSet, context));
12949 }
12950
12951 function handleFlowElementsContainer(container, context) {
12952 handleFlowElements(container.flowElements, context);
12953
12954 if (container.laneSets) {
12955 handleLaneSets(container.laneSets, context);
12956 }
12957 }
12958
12959 function handleFlowElements(flowElements, context) {
12960 forEach(flowElements, function(e) {
12961 if (is(e, 'bpmn:SequenceFlow')) {
12962 deferred.push(function() {
12963 handleSequenceFlow(e, context);
12964 });
12965 } else if (is(e, 'bpmn:BoundaryEvent')) {
12966 deferred.unshift(function() {
12967 handleFlowNode(e, context);
12968 });
12969 } else if (is(e, 'bpmn:FlowNode')) {
12970 handleFlowNode(e, context);
12971 } else if (is(e, 'bpmn:DataObject')) ; else if (is(e, 'bpmn:DataStoreReference')) {
12972 handleDataElement(e, context);
12973 } else if (is(e, 'bpmn:DataObjectReference')) {
12974 handleDataElement(e, context);
12975 } else {
12976 logError(
12977 translate('unrecognized flowElement {element} in context {context}', {
12978 element: elementToString(e),
12979 context: (context ? elementToString(context.businessObject) : 'null')
12980 }),
12981 { element: e, context: context }
12982 );
12983 }
12984 });
12985 }
12986
12987 function handleParticipant(participant, context) {
12988 var newCtx = visitIfDi(participant, context);
12989
12990 var process = participant.processRef;
12991 if (process) {
12992 handleProcess(process, newCtx || context);
12993 }
12994 }
12995
12996 function handleCollaboration(collaboration) {
12997
12998 forEach(collaboration.participants, contextual(handleParticipant));
12999
13000 handleArtifacts(collaboration.artifacts);
13001
13002 // handle message flows latest in the process
13003 deferred.push(function() {
13004 handleMessageFlows(collaboration.messageFlows);
13005 });
13006 }
13007
13008
13009 function wireFlowNodeRefs(lane) {
13010
13011 // wire the virtual flowNodeRefs <-> relationship
13012 forEach(lane.flowNodeRef, function(flowNode) {
13013 var lanes = flowNode.get('lanes');
13014
13015 if (lanes) {
13016 lanes.push(lane);
13017 }
13018 });
13019 }
13020
13021 // API //////////////////////
13022
13023 return {
13024 handleDeferred: handleDeferred,
13025 handleDefinitions: handleDefinitions,
13026 handleSubProcess: handleSubProcess,
13027 registerDi: registerDi
13028 };
13029 }
13030
13031 /**
13032 * Import the definitions into a diagram.
13033 *
13034 * Errors and warnings are reported through the specified callback.
13035 *
13036 * @param {djs.Diagram} diagram
13037 * @param {ModdleElement<Definitions>} definitions
13038 * @param {ModdleElement<BPMNDiagram>} [bpmnDiagram] the diagram to be rendered
13039 * (if not provided, the first one will be rendered)
13040 * @param {Function} done the callback, invoked with (err, [ warning ]) once the import is done
13041 */
13042 function importBpmnDiagram(diagram, definitions, bpmnDiagram, done) {
13043
13044 if (isFunction(bpmnDiagram)) {
13045 done = bpmnDiagram;
13046 bpmnDiagram = null;
13047 }
13048
13049 var importer,
13050 eventBus,
13051 translate;
13052
13053 var error,
13054 warnings = [];
13055
13056 /**
13057 * Walk the diagram semantically, importing (=drawing)
13058 * all elements you encounter.
13059 *
13060 * @param {ModdleElement<Definitions>} definitions
13061 * @param {ModdleElement<BPMNDiagram>} bpmnDiagram
13062 */
13063 function render(definitions, bpmnDiagram) {
13064
13065 var visitor = {
13066
13067 root: function(element) {
13068 return importer.add(element);
13069 },
13070
13071 element: function(element, parentShape) {
13072 return importer.add(element, parentShape);
13073 },
13074
13075 error: function(message, context) {
13076 warnings.push({ message: message, context: context });
13077 }
13078 };
13079
13080 var walker = new BpmnTreeWalker(visitor, translate);
13081
13082 // traverse BPMN 2.0 document model,
13083 // starting at definitions
13084 walker.handleDefinitions(definitions, bpmnDiagram);
13085 }
13086
13087 try {
13088 importer = diagram.get('bpmnImporter');
13089 eventBus = diagram.get('eventBus');
13090 translate = diagram.get('translate');
13091
13092 eventBus.fire('import.render.start', { definitions: definitions });
13093
13094 render(definitions, bpmnDiagram);
13095
13096 eventBus.fire('import.render.complete', {
13097 error: error,
13098 warnings: warnings
13099 });
13100 } catch (e) {
13101 error = e;
13102 }
13103
13104 done(error, warnings);
13105 }
13106
13107 /**
13108 * Is an element of the given BPMN type?
13109 *
13110 * @param {djs.model.Base|ModdleElement} element
13111 * @param {String} type
13112 *
13113 * @return {Boolean}
13114 */
13115 function is$1(element, type) {
13116 var bo = getBusinessObject(element);
13117
13118 return bo && (typeof bo.$instanceOf === 'function') && bo.$instanceOf(type);
13119 }
13120
13121
13122 /**
13123 * Return the business object for a given element.
13124 *
13125 * @param {djs.model.Base|ModdleElement} element
13126 *
13127 * @return {ModdleElement}
13128 */
13129 function getBusinessObject(element) {
13130 return (element && element.businessObject) || element;
13131 }
13132
13133 function isExpanded(element) {
13134
13135 if (is$1(element, 'bpmn:CallActivity')) {
13136 return false;
13137 }
13138
13139 if (is$1(element, 'bpmn:SubProcess')) {
13140 return !!getBusinessObject(element).di.isExpanded;
13141 }
13142
13143 if (is$1(element, 'bpmn:Participant')) {
13144 return !!getBusinessObject(element).processRef;
13145 }
13146
13147 return true;
13148 }
13149
13150 function isEventSubProcess(element) {
13151 return element && !!getBusinessObject(element).triggeredByEvent;
13152 }
13153
13154 function getLabelAttr(semantic) {
13155 if (
13156 is$1(semantic, 'bpmn:FlowElement') ||
13157 is$1(semantic, 'bpmn:Participant') ||
13158 is$1(semantic, 'bpmn:Lane') ||
13159 is$1(semantic, 'bpmn:SequenceFlow') ||
13160 is$1(semantic, 'bpmn:MessageFlow') ||
13161 is$1(semantic, 'bpmn:DataInput') ||
13162 is$1(semantic, 'bpmn:DataOutput')
13163 ) {
13164 return 'name';
13165 }
13166
13167 if (is$1(semantic, 'bpmn:TextAnnotation')) {
13168 return 'text';
13169 }
13170
13171 if (is$1(semantic, 'bpmn:Group')) {
13172 return 'categoryValueRef';
13173 }
13174 }
13175
13176 function getCategoryValue(semantic) {
13177 var categoryValueRef = semantic['categoryValueRef'];
13178
13179 if (!categoryValueRef) {
13180 return '';
13181 }
13182
13183
13184 return categoryValueRef.value || '';
13185 }
13186
13187 function getLabel(element) {
13188 var semantic = element.businessObject,
13189 attr = getLabelAttr(semantic);
13190
13191 if (attr) {
13192
13193 if (attr === 'categoryValueRef') {
13194
13195 return getCategoryValue(semantic);
13196 }
13197
13198 return semantic[attr] || '';
13199 }
13200 }
13201
13202 // element utils //////////////////////
13203
13204 /**
13205 * Checks if eventDefinition of the given element matches with semantic type.
13206 *
13207 * @return {boolean} true if element is of the given semantic type
13208 */
13209 function isTypedEvent(event, eventDefinitionType, filter) {
13210
13211 function matches(definition, filter) {
13212 return every(filter, function(val, key) {
13213
13214 // we want a == conversion here, to be able to catch
13215 // undefined == false and friends
13216 /* jshint -W116 */
13217 return definition[key] == val;
13218 });
13219 }
13220
13221 return some(event.eventDefinitions, function(definition) {
13222 return definition.$type === eventDefinitionType && matches(event, filter);
13223 });
13224 }
13225
13226 function isThrowEvent(event) {
13227 return (event.$type === 'bpmn:IntermediateThrowEvent') || (event.$type === 'bpmn:EndEvent');
13228 }
13229
13230 function isCollection(element) {
13231 var dataObject = element.dataObjectRef;
13232
13233 return element.isCollection || (dataObject && dataObject.isCollection);
13234 }
13235
13236 function getDi(element) {
13237 return element.businessObject.di;
13238 }
13239
13240 function getSemantic(element) {
13241 return element.businessObject;
13242 }
13243
13244
13245 // color access //////////////////////
13246
13247 function getFillColor(element, defaultColor) {
13248 return getDi(element).get('bioc:fill') || defaultColor || 'white';
13249 }
13250
13251 function getStrokeColor(element, defaultColor) {
13252 return getDi(element).get('bioc:stroke') || defaultColor || 'black';
13253 }
13254
13255
13256 // cropping path customizations //////////////////////
13257
13258 function getCirclePath(shape) {
13259
13260 var cx = shape.x + shape.width / 2,
13261 cy = shape.y + shape.height / 2,
13262 radius = shape.width / 2;
13263
13264 var circlePath = [
13265 ['M', cx, cy],
13266 ['m', 0, -radius],
13267 ['a', radius, radius, 0, 1, 1, 0, 2 * radius],
13268 ['a', radius, radius, 0, 1, 1, 0, -2 * radius],
13269 ['z']
13270 ];
13271
13272 return componentsToPath(circlePath);
13273 }
13274
13275 function getRoundRectPath(shape, borderRadius) {
13276
13277 var x = shape.x,
13278 y = shape.y,
13279 width = shape.width,
13280 height = shape.height;
13281
13282 var roundRectPath = [
13283 ['M', x + borderRadius, y],
13284 ['l', width - borderRadius * 2, 0],
13285 ['a', borderRadius, borderRadius, 0, 0, 1, borderRadius, borderRadius],
13286 ['l', 0, height - borderRadius * 2],
13287 ['a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, borderRadius],
13288 ['l', borderRadius * 2 - width, 0],
13289 ['a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, -borderRadius],
13290 ['l', 0, borderRadius * 2 - height],
13291 ['a', borderRadius, borderRadius, 0, 0, 1, borderRadius, -borderRadius],
13292 ['z']
13293 ];
13294
13295 return componentsToPath(roundRectPath);
13296 }
13297
13298 function getDiamondPath(shape) {
13299
13300 var width = shape.width,
13301 height = shape.height,
13302 x = shape.x,
13303 y = shape.y,
13304 halfWidth = width / 2,
13305 halfHeight = height / 2;
13306
13307 var diamondPath = [
13308 ['M', x + halfWidth, y],
13309 ['l', halfWidth, halfHeight],
13310 ['l', -halfWidth, halfHeight],
13311 ['l', -halfWidth, -halfHeight],
13312 ['z']
13313 ];
13314
13315 return componentsToPath(diamondPath);
13316 }
13317
13318 function getRectPath(shape) {
13319 var x = shape.x,
13320 y = shape.y,
13321 width = shape.width,
13322 height = shape.height;
13323
13324 var rectPath = [
13325 ['M', x, y],
13326 ['l', width, 0],
13327 ['l', 0, height],
13328 ['l', -width, 0],
13329 ['z']
13330 ];
13331
13332 return componentsToPath(rectPath);
13333 }
13334
13335 function createCommonjsModule$1(fn, module) {
13336 return module = { exports: {} }, fn(module, module.exports), module.exports;
13337 }
13338
13339 var hat_1 = createCommonjsModule$1(function (module) {
13340 var hat = module.exports = function (bits, base) {
13341 if (!base) base = 16;
13342 if (bits === undefined) bits = 128;
13343 if (bits <= 0) return '0';
13344
13345 var digits = Math.log(Math.pow(2, bits)) / Math.log(base);
13346 for (var i = 2; digits === Infinity; i *= 2) {
13347 digits = Math.log(Math.pow(2, bits / i)) / Math.log(base) * i;
13348 }
13349
13350 var rem = digits - Math.floor(digits);
13351
13352 var res = '';
13353
13354 for (var i = 0; i < Math.floor(digits); i++) {
13355 var x = Math.floor(Math.random() * base).toString(base);
13356 res = x + res;
13357 }
13358
13359 if (rem) {
13360 var b = Math.pow(base, rem);
13361 var x = Math.floor(Math.random() * b).toString(base);
13362 res = x + res;
13363 }
13364
13365 var parsed = parseInt(res, base);
13366 if (parsed !== Infinity && parsed >= Math.pow(2, bits)) {
13367 return hat(bits, base)
13368 }
13369 else return res;
13370 };
13371
13372 hat.rack = function (bits, base, expandBy) {
13373 var fn = function (data) {
13374 var iters = 0;
13375 do {
13376 if (iters ++ > 10) {
13377 if (expandBy) bits += expandBy;
13378 else throw new Error('too many ID collisions, use more bits')
13379 }
13380
13381 var id = hat(bits, base);
13382 } while (Object.hasOwnProperty.call(hats, id));
13383
13384 hats[id] = data;
13385 return id;
13386 };
13387 var hats = fn.hats = {};
13388
13389 fn.get = function (id) {
13390 return fn.hats[id];
13391 };
13392
13393 fn.set = function (id, value) {
13394 fn.hats[id] = value;
13395 return fn;
13396 };
13397
13398 fn.bits = bits || 128;
13399 fn.base = base || 16;
13400 return fn;
13401 };
13402 });
13403
13404 /**
13405 * Create a new id generator / cache instance.
13406 *
13407 * You may optionally provide a seed that is used internally.
13408 *
13409 * @param {Seed} seed
13410 */
13411
13412 function Ids(seed) {
13413 if (!(this instanceof Ids)) {
13414 return new Ids(seed);
13415 }
13416
13417 seed = seed || [128, 36, 1];
13418 this._seed = seed.length ? hat_1.rack(seed[0], seed[1], seed[2]) : seed;
13419 }
13420 /**
13421 * Generate a next id.
13422 *
13423 * @param {Object} [element] element to bind the id to
13424 *
13425 * @return {String} id
13426 */
13427
13428 Ids.prototype.next = function (element) {
13429 return this._seed(element || true);
13430 };
13431 /**
13432 * Generate a next id with a given prefix.
13433 *
13434 * @param {Object} [element] element to bind the id to
13435 *
13436 * @return {String} id
13437 */
13438
13439
13440 Ids.prototype.nextPrefixed = function (prefix, element) {
13441 var id;
13442
13443 do {
13444 id = prefix + this.next(true);
13445 } while (this.assigned(id)); // claim {prefix}{random}
13446
13447
13448 this.claim(id, element); // return
13449
13450 return id;
13451 };
13452 /**
13453 * Manually claim an existing id.
13454 *
13455 * @param {String} id
13456 * @param {String} [element] element the id is claimed by
13457 */
13458
13459
13460 Ids.prototype.claim = function (id, element) {
13461 this._seed.set(id, element || true);
13462 };
13463 /**
13464 * Returns true if the given id has already been assigned.
13465 *
13466 * @param {String} id
13467 * @return {Boolean}
13468 */
13469
13470
13471 Ids.prototype.assigned = function (id) {
13472 return this._seed.get(id) || false;
13473 };
13474 /**
13475 * Unclaim an id.
13476 *
13477 * @param {String} id the id to unclaim
13478 */
13479
13480
13481 Ids.prototype.unclaim = function (id) {
13482 delete this._seed.hats[id];
13483 };
13484 /**
13485 * Clear all claimed ids.
13486 */
13487
13488
13489 Ids.prototype.clear = function () {
13490 var hats = this._seed.hats,
13491 id;
13492
13493 for (id in hats) {
13494 this.unclaim(id);
13495 }
13496 };
13497
13498 var RENDERER_IDS = new Ids();
13499
13500 var TASK_BORDER_RADIUS = 10;
13501 var INNER_OUTER_DIST = 3;
13502
13503 var DEFAULT_FILL_OPACITY = .95,
13504 HIGH_FILL_OPACITY = .35;
13505
13506
13507 function BpmnRenderer(
13508 config, eventBus, styles, pathMap,
13509 canvas, textRenderer, priority) {
13510
13511 BaseRenderer.call(this, eventBus, priority);
13512
13513 var defaultFillColor = config && config.defaultFillColor,
13514 defaultStrokeColor = config && config.defaultStrokeColor;
13515
13516 var rendererId = RENDERER_IDS.next();
13517
13518 var markers = {};
13519
13520 var computeStyle = styles.computeStyle;
13521
13522 function addMarker(id, options) {
13523 var attrs = assign({
13524 fill: 'black',
13525 strokeWidth: 1,
13526 strokeLinecap: 'round',
13527 strokeDasharray: 'none'
13528 }, options.attrs);
13529
13530 var ref = options.ref || { x: 0, y: 0 };
13531
13532 var scale = options.scale || 1;
13533
13534 // fix for safari / chrome / firefox bug not correctly
13535 // resetting stroke dash array
13536 if (attrs.strokeDasharray === 'none') {
13537 attrs.strokeDasharray = [10000, 1];
13538 }
13539
13540 var marker = create('marker');
13541
13542 attr$1(options.element, attrs);
13543
13544 append(marker, options.element);
13545
13546 attr$1(marker, {
13547 id: id,
13548 viewBox: '0 0 20 20',
13549 refX: ref.x,
13550 refY: ref.y,
13551 markerWidth: 20 * scale,
13552 markerHeight: 20 * scale,
13553 orient: 'auto'
13554 });
13555
13556 var defs = query('defs', canvas._svg);
13557
13558 if (!defs) {
13559 defs = create('defs');
13560
13561 append(canvas._svg, defs);
13562 }
13563
13564 append(defs, marker);
13565
13566 markers[id] = marker;
13567 }
13568
13569 function colorEscape(str) {
13570 return str.replace(/[()\s,#]+/g, '_');
13571 }
13572
13573 function marker(type, fill, stroke) {
13574 var id = type + '-' + colorEscape(fill) + '-' + colorEscape(stroke) + '-' + rendererId;
13575
13576 if (!markers[id]) {
13577 createMarker(id, type, fill, stroke);
13578 }
13579
13580 return 'url(#' + id + ')';
13581 }
13582
13583 function createMarker(id, type, fill, stroke) {
13584
13585 if (type === 'sequenceflow-end') {
13586 var sequenceflowEnd = create('path');
13587 attr$1(sequenceflowEnd, { d: 'M 1 5 L 11 10 L 1 15 Z' });
13588
13589 addMarker(id, {
13590 element: sequenceflowEnd,
13591 ref: { x: 11, y: 10 },
13592 scale: 0.5,
13593 attrs: {
13594 fill: stroke,
13595 stroke: stroke
13596 }
13597 });
13598 }
13599
13600 if (type === 'messageflow-start') {
13601 var messageflowStart = create('circle');
13602 attr$1(messageflowStart, { cx: 6, cy: 6, r: 3.5 });
13603
13604 addMarker(id, {
13605 element: messageflowStart,
13606 attrs: {
13607 fill: fill,
13608 stroke: stroke
13609 },
13610 ref: { x: 6, y: 6 }
13611 });
13612 }
13613
13614 if (type === 'messageflow-end') {
13615 var messageflowEnd = create('path');
13616 attr$1(messageflowEnd, { d: 'm 1 5 l 0 -3 l 7 3 l -7 3 z' });
13617
13618 addMarker(id, {
13619 element: messageflowEnd,
13620 attrs: {
13621 fill: fill,
13622 stroke: stroke,
13623 strokeLinecap: 'butt'
13624 },
13625 ref: { x: 8.5, y: 5 }
13626 });
13627 }
13628
13629 if (type === 'association-start') {
13630 var associationStart = create('path');
13631 attr$1(associationStart, { d: 'M 11 5 L 1 10 L 11 15' });
13632
13633 addMarker(id, {
13634 element: associationStart,
13635 attrs: {
13636 fill: 'none',
13637 stroke: stroke,
13638 strokeWidth: 1.5
13639 },
13640 ref: { x: 1, y: 10 },
13641 scale: 0.5
13642 });
13643 }
13644
13645 if (type === 'association-end') {
13646 var associationEnd = create('path');
13647 attr$1(associationEnd, { d: 'M 1 5 L 11 10 L 1 15' });
13648
13649 addMarker(id, {
13650 element: associationEnd,
13651 attrs: {
13652 fill: 'none',
13653 stroke: stroke,
13654 strokeWidth: 1.5
13655 },
13656 ref: { x: 12, y: 10 },
13657 scale: 0.5
13658 });
13659 }
13660
13661 if (type === 'conditional-flow-marker') {
13662 var conditionalflowMarker = create('path');
13663 attr$1(conditionalflowMarker, { d: 'M 0 10 L 8 6 L 16 10 L 8 14 Z' });
13664
13665 addMarker(id, {
13666 element: conditionalflowMarker,
13667 attrs: {
13668 fill: fill,
13669 stroke: stroke
13670 },
13671 ref: { x: -1, y: 10 },
13672 scale: 0.5
13673 });
13674 }
13675
13676 if (type === 'conditional-default-flow-marker') {
13677 var conditionaldefaultflowMarker = create('path');
13678 attr$1(conditionaldefaultflowMarker, { d: 'M 6 4 L 10 16' });
13679
13680 addMarker(id, {
13681 element: conditionaldefaultflowMarker,
13682 attrs: {
13683 stroke: stroke
13684 },
13685 ref: { x: 0, y: 10 },
13686 scale: 0.5
13687 });
13688 }
13689 }
13690
13691 function drawCircle(parentGfx, width, height, offset, attrs) {
13692
13693 if (isObject(offset)) {
13694 attrs = offset;
13695 offset = 0;
13696 }
13697
13698 offset = offset || 0;
13699
13700 attrs = computeStyle(attrs, {
13701 stroke: 'black',
13702 strokeWidth: 2,
13703 fill: 'white'
13704 });
13705
13706 if (attrs.fill === 'none') {
13707 delete attrs.fillOpacity;
13708 }
13709
13710 var cx = width / 2,
13711 cy = height / 2;
13712
13713 var circle = create('circle');
13714 attr$1(circle, {
13715 cx: cx,
13716 cy: cy,
13717 r: Math.round((width + height) / 4 - offset)
13718 });
13719 attr$1(circle, attrs);
13720
13721 append(parentGfx, circle);
13722
13723 return circle;
13724 }
13725
13726 function drawRect(parentGfx, width, height, r, offset, attrs) {
13727
13728 if (isObject(offset)) {
13729 attrs = offset;
13730 offset = 0;
13731 }
13732
13733 offset = offset || 0;
13734
13735 attrs = computeStyle(attrs, {
13736 stroke: 'black',
13737 strokeWidth: 2,
13738 fill: 'white'
13739 });
13740
13741 var rect = create('rect');
13742 attr$1(rect, {
13743 x: offset,
13744 y: offset,
13745 width: width - offset * 2,
13746 height: height - offset * 2,
13747 rx: r,
13748 ry: r
13749 });
13750 attr$1(rect, attrs);
13751
13752 append(parentGfx, rect);
13753
13754 return rect;
13755 }
13756
13757 function drawDiamond(parentGfx, width, height, attrs) {
13758
13759 var x_2 = width / 2;
13760 var y_2 = height / 2;
13761
13762 var points = [{ x: x_2, y: 0 }, { x: width, y: y_2 }, { x: x_2, y: height }, { x: 0, y: y_2 }];
13763
13764 var pointsString = points.map(function(point) {
13765 return point.x + ',' + point.y;
13766 }).join(' ');
13767
13768 attrs = computeStyle(attrs, {
13769 stroke: 'black',
13770 strokeWidth: 2,
13771 fill: 'white'
13772 });
13773
13774 var polygon = create('polygon');
13775 attr$1(polygon, {
13776 points: pointsString
13777 });
13778 attr$1(polygon, attrs);
13779
13780 append(parentGfx, polygon);
13781
13782 return polygon;
13783 }
13784
13785 function drawLine(parentGfx, waypoints, attrs) {
13786 attrs = computeStyle(attrs, [ 'no-fill' ], {
13787 stroke: 'black',
13788 strokeWidth: 2,
13789 fill: 'none'
13790 });
13791
13792 var line = createLine(waypoints, attrs);
13793
13794 append(parentGfx, line);
13795
13796 return line;
13797 }
13798
13799 function drawPath(parentGfx, d, attrs) {
13800
13801 attrs = computeStyle(attrs, [ 'no-fill' ], {
13802 strokeWidth: 2,
13803 stroke: 'black'
13804 });
13805
13806 var path = create('path');
13807 attr$1(path, { d: d });
13808 attr$1(path, attrs);
13809
13810 append(parentGfx, path);
13811
13812 return path;
13813 }
13814
13815 function drawMarker(type, parentGfx, path, attrs) {
13816 return drawPath(parentGfx, path, assign({ 'data-marker': type }, attrs));
13817 }
13818
13819 function as(type) {
13820 return function(parentGfx, element) {
13821 return handlers[type](parentGfx, element);
13822 };
13823 }
13824
13825 function renderer(type) {
13826 return handlers[type];
13827 }
13828
13829 function renderEventContent(element, parentGfx) {
13830
13831 var event = getSemantic(element);
13832 var isThrowing = isThrowEvent(event);
13833
13834 if (event.eventDefinitions && event.eventDefinitions.length>1) {
13835 if (event.parallelMultiple) {
13836 return renderer('bpmn:ParallelMultipleEventDefinition')(parentGfx, element, isThrowing);
13837 }
13838 else {
13839 return renderer('bpmn:MultipleEventDefinition')(parentGfx, element, isThrowing);
13840 }
13841 }
13842
13843 if (isTypedEvent(event, 'bpmn:MessageEventDefinition')) {
13844 return renderer('bpmn:MessageEventDefinition')(parentGfx, element, isThrowing);
13845 }
13846
13847 if (isTypedEvent(event, 'bpmn:TimerEventDefinition')) {
13848 return renderer('bpmn:TimerEventDefinition')(parentGfx, element, isThrowing);
13849 }
13850
13851 if (isTypedEvent(event, 'bpmn:ConditionalEventDefinition')) {
13852 return renderer('bpmn:ConditionalEventDefinition')(parentGfx, element);
13853 }
13854
13855 if (isTypedEvent(event, 'bpmn:SignalEventDefinition')) {
13856 return renderer('bpmn:SignalEventDefinition')(parentGfx, element, isThrowing);
13857 }
13858
13859 if (isTypedEvent(event, 'bpmn:EscalationEventDefinition')) {
13860 return renderer('bpmn:EscalationEventDefinition')(parentGfx, element, isThrowing);
13861 }
13862
13863 if (isTypedEvent(event, 'bpmn:LinkEventDefinition')) {
13864 return renderer('bpmn:LinkEventDefinition')(parentGfx, element, isThrowing);
13865 }
13866
13867 if (isTypedEvent(event, 'bpmn:ErrorEventDefinition')) {
13868 return renderer('bpmn:ErrorEventDefinition')(parentGfx, element, isThrowing);
13869 }
13870
13871 if (isTypedEvent(event, 'bpmn:CancelEventDefinition')) {
13872 return renderer('bpmn:CancelEventDefinition')(parentGfx, element, isThrowing);
13873 }
13874
13875 if (isTypedEvent(event, 'bpmn:CompensateEventDefinition')) {
13876 return renderer('bpmn:CompensateEventDefinition')(parentGfx, element, isThrowing);
13877 }
13878
13879 if (isTypedEvent(event, 'bpmn:TerminateEventDefinition')) {
13880 return renderer('bpmn:TerminateEventDefinition')(parentGfx, element, isThrowing);
13881 }
13882
13883 return null;
13884 }
13885
13886 function renderLabel(parentGfx, label, options) {
13887
13888 options = assign({
13889 size: {
13890 width: 100
13891 }
13892 }, options);
13893
13894 var text = textRenderer.createText(label || '', options);
13895
13896 classes$1(text).add('djs-label');
13897
13898 append(parentGfx, text);
13899
13900 return text;
13901 }
13902
13903 function renderEmbeddedLabel(parentGfx, element, align) {
13904 var semantic = getSemantic(element);
13905
13906 return renderLabel(parentGfx, semantic.name, {
13907 box: element,
13908 align: align,
13909 padding: 5,
13910 style: {
13911 fill: getStrokeColor(element, defaultStrokeColor)
13912 }
13913 });
13914 }
13915
13916 function renderExternalLabel(parentGfx, element) {
13917
13918 var box = {
13919 width: 90,
13920 height: 30,
13921 x: element.width / 2 + element.x,
13922 y: element.height / 2 + element.y
13923 };
13924
13925 return renderLabel(parentGfx, getLabel(element), {
13926 box: box,
13927 fitBox: true,
13928 style: assign(
13929 {},
13930 textRenderer.getExternalStyle(),
13931 {
13932 fill: getStrokeColor(element, defaultStrokeColor)
13933 }
13934 )
13935 });
13936 }
13937
13938 function renderLaneLabel(parentGfx, text, element) {
13939 var textBox = renderLabel(parentGfx, text, {
13940 box: {
13941 height: 30,
13942 width: element.height
13943 },
13944 align: 'center-middle',
13945 style: {
13946 fill: getStrokeColor(element, defaultStrokeColor)
13947 }
13948 });
13949
13950 var top = -1 * element.height;
13951
13952 transform$1(textBox, 0, -top, 270);
13953 }
13954
13955 function createPathFromConnection(connection) {
13956 var waypoints = connection.waypoints;
13957
13958 var pathData = 'm ' + waypoints[0].x + ',' + waypoints[0].y;
13959 for (var i = 1; i < waypoints.length; i++) {
13960 pathData += 'L' + waypoints[i].x + ',' + waypoints[i].y + ' ';
13961 }
13962 return pathData;
13963 }
13964
13965 var handlers = this.handlers = {
13966 'bpmn:Event': function(parentGfx, element, attrs) {
13967
13968 if (!('fillOpacity' in attrs)) {
13969 attrs.fillOpacity = DEFAULT_FILL_OPACITY;
13970 }
13971
13972 return drawCircle(parentGfx, element.width, element.height, attrs);
13973 },
13974 'bpmn:StartEvent': function(parentGfx, element) {
13975 var attrs = {
13976 fill: getFillColor(element, defaultFillColor),
13977 stroke: getStrokeColor(element, defaultStrokeColor)
13978 };
13979
13980 var semantic = getSemantic(element);
13981
13982 if (!semantic.isInterrupting) {
13983 attrs = {
13984 strokeDasharray: '6',
13985 strokeLinecap: 'round',
13986 fill: getFillColor(element, defaultFillColor),
13987 stroke: getStrokeColor(element, defaultStrokeColor)
13988 };
13989 }
13990
13991 var circle = renderer('bpmn:Event')(parentGfx, element, attrs);
13992
13993 renderEventContent(element, parentGfx);
13994
13995 return circle;
13996 },
13997 'bpmn:MessageEventDefinition': function(parentGfx, element, isThrowing) {
13998 var pathData = pathMap.getScaledPath('EVENT_MESSAGE', {
13999 xScaleFactor: 0.9,
14000 yScaleFactor: 0.9,
14001 containerWidth: element.width,
14002 containerHeight: element.height,
14003 position: {
14004 mx: 0.235,
14005 my: 0.315
14006 }
14007 });
14008
14009 var fill = isThrowing ? getStrokeColor(element, defaultStrokeColor) : getFillColor(element, defaultFillColor);
14010 var stroke = isThrowing ? getFillColor(element, defaultFillColor) : getStrokeColor(element, defaultStrokeColor);
14011
14012 var messagePath = drawPath(parentGfx, pathData, {
14013 strokeWidth: 1,
14014 fill: fill,
14015 stroke: stroke
14016 });
14017
14018 return messagePath;
14019 },
14020 'bpmn:TimerEventDefinition': function(parentGfx, element) {
14021 var circle = drawCircle(parentGfx, element.width, element.height, 0.2 * element.height, {
14022 strokeWidth: 2,
14023 fill: getFillColor(element, defaultFillColor),
14024 stroke: getStrokeColor(element, defaultStrokeColor)
14025 });
14026
14027 var pathData = pathMap.getScaledPath('EVENT_TIMER_WH', {
14028 xScaleFactor: 0.75,
14029 yScaleFactor: 0.75,
14030 containerWidth: element.width,
14031 containerHeight: element.height,
14032 position: {
14033 mx: 0.5,
14034 my: 0.5
14035 }
14036 });
14037
14038 drawPath(parentGfx, pathData, {
14039 strokeWidth: 2,
14040 strokeLinecap: 'square',
14041 stroke: getStrokeColor(element, defaultStrokeColor)
14042 });
14043
14044 for (var i = 0;i < 12; i++) {
14045
14046 var linePathData = pathMap.getScaledPath('EVENT_TIMER_LINE', {
14047 xScaleFactor: 0.75,
14048 yScaleFactor: 0.75,
14049 containerWidth: element.width,
14050 containerHeight: element.height,
14051 position: {
14052 mx: 0.5,
14053 my: 0.5
14054 }
14055 });
14056
14057 var width = element.width / 2;
14058 var height = element.height / 2;
14059
14060 drawPath(parentGfx, linePathData, {
14061 strokeWidth: 1,
14062 strokeLinecap: 'square',
14063 transform: 'rotate(' + (i * 30) + ',' + height + ',' + width + ')',
14064 stroke: getStrokeColor(element, defaultStrokeColor)
14065 });
14066 }
14067
14068 return circle;
14069 },
14070 'bpmn:EscalationEventDefinition': function(parentGfx, event, isThrowing) {
14071 var pathData = pathMap.getScaledPath('EVENT_ESCALATION', {
14072 xScaleFactor: 1,
14073 yScaleFactor: 1,
14074 containerWidth: event.width,
14075 containerHeight: event.height,
14076 position: {
14077 mx: 0.5,
14078 my: 0.2
14079 }
14080 });
14081
14082 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14083
14084 return drawPath(parentGfx, pathData, {
14085 strokeWidth: 1,
14086 fill: fill,
14087 stroke: getStrokeColor(event, defaultStrokeColor)
14088 });
14089 },
14090 'bpmn:ConditionalEventDefinition': function(parentGfx, event) {
14091 var pathData = pathMap.getScaledPath('EVENT_CONDITIONAL', {
14092 xScaleFactor: 1,
14093 yScaleFactor: 1,
14094 containerWidth: event.width,
14095 containerHeight: event.height,
14096 position: {
14097 mx: 0.5,
14098 my: 0.222
14099 }
14100 });
14101
14102 return drawPath(parentGfx, pathData, {
14103 strokeWidth: 1,
14104 stroke: getStrokeColor(event, defaultStrokeColor)
14105 });
14106 },
14107 'bpmn:LinkEventDefinition': function(parentGfx, event, isThrowing) {
14108 var pathData = pathMap.getScaledPath('EVENT_LINK', {
14109 xScaleFactor: 1,
14110 yScaleFactor: 1,
14111 containerWidth: event.width,
14112 containerHeight: event.height,
14113 position: {
14114 mx: 0.57,
14115 my: 0.263
14116 }
14117 });
14118
14119 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14120
14121 return drawPath(parentGfx, pathData, {
14122 strokeWidth: 1,
14123 fill: fill,
14124 stroke: getStrokeColor(event, defaultStrokeColor)
14125 });
14126 },
14127 'bpmn:ErrorEventDefinition': function(parentGfx, event, isThrowing) {
14128 var pathData = pathMap.getScaledPath('EVENT_ERROR', {
14129 xScaleFactor: 1.1,
14130 yScaleFactor: 1.1,
14131 containerWidth: event.width,
14132 containerHeight: event.height,
14133 position: {
14134 mx: 0.2,
14135 my: 0.722
14136 }
14137 });
14138
14139 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14140
14141 return drawPath(parentGfx, pathData, {
14142 strokeWidth: 1,
14143 fill: fill,
14144 stroke: getStrokeColor(event, defaultStrokeColor)
14145 });
14146 },
14147 'bpmn:CancelEventDefinition': function(parentGfx, event, isThrowing) {
14148 var pathData = pathMap.getScaledPath('EVENT_CANCEL_45', {
14149 xScaleFactor: 1.0,
14150 yScaleFactor: 1.0,
14151 containerWidth: event.width,
14152 containerHeight: event.height,
14153 position: {
14154 mx: 0.638,
14155 my: -0.055
14156 }
14157 });
14158
14159 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14160
14161 var path = drawPath(parentGfx, pathData, {
14162 strokeWidth: 1,
14163 fill: fill,
14164 stroke: getStrokeColor(event, defaultStrokeColor)
14165 });
14166
14167 rotate(path, 45);
14168
14169 return path;
14170 },
14171 'bpmn:CompensateEventDefinition': function(parentGfx, event, isThrowing) {
14172 var pathData = pathMap.getScaledPath('EVENT_COMPENSATION', {
14173 xScaleFactor: 1,
14174 yScaleFactor: 1,
14175 containerWidth: event.width,
14176 containerHeight: event.height,
14177 position: {
14178 mx: 0.22,
14179 my: 0.5
14180 }
14181 });
14182
14183 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14184
14185 return drawPath(parentGfx, pathData, {
14186 strokeWidth: 1,
14187 fill: fill,
14188 stroke: getStrokeColor(event, defaultStrokeColor)
14189 });
14190 },
14191 'bpmn:SignalEventDefinition': function(parentGfx, event, isThrowing) {
14192 var pathData = pathMap.getScaledPath('EVENT_SIGNAL', {
14193 xScaleFactor: 0.9,
14194 yScaleFactor: 0.9,
14195 containerWidth: event.width,
14196 containerHeight: event.height,
14197 position: {
14198 mx: 0.5,
14199 my: 0.2
14200 }
14201 });
14202
14203 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14204
14205 return drawPath(parentGfx, pathData, {
14206 strokeWidth: 1,
14207 fill: fill,
14208 stroke: getStrokeColor(event, defaultStrokeColor)
14209 });
14210 },
14211 'bpmn:MultipleEventDefinition': function(parentGfx, event, isThrowing) {
14212 var pathData = pathMap.getScaledPath('EVENT_MULTIPLE', {
14213 xScaleFactor: 1.1,
14214 yScaleFactor: 1.1,
14215 containerWidth: event.width,
14216 containerHeight: event.height,
14217 position: {
14218 mx: 0.222,
14219 my: 0.36
14220 }
14221 });
14222
14223 var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
14224
14225 return drawPath(parentGfx, pathData, {
14226 strokeWidth: 1,
14227 fill: fill
14228 });
14229 },
14230 'bpmn:ParallelMultipleEventDefinition': function(parentGfx, event) {
14231 var pathData = pathMap.getScaledPath('EVENT_PARALLEL_MULTIPLE', {
14232 xScaleFactor: 1.2,
14233 yScaleFactor: 1.2,
14234 containerWidth: event.width,
14235 containerHeight: event.height,
14236 position: {
14237 mx: 0.458,
14238 my: 0.194
14239 }
14240 });
14241
14242 return drawPath(parentGfx, pathData, {
14243 strokeWidth: 1,
14244 fill: getStrokeColor(event, defaultStrokeColor),
14245 stroke: getStrokeColor(event, defaultStrokeColor)
14246 });
14247 },
14248 'bpmn:EndEvent': function(parentGfx, element) {
14249 var circle = renderer('bpmn:Event')(parentGfx, element, {
14250 strokeWidth: 4,
14251 fill: getFillColor(element, defaultFillColor),
14252 stroke: getStrokeColor(element, defaultStrokeColor)
14253 });
14254
14255 renderEventContent(element, parentGfx);
14256
14257 return circle;
14258 },
14259 'bpmn:TerminateEventDefinition': function(parentGfx, element) {
14260 var circle = drawCircle(parentGfx, element.width, element.height, 8, {
14261 strokeWidth: 4,
14262 fill: getStrokeColor(element, defaultStrokeColor),
14263 stroke: getStrokeColor(element, defaultStrokeColor)
14264 });
14265
14266 return circle;
14267 },
14268 'bpmn:IntermediateEvent': function(parentGfx, element) {
14269 var outer = renderer('bpmn:Event')(parentGfx, element, {
14270 strokeWidth: 1,
14271 fill: getFillColor(element, defaultFillColor),
14272 stroke: getStrokeColor(element, defaultStrokeColor)
14273 });
14274
14275 /* inner */
14276 drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, {
14277 strokeWidth: 1,
14278 fill: getFillColor(element, 'none'),
14279 stroke: getStrokeColor(element, defaultStrokeColor)
14280 });
14281
14282 renderEventContent(element, parentGfx);
14283
14284 return outer;
14285 },
14286 'bpmn:IntermediateCatchEvent': as('bpmn:IntermediateEvent'),
14287 'bpmn:IntermediateThrowEvent': as('bpmn:IntermediateEvent'),
14288
14289 'bpmn:Activity': function(parentGfx, element, attrs) {
14290
14291 attrs = attrs || {};
14292
14293 if (!('fillOpacity' in attrs)) {
14294 attrs.fillOpacity = DEFAULT_FILL_OPACITY;
14295 }
14296
14297 return drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, attrs);
14298 },
14299
14300 'bpmn:Task': function(parentGfx, element) {
14301 var attrs = {
14302 fill: getFillColor(element, defaultFillColor),
14303 stroke: getStrokeColor(element, defaultStrokeColor)
14304 };
14305
14306 var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
14307
14308 renderEmbeddedLabel(parentGfx, element, 'center-middle');
14309 attachTaskMarkers(parentGfx, element);
14310
14311 return rect;
14312 },
14313 'bpmn:ServiceTask': function(parentGfx, element) {
14314 var task = renderer('bpmn:Task')(parentGfx, element);
14315
14316 var pathDataBG = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
14317 abspos: {
14318 x: 12,
14319 y: 18
14320 }
14321 });
14322
14323 /* service bg */ drawPath(parentGfx, pathDataBG, {
14324 strokeWidth: 1,
14325 fill: getFillColor(element, defaultFillColor),
14326 stroke: getStrokeColor(element, defaultStrokeColor)
14327 });
14328
14329 var fillPathData = pathMap.getScaledPath('TASK_TYPE_SERVICE_FILL', {
14330 abspos: {
14331 x: 17.2,
14332 y: 18
14333 }
14334 });
14335
14336 /* service fill */ drawPath(parentGfx, fillPathData, {
14337 strokeWidth: 0,
14338 fill: getFillColor(element, defaultFillColor)
14339 });
14340
14341 var pathData = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
14342 abspos: {
14343 x: 17,
14344 y: 22
14345 }
14346 });
14347
14348 /* service */ drawPath(parentGfx, pathData, {
14349 strokeWidth: 1,
14350 fill: getFillColor(element, defaultFillColor),
14351 stroke: getStrokeColor(element, defaultStrokeColor)
14352 });
14353
14354 return task;
14355 },
14356 'bpmn:UserTask': function(parentGfx, element) {
14357 var task = renderer('bpmn:Task')(parentGfx, element);
14358
14359 var x = 15;
14360 var y = 12;
14361
14362 var pathData = pathMap.getScaledPath('TASK_TYPE_USER_1', {
14363 abspos: {
14364 x: x,
14365 y: y
14366 }
14367 });
14368
14369 /* user path */ drawPath(parentGfx, pathData, {
14370 strokeWidth: 0.5,
14371 fill: getFillColor(element, defaultFillColor),
14372 stroke: getStrokeColor(element, defaultStrokeColor)
14373 });
14374
14375 var pathData2 = pathMap.getScaledPath('TASK_TYPE_USER_2', {
14376 abspos: {
14377 x: x,
14378 y: y
14379 }
14380 });
14381
14382 /* user2 path */ drawPath(parentGfx, pathData2, {
14383 strokeWidth: 0.5,
14384 fill: getFillColor(element, defaultFillColor),
14385 stroke: getStrokeColor(element, defaultStrokeColor)
14386 });
14387
14388 var pathData3 = pathMap.getScaledPath('TASK_TYPE_USER_3', {
14389 abspos: {
14390 x: x,
14391 y: y
14392 }
14393 });
14394
14395 /* user3 path */ drawPath(parentGfx, pathData3, {
14396 strokeWidth: 0.5,
14397 fill: getStrokeColor(element, defaultStrokeColor),
14398 stroke: getStrokeColor(element, defaultStrokeColor)
14399 });
14400
14401 return task;
14402 },
14403 'bpmn:ManualTask': function(parentGfx, element) {
14404 var task = renderer('bpmn:Task')(parentGfx, element);
14405
14406 var pathData = pathMap.getScaledPath('TASK_TYPE_MANUAL', {
14407 abspos: {
14408 x: 17,
14409 y: 15
14410 }
14411 });
14412
14413 /* manual path */ drawPath(parentGfx, pathData, {
14414 strokeWidth: 0.5, // 0.25,
14415 fill: getFillColor(element, defaultFillColor),
14416 stroke: getStrokeColor(element, defaultStrokeColor)
14417 });
14418
14419 return task;
14420 },
14421 'bpmn:SendTask': function(parentGfx, element) {
14422 var task = renderer('bpmn:Task')(parentGfx, element);
14423
14424 var pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
14425 xScaleFactor: 1,
14426 yScaleFactor: 1,
14427 containerWidth: 21,
14428 containerHeight: 14,
14429 position: {
14430 mx: 0.285,
14431 my: 0.357
14432 }
14433 });
14434
14435 /* send path */ drawPath(parentGfx, pathData, {
14436 strokeWidth: 1,
14437 fill: getStrokeColor(element, defaultStrokeColor),
14438 stroke: getFillColor(element, defaultFillColor)
14439 });
14440
14441 return task;
14442 },
14443 'bpmn:ReceiveTask' : function(parentGfx, element) {
14444 var semantic = getSemantic(element);
14445
14446 var task = renderer('bpmn:Task')(parentGfx, element);
14447 var pathData;
14448
14449 if (semantic.instantiate) {
14450 drawCircle(parentGfx, 28, 28, 20 * 0.22, { strokeWidth: 1 });
14451
14452 pathData = pathMap.getScaledPath('TASK_TYPE_INSTANTIATING_SEND', {
14453 abspos: {
14454 x: 7.77,
14455 y: 9.52
14456 }
14457 });
14458 } else {
14459
14460 pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
14461 xScaleFactor: 0.9,
14462 yScaleFactor: 0.9,
14463 containerWidth: 21,
14464 containerHeight: 14,
14465 position: {
14466 mx: 0.3,
14467 my: 0.4
14468 }
14469 });
14470 }
14471
14472 /* receive path */ drawPath(parentGfx, pathData, {
14473 strokeWidth: 1,
14474 fill: getFillColor(element, defaultFillColor),
14475 stroke: getStrokeColor(element, defaultStrokeColor)
14476 });
14477
14478 return task;
14479 },
14480 'bpmn:ScriptTask': function(parentGfx, element) {
14481 var task = renderer('bpmn:Task')(parentGfx, element);
14482
14483 var pathData = pathMap.getScaledPath('TASK_TYPE_SCRIPT', {
14484 abspos: {
14485 x: 15,
14486 y: 20
14487 }
14488 });
14489
14490 /* script path */ drawPath(parentGfx, pathData, {
14491 strokeWidth: 1,
14492 stroke: getStrokeColor(element, defaultStrokeColor)
14493 });
14494
14495 return task;
14496 },
14497 'bpmn:BusinessRuleTask': function(parentGfx, element) {
14498 var task = renderer('bpmn:Task')(parentGfx, element);
14499
14500 var headerPathData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_HEADER', {
14501 abspos: {
14502 x: 8,
14503 y: 8
14504 }
14505 });
14506
14507 var businessHeaderPath = drawPath(parentGfx, headerPathData);
14508 attr$1(businessHeaderPath, {
14509 strokeWidth: 1,
14510 fill: getFillColor(element, '#aaaaaa'),
14511 stroke: getStrokeColor(element, defaultStrokeColor)
14512 });
14513
14514 var headerData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_MAIN', {
14515 abspos: {
14516 x: 8,
14517 y: 8
14518 }
14519 });
14520
14521 var businessPath = drawPath(parentGfx, headerData);
14522 attr$1(businessPath, {
14523 strokeWidth: 1,
14524 stroke: getStrokeColor(element, defaultStrokeColor)
14525 });
14526
14527 return task;
14528 },
14529 'bpmn:SubProcess': function(parentGfx, element, attrs) {
14530 attrs = assign({
14531 fill: getFillColor(element, defaultFillColor),
14532 stroke: getStrokeColor(element, defaultStrokeColor)
14533 }, attrs);
14534
14535 var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
14536
14537 var expanded = isExpanded(element);
14538
14539 if (isEventSubProcess(element)) {
14540 attr$1(rect, {
14541 strokeDasharray: '1,2'
14542 });
14543 }
14544
14545 renderEmbeddedLabel(parentGfx, element, expanded ? 'center-top' : 'center-middle');
14546
14547 if (expanded) {
14548 attachTaskMarkers(parentGfx, element);
14549 } else {
14550 attachTaskMarkers(parentGfx, element, ['SubProcessMarker']);
14551 }
14552
14553 return rect;
14554 },
14555 'bpmn:AdHocSubProcess': function(parentGfx, element) {
14556 return renderer('bpmn:SubProcess')(parentGfx, element);
14557 },
14558 'bpmn:Transaction': function(parentGfx, element) {
14559 var outer = renderer('bpmn:SubProcess')(parentGfx, element);
14560
14561 var innerAttrs = styles.style([ 'no-fill', 'no-events' ], {
14562 stroke: getStrokeColor(element, defaultStrokeColor)
14563 });
14564
14565 /* inner path */ drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS - 2, INNER_OUTER_DIST, innerAttrs);
14566
14567 return outer;
14568 },
14569 'bpmn:CallActivity': function(parentGfx, element) {
14570 return renderer('bpmn:SubProcess')(parentGfx, element, {
14571 strokeWidth: 5
14572 });
14573 },
14574 'bpmn:Participant': function(parentGfx, element) {
14575
14576 var attrs = {
14577 fillOpacity: DEFAULT_FILL_OPACITY,
14578 fill: getFillColor(element, defaultFillColor),
14579 stroke: getStrokeColor(element, defaultStrokeColor)
14580 };
14581
14582 var lane = renderer('bpmn:Lane')(parentGfx, element, attrs);
14583
14584 var expandedPool = isExpanded(element);
14585
14586 if (expandedPool) {
14587 drawLine(parentGfx, [
14588 { x: 30, y: 0 },
14589 { x: 30, y: element.height }
14590 ], {
14591 stroke: getStrokeColor(element, defaultStrokeColor)
14592 });
14593 var text = getSemantic(element).name;
14594 renderLaneLabel(parentGfx, text, element);
14595 } else {
14596
14597 // Collapsed pool draw text inline
14598 var text2 = getSemantic(element).name;
14599 renderLabel(parentGfx, text2, {
14600 box: element, align: 'center-middle',
14601 style: {
14602 fill: getStrokeColor(element, defaultStrokeColor)
14603 }
14604 });
14605 }
14606
14607 var participantMultiplicity = !!(getSemantic(element).participantMultiplicity);
14608
14609 if (participantMultiplicity) {
14610 renderer('ParticipantMultiplicityMarker')(parentGfx, element);
14611 }
14612
14613 return lane;
14614 },
14615 'bpmn:Lane': function(parentGfx, element, attrs) {
14616 var rect = drawRect(parentGfx, element.width, element.height, 0, assign({
14617 fill: getFillColor(element, defaultFillColor),
14618 fillOpacity: HIGH_FILL_OPACITY,
14619 stroke: getStrokeColor(element, defaultStrokeColor)
14620 }, attrs));
14621
14622 var semantic = getSemantic(element);
14623
14624 if (semantic.$type === 'bpmn:Lane') {
14625 var text = semantic.name;
14626 renderLaneLabel(parentGfx, text, element);
14627 }
14628
14629 return rect;
14630 },
14631 'bpmn:InclusiveGateway': function(parentGfx, element) {
14632 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14633
14634 /* circle path */
14635 drawCircle(parentGfx, element.width, element.height, element.height * 0.24, {
14636 strokeWidth: 2.5,
14637 fill: getFillColor(element, defaultFillColor),
14638 stroke: getStrokeColor(element, defaultStrokeColor)
14639 });
14640
14641 return diamond;
14642 },
14643 'bpmn:ExclusiveGateway': function(parentGfx, element) {
14644 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14645
14646 var pathData = pathMap.getScaledPath('GATEWAY_EXCLUSIVE', {
14647 xScaleFactor: 0.4,
14648 yScaleFactor: 0.4,
14649 containerWidth: element.width,
14650 containerHeight: element.height,
14651 position: {
14652 mx: 0.32,
14653 my: 0.3
14654 }
14655 });
14656
14657 if ((getDi(element).isMarkerVisible)) {
14658 drawPath(parentGfx, pathData, {
14659 strokeWidth: 1,
14660 fill: getStrokeColor(element, defaultStrokeColor),
14661 stroke: getStrokeColor(element, defaultStrokeColor)
14662 });
14663 }
14664
14665 return diamond;
14666 },
14667 'bpmn:ComplexGateway': function(parentGfx, element) {
14668 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14669
14670 var pathData = pathMap.getScaledPath('GATEWAY_COMPLEX', {
14671 xScaleFactor: 0.5,
14672 yScaleFactor:0.5,
14673 containerWidth: element.width,
14674 containerHeight: element.height,
14675 position: {
14676 mx: 0.46,
14677 my: 0.26
14678 }
14679 });
14680
14681 /* complex path */ drawPath(parentGfx, pathData, {
14682 strokeWidth: 1,
14683 fill: getStrokeColor(element, defaultStrokeColor),
14684 stroke: getStrokeColor(element, defaultStrokeColor)
14685 });
14686
14687 return diamond;
14688 },
14689 'bpmn:ParallelGateway': function(parentGfx, element) {
14690 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14691
14692 var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
14693 xScaleFactor: 0.6,
14694 yScaleFactor:0.6,
14695 containerWidth: element.width,
14696 containerHeight: element.height,
14697 position: {
14698 mx: 0.46,
14699 my: 0.2
14700 }
14701 });
14702
14703 /* parallel path */ drawPath(parentGfx, pathData, {
14704 strokeWidth: 1,
14705 fill: getStrokeColor(element, defaultStrokeColor),
14706 stroke: getStrokeColor(element, defaultStrokeColor)
14707 });
14708
14709 return diamond;
14710 },
14711 'bpmn:EventBasedGateway': function(parentGfx, element) {
14712
14713 var semantic = getSemantic(element);
14714
14715 var diamond = renderer('bpmn:Gateway')(parentGfx, element);
14716
14717 /* outer circle path */ drawCircle(parentGfx, element.width, element.height, element.height * 0.20, {
14718 strokeWidth: 1,
14719 fill: 'none',
14720 stroke: getStrokeColor(element, defaultStrokeColor)
14721 });
14722
14723 var type = semantic.eventGatewayType;
14724 var instantiate = !!semantic.instantiate;
14725
14726 function drawEvent() {
14727
14728 var pathData = pathMap.getScaledPath('GATEWAY_EVENT_BASED', {
14729 xScaleFactor: 0.18,
14730 yScaleFactor: 0.18,
14731 containerWidth: element.width,
14732 containerHeight: element.height,
14733 position: {
14734 mx: 0.36,
14735 my: 0.44
14736 }
14737 });
14738
14739 var attrs = {
14740 strokeWidth: 2,
14741 fill: getFillColor(element, 'none'),
14742 stroke: getStrokeColor(element, defaultStrokeColor)
14743 };
14744
14745 /* event path */ drawPath(parentGfx, pathData, attrs);
14746 }
14747
14748 if (type === 'Parallel') {
14749
14750 var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
14751 xScaleFactor: 0.4,
14752 yScaleFactor:0.4,
14753 containerWidth: element.width,
14754 containerHeight: element.height,
14755 position: {
14756 mx: 0.474,
14757 my: 0.296
14758 }
14759 });
14760
14761 var parallelPath = drawPath(parentGfx, pathData);
14762 attr$1(parallelPath, {
14763 strokeWidth: 1,
14764 fill: 'none'
14765 });
14766 } else if (type === 'Exclusive') {
14767
14768 if (!instantiate) {
14769 var innerCircle = drawCircle(parentGfx, element.width, element.height, element.height * 0.26);
14770 attr$1(innerCircle, {
14771 strokeWidth: 1,
14772 fill: 'none',
14773 stroke: getStrokeColor(element, defaultStrokeColor)
14774 });
14775 }
14776
14777 drawEvent();
14778 }
14779
14780
14781 return diamond;
14782 },
14783 'bpmn:Gateway': function(parentGfx, element) {
14784 var attrs = {
14785 fill: getFillColor(element, defaultFillColor),
14786 fillOpacity: DEFAULT_FILL_OPACITY,
14787 stroke: getStrokeColor(element, defaultStrokeColor)
14788 };
14789
14790 return drawDiamond(parentGfx, element.width, element.height, attrs);
14791 },
14792 'bpmn:SequenceFlow': function(parentGfx, element) {
14793 var pathData = createPathFromConnection(element);
14794
14795 var fill = getFillColor(element, defaultFillColor),
14796 stroke = getStrokeColor(element, defaultStrokeColor);
14797
14798 var attrs = {
14799 strokeLinejoin: 'round',
14800 markerEnd: marker('sequenceflow-end', fill, stroke),
14801 stroke: getStrokeColor(element, defaultStrokeColor)
14802 };
14803
14804 var path = drawPath(parentGfx, pathData, attrs);
14805
14806 var sequenceFlow = getSemantic(element);
14807
14808 var source;
14809
14810 if (element.source) {
14811 source = element.source.businessObject;
14812
14813 // conditional flow marker
14814 if (sequenceFlow.conditionExpression && source.$instanceOf('bpmn:Activity')) {
14815 attr$1(path, {
14816 markerStart: marker('conditional-flow-marker', fill, stroke)
14817 });
14818 }
14819
14820 // default marker
14821 if (source.default && (source.$instanceOf('bpmn:Gateway') || source.$instanceOf('bpmn:Activity')) &&
14822 source.default === sequenceFlow) {
14823 attr$1(path, {
14824 markerStart: marker('conditional-default-flow-marker', fill, stroke)
14825 });
14826 }
14827 }
14828
14829 return path;
14830 },
14831 'bpmn:Association': function(parentGfx, element, attrs) {
14832
14833 var semantic = getSemantic(element);
14834
14835 var fill = getFillColor(element, defaultFillColor),
14836 stroke = getStrokeColor(element, defaultStrokeColor);
14837
14838 attrs = assign({
14839 strokeDasharray: '0.5, 5',
14840 strokeLinecap: 'round',
14841 strokeLinejoin: 'round',
14842 stroke: getStrokeColor(element, defaultStrokeColor)
14843 }, attrs || {});
14844
14845 if (semantic.associationDirection === 'One' ||
14846 semantic.associationDirection === 'Both') {
14847 attrs.markerEnd = marker('association-end', fill, stroke);
14848 }
14849
14850 if (semantic.associationDirection === 'Both') {
14851 attrs.markerStart = marker('association-start', fill, stroke);
14852 }
14853
14854 return drawLine(parentGfx, element.waypoints, attrs);
14855 },
14856 'bpmn:DataInputAssociation': function(parentGfx, element) {
14857 var fill = getFillColor(element, defaultFillColor),
14858 stroke = getStrokeColor(element, defaultStrokeColor);
14859
14860 return renderer('bpmn:Association')(parentGfx, element, {
14861 markerEnd: marker('association-end', fill, stroke)
14862 });
14863 },
14864 'bpmn:DataOutputAssociation': function(parentGfx, element) {
14865 var fill = getFillColor(element, defaultFillColor),
14866 stroke = getStrokeColor(element, defaultStrokeColor);
14867
14868 return renderer('bpmn:Association')(parentGfx, element, {
14869 markerEnd: marker('association-end', fill, stroke)
14870 });
14871 },
14872 'bpmn:MessageFlow': function(parentGfx, element) {
14873
14874 var semantic = getSemantic(element),
14875 di = getDi(element);
14876
14877 var fill = getFillColor(element, defaultFillColor),
14878 stroke = getStrokeColor(element, defaultStrokeColor);
14879
14880 var pathData = createPathFromConnection(element);
14881
14882 var attrs = {
14883 markerEnd: marker('messageflow-end', fill, stroke),
14884 markerStart: marker('messageflow-start', fill, stroke),
14885 strokeDasharray: '10, 12',
14886 strokeLinecap: 'round',
14887 strokeLinejoin: 'round',
14888 strokeWidth: '1.5px',
14889 stroke: getStrokeColor(element, defaultStrokeColor)
14890 };
14891
14892 var path = drawPath(parentGfx, pathData, attrs);
14893
14894 if (semantic.messageRef) {
14895 var midPoint = path.getPointAtLength(path.getTotalLength() / 2);
14896
14897 var markerPathData = pathMap.getScaledPath('MESSAGE_FLOW_MARKER', {
14898 abspos: {
14899 x: midPoint.x,
14900 y: midPoint.y
14901 }
14902 });
14903
14904 var messageAttrs = { strokeWidth: 1 };
14905
14906 if (di.messageVisibleKind === 'initiating') {
14907 messageAttrs.fill = 'white';
14908 messageAttrs.stroke = 'black';
14909 } else {
14910 messageAttrs.fill = '#888';
14911 messageAttrs.stroke = 'white';
14912 }
14913
14914 drawPath(parentGfx, markerPathData, messageAttrs);
14915 }
14916
14917 return path;
14918 },
14919 'bpmn:DataObject': function(parentGfx, element) {
14920 var pathData = pathMap.getScaledPath('DATA_OBJECT_PATH', {
14921 xScaleFactor: 1,
14922 yScaleFactor: 1,
14923 containerWidth: element.width,
14924 containerHeight: element.height,
14925 position: {
14926 mx: 0.474,
14927 my: 0.296
14928 }
14929 });
14930
14931 var elementObject = drawPath(parentGfx, pathData, {
14932 fill: getFillColor(element, defaultFillColor),
14933 fillOpacity: DEFAULT_FILL_OPACITY,
14934 stroke: getStrokeColor(element, defaultStrokeColor)
14935 });
14936
14937 var semantic = getSemantic(element);
14938
14939 if (isCollection(semantic)) {
14940 renderDataItemCollection(parentGfx, element);
14941 }
14942
14943 return elementObject;
14944 },
14945 'bpmn:DataObjectReference': as('bpmn:DataObject'),
14946 'bpmn:DataInput': function(parentGfx, element) {
14947
14948 var arrowPathData = pathMap.getRawPath('DATA_ARROW');
14949
14950 // page
14951 var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
14952
14953 /* input arrow path */ drawPath(parentGfx, arrowPathData, { strokeWidth: 1 });
14954
14955 return elementObject;
14956 },
14957 'bpmn:DataOutput': function(parentGfx, element) {
14958 var arrowPathData = pathMap.getRawPath('DATA_ARROW');
14959
14960 // page
14961 var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
14962
14963 /* output arrow path */ drawPath(parentGfx, arrowPathData, {
14964 strokeWidth: 1,
14965 fill: 'black'
14966 });
14967
14968 return elementObject;
14969 },
14970 'bpmn:DataStoreReference': function(parentGfx, element) {
14971 var DATA_STORE_PATH = pathMap.getScaledPath('DATA_STORE', {
14972 xScaleFactor: 1,
14973 yScaleFactor: 1,
14974 containerWidth: element.width,
14975 containerHeight: element.height,
14976 position: {
14977 mx: 0,
14978 my: 0.133
14979 }
14980 });
14981
14982 var elementStore = drawPath(parentGfx, DATA_STORE_PATH, {
14983 strokeWidth: 2,
14984 fill: getFillColor(element, defaultFillColor),
14985 fillOpacity: DEFAULT_FILL_OPACITY,
14986 stroke: getStrokeColor(element, defaultStrokeColor)
14987 });
14988
14989 return elementStore;
14990 },
14991 'bpmn:BoundaryEvent': function(parentGfx, element) {
14992
14993 var semantic = getSemantic(element),
14994 cancel = semantic.cancelActivity;
14995
14996 var attrs = {
14997 strokeWidth: 1,
14998 fill: getFillColor(element, defaultFillColor),
14999 stroke: getStrokeColor(element, defaultStrokeColor)
15000 };
15001
15002 if (!cancel) {
15003 attrs.strokeDasharray = '6';
15004 attrs.strokeLinecap = 'round';
15005 }
15006
15007 // apply fillOpacity
15008 var outerAttrs = assign({}, attrs, {
15009 fillOpacity: 1
15010 });
15011
15012 // apply no-fill
15013 var innerAttrs = assign({}, attrs, {
15014 fill: 'none'
15015 });
15016
15017 var outer = renderer('bpmn:Event')(parentGfx, element, outerAttrs);
15018
15019 /* inner path */ drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, innerAttrs);
15020
15021 renderEventContent(element, parentGfx);
15022
15023 return outer;
15024 },
15025 'bpmn:Group': function(parentGfx, element) {
15026
15027 var group = drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, {
15028 strokeWidth: 1,
15029 strokeDasharray: '8,3,1,3',
15030 fill: 'none',
15031 pointerEvents: 'none'
15032 });
15033
15034 return group;
15035 },
15036 'label': function(parentGfx, element) {
15037 return renderExternalLabel(parentGfx, element);
15038 },
15039 'bpmn:TextAnnotation': function(parentGfx, element) {
15040 var style = {
15041 'fill': 'none',
15042 'stroke': 'none'
15043 };
15044
15045 var textElement = drawRect(parentGfx, element.width, element.height, 0, 0, style);
15046
15047 var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', {
15048 xScaleFactor: 1,
15049 yScaleFactor: 1,
15050 containerWidth: element.width,
15051 containerHeight: element.height,
15052 position: {
15053 mx: 0.0,
15054 my: 0.0
15055 }
15056 });
15057
15058 drawPath(parentGfx, textPathData, {
15059 stroke: getStrokeColor(element, defaultStrokeColor)
15060 });
15061
15062 var text = getSemantic(element).text || '';
15063 renderLabel(parentGfx, text, {
15064 box: element,
15065 align: 'left-top',
15066 padding: 5,
15067 style: {
15068 fill: getStrokeColor(element, defaultStrokeColor)
15069 }
15070 });
15071
15072 return textElement;
15073 },
15074 'ParticipantMultiplicityMarker': function(parentGfx, element) {
15075 var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
15076 xScaleFactor: 1,
15077 yScaleFactor: 1,
15078 containerWidth: element.width,
15079 containerHeight: element.height,
15080 position: {
15081 mx: ((element.width / 2) / element.width),
15082 my: (element.height - 15) / element.height
15083 }
15084 });
15085
15086 drawMarker('participant-multiplicity', parentGfx, markerPath, {
15087 strokeWidth: 1,
15088 fill: getFillColor(element, defaultFillColor),
15089 stroke: getStrokeColor(element, defaultStrokeColor)
15090 });
15091 },
15092 'SubProcessMarker': function(parentGfx, element) {
15093 var markerRect = drawRect(parentGfx, 14, 14, 0, {
15094 strokeWidth: 1,
15095 fill: getFillColor(element, defaultFillColor),
15096 stroke: getStrokeColor(element, defaultStrokeColor)
15097 });
15098
15099 // Process marker is placed in the middle of the box
15100 // therefore fixed values can be used here
15101 translate(markerRect, element.width / 2 - 7.5, element.height - 20);
15102
15103 var markerPath = pathMap.getScaledPath('MARKER_SUB_PROCESS', {
15104 xScaleFactor: 1.5,
15105 yScaleFactor: 1.5,
15106 containerWidth: element.width,
15107 containerHeight: element.height,
15108 position: {
15109 mx: (element.width / 2 - 7.5) / element.width,
15110 my: (element.height - 20) / element.height
15111 }
15112 });
15113
15114 drawMarker('sub-process', parentGfx, markerPath, {
15115 fill: getFillColor(element, defaultFillColor),
15116 stroke: getStrokeColor(element, defaultStrokeColor)
15117 });
15118 },
15119 'ParallelMarker': function(parentGfx, element, position) {
15120 var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
15121 xScaleFactor: 1,
15122 yScaleFactor: 1,
15123 containerWidth: element.width,
15124 containerHeight: element.height,
15125 position: {
15126 mx: ((element.width / 2 + position.parallel) / element.width),
15127 my: (element.height - 20) / element.height
15128 }
15129 });
15130
15131 drawMarker('parallel', parentGfx, markerPath, {
15132 fill: getFillColor(element, defaultFillColor),
15133 stroke: getStrokeColor(element, defaultStrokeColor)
15134 });
15135 },
15136 'SequentialMarker': function(parentGfx, element, position) {
15137 var markerPath = pathMap.getScaledPath('MARKER_SEQUENTIAL', {
15138 xScaleFactor: 1,
15139 yScaleFactor: 1,
15140 containerWidth: element.width,
15141 containerHeight: element.height,
15142 position: {
15143 mx: ((element.width / 2 + position.seq) / element.width),
15144 my: (element.height - 19) / element.height
15145 }
15146 });
15147
15148 drawMarker('sequential', parentGfx, markerPath, {
15149 fill: getFillColor(element, defaultFillColor),
15150 stroke: getStrokeColor(element, defaultStrokeColor)
15151 });
15152 },
15153 'CompensationMarker': function(parentGfx, element, position) {
15154 var markerMath = pathMap.getScaledPath('MARKER_COMPENSATION', {
15155 xScaleFactor: 1,
15156 yScaleFactor: 1,
15157 containerWidth: element.width,
15158 containerHeight: element.height,
15159 position: {
15160 mx: ((element.width / 2 + position.compensation) / element.width),
15161 my: (element.height - 13) / element.height
15162 }
15163 });
15164
15165 drawMarker('compensation', parentGfx, markerMath, {
15166 strokeWidth: 1,
15167 fill: getFillColor(element, defaultFillColor),
15168 stroke: getStrokeColor(element, defaultStrokeColor)
15169 });
15170 },
15171 'LoopMarker': function(parentGfx, element, position) {
15172 var markerPath = pathMap.getScaledPath('MARKER_LOOP', {
15173 xScaleFactor: 1,
15174 yScaleFactor: 1,
15175 containerWidth: element.width,
15176 containerHeight: element.height,
15177 position: {
15178 mx: ((element.width / 2 + position.loop) / element.width),
15179 my: (element.height - 7) / element.height
15180 }
15181 });
15182
15183 drawMarker('loop', parentGfx, markerPath, {
15184 strokeWidth: 1,
15185 fill: getFillColor(element, defaultFillColor),
15186 stroke: getStrokeColor(element, defaultStrokeColor),
15187 strokeLinecap: 'round',
15188 strokeMiterlimit: 0.5
15189 });
15190 },
15191 'AdhocMarker': function(parentGfx, element, position) {
15192 var markerPath = pathMap.getScaledPath('MARKER_ADHOC', {
15193 xScaleFactor: 1,
15194 yScaleFactor: 1,
15195 containerWidth: element.width,
15196 containerHeight: element.height,
15197 position: {
15198 mx: ((element.width / 2 + position.adhoc) / element.width),
15199 my: (element.height - 15) / element.height
15200 }
15201 });
15202
15203 drawMarker('adhoc', parentGfx, markerPath, {
15204 strokeWidth: 1,
15205 fill: getStrokeColor(element, defaultStrokeColor),
15206 stroke: getStrokeColor(element, defaultStrokeColor)
15207 });
15208 }
15209 };
15210
15211 function attachTaskMarkers(parentGfx, element, taskMarkers) {
15212 var obj = getSemantic(element);
15213
15214 var subprocess = taskMarkers && taskMarkers.indexOf('SubProcessMarker') !== -1;
15215 var position;
15216
15217 if (subprocess) {
15218 position = {
15219 seq: -21,
15220 parallel: -22,
15221 compensation: -42,
15222 loop: -18,
15223 adhoc: 10
15224 };
15225 } else {
15226 position = {
15227 seq: -3,
15228 parallel: -6,
15229 compensation: -27,
15230 loop: 0,
15231 adhoc: 10
15232 };
15233 }
15234
15235 forEach(taskMarkers, function(marker) {
15236 renderer(marker)(parentGfx, element, position);
15237 });
15238
15239 if (obj.isForCompensation) {
15240 renderer('CompensationMarker')(parentGfx, element, position);
15241 }
15242
15243 if (obj.$type === 'bpmn:AdHocSubProcess') {
15244 renderer('AdhocMarker')(parentGfx, element, position);
15245 }
15246
15247 var loopCharacteristics = obj.loopCharacteristics,
15248 isSequential = loopCharacteristics && loopCharacteristics.isSequential;
15249
15250 if (loopCharacteristics) {
15251
15252 if (isSequential === undefined) {
15253 renderer('LoopMarker')(parentGfx, element, position);
15254 }
15255
15256 if (isSequential === false) {
15257 renderer('ParallelMarker')(parentGfx, element, position);
15258 }
15259
15260 if (isSequential === true) {
15261 renderer('SequentialMarker')(parentGfx, element, position);
15262 }
15263 }
15264 }
15265
15266 function renderDataItemCollection(parentGfx, element) {
15267
15268 var yPosition = (element.height - 16) / element.height;
15269
15270 var pathData = pathMap.getScaledPath('DATA_OBJECT_COLLECTION_PATH', {
15271 xScaleFactor: 1,
15272 yScaleFactor: 1,
15273 containerWidth: element.width,
15274 containerHeight: element.height,
15275 position: {
15276 mx: 0.451,
15277 my: yPosition
15278 }
15279 });
15280
15281 /* collection path */ drawPath(parentGfx, pathData, {
15282 strokeWidth: 2
15283 });
15284 }
15285
15286
15287 // extension API, use at your own risk
15288 this._drawPath = drawPath;
15289
15290 }
15291
15292
15293 inherits_browser(BpmnRenderer, BaseRenderer);
15294
15295 BpmnRenderer.$inject = [
15296 'config.bpmnRenderer',
15297 'eventBus',
15298 'styles',
15299 'pathMap',
15300 'canvas',
15301 'textRenderer'
15302 ];
15303
15304
15305 BpmnRenderer.prototype.canRender = function(element) {
15306 return is$1(element, 'bpmn:BaseElement');
15307 };
15308
15309 BpmnRenderer.prototype.drawShape = function(parentGfx, element) {
15310 var type = element.type;
15311 var h = this.handlers[type];
15312
15313 /* jshint -W040 */
15314 return h(parentGfx, element);
15315 };
15316
15317 BpmnRenderer.prototype.drawConnection = function(parentGfx, element) {
15318 var type = element.type;
15319 var h = this.handlers[type];
15320
15321 /* jshint -W040 */
15322 return h(parentGfx, element);
15323 };
15324
15325 BpmnRenderer.prototype.getShapePath = function(element) {
15326
15327 if (is$1(element, 'bpmn:Event')) {
15328 return getCirclePath(element);
15329 }
15330
15331 if (is$1(element, 'bpmn:Activity')) {
15332 return getRoundRectPath(element, TASK_BORDER_RADIUS);
15333 }
15334
15335 if (is$1(element, 'bpmn:Gateway')) {
15336 return getDiamondPath(element);
15337 }
15338
15339 return getRectPath(element);
15340 };
15341
15342 var DEFAULT_BOX_PADDING = 0;
15343
15344 var DEFAULT_LABEL_SIZE = {
15345 width: 150,
15346 height: 50
15347 };
15348
15349
15350 function parseAlign(align) {
15351
15352 var parts = align.split('-');
15353
15354 return {
15355 horizontal: parts[0] || 'center',
15356 vertical: parts[1] || 'top'
15357 };
15358 }
15359
15360 function parsePadding(padding) {
15361
15362 if (isObject(padding)) {
15363 return assign({ top: 0, left: 0, right: 0, bottom: 0 }, padding);
15364 } else {
15365 return {
15366 top: padding,
15367 left: padding,
15368 right: padding,
15369 bottom: padding
15370 };
15371 }
15372 }
15373
15374 function getTextBBox(text, fakeText) {
15375
15376 fakeText.textContent = text;
15377
15378 var textBBox;
15379
15380 try {
15381 var bbox,
15382 emptyLine = text === '';
15383
15384 // add dummy text, when line is empty to
15385 // determine correct height
15386 fakeText.textContent = emptyLine ? 'dummy' : text;
15387
15388 textBBox = fakeText.getBBox();
15389
15390 // take text rendering related horizontal
15391 // padding into account
15392 bbox = {
15393 width: textBBox.width + textBBox.x * 2,
15394 height: textBBox.height
15395 };
15396
15397 if (emptyLine) {
15398
15399 // correct width
15400 bbox.width = 0;
15401 }
15402
15403 return bbox;
15404 } catch (e) {
15405 return { width: 0, height: 0 };
15406 }
15407 }
15408
15409
15410 /**
15411 * Layout the next line and return the layouted element.
15412 *
15413 * Alters the lines passed.
15414 *
15415 * @param {Array<String>} lines
15416 * @return {Object} the line descriptor, an object { width, height, text }
15417 */
15418 function layoutNext(lines, maxWidth, fakeText) {
15419
15420 var originalLine = lines.shift(),
15421 fitLine = originalLine;
15422
15423 var textBBox;
15424
15425 for (;;) {
15426 textBBox = getTextBBox(fitLine, fakeText);
15427
15428 textBBox.width = fitLine ? textBBox.width : 0;
15429
15430 // try to fit
15431 if (fitLine === ' ' || fitLine === '' || textBBox.width < Math.round(maxWidth) || fitLine.length < 2) {
15432 return fit(lines, fitLine, originalLine, textBBox);
15433 }
15434
15435 fitLine = shortenLine(fitLine, textBBox.width, maxWidth);
15436 }
15437 }
15438
15439 function fit(lines, fitLine, originalLine, textBBox) {
15440 if (fitLine.length < originalLine.length) {
15441 var remainder = originalLine.slice(fitLine.length).trim();
15442
15443 lines.unshift(remainder);
15444 }
15445
15446 return {
15447 width: textBBox.width,
15448 height: textBBox.height,
15449 text: fitLine
15450 };
15451 }
15452
15453
15454 /**
15455 * Shortens a line based on spacing and hyphens.
15456 * Returns the shortened result on success.
15457 *
15458 * @param {String} line
15459 * @param {Number} maxLength the maximum characters of the string
15460 * @return {String} the shortened string
15461 */
15462 function semanticShorten(line, maxLength) {
15463 var parts = line.split(/(\s|-)/g),
15464 part,
15465 shortenedParts = [],
15466 length = 0;
15467
15468 // try to shorten via spaces + hyphens
15469 if (parts.length > 1) {
15470 while ((part = parts.shift())) {
15471 if (part.length + length < maxLength) {
15472 shortenedParts.push(part);
15473 length += part.length;
15474 } else {
15475
15476 // remove previous part, too if hyphen does not fit anymore
15477 if (part === '-') {
15478 shortenedParts.pop();
15479 }
15480
15481 break;
15482 }
15483 }
15484 }
15485
15486 return shortenedParts.join('');
15487 }
15488
15489
15490 function shortenLine(line, width, maxWidth) {
15491 var length = Math.max(line.length * (maxWidth / width), 1);
15492
15493 // try to shorten semantically (i.e. based on spaces and hyphens)
15494 var shortenedLine = semanticShorten(line, length);
15495
15496 if (!shortenedLine) {
15497
15498 // force shorten by cutting the long word
15499 shortenedLine = line.slice(0, Math.max(Math.round(length - 1), 1));
15500 }
15501
15502 return shortenedLine;
15503 }
15504
15505
15506 function getHelperSvg() {
15507 var helperSvg = document.getElementById('helper-svg');
15508
15509 if (!helperSvg) {
15510 helperSvg = create('svg');
15511
15512 attr$1(helperSvg, {
15513 id: 'helper-svg',
15514 width: 0,
15515 height: 0,
15516 style: 'visibility: hidden; position: fixed'
15517 });
15518
15519 document.body.appendChild(helperSvg);
15520 }
15521
15522 return helperSvg;
15523 }
15524
15525
15526 /**
15527 * Creates a new label utility
15528 *
15529 * @param {Object} config
15530 * @param {Dimensions} config.size
15531 * @param {Number} config.padding
15532 * @param {Object} config.style
15533 * @param {String} config.align
15534 */
15535 function Text(config) {
15536
15537 this._config = assign({}, {
15538 size: DEFAULT_LABEL_SIZE,
15539 padding: DEFAULT_BOX_PADDING,
15540 style: {},
15541 align: 'center-top'
15542 }, config || {});
15543 }
15544
15545 /**
15546 * Returns the layouted text as an SVG element.
15547 *
15548 * @param {String} text
15549 * @param {Object} options
15550 *
15551 * @return {SVGElement}
15552 */
15553 Text.prototype.createText = function(text, options) {
15554 return this.layoutText(text, options).element;
15555 };
15556
15557 /**
15558 * Returns a labels layouted dimensions.
15559 *
15560 * @param {String} text to layout
15561 * @param {Object} options
15562 *
15563 * @return {Dimensions}
15564 */
15565 Text.prototype.getDimensions = function(text, options) {
15566 return this.layoutText(text, options).dimensions;
15567 };
15568
15569 /**
15570 * Creates and returns a label and its bounding box.
15571 *
15572 * @method Text#createText
15573 *
15574 * @param {String} text the text to render on the label
15575 * @param {Object} options
15576 * @param {String} options.align how to align in the bounding box.
15577 * Any of { 'center-middle', 'center-top' },
15578 * defaults to 'center-top'.
15579 * @param {String} options.style style to be applied to the text
15580 * @param {boolean} options.fitBox indicates if box will be recalculated to
15581 * fit text
15582 *
15583 * @return {Object} { element, dimensions }
15584 */
15585 Text.prototype.layoutText = function(text, options) {
15586 var box = assign({}, this._config.size, options.box),
15587 style = assign({}, this._config.style, options.style),
15588 align = parseAlign(options.align || this._config.align),
15589 padding = parsePadding(options.padding !== undefined ? options.padding : this._config.padding),
15590 fitBox = options.fitBox || false;
15591
15592 var lineHeight = getLineHeight(style);
15593
15594 var lines = text.split(/\r?\n/g),
15595 layouted = [];
15596
15597 var maxWidth = box.width - padding.left - padding.right;
15598
15599 // ensure correct rendering by attaching helper text node to invisible SVG
15600 var helperText = create('text');
15601 attr$1(helperText, { x: 0, y: 0 });
15602 attr$1(helperText, style);
15603
15604 var helperSvg = getHelperSvg();
15605
15606 append(helperSvg, helperText);
15607
15608 while (lines.length) {
15609 layouted.push(layoutNext(lines, maxWidth, helperText));
15610 }
15611
15612 if (align.vertical === 'middle') {
15613 padding.top = padding.bottom = 0;
15614 }
15615
15616 var totalHeight = reduce(layouted, function(sum, line, idx) {
15617 return sum + (lineHeight || line.height);
15618 }, 0) + padding.top + padding.bottom;
15619
15620 var maxLineWidth = reduce(layouted, function(sum, line, idx) {
15621 return line.width > sum ? line.width : sum;
15622 }, 0);
15623
15624 // the y position of the next line
15625 var y = padding.top;
15626
15627 if (align.vertical === 'middle') {
15628 y += (box.height - totalHeight) / 2;
15629 }
15630
15631 // magic number initial offset
15632 y -= (lineHeight || layouted[0].height) / 4;
15633
15634
15635 var textElement = create('text');
15636
15637 attr$1(textElement, style);
15638
15639 // layout each line taking into account that parent
15640 // shape might resize to fit text size
15641 forEach(layouted, function(line) {
15642
15643 var x;
15644
15645 y += (lineHeight || line.height);
15646
15647 switch (align.horizontal) {
15648 case 'left':
15649 x = padding.left;
15650 break;
15651
15652 case 'right':
15653 x = ((fitBox ? maxLineWidth : maxWidth)
15654 - padding.right - line.width);
15655 break;
15656
15657 default:
15658
15659 // aka center
15660 x = Math.max((((fitBox ? maxLineWidth : maxWidth)
15661 - line.width) / 2 + padding.left), 0);
15662 }
15663
15664 var tspan = create('tspan');
15665 attr$1(tspan, { x: x, y: y });
15666
15667 tspan.textContent = line.text;
15668
15669 append(textElement, tspan);
15670 });
15671
15672 remove$1(helperText);
15673
15674 var dimensions = {
15675 width: maxLineWidth,
15676 height: totalHeight
15677 };
15678
15679 return {
15680 dimensions: dimensions,
15681 element: textElement
15682 };
15683 };
15684
15685
15686 function getLineHeight(style) {
15687 if ('fontSize' in style && 'lineHeight' in style) {
15688 return style.lineHeight * parseInt(style.fontSize, 10);
15689 }
15690 }
15691
15692 var DEFAULT_FONT_SIZE = 12;
15693 var LINE_HEIGHT_RATIO = 1.2;
15694
15695 var MIN_TEXT_ANNOTATION_HEIGHT = 30;
15696
15697
15698 function TextRenderer(config) {
15699
15700 var defaultStyle = assign({
15701 fontFamily: 'Arial, sans-serif',
15702 fontSize: DEFAULT_FONT_SIZE,
15703 fontWeight: 'normal',
15704 lineHeight: LINE_HEIGHT_RATIO
15705 }, config && config.defaultStyle || {});
15706
15707 var fontSize = parseInt(defaultStyle.fontSize, 10) - 1;
15708
15709 var externalStyle = assign({}, defaultStyle, {
15710 fontSize: fontSize
15711 }, config && config.externalStyle || {});
15712
15713 var textUtil = new Text({
15714 style: defaultStyle
15715 });
15716
15717 /**
15718 * Get the new bounds of an externally rendered,
15719 * layouted label.
15720 *
15721 * @param {Bounds} bounds
15722 * @param {String} text
15723 *
15724 * @return {Bounds}
15725 */
15726 this.getExternalLabelBounds = function(bounds, text) {
15727
15728 var layoutedDimensions = textUtil.getDimensions(text, {
15729 box: {
15730 width: 90,
15731 height: 30,
15732 x: bounds.width / 2 + bounds.x,
15733 y: bounds.height / 2 + bounds.y
15734 },
15735 style: externalStyle
15736 });
15737
15738 // resize label shape to fit label text
15739 return {
15740 x: Math.round(bounds.x + bounds.width / 2 - layoutedDimensions.width / 2),
15741 y: Math.round(bounds.y),
15742 width: Math.ceil(layoutedDimensions.width),
15743 height: Math.ceil(layoutedDimensions.height)
15744 };
15745
15746 };
15747
15748 /**
15749 * Get the new bounds of text annotation.
15750 *
15751 * @param {Bounds} bounds
15752 * @param {String} text
15753 *
15754 * @return {Bounds}
15755 */
15756 this.getTextAnnotationBounds = function(bounds, text) {
15757
15758 var layoutedDimensions = textUtil.getDimensions(text, {
15759 box: bounds,
15760 style: defaultStyle,
15761 align: 'left-top',
15762 padding: 5
15763 });
15764
15765 return {
15766 x: bounds.x,
15767 y: bounds.y,
15768 width: bounds.width,
15769 height: Math.max(MIN_TEXT_ANNOTATION_HEIGHT, Math.round(layoutedDimensions.height))
15770 };
15771 };
15772
15773 /**
15774 * Create a layouted text element.
15775 *
15776 * @param {String} text
15777 * @param {Object} [options]
15778 *
15779 * @return {SVGElement} rendered text
15780 */
15781 this.createText = function(text, options) {
15782 return textUtil.createText(text, options || {});
15783 };
15784
15785 /**
15786 * Get default text style.
15787 */
15788 this.getDefaultStyle = function() {
15789 return defaultStyle;
15790 };
15791
15792 /**
15793 * Get the external text style.
15794 */
15795 this.getExternalStyle = function() {
15796 return externalStyle;
15797 };
15798
15799 }
15800
15801 TextRenderer.$inject = [
15802 'config.textRenderer'
15803 ];
15804
15805 /**
15806 * Map containing SVG paths needed by BpmnRenderer.
15807 */
15808
15809 function PathMap() {
15810
15811 /**
15812 * Contains a map of path elements
15813 *
15814 * <h1>Path definition</h1>
15815 * A parameterized path is defined like this:
15816 * <pre>
15817 * 'GATEWAY_PARALLEL': {
15818 * d: 'm {mx},{my} {e.x0},0 0,{e.x1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
15819 '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
15820 * height: 17.5,
15821 * width: 17.5,
15822 * heightElements: [2.5, 7.5],
15823 * widthElements: [2.5, 7.5]
15824 * }
15825 * </pre>
15826 * <p>It's important to specify a correct <b>height and width</b> for the path as the scaling
15827 * is based on the ratio between the specified height and width in this object and the
15828 * height and width that is set as scale target (Note x,y coordinates will be scaled with
15829 * individual ratios).</p>
15830 * <p>The '<b>heightElements</b>' and '<b>widthElements</b>' array must contain the values that will be scaled.
15831 * The scaling is based on the computed ratios.
15832 * Coordinates on the y axis should be in the <b>heightElement</b>'s array, they will be scaled using
15833 * the computed ratio coefficient.
15834 * In the parameterized path the scaled values can be accessed through the 'e' object in {} brackets.
15835 * <ul>
15836 * <li>The values for the y axis can be accessed in the path string using {e.y0}, {e.y1}, ....</li>
15837 * <li>The values for the x axis can be accessed in the path string using {e.x0}, {e.x1}, ....</li>
15838 * </ul>
15839 * The numbers x0, x1 respectively y0, y1, ... map to the corresponding array index.
15840 * </p>
15841 */
15842 this.pathMap = {
15843 'EVENT_MESSAGE': {
15844 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}',
15845 height: 36,
15846 width: 36,
15847 heightElements: [6, 14],
15848 widthElements: [10.5, 21]
15849 },
15850 'EVENT_SIGNAL': {
15851 d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x1},0 Z',
15852 height: 36,
15853 width: 36,
15854 heightElements: [18],
15855 widthElements: [10, 20]
15856 },
15857 'EVENT_ESCALATION': {
15858 d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x0},-{e.y1} l -{e.x0},{e.y1} Z',
15859 height: 36,
15860 width: 36,
15861 heightElements: [20, 7],
15862 widthElements: [8]
15863 },
15864 'EVENT_CONDITIONAL': {
15865 d: 'M {e.x0},{e.y0} l {e.x1},0 l 0,{e.y2} l -{e.x1},0 Z ' +
15866 'M {e.x2},{e.y3} l {e.x0},0 ' +
15867 'M {e.x2},{e.y4} l {e.x0},0 ' +
15868 'M {e.x2},{e.y5} l {e.x0},0 ' +
15869 'M {e.x2},{e.y6} l {e.x0},0 ' +
15870 'M {e.x2},{e.y7} l {e.x0},0 ' +
15871 'M {e.x2},{e.y8} l {e.x0},0 ',
15872 height: 36,
15873 width: 36,
15874 heightElements: [8.5, 14.5, 18, 11.5, 14.5, 17.5, 20.5, 23.5, 26.5],
15875 widthElements: [10.5, 14.5, 12.5]
15876 },
15877 'EVENT_LINK': {
15878 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',
15879 height: 36,
15880 width: 36,
15881 heightElements: [4.4375, 6.75, 7.8125],
15882 widthElements: [9.84375, 13.5]
15883 },
15884 'EVENT_ERROR': {
15885 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',
15886 height: 36,
15887 width: 36,
15888 heightElements: [0.023, 8.737, 8.151, 16.564, 10.591, 8.714],
15889 widthElements: [0.085, 6.672, 6.97, 4.273, 5.337, 6.636]
15890 },
15891 'EVENT_CANCEL_45': {
15892 d: 'm {mx},{my} -{e.x1},0 0,{e.x0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
15893 '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
15894 height: 36,
15895 width: 36,
15896 heightElements: [4.75, 8.5],
15897 widthElements: [4.75, 8.5]
15898 },
15899 'EVENT_COMPENSATION': {
15900 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',
15901 height: 36,
15902 width: 36,
15903 heightElements: [6.5, 13, 0.4, 6.1],
15904 widthElements: [9, 9.3, 8.7]
15905 },
15906 'EVENT_TIMER_WH': {
15907 d: 'M {mx},{my} l {e.x0},-{e.y0} m -{e.x0},{e.y0} l {e.x1},{e.y1} ',
15908 height: 36,
15909 width: 36,
15910 heightElements: [10, 2],
15911 widthElements: [3, 7]
15912 },
15913 'EVENT_TIMER_LINE': {
15914 d: 'M {mx},{my} ' +
15915 'm {e.x0},{e.y0} l -{e.x1},{e.y1} ',
15916 height: 36,
15917 width: 36,
15918 heightElements: [10, 3],
15919 widthElements: [0, 0]
15920 },
15921 'EVENT_MULTIPLE': {
15922 d:'m {mx},{my} {e.x1},-{e.y0} {e.x1},{e.y0} -{e.x0},{e.y1} -{e.x2},0 z',
15923 height: 36,
15924 width: 36,
15925 heightElements: [6.28099, 12.56199],
15926 widthElements: [3.1405, 9.42149, 12.56198]
15927 },
15928 'EVENT_PARALLEL_MULTIPLE': {
15929 d:'m {mx},{my} {e.x0},0 0,{e.y1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
15930 '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
15931 height: 36,
15932 width: 36,
15933 heightElements: [2.56228, 7.68683],
15934 widthElements: [2.56228, 7.68683]
15935 },
15936 'GATEWAY_EXCLUSIVE': {
15937 d:'m {mx},{my} {e.x0},{e.y0} {e.x1},{e.y0} {e.x2},0 {e.x4},{e.y2} ' +
15938 '{e.x4},{e.y1} {e.x2},0 {e.x1},{e.y3} {e.x0},{e.y3} ' +
15939 '{e.x3},0 {e.x5},{e.y1} {e.x5},{e.y2} {e.x3},0 z',
15940 height: 17.5,
15941 width: 17.5,
15942 heightElements: [8.5, 6.5312, -6.5312, -8.5],
15943 widthElements: [6.5, -6.5, 3, -3, 5, -5]
15944 },
15945 'GATEWAY_PARALLEL': {
15946 d:'m {mx},{my} 0,{e.y1} -{e.x1},0 0,{e.y0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
15947 '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
15948 height: 30,
15949 width: 30,
15950 heightElements: [5, 12.5],
15951 widthElements: [5, 12.5]
15952 },
15953 'GATEWAY_EVENT_BASED': {
15954 d:'m {mx},{my} {e.x0},{e.y0} {e.x0},{e.y1} {e.x1},{e.y2} {e.x2},0 z',
15955 height: 11,
15956 width: 11,
15957 heightElements: [-6, 6, 12, -12],
15958 widthElements: [9, -3, -12]
15959 },
15960 'GATEWAY_COMPLEX': {
15961 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} ' +
15962 '{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} ' +
15963 '{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} ' +
15964 '-{e.x0},{e.y1} 0,-{e.y0} -{e.x3},0 z',
15965 height: 17.125,
15966 width: 17.125,
15967 heightElements: [4.875, 3.4375, 2.125, 3],
15968 widthElements: [3.4375, 2.125, 4.875, 3]
15969 },
15970 'DATA_OBJECT_PATH': {
15971 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',
15972 height: 61,
15973 width: 51,
15974 heightElements: [10, 50, 60],
15975 widthElements: [10, 40, 50, 60]
15976 },
15977 'DATA_OBJECT_COLLECTION_PATH': {
15978 d:'m {mx}, {my} ' +
15979 'm 0 15 l 0 -15 ' +
15980 'm 4 15 l 0 -15 ' +
15981 'm 4 15 l 0 -15 ',
15982 height: 61,
15983 width: 51,
15984 heightElements: [12],
15985 widthElements: [1, 6, 12, 15]
15986 },
15987 'DATA_ARROW': {
15988 d:'m 5,9 9,0 0,-3 5,5 -5,5 0,-3 -9,0 z',
15989 height: 61,
15990 width: 51,
15991 heightElements: [],
15992 widthElements: []
15993 },
15994 'DATA_STORE': {
15995 d:'m {mx},{my} ' +
15996 'l 0,{e.y2} ' +
15997 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' +
15998 'l 0,-{e.y2} ' +
15999 'c -{e.x0},-{e.y1} -{e.x1},-{e.y1} -{e.x2},0' +
16000 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' +
16001 'm -{e.x2},{e.y0}' +
16002 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0' +
16003 'm -{e.x2},{e.y0}' +
16004 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0',
16005 height: 61,
16006 width: 61,
16007 heightElements: [7, 10, 45],
16008 widthElements: [2, 58, 60]
16009 },
16010 'TEXT_ANNOTATION': {
16011 d: 'm {mx}, {my} m 10,0 l -10,0 l 0,{e.y0} l 10,0',
16012 height: 30,
16013 width: 10,
16014 heightElements: [30],
16015 widthElements: [10]
16016 },
16017 'MARKER_SUB_PROCESS': {
16018 d: 'm{mx},{my} m 7,2 l 0,10 m -5,-5 l 10,0',
16019 height: 10,
16020 width: 10,
16021 heightElements: [],
16022 widthElements: []
16023 },
16024 'MARKER_PARALLEL': {
16025 d: 'm{mx},{my} m 3,2 l 0,10 m 3,-10 l 0,10 m 3,-10 l 0,10',
16026 height: 10,
16027 width: 10,
16028 heightElements: [],
16029 widthElements: []
16030 },
16031 'MARKER_SEQUENTIAL': {
16032 d: 'm{mx},{my} m 0,3 l 10,0 m -10,3 l 10,0 m -10,3 l 10,0',
16033 height: 10,
16034 width: 10,
16035 heightElements: [],
16036 widthElements: []
16037 },
16038 'MARKER_COMPENSATION': {
16039 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',
16040 height: 10,
16041 width: 21,
16042 heightElements: [],
16043 widthElements: []
16044 },
16045 'MARKER_LOOP': {
16046 d: 'm {mx},{my} c 3.526979,0 6.386161,-2.829858 6.386161,-6.320661 0,-3.490806 -2.859182,-6.320661 ' +
16047 '-6.386161,-6.320661 -3.526978,0 -6.38616,2.829855 -6.38616,6.320661 0,1.745402 ' +
16048 '0.714797,3.325567 1.870463,4.469381 0.577834,0.571908 1.265885,1.034728 2.029916,1.35457 ' +
16049 'l -0.718163,-3.909793 m 0.718163,3.909793 -3.885211,0.802902',
16050 height: 13.9,
16051 width: 13.7,
16052 heightElements: [],
16053 widthElements: []
16054 },
16055 'MARKER_ADHOC': {
16056 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 ' +
16057 '3.85579,1.15803 5.76082,1.79107 1.06385,0.34139996 2.24454,0.1438 3.18759,-0.43767 0.61743,-0.33642 ' +
16058 '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 ' +
16059 '-3.6918,1.66181996 -1.24459,0.0927 -2.46671,-0.2491 -3.59505,-0.74812 -1.35789,-0.55965 ' +
16060 '-2.75133,-1.33436996 -4.27027,-1.18121996 -1.37741,0.14601 -2.41842,1.13685996 -3.44288,1.96782996 z',
16061 height: 4,
16062 width: 15,
16063 heightElements: [],
16064 widthElements: []
16065 },
16066 'TASK_TYPE_SEND': {
16067 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}',
16068 height: 14,
16069 width: 21,
16070 heightElements: [6, 14],
16071 widthElements: [10.5, 21]
16072 },
16073 'TASK_TYPE_SCRIPT': {
16074 d: 'm {mx},{my} c 9.966553,-6.27276 -8.000926,-7.91932 2.968968,-14.938 l -8.802728,0 ' +
16075 'c -10.969894,7.01868 6.997585,8.66524 -2.968967,14.938 z ' +
16076 'm -7,-12 l 5,0 ' +
16077 'm -4.5,3 l 4.5,0 ' +
16078 'm -3,3 l 5,0' +
16079 'm -4,3 l 5,0',
16080 height: 15,
16081 width: 12.6,
16082 heightElements: [6, 14],
16083 widthElements: [10.5, 21]
16084 },
16085 'TASK_TYPE_USER_1': {
16086 d: 'm {mx},{my} c 0.909,-0.845 1.594,-2.049 1.594,-3.385 0,-2.554 -1.805,-4.62199999 ' +
16087 '-4.357,-4.62199999 -2.55199998,0 -4.28799998,2.06799999 -4.28799998,4.62199999 0,1.348 ' +
16088 '0.974,2.562 1.89599998,3.405 -0.52899998,0.187 -5.669,2.097 -5.794,4.7560005 v 6.718 ' +
16089 'h 17 v -6.718 c 0,-2.2980005 -5.5279996,-4.5950005 -6.0509996,-4.7760005 z' +
16090 'm -8,6 l 0,5.5 m 11,0 l 0,-5'
16091 },
16092 'TASK_TYPE_USER_2': {
16093 d: 'm {mx},{my} m 2.162,1.009 c 0,2.4470005 -2.158,4.4310005 -4.821,4.4310005 ' +
16094 '-2.66499998,0 -4.822,-1.981 -4.822,-4.4310005 '
16095 },
16096 'TASK_TYPE_USER_3': {
16097 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 ' +
16098 '4.124,0.965 -0.098,-0.57 -0.117,-3.79099999 -4.191,-4.13599999 -3.57499998,0.001 ' +
16099 '-4.20799998,3.36699999 -4.20699998,4.34799999 z'
16100 },
16101 'TASK_TYPE_MANUAL': {
16102 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 ' +
16103 '-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 ' +
16104 '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 ' +
16105 '-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 ' +
16106 '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 ' +
16107 '-10.86,-0.003 -11.0829995,-0.003 -0.022,-0.047 -0.045,-0.094 -0.069,-0.139 0.3939995,-0.319 ' +
16108 '2.0409995,-1.626 2.4149995,-2.017 0.469,-0.4870005 0.519,-1.1650005 0.162,-1.6040005 -0.414,-0.511 ' +
16109 '-0.973,-0.5 -1.48,-0.236 -1.4609995,0.764 -6.5999995,3.6430005 -7.7329995,4.2710005 -0.9,0.499 ' +
16110 '-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 ' +
16111 '-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 ' +
16112 '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 ' +
16113 '-5.824,-0.004 -6.04,-0.004 10e-4,-0.084 0.003,-0.586 10e-4,-0.67 z'
16114 },
16115 'TASK_TYPE_INSTANTIATING_SEND': {
16116 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'
16117 },
16118 'TASK_TYPE_SERVICE': {
16119 d: 'm {mx},{my} v -1.71335 c 0.352326,-0.0705 0.703932,-0.17838 1.047628,-0.32133 ' +
16120 '0.344416,-0.14465 0.665822,-0.32133 0.966377,-0.52145 l 1.19431,1.18005 1.567487,-1.57688 ' +
16121 '-1.195028,-1.18014 c 0.403376,-0.61394 0.683079,-1.29908 0.825447,-2.01824 l 1.622133,-0.01 ' +
16122 'v -2.2196 l -1.636514,0.01 c -0.07333,-0.35153 -0.178319,-0.70024 -0.323564,-1.04372 ' +
16123 '-0.145244,-0.34406 -0.321407,-0.6644 -0.522735,-0.96217 l 1.131035,-1.13631 -1.583305,-1.56293 ' +
16124 '-1.129598,1.13589 c -0.614052,-0.40108 -1.302883,-0.68093 -2.022633,-0.82247 l 0.0093,-1.61852 ' +
16125 '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 ' +
16126 '-0.665102,0.32092 -0.9635006,0.52046 l -1.1698628,-1.15823 -1.5667691,1.5792 1.1684265,1.15669 ' +
16127 'c -0.4026573,0.61283 -0.68308,1.29797 -0.8247287,2.01713 l -1.6588041,0.003 v 2.22174 ' +
16128 'l 1.6724648,-0.006 c 0.073327,0.35077 0.1797598,0.70243 0.3242851,1.04472 0.1452428,0.34448 ' +
16129 '0.3214064,0.6644 0.5227339,0.96066 l -1.1993431,1.19723 1.5840256,1.56011 1.1964668,-1.19348 ' +
16130 'c 0.6140517,0.40346 1.3028827,0.68232 2.0233517,0.82331 l 7.19e-4,1.69892 h 2.226848 z ' +
16131 'm 0.221462,-3.9957 c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
16132 '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
16133 '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
16134 },
16135 'TASK_TYPE_SERVICE_FILL': {
16136 d: 'm {mx},{my} c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
16137 '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
16138 '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
16139 },
16140 'TASK_TYPE_BUSINESS_RULE_HEADER': {
16141 d: 'm {mx},{my} 0,4 20,0 0,-4 z'
16142 },
16143 'TASK_TYPE_BUSINESS_RULE_MAIN': {
16144 d: 'm {mx},{my} 0,12 20,0 0,-12 z' +
16145 'm 0,8 l 20,0 ' +
16146 'm -13,-4 l 0,8'
16147 },
16148 'MESSAGE_FLOW_MARKER': {
16149 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'
16150 }
16151 };
16152
16153 this.getRawPath = function getRawPath(pathId) {
16154 return this.pathMap[pathId].d;
16155 };
16156
16157 /**
16158 * Scales the path to the given height and width.
16159 * <h1>Use case</h1>
16160 * <p>Use case is to scale the content of elements (event, gateways) based
16161 * on the element bounding box's size.
16162 * </p>
16163 * <h1>Why not transform</h1>
16164 * <p>Scaling a path with transform() will also scale the stroke and IE does not support
16165 * the option 'non-scaling-stroke' to prevent this.
16166 * Also there are use cases where only some parts of a path should be
16167 * scaled.</p>
16168 *
16169 * @param {String} pathId The ID of the path.
16170 * @param {Object} param <p>
16171 * Example param object scales the path to 60% size of the container (data.width, data.height).
16172 * <pre>
16173 * {
16174 * xScaleFactor: 0.6,
16175 * yScaleFactor:0.6,
16176 * containerWidth: data.width,
16177 * containerHeight: data.height,
16178 * position: {
16179 * mx: 0.46,
16180 * my: 0.2,
16181 * }
16182 * }
16183 * </pre>
16184 * <ul>
16185 * <li>targetpathwidth = xScaleFactor * containerWidth</li>
16186 * <li>targetpathheight = yScaleFactor * containerHeight</li>
16187 * <li>Position is used to set the starting coordinate of the path. M is computed:
16188 * <ul>
16189 * <li>position.x * containerWidth</li>
16190 * <li>position.y * containerHeight</li>
16191 * </ul>
16192 * Center of the container <pre> position: {
16193 * mx: 0.5,
16194 * my: 0.5,
16195 * }</pre>
16196 * Upper left corner of the container
16197 * <pre> position: {
16198 * mx: 0.0,
16199 * my: 0.0,
16200 * }</pre>
16201 * </li>
16202 * </ul>
16203 * </p>
16204 *
16205 */
16206 this.getScaledPath = function getScaledPath(pathId, param) {
16207 var rawPath = this.pathMap[pathId];
16208
16209 // positioning
16210 // compute the start point of the path
16211 var mx, my;
16212
16213 if (param.abspos) {
16214 mx = param.abspos.x;
16215 my = param.abspos.y;
16216 } else {
16217 mx = param.containerWidth * param.position.mx;
16218 my = param.containerHeight * param.position.my;
16219 }
16220
16221 var coordinates = {}; // map for the scaled coordinates
16222 if (param.position) {
16223
16224 // path
16225 var heightRatio = (param.containerHeight / rawPath.height) * param.yScaleFactor;
16226 var widthRatio = (param.containerWidth / rawPath.width) * param.xScaleFactor;
16227
16228
16229 // Apply height ratio
16230 for (var heightIndex = 0; heightIndex < rawPath.heightElements.length; heightIndex++) {
16231 coordinates['y' + heightIndex] = rawPath.heightElements[heightIndex] * heightRatio;
16232 }
16233
16234 // Apply width ratio
16235 for (var widthIndex = 0; widthIndex < rawPath.widthElements.length; widthIndex++) {
16236 coordinates['x' + widthIndex] = rawPath.widthElements[widthIndex] * widthRatio;
16237 }
16238 }
16239
16240 // Apply value to raw path
16241 var path = format(
16242 rawPath.d, {
16243 mx: mx,
16244 my: my,
16245 e: coordinates
16246 }
16247 );
16248 return path;
16249 };
16250 }
16251
16252 // helpers //////////////////////
16253
16254 // copied from https://github.com/adobe-webplatform/Snap.svg/blob/master/src/svg.js
16255 var tokenRegex = /\{([^}]+)\}/g,
16256 objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g; // matches .xxxxx or ["xxxxx"] to run over object properties
16257
16258 function replacer(all, key, obj) {
16259 var res = obj;
16260 key.replace(objNotationRegex, function(all, name, quote, quotedName, isFunc) {
16261 name = name || quotedName;
16262 if (res) {
16263 if (name in res) {
16264 res = res[name];
16265 }
16266 typeof res == 'function' && isFunc && (res = res());
16267 }
16268 });
16269 res = (res == null || res == obj ? all : res) + '';
16270
16271 return res;
16272 }
16273
16274 function format(str, obj) {
16275 return String(str).replace(tokenRegex, function(all, key) {
16276 return replacer(all, key, obj);
16277 });
16278 }
16279
16280 var DrawModule$1 = {
16281 __init__: [ 'bpmnRenderer' ],
16282 bpmnRenderer: [ 'type', BpmnRenderer ],
16283 textRenderer: [ 'type', TextRenderer ],
16284 pathMap: [ 'type', PathMap ]
16285 };
16286
16287 /**
16288 * A simple translation stub to be used for multi-language support
16289 * in diagrams. Can be easily replaced with a more sophisticated
16290 * solution.
16291 *
16292 * @example
16293 *
16294 * // use it inside any diagram component by injecting `translate`.
16295 *
16296 * function MyService(translate) {
16297 * alert(translate('HELLO {you}', { you: 'You!' }));
16298 * }
16299 *
16300 * @param {String} template to interpolate
16301 * @param {Object} [replacements] a map with substitutes
16302 *
16303 * @return {String} the translated string
16304 */
16305 function translate$1(template, replacements) {
16306
16307 replacements = replacements || {};
16308
16309 return template.replace(/{([^}]+)}/g, function(_, key) {
16310 return replacements[key] || '{' + key + '}';
16311 });
16312 }
16313
16314 var TranslateModule = {
16315 translate: [ 'value', translate$1 ]
16316 };
16317
16318 var DEFAULT_LABEL_SIZE$1 = {
16319 width: 90,
16320 height: 20
16321 };
16322
16323 var FLOW_LABEL_INDENT = 15;
16324
16325
16326 /**
16327 * Returns true if the given semantic has an external label
16328 *
16329 * @param {BpmnElement} semantic
16330 * @return {Boolean} true if has label
16331 */
16332 function isLabelExternal(semantic) {
16333 return is$1(semantic, 'bpmn:Event') ||
16334 is$1(semantic, 'bpmn:Gateway') ||
16335 is$1(semantic, 'bpmn:DataStoreReference') ||
16336 is$1(semantic, 'bpmn:DataObjectReference') ||
16337 is$1(semantic, 'bpmn:DataInput') ||
16338 is$1(semantic, 'bpmn:DataOutput') ||
16339 is$1(semantic, 'bpmn:SequenceFlow') ||
16340 is$1(semantic, 'bpmn:MessageFlow') ||
16341 is$1(semantic, 'bpmn:Group');
16342 }
16343
16344 /**
16345 * Get the position for sequence flow labels
16346 *
16347 * @param {Array<Point>} waypoints
16348 * @return {Point} the label position
16349 */
16350 function getFlowLabelPosition(waypoints) {
16351
16352 // get the waypoints mid
16353 var mid = waypoints.length / 2 - 1;
16354
16355 var first = waypoints[Math.floor(mid)];
16356 var second = waypoints[Math.ceil(mid + 0.01)];
16357
16358 // get position
16359 var position = getWaypointsMid(waypoints);
16360
16361 // calculate angle
16362 var angle = Math.atan((second.y - first.y) / (second.x - first.x));
16363
16364 var x = position.x,
16365 y = position.y;
16366
16367 if (Math.abs(angle) < Math.PI / 2) {
16368 y -= FLOW_LABEL_INDENT;
16369 } else {
16370 x += FLOW_LABEL_INDENT;
16371 }
16372
16373 return { x: x, y: y };
16374 }
16375
16376
16377 /**
16378 * Get the middle of a number of waypoints
16379 *
16380 * @param {Array<Point>} waypoints
16381 * @return {Point} the mid point
16382 */
16383 function getWaypointsMid(waypoints) {
16384
16385 var mid = waypoints.length / 2 - 1;
16386
16387 var first = waypoints[Math.floor(mid)];
16388 var second = waypoints[Math.ceil(mid + 0.01)];
16389
16390 return {
16391 x: first.x + (second.x - first.x) / 2,
16392 y: first.y + (second.y - first.y) / 2
16393 };
16394 }
16395
16396
16397 function getExternalLabelMid(element) {
16398
16399 if (element.waypoints) {
16400 return getFlowLabelPosition(element.waypoints);
16401 } else if (is$1(element, 'bpmn:Group')) {
16402 return {
16403 x: element.x + element.width / 2,
16404 y: element.y + DEFAULT_LABEL_SIZE$1.height / 2
16405 };
16406 } else {
16407 return {
16408 x: element.x + element.width / 2,
16409 y: element.y + element.height + DEFAULT_LABEL_SIZE$1.height / 2
16410 };
16411 }
16412 }
16413
16414
16415 /**
16416 * Returns the bounds of an elements label, parsed from the elements DI or
16417 * generated from its bounds.
16418 *
16419 * @param {BpmnElement} semantic
16420 * @param {djs.model.Base} element
16421 */
16422 function getExternalLabelBounds(semantic, element) {
16423
16424 var mid,
16425 size,
16426 bounds,
16427 di = semantic.di,
16428 label = di.label;
16429
16430 if (label && label.bounds) {
16431 bounds = label.bounds;
16432
16433 size = {
16434 width: Math.max(DEFAULT_LABEL_SIZE$1.width, bounds.width),
16435 height: bounds.height
16436 };
16437
16438 mid = {
16439 x: bounds.x + bounds.width / 2,
16440 y: bounds.y + bounds.height / 2
16441 };
16442 } else {
16443
16444 mid = getExternalLabelMid(element);
16445
16446 size = DEFAULT_LABEL_SIZE$1;
16447 }
16448
16449 return assign({
16450 x: mid.x - size.width / 2,
16451 y: mid.y - size.height / 2
16452 }, size);
16453 }
16454
16455 /**
16456 * This file contains portions that got extraced from Snap.svg (licensed Apache-2.0).
16457 *
16458 * @see https://github.com/adobe-webplatform/Snap.svg/blob/master/src/path.js
16459 */
16460
16461 /* eslint no-fallthrough: "off" */
16462
16463 var math = Math,
16464 PI = math.PI;
16465
16466 function roundPoint(point) {
16467
16468 return {
16469 x: Math.round(point.x),
16470 y: Math.round(point.y)
16471 };
16472 }
16473
16474
16475 /**
16476 * Get the mid of the given bounds or point.
16477 *
16478 * @param {Bounds|Point} bounds
16479 *
16480 * @return {Point}
16481 */
16482 function getMid(bounds) {
16483 return roundPoint({
16484 x: bounds.x + (bounds.width || 0) / 2,
16485 y: bounds.y + (bounds.height || 0) / 2
16486 });
16487 }
16488
16489 function elementData(semantic, attrs) {
16490 return assign({
16491 id: semantic.id,
16492 type: semantic.$type,
16493 businessObject: semantic
16494 }, attrs);
16495 }
16496
16497 function getWaypoints(bo, source, target) {
16498
16499 var waypoints = bo.di.waypoint;
16500
16501 if (!waypoints || waypoints.length < 2) {
16502 return [ getMid(source), getMid(target) ];
16503 }
16504
16505 return waypoints.map(function(p) {
16506 return { x: p.x, y: p.y };
16507 });
16508 }
16509
16510 function notYetDrawn(translate, semantic, refSemantic, property) {
16511 return new Error(translate('element {element} referenced by {referenced}#{property} not yet drawn', {
16512 element: elementToString(refSemantic),
16513 referenced: elementToString(semantic),
16514 property: property
16515 }));
16516 }
16517
16518
16519 /**
16520 * An importer that adds bpmn elements to the canvas
16521 *
16522 * @param {EventBus} eventBus
16523 * @param {Canvas} canvas
16524 * @param {ElementFactory} elementFactory
16525 * @param {ElementRegistry} elementRegistry
16526 * @param {Function} translate
16527 * @param {TextRenderer} textRenderer
16528 */
16529 function BpmnImporter(
16530 eventBus, canvas, elementFactory,
16531 elementRegistry, translate, textRenderer) {
16532
16533 this._eventBus = eventBus;
16534 this._canvas = canvas;
16535 this._elementFactory = elementFactory;
16536 this._elementRegistry = elementRegistry;
16537 this._translate = translate;
16538 this._textRenderer = textRenderer;
16539 }
16540
16541 BpmnImporter.$inject = [
16542 'eventBus',
16543 'canvas',
16544 'elementFactory',
16545 'elementRegistry',
16546 'translate',
16547 'textRenderer'
16548 ];
16549
16550
16551 /**
16552 * Add bpmn element (semantic) to the canvas onto the
16553 * specified parent shape.
16554 */
16555 BpmnImporter.prototype.add = function(semantic, parentElement) {
16556
16557 var di = semantic.di,
16558 element,
16559 translate = this._translate,
16560 hidden;
16561
16562 var parentIndex;
16563
16564 // ROOT ELEMENT
16565 // handle the special case that we deal with a
16566 // invisible root element (process or collaboration)
16567 if (is$1(di, 'bpmndi:BPMNPlane')) {
16568
16569 // add a virtual element (not being drawn)
16570 element = this._elementFactory.createRoot(elementData(semantic));
16571
16572 this._canvas.setRootElement(element);
16573 }
16574
16575 // SHAPE
16576 else if (is$1(di, 'bpmndi:BPMNShape')) {
16577
16578 var collapsed = !isExpanded(semantic);
16579 hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
16580
16581 var bounds = semantic.di.bounds;
16582
16583 element = this._elementFactory.createShape(elementData(semantic, {
16584 collapsed: collapsed,
16585 hidden: hidden,
16586 x: Math.round(bounds.x),
16587 y: Math.round(bounds.y),
16588 width: Math.round(bounds.width),
16589 height: Math.round(bounds.height)
16590 }));
16591
16592 if (is$1(semantic, 'bpmn:BoundaryEvent')) {
16593 this._attachBoundary(semantic, element);
16594 }
16595
16596 // insert lanes behind other flow nodes (cf. #727)
16597 if (is$1(semantic, 'bpmn:Lane')) {
16598 parentIndex = 0;
16599 }
16600
16601 if (is$1(semantic, 'bpmn:DataStoreReference')) {
16602
16603 // check wether data store is inside our outside of its semantic parent
16604 if (!isPointInsideBBox(parentElement, getMid(bounds))) {
16605 parentElement = this._canvas.getRootElement();
16606 }
16607 }
16608
16609 this._canvas.addShape(element, parentElement, parentIndex);
16610 }
16611
16612 // CONNECTION
16613 else if (is$1(di, 'bpmndi:BPMNEdge')) {
16614
16615 var source = this._getSource(semantic),
16616 target = this._getTarget(semantic);
16617
16618 hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
16619
16620 element = this._elementFactory.createConnection(elementData(semantic, {
16621 hidden: hidden,
16622 source: source,
16623 target: target,
16624 waypoints: getWaypoints(semantic, source, target)
16625 }));
16626
16627 if (is$1(semantic, 'bpmn:DataAssociation')) {
16628
16629 // render always on top; this ensures DataAssociations
16630 // are rendered correctly across different "hacks" people
16631 // love to model such as cross participant / sub process
16632 // associations
16633 parentElement = null;
16634 }
16635
16636 // insert sequence flows behind other flow nodes (cf. #727)
16637 if (is$1(semantic, 'bpmn:SequenceFlow')) {
16638 parentIndex = 0;
16639 }
16640
16641 this._canvas.addConnection(element, parentElement, parentIndex);
16642 } else {
16643 throw new Error(translate('unknown di {di} for element {semantic}', {
16644 di: elementToString(di),
16645 semantic: elementToString(semantic)
16646 }));
16647 }
16648
16649 // (optional) LABEL
16650 if (isLabelExternal(semantic) && getLabel(element)) {
16651 this.addLabel(semantic, element);
16652 }
16653
16654
16655 this._eventBus.fire('bpmnElement.added', { element: element });
16656
16657 return element;
16658 };
16659
16660
16661 /**
16662 * Attach the boundary element to the given host
16663 *
16664 * @param {ModdleElement} boundarySemantic
16665 * @param {djs.model.Base} boundaryElement
16666 */
16667 BpmnImporter.prototype._attachBoundary = function(boundarySemantic, boundaryElement) {
16668 var translate = this._translate;
16669 var hostSemantic = boundarySemantic.attachedToRef;
16670
16671 if (!hostSemantic) {
16672 throw new Error(translate('missing {semantic}#attachedToRef', {
16673 semantic: elementToString(boundarySemantic)
16674 }));
16675 }
16676
16677 var host = this._elementRegistry.get(hostSemantic.id),
16678 attachers = host && host.attachers;
16679
16680 if (!host) {
16681 throw notYetDrawn(translate, boundarySemantic, hostSemantic, 'attachedToRef');
16682 }
16683
16684 // wire element.host <> host.attachers
16685 boundaryElement.host = host;
16686
16687 if (!attachers) {
16688 host.attachers = attachers = [];
16689 }
16690
16691 if (attachers.indexOf(boundaryElement) === -1) {
16692 attachers.push(boundaryElement);
16693 }
16694 };
16695
16696
16697 /**
16698 * add label for an element
16699 */
16700 BpmnImporter.prototype.addLabel = function(semantic, element) {
16701 var bounds,
16702 text,
16703 label;
16704
16705 bounds = getExternalLabelBounds(semantic, element);
16706
16707 text = getLabel(element);
16708
16709 if (text) {
16710
16711 // get corrected bounds from actual layouted text
16712 bounds = this._textRenderer.getExternalLabelBounds(bounds, text);
16713 }
16714
16715 label = this._elementFactory.createLabel(elementData(semantic, {
16716 id: semantic.id + '_label',
16717 labelTarget: element,
16718 type: 'label',
16719 hidden: element.hidden || !getLabel(element),
16720 x: Math.round(bounds.x),
16721 y: Math.round(bounds.y),
16722 width: Math.round(bounds.width),
16723 height: Math.round(bounds.height)
16724 }));
16725
16726 return this._canvas.addShape(label, element.parent);
16727 };
16728
16729 /**
16730 * Return the drawn connection end based on the given side.
16731 *
16732 * @throws {Error} if the end is not yet drawn
16733 */
16734 BpmnImporter.prototype._getEnd = function(semantic, side) {
16735
16736 var element,
16737 refSemantic,
16738 type = semantic.$type,
16739 translate = this._translate;
16740
16741 refSemantic = semantic[side + 'Ref'];
16742
16743 // handle mysterious isMany DataAssociation#sourceRef
16744 if (side === 'source' && type === 'bpmn:DataInputAssociation') {
16745 refSemantic = refSemantic && refSemantic[0];
16746 }
16747
16748 // fix source / target for DataInputAssociation / DataOutputAssociation
16749 if (side === 'source' && type === 'bpmn:DataOutputAssociation' ||
16750 side === 'target' && type === 'bpmn:DataInputAssociation') {
16751
16752 refSemantic = semantic.$parent;
16753 }
16754
16755 element = refSemantic && this._getElement(refSemantic);
16756
16757 if (element) {
16758 return element;
16759 }
16760
16761 if (refSemantic) {
16762 throw notYetDrawn(translate, semantic, refSemantic, side + 'Ref');
16763 } else {
16764 throw new Error(translate('{semantic}#{side} Ref not specified', {
16765 semantic: elementToString(semantic),
16766 side: side
16767 }));
16768 }
16769 };
16770
16771 BpmnImporter.prototype._getSource = function(semantic) {
16772 return this._getEnd(semantic, 'source');
16773 };
16774
16775 BpmnImporter.prototype._getTarget = function(semantic) {
16776 return this._getEnd(semantic, 'target');
16777 };
16778
16779
16780 BpmnImporter.prototype._getElement = function(semantic) {
16781 return this._elementRegistry.get(semantic.id);
16782 };
16783
16784
16785 // helpers ////////////////////
16786
16787 function isPointInsideBBox(bbox, point) {
16788 var x = point.x,
16789 y = point.y;
16790
16791 return x >= bbox.x &&
16792 x <= bbox.x + bbox.width &&
16793 y >= bbox.y &&
16794 y <= bbox.y + bbox.height;
16795 }
16796
16797 var ImportModule = {
16798 __depends__: [
16799 TranslateModule
16800 ],
16801 bpmnImporter: [ 'type', BpmnImporter ]
16802 };
16803
16804 var CoreModule$1 = {
16805 __depends__: [
16806 DrawModule$1,
16807 ImportModule
16808 ]
16809 };
16810
16811 function getOriginal(event) {
16812 return event.originalEvent || event.srcEvent;
16813 }
16814
16815
16816 function toPoint(event) {
16817
16818 if (event.pointers && event.pointers.length) {
16819 event = event.pointers[0];
16820 }
16821
16822 if (event.touches && event.touches.length) {
16823 event = event.touches[0];
16824 }
16825
16826 return event ? {
16827 x: event.clientX,
16828 y: event.clientY
16829 } : null;
16830 }
16831
16832 function isMac() {
16833 return (/mac/i).test(navigator.platform);
16834 }
16835
16836 function isPrimaryButton(event) {
16837
16838 // button === 0 -> left áka primary mouse button
16839 return !(getOriginal(event) || event).button;
16840 }
16841
16842 function hasPrimaryModifier(event) {
16843 var originalEvent = getOriginal(event) || event;
16844
16845 if (!isPrimaryButton(event)) {
16846 return false;
16847 }
16848
16849 // Use alt as primary modifier key for mac OS
16850 if (isMac()) {
16851 return originalEvent.metaKey;
16852 } else {
16853 return originalEvent.ctrlKey;
16854 }
16855 }
16856
16857 function allowAll(e) { return true; }
16858
16859 var LOW_PRIORITY = 500;
16860
16861
16862 /**
16863 * A plugin that provides interaction events for diagram elements.
16864 *
16865 * It emits the following events:
16866 *
16867 * * element.click
16868 * * element.contextmenu
16869 * * element.dblclick
16870 * * element.hover
16871 * * element.mousedown
16872 * * element.mousemove
16873 * * element.mouseup
16874 * * element.out
16875 *
16876 * Each event is a tuple { element, gfx, originalEvent }.
16877 *
16878 * Canceling the event via Event#preventDefault()
16879 * prevents the original DOM operation.
16880 *
16881 * @param {EventBus} eventBus
16882 */
16883 function InteractionEvents(eventBus, elementRegistry, styles) {
16884
16885 var self = this;
16886
16887 /**
16888 * Fire an interaction event.
16889 *
16890 * @param {String} type local event name, e.g. element.click.
16891 * @param {DOMEvent} event native event
16892 * @param {djs.model.Base} [element] the diagram element to emit the event on;
16893 * defaults to the event target
16894 */
16895 function fire(type, event, element) {
16896
16897 if (isIgnored(type, event)) {
16898 return;
16899 }
16900
16901 var target, gfx, returnValue;
16902
16903 if (!element) {
16904 target = event.delegateTarget || event.target;
16905
16906 if (target) {
16907 gfx = target;
16908 element = elementRegistry.get(gfx);
16909 }
16910 } else {
16911 gfx = elementRegistry.getGraphics(element);
16912 }
16913
16914 if (!gfx || !element) {
16915 return;
16916 }
16917
16918 returnValue = eventBus.fire(type, {
16919 element: element,
16920 gfx: gfx,
16921 originalEvent: event
16922 });
16923
16924 if (returnValue === false) {
16925 event.stopPropagation();
16926 event.preventDefault();
16927 }
16928 }
16929
16930 // TODO(nikku): document this
16931 var handlers = {};
16932
16933 function mouseHandler(localEventName) {
16934 return handlers[localEventName];
16935 }
16936
16937 function isIgnored(localEventName, event) {
16938
16939 var filter = ignoredFilters[localEventName] || isPrimaryButton;
16940
16941 // only react on left mouse button interactions
16942 // except for interaction events that are enabled
16943 // for secundary mouse button
16944 return !filter(event);
16945 }
16946
16947 var bindings = {
16948 click: 'element.click',
16949 contextmenu: 'element.contextmenu',
16950 dblclick: 'element.dblclick',
16951 mousedown: 'element.mousedown',
16952 mousemove: 'element.mousemove',
16953 mouseover: 'element.hover',
16954 mouseout: 'element.out',
16955 mouseup: 'element.mouseup',
16956 };
16957
16958 var ignoredFilters = {
16959 'element.contextmenu': allowAll
16960 };
16961
16962
16963 // manual event trigger //////////
16964
16965 /**
16966 * Trigger an interaction event (based on a native dom event)
16967 * on the target shape or connection.
16968 *
16969 * @param {String} eventName the name of the triggered DOM event
16970 * @param {MouseEvent} event
16971 * @param {djs.model.Base} targetElement
16972 */
16973 function triggerMouseEvent(eventName, event, targetElement) {
16974
16975 // i.e. element.mousedown...
16976 var localEventName = bindings[eventName];
16977
16978 if (!localEventName) {
16979 throw new Error('unmapped DOM event name <' + eventName + '>');
16980 }
16981
16982 return fire(localEventName, event, targetElement);
16983 }
16984
16985
16986 var ELEMENT_SELECTOR = 'svg, .djs-element';
16987
16988 // event handling ///////
16989
16990 function registerEvent(node, event, localEvent, ignoredFilter) {
16991
16992 var handler = handlers[localEvent] = function(event) {
16993 fire(localEvent, event);
16994 };
16995
16996 if (ignoredFilter) {
16997 ignoredFilters[localEvent] = ignoredFilter;
16998 }
16999
17000 handler.$delegate = delegateEvents.bind(node, ELEMENT_SELECTOR, event, handler);
17001 }
17002
17003 function unregisterEvent(node, event, localEvent) {
17004
17005 var handler = mouseHandler(localEvent);
17006
17007 if (!handler) {
17008 return;
17009 }
17010
17011 delegateEvents.unbind(node, event, handler.$delegate);
17012 }
17013
17014 function registerEvents(svg) {
17015 forEach(bindings, function(val, key) {
17016 registerEvent(svg, key, val);
17017 });
17018 }
17019
17020 function unregisterEvents(svg) {
17021 forEach(bindings, function(val, key) {
17022 unregisterEvent(svg, key, val);
17023 });
17024 }
17025
17026 eventBus.on('canvas.destroy', function(event) {
17027 unregisterEvents(event.svg);
17028 });
17029
17030 eventBus.on('canvas.init', function(event) {
17031 registerEvents(event.svg);
17032 });
17033
17034
17035 // hit box updating ////////////////
17036
17037 eventBus.on([ 'shape.added', 'connection.added' ], function(event) {
17038 var element = event.element,
17039 gfx = event.gfx;
17040
17041 eventBus.fire('interactionEvents.createHit', { element: element, gfx: gfx });
17042 });
17043
17044 // Update djs-hit on change.
17045 // A low priortity is necessary, because djs-hit of labels has to be updated
17046 // after the label bounds have been updated in the renderer.
17047 eventBus.on([
17048 'shape.changed',
17049 'connection.changed'
17050 ], LOW_PRIORITY, function(event) {
17051
17052 var element = event.element,
17053 gfx = event.gfx;
17054
17055 eventBus.fire('interactionEvents.updateHit', { element: element, gfx: gfx });
17056 });
17057
17058 eventBus.on('interactionEvents.createHit', LOW_PRIORITY, function(event) {
17059 var element = event.element,
17060 gfx = event.gfx;
17061
17062 self.createDefaultHit(element, gfx);
17063 });
17064
17065 eventBus.on('interactionEvents.updateHit', function(event) {
17066 var element = event.element,
17067 gfx = event.gfx;
17068
17069 self.updateDefaultHit(element, gfx);
17070 });
17071
17072
17073 // hit styles ////////////
17074
17075 var STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-stroke');
17076
17077 var CLICK_STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-click-stroke');
17078
17079 var ALL_HIT_STYLE = createHitStyle('djs-hit djs-hit-all');
17080
17081 var HIT_TYPES = {
17082 'all': ALL_HIT_STYLE,
17083 'click-stroke': CLICK_STROKE_HIT_STYLE,
17084 'stroke': STROKE_HIT_STYLE
17085 };
17086
17087 function createHitStyle(classNames, attrs) {
17088
17089 attrs = assign({
17090 stroke: 'white',
17091 strokeWidth: 15
17092 }, attrs || {});
17093
17094 return styles.cls(classNames, [ 'no-fill', 'no-border' ], attrs);
17095 }
17096
17097
17098 // style helpers ///////////////
17099
17100 function applyStyle(hit, type) {
17101
17102 var attrs = HIT_TYPES[type];
17103
17104 if (!attrs) {
17105 throw new Error('invalid hit type <' + type + '>');
17106 }
17107
17108 attr$1(hit, attrs);
17109
17110 return hit;
17111 }
17112
17113 function appendHit(gfx, hit) {
17114 append(gfx, hit);
17115 }
17116
17117
17118 // API
17119
17120 /**
17121 * Remove hints on the given graphics.
17122 *
17123 * @param {SVGElement} gfx
17124 */
17125 this.removeHits = function(gfx) {
17126 var hits = all('.djs-hit', gfx);
17127
17128 forEach(hits, remove$1);
17129 };
17130
17131 /**
17132 * Create default hit for the given element.
17133 *
17134 * @param {djs.model.Base} element
17135 * @param {SVGElement} gfx
17136 *
17137 * @return {SVGElement} created hit
17138 */
17139 this.createDefaultHit = function(element, gfx) {
17140 var waypoints = element.waypoints,
17141 isFrame = element.isFrame,
17142 boxType;
17143
17144 if (waypoints) {
17145 return this.createWaypointsHit(gfx, waypoints);
17146 } else {
17147
17148 boxType = isFrame ? 'stroke' : 'all';
17149
17150 return this.createBoxHit(gfx, boxType, {
17151 width: element.width,
17152 height: element.height
17153 });
17154 }
17155 };
17156
17157 /**
17158 * Create hits for the given waypoints.
17159 *
17160 * @param {SVGElement} gfx
17161 * @param {Array<Point>} waypoints
17162 *
17163 * @return {SVGElement}
17164 */
17165 this.createWaypointsHit = function(gfx, waypoints) {
17166
17167 var hit = createLine(waypoints);
17168
17169 applyStyle(hit, 'stroke');
17170
17171 appendHit(gfx, hit);
17172
17173 return hit;
17174 };
17175
17176 /**
17177 * Create hits for a box.
17178 *
17179 * @param {SVGElement} gfx
17180 * @param {String} hitType
17181 * @param {Object} attrs
17182 *
17183 * @return {SVGElement}
17184 */
17185 this.createBoxHit = function(gfx, type, attrs) {
17186
17187 attrs = assign({
17188 x: 0,
17189 y: 0
17190 }, attrs);
17191
17192 var hit = create('rect');
17193
17194 applyStyle(hit, type);
17195
17196 attr$1(hit, attrs);
17197
17198 appendHit(gfx, hit);
17199
17200 return hit;
17201 };
17202
17203 /**
17204 * Update default hit of the element.
17205 *
17206 * @param {djs.model.Base} element
17207 * @param {SVGElement} gfx
17208 *
17209 * @return {SVGElement} updated hit
17210 */
17211 this.updateDefaultHit = function(element, gfx) {
17212
17213 var hit = query('.djs-hit', gfx);
17214
17215 if (!hit) {
17216 return;
17217 }
17218
17219 if (element.waypoints) {
17220 updateLine(hit, element.waypoints);
17221 } else {
17222 attr$1(hit, {
17223 width: element.width,
17224 height: element.height
17225 });
17226 }
17227
17228 return hit;
17229 };
17230
17231 this.fire = fire;
17232
17233 this.triggerMouseEvent = triggerMouseEvent;
17234
17235 this.mouseHandler = mouseHandler;
17236
17237 this.registerEvent = registerEvent;
17238 this.unregisterEvent = unregisterEvent;
17239 }
17240
17241
17242 InteractionEvents.$inject = [
17243 'eventBus',
17244 'elementRegistry',
17245 'styles'
17246 ];
17247
17248
17249 /**
17250 * An event indicating that the mouse hovered over an element
17251 *
17252 * @event element.hover
17253 *
17254 * @type {Object}
17255 * @property {djs.model.Base} element
17256 * @property {SVGElement} gfx
17257 * @property {Event} originalEvent
17258 */
17259
17260 /**
17261 * An event indicating that the mouse has left an element
17262 *
17263 * @event element.out
17264 *
17265 * @type {Object}
17266 * @property {djs.model.Base} element
17267 * @property {SVGElement} gfx
17268 * @property {Event} originalEvent
17269 */
17270
17271 /**
17272 * An event indicating that the mouse has clicked an element
17273 *
17274 * @event element.click
17275 *
17276 * @type {Object}
17277 * @property {djs.model.Base} element
17278 * @property {SVGElement} gfx
17279 * @property {Event} originalEvent
17280 */
17281
17282 /**
17283 * An event indicating that the mouse has double clicked an element
17284 *
17285 * @event element.dblclick
17286 *
17287 * @type {Object}
17288 * @property {djs.model.Base} element
17289 * @property {SVGElement} gfx
17290 * @property {Event} originalEvent
17291 */
17292
17293 /**
17294 * An event indicating that the mouse has gone down on an element.
17295 *
17296 * @event element.mousedown
17297 *
17298 * @type {Object}
17299 * @property {djs.model.Base} element
17300 * @property {SVGElement} gfx
17301 * @property {Event} originalEvent
17302 */
17303
17304 /**
17305 * An event indicating that the mouse has gone up on an element.
17306 *
17307 * @event element.mouseup
17308 *
17309 * @type {Object}
17310 * @property {djs.model.Base} element
17311 * @property {SVGElement} gfx
17312 * @property {Event} originalEvent
17313 */
17314
17315 /**
17316 * An event indicating that the context menu action is triggered
17317 * via mouse or touch controls.
17318 *
17319 * @event element.contextmenu
17320 *
17321 * @type {Object}
17322 * @property {djs.model.Base} element
17323 * @property {SVGElement} gfx
17324 * @property {Event} originalEvent
17325 */
17326
17327 var InteractionEventsModule = {
17328 __init__: [ 'interactionEvents' ],
17329 interactionEvents: [ 'type', InteractionEvents ]
17330 };
17331
17332 var LOW_PRIORITY$1 = 500;
17333
17334
17335 /**
17336 * @class
17337 *
17338 * A plugin that adds an outline to shapes and connections that may be activated and styled
17339 * via CSS classes.
17340 *
17341 * @param {EventBus} eventBus
17342 * @param {Styles} styles
17343 * @param {ElementRegistry} elementRegistry
17344 */
17345 function Outline(eventBus, styles, elementRegistry) {
17346
17347 this.offset = 6;
17348
17349 var OUTLINE_STYLE = styles.cls('djs-outline', [ 'no-fill' ]);
17350
17351 var self = this;
17352
17353 function createOutline(gfx, bounds) {
17354 var outline = create('rect');
17355
17356 attr$1(outline, assign({
17357 x: 10,
17358 y: 10,
17359 width: 100,
17360 height: 100
17361 }, OUTLINE_STYLE));
17362
17363 append(gfx, outline);
17364
17365 return outline;
17366 }
17367
17368 // A low priortity is necessary, because outlines of labels have to be updated
17369 // after the label bounds have been updated in the renderer.
17370 eventBus.on([ 'shape.added', 'shape.changed' ], LOW_PRIORITY$1, function(event) {
17371 var element = event.element,
17372 gfx = event.gfx;
17373
17374 var outline = query('.djs-outline', gfx);
17375
17376 if (!outline) {
17377 outline = createOutline(gfx);
17378 }
17379
17380 self.updateShapeOutline(outline, element);
17381 });
17382
17383 eventBus.on([ 'connection.added', 'connection.changed' ], function(event) {
17384 var element = event.element,
17385 gfx = event.gfx;
17386
17387 var outline = query('.djs-outline', gfx);
17388
17389 if (!outline) {
17390 outline = createOutline(gfx);
17391 }
17392
17393 self.updateConnectionOutline(outline, element);
17394 });
17395 }
17396
17397
17398 /**
17399 * Updates the outline of a shape respecting the dimension of the
17400 * element and an outline offset.
17401 *
17402 * @param {SVGElement} outline
17403 * @param {djs.model.Base} element
17404 */
17405 Outline.prototype.updateShapeOutline = function(outline, element) {
17406
17407 attr$1(outline, {
17408 x: -this.offset,
17409 y: -this.offset,
17410 width: element.width + this.offset * 2,
17411 height: element.height + this.offset * 2
17412 });
17413
17414 };
17415
17416
17417 /**
17418 * Updates the outline of a connection respecting the bounding box of
17419 * the connection and an outline offset.
17420 *
17421 * @param {SVGElement} outline
17422 * @param {djs.model.Base} element
17423 */
17424 Outline.prototype.updateConnectionOutline = function(outline, connection) {
17425
17426 var bbox = getBBox(connection);
17427
17428 attr$1(outline, {
17429 x: bbox.x - this.offset,
17430 y: bbox.y - this.offset,
17431 width: bbox.width + this.offset * 2,
17432 height: bbox.height + this.offset * 2
17433 });
17434
17435 };
17436
17437
17438 Outline.$inject = ['eventBus', 'styles', 'elementRegistry'];
17439
17440 var OutlineModule = {
17441 __init__: [ 'outline' ],
17442 outline: [ 'type', Outline ]
17443 };
17444
17445 /**
17446 * A service that offers the current selection in a diagram.
17447 * Offers the api to control the selection, too.
17448 *
17449 * @class
17450 *
17451 * @param {EventBus} eventBus the event bus
17452 */
17453 function Selection(eventBus) {
17454
17455 this._eventBus = eventBus;
17456
17457 this._selectedElements = [];
17458
17459 var self = this;
17460
17461 eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
17462 var element = e.element;
17463 self.deselect(element);
17464 });
17465
17466 eventBus.on([ 'diagram.clear' ], function(e) {
17467 self.select(null);
17468 });
17469 }
17470
17471 Selection.$inject = [ 'eventBus' ];
17472
17473
17474 Selection.prototype.deselect = function(element) {
17475 var selectedElements = this._selectedElements;
17476
17477 var idx = selectedElements.indexOf(element);
17478
17479 if (idx !== -1) {
17480 var oldSelection = selectedElements.slice();
17481
17482 selectedElements.splice(idx, 1);
17483
17484 this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
17485 }
17486 };
17487
17488
17489 Selection.prototype.get = function() {
17490 return this._selectedElements;
17491 };
17492
17493 Selection.prototype.isSelected = function(element) {
17494 return this._selectedElements.indexOf(element) !== -1;
17495 };
17496
17497
17498 /**
17499 * This method selects one or more elements on the diagram.
17500 *
17501 * By passing an additional add parameter you can decide whether or not the element(s)
17502 * should be added to the already existing selection or not.
17503 *
17504 * @method Selection#select
17505 *
17506 * @param {Object|Object[]} elements element or array of elements to be selected
17507 * @param {boolean} [add] whether the element(s) should be appended to the current selection, defaults to false
17508 */
17509 Selection.prototype.select = function(elements, add) {
17510 var selectedElements = this._selectedElements,
17511 oldSelection = selectedElements.slice();
17512
17513 if (!isArray(elements)) {
17514 elements = elements ? [ elements ] : [];
17515 }
17516
17517 // selection may be cleared by passing an empty array or null
17518 // to the method
17519 if (add) {
17520 forEach(elements, function(element) {
17521 if (selectedElements.indexOf(element) !== -1) {
17522
17523 // already selected
17524 return;
17525 } else {
17526 selectedElements.push(element);
17527 }
17528 });
17529 } else {
17530 this._selectedElements = selectedElements = elements.slice();
17531 }
17532
17533 this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
17534 };
17535
17536 var MARKER_HOVER = 'hover',
17537 MARKER_SELECTED = 'selected';
17538
17539
17540 /**
17541 * A plugin that adds a visible selection UI to shapes and connections
17542 * by appending the <code>hover</code> and <code>selected</code> classes to them.
17543 *
17544 * @class
17545 *
17546 * Makes elements selectable, too.
17547 *
17548 * @param {EventBus} events
17549 * @param {SelectionService} selection
17550 * @param {Canvas} canvas
17551 */
17552 function SelectionVisuals(events, canvas, selection, styles) {
17553
17554 this._multiSelectionBox = null;
17555
17556 function addMarker(e, cls) {
17557 canvas.addMarker(e, cls);
17558 }
17559
17560 function removeMarker(e, cls) {
17561 canvas.removeMarker(e, cls);
17562 }
17563
17564 events.on('element.hover', function(event) {
17565 addMarker(event.element, MARKER_HOVER);
17566 });
17567
17568 events.on('element.out', function(event) {
17569 removeMarker(event.element, MARKER_HOVER);
17570 });
17571
17572 events.on('selection.changed', function(event) {
17573
17574 function deselect(s) {
17575 removeMarker(s, MARKER_SELECTED);
17576 }
17577
17578 function select(s) {
17579 addMarker(s, MARKER_SELECTED);
17580 }
17581
17582 var oldSelection = event.oldSelection,
17583 newSelection = event.newSelection;
17584
17585 forEach(oldSelection, function(e) {
17586 if (newSelection.indexOf(e) === -1) {
17587 deselect(e);
17588 }
17589 });
17590
17591 forEach(newSelection, function(e) {
17592 if (oldSelection.indexOf(e) === -1) {
17593 select(e);
17594 }
17595 });
17596 });
17597 }
17598
17599 SelectionVisuals.$inject = [
17600 'eventBus',
17601 'canvas',
17602 'selection',
17603 'styles'
17604 ];
17605
17606 function SelectionBehavior(
17607 eventBus, selection, canvas,
17608 elementRegistry) {
17609
17610 eventBus.on('create.end', 500, function(e) {
17611
17612 var context = e.context,
17613 canExecute = context.canExecute,
17614 elements = context.elements,
17615 hints = context.hints || {},
17616 autoSelect = hints.autoSelect;
17617
17618 // select elements after they have been created
17619 if (canExecute) {
17620 if (autoSelect === false) {
17621
17622 // select no elements
17623 return;
17624 }
17625
17626 if (isArray(autoSelect)) {
17627 selection.select(autoSelect);
17628 } else {
17629
17630 // select all elements by default
17631 selection.select(elements);
17632 }
17633 }
17634 });
17635
17636 eventBus.on('connect.end', 500, function(e) {
17637
17638 // select the connect end target
17639 // after a connect operation
17640 if (e.context.canExecute && e.context.target) {
17641 selection.select(e.context.target);
17642 }
17643 });
17644
17645 eventBus.on('shape.move.end', 500, function(e) {
17646 var previousSelection = e.previousSelection || [];
17647
17648 var shape = elementRegistry.get(e.context.shape.id);
17649
17650 // make sure at least the main moved element is being
17651 // selected after a move operation
17652 var inSelection = find(previousSelection, function(selectedShape) {
17653 return shape.id === selectedShape.id;
17654 });
17655
17656 if (!inSelection) {
17657 selection.select(shape);
17658 }
17659 });
17660
17661 // Shift + click selection
17662 eventBus.on('element.click', function(event) {
17663
17664 var element = event.element;
17665
17666 // do not select the root element
17667 // or connections
17668 if (element === canvas.getRootElement()) {
17669 element = null;
17670 }
17671
17672 var isSelected = selection.isSelected(element),
17673 isMultiSelect = selection.get().length > 1;
17674
17675 // mouse-event: SELECTION_KEY
17676 var add = hasPrimaryModifier(event);
17677
17678 // select OR deselect element in multi selection
17679 if (isSelected && isMultiSelect) {
17680 if (add) {
17681 return selection.deselect(element);
17682 } else {
17683 return selection.select(element);
17684 }
17685 } else
17686 if (!isSelected) {
17687 selection.select(element, add);
17688 } else {
17689 selection.deselect(element);
17690 }
17691 });
17692 }
17693
17694 SelectionBehavior.$inject = [
17695 'eventBus',
17696 'selection',
17697 'canvas',
17698 'elementRegistry'
17699 ];
17700
17701 var SelectionModule = {
17702 __init__: [ 'selectionVisuals', 'selectionBehavior' ],
17703 __depends__: [
17704 InteractionEventsModule,
17705 OutlineModule
17706 ],
17707 selection: [ 'type', Selection ],
17708 selectionVisuals: [ 'type', SelectionVisuals ],
17709 selectionBehavior: [ 'type', SelectionBehavior ]
17710 };
17711
17712 /**
17713 * Util that provides unique IDs.
17714 *
17715 * @class djs.util.IdGenerator
17716 * @constructor
17717 * @memberOf djs.util
17718 *
17719 * The ids can be customized via a given prefix and contain a random value to avoid collisions.
17720 *
17721 * @param {String} prefix a prefix to prepend to generated ids (for better readability)
17722 */
17723 function IdGenerator(prefix) {
17724
17725 this._counter = 0;
17726 this._prefix = (prefix ? prefix + '-' : '') + Math.floor(Math.random() * 1000000000) + '-';
17727 }
17728
17729 /**
17730 * Returns a next unique ID.
17731 *
17732 * @method djs.util.IdGenerator#next
17733 *
17734 * @returns {String} the id
17735 */
17736 IdGenerator.prototype.next = function() {
17737 return this._prefix + (++this._counter);
17738 };
17739
17740 // document wide unique overlay ids
17741 var ids = new IdGenerator('ov');
17742
17743 var LOW_PRIORITY$2 = 500;
17744
17745
17746 /**
17747 * A service that allows users to attach overlays to diagram elements.
17748 *
17749 * The overlay service will take care of overlay positioning during updates.
17750 *
17751 * @example
17752 *
17753 * // add a pink badge on the top left of the shape
17754 * overlays.add(someShape, {
17755 * position: {
17756 * top: -5,
17757 * left: -5
17758 * },
17759 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
17760 * });
17761 *
17762 * // or add via shape id
17763 *
17764 * overlays.add('some-element-id', {
17765 * position: {
17766 * top: -5,
17767 * left: -5
17768 * }
17769 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
17770 * });
17771 *
17772 * // or add with optional type
17773 *
17774 * overlays.add(someShape, 'badge', {
17775 * position: {
17776 * top: -5,
17777 * left: -5
17778 * }
17779 * html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
17780 * });
17781 *
17782 *
17783 * // remove an overlay
17784 *
17785 * var id = overlays.add(...);
17786 * overlays.remove(id);
17787 *
17788 *
17789 * You may configure overlay defaults during tool by providing a `config` module
17790 * with `overlays.defaults` as an entry:
17791 *
17792 * {
17793 * overlays: {
17794 * defaults: {
17795 * show: {
17796 * minZoom: 0.7,
17797 * maxZoom: 5.0
17798 * },
17799 * scale: {
17800 * min: 1
17801 * }
17802 * }
17803 * }
17804 *
17805 * @param {Object} config
17806 * @param {EventBus} eventBus
17807 * @param {Canvas} canvas
17808 * @param {ElementRegistry} elementRegistry
17809 */
17810 function Overlays(config, eventBus, canvas, elementRegistry) {
17811
17812 this._eventBus = eventBus;
17813 this._canvas = canvas;
17814 this._elementRegistry = elementRegistry;
17815
17816 this._ids = ids;
17817
17818 this._overlayDefaults = assign({
17819
17820 // no show constraints
17821 show: null,
17822
17823 // always scale
17824 scale: true
17825 }, config && config.defaults);
17826
17827 /**
17828 * Mapping overlayId -> overlay
17829 */
17830 this._overlays = {};
17831
17832 /**
17833 * Mapping elementId -> overlay container
17834 */
17835 this._overlayContainers = [];
17836
17837 // root html element for all overlays
17838 this._overlayRoot = createRoot(canvas.getContainer());
17839
17840 this._init();
17841 }
17842
17843
17844 Overlays.$inject = [
17845 'config.overlays',
17846 'eventBus',
17847 'canvas',
17848 'elementRegistry'
17849 ];
17850
17851
17852 /**
17853 * Returns the overlay with the specified id or a list of overlays
17854 * for an element with a given type.
17855 *
17856 * @example
17857 *
17858 * // return the single overlay with the given id
17859 * overlays.get('some-id');
17860 *
17861 * // return all overlays for the shape
17862 * overlays.get({ element: someShape });
17863 *
17864 * // return all overlays on shape with type 'badge'
17865 * overlays.get({ element: someShape, type: 'badge' });
17866 *
17867 * // shape can also be specified as id
17868 * overlays.get({ element: 'element-id', type: 'badge' });
17869 *
17870 *
17871 * @param {Object} search
17872 * @param {String} [search.id]
17873 * @param {String|djs.model.Base} [search.element]
17874 * @param {String} [search.type]
17875 *
17876 * @return {Object|Array<Object>} the overlay(s)
17877 */
17878 Overlays.prototype.get = function(search) {
17879
17880 if (isString(search)) {
17881 search = { id: search };
17882 }
17883
17884 if (isString(search.element)) {
17885 search.element = this._elementRegistry.get(search.element);
17886 }
17887
17888 if (search.element) {
17889 var container = this._getOverlayContainer(search.element, true);
17890
17891 // return a list of overlays when searching by element (+type)
17892 if (container) {
17893 return search.type ? filter(container.overlays, matchPattern({ type: search.type })) : container.overlays.slice();
17894 } else {
17895 return [];
17896 }
17897 } else
17898 if (search.type) {
17899 return filter(this._overlays, matchPattern({ type: search.type }));
17900 } else {
17901
17902 // return single element when searching by id
17903 return search.id ? this._overlays[search.id] : null;
17904 }
17905 };
17906
17907 /**
17908 * Adds a HTML overlay to an element.
17909 *
17910 * @param {String|djs.model.Base} element attach overlay to this shape
17911 * @param {String} [type] optional type to assign to the overlay
17912 * @param {Object} overlay the overlay configuration
17913 *
17914 * @param {String|DOMElement} overlay.html html element to use as an overlay
17915 * @param {Object} [overlay.show] show configuration
17916 * @param {Number} [overlay.show.minZoom] minimal zoom level to show the overlay
17917 * @param {Number} [overlay.show.maxZoom] maximum zoom level to show the overlay
17918 * @param {Object} overlay.position where to attach the overlay
17919 * @param {Number} [overlay.position.left] relative to element bbox left attachment
17920 * @param {Number} [overlay.position.top] relative to element bbox top attachment
17921 * @param {Number} [overlay.position.bottom] relative to element bbox bottom attachment
17922 * @param {Number} [overlay.position.right] relative to element bbox right attachment
17923 * @param {Boolean|Object} [overlay.scale=true] false to preserve the same size regardless of
17924 * diagram zoom
17925 * @param {Number} [overlay.scale.min]
17926 * @param {Number} [overlay.scale.max]
17927 *
17928 * @return {String} id that may be used to reference the overlay for update or removal
17929 */
17930 Overlays.prototype.add = function(element, type, overlay) {
17931
17932 if (isObject(type)) {
17933 overlay = type;
17934 type = null;
17935 }
17936
17937 if (!element.id) {
17938 element = this._elementRegistry.get(element);
17939 }
17940
17941 if (!overlay.position) {
17942 throw new Error('must specifiy overlay position');
17943 }
17944
17945 if (!overlay.html) {
17946 throw new Error('must specifiy overlay html');
17947 }
17948
17949 if (!element) {
17950 throw new Error('invalid element specified');
17951 }
17952
17953 var id = this._ids.next();
17954
17955 overlay = assign({}, this._overlayDefaults, overlay, {
17956 id: id,
17957 type: type,
17958 element: element,
17959 html: overlay.html
17960 });
17961
17962 this._addOverlay(overlay);
17963
17964 return id;
17965 };
17966
17967
17968 /**
17969 * Remove an overlay with the given id or all overlays matching the given filter.
17970 *
17971 * @see Overlays#get for filter options.
17972 *
17973 * @param {String} [id]
17974 * @param {Object} [filter]
17975 */
17976 Overlays.prototype.remove = function(filter) {
17977
17978 var overlays = this.get(filter) || [];
17979
17980 if (!isArray(overlays)) {
17981 overlays = [ overlays ];
17982 }
17983
17984 var self = this;
17985
17986 forEach(overlays, function(overlay) {
17987
17988 var container = self._getOverlayContainer(overlay.element, true);
17989
17990 if (overlay) {
17991 remove(overlay.html);
17992 remove(overlay.htmlContainer);
17993
17994 delete overlay.htmlContainer;
17995 delete overlay.element;
17996
17997 delete self._overlays[overlay.id];
17998 }
17999
18000 if (container) {
18001 var idx = container.overlays.indexOf(overlay);
18002 if (idx !== -1) {
18003 container.overlays.splice(idx, 1);
18004 }
18005 }
18006 });
18007
18008 };
18009
18010
18011 Overlays.prototype.show = function() {
18012 setVisible(this._overlayRoot);
18013 };
18014
18015
18016 Overlays.prototype.hide = function() {
18017 setVisible(this._overlayRoot, false);
18018 };
18019
18020 Overlays.prototype.clear = function() {
18021 this._overlays = {};
18022
18023 this._overlayContainers = [];
18024
18025 clear(this._overlayRoot);
18026 };
18027
18028 Overlays.prototype._updateOverlayContainer = function(container) {
18029 var element = container.element,
18030 html = container.html;
18031
18032 // update container left,top according to the elements x,y coordinates
18033 // this ensures we can attach child elements relative to this container
18034
18035 var x = element.x,
18036 y = element.y;
18037
18038 if (element.waypoints) {
18039 var bbox = getBBox(element);
18040 x = bbox.x;
18041 y = bbox.y;
18042 }
18043
18044 setPosition(html, x, y);
18045
18046 attr(container.html, 'data-container-id', element.id);
18047 };
18048
18049
18050 Overlays.prototype._updateOverlay = function(overlay) {
18051
18052 var position = overlay.position,
18053 htmlContainer = overlay.htmlContainer,
18054 element = overlay.element;
18055
18056 // update overlay html relative to shape because
18057 // it is already positioned on the element
18058
18059 // update relative
18060 var left = position.left,
18061 top = position.top;
18062
18063 if (position.right !== undefined) {
18064
18065 var width;
18066
18067 if (element.waypoints) {
18068 width = getBBox(element).width;
18069 } else {
18070 width = element.width;
18071 }
18072
18073 left = position.right * -1 + width;
18074 }
18075
18076 if (position.bottom !== undefined) {
18077
18078 var height;
18079
18080 if (element.waypoints) {
18081 height = getBBox(element).height;
18082 } else {
18083 height = element.height;
18084 }
18085
18086 top = position.bottom * -1 + height;
18087 }
18088
18089 setPosition(htmlContainer, left || 0, top || 0);
18090 };
18091
18092
18093 Overlays.prototype._createOverlayContainer = function(element) {
18094 var html = domify('<div class="djs-overlays" style="position: absolute" />');
18095
18096 this._overlayRoot.appendChild(html);
18097
18098 var container = {
18099 html: html,
18100 element: element,
18101 overlays: []
18102 };
18103
18104 this._updateOverlayContainer(container);
18105
18106 this._overlayContainers.push(container);
18107
18108 return container;
18109 };
18110
18111
18112 Overlays.prototype._updateRoot = function(viewbox) {
18113 var scale = viewbox.scale || 1;
18114
18115 var matrix = 'matrix(' +
18116 [
18117 scale,
18118 0,
18119 0,
18120 scale,
18121 -1 * viewbox.x * scale,
18122 -1 * viewbox.y * scale
18123 ].join(',') +
18124 ')';
18125
18126 setTransform(this._overlayRoot, matrix);
18127 };
18128
18129
18130 Overlays.prototype._getOverlayContainer = function(element, raw) {
18131 var container = find(this._overlayContainers, function(c) {
18132 return c.element === element;
18133 });
18134
18135
18136 if (!container && !raw) {
18137 return this._createOverlayContainer(element);
18138 }
18139
18140 return container;
18141 };
18142
18143
18144 Overlays.prototype._addOverlay = function(overlay) {
18145
18146 var id = overlay.id,
18147 element = overlay.element,
18148 html = overlay.html,
18149 htmlContainer,
18150 overlayContainer;
18151
18152 // unwrap jquery (for those who need it)
18153 if (html.get && html.constructor.prototype.jquery) {
18154 html = html.get(0);
18155 }
18156
18157 // create proper html elements from
18158 // overlay HTML strings
18159 if (isString(html)) {
18160 html = domify(html);
18161 }
18162
18163 overlayContainer = this._getOverlayContainer(element);
18164
18165 htmlContainer = domify('<div class="djs-overlay" data-overlay-id="' + id + '" style="position: absolute">');
18166
18167 htmlContainer.appendChild(html);
18168
18169 if (overlay.type) {
18170 classes(htmlContainer).add('djs-overlay-' + overlay.type);
18171 }
18172
18173 overlay.htmlContainer = htmlContainer;
18174
18175 overlayContainer.overlays.push(overlay);
18176 overlayContainer.html.appendChild(htmlContainer);
18177
18178 this._overlays[id] = overlay;
18179
18180 this._updateOverlay(overlay);
18181 this._updateOverlayVisibilty(overlay, this._canvas.viewbox());
18182 };
18183
18184
18185 Overlays.prototype._updateOverlayVisibilty = function(overlay, viewbox) {
18186 var show = overlay.show,
18187 minZoom = show && show.minZoom,
18188 maxZoom = show && show.maxZoom,
18189 htmlContainer = overlay.htmlContainer,
18190 visible = true;
18191
18192 if (show) {
18193 if (
18194 (isDefined(minZoom) && minZoom > viewbox.scale) ||
18195 (isDefined(maxZoom) && maxZoom < viewbox.scale)
18196 ) {
18197 visible = false;
18198 }
18199
18200 setVisible(htmlContainer, visible);
18201 }
18202
18203 this._updateOverlayScale(overlay, viewbox);
18204 };
18205
18206
18207 Overlays.prototype._updateOverlayScale = function(overlay, viewbox) {
18208 var shouldScale = overlay.scale,
18209 minScale,
18210 maxScale,
18211 htmlContainer = overlay.htmlContainer;
18212
18213 var scale, transform = '';
18214
18215 if (shouldScale !== true) {
18216
18217 if (shouldScale === false) {
18218 minScale = 1;
18219 maxScale = 1;
18220 } else {
18221 minScale = shouldScale.min;
18222 maxScale = shouldScale.max;
18223 }
18224
18225 if (isDefined(minScale) && viewbox.scale < minScale) {
18226 scale = (1 / viewbox.scale || 1) * minScale;
18227 }
18228
18229 if (isDefined(maxScale) && viewbox.scale > maxScale) {
18230 scale = (1 / viewbox.scale || 1) * maxScale;
18231 }
18232 }
18233
18234 if (isDefined(scale)) {
18235 transform = 'scale(' + scale + ',' + scale + ')';
18236 }
18237
18238 setTransform(htmlContainer, transform);
18239 };
18240
18241
18242 Overlays.prototype._updateOverlaysVisibilty = function(viewbox) {
18243
18244 var self = this;
18245
18246 forEach(this._overlays, function(overlay) {
18247 self._updateOverlayVisibilty(overlay, viewbox);
18248 });
18249 };
18250
18251
18252 Overlays.prototype._init = function() {
18253
18254 var eventBus = this._eventBus;
18255
18256 var self = this;
18257
18258
18259 // scroll/zoom integration
18260
18261 function updateViewbox(viewbox) {
18262 self._updateRoot(viewbox);
18263 self._updateOverlaysVisibilty(viewbox);
18264
18265 self.show();
18266 }
18267
18268 eventBus.on('canvas.viewbox.changing', function(event) {
18269 self.hide();
18270 });
18271
18272 eventBus.on('canvas.viewbox.changed', function(event) {
18273 updateViewbox(event.viewbox);
18274 });
18275
18276
18277 // remove integration
18278
18279 eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
18280 var element = e.element;
18281 var overlays = self.get({ element: element });
18282
18283 forEach(overlays, function(o) {
18284 self.remove(o.id);
18285 });
18286
18287 var container = self._getOverlayContainer(element);
18288
18289 if (container) {
18290 remove(container.html);
18291 var i = self._overlayContainers.indexOf(container);
18292 if (i !== -1) {
18293 self._overlayContainers.splice(i, 1);
18294 }
18295 }
18296 });
18297
18298
18299 // move integration
18300
18301 eventBus.on('element.changed', LOW_PRIORITY$2, function(e) {
18302 var element = e.element;
18303
18304 var container = self._getOverlayContainer(element, true);
18305
18306 if (container) {
18307 forEach(container.overlays, function(overlay) {
18308 self._updateOverlay(overlay);
18309 });
18310
18311 self._updateOverlayContainer(container);
18312 }
18313 });
18314
18315
18316 // marker integration, simply add them on the overlays as classes, too.
18317
18318 eventBus.on('element.marker.update', function(e) {
18319 var container = self._getOverlayContainer(e.element, true);
18320 if (container) {
18321 classes(container.html)[e.add ? 'add' : 'remove'](e.marker);
18322 }
18323 });
18324
18325
18326 // clear overlays with diagram
18327
18328 eventBus.on('diagram.clear', this.clear, this);
18329 };
18330
18331
18332
18333 // helpers /////////////////////////////
18334
18335 function createRoot(parentNode) {
18336 var root = domify(
18337 '<div class="djs-overlay-container" style="position: absolute; width: 0; height: 0;" />'
18338 );
18339
18340 parentNode.insertBefore(root, parentNode.firstChild);
18341
18342 return root;
18343 }
18344
18345 function setPosition(el, x, y) {
18346 assign(el.style, { left: x + 'px', top: y + 'px' });
18347 }
18348
18349 function setVisible(el, visible) {
18350 el.style.display = visible === false ? 'none' : '';
18351 }
18352
18353 function setTransform(el, transform) {
18354
18355 el.style['transform-origin'] = 'top left';
18356
18357 [ '', '-ms-', '-webkit-' ].forEach(function(prefix) {
18358 el.style[prefix + 'transform'] = transform;
18359 });
18360 }
18361
18362 var OverlaysModule = {
18363 __init__: [ 'overlays' ],
18364 overlays: [ 'type', Overlays ]
18365 };
18366
18367 /**
18368 * This file must not be changed or exchanged.
18369 *
18370 * @see http://bpmn.io/license for more information.
18371 */
18372
18373
18374 // inlined ../../resources/logo.svg
18375 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>';
18376
18377 var BPMNIO_LOGO_URL = 'data:image/svg+xml,' + encodeURIComponent(BPMNIO_LOGO_SVG);
18378
18379 var BPMNIO_IMG = '<img width="52" height="52" src="' + BPMNIO_LOGO_URL + '" />';
18380
18381 function css(attrs) {
18382 return attrs.join(';');
18383 }
18384
18385 var LIGHTBOX_STYLES = css([
18386 'z-index: 1001',
18387 'position: fixed',
18388 'top: 0',
18389 'left: 0',
18390 'right: 0',
18391 'bottom: 0'
18392 ]);
18393
18394 var BACKDROP_STYLES = css([
18395 'width: 100%',
18396 'height: 100%',
18397 'background: rgba(0,0,0,0.2)'
18398 ]);
18399
18400 var NOTICE_STYLES = css([
18401 'position: absolute',
18402 'left: 50%',
18403 'top: 40%',
18404 'margin: 0 -130px',
18405 'width: 260px',
18406 'padding: 10px',
18407 'background: white',
18408 'border: solid 1px #AAA',
18409 'border-radius: 3px',
18410 'font-family: Helvetica, Arial, sans-serif',
18411 'font-size: 14px',
18412 'line-height: 1.2em'
18413 ]);
18414
18415 var LIGHTBOX_MARKUP =
18416 '<div class="bjs-powered-by-lightbox" style="' + LIGHTBOX_STYLES + '">' +
18417 '<div class="backdrop" style="' + BACKDROP_STYLES + '"></div>' +
18418 '<div class="notice" style="' + NOTICE_STYLES + '">' +
18419 '<a href="http://bpmn.io" target="_blank" style="float: left; margin-right: 10px">' +
18420 BPMNIO_IMG +
18421 '</a>' +
18422 'Web-based tooling for BPMN, DMN and CMMN diagrams ' +
18423 'powered by <a href="http://bpmn.io" target="_blank">bpmn.io</a>.' +
18424 '</div>' +
18425 '</div>';
18426
18427
18428 var lightbox;
18429
18430 function open() {
18431
18432 if (!lightbox) {
18433 lightbox = domify(LIGHTBOX_MARKUP);
18434
18435 delegateEvents.bind(lightbox, '.backdrop', 'click', function(event) {
18436 document.body.removeChild(lightbox);
18437 });
18438 }
18439
18440 document.body.appendChild(lightbox);
18441 }
18442
18443 /**
18444 * The code in the <project-logo></project-logo> area
18445 * must not be changed.
18446 *
18447 * @see http://bpmn.io/license for more information.
18448 */
18449
18450
18451 function checkValidationError(err) {
18452
18453 // check if we can help the user by indicating wrong BPMN 2.0 xml
18454 // (in case he or the exporting tool did not get that right)
18455
18456 var pattern = /unparsable content <([^>]+)> detected([\s\S]*)$/;
18457 var match = pattern.exec(err.message);
18458
18459 if (match) {
18460 err.message =
18461 'unparsable content <' + match[1] + '> detected; ' +
18462 'this may indicate an invalid BPMN 2.0 diagram file' + match[2];
18463 }
18464
18465 return err;
18466 }
18467
18468 var DEFAULT_OPTIONS = {
18469 width: '100%',
18470 height: '100%',
18471 position: 'relative'
18472 };
18473
18474
18475 /**
18476 * Ensure the passed argument is a proper unit (defaulting to px)
18477 */
18478 function ensureUnit(val) {
18479 return val + (isNumber(val) ? 'px' : '');
18480 }
18481
18482
18483 /**
18484 * Find BPMNDiagram in definitions by ID
18485 *
18486 * @param {ModdleElement<Definitions>} definitions
18487 * @param {String} diagramId
18488 *
18489 * @return {ModdleElement<BPMNDiagram>|null}
18490 */
18491 function findBPMNDiagram(definitions, diagramId) {
18492 if (!diagramId) {
18493 return null;
18494 }
18495
18496 return find(definitions.diagrams, function(element) {
18497 return element.id === diagramId;
18498 }) || null;
18499 }
18500
18501 /**
18502 * A viewer for BPMN 2.0 diagrams.
18503 *
18504 * Have a look at {@link NavigatedViewer} or {@link Modeler} for bundles that include
18505 * additional features.
18506 *
18507 *
18508 * ## Extending the Viewer
18509 *
18510 * In order to extend the viewer pass extension modules to bootstrap via the
18511 * `additionalModules` option. An extension module is an object that exposes
18512 * named services.
18513 *
18514 * The following example depicts the integration of a simple
18515 * logging component that integrates with interaction events:
18516 *
18517 *
18518 * ```javascript
18519 *
18520 * // logging component
18521 * function InteractionLogger(eventBus) {
18522 * eventBus.on('element.hover', function(event) {
18523 * console.log()
18524 * })
18525 * }
18526 *
18527 * InteractionLogger.$inject = [ 'eventBus' ]; // minification save
18528 *
18529 * // extension module
18530 * var extensionModule = {
18531 * __init__: [ 'interactionLogger' ],
18532 * interactionLogger: [ 'type', InteractionLogger ]
18533 * };
18534 *
18535 * // extend the viewer
18536 * var bpmnViewer = new Viewer({ additionalModules: [ extensionModule ] });
18537 * bpmnViewer.importXML(...);
18538 * ```
18539 *
18540 * @param {Object} [options] configuration options to pass to the viewer
18541 * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
18542 * @param {String|Number} [options.width] the width of the viewer
18543 * @param {String|Number} [options.height] the height of the viewer
18544 * @param {Object} [options.moddleExtensions] extension packages to provide
18545 * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
18546 * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
18547 */
18548 function Viewer(options) {
18549
18550 options = assign({}, DEFAULT_OPTIONS, options);
18551
18552 this._moddle = this._createModdle(options);
18553
18554 this._container = this._createContainer(options);
18555
18556 /* <project-logo> */
18557
18558 addProjectLogo(this._container);
18559
18560 /* </project-logo> */
18561
18562 this._init(this._container, this._moddle, options);
18563 }
18564
18565 inherits_browser(Viewer, Diagram);
18566
18567
18568 /**
18569 * Parse and render a BPMN 2.0 diagram.
18570 *
18571 * Once finished the viewer reports back the result to the
18572 * provided callback function with (err, warnings).
18573 *
18574 * ## Life-Cycle Events
18575 *
18576 * During import the viewer will fire life-cycle events:
18577 *
18578 * * import.parse.start (about to read model from xml)
18579 * * import.parse.complete (model read; may have worked or not)
18580 * * import.render.start (graphical import start)
18581 * * import.render.complete (graphical import finished)
18582 * * import.done (everything done)
18583 *
18584 * You can use these events to hook into the life-cycle.
18585 *
18586 * @param {String} xml the BPMN 2.0 xml
18587 * @param {ModdleElement<BPMNDiagram>|String} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
18588 * @param {Function} [done] invoked with (err, warnings=[])
18589 */
18590 Viewer.prototype.importXML = function(xml, bpmnDiagram, done) {
18591
18592 if (isFunction(bpmnDiagram)) {
18593 done = bpmnDiagram;
18594 bpmnDiagram = null;
18595 }
18596
18597 // done is optional
18598 done = done || function() {};
18599
18600 var self = this;
18601
18602 // hook in pre-parse listeners +
18603 // allow xml manipulation
18604 xml = this._emit('import.parse.start', { xml: xml }) || xml;
18605
18606 this._moddle.fromXML(xml, 'bpmn:Definitions', function(err, definitions, context) {
18607
18608 // hook in post parse listeners +
18609 // allow definitions manipulation
18610 definitions = self._emit('import.parse.complete', {
18611 error: err,
18612 definitions: definitions,
18613 context: context
18614 }) || definitions;
18615
18616 var parseWarnings = context.warnings;
18617
18618 if (err) {
18619 err = checkValidationError(err);
18620
18621 self._emit('import.done', { error: err, warnings: parseWarnings });
18622
18623 return done(err, parseWarnings);
18624 }
18625
18626 self.importDefinitions(definitions, bpmnDiagram, function(err, importWarnings) {
18627 var allWarnings = [].concat(parseWarnings, importWarnings || []);
18628
18629 self._emit('import.done', { error: err, warnings: allWarnings });
18630
18631 done(err, allWarnings);
18632 });
18633 });
18634 };
18635
18636 /**
18637 * Import parsed definitions and render a BPMN 2.0 diagram.
18638 *
18639 * Once finished the viewer reports back the result to the
18640 * provided callback function with (err, warnings).
18641 *
18642 * ## Life-Cycle Events
18643 *
18644 * During import the viewer will fire life-cycle events:
18645 *
18646 * * import.render.start (graphical import start)
18647 * * import.render.complete (graphical import finished)
18648 *
18649 * You can use these events to hook into the life-cycle.
18650 *
18651 * @param {ModdleElement<Definitions>} definitions parsed BPMN 2.0 definitions
18652 * @param {ModdleElement<BPMNDiagram>|String} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
18653 * @param {Function} [done] invoked with (err, warnings=[])
18654 */
18655 Viewer.prototype.importDefinitions = function(definitions, bpmnDiagram, done) {
18656
18657 if (isFunction(bpmnDiagram)) {
18658 done = bpmnDiagram;
18659 bpmnDiagram = null;
18660 }
18661
18662 // done is optional
18663 done = done || function() {};
18664
18665 this._setDefinitions(definitions);
18666
18667 return this.open(bpmnDiagram, done);
18668 };
18669
18670 /**
18671 * Open diagram of previously imported XML.
18672 *
18673 * Once finished the viewer reports back the result to the
18674 * provided callback function with (err, warnings).
18675 *
18676 * ## Life-Cycle Events
18677 *
18678 * During switch the viewer will fire life-cycle events:
18679 *
18680 * * import.render.start (graphical import start)
18681 * * import.render.complete (graphical import finished)
18682 *
18683 * You can use these events to hook into the life-cycle.
18684 *
18685 * @param {String|ModdleElement<BPMNDiagram>} [bpmnDiagramOrId] id or the diagram to open
18686 * @param {Function} [done] invoked with (err, warnings=[])
18687 */
18688 Viewer.prototype.open = function(bpmnDiagramOrId, done) {
18689
18690 if (isFunction(bpmnDiagramOrId)) {
18691 done = bpmnDiagramOrId;
18692 bpmnDiagramOrId = null;
18693 }
18694
18695 var definitions = this._definitions;
18696 var bpmnDiagram = bpmnDiagramOrId;
18697
18698 // done is optional
18699 done = done || function() {};
18700
18701 if (!definitions) {
18702 return done(new Error('no XML imported'));
18703 }
18704
18705 if (typeof bpmnDiagramOrId === 'string') {
18706 bpmnDiagram = findBPMNDiagram(definitions, bpmnDiagramOrId);
18707
18708 if (!bpmnDiagram) {
18709 return done(new Error('BPMNDiagram <' + bpmnDiagramOrId + '> not found'));
18710 }
18711 }
18712
18713 // clear existing rendered diagram
18714 // catch synchronous exceptions during #clear()
18715 try {
18716 this.clear();
18717 } catch (error) {
18718 return done(error);
18719 }
18720
18721 // perform graphical import
18722 return importBpmnDiagram(this, definitions, bpmnDiagram, done);
18723 };
18724
18725 /**
18726 * Export the currently displayed BPMN 2.0 diagram as
18727 * a BPMN 2.0 XML document.
18728 *
18729 * ## Life-Cycle Events
18730 *
18731 * During XML saving the viewer will fire life-cycle events:
18732 *
18733 * * saveXML.start (before serialization)
18734 * * saveXML.serialized (after xml generation)
18735 * * saveXML.done (everything done)
18736 *
18737 * You can use these events to hook into the life-cycle.
18738 *
18739 * @param {Object} [options] export options
18740 * @param {Boolean} [options.format=false] output formated XML
18741 * @param {Boolean} [options.preamble=true] output preamble
18742 *
18743 * @param {Function} done invoked with (err, xml)
18744 */
18745 Viewer.prototype.saveXML = function(options, done) {
18746
18747 if (!done) {
18748 done = options;
18749 options = {};
18750 }
18751
18752 var self = this;
18753
18754 var definitions = this._definitions;
18755
18756 if (!definitions) {
18757 return done(new Error('no definitions loaded'));
18758 }
18759
18760 // allow to fiddle around with definitions
18761 definitions = this._emit('saveXML.start', {
18762 definitions: definitions
18763 }) || definitions;
18764
18765 this._moddle.toXML(definitions, options, function(err, xml) {
18766
18767 try {
18768 xml = self._emit('saveXML.serialized', {
18769 error: err,
18770 xml: xml
18771 }) || xml;
18772
18773 self._emit('saveXML.done', {
18774 error: err,
18775 xml: xml
18776 });
18777 } catch (e) {
18778 console.error('error in saveXML life-cycle listener', e);
18779 }
18780
18781 done(err, xml);
18782 });
18783 };
18784
18785 /**
18786 * Export the currently displayed BPMN 2.0 diagram as
18787 * an SVG image.
18788 *
18789 * ## Life-Cycle Events
18790 *
18791 * During SVG saving the viewer will fire life-cycle events:
18792 *
18793 * * saveSVG.start (before serialization)
18794 * * saveSVG.done (everything done)
18795 *
18796 * You can use these events to hook into the life-cycle.
18797 *
18798 * @param {Object} [options]
18799 * @param {Function} done invoked with (err, svgStr)
18800 */
18801 Viewer.prototype.saveSVG = function(options, done) {
18802
18803 if (!done) {
18804 done = options;
18805 options = {};
18806 }
18807
18808 this._emit('saveSVG.start');
18809
18810 var svg, err;
18811
18812 try {
18813 var canvas = this.get('canvas');
18814
18815 var contentNode = canvas.getDefaultLayer(),
18816 defsNode = query('defs', canvas._svg);
18817
18818 var contents = innerSVG(contentNode),
18819 defs = defsNode ? '<defs>' + innerSVG(defsNode) + '</defs>' : '';
18820
18821 var bbox = contentNode.getBBox();
18822
18823 svg =
18824 '<?xml version="1.0" encoding="utf-8"?>\n' +
18825 '<!-- created with bpmn-js / http://bpmn.io -->\n' +
18826 '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
18827 '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
18828 'width="' + bbox.width + '" height="' + bbox.height + '" ' +
18829 'viewBox="' + bbox.x + ' ' + bbox.y + ' ' + bbox.width + ' ' + bbox.height + '" version="1.1">' +
18830 defs + contents +
18831 '</svg>';
18832 } catch (e) {
18833 err = e;
18834 }
18835
18836 this._emit('saveSVG.done', {
18837 error: err,
18838 svg: svg
18839 });
18840
18841 done(err, svg);
18842 };
18843
18844 /**
18845 * Get a named diagram service.
18846 *
18847 * @example
18848 *
18849 * var elementRegistry = viewer.get('elementRegistry');
18850 * var startEventShape = elementRegistry.get('StartEvent_1');
18851 *
18852 * @param {String} name
18853 *
18854 * @return {Object} diagram service instance
18855 *
18856 * @method Viewer#get
18857 */
18858
18859 /**
18860 * Invoke a function in the context of this viewer.
18861 *
18862 * @example
18863 *
18864 * viewer.invoke(function(elementRegistry) {
18865 * var startEventShape = elementRegistry.get('StartEvent_1');
18866 * });
18867 *
18868 * @param {Function} fn to be invoked
18869 *
18870 * @return {Object} the functions return value
18871 *
18872 * @method Viewer#invoke
18873 */
18874
18875
18876 Viewer.prototype._setDefinitions = function(definitions) {
18877 this._definitions = definitions;
18878 };
18879
18880 Viewer.prototype.getModules = function() {
18881 return this._modules;
18882 };
18883
18884 /**
18885 * Remove all drawn elements from the viewer.
18886 *
18887 * After calling this method the viewer can still
18888 * be reused for opening another diagram.
18889 *
18890 * @method Viewer#clear
18891 */
18892 Viewer.prototype.clear = function() {
18893
18894 // remove businessObject#di binding
18895 //
18896 // this is necessary, as we establish the bindings
18897 // in the BpmnTreeWalker (and assume none are given
18898 // on reimport)
18899 this.get('elementRegistry').forEach(function(element) {
18900 var bo = element.businessObject;
18901
18902 if (bo && bo.di) {
18903 delete bo.di;
18904 }
18905 });
18906
18907 // remove drawn elements
18908 Diagram.prototype.clear.call(this);
18909 };
18910
18911 /**
18912 * Destroy the viewer instance and remove all its
18913 * remainders from the document tree.
18914 */
18915 Viewer.prototype.destroy = function() {
18916
18917 // diagram destroy
18918 Diagram.prototype.destroy.call(this);
18919
18920 // dom detach
18921 remove(this._container);
18922 };
18923
18924 /**
18925 * Register an event listener
18926 *
18927 * Remove a previously added listener via {@link #off(event, callback)}.
18928 *
18929 * @param {String} event
18930 * @param {Number} [priority]
18931 * @param {Function} callback
18932 * @param {Object} [that]
18933 */
18934 Viewer.prototype.on = function(event, priority, callback, target) {
18935 return this.get('eventBus').on(event, priority, callback, target);
18936 };
18937
18938 /**
18939 * De-register an event listener
18940 *
18941 * @param {String} event
18942 * @param {Function} callback
18943 */
18944 Viewer.prototype.off = function(event, callback) {
18945 this.get('eventBus').off(event, callback);
18946 };
18947
18948 Viewer.prototype.attachTo = function(parentNode) {
18949
18950 if (!parentNode) {
18951 throw new Error('parentNode required');
18952 }
18953
18954 // ensure we detach from the
18955 // previous, old parent
18956 this.detach();
18957
18958 // unwrap jQuery if provided
18959 if (parentNode.get && parentNode.constructor.prototype.jquery) {
18960 parentNode = parentNode.get(0);
18961 }
18962
18963 if (typeof parentNode === 'string') {
18964 parentNode = query(parentNode);
18965 }
18966
18967 parentNode.appendChild(this._container);
18968
18969 this._emit('attach', {});
18970
18971 this.get('canvas').resized();
18972 };
18973
18974 Viewer.prototype.getDefinitions = function() {
18975 return this._definitions;
18976 };
18977
18978 Viewer.prototype.detach = function() {
18979
18980 var container = this._container,
18981 parentNode = container.parentNode;
18982
18983 if (!parentNode) {
18984 return;
18985 }
18986
18987 this._emit('detach', {});
18988
18989 parentNode.removeChild(container);
18990 };
18991
18992 Viewer.prototype._init = function(container, moddle, options) {
18993
18994 var baseModules = options.modules || this.getModules(),
18995 additionalModules = options.additionalModules || [],
18996 staticModules = [
18997 {
18998 bpmnjs: [ 'value', this ],
18999 moddle: [ 'value', moddle ]
19000 }
19001 ];
19002
19003 var diagramModules = [].concat(staticModules, baseModules, additionalModules);
19004
19005 var diagramOptions = assign(omit(options, [ 'additionalModules' ]), {
19006 canvas: assign({}, options.canvas, { container: container }),
19007 modules: diagramModules
19008 });
19009
19010 // invoke diagram constructor
19011 Diagram.call(this, diagramOptions);
19012
19013 if (options && options.container) {
19014 this.attachTo(options.container);
19015 }
19016 };
19017
19018 /**
19019 * Emit an event on the underlying {@link EventBus}
19020 *
19021 * @param {String} type
19022 * @param {Object} event
19023 *
19024 * @return {Object} event processing result (if any)
19025 */
19026 Viewer.prototype._emit = function(type, event) {
19027 return this.get('eventBus').fire(type, event);
19028 };
19029
19030 Viewer.prototype._createContainer = function(options) {
19031
19032 var container = domify('<div class="bjs-container"></div>');
19033
19034 assign(container.style, {
19035 width: ensureUnit(options.width),
19036 height: ensureUnit(options.height),
19037 position: options.position
19038 });
19039
19040 return container;
19041 };
19042
19043 Viewer.prototype._createModdle = function(options) {
19044 var moddleOptions = assign({}, this._moddleExtensions, options.moddleExtensions);
19045
19046 return new simple(moddleOptions);
19047 };
19048
19049 // modules the viewer is composed of
19050 Viewer.prototype._modules = [
19051 CoreModule$1,
19052 TranslateModule,
19053 SelectionModule,
19054 OverlaysModule
19055 ];
19056
19057 // default moddle extensions the viewer is composed of
19058 Viewer.prototype._moddleExtensions = {};
19059
19060 /**
19061 * Adds the project logo to the diagram container as
19062 * required by the bpmn.io license.
19063 *
19064 * @see http://bpmn.io/license
19065 *
19066 * @param {Element} container
19067 */
19068 function addProjectLogo(container) {
19069 var img = BPMNIO_IMG;
19070
19071 var linkMarkup =
19072 '<a href="http://bpmn.io" ' +
19073 'target="_blank" ' +
19074 'class="bjs-powered-by" ' +
19075 'title="Powered by bpmn.io" ' +
19076 'style="position: absolute; bottom: 15px; right: 15px; z-index: 100">' +
19077 img +
19078 '</a>';
19079
19080 var linkElement = domify(linkMarkup);
19081
19082 container.appendChild(linkElement);
19083
19084 componentEvent.bind(linkElement, 'click', function(event) {
19085 open();
19086
19087 event.preventDefault();
19088 });
19089 }
19090
19091 /* </project-logo> */
19092
19093 /**
19094 * Returns true if event was triggered with any modifier
19095 * @param {KeyboardEvent} event
19096 */
19097 function hasModifier(event) {
19098 return (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey);
19099 }
19100
19101 /**
19102 * @param {KeyboardEvent} event
19103 */
19104 function isCmd(event) {
19105
19106 // ensure we don't react to AltGr
19107 // (mapped to CTRL + ALT)
19108 if (event.altKey) {
19109 return false;
19110 }
19111
19112 return event.ctrlKey || event.metaKey;
19113 }
19114
19115 /**
19116 * Checks if key pressed is one of provided keys.
19117 *
19118 * @param {String|String[]} keys
19119 * @param {KeyboardEvent} event
19120 */
19121 function isKey(keys, event) {
19122 keys = isArray(keys) ? keys : [ keys ];
19123
19124 return keys.indexOf(event.key) > -1;
19125 }
19126
19127 /**
19128 * @param {KeyboardEvent} event
19129 */
19130 function isShift(event) {
19131 return event.shiftKey;
19132 }
19133
19134 var KEYDOWN_EVENT = 'keyboard.keydown',
19135 KEYUP_EVENT = 'keyboard.keyup';
19136
19137 var DEFAULT_PRIORITY$1 = 1000;
19138
19139
19140 /**
19141 * A keyboard abstraction that may be activated and
19142 * deactivated by users at will, consuming key events
19143 * and triggering diagram actions.
19144 *
19145 * For keys pressed down, keyboard fires `keyboard.keydown` event.
19146 * The event context contains one field which is `KeyboardEvent` event.
19147 *
19148 * The implementation fires the following key events that allow
19149 * other components to hook into key handling:
19150 *
19151 * - keyboard.bind
19152 * - keyboard.unbind
19153 * - keyboard.init
19154 * - keyboard.destroy
19155 *
19156 * All events contain one field which is node.
19157 *
19158 * A default binding for the keyboard may be specified via the
19159 * `keyboard.bindTo` configuration option.
19160 *
19161 * @param {Config} config
19162 * @param {EventBus} eventBus
19163 */
19164 function Keyboard(config, eventBus) {
19165 var self = this;
19166
19167 this._config = config || {};
19168 this._eventBus = eventBus;
19169
19170 this._keydownHandler = this._keydownHandler.bind(this);
19171 this._keyupHandler = this._keyupHandler.bind(this);
19172
19173 // properly clean dom registrations
19174 eventBus.on('diagram.destroy', function() {
19175 self._fire('destroy');
19176
19177 self.unbind();
19178 });
19179
19180 eventBus.on('diagram.init', function() {
19181 self._fire('init');
19182 });
19183
19184 eventBus.on('attach', function() {
19185 if (config && config.bindTo) {
19186 self.bind(config.bindTo);
19187 }
19188 });
19189
19190 eventBus.on('detach', function() {
19191 self.unbind();
19192 });
19193 }
19194
19195 Keyboard.$inject = [
19196 'config.keyboard',
19197 'eventBus'
19198 ];
19199
19200 Keyboard.prototype._keydownHandler = function(event) {
19201 this._keyHandler(event, KEYDOWN_EVENT);
19202 };
19203
19204 Keyboard.prototype._keyupHandler = function(event) {
19205 this._keyHandler(event, KEYUP_EVENT);
19206 };
19207
19208 Keyboard.prototype._keyHandler = function(event, type) {
19209 var target = event.target,
19210 eventBusResult;
19211
19212 if (isInput(target)) {
19213 return;
19214 }
19215
19216 var context = {
19217 keyEvent: event
19218 };
19219
19220 eventBusResult = this._eventBus.fire(type || KEYDOWN_EVENT, context);
19221
19222 if (eventBusResult) {
19223 event.preventDefault();
19224 }
19225 };
19226
19227 Keyboard.prototype.bind = function(node) {
19228
19229 // make sure that the keyboard is only bound once to the DOM
19230 this.unbind();
19231
19232 this._node = node;
19233
19234 // bind key events
19235 componentEvent.bind(node, 'keydown', this._keydownHandler, true);
19236 componentEvent.bind(node, 'keyup', this._keyupHandler, true);
19237
19238 this._fire('bind');
19239 };
19240
19241 Keyboard.prototype.getBinding = function() {
19242 return this._node;
19243 };
19244
19245 Keyboard.prototype.unbind = function() {
19246 var node = this._node;
19247
19248 if (node) {
19249 this._fire('unbind');
19250
19251 // unbind key events
19252 componentEvent.unbind(node, 'keydown', this._keydownHandler, true);
19253 componentEvent.unbind(node, 'keyup', this._keyupHandler, true);
19254 }
19255
19256 this._node = null;
19257 };
19258
19259 Keyboard.prototype._fire = function(event) {
19260 this._eventBus.fire('keyboard.' + event, { node: this._node });
19261 };
19262
19263 /**
19264 * Add a listener function that is notified with `KeyboardEvent` whenever
19265 * the keyboard is bound and the user presses a key. If no priority is
19266 * provided, the default value of 1000 is used.
19267 *
19268 * @param {Number} [priority]
19269 * @param {Function} listener
19270 * @param {string} type
19271 */
19272 Keyboard.prototype.addListener = function(priority, listener, type) {
19273 if (isFunction(priority)) {
19274 type = listener;
19275 listener = priority;
19276 priority = DEFAULT_PRIORITY$1;
19277 }
19278
19279 this._eventBus.on(type || KEYDOWN_EVENT, priority, listener);
19280 };
19281
19282 Keyboard.prototype.removeListener = function(listener, type) {
19283 this._eventBus.off(type || KEYDOWN_EVENT, listener);
19284 };
19285
19286 Keyboard.prototype.hasModifier = hasModifier;
19287 Keyboard.prototype.isCmd = isCmd;
19288 Keyboard.prototype.isShift = isShift;
19289 Keyboard.prototype.isKey = isKey;
19290
19291
19292
19293 // helpers ///////
19294
19295 function isInput(target) {
19296 return target && (matchesSelector$1(target, 'input, textarea') || target.contentEditable === 'true');
19297 }
19298
19299 var LOW_PRIORITY$3 = 500;
19300
19301
19302 /**
19303 * Adds default keyboard bindings.
19304 *
19305 * This does not pull in any features will bind only actions that
19306 * have previously been registered against the editorActions component.
19307 *
19308 * @param {EventBus} eventBus
19309 * @param {Keyboard} keyboard
19310 */
19311 function KeyboardBindings(eventBus, keyboard) {
19312
19313 var self = this;
19314
19315 eventBus.on('editorActions.init', LOW_PRIORITY$3, function(event) {
19316
19317 var editorActions = event.editorActions;
19318
19319 self.registerBindings(keyboard, editorActions);
19320 });
19321 }
19322
19323 KeyboardBindings.$inject = [
19324 'eventBus',
19325 'keyboard'
19326 ];
19327
19328
19329 /**
19330 * Register available keyboard bindings.
19331 *
19332 * @param {Keyboard} keyboard
19333 * @param {EditorActions} editorActions
19334 */
19335 KeyboardBindings.prototype.registerBindings = function(keyboard, editorActions) {
19336
19337 /**
19338 * Add keyboard binding if respective editor action
19339 * is registered.
19340 *
19341 * @param {String} action name
19342 * @param {Function} fn that implements the key binding
19343 */
19344 function addListener(action, fn) {
19345
19346 if (editorActions.isRegistered(action)) {
19347 keyboard.addListener(fn);
19348 }
19349 }
19350
19351
19352 // undo
19353 // (CTRL|CMD) + Z
19354 addListener('undo', function(context) {
19355
19356 var event = context.keyEvent;
19357
19358 if (isCmd(event) && !isShift(event) && isKey(['z', 'Z'], event)) {
19359 editorActions.trigger('undo');
19360
19361 return true;
19362 }
19363 });
19364
19365 // redo
19366 // CTRL + Y
19367 // CMD + SHIFT + Z
19368 addListener('redo', function(context) {
19369
19370 var event = context.keyEvent;
19371
19372 if (isCmd(event) && (isKey(['y', 'Y'], event) || (isKey(['z', 'Z'], event) && isShift(event)))) {
19373 editorActions.trigger('redo');
19374
19375 return true;
19376 }
19377 });
19378
19379 // copy
19380 // CTRL/CMD + C
19381 addListener('copy', function(context) {
19382
19383 var event = context.keyEvent;
19384
19385 if (isCmd(event) && isKey(['c', 'C'], event)) {
19386 editorActions.trigger('copy');
19387
19388 return true;
19389 }
19390 });
19391
19392 // paste
19393 // CTRL/CMD + V
19394 addListener('paste', function(context) {
19395
19396 var event = context.keyEvent;
19397
19398 if (isCmd(event) && isKey(['v', 'V'], event)) {
19399 editorActions.trigger('paste');
19400
19401 return true;
19402 }
19403 });
19404
19405 // zoom in one step
19406 // CTRL/CMD + +
19407 addListener('stepZoom', function(context) {
19408
19409 var event = context.keyEvent;
19410
19411 if (isKey([ '+', 'Add' ], event) && isCmd(event)) {
19412 editorActions.trigger('stepZoom', { value: 1 });
19413
19414 return true;
19415 }
19416 });
19417
19418 // zoom out one step
19419 // CTRL + -
19420 addListener('stepZoom', function(context) {
19421
19422 var event = context.keyEvent;
19423
19424 if (isKey([ '-', 'Subtract' ], event) && isCmd(event)) {
19425 editorActions.trigger('stepZoom', { value: -1 });
19426
19427 return true;
19428 }
19429 });
19430
19431 // zoom to the default level
19432 // CTRL + 0
19433 addListener('zoom', function(context) {
19434
19435 var event = context.keyEvent;
19436
19437 if (isKey('0', event) && isCmd(event)) {
19438 editorActions.trigger('zoom', { value: 1 });
19439
19440 return true;
19441 }
19442 });
19443
19444 // delete selected element
19445 // DEL
19446 addListener('removeSelection', function(context) {
19447
19448 var event = context.keyEvent;
19449
19450 if (isKey([ 'Delete', 'Del' ], event)) {
19451 editorActions.trigger('removeSelection');
19452
19453 return true;
19454 }
19455 });
19456 };
19457
19458 var KeyboardModule = {
19459 __init__: [ 'keyboard', 'keyboardBindings' ],
19460 keyboard: [ 'type', Keyboard ],
19461 keyboardBindings: [ 'type', KeyboardBindings ]
19462 };
19463
19464 var DEFAULT_CONFIG = {
19465 moveSpeed: 50,
19466 moveSpeedAccelerated: 200
19467 };
19468
19469
19470 /**
19471 * A feature that allows users to move the canvas using the keyboard.
19472 *
19473 * @param {Object} config
19474 * @param {Number} [config.moveSpeed=50]
19475 * @param {Number} [config.moveSpeedAccelerated=200]
19476 * @param {Keyboard} keyboard
19477 * @param {Canvas} canvas
19478 */
19479 function KeyboardMove(
19480 config,
19481 keyboard,
19482 canvas
19483 ) {
19484
19485 var self = this;
19486
19487 this._config = assign({}, DEFAULT_CONFIG, config || {});
19488
19489 keyboard.addListener(arrowsListener);
19490
19491
19492 function arrowsListener(context) {
19493
19494 var event = context.keyEvent,
19495 config = self._config;
19496
19497 if (!keyboard.isCmd(event)) {
19498 return;
19499 }
19500
19501 if (keyboard.isKey([
19502 'ArrowLeft', 'Left',
19503 'ArrowUp', 'Up',
19504 'ArrowDown', 'Down',
19505 'ArrowRight', 'Right'
19506 ], event)) {
19507
19508 var speed = (
19509 keyboard.isShift(event) ?
19510 config.moveSpeedAccelerated :
19511 config.moveSpeed
19512 );
19513
19514 var direction;
19515
19516 switch (event.key) {
19517 case 'ArrowLeft':
19518 case 'Left':
19519 direction = 'left';
19520 break;
19521 case 'ArrowUp':
19522 case 'Up':
19523 direction = 'up';
19524 break;
19525 case 'ArrowRight':
19526 case 'Right':
19527 direction = 'right';
19528 break;
19529 case 'ArrowDown':
19530 case 'Down':
19531 direction = 'down';
19532 break;
19533 }
19534
19535 self.moveCanvas({
19536 speed: speed,
19537 direction: direction
19538 });
19539
19540 return true;
19541 }
19542 }
19543
19544 this.moveCanvas = function(opts) {
19545
19546 var dx = 0,
19547 dy = 0,
19548 speed = opts.speed;
19549
19550 var actualSpeed = speed / Math.min(Math.sqrt(canvas.viewbox().scale), 1);
19551
19552 switch (opts.direction) {
19553 case 'left': // Left
19554 dx = actualSpeed;
19555 break;
19556 case 'up': // Up
19557 dy = actualSpeed;
19558 break;
19559 case 'right': // Right
19560 dx = -actualSpeed;
19561 break;
19562 case 'down': // Down
19563 dy = -actualSpeed;
19564 break;
19565 }
19566
19567 canvas.scroll({
19568 dx: dx,
19569 dy: dy
19570 });
19571 };
19572
19573 }
19574
19575
19576 KeyboardMove.$inject = [
19577 'config.keyboardMove',
19578 'keyboard',
19579 'canvas'
19580 ];
19581
19582 var KeyboardMoveModule = {
19583 __depends__: [
19584 KeyboardModule
19585 ],
19586 __init__: [ 'keyboardMove' ],
19587 keyboardMove: [ 'type', KeyboardMove ]
19588 };
19589
19590 var CURSOR_CLS_PATTERN = /^djs-cursor-.*$/;
19591
19592
19593 function set$1(mode) {
19594 var classes$1 = classes(document.body);
19595
19596 classes$1.removeMatching(CURSOR_CLS_PATTERN);
19597
19598 if (mode) {
19599 classes$1.add('djs-cursor-' + mode);
19600 }
19601 }
19602
19603 function unset() {
19604 set$1(null);
19605 }
19606
19607 var TRAP_PRIORITY = 5000;
19608
19609 /**
19610 * Installs a click trap that prevents a ghost click following a dragging operation.
19611 *
19612 * @return {Function} a function to immediately remove the installed trap.
19613 */
19614 function install(eventBus, eventName) {
19615
19616 eventName = eventName || 'element.click';
19617
19618 function trap() {
19619 return false;
19620 }
19621
19622 eventBus.once(eventName, TRAP_PRIORITY, trap);
19623
19624 return function() {
19625 eventBus.off(eventName, trap);
19626 };
19627 }
19628
19629 function delta(a, b) {
19630 return {
19631 x: a.x - b.x,
19632 y: a.y - b.y
19633 };
19634 }
19635
19636 var THRESHOLD = 15;
19637
19638
19639 /**
19640 * Move the canvas via mouse.
19641 *
19642 * @param {EventBus} eventBus
19643 * @param {Canvas} canvas
19644 */
19645 function MoveCanvas(eventBus, canvas) {
19646
19647 var context;
19648
19649
19650 // listen for move on element mouse down;
19651 // allow others to hook into the event before us though
19652 // (dragging / element moving will do this)
19653 eventBus.on('element.mousedown', 500, function(e) {
19654 return handleStart(e.originalEvent);
19655 });
19656
19657
19658 function handleMove(event) {
19659
19660 var start = context.start,
19661 position = toPoint(event),
19662 delta$1 = delta(position, start);
19663
19664 if (!context.dragging && length(delta$1) > THRESHOLD) {
19665 context.dragging = true;
19666
19667 install(eventBus);
19668
19669 set$1('grab');
19670 }
19671
19672 if (context.dragging) {
19673
19674 var lastPosition = context.last || context.start;
19675
19676 delta$1 = delta(position, lastPosition);
19677
19678 canvas.scroll({
19679 dx: delta$1.x,
19680 dy: delta$1.y
19681 });
19682
19683 context.last = position;
19684 }
19685
19686 // prevent select
19687 event.preventDefault();
19688 }
19689
19690
19691 function handleEnd(event) {
19692 componentEvent.unbind(document, 'mousemove', handleMove);
19693 componentEvent.unbind(document, 'mouseup', handleEnd);
19694
19695 context = null;
19696
19697 unset();
19698 }
19699
19700 function handleStart(event) {
19701
19702 // event is already handled by '.djs-draggable'
19703 if (closest(event.target, '.djs-draggable')) {
19704 return;
19705 }
19706
19707
19708 // reject non-left left mouse button or modifier key
19709 if (event.button || event.ctrlKey || event.shiftKey || event.altKey) {
19710 return;
19711 }
19712
19713 context = {
19714 start: toPoint(event)
19715 };
19716
19717 componentEvent.bind(document, 'mousemove', handleMove);
19718 componentEvent.bind(document, 'mouseup', handleEnd);
19719
19720 // we've handled the event
19721 return true;
19722 }
19723 }
19724
19725
19726 MoveCanvas.$inject = [
19727 'eventBus',
19728 'canvas'
19729 ];
19730
19731
19732
19733 // helpers ///////
19734
19735 function length(point) {
19736 return Math.sqrt(Math.pow(point.x, 2) + Math.pow(point.y, 2));
19737 }
19738
19739 var MoveCanvasModule = {
19740 __init__: [ 'moveCanvas' ],
19741 moveCanvas: [ 'type', MoveCanvas ]
19742 };
19743
19744 /**
19745 * Get the logarithm of x with base 10
19746 * @param {Integer} value
19747 */
19748 function log10(x) {
19749 return Math.log(x) / Math.log(10);
19750 }
19751
19752 /**
19753 * Get step size for given range and number of steps.
19754 *
19755 * @param {Object} range
19756 * @param {number} range.min
19757 * @param {number} range.max
19758 */
19759 function getStepSize(range, steps) {
19760
19761 var minLinearRange = log10(range.min),
19762 maxLinearRange = log10(range.max);
19763
19764 var absoluteLinearRange = Math.abs(minLinearRange) + Math.abs(maxLinearRange);
19765
19766 return absoluteLinearRange / steps;
19767 }
19768
19769 function cap(range, scale) {
19770 return Math.max(range.min, Math.min(range.max, scale));
19771 }
19772
19773 var sign = Math.sign || function(n) {
19774 return n >= 0 ? 1 : -1;
19775 };
19776
19777 var RANGE = { min: 0.2, max: 4 },
19778 NUM_STEPS = 10;
19779
19780 var DELTA_THRESHOLD = 0.1;
19781
19782 var DEFAULT_SCALE = 0.75;
19783
19784 /**
19785 * An implementation of zooming and scrolling within the
19786 * {@link Canvas} via the mouse wheel.
19787 *
19788 * Mouse wheel zooming / scrolling may be disabled using
19789 * the {@link toggle(enabled)} method.
19790 *
19791 * @param {Object} [config]
19792 * @param {Boolean} [config.enabled=true] default enabled state
19793 * @param {Number} [config.scale=.75] scroll sensivity
19794 * @param {EventBus} eventBus
19795 * @param {Canvas} canvas
19796 */
19797 function ZoomScroll(config, eventBus, canvas) {
19798
19799 config = config || {};
19800
19801 this._enabled = false;
19802
19803 this._canvas = canvas;
19804 this._container = canvas._container;
19805
19806 this._handleWheel = bind(this._handleWheel, this);
19807
19808 this._totalDelta = 0;
19809 this._scale = config.scale || DEFAULT_SCALE;
19810
19811 var self = this;
19812
19813 eventBus.on('canvas.init', function(e) {
19814 self._init(config.enabled !== false);
19815 });
19816 }
19817
19818 ZoomScroll.$inject = [
19819 'config.zoomScroll',
19820 'eventBus',
19821 'canvas'
19822 ];
19823
19824 ZoomScroll.prototype.scroll = function scroll(delta) {
19825 this._canvas.scroll(delta);
19826 };
19827
19828
19829 ZoomScroll.prototype.reset = function reset() {
19830 this._canvas.zoom('fit-viewport');
19831 };
19832
19833 /**
19834 * Zoom depending on delta.
19835 *
19836 * @param {number} delta
19837 * @param {Object} position
19838 */
19839 ZoomScroll.prototype.zoom = function zoom(delta, position) {
19840
19841 // zoom with half the step size of stepZoom
19842 var stepSize = getStepSize(RANGE, NUM_STEPS * 2);
19843
19844 // add until threshold reached
19845 this._totalDelta += delta;
19846
19847 if (Math.abs(this._totalDelta) > DELTA_THRESHOLD) {
19848 this._zoom(delta, position, stepSize);
19849
19850 // reset
19851 this._totalDelta = 0;
19852 }
19853 };
19854
19855
19856 ZoomScroll.prototype._handleWheel = function handleWheel(event) {
19857
19858 // event is already handled by '.djs-scrollable'
19859 if (closest(event.target, '.djs-scrollable', true)) {
19860 return;
19861 }
19862
19863 var element = this._container;
19864
19865 event.preventDefault();
19866
19867 // pinch to zoom is mapped to wheel + ctrlKey = true
19868 // in modern browsers (!)
19869
19870 var isZoom = event.ctrlKey;
19871
19872 var isHorizontalScroll = event.shiftKey;
19873
19874 var factor = -1 * this._scale,
19875 delta;
19876
19877 if (isZoom) {
19878 factor *= event.deltaMode === 0 ? 0.020 : 0.32;
19879 } else {
19880 factor *= event.deltaMode === 0 ? 1.0 : 16.0;
19881 }
19882
19883 if (isZoom) {
19884 var elementRect = element.getBoundingClientRect();
19885
19886 var offset = {
19887 x: event.clientX - elementRect.left,
19888 y: event.clientY - elementRect.top
19889 };
19890
19891 delta = (
19892 Math.sqrt(
19893 Math.pow(event.deltaY, 2) +
19894 Math.pow(event.deltaX, 2)
19895 ) * sign(event.deltaY) * factor
19896 );
19897
19898 // zoom in relative to diagram {x,y} coordinates
19899 this.zoom(delta, offset);
19900 } else {
19901
19902 if (isHorizontalScroll) {
19903 delta = {
19904 dx: factor * event.deltaY,
19905 dy: 0
19906 };
19907 } else {
19908 delta = {
19909 dx: factor * event.deltaX,
19910 dy: factor * event.deltaY
19911 };
19912 }
19913
19914 this.scroll(delta);
19915 }
19916 };
19917
19918 /**
19919 * Zoom with fixed step size.
19920 *
19921 * @param {number} delta - Zoom delta (1 for zooming in, -1 for out).
19922 * @param {Object} position
19923 */
19924 ZoomScroll.prototype.stepZoom = function stepZoom(delta, position) {
19925
19926 var stepSize = getStepSize(RANGE, NUM_STEPS);
19927
19928 this._zoom(delta, position, stepSize);
19929 };
19930
19931
19932 /**
19933 * Zoom in/out given a step size.
19934 *
19935 * @param {number} delta
19936 * @param {Object} position
19937 * @param {number} stepSize
19938 */
19939 ZoomScroll.prototype._zoom = function(delta, position, stepSize) {
19940 var canvas = this._canvas;
19941
19942 var direction = delta > 0 ? 1 : -1;
19943
19944 var currentLinearZoomLevel = log10(canvas.zoom());
19945
19946 // snap to a proximate zoom step
19947 var newLinearZoomLevel = Math.round(currentLinearZoomLevel / stepSize) * stepSize;
19948
19949 // increase or decrease one zoom step in the given direction
19950 newLinearZoomLevel += stepSize * direction;
19951
19952 // calculate the absolute logarithmic zoom level based on the linear zoom level
19953 // (e.g. 2 for an absolute x2 zoom)
19954 var newLogZoomLevel = Math.pow(10, newLinearZoomLevel);
19955
19956 canvas.zoom(cap(RANGE, newLogZoomLevel), position);
19957 };
19958
19959
19960 /**
19961 * Toggle the zoom scroll ability via mouse wheel.
19962 *
19963 * @param {Boolean} [newEnabled] new enabled state
19964 */
19965 ZoomScroll.prototype.toggle = function toggle(newEnabled) {
19966
19967 var element = this._container;
19968 var handleWheel = this._handleWheel;
19969
19970 var oldEnabled = this._enabled;
19971
19972 if (typeof newEnabled === 'undefined') {
19973 newEnabled = !oldEnabled;
19974 }
19975
19976 // only react on actual changes
19977 if (oldEnabled !== newEnabled) {
19978
19979 // add or remove wheel listener based on
19980 // changed enabled state
19981 componentEvent[newEnabled ? 'bind' : 'unbind'](element, 'wheel', handleWheel, false);
19982 }
19983
19984 this._enabled = newEnabled;
19985
19986 return newEnabled;
19987 };
19988
19989
19990 ZoomScroll.prototype._init = function(newEnabled) {
19991 this.toggle(newEnabled);
19992 };
19993
19994 var ZoomScrollModule = {
19995 __init__: [ 'zoomScroll' ],
19996 zoomScroll: [ 'type', ZoomScroll ]
19997 };
19998
19999 /**
20000 * A viewer that includes mouse navigation facilities
20001 *
20002 * @param {Object} options
20003 */
20004 function NavigatedViewer(options) {
20005 Viewer.call(this, options);
20006 }
20007
20008 inherits_browser(NavigatedViewer, Viewer);
20009
20010 NavigatedViewer.prototype._navigationModules = [
20011 KeyboardMoveModule,
20012 MoveCanvasModule,
20013 ZoomScrollModule
20014 ];
20015
20016 NavigatedViewer.prototype._modules = [].concat(
20017 NavigatedViewer.prototype._modules,
20018 NavigatedViewer.prototype._navigationModules);
20019
20020 return NavigatedViewer;
20021
20022}));