feat(modeling): add move onto sequence flow
This adds the ability to move flow nodes onto existing sequence flows (similar to the create on flow behavior implemented with an earlier bpmn-js release). Closes camunda/camunda-modeler#432
This commit is contained in:
parent
6dc4af5396
commit
def402971c
|
@ -1,95 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var inherits = require('inherits');
|
||||
|
||||
var assign = require('lodash/object/assign');
|
||||
|
||||
var CommandInterceptor = require('diagram-js/lib/command/CommandInterceptor');
|
||||
|
||||
var getApproxIntersection = require('diagram-js/lib/util/LineIntersection').getApproxIntersection;
|
||||
|
||||
|
||||
function copy(obj) {
|
||||
return assign({}, obj);
|
||||
}
|
||||
|
||||
function CreateOnFlowBehavior(eventBus, bpmnRules, modeling) {
|
||||
|
||||
CommandInterceptor.call(this, eventBus);
|
||||
|
||||
/**
|
||||
* Reconnect start / end of a connection after
|
||||
* dropping an element on a flow.
|
||||
*/
|
||||
|
||||
this.preExecute('shape.create', function(context) {
|
||||
|
||||
var parent = context.parent,
|
||||
shape = context.shape;
|
||||
|
||||
if (bpmnRules.canInsert(shape, parent)) {
|
||||
context.targetFlow = parent;
|
||||
context.parent = parent.parent;
|
||||
}
|
||||
}, true);
|
||||
|
||||
|
||||
this.postExecute('shape.create', function(context) {
|
||||
|
||||
var shape = context.shape,
|
||||
targetFlow = context.targetFlow,
|
||||
position = context.position,
|
||||
source,
|
||||
target,
|
||||
reconnected,
|
||||
intersection,
|
||||
waypoints,
|
||||
waypointsBefore,
|
||||
waypointsAfter,
|
||||
dockingPoint;
|
||||
|
||||
if (targetFlow) {
|
||||
|
||||
waypoints = targetFlow.waypoints;
|
||||
|
||||
|
||||
intersection = getApproxIntersection(waypoints, position);
|
||||
|
||||
if (intersection) {
|
||||
waypointsBefore = waypoints.slice(0, intersection.index);
|
||||
waypointsAfter = waypoints.slice(intersection.index + (intersection.bendpoint ? 1 : 0));
|
||||
|
||||
dockingPoint = intersection.bendpoint ? waypoints[intersection.index] : position;
|
||||
|
||||
waypointsBefore.push(copy(dockingPoint));
|
||||
waypointsAfter.unshift(copy(dockingPoint));
|
||||
}
|
||||
|
||||
source = targetFlow.source;
|
||||
target = targetFlow.target;
|
||||
|
||||
if (bpmnRules.canConnect(source, shape, targetFlow)) {
|
||||
// reconnect source -> inserted shape
|
||||
modeling.reconnectEnd(targetFlow, shape, waypointsBefore || copy(position));
|
||||
|
||||
reconnected = true;
|
||||
}
|
||||
|
||||
if (bpmnRules.canConnect(shape, target, targetFlow)) {
|
||||
|
||||
if (!reconnected) {
|
||||
// reconnect inserted shape -> end
|
||||
modeling.reconnectStart(targetFlow, shape, waypointsAfter || copy(position));
|
||||
} else {
|
||||
modeling.connect(shape, target, { type: targetFlow.type, waypoints: waypointsAfter });
|
||||
}
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
inherits(CreateOnFlowBehavior, CommandInterceptor);
|
||||
|
||||
CreateOnFlowBehavior.$inject = [ 'eventBus', 'bpmnRules', 'modeling' ];
|
||||
|
||||
module.exports = CreateOnFlowBehavior;
|
|
@ -0,0 +1,121 @@
|
|||
'use strict';
|
||||
|
||||
var inherits = require('inherits');
|
||||
|
||||
var assign = require('lodash/object/assign');
|
||||
|
||||
var CommandInterceptor = require('diagram-js/lib/command/CommandInterceptor');
|
||||
|
||||
var getApproxIntersection = require('diagram-js/lib/util/LineIntersection').getApproxIntersection;
|
||||
|
||||
|
||||
function copy(obj) {
|
||||
return assign({}, obj);
|
||||
}
|
||||
|
||||
function DropOnFlow(eventBus, bpmnRules, modeling) {
|
||||
|
||||
CommandInterceptor.call(this, eventBus);
|
||||
|
||||
/**
|
||||
* Reconnect start / end of a connection after
|
||||
* dropping an element on a flow.
|
||||
*/
|
||||
|
||||
function insertShape(shape, targetFlow, position) {
|
||||
var waypoints = targetFlow.waypoints,
|
||||
waypointsBefore, waypointsAfter, dockingPoint, source, target, reconnected;
|
||||
|
||||
var intersection = getApproxIntersection(waypoints, position);
|
||||
|
||||
if (intersection) {
|
||||
waypointsBefore = waypoints.slice(0, intersection.index);
|
||||
waypointsAfter = waypoints.slice(intersection.index + (intersection.bendpoint ? 1 : 0));
|
||||
|
||||
dockingPoint = intersection.bendpoint ? waypoints[intersection.index] : position;
|
||||
|
||||
waypointsBefore.push(copy(dockingPoint));
|
||||
waypointsAfter.unshift(copy(dockingPoint));
|
||||
}
|
||||
|
||||
source = targetFlow.source;
|
||||
target = targetFlow.target;
|
||||
|
||||
if (bpmnRules.canConnect(source, shape, targetFlow)) {
|
||||
// reconnect source -> inserted shape
|
||||
modeling.reconnectEnd(targetFlow, shape, waypointsBefore || position);
|
||||
|
||||
reconnected = true;
|
||||
}
|
||||
|
||||
if (bpmnRules.canConnect(shape, target, targetFlow)) {
|
||||
|
||||
if (!reconnected) {
|
||||
// reconnect inserted shape -> end
|
||||
modeling.reconnectStart(targetFlow, shape, waypointsAfter || position);
|
||||
} else {
|
||||
modeling.connect(shape, target, { type: targetFlow.type, waypoints: waypointsAfter });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eventBus.on('shape.move.move', 250, function(event) {
|
||||
|
||||
var context = event.context,
|
||||
target = context.target,
|
||||
targetFlow = context.targetFlow,
|
||||
shape = context.shape,
|
||||
shapes = context.shapes;
|
||||
|
||||
if (shapes.length === 1 && bpmnRules.canInsert(shape, target)) {
|
||||
context.targetFlow = target;
|
||||
context.target = target.parent;
|
||||
} else if (targetFlow) {
|
||||
context.targetFlow = context.flowParent = null;
|
||||
}
|
||||
});
|
||||
|
||||
eventBus.on('shape.move.end', 250, function(event) {
|
||||
|
||||
var context = event.context,
|
||||
shape = context.shape,
|
||||
targetFlow = context.targetFlow,
|
||||
position = {
|
||||
x: shape.x + (shape.width / 2),
|
||||
y: shape.y + (shape.height / 2)
|
||||
};
|
||||
|
||||
if (targetFlow) {
|
||||
insertShape(shape, targetFlow, position);
|
||||
}
|
||||
}, true);
|
||||
|
||||
this.preExecute('shape.create', function(context) {
|
||||
|
||||
var parent = context.parent,
|
||||
shape = context.shape;
|
||||
|
||||
if (bpmnRules.canInsert(shape, parent)) {
|
||||
context.targetFlow = parent;
|
||||
context.parent = parent.parent;
|
||||
}
|
||||
}, true);
|
||||
|
||||
|
||||
this.postExecute('shape.create', function(context) {
|
||||
|
||||
var shape = context.shape,
|
||||
targetFlow = context.targetFlow,
|
||||
position = context.position;
|
||||
|
||||
if (targetFlow) {
|
||||
insertShape(shape, targetFlow, position);
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
inherits(DropOnFlow, CommandInterceptor);
|
||||
|
||||
DropOnFlow.$inject = [ 'eventBus', 'bpmnRules', 'modeling' ];
|
||||
|
||||
module.exports = DropOnFlow;
|
|
@ -4,7 +4,7 @@ module.exports = {
|
|||
'copyPasteBehavior',
|
||||
'createBoundaryEventBehavior',
|
||||
'createDataObjectBehavior',
|
||||
'createOnFlowBehavior',
|
||||
'dropOnFlowBehavior',
|
||||
'createParticipantBehavior',
|
||||
'dataInputAssociationBehavior',
|
||||
'deleteLaneBehavior',
|
||||
|
@ -25,7 +25,7 @@ module.exports = {
|
|||
copyPasteBehavior: [ 'type', require('./CopyPasteBehavior') ],
|
||||
createBoundaryEventBehavior: [ 'type', require('./CreateBoundaryEventBehavior') ],
|
||||
createDataObjectBehavior: [ 'type', require('./CreateDataObjectBehavior') ],
|
||||
createOnFlowBehavior: [ 'type', require('./CreateOnFlowBehavior') ],
|
||||
dropOnFlowBehavior: [ 'type', require('./DropOnFlowBehavior') ],
|
||||
createParticipantBehavior: [ 'type', require('./CreateParticipantBehavior') ],
|
||||
dataInputAssociationBehavior: [ 'type', require('./DataInputAssociationBehavior') ],
|
||||
deleteLaneBehavior: [ 'type', require('./DeleteLaneBehavior') ],
|
||||
|
|
|
@ -83,7 +83,8 @@ BpmnRules.prototype.init = function() {
|
|||
|
||||
return canAttach(shapes, target, null, position) ||
|
||||
canReplace(shapes, target, position) ||
|
||||
canMove(shapes, target, position);
|
||||
canMove(shapes, target, position) ||
|
||||
canInsert(shapes, target, position);
|
||||
});
|
||||
|
||||
this.addRule([ 'shape.create', 'shape.append' ], function(context) {
|
||||
|
@ -749,6 +750,14 @@ function canConnectDataAssociation(source, target) {
|
|||
|
||||
function canInsert(shape, flow, position) {
|
||||
|
||||
if (Array.isArray(shape)) {
|
||||
if (shape.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
shape = shape[0];
|
||||
}
|
||||
|
||||
// return true if we can drop on the
|
||||
// underlying flow parent
|
||||
//
|
||||
|
|
|
@ -1,171 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
require('../../../../TestHelper');
|
||||
|
||||
/* global inject, bootstrapModeler */
|
||||
|
||||
var flatten = require('lodash/array/flatten');
|
||||
|
||||
var modelingModule = require('../../../../../lib/features/modeling');
|
||||
|
||||
|
||||
describe('modeling/behavior - drop on connection', function() {
|
||||
|
||||
var diagramXML = require('./CreateOnFlowBehavior.bpmn');
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, { modules: modelingModule }));
|
||||
|
||||
|
||||
describe('rules', function() {
|
||||
|
||||
it('should be allowed for an IntermediateThrowEvent', inject(function(elementRegistry, bpmnRules, elementFactory) {
|
||||
|
||||
// when
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow');
|
||||
var intermediateThrowEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent' });
|
||||
|
||||
// then
|
||||
expect(bpmnRules.canCreate(intermediateThrowEvent, sequenceFlow)).to.be.true;
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('execution', function() {
|
||||
|
||||
it('should connect start -> target -> end', inject(function(modeling, elementRegistry, elementFactory) {
|
||||
|
||||
// given
|
||||
var intermediateThrowEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent' });
|
||||
|
||||
var startEvent = elementRegistry.get('StartEvent'),
|
||||
sequenceFlow = elementRegistry.get('SequenceFlow'),
|
||||
task = elementRegistry.get('Task');
|
||||
|
||||
var originalWaypoints = sequenceFlow.waypoints;
|
||||
|
||||
var dropPosition = { x: 340, y: 120 }; // first bendpoint
|
||||
|
||||
// when
|
||||
var newShape = modeling.createShape(intermediateThrowEvent, dropPosition, sequenceFlow);
|
||||
|
||||
// then
|
||||
|
||||
var targetConnection = newShape.outgoing[0];
|
||||
|
||||
// new incoming connection
|
||||
expect(newShape.incoming.length).to.equal(1);
|
||||
expect(newShape.incoming[0]).to.eql(sequenceFlow);
|
||||
|
||||
// new outgoing connection
|
||||
expect(newShape.outgoing.length).to.equal(1);
|
||||
expect(targetConnection).to.be.ok;
|
||||
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]);
|
||||
|
||||
// split target at insertion point
|
||||
expect(sequenceFlow).to.have.waypoints(flatten([
|
||||
originalWaypoints.slice(0, 1),
|
||||
{ x: 322, y: 120 }
|
||||
]));
|
||||
|
||||
expect(sequenceFlow).to.have.endDocking(dropPosition);
|
||||
|
||||
expect(targetConnection).to.have.waypoints(flatten([
|
||||
{ x: 340, y: 138 },
|
||||
originalWaypoints.slice(2)
|
||||
]));
|
||||
|
||||
expect(targetConnection).to.have.startDocking(dropPosition);
|
||||
}));
|
||||
|
||||
|
||||
it('should connect start -> target', inject(function(modeling, elementRegistry, elementFactory) {
|
||||
|
||||
// given
|
||||
var endEventShape = elementFactory.createShape({ type: 'bpmn:EndEvent' });
|
||||
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow');
|
||||
var originalWaypoints = sequenceFlow.waypoints;
|
||||
|
||||
var dropPosition = { x: 340, y: 120 }; // first bendpoint
|
||||
|
||||
// when
|
||||
var newShape = modeling.createShape(endEventShape, dropPosition, sequenceFlow);
|
||||
|
||||
// then
|
||||
|
||||
// new incoming connection
|
||||
expect(newShape.incoming.length).to.equal(1);
|
||||
expect(newShape.incoming[0]).to.eql(sequenceFlow);
|
||||
|
||||
// no outgoing edges
|
||||
expect(newShape.outgoing.length).to.equal(0);
|
||||
|
||||
// split target at insertion point
|
||||
expect(sequenceFlow).to.have.waypoints(flatten([
|
||||
originalWaypoints.slice(0, 1),
|
||||
{ x: 322, y: 120 }
|
||||
]));
|
||||
}));
|
||||
|
||||
|
||||
it('should connect target -> end', inject(function(modeling, elementRegistry, elementFactory) {
|
||||
|
||||
// given
|
||||
var startEventShape = elementFactory.createShape({ type: 'bpmn:StartEvent' });
|
||||
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow');
|
||||
var originalWaypoints = sequenceFlow.waypoints;
|
||||
|
||||
var dropPosition = { x: 340, y: 120 }; // first bendpoint
|
||||
|
||||
// when
|
||||
var newShape = modeling.createShape(startEventShape, dropPosition, sequenceFlow);
|
||||
|
||||
// then
|
||||
|
||||
// no incoming connection
|
||||
expect(newShape.incoming.length).to.equal(0);
|
||||
|
||||
// no outgoing edges
|
||||
expect(newShape.outgoing.length).to.equal(1);
|
||||
expect(newShape.outgoing[0]).to.eql(sequenceFlow);
|
||||
|
||||
// split target at insertion point
|
||||
expect(sequenceFlow).to.have.waypoints(flatten([
|
||||
{ x: 340, y: 138 },
|
||||
originalWaypoints.slice(2)
|
||||
]));
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('rules', function() {
|
||||
|
||||
it('should not insert participant', inject(function(rules, elementRegistry, elementFactory) {
|
||||
|
||||
// given
|
||||
var participantShape = elementFactory.createShape({ type: 'bpmn:Participant' });
|
||||
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow');
|
||||
|
||||
var dropPosition = { x: 340, y: 120 }; // first bendpoint
|
||||
|
||||
// when
|
||||
var canDrop = rules.allowed('shape.create', {
|
||||
shape: participantShape,
|
||||
parent: sequenceFlow,
|
||||
dropPosition: dropPosition
|
||||
});
|
||||
|
||||
// then
|
||||
expect(canDrop).to.be.false;
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -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">
|
||||
<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.7.0-dev">
|
||||
<bpmn:process id="Process" isExecutable="false">
|
||||
<bpmn:startEvent id="StartEvent">
|
||||
<bpmn:outgoing>SequenceFlow</bpmn:outgoing>
|
||||
|
@ -8,6 +8,9 @@
|
|||
<bpmn:incoming>SequenceFlow</bpmn:incoming>
|
||||
</bpmn:task>
|
||||
<bpmn:sequenceFlow id="SequenceFlow" sourceRef="StartEvent" targetRef="Task" />
|
||||
<bpmn:intermediateThrowEvent id="IntermediateThrowEvent_foo" />
|
||||
<bpmn:endEvent id="EndEvent_foo" />
|
||||
<bpmn:startEvent id="StartEvent_foo" />
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process">
|
||||
|
@ -26,6 +29,24 @@
|
|||
<dc:Bounds x="297.5" y="110" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="IntermediateThrowEvent_foo_di" bpmnElement="IntermediateThrowEvent_foo">
|
||||
<dc:Bounds x="173" y="192" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="191" y="228" width="0" height="0" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="EndEvent_foo_di" bpmnElement="EndEvent_foo">
|
||||
<dc:Bounds x="173" y="281" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="191" y="317" width="0" height="0" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="StartEvent_foo_di" bpmnElement="StartEvent_foo">
|
||||
<dc:Bounds x="534" y="192" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="552" y="228" width="0" height="0" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -0,0 +1,364 @@
|
|||
'use strict';
|
||||
|
||||
require('../../../../TestHelper');
|
||||
|
||||
/* global inject, bootstrapModeler */
|
||||
|
||||
var flatten = require('lodash/array/flatten');
|
||||
|
||||
var coreModule = require('../../../../../lib/core'),
|
||||
moveModule = require('diagram-js/lib/features/move'),
|
||||
modelingModule = require('../../../../../lib/features/modeling'),
|
||||
noTouchInteractionModule = { touchInteractionEvents: ['value', null ] };
|
||||
|
||||
var canvasEvent = require('../../../../util/MockEvents').createCanvasEvent;
|
||||
|
||||
|
||||
describe('modeling/behavior - drop on connection', function() {
|
||||
|
||||
var diagramXML = require('./DropOnFlowBehavior.bpmn');
|
||||
|
||||
var testModules = [ noTouchInteractionModule, moveModule, modelingModule, coreModule ];
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
|
||||
|
||||
|
||||
describe('rules', function() {
|
||||
|
||||
it('should be allowed for an IntermediateThrowEvent', inject(function(elementRegistry, bpmnRules, elementFactory) {
|
||||
|
||||
// when
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow');
|
||||
var intermediateThrowEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent' });
|
||||
|
||||
// then
|
||||
expect(bpmnRules.canCreate(intermediateThrowEvent, sequenceFlow)).to.be.true;
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('execution', function() {
|
||||
|
||||
describe('create', function() {
|
||||
|
||||
it('should connect start -> target -> end', inject(function(modeling, elementRegistry, elementFactory) {
|
||||
|
||||
// given
|
||||
var intermediateThrowEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent' });
|
||||
|
||||
var startEvent = elementRegistry.get('StartEvent'),
|
||||
sequenceFlow = elementRegistry.get('SequenceFlow'),
|
||||
task = elementRegistry.get('Task');
|
||||
|
||||
var originalWaypoints = sequenceFlow.waypoints;
|
||||
|
||||
var dropPosition = { x: 340, y: 120 }; // first bendpoint
|
||||
|
||||
// when
|
||||
var newShape = modeling.createShape(intermediateThrowEvent, dropPosition, sequenceFlow);
|
||||
|
||||
// then
|
||||
|
||||
var targetConnection = newShape.outgoing[0];
|
||||
|
||||
// new incoming connection
|
||||
expect(newShape.incoming.length).to.equal(1);
|
||||
expect(newShape.incoming[0]).to.eql(sequenceFlow);
|
||||
|
||||
// new outgoing connection
|
||||
expect(newShape.outgoing.length).to.equal(1);
|
||||
expect(targetConnection).to.be.ok;
|
||||
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]);
|
||||
|
||||
// split target at insertion point
|
||||
expect(sequenceFlow).to.have.waypoints(flatten([
|
||||
originalWaypoints.slice(0, 1),
|
||||
{ x: 322, y: 120 }
|
||||
]));
|
||||
|
||||
expect(sequenceFlow).to.have.endDocking(dropPosition);
|
||||
|
||||
expect(targetConnection).to.have.waypoints(flatten([
|
||||
{ x: 340, y: 138 },
|
||||
originalWaypoints.slice(2)
|
||||
]));
|
||||
|
||||
expect(targetConnection).to.have.startDocking(dropPosition);
|
||||
}));
|
||||
|
||||
|
||||
it('should connect start -> target', inject(function(modeling, elementRegistry, elementFactory) {
|
||||
|
||||
// given
|
||||
var endEventShape = elementFactory.createShape({ type: 'bpmn:EndEvent' });
|
||||
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow');
|
||||
var originalWaypoints = sequenceFlow.waypoints;
|
||||
|
||||
var dropPosition = { x: 340, y: 120 }; // first bendpoint
|
||||
|
||||
// when
|
||||
var newShape = modeling.createShape(endEventShape, dropPosition, sequenceFlow);
|
||||
|
||||
// then
|
||||
|
||||
// new incoming connection
|
||||
expect(newShape.incoming.length).to.equal(1);
|
||||
expect(newShape.incoming[0]).to.eql(sequenceFlow);
|
||||
|
||||
// no outgoing edges
|
||||
expect(newShape.outgoing.length).to.equal(0);
|
||||
|
||||
// split target at insertion point
|
||||
expect(sequenceFlow).to.have.waypoints(flatten([
|
||||
originalWaypoints.slice(0, 1),
|
||||
{ x: 322, y: 120 }
|
||||
]));
|
||||
}));
|
||||
|
||||
|
||||
it('should connect target -> end', inject(function(modeling, elementRegistry, elementFactory) {
|
||||
|
||||
// given
|
||||
var startEventShape = elementFactory.createShape({ type: 'bpmn:StartEvent' });
|
||||
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow');
|
||||
var originalWaypoints = sequenceFlow.waypoints;
|
||||
|
||||
var dropPosition = { x: 340, y: 120 }; // first bendpoint
|
||||
|
||||
// when
|
||||
var newShape = modeling.createShape(startEventShape, dropPosition, sequenceFlow);
|
||||
|
||||
// then
|
||||
|
||||
// no incoming connection
|
||||
expect(newShape.incoming.length).to.equal(0);
|
||||
|
||||
// no outgoing edges
|
||||
expect(newShape.outgoing.length).to.equal(1);
|
||||
expect(newShape.outgoing[0]).to.eql(sequenceFlow);
|
||||
|
||||
// split target at insertion point
|
||||
expect(sequenceFlow).to.have.waypoints(flatten([
|
||||
{ x: 340, y: 138 },
|
||||
originalWaypoints.slice(2)
|
||||
]));
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('move', function() {
|
||||
|
||||
beforeEach(inject(function(dragging) {
|
||||
dragging.setOptions({ manual: true });
|
||||
}));
|
||||
|
||||
it('should connect start -> target -> end', inject(function(dragging, move, elementRegistry, selection) {
|
||||
|
||||
// given
|
||||
var intermediateThrowEvent = elementRegistry.get('IntermediateThrowEvent_foo');
|
||||
|
||||
var startEvent = elementRegistry.get('StartEvent'),
|
||||
sequenceFlow = elementRegistry.get('SequenceFlow'),
|
||||
sequenceFlowGfx = elementRegistry.getGraphics(sequenceFlow),
|
||||
task = elementRegistry.get('Task');
|
||||
|
||||
var originalWaypoints = sequenceFlow.waypoints;
|
||||
|
||||
// when
|
||||
selection.select(intermediateThrowEvent);
|
||||
|
||||
move.start(canvasEvent({ x: 0, y: 0 }), intermediateThrowEvent);
|
||||
|
||||
dragging.hover({
|
||||
element: sequenceFlow,
|
||||
gfx: sequenceFlowGfx
|
||||
});
|
||||
|
||||
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', inject(function(modeling, elementRegistry, selection, move, dragging) {
|
||||
|
||||
// given
|
||||
var endEventShape = elementRegistry.get('EndEvent_foo');
|
||||
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow'),
|
||||
sequenceFlowGfx = elementRegistry.getGraphics(sequenceFlow),
|
||||
originalWaypoints = sequenceFlow.waypoints;
|
||||
|
||||
// when
|
||||
selection.select(endEventShape);
|
||||
|
||||
move.start(canvasEvent({ x: 0, y: 0 }), endEventShape);
|
||||
|
||||
dragging.hover({
|
||||
element: sequenceFlow,
|
||||
gfx: sequenceFlowGfx
|
||||
});
|
||||
|
||||
dragging.move(canvasEvent({ x: 150, y: 0 }));
|
||||
|
||||
dragging.end();
|
||||
|
||||
// then
|
||||
|
||||
// new incoming connection
|
||||
expect(endEventShape.incoming.length).to.equal(1);
|
||||
expect(endEventShape.incoming[0]).to.eql(sequenceFlow);
|
||||
|
||||
// no outgoing edges
|
||||
expect(endEventShape.outgoing.length).to.equal(0);
|
||||
|
||||
// split target at insertion point
|
||||
expect(sequenceFlow).to.have.waypoints(flatten([
|
||||
originalWaypoints.slice(0, 2),
|
||||
{ x: 340, y: 281 }
|
||||
]));
|
||||
}));
|
||||
|
||||
|
||||
it('should connect target -> end', inject(function(modeling, elementRegistry, dragging, selection, move) {
|
||||
|
||||
var startEventShape = elementRegistry.get('StartEvent_foo');
|
||||
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow'),
|
||||
sequenceFlowGfx = elementRegistry.getGraphics(sequenceFlow),
|
||||
originalWaypoints = sequenceFlow.waypoints;
|
||||
|
||||
// when
|
||||
selection.select(startEventShape);
|
||||
|
||||
move.start(canvasEvent({ x: 0, y: 0 }), startEventShape);
|
||||
|
||||
dragging.hover({
|
||||
element: sequenceFlow,
|
||||
gfx: sequenceFlowGfx
|
||||
});
|
||||
|
||||
dragging.move(canvasEvent({ x: -215, y: 0 }));
|
||||
|
||||
dragging.end();
|
||||
|
||||
// then
|
||||
|
||||
// no incoming connection
|
||||
expect(startEventShape.incoming.length).to.equal(0);
|
||||
|
||||
// no outgoing edges
|
||||
expect(startEventShape.outgoing.length).to.equal(1);
|
||||
expect(startEventShape.outgoing[0]).to.eql(sequenceFlow);
|
||||
|
||||
// split target at insertion point
|
||||
expect(sequenceFlow).to.have.waypoints(flatten([
|
||||
{ x: 338, y: 228 },
|
||||
originalWaypoints.slice(2)
|
||||
]));
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('rules', function() {
|
||||
|
||||
it('should not insert participant', inject(function(rules, elementRegistry, elementFactory) {
|
||||
|
||||
// given
|
||||
var participantShape = elementFactory.createShape({ type: 'bpmn:Participant' });
|
||||
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow');
|
||||
|
||||
var dropPosition = { x: 340, y: 120 }; // first bendpoint
|
||||
|
||||
// when
|
||||
var canDrop = rules.allowed('shape.create', {
|
||||
shape: participantShape,
|
||||
parent: sequenceFlow,
|
||||
dropPosition: dropPosition
|
||||
});
|
||||
|
||||
// then
|
||||
expect(canDrop).to.be.false;
|
||||
}));
|
||||
|
||||
|
||||
it('should not insert multiple with "move"', inject(function(elementRegistry, selection, move, dragging) {
|
||||
|
||||
// given
|
||||
var intermediateThrowEvent = elementRegistry.get('IntermediateThrowEvent_foo'),
|
||||
endEventShape = elementRegistry.get('EndEvent_foo');
|
||||
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow'),
|
||||
sequenceFlowGfx = elementRegistry.getGraphics(sequenceFlow);
|
||||
|
||||
var intInitPosition = {
|
||||
x: intermediateThrowEvent.x,
|
||||
y: intermediateThrowEvent.y
|
||||
},
|
||||
endInitPosition = {
|
||||
x: endEventShape.x,
|
||||
y: endEventShape.y
|
||||
};
|
||||
|
||||
selection.select([ intermediateThrowEvent, endEventShape ]);
|
||||
|
||||
// when
|
||||
move.start(canvasEvent({ x: 0, y: 0 }), intermediateThrowEvent);
|
||||
|
||||
dragging.hover({
|
||||
element: sequenceFlow,
|
||||
gfx: sequenceFlowGfx
|
||||
});
|
||||
|
||||
dragging.move(canvasEvent({ x: -215, y: 0 }));
|
||||
|
||||
dragging.end();
|
||||
|
||||
// then
|
||||
expect(intermediateThrowEvent).to.have.position(intInitPosition);
|
||||
expect(endEventShape).to.have.position(endInitPosition);
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue