diff --git a/lib/features/modeling/behavior/CreateLaneBehavior.js b/lib/features/modeling/behavior/CreateLaneBehavior.js new file mode 100644 index 00000000..97b9950d --- /dev/null +++ b/lib/features/modeling/behavior/CreateLaneBehavior.js @@ -0,0 +1,80 @@ +'use strict'; + +var inherits = require('inherits'); + +var CommandInterceptor = require('diagram-js/lib/command/CommandInterceptor'); + +var is = require('../../../util/ModelUtil').is; + +var every = require('lodash/collection/every'); + +var round = Math.round; + + +/** + * BPMN specific create lane behavior + */ +function CreateLaneBehavior(eventBus, modeling) { + + CommandInterceptor.call(this, eventBus); + + /** + * wrap existing elements with new lane + */ + + this.preExecute('shape.create', function(context) { + + var parent = context.parent, + shape = context.shape, + children = parent.children; + + // check whether we need to wrap + // the existing elements into the new lane + if (is(shape, 'bpmn:Lane')) { + + var labelOffset = 0; + + if (is(parent, 'bpmn:Participant') || is(parent, 'bpmn:Lane')) { + labelOffset = 30; + } + + shape.width = parent.width - labelOffset; + context.position.x = round(parent.x + labelOffset / 2 + parent.width / 2); + + // wrap + adjust lane height + y to fit parent + if (every(children, isNonLane)) { + shape.height = parent.height; + context.position.y = round(parent.y + parent.height / 2); + + context.wrapInLane = children.slice(); + } + } + }, true); + + + this.postExecute('shape.create', function(context) { + + var shape = context.shape, + wrapInLane = context.wrapInLane; + + if (wrapInLane) { + + // wrap existing elements onto the new lane, + // if this is the first lane in the parent + modeling.moveElements(wrapInLane, { x: 0, y: 0 }, shape); + } + + }, true); + +} + +CreateLaneBehavior.$inject = [ 'eventBus', 'modeling' ]; + +inherits(CreateLaneBehavior, CommandInterceptor); + +module.exports = CreateLaneBehavior; + + +function isNonLane(element) { + return !is(element, 'bpmn:Lane'); +} \ No newline at end of file diff --git a/lib/features/modeling/behavior/index.js b/lib/features/modeling/behavior/index.js index 1f1b265c..21601101 100644 --- a/lib/features/modeling/behavior/index.js +++ b/lib/features/modeling/behavior/index.js @@ -2,6 +2,7 @@ module.exports = { __init__: [ 'appendBehavior', 'createBoundaryEventBehavior', + 'createLaneBehavior', 'createOnFlowBehavior', 'createParticipantBehavior', 'modelingFeedback', @@ -11,6 +12,7 @@ module.exports = { ], appendBehavior: [ 'type', require('./AppendBehavior') ], createBoundaryEventBehavior: [ 'type', require('./CreateBoundaryEventBehavior') ], + createLaneBehavior: [ 'type', require('./CreateLaneBehavior') ], createOnFlowBehavior: [ 'type', require('./CreateOnFlowBehavior') ], createParticipantBehavior: [ 'type', require('./CreateParticipantBehavior') ], modelingFeedback: [ 'type', require('./ModelingFeedback') ], diff --git a/test/spec/features/modeling/lanes/CreateLaneSpec.js b/test/spec/features/modeling/lanes/CreateLaneSpec.js index 78a95126..ba17a84c 100644 --- a/test/spec/features/modeling/lanes/CreateLaneSpec.js +++ b/test/spec/features/modeling/lanes/CreateLaneSpec.js @@ -218,4 +218,32 @@ describe('features/modeling - create lanes', function() { }); + + function ids(elements) { + return elements.map(function(e) { return e.id; }); + } + + describe('should wrap existing children', function() { + + var diagramXML = require('./nested-lane.bpmn'); + + var testModules = [ coreModule, modelingModule ]; + + beforeEach(bootstrapModeler(diagramXML, { modules: testModules })); + + + it('execute', inject(function(elementRegistry, modeling) { + + // given + var nestedLaneShape = elementRegistry.get('Nested_Lane'); + + // when + var newLaneShape = modeling.createShape({ type: 'bpmn:Lane' }, { x: 180, y: 100 }, nestedLaneShape); + + // then + expect(ids(newLaneShape.children)).to.eql([ 'Task_Boundary', 'Task', 'Boundary' ]); + })); + + }); + });