diff --git a/lib/Modeler.js b/lib/Modeler.js index e40e01a0..f90d5991 100644 --- a/lib/Modeler.js +++ b/lib/Modeler.js @@ -67,13 +67,9 @@ Modeler.prototype._modelingModules = [ require('diagram-js/lib/features/snapping'), require('diagram-js/lib/features/move'), require('diagram-js/lib/features/resize'), - require('diagram-js/lib/features/drop'), require('./features/modeling'), require('./features/context-pad'), - require('./features/palette'), - require('./features/resize'), - require('./features/rules'), - require('./features/drop') + require('./features/palette') ]; diff --git a/lib/features/drop/BpmnDrop.js b/lib/features/drop/BpmnDrop.js deleted file mode 100644 index 103e3c76..00000000 --- a/lib/features/drop/BpmnDrop.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -var _ = require('lodash'); - - - -function BpmnDrop(drop, openSequenceflowHandler, updateSequenceFlowParentHandler) { - - var actions = { - 'updateSequenceFlowParent': updateSequenceFlowParentHandler, - 'removeOpenSequenceflow': openSequenceflowHandler - }; - - var self = this; - - this._drop = drop; - - _.forEach(actions, function(action, key) { - self._drop.registerAfterDropAction(key, action.execute); - }); -} - -BpmnDrop.$inject = [ 'drop', 'openSequenceflowHandler', 'updateSequenceFlowParentHandler' ]; - -module.exports = BpmnDrop; diff --git a/lib/features/drop/OpenSequenceflowHandler.js b/lib/features/drop/OpenSequenceflowHandler.js deleted file mode 100644 index 1d7170b2..00000000 --- a/lib/features/drop/OpenSequenceflowHandler.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -var _ = require('lodash'); - -var self; -function OpenSequenceflowHandler(modeling) { - - self = this; - this._modeling = modeling; -} - -OpenSequenceflowHandler.$inject = [ 'modeling' ]; - -module.exports = OpenSequenceflowHandler; - - -/** - * Removes sequence flows that source or target does not have same parent. - */ -OpenSequenceflowHandler.prototype.execute = function(context) { - - var shapes = context.shapes, - connections = context.connections, - target = context.target; - - self._removeConnections(shapes, connections, target); -}; - - -OpenSequenceflowHandler.prototype._removeConnections = function(shapes, connections, target) { - - var modeling = self._modeling; - - var removeableConnections = getRemoveableConnections(shapes, connections); - - _.forEach(removeableConnections, function(connection) { - - var sourceParent = connection.source.parent, - targetParent = connection.target.parent; - - if (sourceParent.id !== targetParent.id) { - delete connections[connection.id]; - modeling.removeConnection(connection); - } - }); -}; - -function getRemoveableConnections(shapes, connections) { - - var connectionsToRemove = {}; - - _.forEach(shapes, function(shape) { - - var allConnections = _.union(shape.incoming, shape.outgoing); - - _.forEach(allConnections, function(connection) { - // if one of the connection endpoints points to a shape that is not part of the map - // delete the connection - if (!(shapes[connection.source.id] && shapes[connection.target.id])) { - connectionsToRemove[connection.id] = connection; - } - }); - - }); - - return connectionsToRemove; -} diff --git a/lib/features/drop/UpdateSequenceFlowParentHandler.js b/lib/features/drop/UpdateSequenceFlowParentHandler.js deleted file mode 100644 index 0a5a8884..00000000 --- a/lib/features/drop/UpdateSequenceFlowParentHandler.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -var _ = require('lodash'); - -var self; -function UpdateSequenceFlowParentHandler(modeling) { - - self = this; - this._modeling = modeling; -} - -UpdateSequenceFlowParentHandler.$inject = [ 'modeling' ]; - -module.exports = UpdateSequenceFlowParentHandler; - - - -UpdateSequenceFlowParentHandler.prototype.execute = function(context) { - - var shapes = context.shapes, - target = context.target; - - _.forEach(shapes, function(shape) { - handleFlow(shape.incoming); - handleFlow(shape.outgoing); - }); - - - function handleFlow(flows) { - - _.forEach(flows, function(flow) { - if (shapes[flow.source.id] && shapes[flow.target.id]) { - flow.parent = target; - } - }); - } -}; diff --git a/lib/features/drop/index.js b/lib/features/drop/index.js deleted file mode 100644 index 9df6c56f..00000000 --- a/lib/features/drop/index.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -module.exports = { - __init__: [ 'bpmnDrop', 'openSequenceflowHandler', 'updateSequenceFlowParentHandler' ], - __depends__: [ - require('diagram-js/lib/features/drop') - ], - bpmnDrop: [ 'type', require('./BpmnDrop') ], - openSequenceflowHandler: [ 'type', require('./OpenSequenceflowHandler') ], - updateSequenceFlowParentHandler: [ 'type', require('./UpdateSequenceFlowParentHandler') ] -}; diff --git a/lib/features/modeling/BpmnUpdater.js b/lib/features/modeling/BpmnUpdater.js index 8499efdf..a7743508 100644 --- a/lib/features/modeling/BpmnUpdater.js +++ b/lib/features/modeling/BpmnUpdater.js @@ -44,20 +44,22 @@ function BpmnUpdater(eventBus, bpmnFactory, connectionDocking) { // update parent - function updateShapeParent(e) { - self.updateShapeParent(e.context.shape || e.context.connection); + function updateParent(e) { + self.updateParent(e.context.shape || e.context.connection); } this.executed([ 'shape.move', 'shape.create', 'shape.delete', 'connection.create', - 'connection.delete' ], updateShapeParent); + 'connection.move', + 'connection.delete' ], updateParent); this.reverted([ 'shape.move', 'shape.create', 'shape.delete', 'connection.create', - 'connection.delete' ], updateShapeParent); + 'connection.move', + 'connection.delete' ], updateParent); // update bounds @@ -95,11 +97,11 @@ BpmnUpdater.$inject = [ 'eventBus', 'bpmnFactory', 'connectionDocking']; /////// implementation ////////////////////////////////// -BpmnUpdater.prototype.updateShapeParent = function(shape) { +BpmnUpdater.prototype.updateParent = function(element) { - var parentShape = shape.parent; + var parentShape = element.parent; - var businessObject = shape.businessObject, + var businessObject = element.businessObject, parentBusinessObject = parentShape && parentShape.businessObject, parentDi = parentBusinessObject && parentBusinessObject.di; diff --git a/lib/features/modeling/LabelSupport.js b/lib/features/modeling/LabelSupport.js index fbd32188..4e7a341b 100644 --- a/lib/features/modeling/LabelSupport.js +++ b/lib/features/modeling/LabelSupport.js @@ -38,13 +38,21 @@ function LabelSupport(eventBus, modeling, bpmnFactory) { eventBus.on('shape.move.start', 50000, function(e) { var dragContext = e.dragContext, - element = dragContext.element; + shapes = dragContext.shapes; - var label = element.label; + var labels = []; - if (label && !label.hidden && dragContext.shapes.indexOf(label) === -1) { - dragContext.shapes.push(label); - } + _.forEach(shapes, function(element) { + var label = element.label; + + if (label && !label.hidden && dragContext.shapes.indexOf(label) === -1) { + labels.push(label); + } + }); + + _.forEach(labels, function(label) { + shapes.push(label); + }); }); diff --git a/lib/features/modeling/Modeling.js b/lib/features/modeling/Modeling.js index 253b6749..efc6ea26 100644 --- a/lib/features/modeling/Modeling.js +++ b/lib/features/modeling/Modeling.js @@ -17,7 +17,6 @@ var CreateShapeHandler = require('diagram-js/lib/features/modeling/cmd/CreateSha CreateConnectionHandler = require('diagram-js/lib/features/modeling/cmd/CreateConnectionHandler'), DeleteConnectionHandler = require('diagram-js/lib/features/modeling/cmd/DeleteConnectionHandler'), MoveConnectionHandler = require('diagram-js/lib/features/modeling/cmd/MoveConnectionHandler'), - MoveConnectionsHandler = require('diagram-js/lib/features/modeling/cmd/MoveConnectionsHandler'), LayoutConnectionHandler = require('diagram-js/lib/features/modeling/cmd/LayoutConnectionHandler'); @@ -52,7 +51,6 @@ Modeling.prototype.registerHandlers = function(commandStack) { commandStack.registerHandler('connection.create', CreateConnectionHandler); commandStack.registerHandler('connection.delete', DeleteConnectionHandler); commandStack.registerHandler('connection.move', MoveConnectionHandler); - commandStack.registerHandler('connections.move', MoveConnectionsHandler); commandStack.registerHandler('connection.layout', LayoutConnectionHandler); }; diff --git a/lib/features/modeling/behavior/Drop.js b/lib/features/modeling/behavior/Drop.js new file mode 100644 index 00000000..8e800deb --- /dev/null +++ b/lib/features/modeling/behavior/Drop.js @@ -0,0 +1,30 @@ +var _ = require('lodash'); + + +function DropBehavior(eventBus, modeling) { + + // sequence flow handling + + eventBus.on([ + 'commandStack.shapes.move.postExecute' + ], function(e) { + + var context = e.context, + closure = context.closure, + allConnections = closure.allConnections, + allShapes = closure.allShapes; + + _.forEach(allConnections, function(c) { + + // remove sequence flows having source / target on different parents + if (c.businessObject.$instanceOf('bpmn:SequenceFlow') && c.source.parent !== c.target.parent) { + modeling.removeConnection(c); + } + }); + }); + +} + +DropBehavior.$inject = [ 'eventBus', 'modeling' ]; + +module.exports = DropBehavior; \ No newline at end of file diff --git a/lib/features/modeling/behavior/index.js b/lib/features/modeling/behavior/index.js new file mode 100644 index 00000000..bfaf8d95 --- /dev/null +++ b/lib/features/modeling/behavior/index.js @@ -0,0 +1,4 @@ +module.exports = { + __init__: [ 'dropBehavior' ], + dropBehavior: [ 'type', require('./Drop') ] +}; \ No newline at end of file diff --git a/lib/features/modeling/index.js b/lib/features/modeling/index.js index c9296b58..94db0b01 100644 --- a/lib/features/modeling/index.js +++ b/lib/features/modeling/index.js @@ -2,9 +2,10 @@ module.exports = { __init__: [ 'modeling', 'bpmnUpdater', 'labelSupport' ], __depends__: [ require('../label-editing'), + require('./rules'), + require('./behavior'), require('diagram-js/lib/command'), - require('diagram-js/lib/features/change-support'), - require('diagram-js/lib/features/drop') + require('diagram-js/lib/features/change-support') ], bpmnFactory: [ 'type', require('./BpmnFactory') ], bpmnUpdater: [ 'type', require('./BpmnUpdater') ], diff --git a/lib/features/modeling/rules/ModelingRules.js b/lib/features/modeling/rules/ModelingRules.js new file mode 100644 index 00000000..f4b8a8b9 --- /dev/null +++ b/lib/features/modeling/rules/ModelingRules.js @@ -0,0 +1,90 @@ +'use strict'; + +var _ = require('lodash'); + +var RuleProvider = require('diagram-js/lib/features/rules/RuleProvider'); + +function ModelingRules(eventBus) { + RuleProvider.call(this, eventBus); +} + +ModelingRules.$inject = [ 'eventBus' ]; + +module.exports = ModelingRules; + +ModelingRules.prototype = Object.create(RuleProvider.prototype); + + +ModelingRules.prototype.init = function() { + + // rules + + this.addRule('connection.create', function(context) { + + var source = context.source, + target = context.target; + + if (!source || source.labelTarget || !target || target.labelTarget) { + return null; + } + + return source.businessObject.$parent === target.businessObject.$parent && + source.businessObject.$instanceOf('bpmn:FlowNode') && + !source.businessObject.$instanceOf('bpmn:EndEvent') && + !target.businessObject.$instanceOf('bpmn:StartEvent') && + target.businessObject.$instanceOf('bpmn:FlowElement'); + }); + + + this.addRule('shape.resize', function(context) { + + var shape = context.shape, + newBounds = context.newBounds, + bo = shape.businessObject; + + if (!bo.$instanceOf('bpmn:SubProcess') || !bo.di.isExpanded) { + return false; + } + + if (newBounds) { + if (newBounds.width < 100 || newBounds.height < 80) { + return false; + } + } + }); + + + this.addRule('shapes.move', function(context) { + + var target = context.newParent, + shapes = context.shapes; + + // only move if they have the same parent + var sameParent = _.size(_.groupBy(shapes, function(s) { return s.parent && s.parent.id; })); + + if (!sameParent) { + return false; + } + + if (!target) { + return true; + } + + var targetBusinessObject = target.businessObject, + targetDi = targetBusinessObject.di; + + // allow to drop elements elements into sub processes + // unless they are participants or lanes themselves + + if (targetBusinessObject.$instanceOf('bpmn:SubProcess') && targetDi.isExpanded) { + + return shapes.every(function(shape) { + var bo = shape.businessObject; + return !(bo.$instanceOf('bpmn:Participant') || bo.$instanceOf('bpmn:Lane')); + }); + } else { + return false; + } + }); + +}; \ No newline at end of file diff --git a/lib/features/modeling/rules/index.js b/lib/features/modeling/rules/index.js new file mode 100644 index 00000000..42a0b6a3 --- /dev/null +++ b/lib/features/modeling/rules/index.js @@ -0,0 +1,4 @@ +module.exports = { + __init__: [ 'modelingRules' ], + modelingRules: [ 'type', require('./ModelingRules') ] +}; diff --git a/lib/features/resize/BpmnMinimumSizes.js b/lib/features/resize/BpmnMinimumSizes.js deleted file mode 100644 index 18757371..00000000 --- a/lib/features/resize/BpmnMinimumSizes.js +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - 'bpmn:Task': { - 'height': 40, - 'width': 40 - }, - 'bpmn:SubProcess': { - 'resolver': function(element) { - - var isExpanded = element.businessObject.di.isExpanded; - - if (isExpanded) { - return { - 'height': 100, - 'width': 100 - }; - } else { - return { - 'height': 40, - 'width': 40 - }; - } - } - } -}; diff --git a/lib/features/resize/BpmnResizableElements.json b/lib/features/resize/BpmnResizableElements.json deleted file mode 100644 index cf845eb6..00000000 --- a/lib/features/resize/BpmnResizableElements.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "elements": [ - "bpmn:Task", - "bpmn:SubProcess" - ] -} diff --git a/lib/features/resize/BpmnResizeHandler.js b/lib/features/resize/BpmnResizeHandler.js deleted file mode 100644 index 8e8183c1..00000000 --- a/lib/features/resize/BpmnResizeHandler.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -var _ = require('lodash'); - -var resizableElements = require('./BpmnResizableElements.json').elements, - minimumSize = require('./BpmnMinimumSizes.js'); - - -function BpmnResizeHandler(eventBus, resize) { - - var isResizeAllowed = function isResizeAllowed(element) { - var isAllowed = _.contains(resizableElements, element.type); - - if (isAllowed) { - return true; - } else { - return false; - } - }; - - var getMinimumSize = function getMinimumSize(element) { - var size = minimumSize[element.type]; - - if (!size) { - size = { - height: 30, - width: 30 - }; - } - - if (!!size.resolver) { - return size.resolver(element); - } else { - return size; - } - }; - - // Register Handler - eventBus.on('canvas.init', function() { - resize.registerResizableHandler(isResizeAllowed); - resize.registerMinimumSizeResolver(getMinimumSize); - }); -} - -module.exports = BpmnResizeHandler; - -BpmnResizeHandler.$inject = [ 'eventBus', 'resize' ]; diff --git a/lib/features/resize/index.js b/lib/features/resize/index.js deleted file mode 100644 index 6ec21321..00000000 --- a/lib/features/resize/index.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - __depends__: [ - require('diagram-js/lib/features/resize') - ], - __init__: [ 'bpmnResizeHandler' ], - bpmnResizeHandler: [ 'type', require('./BpmnResizeHandler') ] -}; diff --git a/lib/features/rules/BpmnRules.js b/lib/features/rules/BpmnRules.js deleted file mode 100644 index 413b78aa..00000000 --- a/lib/features/rules/BpmnRules.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -var _ = require('lodash'); - -var DropAction = require('./DropRules'), - ConnectHandler = require('./ConnectRules'); - - -function BpmnRules(rules) { - rules.registerRule('drop', 'validateSubProcess', DropAction.validateSubProcess); -} - -BpmnRules.$inject = [ 'rules' ]; - -module.exports = BpmnRules; diff --git a/lib/features/rules/ConnectRules.js b/lib/features/rules/ConnectRules.js deleted file mode 100644 index 5ac460c7..00000000 --- a/lib/features/rules/ConnectRules.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -var _ = require('lodash'); - - -function can(context) { - - var source = context.source, - target = context.target; - - if (source.labelTarget || target.labelTarget) { - return null; - } - - return source.businessObject.$parent === target.businessObject.$parent && - source.businessObject.$instanceOf('bpmn:FlowNode') && - !source.businessObject.$instanceOf('bpmn:EndEvent') && - !target.businessObject.$instanceOf('bpmn:StartEvent') && - target.businessObject.$instanceOf('bpmn:FlowElement'); -} - -module.exports.can = can; diff --git a/lib/features/rules/DropRules.js b/lib/features/rules/DropRules.js deleted file mode 100644 index 2c373593..00000000 --- a/lib/features/rules/DropRules.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -var _ = require('lodash'); - -function validateSubProcess(context) { - - var target = context.target, - shapes = context.shape, - di = target.businessObject.di; - - // can't drop anything to a collapsed subprocess - if (!di.isExpanded) { - return false; - } - - // Elements that can't be dropped to a subprocess - _.forEach(shapes, function(shape) { - if (_.contains(['bpmn:Participant', 'bpmn:Lane'], shape.type)) { - return false; - } - }); - - return true; -} - -module.exports.validateSubProcess = validateSubProcess; diff --git a/lib/features/rules/index.js b/lib/features/rules/index.js deleted file mode 100644 index 2061c19d..00000000 --- a/lib/features/rules/index.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -module.exports = { - __init__: [ 'bpmnRules' ], - bpmnRules: [ 'type', require('./BpmnRules') ] -}; diff --git a/test/spec/features/drop/DropSpec.js b/test/spec/features/modeling/DropSpec.js similarity index 80% rename from test/spec/features/drop/DropSpec.js rename to test/spec/features/modeling/DropSpec.js index 56d2da66..519a6bd4 100644 --- a/test/spec/features/drop/DropSpec.js +++ b/test/spec/features/modeling/DropSpec.js @@ -10,29 +10,27 @@ var _ = require('lodash'); var fs = require('fs'); var modelingModule = require('../../../../lib/features/modeling'), - dropModule = require('../../../../lib/features/drop'), coreModule = require('../../../../lib/core'); -describe('features/drop ', function() { +describe('features/move - drop', function() { beforeEach(Matchers.addDeepEquals); - var diagramXML = fs.readFileSync('test/fixtures/bpmn/features/drop/drop.bpmn', 'utf-8'); - var diagramXML2 = fs.readFileSync('test/fixtures/bpmn/features/drop/recursive-task.bpmn', 'utf-8'); + var diagramXML = fs.readFileSync('test/fixtures/bpmn/features/drop/drop.bpmn', 'utf8'); + var diagramXML2 = fs.readFileSync('test/fixtures/bpmn/features/drop/recursive-task.bpmn', 'utf8'); - var testModules = [ coreModule, modelingModule, dropModule ]; + var testModules = [ coreModule, modelingModule ]; describe('elements', function() { beforeEach(bootstrapModeler(diagramXML, { modules: testModules })); - it('should update parent', inject(function(elementRegistry, modeling, drop) { + it('should update parent', inject(function(elementRegistry, modeling) { // given - var task_1 = elementRegistry.get('ID_Task_1'), parent = elementRegistry.get('ID_SubProcess_1'); @@ -44,12 +42,13 @@ describe('features/drop ', function() { expect(task_1.businessObject.$parent).toBe(parent.businessObject); })); - it('should update parents', inject(function(elementRegistry, modeling, drop) { + + it('should update parents', inject(function(elementRegistry, modeling) { // given - var task_1 = elementRegistry.getById('ID_Task_1'), + var task_1 = elementRegistry.get('ID_Task_1'), task_2 = elementRegistry.get('ID_Task_2'), - parent = elementRegistry.getById('ID_SubProcess_1'); + parent = elementRegistry.get('ID_SubProcess_1'); // when modeling.moveShapes([ task_1, task_2 ], { x: 0, y: 200 }, parent); @@ -60,17 +59,17 @@ describe('features/drop ', function() { expect(task_2.parent).toBe(parent); expect(task_2.businessObject.$parent).toBe(parent.businessObject); })); + }); - - describe('Sequence Flows', function() { + describe('connection handling', function() { beforeEach(bootstrapModeler(diagramXML, { modules: testModules })); it('should remove flow if target and source have different parents', - inject(function(elementRegistry, modeling, drop) { + inject(function(elementRegistry, modeling) { // given var task_1 = elementRegistry.get('ID_Task_1'), @@ -78,8 +77,7 @@ describe('features/drop ', function() { flow = elementRegistry.get('ID_Sequenceflow_1'); // when - modeling.moveShape(task_1, { x: 0, y: 200 }, parent); - + modeling.moveShapes([ task_1 ], { x: 0, y: 200 }, parent); // then expect(flow.parent).toBe(null); @@ -87,8 +85,7 @@ describe('features/drop ', function() { })); - it('should update flow parent if target and source have same parents', - inject(function(elementRegistry, modeling, drop) { + it('should update flow parent if target and source have same parents', inject(function(elementRegistry, modeling) { // given var task_1 = elementRegistry.get('ID_Task_1'), @@ -97,28 +94,29 @@ describe('features/drop ', function() { flow = elementRegistry.get('ID_Sequenceflow_1'); // when - modeling.moveShapes([task_1, task_2], { x: 0, y: 250 }, parent); + modeling.moveShapes([ task_1, task_2 ], { x: 0, y: 250 }, parent); // then expect(flow.parent).toBe(parent); expect(flow.businessObject.$parent).toBe(parent.businessObject); })); + }); + describe('recursion', function() { beforeEach(bootstrapModeler(diagramXML2, { modules: testModules })); - it('should update parent', inject(function(elementRegistry, modeling, drop) { + it('should update parent', inject(function(elementRegistry, modeling) { // given - var task_1 = elementRegistry.get('ID_task_1'), parent = elementRegistry.get('ID_subprocess_1'), sequenceFlow = elementRegistry.get('ID_sequenceflow_1'); // when - modeling.moveShape(task_1, { x: 0, y: 200 }, parent); + modeling.moveShapes([ task_1 ], { x: 0, y: 200 }, parent); // then expect(task_1.parent).toBe(parent); @@ -127,6 +125,7 @@ describe('features/drop ', function() { expect(sequenceFlow.parent).toBe(parent); expect(sequenceFlow.businessObject.$parent).toBe(parent.businessObject); })); + }); });