diff --git a/lib/features/copy-paste/BpmnCopyPaste.js b/lib/features/copy-paste/BpmnCopyPaste.js index 592dbf3b..c4983941 100644 --- a/lib/features/copy-paste/BpmnCopyPaste.js +++ b/lib/features/copy-paste/BpmnCopyPaste.js @@ -4,9 +4,15 @@ var ModelUtil = require('../../util/ModelUtil'), getBusinessObject = ModelUtil.getBusinessObject, is = ModelUtil.is; -var map = require('lodash/collection/map'), - forEach = require('lodash/collection/forEach'); +var ModelCloneHelper = require('../../util/model/ModelCloneHelper'); +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) { forEach(properties, function(property) { @@ -26,61 +32,38 @@ function removeProperties(element, properties) { function BpmnCopyPaste(bpmnFactory, eventBus, copyPaste, clipboard, moddle, canvas, bpmnRules) { + var helper = new ModelCloneHelper(); + copyPaste.registerDescriptor(function(element, descriptor) { var businessObject = getBusinessObject(element), - conditionExpression, - eventDefinitions; + newBusinessObject = bpmnFactory.create(businessObject.$type); + + 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; + setProperties(descriptor, businessObject.di, [ 'isExpanded' ]); + if (element.type === 'label') { return descriptor; } setProperties(descriptor, businessObject, [ - 'name', - 'text', + 'type', 'processRef', - 'isInterrupting', - 'isForCompensation', - 'associationDirection', - 'triggeredByEvent', - 'cancelActivity' + 'triggeredByEvent' ]); if (businessObject.default) { 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; }); @@ -90,9 +73,6 @@ function BpmnCopyPaste(bpmnFactory, eventBus, copyPaste, clipboard, moddle, canv parent = descriptor.parent, rootElement = canvas.getRootElement(), businessObject, - newEventDefinition, - conditionExpression, - loopCharacteristics, source, target, 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) { descriptor.processRef = businessObject.processRef = bpmnFactory.create('bpmn:Process'); } setProperties(businessObject, descriptor, [ - 'name', - 'text', 'isExpanded', - 'isInterrupting', - 'cancelActivity', '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, [ - 'name', - 'text', - 'eventDefinitions', - 'conditionExpression', - 'loopCharacteristics', - 'isInterrupting', - 'cancelActivity', 'triggeredByEvent' ]); }); diff --git a/test/TestHelper.js b/test/TestHelper.js index ddce84d8..187bd724 100644 --- a/test/TestHelper.js +++ b/test/TestHelper.js @@ -13,4 +13,5 @@ TestHelper.insertCSS('diagram-js-testing.css', // add suite specific matchers global.chai.use(require('diagram-js/test/matchers/BoundsMatchers')); -global.chai.use(require('diagram-js/test/matchers/ConnectionMatchers')); \ No newline at end of file +global.chai.use(require('diagram-js/test/matchers/ConnectionMatchers')); +global.chai.use(require('./matchers/JSONMatcher')); diff --git a/test/matchers/JSONMatcher.js b/test/matchers/JSONMatcher.js new file mode 100644 index 00000000..e71fc44e --- /dev/null +++ b/test/matchers/JSONMatcher.js @@ -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 + ); + }); +}; diff --git a/test/spec/features/copy-paste/BpmnCopyPasteSpec.js b/test/spec/features/copy-paste/BpmnCopyPasteSpec.js index ef33535d..c7f1217f 100644 --- a/test/spec/features/copy-paste/BpmnCopyPasteSpec.js +++ b/test/spec/features/copy-paste/BpmnCopyPasteSpec.js @@ -11,17 +11,20 @@ var bpmnCopyPasteModule = require('../../../../lib/features/copy-paste'), coreModule = require('../../../../lib/core'); var map = require('lodash/collection/map'), + filter = require('lodash/collection/filter'), forEach = require('lodash/collection/forEach'), uniq = require('lodash/array/uniq'); var DescriptorTree = require('./DescriptorTree'); +var is = require('../../../../lib/util/ModelUtil').is; describe('features/copy-paste', function() { var testModules = [ bpmnCopyPasteModule, copyPasteModule, tooltipsModule, modelingModule, coreModule ]; 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'), collaborationXML = require('../../../fixtures/bpmn/features/copy-paste/collaboration.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) { - // given - var subProcess, - startEvent, - boundaryEvent, - textAnnotation; - // when var tree = copy([ 'SubProcess_1kd6ist' ]); - startEvent = tree.getElement('StartEvent_1'); - boundaryEvent = tree.getElement('BoundaryEvent_1c94bi9'); - subProcess = tree.getElement('SubProcess_1kd6ist'); - textAnnotation = tree.getElement('TextAnnotation_0h1hhgg'); + var subProcess = tree.getElement('SubProcess_1kd6ist'); // then expect(tree.getLength()).to.equal(3); @@ -59,9 +53,6 @@ describe('features/copy-paste', function() { expect(tree.getDepthLength(2)).to.equal(15); 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); + }) + ); + + }); + });