UNPKG

vmes-flowable

Version:

ceshibao

470 lines (369 loc) 13.3 kB
'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; }