123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770 |
- 'use strict';
- var assign = require('lodash/assign');
- var entryFactory = require('../../../../factory/EntryFactory'),
- getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject,
- getTemplate = require('../Helper').getTemplate,
- cmdHelper = require('../../../../helper/CmdHelper'),
- elementHelper = require('../../../../helper/ElementHelper');
- var findExtension = require('../Helper').findExtension,
- findExtensions = require('../Helper').findExtensions,
- findInputParameter = require('../Helper').findInputParameter,
- findOutputParameter = require('../Helper').findOutputParameter,
- findActivitiProperty = require('../Helper').findActivitiProperty,
- findActivitiInOut = require('../Helper').findActivitiInOut;
- var createActivitiProperty = require('../CreateHelper').createActivitiProperty,
- createInputParameter = require('../CreateHelper').createInputParameter,
- createOutputParameter = require('../CreateHelper').createOutputParameter,
- createActivitiIn = require('../CreateHelper').createActivitiIn,
- createActivitiOut = require('../CreateHelper').createActivitiOut,
- createActivitiInWithBusinessKey = require('../CreateHelper').createActivitiInWithBusinessKey,
- createActivitiFieldInjection = require('../CreateHelper').createActivitiFieldInjection;
- var ACTIVITI_PROPERTY_TYPE = 'activiti:property',
- ACTIVITI_INPUT_PARAMETER_TYPE = 'activiti:inputParameter',
- ACTIVITI_OUTPUT_PARAMETER_TYPE = 'activiti:outputParameter',
- ACTIVITI_IN_TYPE = 'activiti:in',
- ACTIVITI_OUT_TYPE = 'activiti:out',
- ACTIVITI_IN_BUSINESS_KEY_TYPE = 'activiti:in:businessKey',
- ACTIVITI_EXECUTION_LISTENER_TYPE = 'activiti:executionListener',
- ACTIVITI_FIELD = 'activiti:field';
- var BASIC_MODDLE_TYPES = [
- 'Boolean',
- 'Integer',
- 'String'
- ];
- var EXTENSION_BINDING_TYPES = [
- ACTIVITI_PROPERTY_TYPE,
- ACTIVITI_INPUT_PARAMETER_TYPE,
- ACTIVITI_OUTPUT_PARAMETER_TYPE,
- ACTIVITI_IN_TYPE,
- ACTIVITI_OUT_TYPE,
- ACTIVITI_IN_BUSINESS_KEY_TYPE,
- ACTIVITI_FIELD
- ];
- var IO_BINDING_TYPES = [
- ACTIVITI_INPUT_PARAMETER_TYPE,
- ACTIVITI_OUTPUT_PARAMETER_TYPE
- ];
- var IN_OUT_BINDING_TYPES = [
- ACTIVITI_IN_TYPE,
- ACTIVITI_OUT_TYPE,
- ACTIVITI_IN_BUSINESS_KEY_TYPE
- ];
- /**
- * Injects custom properties into the given group.
- *
- * @param {djs.model.Base} element
- * @param {ElementTemplates} elementTemplates
- * @param {BpmnFactory} bpmnFactory
- * @param {Function} translate
- */
- module.exports = function(element, elementTemplates, bpmnFactory, translate) {
- var template = getTemplate(element, elementTemplates);
- if (!template) {
- return [];
- }
- var renderCustomField = function(id, p, idx) {
- var propertyType = p.type;
- var entryOptions = {
- id: id,
- description: p.description,
- label: p.label ? translate(p.label) : p.label,
- modelProperty: id,
- get: propertyGetter(id, p),
- set: propertySetter(id, p, bpmnFactory),
- validate: propertyValidator(id, p, translate)
- };
- var entry;
- if (propertyType === 'Boolean') {
- entry = entryFactory.checkbox(entryOptions);
- }
- if (propertyType === 'String') {
- entry = entryFactory.textField(entryOptions);
- }
- if (propertyType === 'Text') {
- entry = entryFactory.textBox(entryOptions);
- }
- if (propertyType === 'Dropdown') {
- entryOptions.selectOptions = p.choices;
- entry = entryFactory.selectBox(entryOptions);
- }
- return entry;
- };
- var groups = [];
- var id, entry;
- var customFieldsGroup = {
- id: 'customField',
- label: translate('Custom Fields'),
- entries: []
- };
- template.properties.forEach(function(p, idx) {
- id = 'custom-' + template.id + '-' + idx;
- entry = renderCustomField(id, p, idx);
- if (entry) {
- customFieldsGroup.entries.push(entry);
- }
- });
- if (customFieldsGroup.entries.length > 0) {
- groups.push(customFieldsGroup);
- }
- if (template.scopes) {
- for (var scopeName in template.scopes) {
- var scope = template.scopes[scopeName];
- var idScopeName = scopeName.replace(/:/g, '_');
- var customScopeFieldsGroup = {
- id: 'customField-' + idScopeName,
- label: translate('Custom Fields for scope: ') + scopeName,
- entries: []
- };
- scope.properties.forEach(function(p, idx) {
- var propertyId = 'custom-' + template.id + '-' + idScopeName + '-' + idx;
- var scopedProperty = propertyWithScope(p, scopeName);
- entry = renderCustomField(propertyId, scopedProperty, idx);
- if (entry) {
- customScopeFieldsGroup.entries.push(entry);
- }
- });
- if (customScopeFieldsGroup.entries.length > 0) {
- groups.push(customScopeFieldsGroup);
- }
- }
- }
- return groups;
- };
- // getters, setters and validators ///////////////
- /**
- * Return a getter that retrieves the given property.
- *
- * @param {String} name
- * @param {PropertyDescriptor} property
- *
- * @return {Function}
- */
- function propertyGetter(name, property) {
- /* getter */
- return function get(element) {
- var value = getPropertyValue(element, property);
- return objectWithKey(name, value);
- };
- }
- /**
- * Return a setter that updates the given property.
- *
- * @param {String} name
- * @param {PropertyDescriptor} property
- * @param {BpmnFactory} bpmnFactory
- *
- * @return {Function}
- */
- function propertySetter(name, property, bpmnFactory) {
- /* setter */
- return function set(element, values) {
- var value = values[name];
- return setPropertyValue(element, property, value, bpmnFactory);
- };
- }
- /**
- * Return a validator that ensures the property is ok.
- *
- * @param {String} name
- * @param {PropertyDescriptor} property
- * @param {Function} translate
- *
- * @return {Function}
- */
- function propertyValidator(name, property, translate) {
- /* validator */
- return function validate(element, values) {
- var value = values[name];
- var error = validateValue(value, property, translate);
- if (error) {
- return objectWithKey(name, error);
- }
- };
- }
- // get, set and validate helpers ///////////////////
- /**
- * Return the value of the specified property descriptor,
- * on the passed diagram element.
- *
- * @param {djs.model.Base} element
- * @param {PropertyDescriptor} property
- *
- * @return {Any}
- */
- function getPropertyValue(element, property) {
- var bo = getBusinessObject(element);
- var binding = property.binding,
- scope = property.scope;
- var bindingType = binding.type,
- bindingName = binding.name;
- var propertyValue = property.value || '';
- if (scope) {
- bo = findExtension(bo, scope.name);
- if (!bo) {
- return propertyValue;
- }
- }
- // property
- if (bindingType === 'property') {
- var value = bo.get(bindingName);
- if (bindingName === 'conditionExpression') {
- if (value) {
- return value.body;
- } else {
- // return defined default
- return propertyValue;
- }
- } else {
- // return value; default to defined default
- return typeof value !== 'undefined' ? value : propertyValue;
- }
- }
- var activitiProperties,
- activitiProperty;
- if (bindingType === ACTIVITI_PROPERTY_TYPE) {
- if (scope) {
- activitiProperties = bo.get('properties');
- } else {
- activitiProperties = findExtension(bo, 'activiti:Properties');
- }
- if (activitiProperties) {
- activitiProperty = findActivitiProperty(activitiProperties, binding);
- if (activitiProperty) {
- return activitiProperty.value;
- }
- }
- return propertyValue;
- }
- var inputOutput,
- ioParameter;
- if (IO_BINDING_TYPES.indexOf(bindingType) !== -1) {
- if (scope) {
- inputOutput = bo.get('inputOutput');
- } else {
- inputOutput = findExtension(bo, 'activiti:InputOutput');
- }
- if (!inputOutput) {
- // ioParameter cannot exist yet, return property value
- return propertyValue;
- }
- }
- // activiti input parameter
- if (bindingType === ACTIVITI_INPUT_PARAMETER_TYPE) {
- ioParameter = findInputParameter(inputOutput, binding);
- if (ioParameter) {
- if (binding.scriptFormat) {
- if (ioParameter.definition) {
- return ioParameter.definition.value;
- }
- } else {
- return ioParameter.value || '';
- }
- }
- return propertyValue;
- }
- // activiti output parameter
- if (binding.type === ACTIVITI_OUTPUT_PARAMETER_TYPE) {
- ioParameter = findOutputParameter(inputOutput, binding);
- if (ioParameter) {
- return ioParameter.name;
- }
- return propertyValue;
- }
- var ioElement;
- if (IN_OUT_BINDING_TYPES.indexOf(bindingType) != -1) {
- ioElement = findActivitiInOut(bo, binding);
- if (ioElement) {
- if (bindingType === ACTIVITI_IN_BUSINESS_KEY_TYPE) {
- return ioElement.businessKey;
- } else
- if (bindingType === ACTIVITI_OUT_TYPE) {
- return ioElement.target;
- } else
- if (bindingType === ACTIVITI_IN_TYPE) {
- return ioElement[binding.expression ? 'sourceExpression' : 'source'];
- }
- }
- return propertyValue;
- }
- if (bindingType === ACTIVITI_EXECUTION_LISTENER_TYPE) {
- var executionListener;
- if (scope) {
- executionListener = bo.get('executionListener');
- } else {
- executionListener = findExtension(bo, 'activiti:ExecutionListener');
- }
- return executionListener.script.value;
- }
- var fieldInjection;
- if (ACTIVITI_FIELD === bindingType) {
- var fieldInjections = findExtensions(bo, [ 'activiti:Field' ]);
- fieldInjections.forEach(function(item) {
- if (item.name === binding.name) {
- fieldInjection = item;
- }
- });
- if (fieldInjection) {
- return fieldInjection.string || fieldInjection.expression;
- } else {
- return '';
- }
- }
- throw unknownPropertyBinding(property);
- }
- module.exports.getPropertyValue = getPropertyValue;
- /**
- * Return an update operation that changes the diagram
- * element's custom property to the given value.
- *
- * The response of this method will be processed via
- * {@link PropertiesPanel#applyChanges}.
- *
- * @param {djs.model.Base} element
- * @param {PropertyDescriptor} property
- * @param {String} value
- * @param {BpmnFactory} bpmnFactory
- *
- * @return {Object|Array<Object>} results to be processed
- */
- function setPropertyValue(element, property, value, bpmnFactory) {
- var bo = getBusinessObject(element);
- var binding = property.binding,
- scope = property.scope;
- var bindingType = binding.type,
- bindingName = binding.name;
- var propertyValue;
- var updates = [];
- var extensionElements;
- if (EXTENSION_BINDING_TYPES.indexOf(bindingType) !== -1) {
- extensionElements = bo.get('extensionElements');
- // create extension elements, if they do not exist (yet)
- if (!extensionElements) {
- extensionElements = elementHelper.createElement('bpmn:ExtensionElements', null, element, bpmnFactory);
- updates.push(cmdHelper.updateBusinessObject(
- element, bo, objectWithKey('extensionElements', extensionElements)
- ));
- }
- }
- if (scope) {
- bo = findExtension(bo, scope.name);
- if (!bo) {
- bo = elementHelper.createElement(scope.name, null, element, bpmnFactory);
- updates.push(cmdHelper.addElementsTolist(
- bo, extensionElements, 'values', [ bo ]
- ));
- }
- }
- // property
- if (bindingType === 'property') {
- if (bindingName === 'conditionExpression') {
- propertyValue = elementHelper.createElement('bpmn:FormalExpression', {
- body: value,
- language: binding.scriptFormat
- }, bo, bpmnFactory);
- } else {
- var moddlePropertyDescriptor = bo.$descriptor.propertiesByName[bindingName];
- var moddleType = moddlePropertyDescriptor.type;
- // make sure we only update String, Integer, Real and
- // Boolean properties (do not accidentally override complex objects...)
- if (BASIC_MODDLE_TYPES.indexOf(moddleType) === -1) {
- throw new Error('cannot set moddle type <' + moddleType + '>');
- }
- if (moddleType === 'Boolean') {
- propertyValue = !!value;
- } else
- if (moddleType === 'Integer') {
- propertyValue = parseInt(value, 10);
- if (isNaN(propertyValue)) {
- // do not write NaN value
- propertyValue = undefined;
- }
- } else {
- propertyValue = value;
- }
- }
- if (propertyValue !== undefined) {
- updates.push(cmdHelper.updateBusinessObject(
- element, bo, objectWithKey(bindingName, propertyValue)
- ));
- }
- }
- // activiti:property
- var activitiProperties,
- existingActivitiProperty,
- newActivitiProperty;
- if (bindingType === ACTIVITI_PROPERTY_TYPE) {
- if (scope) {
- activitiProperties = bo.get('properties');
- } else {
- activitiProperties = findExtension(extensionElements, 'activiti:Properties');
- }
- if (!activitiProperties) {
- activitiProperties = elementHelper.createElement('activiti:Properties', null, bo, bpmnFactory);
- if (scope) {
- updates.push(cmdHelper.updateBusinessObject(
- element, bo, { properties: activitiProperties }
- ));
- }
- else {
- updates.push(cmdHelper.addElementsTolist(
- element, extensionElements, 'values', [ activitiProperties ]
- ));
- }
- }
- existingActivitiProperty = findActivitiProperty(activitiProperties, binding);
- newActivitiProperty = createActivitiProperty(binding, value, bpmnFactory);
- updates.push(cmdHelper.addAndRemoveElementsFromList(
- element,
- activitiProperties,
- 'values',
- null,
- [ newActivitiProperty ],
- existingActivitiProperty ? [ existingActivitiProperty ] : []
- ));
- }
- // activiti:inputParameter
- // activiti:outputParameter
- var inputOutput,
- existingIoParameter,
- newIoParameter;
- if (IO_BINDING_TYPES.indexOf(bindingType) !== -1) {
- if (scope) {
- inputOutput = bo.get('inputOutput');
- } else {
- inputOutput = findExtension(extensionElements, 'activiti:InputOutput');
- }
- // create inputOutput element, if it do not exist (yet)
- if (!inputOutput) {
- inputOutput = elementHelper.createElement('activiti:InputOutput', null, bo, bpmnFactory);
- if (scope) {
- updates.push(cmdHelper.updateBusinessObject(
- element, bo, { inputOutput: inputOutput }
- ));
- }
- else {
- updates.push(cmdHelper.addElementsTolist(
- element, extensionElements, 'values', inputOutput
- ));
- }
- }
- }
- if (bindingType === ACTIVITI_INPUT_PARAMETER_TYPE) {
- existingIoParameter = findInputParameter(inputOutput, binding);
- newIoParameter = createInputParameter(binding, value, bpmnFactory);
- updates.push(cmdHelper.addAndRemoveElementsFromList(
- element,
- inputOutput,
- 'inputParameters',
- null,
- [ newIoParameter ],
- existingIoParameter ? [ existingIoParameter ] : []
- ));
- }
- if (bindingType === ACTIVITI_OUTPUT_PARAMETER_TYPE) {
- existingIoParameter = findOutputParameter(inputOutput, binding);
- newIoParameter = createOutputParameter(binding, value, bpmnFactory);
- updates.push(cmdHelper.addAndRemoveElementsFromList(
- element,
- inputOutput,
- 'outputParameters',
- null,
- [ newIoParameter ],
- existingIoParameter ? [ existingIoParameter ] : []
- ));
- }
- // activiti:in
- // activiti:out
- // activiti:in:businessKey
- var existingInOut,
- newInOut;
- if (IN_OUT_BINDING_TYPES.indexOf(bindingType) !== -1) {
- existingInOut = findActivitiInOut(bo, binding);
- if (bindingType === ACTIVITI_IN_TYPE) {
- newInOut = createActivitiIn(binding, value, bpmnFactory);
- } else
- if (bindingType === ACTIVITI_OUT_TYPE) {
- newInOut = createActivitiOut(binding, value, bpmnFactory);
- } else {
- newInOut = createActivitiInWithBusinessKey(binding, value, bpmnFactory);
- }
- updates.push(cmdHelper.addAndRemoveElementsFromList(
- element,
- extensionElements,
- 'values',
- null,
- [ newInOut ],
- existingInOut ? [ existingInOut ] : []
- ));
- }
- if (bindingType === ACTIVITI_FIELD) {
- var existingFieldInjections = findExtensions(bo, [ 'activiti:Field' ]);
- var newFieldInjections = [];
- if (existingFieldInjections.length > 0) {
- existingFieldInjections.forEach(function(item) {
- if (item.name === binding.name) {
- newFieldInjections.push(createActivitiFieldInjection(binding, value, bpmnFactory));
- } else {
- newFieldInjections.push(item);
- }
- });
- } else {
- newFieldInjections.push(createActivitiFieldInjection(binding, value, bpmnFactory));
- }
- updates.push(cmdHelper.addAndRemoveElementsFromList(
- element,
- extensionElements,
- 'values',
- null,
- newFieldInjections,
- existingFieldInjections ? existingFieldInjections : []
- ));
- }
- if (updates.length) {
- return updates;
- }
- // quick warning for better debugging
- console.warn('no update', element, property, value);
- }
- module.exports.setPropertyValue = setPropertyValue;
- /**
- * Validate value of a given property.
- *
- * @param {String} value
- * @param {PropertyDescriptor} property
- * @param {Function} translate
- *
- * @return {Object} with validation errors
- */
- function validateValue(value, property, translate) {
- var constraints = property.constraints || {};
- if (constraints.notEmpty && isEmpty(value)) {
- return translate('Must not be empty');
- }
- if (constraints.maxLength && value.length > constraints.maxLength) {
- return translate('Must have max length {length}', { length: constraints.maxLength });
- }
- if (constraints.minLength && value.length < constraints.minLength) {
- return translate('Must have min length {length}', { length: constraints.minLength });
- }
- var pattern = constraints.pattern,
- message;
- if (pattern) {
- if (typeof pattern !== 'string') {
- message = pattern.message;
- pattern = pattern.value;
- }
- if (!matchesPattern(value, pattern)) {
- return message || translate('Must match pattern {pattern}', { pattern: pattern });
- }
- }
- }
- // misc helpers ///////////////////////////////
- function propertyWithScope(property, scopeName) {
- if (!scopeName) {
- return property;
- }
- return assign({}, property, {
- scope: {
- name: scopeName
- }
- });
- }
- /**
- * Return an object with a single key -> value association.
- *
- * @param {String} key
- * @param {Any} value
- *
- * @return {Object}
- */
- function objectWithKey(key, value) {
- var obj = {};
- obj[key] = value;
- return obj;
- }
- /**
- * Does the given string match the specified pattern?
- *
- * @param {String} str
- * @param {String} pattern
- *
- * @return {Boolean}
- */
- function matchesPattern(str, pattern) {
- var regexp = new RegExp(pattern);
- return regexp.test(str);
- }
- function isEmpty(str) {
- return !str || /^\s*$/.test(str);
- }
- /**
- * Create a new {@link Error} indicating an unknown
- * property binding.
- *
- * @param {PropertyDescriptor} property
- *
- * @return {Error}
- */
- function unknownPropertyBinding(property) {
- var binding = property.binding;
- return new Error('unknown binding: <' + binding.type + '>');
- }
|