fix(modeling/BpmnUpdater): ignore custom elements on canvas.updateRoot

Closes #559
This commit is contained in:
Nico Rehwaldt 2016-05-30 19:42:46 +02:00 committed by Vladimirs Katusenoks
parent f15647edfd
commit 7e93759a0d
3 changed files with 150 additions and 72 deletions

View File

@ -103,7 +103,9 @@ function BpmnUpdater(eventBus, bpmnFactory, connectionDocking, translate) {
children = oldRoot.children;
forEach(children, function(child) {
self.updateParent(child);
if (is(child, 'bpmn:BaseElement')) {
self.updateParent(child);
}
});
}
@ -539,7 +541,7 @@ BpmnUpdater.prototype.updateSemanticParent = function(businessObject, newParent,
diChildren = [];
newParent.set(containment, diChildren);
}
diChildren.push(businessObject);
}
}

View File

@ -14,17 +14,20 @@ var customElementsModules = require('./custom-elements'),
var testModules = [].concat(modelerModules, customModules);
var processDiagramXML = require('../fixtures/bpmn/simple.bpmn');
var collaborationDiagramXML = require('../fixtures/bpmn/collaboration.bpmn');
describe('custom elements', function() {
var diagramXML = require('../fixtures/bpmn/simple.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules
}));
describe('renderer', function () {
beforeEach(bootstrapModeler(processDiagramXML, {
modules: testModules
}));
var triangle, circle;
beforeEach(inject(function(elementFactory, canvas) {
@ -79,91 +82,140 @@ describe('custom elements', function() {
describe('integration', function () {
var triangle, circle;
describe('process diagram', function() {
beforeEach(inject(function(elementFactory, canvas) {
circle = elementFactory.createShape({
id: 'circle',
type: 'custom:circle',
x: 800, y: 100
});
canvas.addShape(circle);
triangle = elementFactory.createShape({
id: 'triangle',
type: 'custom:triangle',
x: 700, y: 100
});
canvas.addShape(triangle);
}));
beforeEach(bootstrapModeler(processDiagramXML, {
modules: testModules
}));
it('should allow moving a custom shape inside another one',
inject(function(elementFactory, elementRegistry, dragging, move) {
var triangle, circle;
// given
var circleGfx = elementRegistry.getGraphics(circle);
beforeEach(inject(function(elementFactory, canvas) {
// when
move.start(canvasEvent({ x: 0, y: 0 }), triangle);
circle = elementFactory.createShape({
id: 'circle',
type: 'custom:circle',
x: 800, y: 100
});
dragging.move(canvasEvent({ x: 100, y: 0 }));
dragging.hover({ element: circle, gfx: circleGfx });
dragging.move(canvasEvent({ x: 150, y: 50 }));
canvas.addShape(circle);
dragging.end();
triangle = elementFactory.createShape({
id: 'triangle',
type: 'custom:triangle',
x: 700, y: 100
});
// then
expect(triangle.parent).to.equal(circle);
}));
canvas.addShape(triangle);
}));
it('should update the custom shape properties',
inject(function(elementFactory, elementRegistry, dragging, move) {
it('should allow moving a custom shape inside another one',
inject(function(elementFactory, elementRegistry, dragging, move) {
// given
var circleGfx = elementRegistry.getGraphics(circle);
// given
var circleGfx = elementRegistry.getGraphics(circle);
// when
move.start(canvasEvent({ x: 0, y: 0 }), triangle);
// when
move.start(canvasEvent({ x: 0, y: 0 }), triangle);
dragging.move(canvasEvent({ x: 100, y: 0 }));
dragging.hover({ element: circle, gfx: circleGfx });
dragging.move(canvasEvent({ x: 150, y: 50 }));
dragging.move(canvasEvent({ x: 100, y: 0 }));
dragging.hover({ element: circle, gfx: circleGfx });
dragging.move(canvasEvent({ x: 150, y: 50 }));
dragging.end();
dragging.end();
// then
expect(triangle.businessObject.leader).to.equal(circle);
expect(circle.businessObject.companions).to.include(triangle);
}));
// then
expect(triangle.parent).to.equal(circle);
}));
it('should connect a bpmn element to a custom one',
inject(function(elementFactory, dragging, elementRegistry, connect) {
it('should update the custom shape properties',
inject(function(elementFactory, elementRegistry, dragging, move) {
// given
var subProcess = elementRegistry.get('SubProcess_1'),
triangleGfx = elementRegistry.getGraphics(triangle);
// given
var circleGfx = elementRegistry.getGraphics(circle);
// when
connect.start(canvasEvent({ x: 590, y: 90 }), subProcess);
// when
move.start(canvasEvent({ x: 0, y: 0 }), triangle);
dragging.move(canvasEvent({ x: 700, y: 100 }));
dragging.hover({ element: triangle, gfx: triangleGfx });
dragging.move(canvasEvent({ x: 715, y: 115 }));
dragging.move(canvasEvent({ x: 100, y: 0 }));
dragging.hover({ element: circle, gfx: circleGfx });
dragging.move(canvasEvent({ x: 150, y: 50 }));
dragging.end();
dragging.end();
var connection = triangle.incoming[0];
// then
expect(triangle.businessObject.leader).to.equal(circle);
expect(circle.businessObject.companions).to.include(triangle);
}));
// then
expect(connection.type).to.equal('bpmn:Association');
expect(connection.source).to.equal(subProcess);
}));
it('should connect a bpmn element to a custom one',
inject(function(elementFactory, dragging, elementRegistry, connect) {
// given
var subProcess = elementRegistry.get('SubProcess_1'),
triangleGfx = elementRegistry.getGraphics(triangle);
// when
connect.start(canvasEvent({ x: 590, y: 90 }), subProcess);
dragging.move(canvasEvent({ x: 700, y: 100 }));
dragging.hover({ element: triangle, gfx: triangleGfx });
dragging.move(canvasEvent({ x: 715, y: 115 }));
dragging.end();
var connection = triangle.incoming[0];
// then
expect(connection.type).to.equal('bpmn:Association');
expect(connection.source).to.equal(subProcess);
}));
});
describe('collaboration diagram', function() {
beforeEach(bootstrapModeler(collaborationDiagramXML, {
modules: testModules
}));
var triangle;
beforeEach(inject(function(elementFactory, canvas) {
triangle = elementFactory.createShape({
id: 'triangle',
type: 'custom:triangle',
x: 700, y: 100
});
canvas.addShape(triangle);
}));
it('should update parent when removing collaboration',
inject(function(elementRegistry, modeling, canvas) {
// given
var customTriangle = elementRegistry.get('triangle');
// when
modeling.removeElements([
elementRegistry.get('Participant_1'),
elementRegistry.get('Participant_2')
]);
// then
expect(customTriangle.parent).to.eql(canvas.getRootElement());
}));
});
});

View File

@ -8,6 +8,11 @@ var CommandInterceptor = require('diagram-js/lib/command/CommandInterceptor');
function isCustom(element, type) {
if (!type) {
return /custom:/.test(element.type);
}
return element && element.type === type;
}
@ -26,7 +31,7 @@ function ifCustomElement(fn) {
* A handler responsible for updating the custom element's businessObject
* once changes on the diagram happen
*/
function CustomUpdater(eventBus, bpmnFactory, connectionDocking) {
function CustomUpdater(eventBus, modeling) {
CommandInterceptor.call(this, eventBus);
@ -82,10 +87,29 @@ function CustomUpdater(eventBus, bpmnFactory, connectionDocking) {
'shape.create'
], ifCustomElement(updateTriangle));
/**
* When morphing a Process into a Collaboration or vice-versa,
* make sure that the existing custom elements get their parents updated.
*/
function updateCustomElementsRoot(event) {
var context = event.context,
oldRoot = context.oldRoot,
newRoot = context.newRoot,
children = oldRoot.children;
var customChildren = children.filter(isCustom);
if (customChildren.length) {
modeling.moveElements(customChildren, { x: 0, y: 0 }, newRoot);
}
}
this.postExecute('canvas.updateRoot', updateCustomElementsRoot);
}
inherits(CustomUpdater, CommandInterceptor);
module.exports = CustomUpdater;
CustomUpdater.$inject = [ 'eventBus' ];
CustomUpdater.$inject = [ 'eventBus', 'modeling' ];