293 lines
6.8 KiB
JavaScript
293 lines
6.8 KiB
JavaScript
import {
|
|
find,
|
|
forEach,
|
|
isArray,
|
|
isDefined,
|
|
isObject,
|
|
matchPattern,
|
|
reduce,
|
|
has,
|
|
sortBy
|
|
} from 'min-dash';
|
|
|
|
var DISALLOWED_PROPERTIES = [
|
|
'artifacts',
|
|
'dataInputAssociations',
|
|
'dataOutputAssociations',
|
|
'default',
|
|
'flowElements',
|
|
'lanes',
|
|
'incoming',
|
|
'outgoing'
|
|
];
|
|
|
|
/**
|
|
* @typedef {Function} <moddleCopy.canCopyProperties> listener
|
|
*
|
|
* @param {Object} context
|
|
* @param {Array<string>} context.propertyNames
|
|
* @param {ModdleElement} context.sourceElement
|
|
* @param {ModdleElement} context.targetElement
|
|
*
|
|
* @returns {Array<string>|boolean} - Return properties to be copied or false to disallow
|
|
* copying.
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Function} <moddleCopy.canCopyProperty> listener
|
|
*
|
|
* @param {Object} context
|
|
* @param {ModdleElement} context.parent
|
|
* @param {*} context.property
|
|
* @param {string} context.propertyName
|
|
*
|
|
* @returns {*|boolean} - Return copied property or false to disallow
|
|
* copying.
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Function} <moddleCopy.canSetCopiedProperty> listener
|
|
*
|
|
* @param {Object} context
|
|
* @param {ModdleElement} context.parent
|
|
* @param {*} context.property
|
|
* @param {string} context.propertyName
|
|
*
|
|
* @returns {boolean} - Return false to disallow
|
|
* setting copied property.
|
|
*/
|
|
|
|
/**
|
|
* Utility for copying model properties from source element to target element.
|
|
*
|
|
* @param {EventBus} eventBus
|
|
* @param {BpmnFactory} bpmnFactory
|
|
* @param {BpmnModdle} moddle
|
|
*/
|
|
export default function ModdleCopy(eventBus, bpmnFactory, moddle) {
|
|
this._bpmnFactory = bpmnFactory;
|
|
this._eventBus = eventBus;
|
|
this._moddle = moddle;
|
|
|
|
// copy extension elements last
|
|
eventBus.on('moddleCopy.canCopyProperties', function(context) {
|
|
var propertyNames = context.propertyNames;
|
|
|
|
if (!propertyNames || !propertyNames.length) {
|
|
return;
|
|
}
|
|
|
|
return sortBy(propertyNames, function(propertyName) {
|
|
return propertyName === 'extensionElements';
|
|
});
|
|
});
|
|
|
|
// default check whether property can be copied
|
|
eventBus.on('moddleCopy.canCopyProperty', function(context) {
|
|
var parent = context.parent,
|
|
parentDescriptor = isObject(parent) && parent.$descriptor,
|
|
propertyName = context.propertyName;
|
|
|
|
if (propertyName && DISALLOWED_PROPERTIES.indexOf(propertyName) !== -1) {
|
|
|
|
// disallow copying property
|
|
return false;
|
|
}
|
|
|
|
if (propertyName &&
|
|
parentDescriptor &&
|
|
!find(parentDescriptor.properties, matchPattern({ name: propertyName }))) {
|
|
|
|
// disallow copying property
|
|
return false;
|
|
}
|
|
});
|
|
|
|
// do NOT allow to copy empty extension elements
|
|
eventBus.on('moddleCopy.canSetCopiedProperty', function(context) {
|
|
var property = context.property;
|
|
|
|
if (is(property, 'bpmn:ExtensionElements') && (!property.values || !property.values.length)) {
|
|
|
|
// disallow setting copied property
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
ModdleCopy.$inject = [
|
|
'eventBus',
|
|
'bpmnFactory',
|
|
'moddle'
|
|
];
|
|
|
|
/**
|
|
* Copy model properties of source element to target element.
|
|
*
|
|
* @param {ModdleElement} sourceElement
|
|
* @param {ModdleElement} targetElement
|
|
* @param {Array<string>} [propertyNames]
|
|
*
|
|
* @param {ModdleElement}
|
|
*/
|
|
ModdleCopy.prototype.copyElement = function(sourceElement, targetElement, propertyNames) {
|
|
var self = this;
|
|
|
|
if (propertyNames && !isArray(propertyNames)) {
|
|
propertyNames = [ propertyNames ];
|
|
}
|
|
|
|
propertyNames = propertyNames || getPropertyNames(sourceElement.$descriptor);
|
|
|
|
var canCopyProperties = this._eventBus.fire('moddleCopy.canCopyProperties', {
|
|
propertyNames: propertyNames,
|
|
sourceElement: sourceElement,
|
|
targetElement: targetElement
|
|
});
|
|
|
|
if (canCopyProperties === false) {
|
|
return targetElement;
|
|
}
|
|
|
|
if (isArray(canCopyProperties)) {
|
|
propertyNames = canCopyProperties;
|
|
}
|
|
|
|
// copy properties
|
|
forEach(propertyNames, function(propertyName) {
|
|
var sourceProperty;
|
|
|
|
if (has(sourceElement, propertyName)) {
|
|
sourceProperty = sourceElement.get(propertyName);
|
|
}
|
|
|
|
var copiedProperty = self.copyProperty(sourceProperty, targetElement, propertyName);
|
|
|
|
var canSetProperty = self._eventBus.fire('moddleCopy.canSetCopiedProperty', {
|
|
parent: targetElement,
|
|
property: copiedProperty,
|
|
propertyName: propertyName
|
|
});
|
|
|
|
if (canSetProperty === false) {
|
|
return;
|
|
}
|
|
|
|
if (isDefined(copiedProperty)) {
|
|
targetElement.set(propertyName, copiedProperty);
|
|
}
|
|
});
|
|
|
|
return targetElement;
|
|
};
|
|
|
|
/**
|
|
* Copy model property.
|
|
*
|
|
* @param {*} property
|
|
* @param {ModdleElement} parent
|
|
* @param {string} propertyName
|
|
*
|
|
* @returns {*}
|
|
*/
|
|
ModdleCopy.prototype.copyProperty = function(property, parent, propertyName) {
|
|
var self = this;
|
|
|
|
// allow others to copy property
|
|
var copiedProperty = this._eventBus.fire('moddleCopy.canCopyProperty', {
|
|
parent: parent,
|
|
property: property,
|
|
propertyName: propertyName
|
|
});
|
|
|
|
// return if copying is NOT allowed
|
|
if (copiedProperty === false) {
|
|
return;
|
|
}
|
|
|
|
if (copiedProperty) {
|
|
if (isObject(copiedProperty) && copiedProperty.$type && !copiedProperty.$parent) {
|
|
copiedProperty.$parent = parent;
|
|
}
|
|
|
|
return copiedProperty;
|
|
}
|
|
|
|
var propertyDescriptor = this._moddle.getPropertyDescriptor(parent, propertyName);
|
|
|
|
// do NOT copy references
|
|
if (propertyDescriptor.isReference) {
|
|
return;
|
|
}
|
|
|
|
// copy id
|
|
if (propertyDescriptor.isId) {
|
|
return this._copyId(property, parent);
|
|
}
|
|
|
|
// copy arrays
|
|
if (isArray(property)) {
|
|
return reduce(property, function(childProperties, childProperty) {
|
|
|
|
// recursion
|
|
copiedProperty = self.copyProperty(childProperty, parent, propertyName);
|
|
|
|
// copying might NOT be allowed
|
|
if (copiedProperty) {
|
|
copiedProperty.$parent = parent;
|
|
|
|
return childProperties.concat(copiedProperty);
|
|
}
|
|
|
|
return childProperties;
|
|
}, []);
|
|
}
|
|
|
|
// copy model elements
|
|
if (isObject(property) && property.$type) {
|
|
if (this._moddle.getElementDescriptor(property).isGeneric) {
|
|
return;
|
|
}
|
|
|
|
copiedProperty = self._bpmnFactory.create(property.$type);
|
|
|
|
copiedProperty.$parent = parent;
|
|
|
|
// recursion
|
|
copiedProperty = self.copyElement(property, copiedProperty);
|
|
|
|
return copiedProperty;
|
|
}
|
|
|
|
// copy primitive properties
|
|
return property;
|
|
};
|
|
|
|
ModdleCopy.prototype._copyId = function(id, element) {
|
|
|
|
// disallow if already taken
|
|
if (this._moddle.ids.assigned(id)) {
|
|
return;
|
|
} else {
|
|
|
|
this._moddle.ids.claim(id, element);
|
|
return id;
|
|
}
|
|
};
|
|
|
|
// helpers //////////
|
|
|
|
export function getPropertyNames(descriptor, keepDefaultProperties) {
|
|
return reduce(descriptor.properties, function(properties, property) {
|
|
|
|
if (keepDefaultProperties && property.default) {
|
|
return properties;
|
|
}
|
|
|
|
return properties.concat(property.name);
|
|
}, []);
|
|
}
|
|
|
|
function is(element, type) {
|
|
return element && (typeof element.$instanceOf === 'function') && element.$instanceOf(type);
|
|
} |