fix(import): handle invisible root elements

This commit ensures we pipe invisible root elements (Process,
Collaboration) through our import infrastructure, too.

This way we we receive proper events for them.

Related to #6
This commit is contained in:
Nico Rehwaldt 2014-07-01 11:33:28 +02:00
parent 921de712d2
commit ae60914146
7 changed files with 95 additions and 25 deletions

View File

@ -137,8 +137,20 @@ BpmnImporter.prototype.add = function(semantic, di, parent) {
data.label = label;
}
// handle the special case that we deal with a
// invisible root element (process or collaboration)
if (di.$instanceOf('bpmndi:BPMNPlane')) {
// we still fire the added event, making sure our
// infrastructure pics it up properly
fire('add', null);
fire('added', null);
return null;
}
if (di.$instanceOf('bpmndi:BPMNShape')) {
if (di.$type === 'bpmndi:BPMNShape') {
var bounds = di.bounds;
var collapsed = isCollapsed(semantic, di);

View File

@ -20,6 +20,9 @@ function BpmnRegistry(events, elementRegistry) {
diagramElement: {}
};
// we attach to element.add rather than element.added to ensure
// the meta-data (semantic, di) for the element is already present
// during rendering
events.on('bpmn.element.add', function(e) {
var semantic = e.semantic,
id = semantic.id;

View File

@ -1,3 +1,5 @@
module.exports = {
bpmnRegistry: [ 'type', require('./BpmnRegistry') ]
__init__: [ 'bpmnRegistry' ],
bpmnRegistry: [ 'type', require('./BpmnRegistry') ],
bpmnImporter: [ 'type', require('./BpmnImporter') ]
};

View File

@ -38,6 +38,10 @@ function BpmnTreeWalker(handler) {
return gfx;
}
function visitRoot(element, diagram) {
return handler.root(element, diagram);
}
function visitIfDi(element, ctx) {
var di = getDi(element);
@ -96,10 +100,8 @@ function BpmnTreeWalker(handler) {
throw new Error('diagram not part of bpmn:Definitions');
}
if (!diagram) {
if (diagrams && diagrams.length) {
diagram = diagrams[0];
}
if (!diagram && diagrams && diagrams.length) {
diagram = diagrams[0];
}
// no diagram -> nothing to import
@ -110,19 +112,23 @@ function BpmnTreeWalker(handler) {
// load DI from selected diagram only
handleDiagram(diagram);
var rootElement = diagram.plane.bpmnElement;
var plane = diagram.plane,
rootElement = plane.bpmnElement;
if (!rootElement) {
throw new Error('no rootElement referenced in BPMNPlane <' + diagram.plane.id + '>');
}
var ctx = visitRoot(rootElement, plane);
if (is(rootElement, 'bpmn:Process')) {
handleProcess(rootElement);
handleProcess(rootElement, ctx);
} else if (is(rootElement, 'bpmn:Collaboration')) {
handleCollaboration(rootElement);
handleCollaboration(rootElement, ctx);
// force drawing of everything not yet drawn that is part of the target DI
handleUnhandledProcesses(definitions.rootElements);
handleUnhandledProcesses(definitions.rootElements, ctx);
} else {
throw new Error('unsupported root element for bpmndi:Diagram <' + rootElement.$type + '>');
}
@ -141,11 +147,12 @@ function BpmnTreeWalker(handler) {
function handleUnhandledProcesses(rootElements) {
// walk through all processes that have not yet been drawn and draw them
// (in case they contain lanes with DI information)
// if they contain lanes with DI information.
// we do this to pass the free-floating lane test cases in the MIWG test suite
var processes = _.filter(rootElements, function(e) {
//Need this fix to get run test-case "01"
return e.$type === 'bpmn:Process' && e.laneSets && handledProcesses.indexOf(e) === -1;
return is(e, 'bpmn:Process') && e.laneSets && handledProcesses.indexOf(e) === -1;
});
processes.forEach(contextual(handleProcess));
}

View File

@ -20,6 +20,10 @@ function importBpmnDiagram(diagram, definitions, done) {
var visitor = {
root: function(element, di) {
return importer.add(element, di);
},
element: function(element, di, parent) {
return importer.add(element, di, parent);
},

View File

@ -0,0 +1,37 @@
'use strict';
var Matchers = require('../../Matchers'),
TestHelper = require('../../TestHelper');
/* global bootstrapBpmnJS, inject */
var fs = require('fs');
var bpmnCoreModule = require('../../../../lib/core');
describe('core', function() {
beforeEach(Matchers.add);
var diagramXML = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf-8');
var testModules = [ bpmnCoreModule ];
beforeEach(bootstrapBpmnJS(diagramXML, { modules: testModules }));
describe('BpmnRegistry', function() {
it('should get process semantic by ID', inject(function(bpmnRegistry) {
expect(bpmnRegistry.getSemantic('Process_1')).toBeDefined();
}));
});
});

View File

@ -64,25 +64,18 @@ describe('import - importer', function() {
// given
var xml = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf8');
var events = [];
var eventCount = 0;
// 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 });
eventCount++;
});
// when
runImport(diagram, xml, function(err, warnings) {
// 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' },
{ type: 'add', semantic: 'EndEvent_1', di: '_BPMNShape_EndEvent_2', diagramElement: 'EndEvent_1' },
{ type: 'add', semantic: 'SequenceFlow_2', di: 'BPMNEdge_SequenceFlow_2', diagramElement: 'SequenceFlow_2' }
]);
expect(eventCount).toEqual(7);
done(err);
});
@ -102,7 +95,12 @@ describe('import - importer', function() {
// 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 });
events.push({
type: 'add',
semantic: e.semantic.id,
di: e.di.id,
diagramElement: e.diagramElement && e.diagramElement.id
});
});
// when
@ -110,6 +108,7 @@ describe('import - importer', function() {
// then
expect(events).toEqual([
{ type: 'add', semantic: 'Process_1', di: 'BPMNPlane_1', diagramElement: null },
{ 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' },
@ -132,7 +131,12 @@ describe('import - importer', function() {
// 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 });
events.push({
type: 'add',
semantic: e.semantic.id,
di: e.di.id,
diagramElement: e.diagramElement && e.diagramElement.id
});
});
// when
@ -140,6 +144,7 @@ describe('import - importer', function() {
// then
expect(events).toEqual([
{ type: 'add', semantic: '_Collaboration_2', di: 'BPMNPlane_1', diagramElement: null },
{ type: 'add', semantic: 'Participant_2', di: '_BPMNShape_Participant_2', diagramElement: 'Participant_2' },
{ type: 'add', semantic: 'Lane_1', di: '_BPMNShape_Lane_2', diagramElement: 'Lane_1' },
{ type: 'add', semantic: 'Lane_2', di: '_BPMNShape_Lane_3', diagramElement: 'Lane_2' },