parent
5185c55f68
commit
4fe5bbc0f5
|
@ -0,0 +1,91 @@
|
|||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
|
||||
var BpmnModdle = require('bpmn-moddle');
|
||||
|
||||
|
||||
|
||||
function BpmnFactory() {
|
||||
this._model = BpmnModdle.instance();
|
||||
this._uuid = 1;
|
||||
}
|
||||
|
||||
BpmnFactory.$inject = [ ];
|
||||
|
||||
|
||||
BpmnFactory.prototype._ensureId = function(element) {
|
||||
if (element.id === undefined) {
|
||||
element.id = '' + (++this._uuid);
|
||||
}
|
||||
};
|
||||
|
||||
BpmnFactory.prototype.create = function(type, attrs) {
|
||||
var element = this._model.create(type, attrs);
|
||||
|
||||
this._ensureId(element);
|
||||
|
||||
return element;
|
||||
};
|
||||
|
||||
BpmnFactory.prototype.createDiShape = function(semantic, position, attrs) {
|
||||
|
||||
position = position || { x: 0, y: 0 };
|
||||
|
||||
var bounds;
|
||||
|
||||
if (semantic.$instanceOf('bpmn:Task')) {
|
||||
bounds = { width: 100, height: 80 };
|
||||
} else {
|
||||
bounds = { width: 50, height: 50 };
|
||||
}
|
||||
|
||||
_.extend(bounds, {
|
||||
x: (position.x || 0) - bounds.width / 2,
|
||||
y: (position.y || 0) - bounds.height / 2
|
||||
});
|
||||
|
||||
return this.create('bpmndi:BPMNShape', _.extend({
|
||||
bpmnElement: semantic,
|
||||
bounds: this.createDiBounds(bounds)
|
||||
}, attrs));
|
||||
};
|
||||
|
||||
BpmnFactory.prototype.createDiBounds = function(bounds) {
|
||||
return this.create('dc:Bounds', bounds);
|
||||
};
|
||||
|
||||
BpmnFactory.prototype.createDiWaypoint = function(point) {
|
||||
return this.create('dc:Point', point);
|
||||
};
|
||||
|
||||
BpmnFactory.prototype.createDiEdge = function(sequenceFlow, points, attrs) {
|
||||
|
||||
var sourceDi = sequenceFlow.sourceRef.di,
|
||||
targetDi = sequenceFlow.targetRef.di;
|
||||
|
||||
var waypoints = _.map(points, function(pos) {
|
||||
return this.createDiWaypoint(pos);
|
||||
}, this);
|
||||
|
||||
return this.create('bpmndi:BPMNEdge', _.extend({
|
||||
bpmnElement: sequenceFlow,
|
||||
waypoint: waypoints
|
||||
}, attrs));
|
||||
};
|
||||
|
||||
BpmnFactory.prototype.createSequenceFlow = function(source, target, attrs) {
|
||||
|
||||
var sequenceFlow = this.create('bpmn:SequenceFlow', _.extend({
|
||||
sourceRef: source,
|
||||
targetRef: target
|
||||
}, attrs));
|
||||
|
||||
source.get('outgoing').push(sequenceFlow);
|
||||
target.get('incoming').push(sequenceFlow);
|
||||
|
||||
return sequenceFlow;
|
||||
};
|
||||
|
||||
|
||||
module.exports = BpmnFactory;
|
|
@ -0,0 +1,37 @@
|
|||
'use strict';
|
||||
|
||||
var AppendFlowNodeHandler = require('./cmd/AppendFlowNodeHandler');
|
||||
|
||||
/**
|
||||
* BPMN 2.0 modeling features activator
|
||||
*
|
||||
* @param {CommandStack} commandStack
|
||||
*/
|
||||
function BpmnModeling(commandStack) {
|
||||
commandStack.registerHandler('shape.appendNode', AppendFlowNodeHandler);
|
||||
this._commandStack = commandStack;
|
||||
}
|
||||
|
||||
BpmnModeling.$inject = [ 'commandStack' ];
|
||||
|
||||
|
||||
/**
|
||||
* Append a flow node to the element with the given source
|
||||
* at the specified position.
|
||||
*/
|
||||
BpmnModeling.prototype.appendFlowNode = function(source, parent, type, position) {
|
||||
|
||||
var context = {
|
||||
source: source,
|
||||
type: type,
|
||||
parent: parent,
|
||||
position: position
|
||||
};
|
||||
|
||||
this._commandStack.execute('shape.appendNode', context);
|
||||
|
||||
return context.target;
|
||||
};
|
||||
|
||||
|
||||
module.exports = BpmnModeling;
|
|
@ -0,0 +1,15 @@
|
|||
'use strict';
|
||||
|
||||
var getMidPoint = module.exports.getMidPoint = function(bounds) {
|
||||
return {
|
||||
x: bounds.x + bounds.width / 2,
|
||||
y: bounds.y + bounds.height / 2
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.getDirectConnectionPoints = function(boundsA, boundsB) {
|
||||
return [
|
||||
getMidPoint(boundsA),
|
||||
getMidPoint(boundsB)
|
||||
];
|
||||
};
|
|
@ -0,0 +1,142 @@
|
|||
'use strict';
|
||||
|
||||
var LayoutUtil = require('../LayoutUtil');
|
||||
|
||||
var AppendShapeHandler = require('diagram-js/lib/features/modeling/cmd/AppendShapeHandler');
|
||||
|
||||
var Refs = require('object-refs');
|
||||
|
||||
var diRefs = new Refs({ name: 'bpmnElement', enumerable: true }, { name: 'di' });
|
||||
|
||||
|
||||
function AppendFlowNodeHandler(canvas, bpmnFactory, bpmnImporter) {
|
||||
AppendShapeHandler.call(this);
|
||||
|
||||
this._bpmnImporter = bpmnImporter;
|
||||
this._bpmnFactory = bpmnFactory;
|
||||
|
||||
this._canvas = canvas;
|
||||
}
|
||||
|
||||
AppendFlowNodeHandler.prototype = Object.create(AppendShapeHandler.prototype);
|
||||
|
||||
AppendFlowNodeHandler.$inject = [ 'canvas', 'bpmnFactory', 'bpmnImporter' ];
|
||||
|
||||
|
||||
AppendFlowNodeHandler.prototype.createShape = function(source, position, parent, context) {
|
||||
|
||||
var sourceSemantic = source.businessObject,
|
||||
parentSemantic = parent.businessObject;
|
||||
|
||||
var target = context.target,
|
||||
targetSemantic,
|
||||
targetDi;
|
||||
|
||||
// create semantic
|
||||
targetSemantic = this._bpmnFactory.create(context.type, {
|
||||
id: target && target.businessObject.id
|
||||
});
|
||||
|
||||
// add to model
|
||||
parentSemantic.get('flowElements').push(targetSemantic);
|
||||
targetSemantic.$parent = parentSemantic;
|
||||
|
||||
// create di
|
||||
targetDi = this._bpmnFactory.createDiShape(targetSemantic, position, {
|
||||
id: targetSemantic.id + '_di'
|
||||
});
|
||||
|
||||
diRefs.bind(targetSemantic, 'di');
|
||||
targetSemantic.di = targetDi;
|
||||
|
||||
// add to model
|
||||
sourceSemantic.di.$parent.get('planeElement').push(targetDi);
|
||||
targetDi.$parent = sourceSemantic.di.$parent;
|
||||
|
||||
return this._bpmnImporter.add(targetSemantic, parent);
|
||||
};
|
||||
|
||||
|
||||
AppendFlowNodeHandler.prototype.createConnection = function(source, target, parent, context) {
|
||||
|
||||
var sourceSemantic = source.businessObject,
|
||||
targetSemantic = target.businessObject,
|
||||
parentSemantic = parent.businessObject;
|
||||
|
||||
var flowSemantic,
|
||||
flowDi;
|
||||
|
||||
var connection = context.connection;
|
||||
|
||||
// create semantic
|
||||
flowSemantic = this._bpmnFactory.createSequenceFlow(sourceSemantic, targetSemantic, {
|
||||
id: connection && connection.businessObject.id
|
||||
});
|
||||
|
||||
// add to model
|
||||
parentSemantic.get('flowElements').push(flowSemantic);
|
||||
flowSemantic.$parent = parentSemantic;
|
||||
|
||||
// create di
|
||||
var waypoints = LayoutUtil.getDirectConnectionPoints(sourceSemantic.di.bounds, targetSemantic.di.bounds);
|
||||
|
||||
flowDi = this._bpmnFactory.createDiEdge(flowSemantic, waypoints, {
|
||||
id: flowSemantic.id + '_di'
|
||||
});
|
||||
|
||||
diRefs.bind(flowSemantic, 'di');
|
||||
flowSemantic.di = flowDi;
|
||||
|
||||
// add to model
|
||||
sourceSemantic.di.$parent.get('planeElement').push(flowDi);
|
||||
flowDi.$parent = sourceSemantic.di.$parent;
|
||||
|
||||
return this._bpmnImporter.add(flowSemantic, parent);
|
||||
};
|
||||
|
||||
|
||||
AppendFlowNodeHandler.prototype.removeShape = function(shape) {
|
||||
|
||||
var semantic = shape.businessObject,
|
||||
parentSemantic = semantic.$parent;
|
||||
|
||||
// remove semantic
|
||||
parentSemantic.get('flowElements').splice(parentSemantic.get('flowElements').indexOf(semantic), 1);
|
||||
semantic.$parent = null;
|
||||
|
||||
// remove di
|
||||
var di = semantic.di;
|
||||
di.$parent.get('planeElement').splice(di.$parent.get('planeElement').indexOf(di), 1);
|
||||
di.$parent = null;
|
||||
|
||||
// actual remove shape
|
||||
return this._canvas.removeShape(shape);
|
||||
};
|
||||
|
||||
|
||||
AppendFlowNodeHandler.prototype.removeConnection = function(connection) {
|
||||
|
||||
var semantic = connection.businessObject,
|
||||
parentSemantic = semantic.$parent;
|
||||
|
||||
// remove semantic
|
||||
parentSemantic.get('flowElements').splice(parentSemantic.get('flowElements').indexOf(semantic), 1);
|
||||
|
||||
// remove di
|
||||
var di = semantic.di;
|
||||
di.$parent.get('planeElement').splice(di.$parent.get('planeElement').indexOf(di), 1);
|
||||
di.$parent = null;
|
||||
|
||||
// remove refs in source / target
|
||||
semantic.sourceRef.outgoing.splice(semantic.sourceRef.outgoing.indexOf(semantic), 1);
|
||||
semantic.targetRef.incoming.splice(semantic.targetRef.incoming.indexOf(semantic), 1);
|
||||
|
||||
semantic.sourceRef = null;
|
||||
semantic.targetRef = null;
|
||||
semantic.$parent = null;
|
||||
|
||||
// actual remove connection
|
||||
return this._canvas.removeConnection(connection);
|
||||
};
|
||||
|
||||
module.exports = AppendFlowNodeHandler;
|
|
@ -0,0 +1,9 @@
|
|||
module.exports = {
|
||||
__init__: [ 'bpmnModeling' ],
|
||||
__depends__: [
|
||||
require('../../core'),
|
||||
require('diagram-js/lib/cmd')
|
||||
],
|
||||
bpmnFactory: [ 'type', require('./BpmnFactory') ],
|
||||
bpmnModeling: [ 'type', require('./BpmnModeling') ]
|
||||
};
|
|
@ -59,6 +59,7 @@
|
|||
"didi": "~0.0.4",
|
||||
"jquery": "~2.1.0",
|
||||
"jquery-mousewheel": "~3.1.11",
|
||||
"lodash": "~2.4.0"
|
||||
"lodash": "~2.4.0",
|
||||
"object-refs": "^0.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
'use strict';
|
||||
|
||||
var Matchers = require('../../../Matchers'),
|
||||
TestHelper = require('../../../TestHelper');
|
||||
|
||||
/* global bootstrapBpmnJS, inject */
|
||||
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
var bpmnFactoryModule = require('../../../../../lib/features/bpmn-modeling');
|
||||
|
||||
|
||||
xdescribe('features - bpmn-factory', function() {
|
||||
|
||||
beforeEach(Matchers.add);
|
||||
|
||||
|
||||
var diagramXML = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf-8');
|
||||
|
||||
var testModules = [ bpmnFactoryModule ];
|
||||
|
||||
beforeEach(bootstrapBpmnJS(diagramXML, { modules: testModules }));
|
||||
|
||||
|
||||
describe('create task', function() {
|
||||
|
||||
it('should create', inject(function(bpmnFactory) {
|
||||
var result = bpmnFactory.createNode('bpmn:Task');
|
||||
|
||||
expect(result.semantic.id).toBeDefined();
|
||||
expect(result.di.id).toBeDefined();
|
||||
|
||||
expect(result.di.bounds.width).toBe(100);
|
||||
expect(result.di.bounds.height).toBe(80);
|
||||
expect(result.di.bounds.x).toBe(-50);
|
||||
expect(result.di.bounds.y).toBe(-40);
|
||||
}));
|
||||
|
||||
|
||||
it('should create with position', inject(function(bpmnFactory) {
|
||||
|
||||
var result = bpmnFactory.createNode('bpmn:Task', { x: 100, y: 100 });
|
||||
|
||||
expect(result.semantic.id).toBeDefined();
|
||||
expect(result.di.id).toBeDefined();
|
||||
|
||||
expect(result.di.bounds.width).toBe(100);
|
||||
expect(result.di.bounds.height).toBe(80);
|
||||
expect(result.di.bounds.x).toBe(50);
|
||||
expect(result.di.bounds.y).toBe(60);
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,163 @@
|
|||
'use strict';
|
||||
|
||||
var Matchers = require('../../../Matchers'),
|
||||
TestHelper = require('../../../TestHelper');
|
||||
|
||||
/* global bootstrapBpmnJS, inject */
|
||||
|
||||
var _ = require('lodash');
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
var bpmnFactoryModule = require('../../../../../lib/features/bpmn-modeling'),
|
||||
bpmnDrawModule = require('../../../../../lib/draw');
|
||||
|
||||
|
||||
describe('features - bpmn-modeling', function() {
|
||||
|
||||
beforeEach(Matchers.add);
|
||||
|
||||
|
||||
var diagramXML = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf-8');
|
||||
|
||||
var testModules = [ bpmnFactoryModule, bpmnDrawModule ];
|
||||
|
||||
beforeEach(bootstrapBpmnJS(diagramXML, { modules: testModules }));
|
||||
|
||||
|
||||
describe('commands', function() {
|
||||
|
||||
|
||||
describe('shape.appendNode', function() {
|
||||
|
||||
it('should execute', inject(function(elementRegistry, bpmnModeling) {
|
||||
|
||||
// given
|
||||
var startEventShape = elementRegistry.getById('StartEvent_1');
|
||||
|
||||
// when
|
||||
var targetShape = bpmnModeling.appendFlowNode(startEventShape, null, 'bpmn:Task'),
|
||||
target = targetShape.businessObject;
|
||||
|
||||
// then
|
||||
expect(targetShape).toBeDefined();
|
||||
expect(target.$instanceOf('bpmn:Task')).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it('should create DI', inject(function(elementRegistry, bpmnModeling) {
|
||||
|
||||
// given
|
||||
var startEventShape = elementRegistry.getById('StartEvent_1');
|
||||
var subProcessShape = elementRegistry.getById('SubProcess_1');
|
||||
|
||||
var startEvent = startEventShape.businessObject,
|
||||
subProcess = subProcessShape.businessObject;
|
||||
|
||||
// when
|
||||
var targetShape = bpmnModeling.appendFlowNode(startEventShape, null, 'bpmn:Task'),
|
||||
target = targetShape.businessObject;
|
||||
|
||||
// then
|
||||
expect(target.di).toBeDefined();
|
||||
expect(target.di.$parent).toBe(startEvent.di.$parent);
|
||||
}));
|
||||
|
||||
|
||||
it('should add to parent (sub process)', inject(function(elementRegistry, bpmnModeling) {
|
||||
|
||||
// given
|
||||
var startEventShape = elementRegistry.getById('StartEvent_1');
|
||||
var subProcessShape = elementRegistry.getById('SubProcess_1');
|
||||
|
||||
var startEvent = startEventShape.businessObject,
|
||||
subProcess = subProcessShape.businessObject;
|
||||
|
||||
// when
|
||||
var targetShape = bpmnModeling.appendFlowNode(startEventShape, null, 'bpmn:Task'),
|
||||
target = targetShape.businessObject;
|
||||
|
||||
// then
|
||||
expect(subProcess.get('flowElements')).toContain(target);
|
||||
}));
|
||||
|
||||
|
||||
it('should add connection', inject(function(elementRegistry, bpmnModeling) {
|
||||
|
||||
// given
|
||||
var startEventShape = elementRegistry.getById('StartEvent_1');
|
||||
var subProcessShape = elementRegistry.getById('SubProcess_1');
|
||||
|
||||
var startEvent = startEventShape.businessObject,
|
||||
subProcess = subProcessShape.businessObject;
|
||||
|
||||
// when
|
||||
var targetShape = bpmnModeling.appendFlowNode(startEventShape, null, 'bpmn:Task'),
|
||||
target = targetShape.businessObject;
|
||||
|
||||
var connection = _.find(subProcess.get('flowElements'), function(e) {
|
||||
return e.sourceRef === startEvent && e.targetRef === target;
|
||||
});
|
||||
|
||||
// then
|
||||
expect(connection).toBeDefined();
|
||||
expect(connection.$instanceOf('bpmn:SequenceFlow')).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
describe('undo support', function() {
|
||||
|
||||
it('should undo add to parent', inject(function(elementRegistry, bpmnModeling, commandStack) {
|
||||
|
||||
// given
|
||||
var startEventShape = elementRegistry.getById('StartEvent_1');
|
||||
var subProcessShape = elementRegistry.getById('SubProcess_1');
|
||||
|
||||
var startEvent = startEventShape.businessObject,
|
||||
subProcess = subProcessShape.businessObject;
|
||||
|
||||
var targetShape = bpmnModeling.appendFlowNode(startEventShape, null, 'bpmn:Task'),
|
||||
target = targetShape.businessObject;
|
||||
|
||||
// when
|
||||
commandStack.undo();
|
||||
|
||||
// then
|
||||
expect(subProcess.get('flowElements')).not.toContain(target);
|
||||
expect(subProcess.di.$parent.get('planeElement')).not.toContain(target.di);
|
||||
}));
|
||||
|
||||
|
||||
it('should undo add connection', inject(function(elementRegistry, bpmnModeling, commandStack) {
|
||||
|
||||
// given
|
||||
var startEventShape = elementRegistry.getById('StartEvent_1');
|
||||
var subProcessShape = elementRegistry.getById('SubProcess_1');
|
||||
|
||||
var startEvent = startEventShape.businessObject,
|
||||
subProcess = subProcessShape.businessObject;
|
||||
|
||||
var targetShape = bpmnModeling.appendFlowNode(startEventShape, null, 'bpmn:Task'),
|
||||
target = targetShape.businessObject;
|
||||
|
||||
var connection = _.find(subProcess.get('flowElements'), function(e) {
|
||||
return e.sourceRef === startEvent && e.targetRef === target;
|
||||
});
|
||||
|
||||
// when
|
||||
commandStack.undo();
|
||||
|
||||
// then
|
||||
expect(connection.sourceRef).toBe(null);
|
||||
expect(connection.targetRef).toBe(null);
|
||||
expect(connection.$parent).toBe(null);
|
||||
expect(subProcess.di.$parent.get('planeElement')).not.toContain(connection.di);
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue