feat(modeling): create boundary event via moving intermediate event

This commit is contained in:
Maciej Barelkowski 2019-05-17 14:26:13 +02:00 committed by merge-me[bot]
parent 1da513808c
commit 1e9aceecd7
6 changed files with 149 additions and 8 deletions

View File

@ -0,0 +1,61 @@
import inherits from 'inherits';
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
import { is } from '../../../util/ModelUtil';
/**
* BPMN specific attach event behavior
*/
export default function AttachEventBehavior(eventBus, bpmnFactory, bpmnReplace) {
CommandInterceptor.call(this, eventBus);
/**
* replace intermediate event with boundary event when
* attaching it to a shape
*/
this.preExecute('elements.move', function(context) {
var shapes = context.shapes,
host = context.newHost,
shape,
newShape,
businessObject,
boundaryEvent;
if (shapes.length !== 1) {
return;
}
shape = shapes[0];
var attrs = {
cancelActivity: true
};
if (host && is(shape, 'bpmn:IntermediateThrowEvent')) {
attrs.attachedToRef = host.businessObject;
businessObject = bpmnFactory.create('bpmn:BoundaryEvent', attrs);
boundaryEvent = {
type: 'bpmn:BoundaryEvent',
businessObject: businessObject
};
newShape = bpmnReplace.replaceElement(shape, boundaryEvent);
context.shapes = [ newShape ];
}
}, true);
}
AttachEventBehavior.$inject = [
'eventBus',
'bpmnFactory',
'bpmnReplace'
];
inherits(AttachEventBehavior, CommandInterceptor);

View File

@ -1,5 +1,6 @@
import AdaptiveLabelPositioningBehavior from './AdaptiveLabelPositioningBehavior'; import AdaptiveLabelPositioningBehavior from './AdaptiveLabelPositioningBehavior';
import AppendBehavior from './AppendBehavior'; import AppendBehavior from './AppendBehavior';
import AttachEventBehavior from './AttachEventBehavior';
import BoundaryEventBehavior from './BoundaryEventBehavior'; import BoundaryEventBehavior from './BoundaryEventBehavior';
import CopyPasteBehavior from './CopyPasteBehavior'; import CopyPasteBehavior from './CopyPasteBehavior';
import CreateBoundaryEventBehavior from './CreateBoundaryEventBehavior'; import CreateBoundaryEventBehavior from './CreateBoundaryEventBehavior';
@ -31,6 +32,7 @@ export default {
__init__: [ __init__: [
'adaptiveLabelPositioningBehavior', 'adaptiveLabelPositioningBehavior',
'appendBehavior', 'appendBehavior',
'attachEventBehavior',
'boundaryEventBehavior', 'boundaryEventBehavior',
'copyPasteBehavior', 'copyPasteBehavior',
'createBoundaryEventBehavior', 'createBoundaryEventBehavior',
@ -60,6 +62,7 @@ export default {
], ],
adaptiveLabelPositioningBehavior: [ 'type', AdaptiveLabelPositioningBehavior ], adaptiveLabelPositioningBehavior: [ 'type', AdaptiveLabelPositioningBehavior ],
appendBehavior: [ 'type', AppendBehavior ], appendBehavior: [ 'type', AppendBehavior ],
attachEventBehavior: [ 'type', AttachEventBehavior ],
boundaryEventBehavior: [ 'type', BoundaryEventBehavior ], boundaryEventBehavior: [ 'type', BoundaryEventBehavior ],
copyPasteBehavior: [ 'type', CopyPasteBehavior ], copyPasteBehavior: [ 'type', CopyPasteBehavior ],
createBoundaryEventBehavior: [ 'type', CreateBoundaryEventBehavior ], createBoundaryEventBehavior: [ 'type', CreateBoundaryEventBehavior ],

View File

@ -564,8 +564,7 @@ function isLane(element) {
* this must be reflected in the rules. * this must be reflected in the rules.
*/ */
function isBoundaryCandidate(element) { function isBoundaryCandidate(element) {
return isBoundaryEvent(element) || return isBoundaryEvent(element) || is(element, 'bpmn:IntermediateThrowEvent');
(is(element, 'bpmn:IntermediateThrowEvent') && !element.parent);
} }
function hasNoEventDefinition(element) { function hasNoEventDefinition(element) {
@ -605,11 +604,6 @@ function canAttach(elements, target, source, position) {
elements = [ elements ]; elements = [ elements ];
} }
// disallow appending as boundary event
if (source) {
return false;
}
// only (re-)attach one element at a time // only (re-)attach one element at a time
if (elements.length !== 1) { if (elements.length !== 1) {
return false; return false;

View File

@ -14,6 +14,7 @@
<bpmn2:task id="Task_2" /> <bpmn2:task id="Task_2" />
<bpmn2:boundaryEvent id="BoundaryEvent_2" name="superman" attachedToRef="Task_2" /> <bpmn2:boundaryEvent id="BoundaryEvent_2" name="superman" attachedToRef="Task_2" />
<bpmn2:task id="CompensationTask" isForCompensation="true" /> <bpmn2:task id="CompensationTask" isForCompensation="true" />
<bpmn2:intermediateThrowEvent id="IntermediateThrowEvent_1" name="joker" />
</bpmn2:process> </bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1"> <bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1"> <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
@ -54,6 +55,12 @@
<bpmndi:BPMNShape id="CompensationTask_di" bpmnElement="CompensationTask"> <bpmndi:BPMNShape id="CompensationTask_di" bpmnElement="CompensationTask">
<dc:Bounds x="795" y="249" width="100" height="80" /> <dc:Bounds x="795" y="249" width="100" height="80" />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>
<bpmndi:BPMNShape id="IntermediateThrowEvent_1_di" bpmnElement="IntermediateThrowEvent_1">
<dc:Bounds x="185" y="480" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="191" y="525" width="24" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane> </bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram> </bpmndi:BPMNDiagram>
</bpmn2:definitions> </bpmn2:definitions>

View File

@ -0,0 +1,59 @@
import {
bootstrapModeler,
inject
} from 'test/TestHelper';
import modelingModule from 'lib/features/modeling';
import coreModule from 'lib/core';
describe('features/modeling/behavior - attach events', function() {
var testModules = [ coreModule, modelingModule ];
var processDiagramXML = require('../../../../fixtures/bpmn/boundary-events.bpmn');
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
it('should execute on attach', inject(function(elementRegistry, modeling) {
// given
var eventId = 'IntermediateThrowEvent_1',
intermediateThrowEvent = elementRegistry.get(eventId),
subProcess = elementRegistry.get('SubProcess_1'),
boundaryEvent;
var elements = [ intermediateThrowEvent ];
// when
modeling.moveElements(elements, { x: 60, y: -131 }, subProcess, { attach: true });
// then
boundaryEvent = elementRegistry.get(eventId);
expect(intermediateThrowEvent.parent).to.not.exist;
expect(boundaryEvent).to.exist;
expect(boundaryEvent.type).to.equal('bpmn:BoundaryEvent');
expect(boundaryEvent.businessObject.attachedToRef).to.equal(subProcess.businessObject);
}));
it('should NOT execute on drop', inject(function(elementRegistry, modeling) {
// given
var eventId = 'IntermediateThrowEvent_1',
intermediateThrowEvent = elementRegistry.get(eventId),
subProcess = elementRegistry.get('SubProcess_1');
var elements = [ intermediateThrowEvent ];
// when
modeling.moveElements(elements, { x: 60, y: -191 }, subProcess);
// then
expect(intermediateThrowEvent.parent).to.eql(subProcess);
expect(intermediateThrowEvent.type).to.equal('bpmn:IntermediateThrowEvent');
}));
});

View File

@ -1260,6 +1260,23 @@ describe('features/modeling/rules - BpmnRules', function() {
} }
)); ));
it('attach/move IntermediateThrowEvent -> SubProcess', inject(
function(elementRegistry) {
// given
var intermediateThrowEvent = elementRegistry.get('IntermediateThrowEvent_1');
var elements = [ intermediateThrowEvent ];
// then
expectCanMove(elements, 'SubProcess_1', {
attach: 'attach',
move: true
});
}
));
}); });
@ -1539,7 +1556,7 @@ describe('features/modeling/rules - BpmnRules', function() {
); );
// then // then
expect(canAttach).to.be.false; expect(canAttach).to.eql('attach');
expect(canCreate).to.be.false; expect(canCreate).to.be.false;
} }
)); ));