diff --git a/lib/features/modeling/behavior/DropOnFlowBehavior.js b/lib/features/modeling/behavior/DropOnFlowBehavior.js
index 6ef66e7a..9e0b8980 100644
--- a/lib/features/modeling/behavior/DropOnFlowBehavior.js
+++ b/lib/features/modeling/behavior/DropOnFlowBehavior.js
@@ -2,7 +2,8 @@ import inherits from 'inherits';
import {
assign,
- find
+ find,
+ filter
} from 'min-dash';
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
@@ -23,7 +24,15 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) {
function insertShape(shape, targetFlow, position) {
var waypoints = targetFlow.waypoints,
- waypointsBefore, waypointsAfter, dockingPoint, source, target, reconnected;
+ waypointsBefore,
+ waypointsAfter,
+ dockingPoint,
+ source,
+ target,
+ incomingConnection,
+ outgoingConnection,
+ oldOutgoing = shape.outgoing.slice(),
+ oldIncoming = shape.incoming.slice();
var intersection = getApproxIntersection(waypoints, position);
@@ -56,18 +65,37 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) {
// reconnect source -> inserted shape
modeling.reconnectEnd(targetFlow, shape, waypointsBefore || position);
- reconnected = true;
+ incomingConnection = targetFlow;
}
if (bpmnRules.canConnect(shape, target, targetFlow)) {
- if (!reconnected) {
+ if (!incomingConnection) {
// reconnect inserted shape -> end
modeling.reconnectStart(targetFlow, shape, waypointsAfter || position);
+
+ outgoingConnection = targetFlow;
} else {
- modeling.connect(shape, target, { type: targetFlow.type, waypoints: waypointsAfter });
+ outgoingConnection = modeling.connect(
+ shape, target, { type: targetFlow.type, waypoints: waypointsAfter }
+ );
}
}
+
+ var duplicateConnections = [].concat(
+
+ incomingConnection && filter(oldIncoming, function(connection) {
+ return connection.source === incomingConnection.source;
+ }) || [],
+
+ outgoingConnection && filter(oldOutgoing, function(connection) {
+ return connection.source === outgoingConnection.source;
+ }) || []
+ );
+
+ if (duplicateConnections.length) {
+ modeling.removeElements(duplicateConnections);
+ }
}
this.preExecute('elements.move', function(context) {
diff --git a/test/spec/features/modeling/behavior/DropOnFlowBehavior.bpmn b/test/spec/features/modeling/behavior/DropOnFlowBehavior.bpmn
index 59e6a830..67050aa7 100644
--- a/test/spec/features/modeling/behavior/DropOnFlowBehavior.bpmn
+++ b/test/spec/features/modeling/behavior/DropOnFlowBehavior.bpmn
@@ -3,9 +3,11 @@
SequenceFlow_1
+ SequenceFlow_3
SequenceFlow_1
+ SequenceFlow_4
SequenceFlow_2
@@ -17,6 +19,12 @@
+
+ SequenceFlow_3
+ SequenceFlow_4
+
+
+
@@ -27,10 +35,10 @@
-
-
-
-
+
+
+
+
@@ -53,19 +61,31 @@
-
+
-
-
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/spec/features/modeling/behavior/DropOnFlowBehaviorSpec.js b/test/spec/features/modeling/behavior/DropOnFlowBehaviorSpec.js
index 4c467145..bb9652b0 100644
--- a/test/spec/features/modeling/behavior/DropOnFlowBehaviorSpec.js
+++ b/test/spec/features/modeling/behavior/DropOnFlowBehaviorSpec.js
@@ -69,11 +69,11 @@ describe('modeling/behavior - drop on connection', function() {
// new outgoing connection
expect(newShape.outgoing.length).to.equal(1);
- expect(targetConnection).to.be.ok;
+ expect(targetConnection).to.exist;
expect(targetConnection.type).to.equal('bpmn:SequenceFlow');
expect(startEvent.outgoing[0]).to.equal(newShape.incoming[0]);
- expect(task.incoming[0]).to.equal(newShape.outgoing[0]);
+ expect(task.incoming[1]).to.equal(newShape.outgoing[0]);
// split target at insertion point
expect(sequenceFlow).to.have.waypoints(flatten([
@@ -259,11 +259,11 @@ describe('modeling/behavior - drop on connection', function() {
// new outgoing connection
expect(intermediateThrowEvent.outgoing.length).to.equal(1);
- expect(targetConnection).to.be.ok;
+ expect(targetConnection).to.exist;
expect(targetConnection.type).to.equal('bpmn:SequenceFlow');
expect(startEvent.outgoing[0]).to.equal(intermediateThrowEvent.incoming[0]);
- expect(task.incoming[0]).to.equal(intermediateThrowEvent.outgoing[0]);
+ expect(task.incoming[1]).to.equal(intermediateThrowEvent.outgoing[0]);
// split target at insertion point
expect(sequenceFlow).to.have.waypoints(flatten([
@@ -319,11 +319,11 @@ describe('modeling/behavior - drop on connection', function() {
// new outgoing connection
expect(intermediateThrowEvent.outgoing.length).to.equal(1);
- expect(targetConnection).to.be.ok;
+ expect(targetConnection).to.exist;
expect(targetConnection.type).to.equal('bpmn:SequenceFlow');
expect(startEvent.outgoing[0]).to.equal(intermediateThrowEvent.incoming[0]);
- expect(task.incoming[0]).to.equal(intermediateThrowEvent.outgoing[0]);
+ expect(task.incoming[1]).to.equal(intermediateThrowEvent.outgoing[0]);
// split target at insertion point
expect(sequenceFlow).to.have.waypoints(flatten([
@@ -561,6 +561,40 @@ describe('modeling/behavior - drop on connection', function() {
}
));
+
+ it('should remove redundant flows', inject(
+ function(elementRegistry, selection, move, dragging) {
+
+ var existingIncoming = elementRegistry.get('SequenceFlow_3'),
+ existingOutgoing = elementRegistry.get('SequenceFlow_4');
+
+ // given
+ var element = elementRegistry.get('Task_4');
+
+ var targetFlow = elementRegistry.get('SequenceFlow_1'),
+ targetFlowGfx = elementRegistry.getGraphics(targetFlow);
+
+ // when
+ selection.select(element);
+
+ move.start(canvasEvent({ x: 0, y: 0 }), element);
+
+ dragging.hover({
+ element: targetFlow,
+ gfx: targetFlowGfx
+ });
+
+ dragging.move(canvasEvent({ x: -40, y: 179 }));
+
+ dragging.end();
+
+ // then
+ // existing connections are removed, as they are duplicates
+ expect(element.incoming).not.to.contain(existingIncoming);
+ expect(element.outgoing).not.to.contain(existingOutgoing);
+ }
+ ));
+
});
});