import inherits from 'inherits'; import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor'; import { is } from '../../../util/ModelUtil'; import { isAny } from '../util/ModelingUtil'; import UpdateSemanticParentHandler from '../cmd/UpdateSemanticParentHandler'; /** * BPMN specific data store behavior */ export default function DataStoreBehavior( canvas, commandStack, elementRegistry, eventBus) { CommandInterceptor.call(this, eventBus); commandStack.registerHandler('dataStore.updateContainment', UpdateSemanticParentHandler); function getFirstParticipant() { return elementRegistry.filter(function(element) { return is(element, 'bpmn:Participant'); })[0]; } function getDataStores(element) { return element.children.filter(function(child) { return is(child, 'bpmn:DataStoreReference') && !child.labelTarget; }); } function updateDataStoreParent(dataStore, newDataStoreParent) { var dataStoreBo = dataStore.businessObject || dataStore; newDataStoreParent = newDataStoreParent || getFirstParticipant(); if (newDataStoreParent) { var newDataStoreParentBo = newDataStoreParent.businessObject || newDataStoreParent; commandStack.execute('dataStore.updateContainment', { dataStoreBo: dataStoreBo, newSemanticParent: newDataStoreParentBo.processRef || newDataStoreParentBo, newDiParent: newDataStoreParentBo.di }); } } // disable auto-resize for data stores this.preExecute('shape.create', function(event) { var context = event.context, shape = context.shape; if (is(shape, 'bpmn:DataStoreReference') && shape.type !== 'label') { if (!context.hints) { context.hints = {}; } // prevent auto resizing context.hints.autoResize = false; } }); // disable auto-resize for data stores this.preExecute('elements.move', function(event) { var context = event.context, shapes = context.shapes; var dataStoreReferences = shapes.filter(function(shape) { return is(shape, 'bpmn:DataStoreReference'); }); if (dataStoreReferences.length) { if (!context.hints) { context.hints = {}; } // prevent auto resizing for data store references context.hints.autoResize = shapes.filter(function(shape) { return !is(shape, 'bpmn:DataStoreReference'); }); } }); // update parent on data store created this.postExecute('shape.create', function(event) { var context = event.context, shape = context.shape, parent = shape.parent; if (is(shape, 'bpmn:DataStoreReference') && shape.type !== 'label' && is(parent, 'bpmn:Collaboration')) { updateDataStoreParent(shape); } }); // update parent on data store moved this.postExecute('shape.move', function(event) { var context = event.context, shape = context.shape, oldParent = context.oldParent, parent = shape.parent; if (is(oldParent, 'bpmn:Collaboration')) { // do nothing if not necessary return; } if (is(shape, 'bpmn:DataStoreReference') && shape.type !== 'label' && is(parent, 'bpmn:Collaboration')) { var participant = is(oldParent, 'bpmn:Participant') ? oldParent : getAncestor(oldParent, 'bpmn:Participant'); updateDataStoreParent(shape, participant); } }); // update data store parents on participant or subprocess deleted this.postExecute('shape.delete', function(event) { var context = event.context, shape = context.shape, rootElement = canvas.getRootElement(); if (isAny(shape, [ 'bpmn:Participant', 'bpmn:SubProcess' ]) && is(rootElement, 'bpmn:Collaboration')) { getDataStores(rootElement) .filter(function(dataStore) { return isDescendant(dataStore, shape); }) .forEach(function(dataStore) { updateDataStoreParent(dataStore); }); } }); // update data store parents on collaboration -> process this.postExecute('canvas.updateRoot', function(event) { var context = event.context, oldRoot = context.oldRoot, newRoot = context.newRoot; var dataStores = getDataStores(oldRoot); dataStores.forEach(function(dataStore) { if (is(newRoot, 'bpmn:Process')) { updateDataStoreParent(dataStore, newRoot); } }); }); } DataStoreBehavior.$inject = [ 'canvas', 'commandStack', 'elementRegistry', 'eventBus', ]; inherits(DataStoreBehavior, CommandInterceptor); // helpers ////////// function isDescendant(descendant, ancestor) { var descendantBo = descendant.businessObject || descendant, ancestorBo = ancestor.businessObject || ancestor; while (descendantBo.$parent) { if (descendantBo.$parent === ancestorBo.processRef || ancestorBo) { return true; } descendantBo = descendantBo.$parent; } return false; } function getAncestor(element, type) { while (element.parent) { if (is(element.parent, type)) { return element.parent; } element = element.parent; } }