feat(bpmn): make available BpmnRegistry in renderer
This commit upgrades the code base to the latest diagram-js changes and adds a component called BpmnRegistry that can be used to retrieve a certain BPMN/DI element from a shape/connection id. Related to #19
This commit is contained in:
parent
4c0c286ae7
commit
02313e6c1b
14
lib/Model.js
14
lib/Model.js
|
@ -24,8 +24,22 @@ function instance() {
|
||||||
return INSTANCE;
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a BPMN model tree from a given xml string.
|
||||||
|
*
|
||||||
|
* @param {String} xmlStr
|
||||||
|
* @param {String} [typeName] name of the root element, defaults to 'bpmn:Definitions'
|
||||||
|
* @param {Object} [options] to pass to the underlying reader
|
||||||
|
* @param {Function} callback the callback that is invoked with (err, result, parseContext)
|
||||||
|
*/
|
||||||
function fromXML(xmlStr, typeName, options, callback) {
|
function fromXML(xmlStr, typeName, options, callback) {
|
||||||
|
|
||||||
|
if (!_.isString(typeName)) {
|
||||||
|
callback = options;
|
||||||
|
options = typeName;
|
||||||
|
typeName = 'bpmn:Definitions';
|
||||||
|
}
|
||||||
|
|
||||||
if (_.isFunction(options)) {
|
if (_.isFunction(options)) {
|
||||||
callback = options;
|
callback = options;
|
||||||
options = {};
|
options = {};
|
||||||
|
|
|
@ -3,10 +3,12 @@ var Diagram = require('diagram-js');
|
||||||
var bpmnModule = require('./di').defaultModule,
|
var bpmnModule = require('./di').defaultModule,
|
||||||
Viewer = require('./Viewer');
|
Viewer = require('./Viewer');
|
||||||
|
|
||||||
|
require('./core/BpmnRegistry');
|
||||||
|
|
||||||
require('./draw/BpmnRenderer');
|
require('./draw/BpmnRenderer');
|
||||||
|
|
||||||
require('diagram-js/src/features/DragUI');
|
require('diagram-js/lib/features/dnd/Visuals');
|
||||||
require('diagram-js/src/features/SelectionUI');
|
require('diagram-js/lib/features/selection/Visuals');
|
||||||
|
|
||||||
|
|
||||||
function Modeler(container) {
|
function Modeler(container) {
|
||||||
|
@ -20,7 +22,7 @@ Modeler.prototype.createDiagram = function() {
|
||||||
return new Diagram({
|
return new Diagram({
|
||||||
canvas: { container: this.container },
|
canvas: { container: this.container },
|
||||||
modules: [ bpmnModule ],
|
modules: [ bpmnModule ],
|
||||||
components: [ 'selectionUI', 'dragUI' ]
|
components: [ 'selectionVisuals', 'dragVisuals', 'bpmnRegistry']
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
function failSafeAsync(fn) {
|
||||||
|
|
||||||
|
return function() {
|
||||||
|
|
||||||
|
var args = Array.prototype.slice.call(arguments);
|
||||||
|
|
||||||
|
var done = args[args.length - 1];
|
||||||
|
if (!done || !_.isFunction(done)) {
|
||||||
|
done = function(e) {
|
||||||
|
throw e;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
fn.apply(this, args);
|
||||||
|
} catch (e) {
|
||||||
|
done(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.failSafeAsync = failSafeAsync;
|
|
@ -1,11 +1,12 @@
|
||||||
var Diagram = require('diagram-js');
|
var Diagram = require('diagram-js');
|
||||||
|
|
||||||
var Importer = require('./import/Importer'),
|
var Importer = require('./import/Importer'),
|
||||||
Model = require('./Model');
|
Model = require('./Model'),
|
||||||
|
failSafeAsync = require('./Util').failSafeAsync;
|
||||||
|
|
||||||
|
|
||||||
function initListeners(diagram, listeners) {
|
function initListeners(diagram, listeners) {
|
||||||
var events = diagram.get('events');
|
var events = diagram.get('eventBus');
|
||||||
|
|
||||||
listeners.forEach(function(l) {
|
listeners.forEach(function(l) {
|
||||||
events.on(l.event, l.handler);
|
events.on(l.event, l.handler);
|
||||||
|
@ -72,7 +73,7 @@ Viewer.prototype.saveSVG = function(options, done) {
|
||||||
done(null, svg);
|
done(null, svg);
|
||||||
};
|
};
|
||||||
|
|
||||||
Viewer.prototype.importDefinitions = function(definitions, done) {
|
Viewer.prototype.importDefinitions = failSafeAsync(function(definitions, done) {
|
||||||
|
|
||||||
if (this.diagram) {
|
if (this.diagram) {
|
||||||
this.clear();
|
this.clear();
|
||||||
|
@ -85,7 +86,7 @@ Viewer.prototype.importDefinitions = function(definitions, done) {
|
||||||
this.definitions = definitions;
|
this.definitions = definitions;
|
||||||
|
|
||||||
Importer.importBpmnDiagram(this.diagram, definitions, done);
|
Importer.importBpmnDiagram(this.diagram, definitions, done);
|
||||||
};
|
});
|
||||||
|
|
||||||
Viewer.prototype.createDiagram = function() {
|
Viewer.prototype.createDiagram = function() {
|
||||||
return new Diagram({ canvas: { container: this.container }});
|
return new Diagram({ canvas: { container: this.container }});
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
var bpmnModule = require('../di').defaultModule;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class
|
||||||
|
*
|
||||||
|
* A registry that keeps track of bpmn semantic / di elements and the
|
||||||
|
* corresponding shapes.
|
||||||
|
*
|
||||||
|
* @param {EventBus} events
|
||||||
|
* @param {ElementRegistry} elementRegistry
|
||||||
|
*/
|
||||||
|
function BpmnRegistry(events, elementRegistry) {
|
||||||
|
|
||||||
|
var elements = {
|
||||||
|
di: {},
|
||||||
|
semantic: {},
|
||||||
|
diagramElement: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
events.on('bpmn.element.add', function(e) {
|
||||||
|
var semantic = e.semantic,
|
||||||
|
id = semantic.id;
|
||||||
|
|
||||||
|
elements.di[id] = e.di;
|
||||||
|
elements.semantic[id] = e.semantic;
|
||||||
|
elements.diagramElement[id] = e.diagramElement;
|
||||||
|
});
|
||||||
|
|
||||||
|
events.on('bpmn.element.removed', function(e) {
|
||||||
|
var semantic = e.semantic,
|
||||||
|
id = semantic.id;
|
||||||
|
|
||||||
|
delete elements.di[id];
|
||||||
|
delete elements.semantic[id];
|
||||||
|
delete elements.diagramElement[id];
|
||||||
|
});
|
||||||
|
|
||||||
|
function get(type) {
|
||||||
|
var collection = elements[type];
|
||||||
|
|
||||||
|
return function(id) {
|
||||||
|
return collection[id];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// API
|
||||||
|
this.getSemantic = get('semantic');
|
||||||
|
this.getDi = get('di');
|
||||||
|
this.getDiagramElement = get('diagramElement');
|
||||||
|
}
|
||||||
|
|
||||||
|
bpmnModule.type('bpmnRegistry', [ 'eventBus', 'elementRegistry', BpmnRegistry ]);
|
||||||
|
|
||||||
|
module.exports = BpmnRegistry;
|
|
@ -1,14 +1,14 @@
|
||||||
var bpmnModule = require('../di').defaultModule;
|
var bpmnModule = require('../di').defaultModule;
|
||||||
|
|
||||||
require('diagram-js/src/core/Events');
|
require('diagram-js/lib/core/EventBus');
|
||||||
require('diagram-js/src/draw/Styles');
|
require('diagram-js/lib/draw/Styles');
|
||||||
|
|
||||||
var DefaultRenderer = require('diagram-js/src/draw/Renderer');
|
var DefaultRenderer = require('diagram-js/lib/draw/Renderer');
|
||||||
|
|
||||||
|
|
||||||
var flattenPoints = DefaultRenderer.flattenPoints;
|
var flattenPoints = DefaultRenderer.flattenPoints;
|
||||||
|
|
||||||
function BpmnRenderer(events, styles) {
|
function BpmnRenderer(events, styles, bpmnRegistry) {
|
||||||
|
|
||||||
DefaultRenderer.apply(this, [ events, styles ]);
|
DefaultRenderer.apply(this, [ events, styles ]);
|
||||||
|
|
||||||
|
@ -394,6 +394,6 @@ function BpmnRenderer(events, styles) {
|
||||||
BpmnRenderer.prototype = Object.create(DefaultRenderer.prototype);
|
BpmnRenderer.prototype = Object.create(DefaultRenderer.prototype);
|
||||||
|
|
||||||
|
|
||||||
bpmnModule.type('renderer', [ 'events', 'styles', BpmnRenderer ]);
|
bpmnModule.type('renderer', [ 'eventBus', 'styles', 'bpmnRegistry', BpmnRenderer ]);
|
||||||
|
|
||||||
module.exports = BpmnRenderer;
|
module.exports = BpmnRenderer;
|
|
@ -1,12 +1,12 @@
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
|
|
||||||
var BpmnTreeWalker = require('./BpmnTreeWalker');
|
var BpmnTreeWalker = require('./BpmnTreeWalker'),
|
||||||
|
Util = require('../Util');
|
||||||
|
|
||||||
function importBpmnDiagram(diagram, definitions, done) {
|
function importBpmnDiagram(diagram, definitions, done) {
|
||||||
|
|
||||||
var canvas = diagram.get('canvas');
|
var canvas = diagram.get('canvas');
|
||||||
|
var events = diagram.get('eventBus');
|
||||||
var shapes = {};
|
|
||||||
|
|
||||||
var visitor = {
|
var visitor = {
|
||||||
|
|
||||||
|
@ -14,6 +14,12 @@ function importBpmnDiagram(diagram, definitions, done) {
|
||||||
|
|
||||||
var shape;
|
var shape;
|
||||||
|
|
||||||
|
function fire(type, shape) {
|
||||||
|
events.fire('bpmn.element.' + type, {
|
||||||
|
semantic: element, di: di, diagramElement: shape
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (di.$type === 'bpmndi:BPMNShape') {
|
if (di.$type === 'bpmndi:BPMNShape') {
|
||||||
var bounds = di.bounds;
|
var bounds = di.bounds;
|
||||||
|
|
||||||
|
@ -24,6 +30,7 @@ function importBpmnDiagram(diagram, definitions, done) {
|
||||||
parent: parent
|
parent: parent
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fire('add', shape);
|
||||||
canvas.addShape(shape);
|
canvas.addShape(shape);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -32,10 +39,12 @@ function importBpmnDiagram(diagram, definitions, done) {
|
||||||
});
|
});
|
||||||
|
|
||||||
shape = { id: element.id, type: element.$type, waypoints: waypoints };
|
shape = { id: element.id, type: element.$type, waypoints: waypoints };
|
||||||
|
|
||||||
|
fire('add', shape);
|
||||||
canvas.addConnection(shape);
|
canvas.addConnection(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
shapes[element.id] = shape;
|
fire('added', shape);
|
||||||
|
|
||||||
return shape;
|
return shape;
|
||||||
},
|
},
|
||||||
|
@ -46,10 +55,9 @@ function importBpmnDiagram(diagram, definitions, done) {
|
||||||
};
|
};
|
||||||
|
|
||||||
var walker = new BpmnTreeWalker(visitor);
|
var walker = new BpmnTreeWalker(visitor);
|
||||||
|
|
||||||
walker.handleDefinitions(definitions);
|
walker.handleDefinitions(definitions);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.importBpmnDiagram = importBpmnDiagram;
|
module.exports.importBpmnDiagram = Util.failSafeAsync(importBpmnDiagram);
|
|
@ -0,0 +1,71 @@
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
var BpmnModel = require('../../../lib/Model'),
|
||||||
|
Modeler = require('../../../lib/Modeler');
|
||||||
|
|
||||||
|
var Matchers = require('../Matchers');
|
||||||
|
|
||||||
|
describe('Modeler', function() {
|
||||||
|
|
||||||
|
var bpmnModel = BpmnModel.instance();
|
||||||
|
|
||||||
|
function read(xml, opts, callback) {
|
||||||
|
return BpmnModel.fromXML(xml, 'bpmn:Definitions', opts, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var container;
|
||||||
|
|
||||||
|
|
||||||
|
beforeEach(Matchers.add);
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
container = document.createElement('div');
|
||||||
|
document.getElementsByTagName('body')[0].appendChild(container);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
container.parentNode.removeChild(container);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should import simple process', function(done) {
|
||||||
|
|
||||||
|
var xml = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf8');
|
||||||
|
|
||||||
|
var renderer = new Modeler(container);
|
||||||
|
|
||||||
|
renderer.importXML(xml, function(err) {
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should import empty definitions', function(done) {
|
||||||
|
|
||||||
|
var xml = fs.readFileSync('test/fixtures/bpmn/empty-definitions.bpmn', 'utf8');
|
||||||
|
|
||||||
|
var renderer = new Modeler(container);
|
||||||
|
|
||||||
|
renderer.importXML(xml, function(err) {
|
||||||
|
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should handle errors', function(done) {
|
||||||
|
|
||||||
|
var xml = 'invalid stuff';
|
||||||
|
|
||||||
|
var renderer = new Modeler(container);
|
||||||
|
|
||||||
|
renderer.importXML(xml, function(err) {
|
||||||
|
|
||||||
|
expect(err).toBeDefined();
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -5,7 +5,7 @@ var BpmnModel = require('../../../lib/Model'),
|
||||||
|
|
||||||
var Matchers = require('../Matchers');
|
var Matchers = require('../Matchers');
|
||||||
|
|
||||||
describe('Importer', function() {
|
describe('Viewer', function() {
|
||||||
|
|
||||||
var bpmnModel = BpmnModel.instance();
|
var bpmnModel = BpmnModel.instance();
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
var fs = require('fs'),
|
||||||
|
Diagram = require('diagram-js/lib/Diagram');
|
||||||
|
|
||||||
|
var BpmnModel = require('../../../../lib/Model');
|
||||||
|
var Importer = require('../../../../lib/import/Importer');
|
||||||
|
|
||||||
|
var bpmnModule = require('../../../../lib/di').defaultModule;
|
||||||
|
|
||||||
|
require('../../../../lib/core/BpmnRegistry');
|
||||||
|
require('../../../../lib/draw/BpmnRenderer');
|
||||||
|
|
||||||
|
var Matchers = require('../../Matchers');
|
||||||
|
|
||||||
|
describe('import/Importer', function() {
|
||||||
|
|
||||||
|
var bpmnModel = BpmnModel.instance();
|
||||||
|
|
||||||
|
function read(xml, opts, callback) {
|
||||||
|
return BpmnModel.fromXML(xml, 'bpmn:Definitions', opts, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
var container;
|
||||||
|
|
||||||
|
|
||||||
|
beforeEach(Matchers.add);
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
container = document.createElement('div');
|
||||||
|
document.getElementsByTagName('body')[0].appendChild(container);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
container.parentNode.removeChild(container);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function createDiagram() {
|
||||||
|
return new Diagram({
|
||||||
|
canvas: { container: container },
|
||||||
|
modules: [ bpmnModule ],
|
||||||
|
components: [ 'bpmnRegistry']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should fire bpmn.element.add during import', function(done) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var xml = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf8');
|
||||||
|
|
||||||
|
var diagram = createDiagram();
|
||||||
|
|
||||||
|
var events = [];
|
||||||
|
|
||||||
|
// log events
|
||||||
|
diagram.get('eventBus').on('bpmn.element.add', function(e) {
|
||||||
|
events.push({ type: 'add', semantic: e.semantic.id, di: e.di.id, diagramElement: e.diagramElement.id });
|
||||||
|
});
|
||||||
|
|
||||||
|
BpmnModel.fromXML(xml, function(err, definitions) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
Importer.importBpmnDiagram(diagram, definitions, function(err) {
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(events).toEqual([
|
||||||
|
{ type: 'add', semantic: 'SubProcess_1', di: '_BPMNShape_SubProcess_2', diagramElement: 'SubProcess_1' },
|
||||||
|
{ type: 'add', semantic: 'StartEvent_1', di: '_BPMNShape_StartEvent_2', diagramElement: 'StartEvent_1' },
|
||||||
|
{ type: 'add', semantic: 'Task_1', di: '_BPMNShape_Task_2', diagramElement: 'Task_1' },
|
||||||
|
{ type: 'add', semantic: 'SequenceFlow_1', di: 'BPMNEdge_SequenceFlow_1', diagramElement: 'SequenceFlow_1' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in New Issue