diff --git a/lib/features/modeling/behavior/CompensateBoundaryEventBehaviour.js b/lib/features/modeling/behavior/CompensateBoundaryEventBehaviour.js
new file mode 100644
index 0000000000..0d5097f03b
--- /dev/null
+++ b/lib/features/modeling/behavior/CompensateBoundaryEventBehaviour.js
@@ -0,0 +1,78 @@
+import inherits from 'inherits-browser';
+
+import { is } from '../../../util/ModelUtil';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+import { hasEventDefinition } from '../../../util/DiUtil';
+
+/**
+ * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
+ * @typedef {import('diagram-js/lib/features/modeling/Modeling').default} Modeling
+ */
+
+export default function CompensateBoundaryEventBehaviour(eventBus, modeling) {
+
+ CommandInterceptor.call(this, eventBus);
+
+ function addIsForCompensationProperty(source, target) {
+ if (isCompensationBoundaryEvent(source)) {
+ if (is(target, 'bpmn:Activity') && !isForCompensation(target)) {
+ modeling.updateProperties(target, { isForCompensation: true });
+ }
+ }
+ }
+
+ function removeIsForCompensationProperty(source, target) {
+ if (isCompensationBoundaryEvent(source)) {
+ if (is(target, 'bpmn:Activity') && isForCompensation(target)) {
+ modeling.updateProperties(target, { isForCompensation: false });
+ }
+ }
+ }
+
+ this.preExecute('connection.create', function(context) {
+ var source = context.source,
+ target = context.target;
+
+ addIsForCompensationProperty(source, target);
+ }, true);
+
+ this.postExecute('connection.reconnect', function(context) {
+ var newSource = context.newSource,
+ newTarget = context.newTarget,
+ oldSource = context.oldSource,
+ oldTarget = context.oldTarget;
+
+ // add `isForCompensation` to new target
+ addIsForCompensationProperty(newSource, newTarget);
+
+ // remove `isForCompensation` from old target
+ removeIsForCompensationProperty(oldSource, oldTarget);
+ }, true);
+
+ this.postExecute('connection.delete', function(context) {
+ var source = context.source,
+ target = context.target;
+
+ removeIsForCompensationProperty(source, target);
+ }, true);
+
+}
+
+inherits(CompensateBoundaryEventBehaviour, CommandInterceptor);
+
+CompensateBoundaryEventBehaviour.$inject = [
+ 'eventBus',
+ 'modeling'
+];
+
+// helpers //////////
+
+function isForCompensation(element) {
+ return element && element.businessObject.isForCompensation;
+}
+
+function isCompensationBoundaryEvent(element) {
+ return element && is(element, 'bpmn:BoundaryEvent') &&
+ hasEventDefinition(element, 'bpmn:CompensateEventDefinition');
+}
\ No newline at end of file
diff --git a/lib/features/modeling/behavior/index.js b/lib/features/modeling/behavior/index.js
index 4e2f681a3f..50272f838c 100644
--- a/lib/features/modeling/behavior/index.js
+++ b/lib/features/modeling/behavior/index.js
@@ -3,6 +3,7 @@ import AppendBehavior from './AppendBehavior';
import AssociationBehavior from './AssociationBehavior';
import AttachEventBehavior from './AttachEventBehavior';
import BoundaryEventBehavior from './BoundaryEventBehavior';
+import CompensateBoundaryEventBehaviour from './CompensateBoundaryEventBehaviour';
import CreateBehavior from './CreateBehavior';
import CreateDataObjectBehavior from './CreateDataObjectBehavior';
import CreateParticipantBehavior from './CreateParticipantBehavior';
@@ -47,6 +48,7 @@ export default {
'associationBehavior',
'attachEventBehavior',
'boundaryEventBehavior',
+ 'compensateBoundaryEventBehaviour',
'createBehavior',
'createDataObjectBehavior',
'createParticipantBehavior',
@@ -86,6 +88,7 @@ export default {
associationBehavior: [ 'type', AssociationBehavior ],
attachEventBehavior: [ 'type', AttachEventBehavior ],
boundaryEventBehavior: [ 'type', BoundaryEventBehavior ],
+ compensateBoundaryEventBehaviour: [ 'type', CompensateBoundaryEventBehaviour ],
createBehavior: [ 'type', CreateBehavior ],
createDataObjectBehavior: [ 'type', CreateDataObjectBehavior ],
createParticipantBehavior: [ 'type', CreateParticipantBehavior ],
diff --git a/lib/features/rules/BpmnRules.js b/lib/features/rules/BpmnRules.js
index e6f4331428..0bb1284224 100644
--- a/lib/features/rules/BpmnRules.js
+++ b/lib/features/rules/BpmnRules.js
@@ -550,15 +550,15 @@ function canConnect(source, target, connection) {
return connectDataAssociation;
}
- if (isCompensationBoundary(source) && isForCompensation(target)) {
- return {
- type: 'bpmn:Association',
- associationDirection: 'One'
- };
- }
-
if (canConnectAssociation(source, target)) {
+ if (isCompensationBoundary(source) && is(target, 'bpmn:Activity')) {
+ return {
+ type: 'bpmn:Association',
+ associationDirection: 'One'
+ };
+ }
+
return {
type: 'bpmn:Association'
};
@@ -1028,7 +1028,7 @@ function isOneTextAnnotation(source, target) {
function canConnectAssociation(source, target) {
// compensation boundary events are exception
- if (isCompensationBoundary(source) && isForCompensation(target)) {
+ if (isCompensationBoundary(source) && is(target, 'bpmn:Activity') && !isEventSubProcess(target)) {
return true;
}
diff --git a/test/spec/features/modeling/behavior/CompensateBoundaryEventBehaviour.bpmn b/test/spec/features/modeling/behavior/CompensateBoundaryEventBehaviour.bpmn
new file mode 100644
index 0000000000..3d2b2bf7aa
--- /dev/null
+++ b/test/spec/features/modeling/behavior/CompensateBoundaryEventBehaviour.bpmn
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/spec/features/modeling/behavior/CompensateBoundaryEventBehaviourSpec.js b/test/spec/features/modeling/behavior/CompensateBoundaryEventBehaviourSpec.js
new file mode 100644
index 0000000000..d5dc464dd1
--- /dev/null
+++ b/test/spec/features/modeling/behavior/CompensateBoundaryEventBehaviourSpec.js
@@ -0,0 +1,115 @@
+import {
+ bootstrapModeler,
+ inject
+} from 'test/TestHelper';
+
+import modelingModule from 'lib/features/modeling';
+import coreModule from 'lib/core';
+
+import diagramXML from './CompensateBoundaryEventBehaviour.bpmn';
+
+
+describe('features/modeling/behavior - compensation boundary event', function() {
+
+ var testModules = [ coreModule, modelingModule ];
+
+ beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
+
+
+ describe('should add `isForCompensation`', function() {
+
+ it('on append', inject(function(elementFactory, modeling, elementRegistry) {
+
+ // given
+ var boundaryEventShape = elementRegistry.get('Attached_Event');
+ var taskShape = elementFactory.createShape({ type: 'bpmn:Task' });
+
+ // when
+ var task = modeling.appendShape(boundaryEventShape, taskShape, { x: 100, y: 100 });
+
+ // then
+ expect(task.businessObject.isForCompensation).to.be.true;
+ }));
+
+
+ it('on connect', inject(function(modeling, elementRegistry) {
+
+ // given
+ var boundaryEventShape = elementRegistry.get('Attached_Event');
+ var taskShape = elementRegistry.get('Task');
+
+ // when
+ modeling.connect(boundaryEventShape, taskShape);
+
+ // then
+ expect(taskShape.businessObject.isForCompensation).to.be.true;
+ }));
+
+
+ it('on reconnect', inject(function(modeling, elementRegistry) {
+
+ // given
+ var taskShape = elementRegistry.get('Task');
+ var connection = elementRegistry.get('Association');
+
+ // when
+ modeling.reconnectEnd(connection, taskShape, { x: 100, y: 100 });
+
+ // then
+ expect(taskShape.businessObject.isForCompensation).to.be.true;
+ }));
+ });
+
+
+ describe('should remove `isForCompensation`', function() {
+
+ it('on remove element', inject(function(elementRegistry, modeling) {
+
+ // given
+ var taskShape = elementRegistry.get('Task_Compensation');
+ var boundaryEventShape = elementRegistry.get('Attached_Event2');
+
+ // then
+ expect(taskShape.businessObject.isForCompensation).to.be.true;
+
+ // when
+ modeling.removeElements([ boundaryEventShape ]);
+
+ // then
+ expect(taskShape.businessObject.isForCompensation).to.be.false;
+ }));
+
+
+ it('on delete connection', inject(function(elementRegistry, modeling) {
+
+ // given
+ var taskShape = elementRegistry.get('Task_Compensation');
+ var connection = elementRegistry.get('Association');
+
+ // then
+ expect(taskShape.businessObject.isForCompensation).to.be.true;
+
+ // when
+ modeling.removeConnection(connection);
+
+ // then
+ expect(taskShape.businessObject.isForCompensation).to.be.false;
+ }));
+
+
+ it('on reconnect', inject(function(modeling, elementRegistry) {
+
+ // given
+ var oldShape = elementRegistry.get('Task_Compensation');
+ var taskShape = elementRegistry.get('Task');
+ var connection = elementRegistry.get('Association');
+
+ // when
+ modeling.reconnectEnd(connection, taskShape, { x: 100, y: 100 });
+
+ // then
+ expect(oldShape.businessObject.isForCompensation).to.be.false;
+ }));
+
+ });
+});
diff --git a/test/spec/features/rules/BpmnRules.compensation.bpmn b/test/spec/features/rules/BpmnRules.compensation.bpmn
index 3ca81df018..7e837bf966 100644
--- a/test/spec/features/rules/BpmnRules.compensation.bpmn
+++ b/test/spec/features/rules/BpmnRules.compensation.bpmn
@@ -17,16 +17,16 @@
-
-
+
+
+
+
+
-
-
-
-
+
@@ -61,6 +61,15 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/spec/features/rules/BpmnRulesSpec.js b/test/spec/features/rules/BpmnRulesSpec.js
index 2cdf802dd7..b0cdab46d7 100644
--- a/test/spec/features/rules/BpmnRulesSpec.js
+++ b/test/spec/features/rules/BpmnRulesSpec.js
@@ -733,6 +733,28 @@ describe('features/modeling/rules - BpmnRules', function() {
it('connect CompensationBoundary -> Task', inject(function() {
expectCanConnect('CompensationBoundary', 'Task', {
+ sequenceFlow: false,
+ messageFlow: false,
+ association: true,
+ dataAssociation: false
+ });
+ }));
+
+
+ it('connect CompensationBoundary -> SubProcess', inject(function() {
+
+ expectCanConnect('CompensationBoundary', 'SubProcess_2', {
+ sequenceFlow: false,
+ messageFlow: false,
+ association: true,
+ dataAssociation: false
+ });
+ }));
+
+
+ it('connect CompensationBoundary -> Event SubProcess', inject(function() {
+
+ expectCanConnect('CompensationBoundary', 'SubProcess_1', {
sequenceFlow: false,
messageFlow: false,
association: false,