feat(replace): add cancel events

Closes #337
This commit is contained in:
Ricardo Matias 2015-09-17 09:05:09 +02:00 committed by pedesen
parent 02af025a2e
commit 8a0f566ee3
11 changed files with 813 additions and 161 deletions

View File

@ -1,57 +0,0 @@
'use strict';
var inherits = require('inherits');
var CommandInterceptor = require('diagram-js/lib/command/CommandInterceptor');
var forEach = require('lodash/collection/forEach');
var isEventSubProcess = require('../../../util/DiUtil').isEventSubProcess;
/**
* Defines the behavior when a start event is moved
*/
function MoveStartEventBehavior(eventBus, bpmnReplace, bpmnRules, elementRegistry, selection) {
CommandInterceptor.call(this, eventBus);
this.postExecuted([ 'elements.move' ], function(event) {
var context = event.context,
target = context.newParent,
elements = [];
forEach(context.closure.topLevel, function(topLevelElements) {
if (isEventSubProcess(topLevelElements)) {
elements = elements.concat(topLevelElements.children);
} else {
elements = elements.concat(topLevelElements);
}
});
var canReplace = bpmnRules.canReplace(elements, target);
forEach(canReplace.replacements, function(replacements) {
var newElement = {
type: replacements.newElementType
};
var oldElement = elementRegistry.get(replacements.oldElementId);
var idx = elements.indexOf(oldElement);
elements[idx] = bpmnReplace.replaceElement(oldElement, newElement, { select: false });
});
if (canReplace.replacements) {
selection.select(elements);
}
});
}
MoveStartEventBehavior.$inject = [ 'eventBus', 'bpmnReplace', 'bpmnRules', 'elementRegistry', 'selection' ];
inherits(MoveStartEventBehavior, CommandInterceptor);
module.exports = MoveStartEventBehavior;

View File

@ -0,0 +1,107 @@
'use strict';
var inherits = require('inherits');
var CommandInterceptor = require('diagram-js/lib/command/CommandInterceptor');
var forEach = require('lodash/collection/forEach');
var isEventSubProcess = require('../../../util/DiUtil').isEventSubProcess;
var is = require('../../../util/ModelUtil').is;
/**
* Defines the behaviour of what happens to the elements inside a container
* that morphs into another BPMN element
*/
function ReplaceElementBehaviour(eventBus, bpmnReplace, bpmnRules, elementRegistry, selection, modeling) {
CommandInterceptor.call(this, eventBus);
this._bpmnReplace = bpmnReplace;
this._elementRegistry = elementRegistry;
this._selection = selection;
this._modeling = modeling;
this.postExecuted([ 'elements.move' ], 500, function(event) {
var context = event.context,
target = context.newParent,
newHost = context.newHost,
elements = [];
forEach(context.closure.topLevel, function(topLevelElements) {
if (isEventSubProcess(topLevelElements)) {
elements = elements.concat(topLevelElements.children);
} else {
elements = elements.concat(topLevelElements);
}
});
// Change target to host when the moving element is a `bpmn:BoundaryEvent`
if (elements.length === 1 && newHost) {
target = newHost;
}
var canReplace = bpmnRules.canReplace(elements, target);
if (canReplace) {
this.replaceElements(elements, canReplace.replacements, newHost);
}
}, this);
// update attachments if the host is replaced
this.postExecute([ 'shape.replace' ], 1500, function(e) {
var context = e.context,
oldShape = context.oldShape,
newShape = context.newShape,
attachers = oldShape.attachers,
canReplace;
if (attachers && attachers.length) {
canReplace = bpmnRules.canReplace(attachers, newShape);
this.replaceElements(attachers, canReplace.replacements);
}
}, this);
}
inherits(ReplaceElementBehaviour, CommandInterceptor);
ReplaceElementBehaviour.prototype.replaceElements = function(elements, newElements, newHost) {
var elementRegistry = this._elementRegistry,
bpmnReplace = this._bpmnReplace,
selection = this._selection,
modeling = this._modeling;
forEach(newElements, function(replacement) {
var newElement = {
type: replacement.newElementType
};
var oldElement = elementRegistry.get(replacement.oldElementId);
if (newHost && is(oldElement, 'bpmn:BoundaryEvent')) {
modeling.updateAttachment(oldElement, null);
}
var idx = elements.indexOf(oldElement);
elements[idx] = bpmnReplace.replaceElement(oldElement, newElement, { select: false });
if (newHost && is(elements[idx], 'bpmn:BoundaryEvent')) {
modeling.updateAttachment(elements[idx], newHost);
}
});
if (newElements) {
selection.select(elements);
}
};
ReplaceElementBehaviour.$inject = [ 'eventBus', 'bpmnReplace', 'bpmnRules', 'elementRegistry',
'selection', 'modeling' ];
module.exports = ReplaceElementBehaviour;

View File

@ -6,7 +6,7 @@ module.exports = {
'createOnFlowBehavior',
'createParticipantBehavior',
'modelingFeedback',
'moveStartEventBehavior',
'replaceElementBehaviour',
'removeParticipantBehavior',
'replaceConnectionBehavior'
],
@ -16,7 +16,7 @@ module.exports = {
createOnFlowBehavior: [ 'type', require('./CreateOnFlowBehavior') ],
createParticipantBehavior: [ 'type', require('./CreateParticipantBehavior') ],
modelingFeedback: [ 'type', require('./ModelingFeedback') ],
moveStartEventBehavior: [ 'type', require('./MoveStartEventBehavior') ],
replaceElementBehaviour: [ 'type', require('./ReplaceElementBehaviour') ],
removeParticipantBehavior: [ 'type', require('./RemoveParticipantBehavior') ],
replaceConnectionBehavior: [ 'type', require('./ReplaceConnectionBehavior') ]
};

View File

@ -289,6 +289,10 @@ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection, modelin
// filter for boundary events
if (is(businessObject, 'bpmn:BoundaryEvent')) {
if (target.eventDefinition == 'bpmn:CancelEventDefinition' &&
!is(businessObject.attachedToRef, 'bpmn:Transaction')) {
return false;
}
var cancelActivity = target.cancelActivity !== false;
var isCancelActivityEqual = businessObject.cancelActivity == cancelActivity;
@ -305,6 +309,11 @@ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection, modelin
return !(isEventDefinitionEqual && isEventDefinitionEqual && isInterruptingEqual);
}
if (is(businessObject, 'bpmn:EndEvent') && target.eventDefinition == 'bpmn:CancelEventDefinition' &&
!is(businessObject.$parent, 'bpmn:Transaction')) {
return false;
}
// filter for all other elements
return (!isEventDefinitionEqual && isEventTypeEqual) || !isEventTypeEqual;
}

View File

@ -533,6 +533,15 @@ module.exports.BOUNDARY_EVENT = [
eventDefinition: 'bpmn:ErrorEventDefinition'
}
},
{
label: 'Cancel Boundary Event',
actionName: 'replace-with-cancel-boundary',
className: 'icon-intermediate-event-catch-cancel',
target: {
type: 'bpmn:BoundaryEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
}
},
{
label: 'Signal Boundary Event',
actionName: 'replace-with-signal-boundary',

View File

@ -77,7 +77,7 @@ BpmnRules.prototype.init = function() {
position = context.position;
return canAttach(shapes, target, null, position) ||
canReplace(shapes, target) ||
canReplace(shapes, target, position) ||
canMove(shapes, target, position);
});
@ -286,7 +286,7 @@ function canConnect(source, target, connection) {
*
* @return {Boolean}
*/
function canDrop(element, target) {
function canDrop(element, target, position) {
// can move labels everywhere
if (isLabel(element) && !isConnection(target)) {
@ -346,6 +346,9 @@ function isBoundaryCandidate(element) {
function canAttach(elements, target, source, position) {
if (!Array.isArray(elements)) {
elements = [ elements ];
}
// disallow appending as boundary event
if (source) {
@ -412,7 +415,7 @@ function canAttach(elements, target, source, position) {
*
* @return {Object} an object containing all elements which have to be replaced
*/
function canReplace(elements, target) {
function canReplace(elements, target, position) {
if (!target) {
return false;
@ -439,6 +442,26 @@ function canReplace(elements, target) {
});
}
}
if (!is(target, 'bpmn:Transaction')) {
if (hasEventDefinition(element, 'bpmn:CancelEventDefinition') &&
element.type !== 'label') {
if (is(element, 'bpmn:EndEvent') && canDrop(element, target)) {
canExecute.replacements.push({
oldElementId: element.id,
newElementType: 'bpmn:EndEvent'
});
}
if (is(element, 'bpmn:BoundaryEvent') && canAttach(element, target, null, position)) {
canExecute.replacements.push({
oldElementId: element.id,
newElementType: 'bpmn:BoundaryEvent'
});
}
}
}
});
return canExecute.replacements.length ? canExecute : false;

View File

@ -0,0 +1,49 @@
<?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" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:transaction id="Transaction_1">
<bpmn:endEvent id="EndEvent_1">
<bpmn:cancelEventDefinition />
</bpmn:endEvent>
</bpmn:transaction>
<bpmn:boundaryEvent id="BoundaryEvent_1" attachedToRef="Transaction_1" />
<bpmn:subProcess id="SubProcess_1">
<bpmn:endEvent id="EndEvent_2" />
</bpmn:subProcess>
<bpmn:boundaryEvent id="BoundaryEvent_2" attachedToRef="SubProcess_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="EndEvent_2_di" bpmnElement="EndEvent_2">
<dc:Bounds x="555" y="131" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="528" y="167" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Transaction_1_di" bpmnElement="Transaction_1" isExpanded="true">
<dc:Bounds x="46" y="45" width="350" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="EndEvent_1_di" bpmnElement="EndEvent_1">
<dc:Bounds x="208" y="126" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="181" y="162" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BoundaryEvent_1_di" bpmnElement="BoundaryEvent_1">
<dc:Bounds x="96" y="227" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="379" y="350" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="SubProcess_1_di" bpmnElement="SubProcess_1" isExpanded="true">
<dc:Bounds x="454" y="45" width="350" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BoundaryEvent_2_di" bpmnElement="BoundaryEvent_2">
<dc:Bounds x="483" y="227" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="680" y="350" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -1,95 +0,0 @@
'use strict';
var TestHelper = require('../../../../TestHelper');
/* global bootstrapModeler, inject */
var replacePreviewModule = require('../../../../../lib/features/replace-preview'),
modelingModule = require('../../../../../lib/features/modeling'),
coreModule = require('../../../../../lib/core');
var is = require('../../../../../lib/util/ModelUtil').is,
canvasEvent = require('../../../../util/MockEvents').createCanvasEvent;
describe('features/modeling - move start event behavior', function() {
var testModules = [ replacePreviewModule, modelingModule, coreModule ];
var diagramXML = require('../../../../fixtures/bpmn/event-sub-processes.bpmn');
var moveShape;
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
beforeEach(inject(function(move, dragging, elementRegistry) {
moveShape = function(shape, target, position) {
var startPosition = { x: shape.x + 10 + shape.width / 2, y: shape.y + 30 + shape.height/2 };
move.start(canvasEvent(startPosition), shape);
dragging.hover({
element: target,
gfx: elementRegistry.getGraphics(target)
});
dragging.move(canvasEvent(position));
};
}));
it('should select the replacement after replacing the start event',
inject(function(elementRegistry, canvas, dragging, move, selection) {
// given
var startEvent = elementRegistry.get('StartEvent_1'),
rootElement = canvas.getRootElement();
// when
moveShape(startEvent, rootElement, { x: 140, y: 250 });
dragging.end();
var replacement = elementRegistry.filter(function(element) {
if(is(element, 'bpmn:StartEvent') && element.parent === rootElement) {
return true;
}
})[0];
// then
expect(selection.get()).to.include(replacement);
expect(selection.get()).not.to.include(startEvent);
}));
it('should select all moved shapes after some of them got replaced',
inject(function(elementRegistry, canvas, dragging, move, selection) {
// given
var startEvent1 = elementRegistry.get('StartEvent_1'),
startEvent2 = elementRegistry.get('StartEvent_2'),
startEvent3 = elementRegistry.get('StartEvent_3'),
rootElement = canvas.getRootElement();
// when
selection.select([ startEvent1, startEvent2, startEvent3 ]);
moveShape(startEvent1, rootElement, { x: 140, y: 250 });
dragging.end();
var replacements = elementRegistry.filter(function(element) {
if(is(element, 'bpmn:StartEvent') && element.type !== 'label') {
return true;
}
});
// then
expect(selection.get()).to.include(replacements[0]);
expect(selection.get()).to.include(replacements[1]);
expect(selection.get()).to.include(replacements[2]);
}));
});

View File

@ -0,0 +1,351 @@
'use strict';
var TestHelper = require('../../../../TestHelper');
/* global bootstrapModeler, inject */
var replacePreviewModule = require('../../../../../lib/features/replace-preview'),
modelingModule = require('../../../../../lib/features/modeling'),
moveModule = require('diagram-js/lib/features/move'),
coreModule = require('../../../../../lib/core');
var is = require('../../../../../lib/util/ModelUtil').is,
canvasEvent = require('../../../../util/MockEvents').createCanvasEvent;
describe('features/modeling - move start event behavior', function() {
var testModules = [ replacePreviewModule, modelingModule, coreModule, moveModule ];
describe('Start Events', function() {
var diagramXML = require('../../../../fixtures/bpmn/event-sub-processes.bpmn');
var moveShape;
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
beforeEach(inject(function(move, dragging, elementRegistry) {
moveShape = function(shape, target, position) {
var startPosition = { x: shape.x + 10 + shape.width / 2, y: shape.y + 30 + shape.height/2 };
move.start(canvasEvent(startPosition), shape);
dragging.hover({
element: target,
gfx: elementRegistry.getGraphics(target)
});
dragging.move(canvasEvent(position));
};
}));
it('should select the replacement after replacing the start event',
inject(function(elementRegistry, canvas, dragging, move, selection) {
// given
var startEvent = elementRegistry.get('StartEvent_1'),
rootElement = canvas.getRootElement();
// when
moveShape(startEvent, rootElement, { x: 140, y: 250 });
dragging.end();
var replacement = elementRegistry.filter(function(element) {
if(is(element, 'bpmn:StartEvent') && element.parent === rootElement) {
return true;
}
})[0];
// then
expect(selection.get()).to.include(replacement);
expect(selection.get()).not.to.include(startEvent);
}));
it('should select all moved shapes after some of them got replaced',
inject(function(elementRegistry, canvas, dragging, move, selection) {
// given
var startEvent1 = elementRegistry.get('StartEvent_1'),
startEvent2 = elementRegistry.get('StartEvent_2'),
startEvent3 = elementRegistry.get('StartEvent_3'),
rootElement = canvas.getRootElement();
// when
selection.select([ startEvent1, startEvent2, startEvent3 ]);
moveShape(startEvent1, rootElement, { x: 140, y: 250 });
dragging.end();
var replacements = elementRegistry.filter(function(element) {
if(is(element, 'bpmn:StartEvent') && element.type !== 'label') {
return true;
}
});
// then
expect(selection.get()).to.include(replacements[0]);
expect(selection.get()).to.include(replacements[1]);
expect(selection.get()).to.include(replacements[2]);
}));
});
describe('Cancel Events', function () {
var diagramXML = require('../../../../fixtures/bpmn/features/replace/cancel-events.bpmn');
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
describe('- normal -', function() {
it('should replace CancelEvent when morphing transaction',
inject(function(elementRegistry, bpmnReplace) {
// given
var transaction = elementRegistry.get('Transaction_1'),
endEvent = elementRegistry.get('EndEvent_1');
// when
bpmnReplace.replaceElement(endEvent, {
type: 'bpmn:EndEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
var subProcess = bpmnReplace.replaceElement(transaction, { type: 'bpmn:SubProcess' });
var newEndEvent = subProcess.children[0].businessObject;
// then
expect(subProcess.children).to.have.length(2);
expect(newEndEvent.eventDefinitions).to.not.exist;
}));
it('should replace CancelEvent when morphing transaction -> undo',
inject(function(elementRegistry, bpmnReplace, commandStack) {
// given
var transaction = elementRegistry.get('Transaction_1'),
endEvent = elementRegistry.get('EndEvent_1');
// when
bpmnReplace.replaceElement(endEvent, {
type: 'bpmn:EndEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
bpmnReplace.replaceElement(transaction, { type: 'bpmn:SubProcess' });
commandStack.undo();
var endEventAfter = elementRegistry.filter(function(element) {
return (element.id !== 'EndEvent_2' && element.type === 'bpmn:EndEvent');
})[0];
// then
expect(transaction.children).to.have.length(2);
expect(endEventAfter.businessObject.eventDefinitions).to.exist;
}));
it('should replace a CancelEvent when moving outside of a transaction',
inject(function(elementRegistry, bpmnReplace, modeling) {
// given
var process = elementRegistry.get('Process_1'),
transaction = elementRegistry.get('Transaction_1'),
endEvent = elementRegistry.get('EndEvent_1');
// when
var cancelEvent = bpmnReplace.replaceElement(endEvent, {
type: 'bpmn:EndEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
modeling.moveElements([ cancelEvent ], { x: 0, y: 150 }, process);
var endEventAfter = elementRegistry.filter(function(element) {
return (element.parent === process && element.type === 'bpmn:EndEvent');
})[0];
// then
expect(transaction.children).to.have.length(0);
expect(endEventAfter.businessObject.eventDefinitions).to.not.exist;
}));
it('should replace a CancelEvent when moving outside of a transaction -> undo',
inject(function(elementRegistry, bpmnReplace, modeling, commandStack) {
// given
var process = elementRegistry.get('Process_1'),
transaction = elementRegistry.get('Transaction_1'),
endEvent = elementRegistry.get('EndEvent_1');
// when
var cancelEvent = bpmnReplace.replaceElement(endEvent, {
type: 'bpmn:EndEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
modeling.moveElements([ cancelEvent ], { x: 0, y: 150 }, process);
commandStack.undo();
var endEventAfter = elementRegistry.filter(function(element) {
return (element.id !== 'EndEvent_2' && element.type === 'bpmn:EndEvent');
})[0];
// then
expect(transaction.children).to.have.length(2);
expect(endEventAfter.businessObject.eventDefinitions).to.exist;
}));
});
describe('- boundary events -', function() {
it('should replace CancelBoundaryEvent when morphing from a transaction',
inject(function(elementRegistry, bpmnReplace) {
// given
var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
transaction = elementRegistry.get('Transaction_1');
// when
bpmnReplace.replaceElement(boundaryEvent, {
type: 'bpmn:BoundaryEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
var subProcess = bpmnReplace.replaceElement(transaction, { type: 'bpmn:SubProcess' });
var newBoundaryEvent = subProcess.attachers[0].businessObject;
// then
expect(newBoundaryEvent.eventDefinitions).to.not.exist;
expect(newBoundaryEvent.attachedToRef).to.equal(subProcess.businessObject);
expect(elementRegistry.get('Transaction_1')).to.not.exist;
}));
it('should replace CancelBoundaryEvent when morphing from a transaction -> undo',
inject(function(elementRegistry, bpmnReplace, commandStack) {
// given
var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
transaction = elementRegistry.get('Transaction_1');
// when
bpmnReplace.replaceElement(boundaryEvent, {
type: 'bpmn:BoundaryEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
bpmnReplace.replaceElement(transaction, { type: 'bpmn:SubProcess' });
commandStack.undo();
var afterBoundaryEvent = elementRegistry.filter(function(element) {
return (element.type === 'bpmn:BoundaryEvent' && element.id !== 'BoundaryEvent_2');
})[0];
// then
expect(afterBoundaryEvent.businessObject.eventDefinitions).exist;
expect(afterBoundaryEvent.businessObject.attachedToRef).to.equal(transaction.businessObject);
expect(transaction.attachers).to.have.length(1);
}));
it('should replace CancelBoundaryEvent when attaching to a NON-transaction',
inject(function(elementRegistry, bpmnReplace, modeling) {
// given
var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
subProcess = elementRegistry.get('SubProcess_1'),
process = elementRegistry.get('Process_1'),
transaction = elementRegistry.get('Transaction_1');
// when
var newBoundaryEvent = bpmnReplace.replaceElement(boundaryEvent, {
type: 'bpmn:BoundaryEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
modeling.moveElements([ newBoundaryEvent ], { x: 500, y: 0 }, subProcess, true);
var movedBoundaryEvent = elementRegistry.filter(function(element) {
return (element.type === 'bpmn:BoundaryEvent' && element.id !== 'BoundaryEvent_2');
})[0];
// then
expect(movedBoundaryEvent.businessObject.eventDefinitions).to.not.exist;
expect(movedBoundaryEvent.businessObject.attachedToRef).to.equal(subProcess.businessObject);
expect(movedBoundaryEvent.parent).to.equal(process);
expect(movedBoundaryEvent.host).to.equal(subProcess);
expect(subProcess.attachers).to.contain(movedBoundaryEvent);
expect(transaction.attachers).to.be.empty;
}));
it('should replace CancelBoundaryEvent when attaching to a NON-transaction -> undo',
inject(function(elementRegistry, bpmnReplace, modeling, commandStack) {
// given
var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
transaction = elementRegistry.get('Transaction_1'),
subProcess = elementRegistry.get('SubProcess_1');
// when
var newBoundaryEvent = bpmnReplace.replaceElement(boundaryEvent, {
type: 'bpmn:BoundaryEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
modeling.moveElements([ newBoundaryEvent ], { x: 500, y: 0 }, subProcess, true);
commandStack.undo();
var movedBoundaryEvent = elementRegistry.filter(function(element) {
return (element.type === 'bpmn:BoundaryEvent' && element.id !== 'BoundaryEvent_2');
})[0];
// then
expect(movedBoundaryEvent.businessObject.eventDefinitions).to.exist;
expect(movedBoundaryEvent.businessObject.attachedToRef).to.equal(transaction.businessObject);
expect(movedBoundaryEvent.host).to.equal(transaction);
expect(transaction.attachers).to.contain(movedBoundaryEvent);
expect(subProcess.attachers).to.have.length(1);
}));
it('should NOT allow morphing into an IntermediateEvent',
inject(function(elementRegistry, bpmnReplace, commandStack, move, dragging) {
// given
var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
subProcess = elementRegistry.get('SubProcess_1');
// when
var newBoundaryEvent = bpmnReplace.replaceElement(boundaryEvent, {
type: 'bpmn:BoundaryEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
move.start(canvasEvent({ x: 0, y: 0 }), newBoundaryEvent);
dragging.hover({
gfx: elementRegistry.getGraphics(subProcess),
element: subProcess
});
dragging.move(canvasEvent({ x: 450, y: -50 }));
var canExecute = dragging.active().data.context.canExecute;
// then
expect(canExecute).to.be.false;
}));
});
});
});

View File

@ -618,7 +618,7 @@ describe('features/popup-menu', function() {
// then
expect(queryEntry(popupMenu, 'replace-with-none-end')).to.be.null;
expect(entriesContainer.childNodes.length).to.equal(9);
expect(entriesContainer.childNodes.length).to.equal(8);
}));

View File

@ -6,8 +6,12 @@ var TestHelper = require('../../../TestHelper');
var modelingModule = require('../../../../lib/features/modeling'),
replaceModule = require('../../../../lib/features/replace'),
coreModule = require('../../../../lib/core'),
is = require('../../../../lib/util/ModelUtil').is,
moveModule = require('diagram-js/lib/features/move'),
coreModule = require('../../../../lib/core');
var canvasEvent = require('../../../util/MockEvents').createCanvasEvent;
var is = require('../../../../lib/util/ModelUtil').is,
isExpanded = require('../../../../lib/util/DiUtil').isExpanded,
isInterrupting = require('../../../../lib/util/DiUtil').isInterrupting,
isEventSubProcess = require('../../../../lib/util/DiUtil').isEventSubProcess;
@ -15,7 +19,7 @@ var modelingModule = require('../../../../lib/features/modeling'),
describe('features/replace', function() {
var testModules = [ coreModule, modelingModule, replaceModule ];
var testModules = [ coreModule, modelingModule, replaceModule, moveModule ];
describe('should replace', function() {
@ -857,4 +861,256 @@ describe('features/replace', function() {
});
describe('Cancel Events', function () {
var diagramXML = require('../../../fixtures/bpmn/features/replace/cancel-events.bpmn');
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
describe('- normal -', function() {
it('should replace CancelEvent when morphing transaction',
inject(function(elementRegistry, bpmnReplace) {
// given
var transaction = elementRegistry.get('Transaction_1'),
endEvent = elementRegistry.get('EndEvent_1');
// when
bpmnReplace.replaceElement(endEvent, {
type: 'bpmn:EndEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
var subProcess = bpmnReplace.replaceElement(transaction, { type: 'bpmn:SubProcess' });
var newEndEvent = subProcess.children[0].businessObject;
// then
expect(subProcess.children).to.have.length(2);
expect(newEndEvent.eventDefinitions).to.not.exist;
}));
it('should replace CancelEvent when morphing transaction -> undo',
inject(function(elementRegistry, bpmnReplace, commandStack) {
// given
var transaction = elementRegistry.get('Transaction_1'),
endEvent = elementRegistry.get('EndEvent_1');
// when
bpmnReplace.replaceElement(endEvent, {
type: 'bpmn:EndEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
bpmnReplace.replaceElement(transaction, { type: 'bpmn:SubProcess' });
commandStack.undo();
var endEventAfter = elementRegistry.filter(function(element) {
return (element.id !== 'EndEvent_2' && element.type === 'bpmn:EndEvent');
})[0];
// then
expect(transaction.children).to.have.length(2);
expect(endEventAfter.businessObject.eventDefinitions).to.exist;
}));
it('should replace a CancelEvent when moving outside of a transaction',
inject(function(elementRegistry, bpmnReplace, modeling) {
// given
var process = elementRegistry.get('Process_1'),
transaction = elementRegistry.get('Transaction_1'),
endEvent = elementRegistry.get('EndEvent_1');
// when
var cancelEvent = bpmnReplace.replaceElement(endEvent, {
type: 'bpmn:EndEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
modeling.moveElements([ cancelEvent ], { x: 0, y: 150 }, process);
var endEventAfter = elementRegistry.filter(function(element) {
return (element.parent === process && element.type === 'bpmn:EndEvent');
})[0];
// then
expect(transaction.children).to.have.length(0);
expect(endEventAfter.businessObject.eventDefinitions).to.not.exist;
}));
it('should replace a CancelEvent when moving outside of a transaction -> undo',
inject(function(elementRegistry, bpmnReplace, modeling, commandStack) {
// given
var process = elementRegistry.get('Process_1'),
transaction = elementRegistry.get('Transaction_1'),
endEvent = elementRegistry.get('EndEvent_1');
// when
var cancelEvent = bpmnReplace.replaceElement(endEvent, {
type: 'bpmn:EndEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
modeling.moveElements([ cancelEvent ], { x: 0, y: 150 }, process);
commandStack.undo();
var endEventAfter = elementRegistry.filter(function(element) {
return (element.id !== 'EndEvent_2' && element.type === 'bpmn:EndEvent');
})[0];
// then
expect(transaction.children).to.have.length(2);
expect(endEventAfter.businessObject.eventDefinitions).to.exist;
}));
});
describe('- boundary events -', function() {
it('should replace CancelBoundaryEvent when morphing from a transaction',
inject(function(elementRegistry, bpmnReplace) {
// given
var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
transaction = elementRegistry.get('Transaction_1');
// when
bpmnReplace.replaceElement(boundaryEvent, {
type: 'bpmn:BoundaryEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
var subProcess = bpmnReplace.replaceElement(transaction, { type: 'bpmn:SubProcess' });
var newBoundaryEvent = subProcess.attachers[0].businessObject;
// then
expect(newBoundaryEvent.eventDefinitions).to.not.exist;
expect(newBoundaryEvent.attachedToRef).to.equal(subProcess.businessObject);
expect(elementRegistry.get('Transaction_1')).to.not.exist;
}));
it('should replace CancelBoundaryEvent when morphing from a transaction -> undo',
inject(function(elementRegistry, bpmnReplace, commandStack) {
// given
var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
transaction = elementRegistry.get('Transaction_1');
// when
bpmnReplace.replaceElement(boundaryEvent, {
type: 'bpmn:BoundaryEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
bpmnReplace.replaceElement(transaction, { type: 'bpmn:SubProcess' });
commandStack.undo();
var afterBoundaryEvent = elementRegistry.filter(function(element) {
return (element.type === 'bpmn:BoundaryEvent' && element.id !== 'BoundaryEvent_2');
})[0];
// then
expect(afterBoundaryEvent.businessObject.eventDefinitions).exist;
expect(afterBoundaryEvent.businessObject.attachedToRef).to.equal(transaction.businessObject);
expect(transaction.attachers).to.have.length(1);
}));
it('should replace CancelBoundaryEvent when attaching to a NON-transaction',
inject(function(elementRegistry, bpmnReplace, modeling) {
// given
var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
subProcess = elementRegistry.get('SubProcess_1'),
process = elementRegistry.get('Process_1'),
transaction = elementRegistry.get('Transaction_1');
// when
var newBoundaryEvent = bpmnReplace.replaceElement(boundaryEvent, {
type: 'bpmn:BoundaryEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
modeling.moveElements([ newBoundaryEvent ], { x: 500, y: 0 }, subProcess, true);
var movedBoundaryEvent = elementRegistry.filter(function(element) {
return (element.type === 'bpmn:BoundaryEvent' && element.id !== 'BoundaryEvent_2');
})[0];
// then
expect(movedBoundaryEvent.businessObject.eventDefinitions).to.not.exist;
expect(movedBoundaryEvent.businessObject.attachedToRef).to.equal(subProcess.businessObject);
expect(movedBoundaryEvent.parent).to.equal(process);
expect(movedBoundaryEvent.host).to.equal(subProcess);
expect(subProcess.attachers).to.contain(movedBoundaryEvent);
expect(transaction.attachers).to.be.empty;
}));
it('should replace CancelBoundaryEvent when attaching to a NON-transaction -> undo',
inject(function(elementRegistry, bpmnReplace, modeling, commandStack) {
// given
var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
transaction = elementRegistry.get('Transaction_1'),
subProcess = elementRegistry.get('SubProcess_1');
// when
var newBoundaryEvent = bpmnReplace.replaceElement(boundaryEvent, {
type: 'bpmn:BoundaryEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
modeling.moveElements([ newBoundaryEvent ], { x: 500, y: 0 }, subProcess, true);
commandStack.undo();
var movedBoundaryEvent = elementRegistry.filter(function(element) {
return (element.type === 'bpmn:BoundaryEvent' && element.id !== 'BoundaryEvent_2');
})[0];
// then
expect(movedBoundaryEvent.businessObject.eventDefinitions).to.exist;
expect(movedBoundaryEvent.businessObject.attachedToRef).to.equal(transaction.businessObject);
expect(movedBoundaryEvent.host).to.equal(transaction);
expect(transaction.attachers).to.contain(movedBoundaryEvent);
expect(subProcess.attachers).to.have.length(1);
}));
it('should NOT allow morphing into an IntermediateEvent',
inject(function(elementRegistry, bpmnReplace, commandStack, move, dragging) {
// given
var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
subProcess = elementRegistry.get('SubProcess_1');
// when
var newBoundaryEvent = bpmnReplace.replaceElement(boundaryEvent, {
type: 'bpmn:BoundaryEvent',
eventDefinition: 'bpmn:CancelEventDefinition'
});
move.start(canvasEvent({ x: 0, y: 0 }), newBoundaryEvent);
dragging.hover({
gfx: elementRegistry.getGraphics(subProcess),
element: subProcess
});
dragging.move(canvasEvent({ x: 450, y: -50 }));
var canExecute = dragging.active().data.context.canExecute;
expect(canExecute).to.be.false;
}));
});
});
});