fix(util/model): able to clone Event Definitions extension elements
Related to camunda/camunda-modeler#516 Related to camunda/camunda-modeler#517
This commit is contained in:
parent
1a4a8959fe
commit
2c51cfbe3d
|
@ -36,8 +36,10 @@ function ModelCloneHelper(eventBus) {
|
||||||
module.exports = ModelCloneHelper;
|
module.exports = ModelCloneHelper;
|
||||||
|
|
||||||
|
|
||||||
ModelCloneHelper.prototype.clone = function(oldElement, newElement, properties) {
|
ModelCloneHelper.prototype.clone = function(refElement, newElement, properties) {
|
||||||
this._newElement = newElement;
|
var context = {
|
||||||
|
newElement: newElement
|
||||||
|
};
|
||||||
|
|
||||||
// we want the extensionElements to be cloned last
|
// we want the extensionElements to be cloned last
|
||||||
// so that they can check certain properties
|
// so that they can check certain properties
|
||||||
|
@ -46,7 +48,7 @@ ModelCloneHelper.prototype.clone = function(oldElement, newElement, properties)
|
||||||
});
|
});
|
||||||
|
|
||||||
forEach(properties, function(propName) {
|
forEach(properties, function(propName) {
|
||||||
var oldElementProp = oldElement.get(propName),
|
var refElementProp = refElement.get(propName),
|
||||||
newElementProp = newElement.get(propName),
|
newElementProp = newElement.get(propName),
|
||||||
propDescriptor = newElement.$model.getPropertyDescriptor(newElement, propName),
|
propDescriptor = newElement.$model.getPropertyDescriptor(newElement, propName),
|
||||||
name;
|
name;
|
||||||
|
@ -55,22 +57,26 @@ ModelCloneHelper.prototype.clone = function(oldElement, newElement, properties)
|
||||||
// - same values from simple types
|
// - same values from simple types
|
||||||
// - cloning id's
|
// - cloning id's
|
||||||
// - cloning reference elements
|
// - cloning reference elements
|
||||||
if (newElementProp === oldElementProp ||
|
if (newElementProp === refElementProp ||
|
||||||
(propDescriptor && (propDescriptor.isId || propDescriptor.isReference))) {
|
(propDescriptor && (propDescriptor.isId || propDescriptor.isReference))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the property is of type 'boolean', 'string', 'number' or 'null', just set it
|
// if the property is of type 'boolean', 'string', 'number' or 'null', just set it
|
||||||
if (isType(oldElementProp, [ 'boolean', 'string', 'number' ]) || oldElementProp === null) {
|
if (isType(refElementProp, [ 'boolean', 'string', 'number' ]) || refElementProp === null) {
|
||||||
newElement.set(propName, oldElementProp);
|
newElement.set(propName, refElementProp);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isArray(oldElementProp)) {
|
if (isArray(refElementProp)) {
|
||||||
|
|
||||||
forEach(oldElementProp, function(extElement) {
|
forEach(refElementProp, function(extElement) {
|
||||||
var newProp = this._deepClone(extElement);
|
var newProp;
|
||||||
|
|
||||||
|
context.refTopLevelProperty = extElement;
|
||||||
|
|
||||||
|
newProp = this._deepClone(extElement, context);
|
||||||
|
|
||||||
newProp.$parent = newElement;
|
newProp.$parent = newElement;
|
||||||
|
|
||||||
|
@ -79,21 +85,21 @@ ModelCloneHelper.prototype.clone = function(oldElement, newElement, properties)
|
||||||
} else {
|
} else {
|
||||||
name = propName.replace(/bpmn:/, '');
|
name = propName.replace(/bpmn:/, '');
|
||||||
|
|
||||||
newElement[name] = this._deepClone(oldElementProp);
|
context.refTopLevelProperty = refElementProp;
|
||||||
|
|
||||||
|
newElement[name] = this._deepClone(refElementProp, context);
|
||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
return newElement;
|
return newElement;
|
||||||
};
|
};
|
||||||
|
|
||||||
ModelCloneHelper.prototype._deepClone = function _deepClone(element) {
|
ModelCloneHelper.prototype._deepClone = function _deepClone(propertyElement, context) {
|
||||||
var eventBus = this._eventBus;
|
var eventBus = this._eventBus;
|
||||||
|
|
||||||
var newElement = this._newElement;
|
var newProp = propertyElement.$model.create(propertyElement.$type);
|
||||||
|
|
||||||
var newProp = element.$model.create(element.$type);
|
var properties = filter(Object.keys(propertyElement), function(prop) {
|
||||||
|
|
||||||
var properties = filter(Object.keys(element), function(prop) {
|
|
||||||
var descriptor = newProp.$model.getPropertyDescriptor(newProp, prop);
|
var descriptor = newProp.$model.getPropertyDescriptor(newProp, prop);
|
||||||
|
|
||||||
if (descriptor && (descriptor.isId || descriptor.isReference)) {
|
if (descriptor && (descriptor.isId || descriptor.isReference)) {
|
||||||
|
@ -111,14 +117,15 @@ ModelCloneHelper.prototype._deepClone = function _deepClone(element) {
|
||||||
});
|
});
|
||||||
|
|
||||||
forEach(properties, function(propName) {
|
forEach(properties, function(propName) {
|
||||||
// check if the element has this property defined
|
// check if the propertyElement has this property defined
|
||||||
if (element[propName] !== undefined && (element[propName].$type || isArray(element[propName]))) {
|
if (propertyElement[propName] !== undefined &&
|
||||||
|
(propertyElement[propName].$type || isArray(propertyElement[propName]))) {
|
||||||
|
|
||||||
if (isArray(element[propName])) {
|
if (isArray(propertyElement[propName])) {
|
||||||
newProp[propName] = [];
|
newProp[propName] = [];
|
||||||
|
|
||||||
forEach(element[propName], function(property) {
|
forEach(propertyElement[propName], function(property) {
|
||||||
var extProp = element.$model.getTypeDescriptor(property.$type),
|
var extProp = propertyElement.$model.getTypeDescriptor(property.$type),
|
||||||
newDeepProp;
|
newDeepProp;
|
||||||
|
|
||||||
// we're not going to copy undefined types
|
// we're not going to copy undefined types
|
||||||
|
@ -127,35 +134,36 @@ ModelCloneHelper.prototype._deepClone = function _deepClone(element) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var canClone = eventBus.fire('property.clone', {
|
var canClone = eventBus.fire('property.clone', {
|
||||||
newElement: newElement,
|
newElement: context.newElement,
|
||||||
|
refTopLevelProperty: context.refTopLevelProperty,
|
||||||
propertyDescriptor: extProp
|
propertyDescriptor: extProp
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!canClone) {
|
if (!canClone) {
|
||||||
// if can clone is 'undefined' or 'false'
|
// if can clone is 'undefined' or 'false'
|
||||||
// check for the meta information if it is allowed
|
// check for the meta information if it is allowed
|
||||||
if (element.$type === 'bpmn:ExtensionElements' &&
|
if (propertyElement.$type === 'bpmn:ExtensionElements' &&
|
||||||
extProp.meta && extProp.meta.allowedIn &&
|
extProp.meta && extProp.meta.allowedIn &&
|
||||||
!isAllowedIn(extProp, newElement.$type)) {
|
!isAllowedIn(extProp, context.newElement.$type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newDeepProp = this._deepClone(property);
|
newDeepProp = this._deepClone(property, context);
|
||||||
|
|
||||||
newDeepProp.$parent = newProp;
|
newDeepProp.$parent = newProp;
|
||||||
|
|
||||||
newProp[propName].push(newDeepProp);
|
newProp[propName].push(newDeepProp);
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
} else if (element[propName].$type) {
|
} else if (propertyElement[propName].$type) {
|
||||||
newProp[propName] = this._deepClone(element[propName]);
|
newProp[propName] = this._deepClone(propertyElement[propName], context);
|
||||||
|
|
||||||
newProp[propName].$parent = newProp;
|
newProp[propName].$parent = newProp;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// just assign directly if it's a value
|
// just assign directly if it's a value
|
||||||
newProp[propName] = element[propName];
|
newProp[propName] = propertyElement[propName];
|
||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
|
|
|
@ -276,16 +276,14 @@ describe('util/ModelCloneHelper', function() {
|
||||||
newSubProcessExtElems = newSubProcess.extensionElements.values;
|
newSubProcessExtElems = newSubProcess.extensionElements.values;
|
||||||
|
|
||||||
// then
|
// then
|
||||||
function expectTimeCycle(extElems) {
|
expect(intCatchEvtExtElems[0].$type).to.equal('camunda:FailedJobRetryTimeCycle');
|
||||||
expect(extElems[0].$type).to.equal('camunda:FailedJobRetryTimeCycle');
|
expect(intCatchEvtExtElems[0].body).to.equal('foobar');
|
||||||
expect(extElems[0].body).to.equal('foobar');
|
|
||||||
}
|
|
||||||
|
|
||||||
expectTimeCycle(intCatchEvtExtElems);
|
expect(startEvtExtElems[0].$type).to.equal('camunda:FailedJobRetryTimeCycle');
|
||||||
|
expect(startEvtExtElems[0].body).to.equal('foobar');
|
||||||
|
|
||||||
expectTimeCycle(startEvtExtElems);
|
expect(newSubProcessExtElems[0].$type).to.equal('camunda:FailedJobRetryTimeCycle');
|
||||||
|
expect(newSubProcessExtElems[0].body).to.equal('foobar');
|
||||||
expectTimeCycle(newSubProcessExtElems);
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
@ -298,10 +296,11 @@ describe('util/ModelCloneHelper', function() {
|
||||||
|
|
||||||
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ connector ] });
|
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ connector ] });
|
||||||
|
|
||||||
var msgEvtDef = moddle.create('bpmn:MessageEventDefinition');
|
var msgEvtDef = moddle.create('bpmn:MessageEventDefinition', {
|
||||||
|
extensionElements: extensionElements
|
||||||
|
});
|
||||||
|
|
||||||
var msgIntermThrowEvt = moddle.create('bpmn:IntermediateThrowEvent', {
|
var msgIntermThrowEvt = moddle.create('bpmn:IntermediateThrowEvent', {
|
||||||
extensionElements: extensionElements,
|
|
||||||
eventDefinitions: [ msgEvtDef ]
|
eventDefinitions: [ msgEvtDef ]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -310,7 +309,7 @@ describe('util/ModelCloneHelper', function() {
|
||||||
'bpmn:eventDefinitions'
|
'bpmn:eventDefinitions'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var extElems = clonedElement.extensionElements.values;
|
var extElems = clonedElement.eventDefinitions[0].extensionElements.values;
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(extElems[0].$type).to.equal('camunda:Connector');
|
expect(extElems[0].$type).to.equal('camunda:Connector');
|
||||||
|
@ -327,10 +326,11 @@ describe('util/ModelCloneHelper', function() {
|
||||||
|
|
||||||
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ field ] });
|
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ field ] });
|
||||||
|
|
||||||
var msgEvtDef = moddle.create('bpmn:MessageEventDefinition');
|
var msgEvtDef = moddle.create('bpmn:MessageEventDefinition', {
|
||||||
|
extensionElements: extensionElements
|
||||||
|
});
|
||||||
|
|
||||||
var msgIntermThrowEvt = moddle.create('bpmn:IntermediateThrowEvent', {
|
var msgIntermThrowEvt = moddle.create('bpmn:IntermediateThrowEvent', {
|
||||||
extensionElements: extensionElements,
|
|
||||||
eventDefinitions: [ msgEvtDef ]
|
eventDefinitions: [ msgEvtDef ]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -339,7 +339,7 @@ describe('util/ModelCloneHelper', function() {
|
||||||
'bpmn:eventDefinitions'
|
'bpmn:eventDefinitions'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var extElems = clonedElement.extensionElements.values;
|
var extElems = clonedElement.eventDefinitions[0].extensionElements.values;
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(extElems[0].$type).to.equal('camunda:Field');
|
expect(extElems[0].$type).to.equal('camunda:Field');
|
||||||
|
@ -356,10 +356,11 @@ describe('util/ModelCloneHelper', function() {
|
||||||
|
|
||||||
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ field ] });
|
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ field ] });
|
||||||
|
|
||||||
var msgEvtDef = moddle.create('bpmn:MessageEventDefinition');
|
var msgEvtDef = moddle.create('bpmn:MessageEventDefinition', {
|
||||||
|
extensionElements: extensionElements
|
||||||
|
});
|
||||||
|
|
||||||
var msgIntermThrowEvt = moddle.create('bpmn:IntermediateThrowEvent', {
|
var msgIntermThrowEvt = moddle.create('bpmn:IntermediateThrowEvent', {
|
||||||
extensionElements: extensionElements,
|
|
||||||
eventDefinitions: [ msgEvtDef ]
|
eventDefinitions: [ msgEvtDef ]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -367,10 +368,8 @@ describe('util/ModelCloneHelper', function() {
|
||||||
'bpmn:extensionElements'
|
'bpmn:extensionElements'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var extElems = clonedElement.extensionElements;
|
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(extElems.values).be.empty;
|
expect(clonedElement.eventDefinitions).to.be.empty;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -41,27 +41,30 @@ function CamundaModdleExtension(eventBus) {
|
||||||
|
|
||||||
eventBus.on('property.clone', function(context) {
|
eventBus.on('property.clone', function(context) {
|
||||||
var newElement = context.newElement,
|
var newElement = context.newElement,
|
||||||
|
refTopLevelProperty = context.refTopLevelProperty,
|
||||||
propDescriptor = context.propertyDescriptor;
|
propDescriptor = context.propertyDescriptor;
|
||||||
|
|
||||||
if (isAllowed('camunda:FailedJobRetryTimeCycle', propDescriptor, newElement)) {
|
return this.canCloneProperty(newElement, refTopLevelProperty, propDescriptor);
|
||||||
return includesType(newElement.eventDefinitions, 'bpmn:TimerEventDefinition') ||
|
}, this);
|
||||||
includesType(newElement.eventDefinitions, 'bpmn:SignalEventDefinition') ||
|
|
||||||
is(newElement.loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAllowed('camunda:Connector', propDescriptor, newElement)) {
|
|
||||||
return includesType(newElement.eventDefinitions, 'bpmn:MessageEventDefinition');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAllowed('camunda:Field', propDescriptor, newElement)) {
|
|
||||||
return includesType(newElement.eventDefinitions, 'bpmn:MessageEventDefinition');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CamundaModdleExtension.$inject = [ 'eventBus' ];
|
CamundaModdleExtension.$inject = [ 'eventBus' ];
|
||||||
|
|
||||||
module.exports = {
|
CamundaModdleExtension.prototype.canCloneProperty = function(newElement, refTopLevelProperty, propDescriptor) {
|
||||||
__init__: [ 'CamundaModdleExtension' ],
|
|
||||||
CamundaModdleExtension: [ 'type', CamundaModdleExtension ]
|
if (isAllowed('camunda:FailedJobRetryTimeCycle', propDescriptor, newElement)) {
|
||||||
|
return includesType(newElement.eventDefinitions, 'bpmn:TimerEventDefinition') ||
|
||||||
|
includesType(newElement.eventDefinitions, 'bpmn:SignalEventDefinition') ||
|
||||||
|
is(newElement.loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAllowed('camunda:Connector', propDescriptor, newElement) ||
|
||||||
|
isAllowed('camunda:Field', propDescriptor, newElement)) {
|
||||||
|
return is(refTopLevelProperty, 'bpmn:MessageEventDefinition');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
__init__: [ 'camundaModdleExtension' ],
|
||||||
|
camundaModdleExtension: [ 'type', CamundaModdleExtension ]
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue