feat(util/model): avoid persisting empty property element containers

Closes camunda/camunda-modeler#512
This commit is contained in:
Ricardo Matias 2017-02-01 10:42:49 +01:00 committed by Philipp Fromme
parent c1c62823f6
commit 86c0a0aa75
2 changed files with 42 additions and 10 deletions

View File

@ -39,6 +39,10 @@ module.exports = ModelCloneHelper;
ModelCloneHelper.prototype.clone = function(oldElement, newElement, properties) { ModelCloneHelper.prototype.clone = function(oldElement, newElement, properties) {
this._newElement = newElement; this._newElement = newElement;
// this property allows us to avoid ending up with empty (xml) tags
// f.ex: if extensionElements.values is empty, don't set it
this._hasNestedProperty = false;
// 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
properties = sort(properties, function(prop) { properties = sort(properties, function(prop) {
@ -49,7 +53,7 @@ ModelCloneHelper.prototype.clone = function(oldElement, newElement, properties)
var oldElementProp = oldElement.get(propName), var oldElementProp = oldElement.get(propName),
newElementProp = newElement.get(propName), newElementProp = newElement.get(propName),
propDescriptor = newElement.$model.getPropertyDescriptor(newElement, propName), propDescriptor = newElement.$model.getPropertyDescriptor(newElement, propName),
name; newProperty, name;
// we're not interested in cloning: // we're not interested in cloning:
// - same values from simple types // - same values from simple types
@ -72,14 +76,25 @@ ModelCloneHelper.prototype.clone = function(oldElement, newElement, properties)
forEach(oldElementProp, function(extElement) { forEach(oldElementProp, function(extElement) {
var newProp = this._deepClone(extElement); var newProp = this._deepClone(extElement);
if (this._hasNestedProperty) {
newProp.$parent = newElement; newProp.$parent = newElement;
newElementProp.push(newProp); newElementProp.push(newProp);
}
this._hasNestedProperty = false;
}, this); }, this);
} else { } else {
name = propName.replace(/bpmn:/, ''); name = propName.replace(/bpmn:/, '');
newElement[name] = this._deepClone(oldElementProp); newProperty = this._deepClone(oldElementProp);
if (this._hasNestedProperty) {
newElement[name] = newProperty;
}
this._hasNestedProperty = false;
} }
}, this); }, this);
@ -110,12 +125,15 @@ ModelCloneHelper.prototype._deepClone = function _deepClone(element) {
return prop !== '$type'; return prop !== '$type';
}); });
if (!properties.length) {
this._hasNestedProperty = true;
}
forEach(properties, function(propName) { forEach(properties, function(propName) {
// check if the element has this property defined // check if the element has this property defined
if (element[propName] !== undefined && (element[propName].$type || isArray(element[propName]))) { if (element[propName] !== undefined && (element[propName].$type || isArray(element[propName]))) {
if (isArray(element[propName])) { if (isArray(element[propName])) {
newProp[propName] = [];
forEach(element[propName], function(property) { forEach(element[propName], function(property) {
var extProp = element.$model.getTypeDescriptor(property.$type), var extProp = element.$model.getTypeDescriptor(property.$type),
@ -145,15 +163,27 @@ ModelCloneHelper.prototype._deepClone = function _deepClone(element) {
newDeepProp.$parent = newProp; newDeepProp.$parent = newProp;
if (!newProp[propName]) {
newProp[propName] = [];
}
this._hasNestedProperty = true;
newProp[propName].push(newDeepProp); newProp[propName].push(newDeepProp);
}, this); }, this);
} else if (element[propName].$type) { } else if (element[propName].$type) {
newProp[propName] = this._deepClone(element[propName]); newProp[propName] = this._deepClone(element[propName]);
if (newProp[propName]) {
this._hasNestedProperty = true;
newProp[propName].$parent = newProp; newProp[propName].$parent = newProp;
} }
}
} else { } else {
this._hasNestedProperty = true;
// just assign directly if it's a value // just assign directly if it's a value
newProp[propName] = element[propName]; newProp[propName] = element[propName];
} }

View File

@ -208,7 +208,7 @@ describe('util/ModelCloneHelper', function() {
var extElem = userTask.extensionElements; var extElem = userTask.extensionElements;
// then // then
expect(extElem.values).to.be.empty; expect(extElem).to.not.exist;
})); }));
}); });
@ -230,10 +230,12 @@ describe('util/ModelCloneHelper', function() {
}); });
var signalEvtDef = moddle.create('bpmn:SignalEventDefinition', { var signalEvtDef = moddle.create('bpmn:SignalEventDefinition', {
timeDuration: 'foobar' async: true
}); });
var multiInst = moddle.create('bpmn:MultiInstanceLoopCharacteristics'); var multiInst = moddle.create('bpmn:MultiInstanceLoopCharacteristics', {
elementVariable: 'foobar'
});
var timerStartEvent = moddle.create('bpmn:StartEvent', { var timerStartEvent = moddle.create('bpmn:StartEvent', {
extensionElements: createExtElems(), extensionElements: createExtElems(),
@ -364,7 +366,7 @@ describe('util/ModelCloneHelper', function() {
var extElems = clonedElement.extensionElements; var extElems = clonedElement.extensionElements;
// then // then
expect(extElems.values).be.empty; expect(extElems).not.exist;
})); }));
}); });