vmes-flowable
Version:
ceshibao
470 lines (369 loc) • 13.3 kB
JavaScript
'use strict';
var findExtension = require('../Helper').findExtension,
findExtensions = require('../Helper').findExtensions;
var createFlowableProperty = require('../CreateHelper').createFlowableProperty,
createInputParameter = require('../CreateHelper').createInputParameter,
createOutputParameter = require('../CreateHelper').createOutputParameter,
createFlowableIn = require('../CreateHelper').createFlowableIn,
createFlowableOut = require('../CreateHelper').createFlowableOut,
createFlowableInWithBusinessKey = require('../CreateHelper').createFlowableInWithBusinessKey,
createFlowableExecutionListenerScript = require('../CreateHelper').createFlowableExecutionListenerScript,
createFlowableFieldInjection = require('../CreateHelper').createFlowableFieldInjection;
var forEach = require('lodash/forEach');
var CAMUNDA_SERVICE_TASK_LIKE = [
'flowable:class',
'flowable:delegateExpression',
'flowable:expression'
];
/**
* A handler that changes the modeling template of a BPMN element.
*/
function ChangeElementTemplateHandler(modeling, commandStack, bpmnFactory) {
function getOrCreateExtensionElements(element) {
var bo = element.businessObject;
var extensionElements = bo.extensionElements;
// add extension elements
if (!extensionElements) {
extensionElements = bpmnFactory.create('bpmn:ExtensionElements', {
values: []
});
modeling.updateProperties(element, {
extensionElements: extensionElements
});
}
return extensionElements;
}
function updateModelerTemplate(element, newTemplate) {
modeling.updateProperties(element, {
'flowable:modelerTemplate': newTemplate && newTemplate.id
});
}
function updateIoMappings(element, newTemplate, context) {
var newMappings = createInputOutputMappings(newTemplate, bpmnFactory),
oldMappings;
if (!newMappings) {
return;
}
if (context) {
commandStack.execute('properties-panel.update-businessobject', {
element: element,
businessObject: context,
properties: { inputOutput: newMappings }
});
} else {
context = getOrCreateExtensionElements(element);
oldMappings = findExtension(element, 'flowable:InputOutput');
commandStack.execute('properties-panel.update-businessobject-list', {
element: element,
currentObject: context,
propertyName: 'values',
objectsToAdd: [ newMappings ],
objectsToRemove: oldMappings ? [ oldMappings ] : []
});
}
}
function updateFlowableField(element, newTemplate, context) {
var newMappings = createFlowableFieldInjections(newTemplate, bpmnFactory),
oldMappings;
if (!newMappings) {
return;
}
if (context) {
commandStack.execute('properties-panel.update-businessobject', {
element: element,
businessObject: context,
properties: { field: newMappings }
});
} else {
context = getOrCreateExtensionElements(element);
oldMappings = findExtensions(element, ['flowable:Field']);
commandStack.execute('properties-panel.update-businessobject-list', {
element: element,
currentObject: context,
propertyName: 'values',
objectsToAdd: newMappings,
objectsToRemove: oldMappings ? oldMappings : []
});
}
}
function updateFlowableProperties(element, newTemplate, context) {
var newProperties = createFlowableProperties(newTemplate, bpmnFactory),
oldProperties;
if (!newProperties) {
return;
}
if (context) {
commandStack.execute('properties-panel.update-businessobject', {
element: element,
businessObject: context,
properties: { properties: newProperties }
});
} else {
context = getOrCreateExtensionElements(element);
oldProperties = findExtension(element, 'flowable:Properties');
commandStack.execute('properties-panel.update-businessobject-list', {
element: element,
currentObject: context,
propertyName: 'values',
objectsToAdd: [ newProperties ],
objectsToRemove: oldProperties ? [ oldProperties ] : []
});
}
}
function updateProperties(element, newTemplate, context) {
var newProperties = createBpmnPropertyUpdates(newTemplate, bpmnFactory);
var newPropertiesCount = Object.keys(newProperties).length;
if (!newPropertiesCount) {
return;
}
if (context) {
commandStack.execute('properties-panel.update-businessobject', {
element: element,
businessObject: context,
properties: newProperties
});
} else {
modeling.updateProperties(element, newProperties);
}
}
function updateInOut(element, newTemplate, context) {
var newInOut = createFlowableInOut(newTemplate, bpmnFactory),
oldInOut;
if (!newInOut) {
return;
}
if (context) {
commandStack.execute('properties-panel.update-businessobject', {
element: element,
businessObject: context,
properties: { inout: newInOut }
});
} else {
context = getOrCreateExtensionElements(element);
oldInOut = findExtensions(context, [ 'flowable:In', 'flowable:Out' ]);
commandStack.execute('properties-panel.update-businessobject-list', {
element: element,
currentObject: context,
propertyName: 'values',
objectsToAdd: newInOut,
objectsToRemove: oldInOut
});
}
}
function updateExecutionListener(element, newTemplate, context) {
var newExecutionListeners = createFlowableExecutionListeners(newTemplate, bpmnFactory),
oldExecutionsListeners;
if (!newExecutionListeners.length) {
return;
}
if (context) {
commandStack.execute('properties-panel.update-businessobject', {
element: element,
businessObject: context,
properties: { executionListener: newExecutionListeners }
});
} else {
context = getOrCreateExtensionElements(element);
oldExecutionsListeners = findExtensions(context, [ 'flowable:ExecutionListener' ]);
commandStack.execute('properties-panel.update-businessobject-list', {
element: element,
currentObject: context,
propertyName: 'values',
objectsToAdd: newExecutionListeners,
objectsToRemove: oldExecutionsListeners
});
}
}
/**
* Update / recreate a scoped element.
*
* @param {djs.model.Base} element the diagram parent element
* @param {String} scopeName name of the scope, i.e. flowable:Connector
* @param {Object} scopeDefinition
*/
function updateScopeElements(element, scopeName, scopeDefinition) {
var scopeElement = bpmnFactory.create(scopeName);
// update flowable:inputOutput
updateIoMappings(element, scopeDefinition, scopeElement);
// update flowable:field
updateFlowableField(element, scopeDefinition, scopeElement);
// update flowable:properties
updateFlowableProperties(element, scopeDefinition, scopeElement);
// update other properties (bpmn:condition, flowable:async, ...)
updateProperties(element, scopeDefinition, scopeElement);
// update flowable:in and flowable:out
updateInOut(element, scopeDefinition, scopeElement);
// update flowable:executionListener
updateExecutionListener(element, scopeDefinition, scopeElement);
var extensionElements = getOrCreateExtensionElements(element);
var oldScope = findExtension(extensionElements, scopeName);
commandStack.execute('properties-panel.update-businessobject-list', {
element: element,
currentObject: extensionElements,
propertyName: 'values',
objectsToAdd: [ scopeElement ],
objectsToRemove: oldScope ? [ oldScope ] : []
});
}
/**
* Compose an element template change action, updating all
* necessary underlying properties.
*
* @param {Object} context
* @param {Object} context.element
* @param {Object} context.oldTemplate
* @param {Object} context.newTemplate
*/
this.preExecute = function(context) {
var element = context.element,
newTemplate = context.newTemplate;
// update flowable:modelerTemplate attribute
updateModelerTemplate(element, newTemplate);
if (newTemplate) {
// update flowable:inputOutput
updateIoMappings(element, newTemplate);
// update flowable:field
updateFlowableField(element, newTemplate);
// update flowable:properties
updateFlowableProperties(element, newTemplate);
// update other properties (bpmn:condition, flowable:async, ...)
updateProperties(element, newTemplate);
// update flowable:in and flowable:out
updateInOut(element, newTemplate);
// update flowable:executionListener
updateExecutionListener(element, newTemplate);
// loop on scopes properties
forEach(newTemplate.scopes, function(scopeDefinition, scopeName) {
updateScopeElements(element, scopeName, scopeDefinition);
});
}
};
}
ChangeElementTemplateHandler.$inject = [ 'modeling', 'commandStack', 'bpmnFactory' ];
module.exports = ChangeElementTemplateHandler;
// helpers /////////////////////////////
function createBpmnPropertyUpdates(template, bpmnFactory) {
var propertyUpdates = {};
template.properties.forEach(function(p) {
var binding = p.binding,
bindingTarget = binding.name,
propertyValue;
if (binding.type === 'property') {
if (bindingTarget === 'conditionExpression') {
propertyValue = bpmnFactory.create('bpmn:FormalExpression', {
body: p.value,
language: binding.scriptFormat
});
} else {
propertyValue = p.value;
}
// assigning flowable:async to true|false
// assigning bpmn:conditionExpression to { $type: 'bpmn:FormalExpression', ... }
propertyUpdates[bindingTarget] = propertyValue;
// make sure we unset other "implementation types"
// when applying a flowable:class template onto a preconfigured
// flowable:delegateExpression element
if (CAMUNDA_SERVICE_TASK_LIKE.indexOf(bindingTarget) !== -1) {
CAMUNDA_SERVICE_TASK_LIKE.forEach(function(prop) {
if (prop !== bindingTarget) {
propertyUpdates[prop] = undefined;
}
});
}
}
});
return propertyUpdates;
}
function createFlowableFieldInjections(template, bpmnFactory) {
var injections = [];
template.properties.forEach(function(p) {
var binding = p.binding,
bindingType = binding.type;
if (bindingType === 'flowable:field') {
injections.push(createFlowableFieldInjection(
binding, p.value, bpmnFactory
));
}
});
if (injections.length) {
return injections;
}
}
function createFlowableProperties(template, bpmnFactory) {
var properties = [];
template.properties.forEach(function(p) {
var binding = p.binding,
bindingType = binding.type;
if (bindingType === 'flowable:property') {
properties.push(createFlowableProperty(
binding, p.value, bpmnFactory
));
}
});
if (properties.length) {
return bpmnFactory.create('flowable:Properties', {
values: properties
});
}
}
function createInputOutputMappings(template, bpmnFactory) {
var inputParameters = [],
outputParameters = [];
template.properties.forEach(function(p) {
var binding = p.binding,
bindingType = binding.type;
if (bindingType === 'flowable:inputParameter') {
inputParameters.push(createInputParameter(
binding, p.value, bpmnFactory
));
}
if (bindingType === 'flowable:outputParameter') {
outputParameters.push(createOutputParameter(
binding, p.value, bpmnFactory
));
}
});
// do we need to create new ioMappings (?)
if (outputParameters.length || inputParameters.length) {
return bpmnFactory.create('flowable:InputOutput', {
inputParameters: inputParameters,
outputParameters: outputParameters
});
}
}
function createFlowableInOut(template, bpmnFactory) {
var inOuts = [];
template.properties.forEach(function(p) {
var binding = p.binding,
bindingType = binding.type;
if (bindingType === 'flowable:in') {
inOuts.push(createFlowableIn(
binding, p.value, bpmnFactory
));
} else
if (bindingType === 'flowable:out') {
inOuts.push(createFlowableOut(
binding, p.value, bpmnFactory
));
} else
if (bindingType === 'flowable:in:businessKey') {
inOuts.push(createFlowableInWithBusinessKey(
binding, p.value, bpmnFactory
));
}
});
return inOuts;
}
function createFlowableExecutionListeners(template, bpmnFactory) {
var executionListener = [];
template.properties.forEach(function(p) {
var binding = p.binding,
bindingType = binding.type;
if (bindingType === 'flowable:executionListener') {
executionListener.push(createFlowableExecutionListenerScript(
binding, p.value, bpmnFactory
));
}
});
return executionListener;
}