bpmn-js 9.0.0-subprocesses.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +73 -1
  2. package/dist/assets/bpmn-js.css +113 -0
  3. package/dist/assets/diagram-js.css +82 -78
  4. package/dist/bpmn-modeler.development.js +3402 -2196
  5. package/dist/bpmn-modeler.production.min.js +9 -8
  6. package/dist/bpmn-navigated-viewer.development.js +21207 -20345
  7. package/dist/bpmn-navigated-viewer.production.min.js +22 -20
  8. package/dist/bpmn-viewer.development.js +20401 -19562
  9. package/dist/bpmn-viewer.production.min.js +22 -20
  10. package/lib/BaseViewer.js +1 -1
  11. package/lib/Modeler.js +1 -4
  12. package/lib/Viewer.js +2 -2
  13. package/lib/draw/BpmnRenderer.js +8 -7
  14. package/lib/draw/PathMap.js +2 -2
  15. package/lib/features/auto-resize/BpmnAutoResizeProvider.js +9 -6
  16. package/lib/features/copy-paste/BpmnCopyPaste.js +1 -0
  17. package/lib/features/copy-paste/ModdleCopy.js +19 -2
  18. package/lib/features/di-ordering/BpmnDiOrdering.js +15 -11
  19. package/lib/features/drilldown/DrilldownBreadcrumbs.js +122 -0
  20. package/lib/features/drilldown/DrilldownCentering.js +118 -0
  21. package/lib/features/drilldown/DrilldownOverlayBehavior.js +181 -0
  22. package/lib/features/drilldown/SubprocessCompatibility.js +196 -0
  23. package/lib/features/drilldown/index.js +17 -0
  24. package/lib/features/label-editing/LabelEditingProvider.js +1 -1
  25. package/lib/features/label-editing/cmd/UpdateLabelHandler.js +29 -2
  26. package/lib/features/modeling/BpmnFactory.js +12 -8
  27. package/lib/features/modeling/BpmnUpdater.js +43 -6
  28. package/lib/features/modeling/ElementFactory.js +31 -13
  29. package/lib/features/modeling/behavior/CreateParticipantBehavior.js +59 -84
  30. package/lib/features/modeling/behavior/DropOnFlowBehavior.js +2 -2
  31. package/lib/features/modeling/behavior/RemoveEmbeddedLabelBoundsBehavior.js +34 -0
  32. package/lib/features/modeling/behavior/ResizeBehavior.js +129 -3
  33. package/lib/features/modeling/behavior/SubProcessPlaneBehavior.js +557 -0
  34. package/lib/features/modeling/behavior/ToggleCollapseConnectionBehaviour.js +74 -0
  35. package/lib/features/modeling/behavior/UnclaimIdBehavior.js +3 -1
  36. package/lib/features/modeling/behavior/index.js +27 -18
  37. package/lib/features/modeling/behavior/util/ResizeUtil.js +1 -132
  38. package/lib/features/modeling/cmd/SetColorHandler.js +23 -6
  39. package/lib/features/modeling/cmd/UpdateCanvasRootHandler.js +4 -2
  40. package/lib/features/modeling/util/ModelingUtil.js +2 -20
  41. package/lib/features/ordering/BpmnOrderingProvider.js +3 -3
  42. package/lib/features/palette/PaletteProvider.js +1 -1
  43. package/lib/features/popup-menu/ReplaceMenuProvider.js +1 -1
  44. package/lib/features/replace/BpmnReplace.js +38 -16
  45. package/lib/import/BpmnImporter.js +19 -13
  46. package/lib/import/BpmnTreeWalker.js +2 -2
  47. package/lib/import/Importer.js +134 -14
  48. package/lib/util/DiUtil.js +1 -0
  49. package/lib/util/DrilldownUtil.js +66 -0
  50. package/lib/util/ModelUtil.js +19 -0
  51. package/package.json +2 -2
  52. package/test/util/MockEvents.js +10 -2
  53. package/lib/features/collapsed-subprocesses/DeleteBehaviour.js +0 -65
  54. package/lib/features/collapsed-subprocesses/ToggleCollapseBehaviour.js +0 -133
  55. package/lib/features/collapsed-subprocesses/diagramFactory.js +0 -56
  56. package/lib/features/collapsed-subprocesses/index.js +0 -12
  57. package/lib/features/collapsed-subprocesses-navigation/CollapsedSubprocessNavigation.js +0 -198
  58. package/lib/features/collapsed-subprocesses-navigation/index.js +0 -7
@@ -0,0 +1,196 @@
1
+
2
+ import { asBounds, asTRBL } from 'diagram-js/lib/layout/LayoutUtil';
3
+ import { is } from '../../util/ModelUtil';
4
+
5
+ var DEFAULT_POSITION = {
6
+ x: 180,
7
+ y: 160
8
+ };
9
+
10
+ /**
11
+ * Hook into `import.render.start` and create new planes for diagrams with
12
+ * collapsed subprocesses and all dis on the same plane.
13
+ *
14
+ * @param {eventBus} eventBus
15
+ * @param {moddle} moddle
16
+ */
17
+ export default function SubprocessCompatibility(eventBus, moddle) {
18
+ this._eventBus = eventBus;
19
+ this._moddle = moddle;
20
+
21
+ var self = this;
22
+
23
+ eventBus.on('import.render.start', 1500, function(e, context) {
24
+ self.handleImport(context.definitions);
25
+ });
26
+ }
27
+
28
+ SubprocessCompatibility.prototype.handleImport = function(definitions) {
29
+ if (!definitions.diagrams) {
30
+ return;
31
+ }
32
+
33
+ var self = this;
34
+ this._definitions = definitions;
35
+ this._processToDiagramMap = {};
36
+
37
+ definitions.diagrams.forEach(function(diagram) {
38
+ if (!diagram.plane || !diagram.plane.bpmnElement) {
39
+ return;
40
+ }
41
+
42
+ self._processToDiagramMap[diagram.plane.bpmnElement.id] = diagram;
43
+ });
44
+
45
+ var newDiagrams = [];
46
+ definitions.diagrams.forEach(function(diagram) {
47
+ var createdDiagrams = self.createNewDiagrams(diagram.plane);
48
+ Array.prototype.push.apply(newDiagrams, createdDiagrams);
49
+ });
50
+
51
+ newDiagrams.forEach(function(diagram) {
52
+ self.movePlaneElementsToOrigin(diagram.plane);
53
+ });
54
+ };
55
+
56
+
57
+ /**
58
+ * Moves all DI elements from collapsed subprocesses to a new plane.
59
+ *
60
+ * @param {Object} plane
61
+ * @return {Array} new diagrams created for the collapsed subprocesses
62
+ */
63
+ SubprocessCompatibility.prototype.createNewDiagrams = function(plane) {
64
+ var self = this;
65
+
66
+ var collapsedElements = [];
67
+ var elementsToMove = [];
68
+
69
+ plane.get('planeElement').forEach(function(diElement) {
70
+ var bo = diElement.bpmnElement;
71
+ var parent = bo.$parent;
72
+
73
+ if (is(bo, 'bpmn:SubProcess') && !diElement.isExpanded) {
74
+ collapsedElements.push(bo);
75
+ }
76
+
77
+ if (is(parent, 'bpmn:SubProcess') && parent !== plane.bpmnElement) {
78
+
79
+ // don't change the array while we iterate over it
80
+ elementsToMove.push({ diElement: diElement, parent: parent });
81
+ }
82
+ });
83
+
84
+ var newDiagrams = [];
85
+
86
+ // create new planes for all collapsed subprocesses, even when they are empty
87
+ collapsedElements.forEach(function(element) {
88
+ if (!self._processToDiagramMap[element.id]) {
89
+ var diagram = self.createDiagram(element);
90
+ self._processToDiagramMap[element.id] = diagram;
91
+ newDiagrams.push(diagram);
92
+ }
93
+ });
94
+
95
+ elementsToMove.forEach(function(element) {
96
+ var diElement = element.diElement;
97
+ var parent = element.parent;
98
+
99
+ // parent is expanded, get nearest collapsed parent
100
+ while (parent && !collapsedElements.includes(parent)) {
101
+ parent = parent.$parent;
102
+ }
103
+
104
+ // false positive, all parents are expanded
105
+ if (!parent) {
106
+ return;
107
+ }
108
+
109
+ var diagram = self._processToDiagramMap[parent.id];
110
+ self.moveToDiPlane(diElement, diagram.plane);
111
+ });
112
+
113
+ return newDiagrams;
114
+ };
115
+
116
+ SubprocessCompatibility.prototype.movePlaneElementsToOrigin = function(plane) {
117
+ var elements = plane.get('planeElement');
118
+
119
+ // get bounding box of all elements
120
+ var planeBounds = getPlaneBounds(plane);
121
+
122
+ var offset = {
123
+ x: planeBounds.x - DEFAULT_POSITION.x,
124
+ y: planeBounds.y - DEFAULT_POSITION.y
125
+ };
126
+
127
+ elements.forEach(function(diElement) {
128
+ if (diElement.waypoint) {
129
+ diElement.waypoint.forEach(function(waypoint) {
130
+ waypoint.x = waypoint.x - offset.x;
131
+ waypoint.y = waypoint.y - offset.y;
132
+ });
133
+ } else if (diElement.bounds) {
134
+ diElement.bounds.x = diElement.bounds.x - offset.x;
135
+ diElement.bounds.y = diElement.bounds.y - offset.y;
136
+ }
137
+ });
138
+ };
139
+
140
+
141
+ SubprocessCompatibility.prototype.moveToDiPlane = function(diElement, newPlane) {
142
+ var containingDiagram = findRootDiagram(diElement);
143
+
144
+ // remove DI from old Plane and add it to the new one
145
+ var parentPlaneElement = containingDiagram.plane.get('planeElement');
146
+ parentPlaneElement.splice(parentPlaneElement.indexOf(diElement), 1);
147
+ newPlane.get('planeElement').push(diElement);
148
+ };
149
+
150
+
151
+ SubprocessCompatibility.prototype.createDiagram = function(bo) {
152
+ var plane = this._moddle.create('bpmndi:BPMNPlane', { bpmnElement: bo });
153
+ var diagram = this._moddle.create('bpmndi:BPMNDiagram', {
154
+ plane: plane
155
+ });
156
+ plane.$parent = diagram;
157
+ plane.bpmnElement = bo;
158
+ diagram.$parent = this._definitions;
159
+ this._definitions.diagrams.push(diagram);
160
+ return diagram;
161
+ };
162
+
163
+ SubprocessCompatibility.$inject = [ 'eventBus', 'moddle' ];
164
+
165
+
166
+ // helpers
167
+
168
+ function findRootDiagram(element) {
169
+ if (is(element, 'bpmndi:BPMNDiagram')) {
170
+ return element;
171
+ } else {
172
+ return findRootDiagram(element.$parent);
173
+ }
174
+ }
175
+
176
+ function getPlaneBounds(plane) {
177
+ var planeTrbl = {
178
+ top: Infinity,
179
+ right: -Infinity,
180
+ bottom: -Infinity,
181
+ left: Infinity
182
+ };
183
+
184
+ plane.planeElement.forEach(function(element) {
185
+ if (!element.bounds) {
186
+ return;
187
+ }
188
+
189
+ var trbl = asTRBL(element.bounds);
190
+
191
+ planeTrbl.top = Math.min(trbl.top, planeTrbl.top);
192
+ planeTrbl.left = Math.min(trbl.left, planeTrbl.left);
193
+ });
194
+
195
+ return asBounds(planeTrbl);
196
+ }
@@ -0,0 +1,17 @@
1
+ import OverlaysModule from 'diagram-js/lib/features/overlays';
2
+ import ChangeSupportModule from 'diagram-js/lib/features/change-support';
3
+ import RootElementsModule from 'diagram-js/lib/features/root-elements';
4
+
5
+ import DrilldownBreadcrumbs from './DrilldownBreadcrumbs';
6
+ import DrilldownCentering from './DrilldownCentering';
7
+ import SubprocessCompatibility from './SubprocessCompatibility';
8
+ import DrilldownOverlayBehavior from './DrilldownOverlayBehavior';
9
+
10
+ export default {
11
+ __depends__: [ OverlaysModule, ChangeSupportModule, RootElementsModule ],
12
+ __init__: [ 'drilldownBreadcrumbs', 'drilldownOverlayBehavior', 'drilldownCentering', 'subprocessCompatibility'],
13
+ drilldownBreadcrumbs: [ 'type', DrilldownBreadcrumbs ],
14
+ drilldownCentering: [ 'type', DrilldownCentering ],
15
+ drilldownOverlayBehavior: [ 'type', DrilldownOverlayBehavior ],
16
+ subprocessCompatibility: [ 'type', SubprocessCompatibility ]
17
+ };
@@ -105,7 +105,7 @@ export default function LabelEditingProvider(
105
105
 
106
106
  function activateDirectEdit(element, force) {
107
107
  if (force ||
108
- isAny(element, [ 'bpmn:Task', 'bpmn:TextAnnotation', 'bpmn:Group' ]) ||
108
+ isAny(element, [ 'bpmn:Task', 'bpmn:TextAnnotation' ]) ||
109
109
  isCollapsedSubProcess(element)) {
110
110
 
111
111
  directEditing.activate(element);
@@ -11,6 +11,7 @@ import {
11
11
  } from '../../../util/LabelUtil';
12
12
 
13
13
  import {
14
+ getDi,
14
15
  is
15
16
  } from '../../../util/ModelUtil';
16
17
 
@@ -23,7 +24,30 @@ var NULL_DIMENSIONS = {
23
24
  /**
24
25
  * A handler that updates the text of a BPMN element.
25
26
  */
26
- export default function UpdateLabelHandler(modeling, textRenderer) {
27
+ export default function UpdateLabelHandler(modeling, textRenderer, bpmnFactory) {
28
+
29
+ /**
30
+ * Creates an empty `diLabel` attribute for embedded labels.
31
+ *
32
+ * @param {djs.model.Base} element
33
+ * @param {string} text
34
+ */
35
+ function ensureInternalLabelDi(element, text) {
36
+ if (isLabelExternal(element)) {
37
+ return;
38
+ }
39
+
40
+ var di = getDi(element);
41
+
42
+ if (text && !di.label) {
43
+ di.label = bpmnFactory.create('bpmndi:BPMNLabel');
44
+ }
45
+
46
+ if (!text && di.label) {
47
+ di.label = null;
48
+ }
49
+ }
50
+
27
51
 
28
52
  /**
29
53
  * Set the label and return the changed elements.
@@ -42,6 +66,8 @@ export default function UpdateLabelHandler(modeling, textRenderer) {
42
66
 
43
67
  setLabel(label, text, labelTarget !== label);
44
68
 
69
+ ensureInternalLabelDi(element, text);
70
+
45
71
  return [ label, labelTarget ];
46
72
  }
47
73
 
@@ -127,7 +153,8 @@ export default function UpdateLabelHandler(modeling, textRenderer) {
127
153
 
128
154
  UpdateLabelHandler.$inject = [
129
155
  'modeling',
130
- 'textRenderer'
156
+ 'textRenderer',
157
+ 'bpmnFactory'
131
158
  ];
132
159
 
133
160
 
@@ -42,6 +42,10 @@ BpmnFactory.prototype._needsId = function(element) {
42
42
  };
43
43
 
44
44
  BpmnFactory.prototype._ensureId = function(element) {
45
+ if (element.id) {
46
+ this._model.ids.claim(element.id, element);
47
+ return;
48
+ }
45
49
 
46
50
  // generate semantic ids for elements
47
51
  // bpmn:SequenceFlow -> SequenceFlow_ID
@@ -83,11 +87,10 @@ BpmnFactory.prototype.createDiLabel = function() {
83
87
  };
84
88
 
85
89
 
86
- BpmnFactory.prototype.createDiShape = function(semantic, bounds, attrs) {
87
-
90
+ BpmnFactory.prototype.createDiShape = function(semantic, attrs) {
88
91
  return this.create('bpmndi:BPMNShape', assign({
89
92
  bpmnElement: semantic,
90
- bounds: this.createDiBounds(bounds)
93
+ bounds: this.createDiBounds()
91
94
  }, attrs));
92
95
  };
93
96
 
@@ -110,14 +113,15 @@ BpmnFactory.prototype.createDiWaypoint = function(point) {
110
113
  };
111
114
 
112
115
 
113
- BpmnFactory.prototype.createDiEdge = function(semantic, waypoints, attrs) {
116
+ BpmnFactory.prototype.createDiEdge = function(semantic, attrs) {
114
117
  return this.create('bpmndi:BPMNEdge', assign({
115
- bpmnElement: semantic
118
+ bpmnElement: semantic,
119
+ waypoint: this.createDiWaypoints([])
116
120
  }, attrs));
117
121
  };
118
122
 
119
- BpmnFactory.prototype.createDiPlane = function(semantic) {
120
- return this.create('bpmndi:BPMNPlane', {
123
+ BpmnFactory.prototype.createDiPlane = function(semantic, attrs) {
124
+ return this.create('bpmndi:BPMNPlane', assign({
121
125
  bpmnElement: semantic
122
- });
126
+ }, attrs));
123
127
  };
@@ -24,6 +24,10 @@ import {
24
24
  isAny
25
25
  } from './util/ModelingUtil';
26
26
 
27
+ import {
28
+ delta
29
+ } from 'diagram-js/lib/util/PositionUtil';
30
+
27
31
  import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
28
32
 
29
33
  /**
@@ -344,7 +348,18 @@ BpmnUpdater.prototype.updateParent = function(element, oldParent) {
344
348
 
345
349
  BpmnUpdater.prototype.updateBounds = function(shape) {
346
350
 
347
- var di = getDi(shape);
351
+ var di = getDi(shape),
352
+ embeddedLabelBounds = getEmbeddedLabelBounds(shape);
353
+
354
+ // update embedded label bounds if possible
355
+ if (embeddedLabelBounds) {
356
+ var embeddedLabelBoundsDelta = delta(embeddedLabelBounds, di.get('bounds'));
357
+
358
+ assign(embeddedLabelBounds, {
359
+ x: shape.x + embeddedLabelBoundsDelta.x,
360
+ y: shape.y + embeddedLabelBoundsDelta.y
361
+ });
362
+ }
348
363
 
349
364
  var target = (shape instanceof Label) ? this._getLabel(di) : di;
350
365
 
@@ -410,11 +425,6 @@ BpmnUpdater.prototype.updateDiParent = function(di, parentDi) {
410
425
  return;
411
426
  }
412
427
 
413
- // Cover the case where di.$parent === undefined and parentDi === null
414
- if (!parentDi && !di.$parent) {
415
- return;
416
- }
417
-
418
428
  var planeElements = (parentDi || di.$parent).get('planeElement');
419
429
 
420
430
  if (parentDi) {
@@ -723,3 +733,30 @@ function ifBpmn(fn) {
723
733
  }
724
734
  };
725
735
  }
736
+
737
+ /**
738
+ * Return dc:Bounds of bpmndi:BPMNLabel if exists.
739
+ *
740
+ * @param {djs.model.shape} shape
741
+ *
742
+ * @returns {Object|undefined}
743
+ */
744
+ function getEmbeddedLabelBounds(shape) {
745
+ if (!is(shape, 'bpmn:Activity')) {
746
+ return;
747
+ }
748
+
749
+ var di = getDi(shape);
750
+
751
+ if (!di) {
752
+ return;
753
+ }
754
+
755
+ var label = di.get('label');
756
+
757
+ if (!label) {
758
+ return;
759
+ }
760
+
761
+ return label.get('bounds');
762
+ }
@@ -12,6 +12,10 @@ import {
12
12
  is
13
13
  } from '../../util/ModelUtil';
14
14
 
15
+ import {
16
+ isAny
17
+ } from '../modeling/util/ModelingUtil';
18
+
15
19
  import {
16
20
  isExpanded
17
21
  } from '../../util/DiUtil';
@@ -80,20 +84,19 @@ ElementFactory.prototype.createBpmnElement = function(elementType, attrs) {
80
84
  ensureCompatDiRef(businessObject);
81
85
  }
82
86
 
83
- if (!di) {
87
+ if (!isModdleDi(di)) {
88
+ var diAttrs = assign(
89
+ di || {},
90
+ { id: businessObject.id + '_di' }
91
+ );
92
+
84
93
  if (elementType === 'root') {
85
- di = this._bpmnFactory.createDiPlane(businessObject, [], {
86
- id: businessObject.id + '_di'
87
- });
94
+ di = this._bpmnFactory.createDiPlane(businessObject, diAttrs);
88
95
  } else
89
96
  if (elementType === 'connection') {
90
- di = this._bpmnFactory.createDiEdge(businessObject, [], {
91
- id: businessObject.id + '_di'
92
- });
97
+ di = this._bpmnFactory.createDiEdge(businessObject, diAttrs);
93
98
  } else {
94
- di = this._bpmnFactory.createDiShape(businessObject, {}, {
95
- id: businessObject.id + '_di'
96
- });
99
+ di = this._bpmnFactory.createDiShape(businessObject, diAttrs);
97
100
  }
98
101
  }
99
102
 
@@ -114,6 +117,10 @@ ElementFactory.prototype.createBpmnElement = function(elementType, attrs) {
114
117
  applyAttribute(di, attrs, 'isExpanded');
115
118
  }
116
119
 
120
+ if (is(businessObject, 'bpmn:SubProcess')) {
121
+ attrs.collapsed = !isExpanded(businessObject, di);
122
+ }
123
+
117
124
  if (is(businessObject, 'bpmn:ExclusiveGateway')) {
118
125
  di.isMarkerVisible = true;
119
126
  }
@@ -140,10 +147,11 @@ ElementFactory.prototype.createBpmnElement = function(elementType, attrs) {
140
147
  size = this.getDefaultSize(businessObject, di);
141
148
 
142
149
  attrs = assign({
143
- businessObject: businessObject,
144
- di: di,
145
150
  id: businessObject.id
146
- }, size, attrs);
151
+ }, size, attrs, {
152
+ businessObject: businessObject,
153
+ di: di
154
+ });
147
155
 
148
156
  return this.baseCreate(elementType, attrs);
149
157
  };
@@ -261,4 +269,14 @@ function applyAttribute(element, attrs, attributeName) {
261
269
  element[attributeName] = attrs[attributeName];
262
270
 
263
271
  delete attrs[attributeName];
272
+ }
273
+
274
+
275
+ function isModdleDi(element) {
276
+ return isAny(element, [
277
+ 'bpmndi:BPMNShape',
278
+ 'bpmndi:BPMNEdge',
279
+ 'bpmndi:BPMNDiagram',
280
+ 'bpmndi:BPMNPlane',
281
+ ]);
264
282
  }
@@ -2,7 +2,7 @@ import inherits from 'inherits';
2
2
 
3
3
  import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
4
4
 
5
- import { is } from '../../../util/ModelUtil';
5
+ import { getBusinessObject, is } from '../../../util/ModelUtil';
6
6
 
7
7
  import { isLabel } from '../../../util/LabelUtil';
8
8
 
@@ -88,122 +88,97 @@ export default function CreateParticipantBehavior(canvas, eventBus, modeling) {
88
88
  }
89
89
  });
90
90
 
91
- function ensureCollaboration(context) {
92
- var parent = context.parent,
93
- collaboration;
94
-
91
+ // turn process into collaboration when creating first participant
92
+ function getOrCreateCollaboration() {
95
93
  var rootElement = canvas.getRootElement();
96
94
 
97
95
  if (is(rootElement, 'bpmn:Collaboration')) {
98
- collaboration = rootElement;
99
- } else {
100
-
101
- // update root element by making collaboration
102
- collaboration = modeling.makeCollaboration();
103
-
104
- // re-use process when creating first participant
105
- context.process = parent;
96
+ return rootElement;
106
97
  }
107
98
 
108
- context.parent = collaboration;
99
+ return modeling.makeCollaboration();
109
100
  }
110
101
 
111
- // turn process into collaboration before adding participant
112
- this.preExecute('shape.create', function(context) {
113
- var parent = context.parent,
114
- shape = context.shape;
115
-
116
- if (is(shape, 'bpmn:Participant') && is(parent, 'bpmn:Process')) {
117
- ensureCollaboration(context);
118
- }
119
- }, true);
120
-
121
- this.execute('shape.create', function(context) {
122
- var process = context.process,
123
- shape = context.shape;
124
-
125
- if (process) {
126
- context.oldProcessRef = shape.businessObject.processRef;
127
-
128
- // re-use process when creating first participant
129
- shape.businessObject.processRef = process.businessObject;
130
- }
131
- }, true);
102
+ // when creating mutliple elements through `elements.create` parent must be set to collaboration
103
+ // and passed to `shape.create` as hint
104
+ this.preExecute('elements.create', HIGH_PRIORITY, function(context) {
105
+ var elements = context.elements,
106
+ parent = context.parent,
107
+ participant = findParticipant(elements),
108
+ hints;
132
109
 
133
- this.revert('shape.create', function(context) {
134
- var process = context.process,
135
- shape = context.shape;
110
+ if (participant && is(parent, 'bpmn:Process')) {
111
+ context.parent = getOrCreateCollaboration();
136
112
 
137
- if (process) {
113
+ hints = context.hints = context.hints || {};
138
114
 
139
- // re-use process when creating first participant
140
- shape.businessObject.processRef = context.oldProcessRef;
115
+ hints.participant = participant;
116
+ hints.process = parent;
117
+ hints.processRef = getBusinessObject(participant).get('processRef');
141
118
  }
142
119
  }, true);
143
120
 
144
- this.postExecute('shape.create', function(context) {
145
- var process = context.process,
121
+ // when creating single shape through `shape.create` parent must be set to collaboration
122
+ // unless it was already set through `elements.create`
123
+ this.preExecute('shape.create', function(context) {
124
+ var parent = context.parent,
146
125
  shape = context.shape;
147
126
 
148
- if (process) {
149
-
150
- // move children from process to participant
151
- var processChildren = process.children.slice();
127
+ if (is(shape, 'bpmn:Participant') && is(parent, 'bpmn:Process')) {
128
+ context.parent = getOrCreateCollaboration();
152
129
 
153
- modeling.moveElements(processChildren, { x: 0, y: 0 }, shape);
130
+ context.process = parent;
131
+ context.processRef = getBusinessObject(shape).get('processRef');
154
132
  }
155
-
156
133
  }, true);
157
134
 
158
- // turn process into collaboration when creating participants
159
- this.preExecute('elements.create', HIGH_PRIORITY, function(context) {
160
- var elements = context.elements,
161
- parent = context.parent,
162
- participant;
163
-
164
- var hasParticipants = findParticipant(elements);
165
-
166
- if (hasParticipants && is(parent, 'bpmn:Process')) {
167
- ensureCollaboration(context);
168
-
169
- participant = findParticipant(elements);
135
+ // #execute necessary because #preExecute not called on CommandStack#redo
136
+ this.execute('shape.create', function(context) {
137
+ var hints = context.hints || {},
138
+ process = context.process || hints.process,
139
+ shape = context.shape,
140
+ participant = hints.participant;
170
141
 
171
- context.oldProcessRef = participant.businessObject.processRef;
142
+ // both shape.create and elements.create must be handled
143
+ if (process && (!participant || shape === participant)) {
172
144
 
173
- // re-use process when creating first participant
174
- participant.businessObject.processRef = parent.businessObject;
145
+ // monkey-patch process ref
146
+ getBusinessObject(shape).set('processRef', getBusinessObject(process));
175
147
  }
176
148
  }, true);
177
149
 
178
- this.revert('elements.create', function(context) {
179
- var elements = context.elements,
180
- process = context.process,
181
- participant;
150
+ this.revert('shape.create', function(context) {
151
+ var hints = context.hints || {},
152
+ process = context.process || hints.process,
153
+ processRef = context.processRef || hints.processRef,
154
+ shape = context.shape,
155
+ participant = hints.participant;
182
156
 
183
- if (process) {
184
- participant = findParticipant(elements);
157
+ // both shape.create and elements.create must be handled
158
+ if (process && (!participant || shape === participant)) {
185
159
 
186
- // re-use process when creating first participant
187
- participant.businessObject.processRef = context.oldProcessRef;
160
+ // monkey-patch process ref
161
+ getBusinessObject(shape).set('processRef', processRef);
188
162
  }
189
163
  }, true);
190
164
 
191
- this.postExecute('elements.create', function(context) {
192
- var elements = context.elements,
193
- process = context.process,
194
- participant;
165
+ this.postExecute('shape.create', function(context) {
166
+ var hints = context.hints || {},
167
+ process = context.process || context.hints.process,
168
+ shape = context.shape,
169
+ participant = hints.participant;
195
170
 
196
171
  if (process) {
197
- participant = findParticipant(elements);
198
-
199
- // move children from process to first participant
200
- var processChildren = process.children.slice();
201
-
202
- modeling.moveElements(processChildren, { x: 0, y: 0 }, participant);
172
+ var children = process.children.slice();
173
+
174
+ // both shape.create and elements.create must be handled
175
+ if (!participant) {
176
+ modeling.moveElements(children, { x: 0, y: 0 }, shape);
177
+ } else if (shape === participant) {
178
+ modeling.moveElements(children, { x: 0, y: 0 }, participant);
179
+ }
203
180
  }
204
-
205
181
  }, true);
206
-
207
182
  }
208
183
 
209
184
  CreateParticipantBehavior.$inject = [
@@ -59,12 +59,12 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) {
59
59
  dockingPoint = intersection.bendpoint ? waypoints[intersection.index] : mid;
60
60
 
61
61
  // if last waypointBefore is inside shape's bounds, ignore docking point
62
- if (!isPointInsideBBox(shape, waypointsBefore[waypointsBefore.length-1])) {
62
+ if (waypointsBefore.length === 1 || !isPointInsideBBox(shape, waypointsBefore[waypointsBefore.length-1])) {
63
63
  waypointsBefore.push(copy(dockingPoint));
64
64
  }
65
65
 
66
66
  // if first waypointAfter is inside shape's bounds, ignore docking point
67
- if (!isPointInsideBBox(shape, waypointsAfter[0])) {
67
+ if (waypointsAfter.length === 1 || !isPointInsideBBox(shape, waypointsAfter[0])) {
68
68
  waypointsAfter.unshift(copy(dockingPoint));
69
69
  }
70
70
  }