feat(copy-paste): clone properties when morphing to new element

Closes #648
This commit is contained in:
Ricardo Matias 2017-01-19 16:16:56 +01:00 committed by Nico Rehwaldt
parent 432d7f4b7c
commit 2ecb9aeae4
4 changed files with 106 additions and 99 deletions

View File

@ -4,9 +4,15 @@ var ModelUtil = require('../../util/ModelUtil'),
getBusinessObject = ModelUtil.getBusinessObject, getBusinessObject = ModelUtil.getBusinessObject,
is = ModelUtil.is; is = ModelUtil.is;
var map = require('lodash/collection/map'), var ModelCloneHelper = require('../../util/model/ModelCloneHelper');
forEach = require('lodash/collection/forEach');
var ModelCloneUtils = require('../../util/model/ModelCloneUtils'),
getProperties = ModelCloneUtils.getProperties;
var IGNORED_PROPERTIES = ModelCloneUtils.IGNORED_PROPERTIES;
var filter = require('lodash/collection/filter'),
forEach = require('lodash/collection/forEach');
function setProperties(descriptor, data, properties) { function setProperties(descriptor, data, properties) {
forEach(properties, function(property) { forEach(properties, function(property) {
@ -26,61 +32,38 @@ function removeProperties(element, properties) {
function BpmnCopyPaste(bpmnFactory, eventBus, copyPaste, clipboard, moddle, canvas, bpmnRules) { function BpmnCopyPaste(bpmnFactory, eventBus, copyPaste, clipboard, moddle, canvas, bpmnRules) {
var helper = new ModelCloneHelper();
copyPaste.registerDescriptor(function(element, descriptor) { copyPaste.registerDescriptor(function(element, descriptor) {
var businessObject = getBusinessObject(element), var businessObject = getBusinessObject(element),
conditionExpression, newBusinessObject = bpmnFactory.create(businessObject.$type);
eventDefinitions;
var properties = getProperties(businessObject.$descriptor);
properties = filter(properties, function(property) {
return IGNORED_PROPERTIES.indexOf(property.replace(/bpmn:/, '')) === -1;
});
descriptor.businessObject = helper.clone(businessObject, newBusinessObject, properties);
descriptor.type = element.type; descriptor.type = element.type;
setProperties(descriptor, businessObject.di, [ 'isExpanded' ]);
if (element.type === 'label') { if (element.type === 'label') {
return descriptor; return descriptor;
} }
setProperties(descriptor, businessObject, [ setProperties(descriptor, businessObject, [
'name', 'type',
'text',
'processRef', 'processRef',
'isInterrupting', 'triggeredByEvent'
'isForCompensation',
'associationDirection',
'triggeredByEvent',
'cancelActivity'
]); ]);
if (businessObject.default) { if (businessObject.default) {
descriptor.default = businessObject.default.id; descriptor.default = businessObject.default.id;
} }
if (businessObject.loopCharacteristics) {
descriptor.loopCharacteristics = {
type: businessObject.loopCharacteristics.$type,
isSequential: businessObject.loopCharacteristics.isSequential
};
}
setProperties(descriptor, businessObject.di, [ 'isExpanded' ]);
if (is(businessObject, 'bpmn:SequenceFlow')) {
conditionExpression = businessObject.get('conditionExpression');
if (conditionExpression) {
descriptor.conditionExpression = {
type: conditionExpression.$type,
body: conditionExpression.body
};
}
}
eventDefinitions = businessObject.get('eventDefinitions') || [];
if (eventDefinitions.length) {
descriptor.eventDefinitions = map(eventDefinitions, function(defs) {
return defs.$type;
});
}
return descriptor; return descriptor;
}); });
@ -90,9 +73,6 @@ function BpmnCopyPaste(bpmnFactory, eventBus, copyPaste, clipboard, moddle, canv
parent = descriptor.parent, parent = descriptor.parent,
rootElement = canvas.getRootElement(), rootElement = canvas.getRootElement(),
businessObject, businessObject,
newEventDefinition,
conditionExpression,
loopCharacteristics,
source, source,
target, target,
canConnect; canConnect;
@ -132,59 +112,24 @@ function BpmnCopyPaste(bpmnFactory, eventBus, copyPaste, clipboard, moddle, canv
} }
} }
descriptor.businessObject = businessObject = bpmnFactory.create(descriptor.type); businessObject = descriptor.businessObject;
// remove the id or else we cannot paste multiple times
delete businessObject.id;
// assign an ID
bpmnFactory._ensureId(businessObject);
if (descriptor.type === 'bpmn:Participant' && descriptor.processRef) { if (descriptor.type === 'bpmn:Participant' && descriptor.processRef) {
descriptor.processRef = businessObject.processRef = bpmnFactory.create('bpmn:Process'); descriptor.processRef = businessObject.processRef = bpmnFactory.create('bpmn:Process');
} }
setProperties(businessObject, descriptor, [ setProperties(businessObject, descriptor, [
'name',
'text',
'isExpanded', 'isExpanded',
'isInterrupting',
'cancelActivity',
'triggeredByEvent' 'triggeredByEvent'
]); ]);
if (descriptor.loopCharacteristics) {
loopCharacteristics = descriptor.loopCharacteristics;
businessObject.loopCharacteristics = moddle.create(loopCharacteristics.type);
if (loopCharacteristics.isSequential) {
businessObject.loopCharacteristics.isSequential = true;
}
businessObject.loopCharacteristics.$parent = businessObject;
}
if (descriptor.conditionExpression) {
conditionExpression = descriptor.conditionExpression;
businessObject.conditionExpression = moddle.create(conditionExpression.type, { body: conditionExpression.body });
businessObject.conditionExpression.$parent = businessObject;
}
if (descriptor.eventDefinitions) {
businessObject.eventDefinitions = map(descriptor.eventDefinitions, function(type) {
newEventDefinition = moddle.create(type);
newEventDefinition.$parent = businessObject;
return newEventDefinition;
});
}
removeProperties(descriptor, [ removeProperties(descriptor, [
'name',
'text',
'eventDefinitions',
'conditionExpression',
'loopCharacteristics',
'isInterrupting',
'cancelActivity',
'triggeredByEvent' 'triggeredByEvent'
]); ]);
}); });

View File

@ -13,4 +13,5 @@ TestHelper.insertCSS('diagram-js-testing.css',
// add suite specific matchers // add suite specific matchers
global.chai.use(require('diagram-js/test/matchers/BoundsMatchers')); global.chai.use(require('diagram-js/test/matchers/BoundsMatchers'));
global.chai.use(require('diagram-js/test/matchers/ConnectionMatchers')); global.chai.use(require('diagram-js/test/matchers/ConnectionMatchers'));
global.chai.use(require('./matchers/JSONMatcher'));

View File

@ -0,0 +1,19 @@
'use strict';
module.exports = function(chai, utils) {
utils.addMethod(chai.Assertion.prototype, 'jsonEqual', function(comparison) {
var actual = JSON.stringify(this._obj);
var expected = JSON.stringify(comparison);
this.assert(
actual == expected,
'expected #{this} to deep equal #{act}',
'expected #{this} not to deep equal #{act}',
comparison, // expected
this._obj, // actual
true // show diff
);
});
};

View File

@ -11,17 +11,20 @@ var bpmnCopyPasteModule = require('../../../../lib/features/copy-paste'),
coreModule = require('../../../../lib/core'); coreModule = require('../../../../lib/core');
var map = require('lodash/collection/map'), var map = require('lodash/collection/map'),
filter = require('lodash/collection/filter'),
forEach = require('lodash/collection/forEach'), forEach = require('lodash/collection/forEach'),
uniq = require('lodash/array/uniq'); uniq = require('lodash/array/uniq');
var DescriptorTree = require('./DescriptorTree'); var DescriptorTree = require('./DescriptorTree');
var is = require('../../../../lib/util/ModelUtil').is;
describe('features/copy-paste', function() { describe('features/copy-paste', function() {
var testModules = [ bpmnCopyPasteModule, copyPasteModule, tooltipsModule, modelingModule, coreModule ]; var testModules = [ bpmnCopyPasteModule, copyPasteModule, tooltipsModule, modelingModule, coreModule ];
var basicXML = require('../../../fixtures/bpmn/features/copy-paste/basic.bpmn'), var basicXML = require('../../../fixtures/bpmn/features/copy-paste/basic.bpmn'),
clonePropertiesXML = require('../../../fixtures/bpmn/features/replace/clone-properties.bpmn'),
propertiesXML = require('../../../fixtures/bpmn/features/copy-paste/properties.bpmn'), propertiesXML = require('../../../fixtures/bpmn/features/copy-paste/properties.bpmn'),
collaborationXML = require('../../../fixtures/bpmn/features/copy-paste/collaboration.bpmn'), collaborationXML = require('../../../fixtures/bpmn/features/copy-paste/collaboration.bpmn'),
collaborationMultipleXML = require('../../../fixtures/bpmn/features/copy-paste/collaboration-multiple.bpmn'), collaborationMultipleXML = require('../../../fixtures/bpmn/features/copy-paste/collaboration-multiple.bpmn'),
@ -37,19 +40,10 @@ describe('features/copy-paste', function() {
it('selected elements', inject(function(elementRegistry, copyPaste) { it('selected elements', inject(function(elementRegistry, copyPaste) {
// given
var subProcess,
startEvent,
boundaryEvent,
textAnnotation;
// when // when
var tree = copy([ 'SubProcess_1kd6ist' ]); var tree = copy([ 'SubProcess_1kd6ist' ]);
startEvent = tree.getElement('StartEvent_1'); var subProcess = tree.getElement('SubProcess_1kd6ist');
boundaryEvent = tree.getElement('BoundaryEvent_1c94bi9');
subProcess = tree.getElement('SubProcess_1kd6ist');
textAnnotation = tree.getElement('TextAnnotation_0h1hhgg');
// then // then
expect(tree.getLength()).to.equal(3); expect(tree.getLength()).to.equal(3);
@ -59,9 +53,6 @@ describe('features/copy-paste', function() {
expect(tree.getDepthLength(2)).to.equal(15); expect(tree.getDepthLength(2)).to.equal(15);
expect(subProcess.isExpanded).to.be.true; expect(subProcess.isExpanded).to.be.true;
expect(startEvent.name).to.equal('hello');
expect(textAnnotation.text).to.equal('foo');
expect(boundaryEvent.eventDefinitions).to.contain('bpmn:TimerEventDefinition');
})); }));
}); });
@ -512,6 +503,57 @@ describe('features/copy-paste', function() {
}); });
describe('deep properties', function() {
var camundaPackage = require('../../../fixtures/json/model/camunda');
beforeEach(bootstrapModeler(clonePropertiesXML, {
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
it('integration', inject(integrationTest([ 'Participant_0x9lnke' ])));
it('should copy UserTask properties',
inject(function(elementRegistry, copyPaste, canvas) {
var participant = elementRegistry.get('Participant_0x9lnke'),
task = elementRegistry.get('Task_1'),
newTask;
// when
copyPaste.copy([ task ]);
copyPaste.paste({
element: participant,
point: {
x: 500,
y: 50
}
});
newTask = filter(participant.children, function(element) {
return is(element, 'bpmn:Task');
})[0];
// then
var bo = task.businessObject;
var copiedBo = newTask.businessObject;
expect(copiedBo.asyncBefore).to.eql(bo.asyncBefore);
expect(copiedBo.documentation).to.jsonEqual(bo.documentation);
expect(copiedBo.extensionElements).to.jsonEqual(bo.extensionElements);
})
);
});
}); });