feat(import): allow users to hook into via events
This commit adds more life-cycle events users can plug into during xml parsing and rendering: * import.parse.start * import.parse.complete * import.render.start * import.render.complete * import.done Some other events had to go because of that, namely * import.start * import.(success|error) BREAKING CHANGE: * the event import.start got renamed to import.render.start * the events import.success and import.error got removed in favour of import.render.complete (passing err, warnings)
This commit is contained in:
parent
a5b8f379fc
commit
46d8abdd70
|
@ -101,23 +101,52 @@ var initialDiagram =
|
|||
*/
|
||||
function Modeler(options) {
|
||||
Viewer.call(this, options);
|
||||
|
||||
// hook ID collection into the modeler
|
||||
this.on('import.parse.complete', function(event) {
|
||||
if (!event.error) {
|
||||
this._collectIds(event.definitions, event.context);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
inherits(Modeler, Viewer);
|
||||
|
||||
module.exports = Modeler;
|
||||
|
||||
/**
|
||||
* Create a new diagram to start modeling.
|
||||
*
|
||||
* @param {Function} done
|
||||
*/
|
||||
Modeler.prototype.createDiagram = function(done) {
|
||||
return this.importXML(initialDiagram, done);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a moddle instance, attaching ids to it.
|
||||
*
|
||||
* @param {Object} options
|
||||
*/
|
||||
Modeler.prototype._createModdle = function(options) {
|
||||
var moddle = Viewer.prototype._createModdle.call(this, options);
|
||||
|
||||
// attach ids to moddle to be able to track
|
||||
// and validated ids in the BPMN 2.0 XML document
|
||||
// tree
|
||||
moddle.ids = new Ids([ 32, 36, 1 ]);
|
||||
|
||||
return moddle;
|
||||
};
|
||||
|
||||
Modeler.prototype._parsedXML = function(definitions, context) {
|
||||
/**
|
||||
* Collect ids processed during parsing of the
|
||||
* definitions object.
|
||||
*
|
||||
* @param {ModdleElement} definitions
|
||||
* @param {Context} context
|
||||
*/
|
||||
Modeler.prototype._collectIds = function(definitions, context) {
|
||||
|
||||
var moddle = definitions.$model,
|
||||
ids = moddle.ids,
|
||||
|
@ -167,7 +196,4 @@ Modeler.prototype._modelingModules = [
|
|||
Modeler.prototype._modules = [].concat(
|
||||
Modeler.prototype._modules,
|
||||
Modeler.prototype._interactionModules,
|
||||
Modeler.prototype._modelingModules);
|
||||
|
||||
|
||||
module.exports = Modeler;
|
||||
Modeler.prototype._modelingModules);
|
|
@ -126,11 +126,23 @@ module.exports = Viewer;
|
|||
|
||||
|
||||
/**
|
||||
* Import and render a BPMN 2.0 diagram.
|
||||
* Parse and render a BPMN 2.0 diagram.
|
||||
*
|
||||
* Once finished the viewer reports back the result to the
|
||||
* provided callback function with (err, warnings).
|
||||
*
|
||||
* ## Life-Cycle Events
|
||||
*
|
||||
* During import the viewer will fire life-cycle events:
|
||||
*
|
||||
* * import.parse.start (about to read model from xml)
|
||||
* * import.parse.complete (model read; may have worked or not)
|
||||
* * import.render.start (graphical import start)
|
||||
* * import.render.complete (graphical import finished)
|
||||
* * import.done (everything done)
|
||||
*
|
||||
* You can use these events to hook into the life-cycle.
|
||||
*
|
||||
* @param {String} xml the BPMN 2.0 xml
|
||||
* @param {Function} done invoked with (err, warnings=[])
|
||||
*/
|
||||
|
@ -138,21 +150,34 @@ Viewer.prototype.importXML = function(xml, done) {
|
|||
|
||||
var self = this;
|
||||
|
||||
// hook in pre-parse listeners +
|
||||
// allow xml manipulation
|
||||
xml = this._emit('import.parse.start', { xml: xml }) || xml;
|
||||
|
||||
this.moddle.fromXML(xml, 'bpmn:Definitions', function(err, definitions, context) {
|
||||
|
||||
// hook in post parse listeners +
|
||||
// allow definitions manipulation
|
||||
definitions = self._emit('import.parse.complete', {
|
||||
error: err,
|
||||
definitions: definitions,
|
||||
context: context
|
||||
}) || definitions;
|
||||
|
||||
if (err) {
|
||||
err = checkValidationError(err);
|
||||
return done(err);
|
||||
}
|
||||
|
||||
if (typeof self._parsedXML === 'function') {
|
||||
self._parsedXML(definitions, context);
|
||||
self._emit('import.done', { error: err });
|
||||
|
||||
return done(err);
|
||||
}
|
||||
|
||||
var parseWarnings = context.warnings;
|
||||
|
||||
self.importDefinitions(definitions, function(err, importWarnings) {
|
||||
var allWarnings = parseWarnings.concat(importWarnings || []);
|
||||
var allWarnings = [].concat(parseWarnings, importWarnings || []);
|
||||
|
||||
self._emit('import.done', { error: err, warnings: allWarnings });
|
||||
|
||||
done(err, allWarnings);
|
||||
});
|
||||
|
@ -349,6 +374,18 @@ Viewer.prototype._init = function(container, moddle, options) {
|
|||
Diagram.call(this, diagramOptions);
|
||||
};
|
||||
|
||||
/**
|
||||
* Emit an event on the underlying {@link EventBus}
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {Object} event
|
||||
*
|
||||
* @return {Object} event processing result (if any)
|
||||
*/
|
||||
Viewer.prototype._emit = function(type, event) {
|
||||
return this.get('eventBus').fire(type, event);
|
||||
};
|
||||
|
||||
Viewer.prototype._createContainer = function(options) {
|
||||
|
||||
var parent = options.container,
|
||||
|
|
|
@ -21,7 +21,13 @@ function importBpmnDiagram(diagram, definitions, done) {
|
|||
var error,
|
||||
warnings = [];
|
||||
|
||||
function parse(definitions) {
|
||||
/**
|
||||
* Walk the diagram semantically, importing (=drawing)
|
||||
* all elements you encounter.
|
||||
*
|
||||
* @param {ModdleElement} definitions
|
||||
*/
|
||||
function render(definitions) {
|
||||
|
||||
var visitor = {
|
||||
|
||||
|
@ -40,19 +46,24 @@ function importBpmnDiagram(diagram, definitions, done) {
|
|||
|
||||
var walker = new BpmnTreeWalker(visitor, translate);
|
||||
|
||||
// import
|
||||
// traverse BPMN 2.0 document model,
|
||||
// starting at definitions
|
||||
walker.handleDefinitions(definitions);
|
||||
}
|
||||
|
||||
eventBus.fire('import.start', { definitions: definitions });
|
||||
eventBus.fire('import.render.start', { definitions: definitions });
|
||||
|
||||
try {
|
||||
parse(definitions);
|
||||
render(definitions);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
eventBus.fire(error ? 'import.error' : 'import.success', { error: error, warnings: warnings });
|
||||
eventBus.fire('import.render.complete', {
|
||||
error: error,
|
||||
warnings: warnings
|
||||
});
|
||||
|
||||
done(error, warnings);
|
||||
}
|
||||
|
||||
|
|
|
@ -91,45 +91,6 @@ describe('Viewer', function() {
|
|||
});
|
||||
|
||||
|
||||
describe('import events', function() {
|
||||
|
||||
it('should fire <import.*> events', function(done) {
|
||||
|
||||
// given
|
||||
var viewer = new Viewer({ container: container });
|
||||
|
||||
var xml = require('../fixtures/bpmn/simple.bpmn');
|
||||
|
||||
var events = [];
|
||||
|
||||
viewer.on('import.start', function() {
|
||||
events.push('import.start');
|
||||
});
|
||||
|
||||
viewer.on('import.success', function() {
|
||||
events.push('import.success');
|
||||
});
|
||||
|
||||
viewer.on('import.error', function() {
|
||||
events.push('import.error');
|
||||
});
|
||||
|
||||
// when
|
||||
viewer.importXML(xml, function(err) {
|
||||
|
||||
// then
|
||||
expect(events).to.eql([
|
||||
'import.start',
|
||||
'import.success'
|
||||
]);
|
||||
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('overlay support', function() {
|
||||
|
||||
it('should allow to add overlays', function(done) {
|
||||
|
@ -765,6 +726,52 @@ describe('Viewer', function() {
|
|||
});
|
||||
|
||||
|
||||
describe('#importXML', function() {
|
||||
|
||||
it('should emit <import.*> events', function(done) {
|
||||
|
||||
// given
|
||||
var viewer = new Viewer({ container: container });
|
||||
|
||||
var xml = require('../fixtures/bpmn/simple.bpmn');
|
||||
|
||||
var events = [];
|
||||
|
||||
viewer.on([
|
||||
'import.parse.start',
|
||||
'import.parse.complete',
|
||||
'import.render.start',
|
||||
'import.render.complete',
|
||||
'import.done'
|
||||
], function(e) {
|
||||
// log event type + event arguments
|
||||
events.push([
|
||||
e.type,
|
||||
Object.keys(e).filter(function(key) {
|
||||
return key !== 'type';
|
||||
})
|
||||
]);
|
||||
});
|
||||
|
||||
// when
|
||||
viewer.importXML(xml, function(err) {
|
||||
|
||||
// then
|
||||
expect(events).to.eql([
|
||||
[ 'import.parse.start', [ 'xml' ] ],
|
||||
[ 'import.parse.complete', ['error', 'definitions', 'context' ] ],
|
||||
[ 'import.render.start', [ 'definitions' ] ],
|
||||
[ 'import.render.complete', [ 'error', 'warnings' ] ],
|
||||
[ 'import.done', [ 'error', 'warnings' ] ]
|
||||
]);
|
||||
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('#on', function() {
|
||||
|
||||
it('should fire with given three', function(done) {
|
||||
|
|
|
@ -45,7 +45,7 @@ describe('import - Importer', function() {
|
|||
|
||||
describe('events', function() {
|
||||
|
||||
it('should fire <import.start> and <import.success>', function(done) {
|
||||
it('should fire <import.render.start> and <import.render.complete>', function(done) {
|
||||
|
||||
// given
|
||||
var xml = require('../../fixtures/bpmn/import/process.bpmn');
|
||||
|
@ -55,13 +55,13 @@ describe('import - Importer', function() {
|
|||
var eventBus = diagram.get('eventBus');
|
||||
|
||||
// log events
|
||||
eventBus.on('import.start', function(event) {
|
||||
eventBus.on('import.render.start', function(event) {
|
||||
expect(event.definitions).to.exist;
|
||||
|
||||
eventCount++;
|
||||
});
|
||||
|
||||
eventBus.on('import.success', function(event) {
|
||||
eventBus.on('import.render.complete', function(event) {
|
||||
expect(event).to.have.property('error');
|
||||
expect(event).to.have.property('warnings');
|
||||
|
||||
|
|
Loading…
Reference in New Issue