diff --git a/lib/features/replace/BpmnReplace.js b/lib/features/replace/BpmnReplace.js
index 77ba0566..91a41f34 100644
--- a/lib/features/replace/BpmnReplace.js
+++ b/lib/features/replace/BpmnReplace.js
@@ -1,7 +1,9 @@
'use strict';
-var forEach = require('lodash/collection/forEach'),
- filter = require('lodash/collection/filter');
+var forEach = require('lodash/collection/forEach'),
+ filter = require('lodash/collection/filter'),
+ pick = require('lodash/object/pick'),
+ assign = require('lodash/object/assign');
var REPLACE_OPTIONS = require ('./ReplaceOptions');
@@ -11,12 +13,20 @@ var startEventReplace = REPLACE_OPTIONS.START_EVENT,
gatewayReplace = REPLACE_OPTIONS.GATEWAY,
taskReplace = REPLACE_OPTIONS.TASK,
subProcessExpandedReplace = REPLACE_OPTIONS.SUBPROCESS_EXPANDED,
- transactionReplace = REPLACE_OPTIONS.TRANSACTION;
+ transactionReplace = REPLACE_OPTIONS.TRANSACTION,
+ boundaryEventReplace = REPLACE_OPTIONS.BOUNDARY_EVENT;
var is = require('../../util/ModelUtil').is,
getBusinessObject = require('../../util/ModelUtil').getBusinessObject,
isExpanded = require('../../util/DiUtil').isExpanded;
+var CUSTOM_PROPERTIES = [
+ 'cancelActivity',
+ 'instantiate',
+ 'eventGatewayType'
+];
+
+
/**
* A replace menu provider that gives users the controls to choose
* and replace BPMN elements with each other.
@@ -60,13 +70,10 @@ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection, modelin
eventDefinitions.push(eventDefinition);
}
- if (target.instantiate !== undefined) {
- businessObject.instantiate = target.instantiate;
- }
+ // initialize special properties defined in target definition
+
+ assign(businessObject, pick(target, CUSTOM_PROPERTIES));
- if (target.eventGatewayType !== undefined) {
- businessObject.eventGatewayType = target.eventGatewayType;
- }
// copy size (for activities only)
if (is(oldBusinessObject, 'bpmn:Activity')) {
@@ -77,6 +84,7 @@ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection, modelin
newElement.height = element.height;
}
+
if (is(oldBusinessObject, 'bpmn:SubProcess')) {
newElement.isExpanded = isExpanded(oldBusinessObject);
}
@@ -236,6 +244,10 @@ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection, modelin
});
} else
+ if (is(businessObject, 'bpmn:BoundaryEvent')) {
+ addEntries(boundaryEventReplace, filterEvents);
+ } else
+
if (is(businessObject, 'bpmn:FlowNode')) {
addEntries(taskReplace, function(entry) {
return entry.target.type !== businessObject.$type;
@@ -247,13 +259,16 @@ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection, modelin
var target = entry.target;
- var eventDefinition = businessObject.eventDefinitions && businessObject.eventDefinitions[0].$type;
- var isEventDefinitionEqual = target.eventDefinition == eventDefinition;
- var isEventTypeEqual = businessObject.$type == target.type;
+ var eventDefinition = businessObject.eventDefinitions && businessObject.eventDefinitions[0].$type,
+ cancelActivity = target.cancelActivity !== false;
+
+ var isEventDefinitionEqual = target.eventDefinition == eventDefinition,
+ isEventTypeEqual = businessObject.$type == target.type,
+ isInterruptingEqual = businessObject.cancelActivity == cancelActivity;
return ((!isEventDefinitionEqual && isEventTypeEqual) ||
!isEventTypeEqual) ||
- !(isEventDefinitionEqual && isEventTypeEqual);
+ !(isEventDefinitionEqual && isEventTypeEqual && isInterruptingEqual);
}
diff --git a/lib/features/replace/ReplaceOptions.js b/lib/features/replace/ReplaceOptions.js
index 91ef92cf..d03f4bac 100644
--- a/lib/features/replace/ReplaceOptions.js
+++ b/lib/features/replace/ReplaceOptions.js
@@ -90,7 +90,7 @@ module.exports.INTERMEDIATE_EVENT = [
},
{
label: 'Message Intermediate Catch Event',
- actionName: 'replace-with-intermediate-catch',
+ actionName: 'replace-with-message-intermediate-catch',
className: 'icon-intermediate-event-catch-message',
target: {
type: 'bpmn:IntermediateCatchEvent',
@@ -99,7 +99,7 @@ module.exports.INTERMEDIATE_EVENT = [
},
{
label: 'Message Intermediate Throw Event',
- actionName: 'replace-with-intermediate-throw',
+ actionName: 'replace-with-message-intermediate-throw',
className: 'icon-intermediate-event-throw-message',
target: {
type: 'bpmn:IntermediateThrowEvent',
@@ -117,7 +117,7 @@ module.exports.INTERMEDIATE_EVENT = [
},
{
label: 'Escalation Intermediate Catch Event',
- actionName: 'replace-with-escalation-catch',
+ actionName: 'replace-with-escalation-intermediate-catch',
className: 'icon-intermediate-event-catch-escalation',
target: {
type: 'bpmn:IntermediateCatchEvent',
@@ -161,8 +161,8 @@ module.exports.INTERMEDIATE_EVENT = [
}
},
{
- label: 'Signal Throw Catch Event',
- actionName: 'replace-with-throw-intermediate-catch',
+ label: 'Signal Intermediate Catch Event',
+ actionName: 'replace-with-signal-intermediate-catch',
className: 'icon-intermediate-event-catch-signal',
target: {
type: 'bpmn:IntermediateCatchEvent',
@@ -444,3 +444,110 @@ module.exports.TASK = [
}
}
];
+
+module.exports.BOUNDARY_EVENT = [
+ {
+ label: 'Message Boundary Event',
+ actionName: 'replace-with-message-boundary',
+ className: 'icon-intermediate-event-catch-message',
+ target: {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:MessageEventDefinition'
+ }
+ },
+ {
+ label: 'Timer Boundary Event',
+ actionName: 'replace-with-timer-boundary',
+ className: 'icon-intermediate-event-catch-timer',
+ target: {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:TimerEventDefinition'
+ }
+ },
+ {
+ label: 'Escalation Boundary Event',
+ actionName: 'replace-with-escalation-boundary',
+ className: 'icon-intermediate-event-catch-escalation',
+ target: {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:EscalationEventDefinition'
+ }
+ },
+ {
+ label: 'Conditional Boundary Event',
+ actionName: 'replace-with-conditional-boundary',
+ className: 'icon-intermediate-event-catch-condition',
+ target: {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:ConditionalEventDefinition'
+ }
+ },
+ {
+ label: 'Error Boundary Event',
+ actionName: 'replace-with-error-boundary',
+ className: 'icon-intermediate-event-catch-error',
+ target: {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:ErrorEventDefinition'
+ }
+ },
+ {
+ label: 'Signal Boundary Event',
+ actionName: 'replace-with-signal-boundary',
+ className: 'icon-intermediate-event-catch-signal',
+ target: {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:SignalEventDefinition'
+ }
+ },
+ {
+ label: 'Message Boundary Event (non-interrupting)',
+ actionName: 'replace-with-non-interrupting-message-boundary',
+ className: 'icon-intermediate-event-catch-non-interrupting-message',
+ target: {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:MessageEventDefinition',
+ cancelActivity: false
+ }
+ },
+ {
+ label: 'Timer Boundary Event (non-interrupting)',
+ actionName: 'replace-with-non-interrupting-timer-boundary',
+ className: 'icon-intermediate-event-catch-non-interrupting-timer',
+ target: {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:TimerEventDefinition',
+ cancelActivity: false
+ }
+ },
+ {
+ label: 'Escalation Boundary Event (non-interrupting)',
+ actionName: 'replace-with-non-interrupting-escalation-boundary',
+ className: 'icon-intermediate-event-catch-non-interrupting-escalation',
+ target: {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:EscalationEventDefinition',
+ cancelActivity: false
+ }
+ },
+ {
+ label: 'Conditional Boundary Event (non-interrupting)',
+ actionName: 'replace-with-non-interrupting-conditional-boundary',
+ className: 'icon-intermediate-event-catch-non-interrupting-condition',
+ target: {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:ConditionalEventDefinition',
+ cancelActivity: false
+ }
+ },
+ {
+ label: 'Signal Boundary Event (non-interrupting)',
+ actionName: 'replace-with-non-interrupting-signal-boundary',
+ className: 'icon-intermediate-event-catch-non-interrupting-signal',
+ target: {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:SignalEventDefinition',
+ cancelActivity: false
+ }
+ },
+];
diff --git a/test/fixtures/bpmn/draw/activity-markers-simple.bpmn b/test/fixtures/bpmn/draw/activity-markers-simple.bpmn
index 444714c1..8fb5d1e7 100644
--- a/test/fixtures/bpmn/draw/activity-markers-simple.bpmn
+++ b/test/fixtures/bpmn/draw/activity-markers-simple.bpmn
@@ -14,6 +14,12 @@
+
+
+
+
+
+
@@ -38,6 +44,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/bpmn/features/replace/01_replace.bpmn b/test/fixtures/bpmn/features/replace/01_replace.bpmn
index 711df8ec..9643d6dd 100644
--- a/test/fixtures/bpmn/features/replace/01_replace.bpmn
+++ b/test/fixtures/bpmn/features/replace/01_replace.bpmn
@@ -31,6 +31,12 @@
+
+
+
+
+
+
@@ -107,6 +113,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/spec/features/popup-menu/PopupMenuSpec.js b/test/spec/features/popup-menu/PopupMenuSpec.js
index 65de7eeb..2c449635 100644
--- a/test/spec/features/popup-menu/PopupMenuSpec.js
+++ b/test/spec/features/popup-menu/PopupMenuSpec.js
@@ -514,7 +514,7 @@ describe('features/popup-menu', function() {
var entry = queryEntry(popupMenu, 'replace-with-subprocess');
// when
- // replacing the expanded sub process with a transaction
+ // replacing the transaction with an expanded sub process
var subProcess = popupMenu.trigger(Events.create(entry, { x: 0, y: 0 }));
// then
@@ -523,4 +523,41 @@ describe('features/popup-menu', function() {
});
+ describe('replace menu', function() {
+
+ it('should contain all boundary events for an interrupting boundary event',
+ inject(function(popupMenu, bpmnReplace, elementRegistry) {
+
+ // given
+ var boundaryEvent = elementRegistry.get('BoundaryEvent_1');
+
+ // when
+ openPopup(boundaryEvent, 40);
+
+ var entriesContainer = queryPopup(popupMenu, '.djs-popup-body');
+
+ // then
+ expect(entriesContainer.childNodes.length).to.equal(10);
+ expect(queryEntry(popupMenu, 'replace-with-message-intermediate-catch')).to.be.null;
+ }));
+
+
+ it('should contain all boundary events for a non interrupting boundary event',
+ inject(function(popupMenu, bpmnReplace, elementRegistry) {
+
+ // given
+ var boundaryEvent = elementRegistry.get('BoundaryEvent_2');
+
+ // when
+ openPopup(boundaryEvent, 40);
+
+ var entriesContainer = queryPopup(popupMenu, '.djs-popup-body');
+
+ // then
+ expect(entriesContainer.childNodes.length).to.equal(10);
+ expect(queryEntry(popupMenu, 'replace-with-non-interrupting-message-intermediate-catch')).to.be.null;
+ }));
+
+ });
+
});
diff --git a/test/spec/features/replace/BpmnReplaceSpec.js b/test/spec/features/replace/BpmnReplaceSpec.js
index 30f06d1c..5d319d74 100644
--- a/test/spec/features/replace/BpmnReplaceSpec.js
+++ b/test/spec/features/replace/BpmnReplaceSpec.js
@@ -82,19 +82,85 @@ describe('features/replace', function() {
it('transaction', inject(function(elementRegistry, modeling, bpmnReplace, canvas) {
+ // given
var transaction = elementRegistry.get('Transaction_1'),
newElementData = {
type: 'bpmn:SubProcess',
isExpanded: true
};
+ // when
var newElement = bpmnReplace.replaceElement(transaction, newElementData);
+ // then
expect(newElement).to.be.defined;
expect(is(newElement.businessObject, 'bpmn:SubProcess')).to.be.true;
}));
+
+ it('non interrupting boundary event by interrupting boundary event',
+ inject(function(elementRegistry, modeling, bpmnReplace, canvas) {
+
+ // given
+ var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
+ newElementData = {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:EscalationEventDefinition'
+ };
+
+ // when
+ var newElement = bpmnReplace.replaceElement(boundaryEvent, newElementData);
+
+ // then
+ expect(newElement).to.be.defined;
+ expect(is(newElement.businessObject, 'bpmn:BoundaryEvent')).to.be.true;
+ expect(newElement.businessObject.eventDefinitions[0].$type).to.equal('bpmn:EscalationEventDefinition');
+ expect(newElement.businessObject.cancelActivity).to.be.true;
+ }));
+
+
+ it('interrupting boundary event by non interrupting boundary event',
+ inject(function(elementRegistry, modeling, bpmnReplace, canvas) {
+
+ // given
+ var boundaryEvent = elementRegistry.get('BoundaryEvent_2'),
+ newElementData = {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:SignalEventDefinition',
+ cancelActivity: false
+ };
+
+ // when
+ var newElement = bpmnReplace.replaceElement(boundaryEvent, newElementData);
+
+ // then
+ expect(newElement).to.be.defined;
+ expect(is(newElement.businessObject, 'bpmn:BoundaryEvent')).to.be.true;
+ expect(newElement.businessObject.eventDefinitions[0].$type).to.equal('bpmn:SignalEventDefinition');
+ expect(newElement.businessObject.cancelActivity).to.be.false;
+ }));
+
+
+ it('boundary event and update host',
+ inject(function(elementRegistry, modeling, bpmnReplace, canvas) {
+
+ // given
+ var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
+ host = elementRegistry.get('Task_1'),
+ newElementData = {
+ type: 'bpmn:BoundaryEvent',
+ eventDefinition: 'bpmn:ErrorEventDefinition',
+ };
+
+ // when
+ var newElement = bpmnReplace.replaceElement(boundaryEvent, newElementData);
+
+ // then
+ expect(newElement.host).to.be.defined;
+ expect(newElement.host).to.eql(host);
+ }));
+
});