feat(DropOnFlowBehavior): drop existing elements on flows

Closes #695
This commit is contained in:
pedesen 2017-07-27 13:40:21 +02:00
parent b1a544b84f
commit 58207e7db2
3 changed files with 164 additions and 18 deletions

View File

@ -2,7 +2,8 @@
var inherits = require('inherits');
var assign = require('lodash/object/assign');
var assign = require('lodash/object/assign'),
find = require('lodash/collection/find');
var CommandInterceptor = require('diagram-js/lib/command/CommandInterceptor');
@ -85,24 +86,40 @@ function DropOnFlow(eventBus, bpmnRules, modeling) {
this.preExecute('elements.move', function(context) {
var parent = context.newParent,
var newParent = context.newParent,
shapes = context.shapes,
shape,
shapeMid,
delta = context.delta;
if (bpmnRules.canInsert(shapes, parent)) {
delta = context.delta,
shape = shapes[0];
shapeMid = getMid(shape);
context.targetFlow = parent;
context.newParent = parent.parent;
context.position = {
if (!shape || !newParent) {
return;
}
// if the new parent is a connection,
// change it to the new parent's parent
if (newParent && newParent.waypoints) {
context.newParent = newParent = newParent.parent;
}
var shapeMid = getMid(shape);
var newShapeMid = {
x: shapeMid.x + delta.x,
y: shapeMid.y + delta.y
};
// find a connection which intersects with the
// element's mid point
var connection = find(newParent.children, function(element) {
var canInsert = bpmnRules.canInsert(shapes, element);
return canInsert && getApproxIntersection(element.waypoints, newShapeMid);
});
if (connection) {
context.targetFlow = connection;
context.position = newShapeMid;
}
}, true);
this.postExecuted('elements.move', function(context) {

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.6.0">
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.9.0-dev">
<bpmn:process id="Process" isExecutable="false">
<bpmn:startEvent id="StartEvent">
<bpmn:outgoing>SequenceFlow_1</bpmn:outgoing>
@ -16,6 +16,7 @@
<bpmn:incoming>SequenceFlow_2</bpmn:incoming>
</bpmn:task>
<bpmn:sequenceFlow id="SequenceFlow_2" name="FOO BAR" sourceRef="Task_1" targetRef="Task_2" />
<bpmn:task id="Task_3" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process">
@ -62,6 +63,9 @@
<dc:Bounds x="675" y="274" width="50" height="12" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Task_00wmo3b_di" bpmnElement="Task_3">
<dc:Bounds x="141" y="371" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -13,7 +13,6 @@ var coreModule = require('../../../../../lib/core'),
var canvasEvent = require('../../../../util/MockEvents').createCanvasEvent;
describe('modeling/behavior - drop on connection', function() {
var diagramXML = require('./DropOnFlowBehavior.bpmn');
@ -264,6 +263,132 @@ describe('modeling/behavior - drop on connection', function() {
}));
it('should connect start -> target -> end (hovering parent)',
inject(function(dragging, move, elementRegistry, selection, canvas) {
// given
var intermediateThrowEvent = elementRegistry.get('IntermediateThrowEvent_foo');
var startEvent = elementRegistry.get('StartEvent'),
sequenceFlow = elementRegistry.get('SequenceFlow_1'),
task = elementRegistry.get('Task_1'),
rootElement = canvas.getRootElement(),
rootElementGfx = elementRegistry.getGraphics(rootElement);
var originalWaypoints = sequenceFlow.waypoints;
// when
selection.select(intermediateThrowEvent);
move.start(canvasEvent({ x: 0, y: 0 }), intermediateThrowEvent);
dragging.hover({
element: rootElement,
gfx: rootElementGfx
});
dragging.move(canvasEvent({ x: 150, y: 0 }));
dragging.end();
// then
var targetConnection = intermediateThrowEvent.outgoing[0];
// new incoming connection
expect(intermediateThrowEvent.incoming.length).to.equal(1);
expect(intermediateThrowEvent.incoming[0]).to.eql(sequenceFlow);
// new outgoing connection
expect(intermediateThrowEvent.outgoing.length).to.equal(1);
expect(targetConnection).to.be.ok;
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]);
// split target at insertion point
expect(sequenceFlow).to.have.waypoints(flatten([
originalWaypoints.slice(0, 2),
{ x: 341, y: 192 }
]));
expect(sequenceFlow).to.have.endDocking({ x: 341, y: 210 });
expect(targetConnection).to.have.waypoints(flatten([
{ x: 341, y: 228 },
originalWaypoints.slice(2)
]));
expect(targetConnection).to.have.startDocking({ x: 341, y: 210 });
}
));
it('should connect start -> target -> end (with bendpointBefore inside bbox)',
inject(function(elementRegistry, selection, move, dragging) {
// given
var task3 = elementRegistry.get('Task_3'),
sequenceFlow = elementRegistry.get('SequenceFlow_1'),
sequenceFlowGfx = elementRegistry.getGraphics(sequenceFlow),
originalWaypoints = sequenceFlow.waypoints;
// when
selection.select(task3);
move.start(canvasEvent({ x: 0, y: 0 }), task3);
dragging.hover({
element: sequenceFlow,
gfx: sequenceFlowGfx
});
dragging.move(canvasEvent({ x: 150, y: -130 }));
dragging.end();
// then
// split target but don't keep insertion point
expect(sequenceFlow).to.have.waypoints(flatten([
originalWaypoints.slice(0, 2),
{ x: 341, y: 241 }
]));
expect(sequenceFlow).to.have.endDocking({ x: 341, y: 281 });
}
));
it('should connect start -> target -> end (with bendpointAfter inside bbox)',
inject(function(elementRegistry, selection, move, dragging) {
// given
var task3 = elementRegistry.get('Task_3'),
sequenceFlow = elementRegistry.get('SequenceFlow_1'),
sequenceFlowGfx = elementRegistry.getGraphics(sequenceFlow),
originalWaypoints = sequenceFlow.waypoints;
// when
selection.select(task3);
move.start(canvasEvent({ x: 0, y: 0 }), task3);
dragging.hover({
element: sequenceFlow,
gfx: sequenceFlowGfx
});
dragging.move(canvasEvent({ x: 170, y: -110 }));
dragging.end();
// then
// split target but don't keep insertion point
expect(sequenceFlow).to.have.waypoints(flatten([
originalWaypoints.slice(0, 2),
{ x: 340, y: 261 }
]));
expect(sequenceFlow).to.have.endDocking({ x: 340, y: 299 });
}
));
it('should connect start -> target', inject(function(modeling, elementRegistry, selection, move, dragging) {
// given