From ae60914146c0c114833210ef79ba25b6a6bccac3 Mon Sep 17 00:00:00 2001 From: Nico Rehwaldt Date: Tue, 1 Jul 2014 11:33:28 +0200 Subject: [PATCH] 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 --- lib/core/BpmnImporter.js | 14 +++++++- lib/core/BpmnRegistry.js | 3 ++ lib/core/index.js | 4 ++- lib/import/BpmnTreeWalker.js | 29 ++++++++++------- lib/import/Importer.js | 4 +++ test/spec/browser/core/BpmnRegistrySpec.js | 37 ++++++++++++++++++++++ test/spec/browser/import/ImporterSpec.js | 29 ++++++++++------- 7 files changed, 95 insertions(+), 25 deletions(-) create mode 100644 test/spec/browser/core/BpmnRegistrySpec.js diff --git a/lib/core/BpmnImporter.js b/lib/core/BpmnImporter.js index 1f99312e..8fae8e3a 100644 --- a/lib/core/BpmnImporter.js +++ b/lib/core/BpmnImporter.js @@ -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); diff --git a/lib/core/BpmnRegistry.js b/lib/core/BpmnRegistry.js index cf05a854..4e1f797a 100644 --- a/lib/core/BpmnRegistry.js +++ b/lib/core/BpmnRegistry.js @@ -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; diff --git a/lib/core/index.js b/lib/core/index.js index c618d0d3..3bb03f99 100644 --- a/lib/core/index.js +++ b/lib/core/index.js @@ -1,3 +1,5 @@ module.exports = { - bpmnRegistry: [ 'type', require('./BpmnRegistry') ] + __init__: [ 'bpmnRegistry' ], + bpmnRegistry: [ 'type', require('./BpmnRegistry') ], + bpmnImporter: [ 'type', require('./BpmnImporter') ] }; \ No newline at end of file diff --git a/lib/import/BpmnTreeWalker.js b/lib/import/BpmnTreeWalker.js index 9951e8cf..7381478a 100644 --- a/lib/import/BpmnTreeWalker.js +++ b/lib/import/BpmnTreeWalker.js @@ -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)); } diff --git a/lib/import/Importer.js b/lib/import/Importer.js index 4c7d8437..967fac53 100644 --- a/lib/import/Importer.js +++ b/lib/import/Importer.js @@ -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); }, diff --git a/test/spec/browser/core/BpmnRegistrySpec.js b/test/spec/browser/core/BpmnRegistrySpec.js new file mode 100644 index 00000000..df5551a1 --- /dev/null +++ b/test/spec/browser/core/BpmnRegistrySpec.js @@ -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(); + + })); + + }); + +}); \ No newline at end of file diff --git a/test/spec/browser/import/ImporterSpec.js b/test/spec/browser/import/ImporterSpec.js index 20c36daa..452c5764 100644 --- a/test/spec/browser/import/ImporterSpec.js +++ b/test/spec/browser/import/ImporterSpec.js @@ -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' },