Skip to content

Commit

Permalink
feat(modeling): add generic create-on-flow
Browse files Browse the repository at this point in the history
Closes #232
  • Loading branch information
nikku committed May 28, 2015
1 parent 009a440 commit 30b8ed6
Show file tree
Hide file tree
Showing 8 changed files with 272 additions and 89 deletions.
19 changes: 0 additions & 19 deletions lib/features/modeling/behavior/CreateBehavior.js
Expand Up @@ -25,11 +25,6 @@ function CreateBehavior(eventBus, modeling) {
shape = context.shape,
position = context.position;

if (is(parent, 'bpmn:SequenceFlow')){
context.insertTarget = parent;
context.parent = context.parent.parent;
}

if (is(parent, 'bpmn:Process') && is(shape, 'bpmn:Participant')) {

// this is going to detach the process root
Expand Down Expand Up @@ -80,20 +75,6 @@ function CreateBehavior(eventBus, modeling) {
var processChildren = processRoot.children.slice();
modeling.moveShapes(processChildren, { x: 0, y: 0 }, shape);
}

if (context.insertTarget) {

var initialTarget = context.insertTarget.target;
var insertShape = context.shape;

// reconnecting end to inserted shape
modeling.reconnectEnd(context.insertTarget, insertShape, context.position);

// create new connection between inserted shape and initial target
modeling.createConnection(insertShape, initialTarget, {
type: context.insertTarget.type,
}, context.parent);
}
}, true);

}
Expand Down
95 changes: 95 additions & 0 deletions lib/features/modeling/behavior/CreateOnFlowBehavior.js
@@ -0,0 +1,95 @@
'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.insertTarget = parent;
context.parent = parent.parent;
}
}, true);


this.postExecute('shape.create', function(context) {

var shape = context.shape,
insertTarget = context.insertTarget,
position = context.position,
source,
target,
reconnected,
intersection,
waypoints,
waypointsBefore,
waypointsAfter,
dockingPoint;

if (insertTarget) {

waypoints = insertTarget.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 = insertTarget.source;
target = insertTarget.target;

if (bpmnRules.canConnect(source, shape, insertTarget)) {
// reconnect source -> inserted shape
modeling.reconnectEnd(insertTarget, shape, waypointsBefore || copy(position));

reconnected = true;
}

if (bpmnRules.canConnect(shape, target, insertTarget)) {

if (!reconnected) {
// reconnect inserted shape -> end
modeling.reconnectStart(insertTarget, shape, waypointsAfter || copy(position));
} else {
modeling.connect(shape, target, { type: insertTarget.type, waypoints: waypointsAfter });
}
}
}
}, true);
}

inherits(CreateOnFlowBehavior, CommandInterceptor);

CreateOnFlowBehavior.$inject = [ 'eventBus', 'bpmnRules', 'modeling' ];

module.exports = CreateOnFlowBehavior;
2 changes: 2 additions & 0 deletions lib/features/modeling/behavior/index.js
Expand Up @@ -2,13 +2,15 @@ module.exports = {
__init__: [
'appendBehavior',
'createBehavior',
'createOnFlowBehavior',
'dropBehavior',
'removeBehavior',
'modelingFeedback'
],
appendBehavior: [ 'type', require('./AppendBehavior') ],
dropBehavior: [ 'type', require('./DropBehavior') ],
createBehavior: [ 'type', require('./CreateBehavior') ],
createOnFlowBehavior: [ 'type', require('./CreateOnFlowBehavior') ],
removeBehavior: [ 'type', require('./RemoveBehavior') ],
modelingFeedback: [ 'type', require('./ModelingFeedback') ]
};
35 changes: 14 additions & 21 deletions lib/features/modeling/rules/BpmnRules.js
Expand Up @@ -94,6 +94,8 @@ BpmnRules.prototype.canMove = canMove;

BpmnRules.prototype.canDrop = canDrop;

BpmnRules.prototype.canInsert = canInsert;

BpmnRules.prototype.canCreate = canCreate;

BpmnRules.prototype.canConnect = canConnect;
Expand Down Expand Up @@ -339,11 +341,7 @@ function canCreate(shape, target, source) {
return false;
}

if (canInsert(shape, target)){
return true;
}

return canDrop(shape, target);
return canDrop(shape, target) || canInsert(shape, target);
}

function canResize(shape, newBounds) {
Expand Down Expand Up @@ -391,20 +389,15 @@ function canConnectSequenceFlow(source, target) {
!(is(source, 'bpmn:EventBasedGateway') && !isEventBasedTarget(target));
}

function canInsert(shape, target) {

var startEvent = target.source;
var endEvent = target.target;

if (!is(target, 'bpmn:SequenceFlow')) {
return false;
}

if(is(shape, 'bpmn:IntermediateThrowEvent') &&
is(startEvent, 'bpmn:FlowElement') &&
is(endEvent, 'bpmn:FlowElement')) {
return true;
}

return false;
function canInsert(shape, flow) {

// return true if we can drop on the
// underlying flow parent
//
// at this point we are not really able to talk
// about connection rules (yet)
return (
is(flow, 'bpmn:SequenceFlow') ||
is(flow, 'bpmn:MessageFlow')
) && canDrop(shape, flow.parent);
}
5 changes: 4 additions & 1 deletion lib/features/snapping/BpmnSnapping.js
Expand Up @@ -137,7 +137,7 @@ function BpmnSnapping(eventBus, canvas) {
context.minDimensions = { width: 50, height: 50 };
}
});

}

inherits(BpmnSnapping, Snapping);
Expand Down Expand Up @@ -227,6 +227,9 @@ BpmnSnapping.prototype.addTargetSnaps = function(snapPoints, shape, target) {

var siblings = this.getSiblings(shape, target);

if (is(target, 'bpmn:SequenceFlow')) {
this.addTargetSnaps(snapPoints, shape, target.parent);
}

forEach(siblings, function(s) {
snapPoints.add('mid', mid(s));
Expand Down
36 changes: 0 additions & 36 deletions test/spec/features/drop-on-connection/DropOnConnectionSpec.js

This file was deleted.

@@ -1,25 +1,27 @@
<?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:process id="Process_1" isExecutable="false">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>SequenceFlow_0lk9mnl</bpmn:outgoing>
<bpmn:process id="Process" isExecutable="false">
<bpmn:startEvent id="StartEvent">
<bpmn:outgoing>SequenceFlow</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="Task_195jx60">
<bpmn:incoming>SequenceFlow_0lk9mnl</bpmn:incoming>
<bpmn:task id="Task">
<bpmn:incoming>SequenceFlow</bpmn:incoming>
</bpmn:task>
<bpmn:sequenceFlow id="SequenceFlow_0lk9mnl" sourceRef="StartEvent_1" targetRef="Task_195jx60" />
<bpmn:sequenceFlow id="SequenceFlow" sourceRef="StartEvent" targetRef="Task" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent">
<dc:Bounds x="173" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_195jx60_di" bpmnElement="Task_195jx60">
<dc:Bounds x="476" y="80" width="100" height="80" />
<bpmndi:BPMNShape id="Task_di" bpmnElement="Task">
<dc:Bounds x="502" y="259" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_0lk9mnl_di" bpmnElement="SequenceFlow_0lk9mnl">
<bpmndi:BPMNEdge id="SequenceFlow_di" bpmnElement="SequenceFlow">
<di:waypoint xsi:type="dc:Point" x="209" y="120" />
<di:waypoint xsi:type="dc:Point" x="476" y="120" />
<di:waypoint xsi:type="dc:Point" x="340" y="120" />
<di:waypoint xsi:type="dc:Point" x="340" y="299" />
<di:waypoint xsi:type="dc:Point" x="502" y="299" />
<bpmndi:BPMNLabel>
<dc:Bounds x="297.5" y="110" width="90" height="20" />
</bpmndi:BPMNLabel>
Expand Down

0 comments on commit 30b8ed6

Please sign in to comment.