diff --git a/lib/features/context-pad/ContextPadProvider.js b/lib/features/context-pad/ContextPadProvider.js index c4bb6fad..91c4a172 100644 --- a/lib/features/context-pad/ContextPadProvider.js +++ b/lib/features/context-pad/ContextPadProvider.js @@ -158,7 +158,9 @@ ContextPadProvider.prototype.getContextPadEntries = function(element) { function appendStart(event, element) { var shape = elementFactory.createShape(assign({ type: type }, options)); - create.start(event, shape, element); + create.start(event, shape, { + source: element + }); } diff --git a/lib/features/modeling/ElementFactory.js b/lib/features/modeling/ElementFactory.js index 498c50d1..101f6a6d 100644 --- a/lib/features/modeling/ElementFactory.js +++ b/lib/features/modeling/ElementFactory.js @@ -1,6 +1,7 @@ import { assign, - forEach + forEach, + isObject } from 'min-dash'; import inherits from 'inherits'; @@ -164,10 +165,10 @@ ElementFactory.prototype._getDefaultSize = function(semantic) { } if (is(semantic, 'bpmn:Participant')) { - if (!isExpanded(semantic)) { - return { width: 400, height: 60 }; - } else { + if (isExpanded(semantic)) { return { width: 600, height: 250 }; + } else { + return { width: 400, height: 60 }; } } @@ -195,11 +196,23 @@ ElementFactory.prototype._getDefaultSize = function(semantic) { }; -ElementFactory.prototype.createParticipantShape = function(collapsed) { +/** + * Create participant. + * + * @param {boolean|Object} [attrs] attrs + * + * @returns {djs.model.Shape} + */ +ElementFactory.prototype.createParticipantShape = function(attrs) { - var attrs = { type: 'bpmn:Participant' }; + if (!isObject(attrs)) { + attrs = { isExpanded: attrs }; + } - if (!collapsed) { + attrs = assign({ type: 'bpmn:Participant' }, attrs || {}); + + // participants are expanded by default + if (attrs.isExpanded !== false) { attrs.processRef = this._bpmnFactory.create('bpmn:Process'); } diff --git a/lib/features/modeling/behavior/CreateParticipantBehavior.js b/lib/features/modeling/behavior/CreateParticipantBehavior.js index c241f206..76f8f373 100644 --- a/lib/features/modeling/behavior/CreateParticipantBehavior.js +++ b/lib/features/modeling/behavior/CreateParticipantBehavior.js @@ -8,7 +8,10 @@ import { isLabel } from '../../../util/LabelUtil'; import { getBBox } from 'diagram-js/lib/util/Elements'; -import { assign } from 'min-dash'; +import { + assign, + find +} from 'min-dash'; import { asTRBL } from 'diagram-js/lib/layout/LayoutUtil'; @@ -85,71 +88,122 @@ export default function CreateParticipantBehavior(canvas, eventBus, modeling) { } }); - // turn process into collaboration before adding participant - this.preExecute('shape.create', function(context) { + function ensureCollaboration(context) { var parent = context.parent, - shape = context.shape, - position = context.position; + collaboration; var rootElement = canvas.getRootElement(); - if ( - is(parent, 'bpmn:Process') && - is(shape, 'bpmn:Participant') && - !is(rootElement, 'bpmn:Collaboration') - ) { + if (is(rootElement, 'bpmn:Collaboration')) { + collaboration = rootElement; + } else { - // this is going to detach the process root - // and set the returned collaboration element - // as the new root element - var collaborationElement = modeling.makeCollaboration(); + // update root element by making collaboration + collaboration = modeling.makeCollaboration(); - // monkey patch the create context - // so that the participant is being dropped - // onto the new collaboration root instead - context.position = position; - context.parent = collaborationElement; + // re-use process when creating first participant + context.process = parent; + } - context.processRoot = parent; + context.parent = collaboration; + } + + // turn process into collaboration before adding participant + this.preExecute('shape.create', function(context) { + var parent = context.parent, + shape = context.shape; + + if (is(shape, 'bpmn:Participant') && is(parent, 'bpmn:Process')) { + ensureCollaboration(context); } }, true); this.execute('shape.create', function(context) { - var processRoot = context.processRoot, + var process = context.process, shape = context.shape; - if (processRoot) { + if (process) { context.oldProcessRef = shape.businessObject.processRef; - // assign the participant processRef - shape.businessObject.processRef = processRoot.businessObject; + // re-use process when creating first participant + shape.businessObject.processRef = process.businessObject; } }, true); this.revert('shape.create', function(context) { - var processRoot = context.processRoot, + var process = context.process, shape = context.shape; - if (processRoot) { + if (process) { - // assign the participant processRef + // re-use process when creating first participant shape.businessObject.processRef = context.oldProcessRef; } }, true); this.postExecute('shape.create', function(context) { - var processRoot = context.processRoot, + var process = context.process, shape = context.shape; - if (processRoot) { + if (process) { - // process root is already detached at this point - var processChildren = processRoot.children.slice(); + // move children from process to participant + var processChildren = process.children.slice(); modeling.moveElements(processChildren, { x: 0, y: 0 }, shape); } }, true); + + // turn process into collaboration when creating participants + this.preExecute('elements.create', HIGH_PRIORITY, function(context) { + var elements = context.elements, + parent = context.parent, + participant; + + var hasParticipants = findParticipant(elements); + + if (hasParticipants && is(parent, 'bpmn:Process')) { + ensureCollaboration(context); + + participant = findParticipant(elements); + + context.oldProcessRef = participant.businessObject.processRef; + + // re-use process when creating first participant + participant.businessObject.processRef = parent.businessObject; + } + }, true); + + this.revert('elements.create', function(context) { + var elements = context.elements, + process = context.process, + participant; + + if (process) { + participant = findParticipant(elements); + + // re-use process when creating first participant + participant.businessObject.processRef = context.oldProcessRef; + } + }, true); + + this.postExecute('elements.create', function(context) { + var elements = context.elements, + process = context.process, + participant; + + if (process) { + participant = findParticipant(elements); + + // move children from process to first participant + var processChildren = process.children.slice(); + + modeling.moveElements(processChildren, { x: 0, y: 0 }, participant); + } + + }, true); + } CreateParticipantBehavior.$inject = [ @@ -168,9 +222,14 @@ function getParticipantBounds(shape, childrenBBox) { height: childrenBBox.height + VERTICAL_PARTICIPANT_PADDING * 2 }; + var width = Math.max(shape.width, childrenBBox.width), + height = Math.max(shape.height, childrenBBox.height); + return { - width: Math.max(shape.width, childrenBBox.width), - height: Math.max(shape.height, childrenBBox.height) + x: -width / 2, + y: -height / 2, + width: width, + height: height }; } @@ -187,4 +246,10 @@ function getParticipantCreateConstraints(shape, childrenBBox) { function isConnection(element) { return !!element.waypoints; +} + +function findParticipant(elements) { + return find(elements, function(element) { + return is(element, 'bpmn:Participant'); + }); } \ No newline at end of file diff --git a/lib/features/modeling/behavior/SubProcessStartEventBehavior.js b/lib/features/modeling/behavior/SubProcessStartEventBehavior.js index 0bb405c0..0f1ca99a 100644 --- a/lib/features/modeling/behavior/SubProcessStartEventBehavior.js +++ b/lib/features/modeling/behavior/SubProcessStartEventBehavior.js @@ -6,37 +6,17 @@ import { is } from '../../../util/ModelUtil'; import { isExpanded } from '../../../util/DiUtil.js'; /** - * Add start event child by default when creating an expanded subprocess - * with create.start or replacing a task with an expanded subprocess. + * Add start event replacing element with expanded sub process. + * + * @param {Injector} injector + * @param {Modeling} modeling */ -export default function SubProcessStartEventBehavior(eventBus, modeling) { - CommandInterceptor.call(this, eventBus); - - eventBus.on('create.start', function(event) { - var shape = event.context.shape, - hints = event.context.hints; - - hints.shouldAddStartEvent = is(shape, 'bpmn:SubProcess') && isExpanded(shape); - }); - - this.postExecuted('shape.create', function(event) { - var shape = event.context.shape, - hints = event.context.hints, - position; - - if (!hints.shouldAddStartEvent) { - return; - } - - position = calculatePositionRelativeToShape(shape); - - modeling.createShape({ type: 'bpmn:StartEvent' }, position, shape); - }); +export default function SubProcessStartEventBehavior(injector, modeling) { + injector.invoke(CommandInterceptor, this); this.postExecuted('shape.replace', function(event) { var oldShape = event.context.oldShape, - newShape = event.context.newShape, - position; + newShape = event.context.newShape; if ( !is(newShape, 'bpmn:SubProcess') || @@ -46,14 +26,14 @@ export default function SubProcessStartEventBehavior(eventBus, modeling) { return; } - position = calculatePositionRelativeToShape(newShape); + var position = getStartEventPosition(newShape); modeling.createShape({ type: 'bpmn:StartEvent' }, position, newShape); }); } SubProcessStartEventBehavior.$inject = [ - 'eventBus', + 'injector', 'modeling' ]; @@ -61,7 +41,7 @@ inherits(SubProcessStartEventBehavior, CommandInterceptor); // helpers ////////// -function calculatePositionRelativeToShape(shape) { +function getStartEventPosition(shape) { return { x: shape.x + shape.width / 6, y: shape.y + shape.height / 2 diff --git a/lib/features/palette/PaletteProvider.js b/lib/features/palette/PaletteProvider.js index 1d21b161..b4e638d5 100644 --- a/lib/features/palette/PaletteProvider.js +++ b/lib/features/palette/PaletteProvider.js @@ -71,8 +71,26 @@ PaletteProvider.prototype.getPaletteEntries = function(element) { }; } - function createParticipant(event, collapsed) { - create.start(event, elementFactory.createParticipantShape(collapsed)); + function createSubprocess(event) { + var subProcess = elementFactory.createShape({ + type: 'bpmn:SubProcess', + x: 0, + y: 0, + isExpanded: true + }); + + var startEvent = elementFactory.createShape({ + type: 'bpmn:StartEvent', + x: 40, + y: 82, + parent: subProcess + }); + + create.start(event, [ subProcess, startEvent ]); + } + + function createParticipant(event) { + create.start(event, elementFactory.createParticipantShape()); } assign(actions, { @@ -148,11 +166,15 @@ PaletteProvider.prototype.getPaletteEntries = function(element) { 'bpmn:DataStoreReference', 'data-store', 'bpmn-icon-data-store', translate('Create DataStoreReference') ), - 'create.subprocess-expanded': createAction( - 'bpmn:SubProcess', 'activity', 'bpmn-icon-subprocess-expanded', - translate('Create expanded SubProcess'), - { isExpanded: true } - ), + 'create.subprocess-expanded': { + group: 'activity', + className: 'bpmn-icon-subprocess-expanded', + title: translate('Create expanded SubProcess'), + action: { + dragstart: createSubprocess, + click: createSubprocess + } + }, 'create.participant-expanded': { group: 'collaboration', className: 'bpmn-icon-participant', diff --git a/lib/features/rules/BpmnRules.js b/lib/features/rules/BpmnRules.js index 8cd83409..e43bf1e5 100644 --- a/lib/features/rules/BpmnRules.js +++ b/lib/features/rules/BpmnRules.js @@ -13,6 +13,7 @@ import { } from '../../util/ModelUtil'; import { + getParent, isAny } from '../modeling/util/ModelingUtil'; @@ -117,6 +118,20 @@ BpmnRules.prototype.init = function() { return canResize(shape, newBounds); }); + this.addRule('elements.create', function(context) { + var elements = context.elements, + position = context.position, + target = context.target; + + return every(elements, function(element) { + if (isConnection(element)) { + return canConnect(element.source, element.target, element); + } + + return canCreate(element, target, null, position); + }); + }); + this.addRule('elements.move', function(context) { var target = context.target, @@ -320,7 +335,7 @@ function isSameScope(a, b) { var scopeParentA = getScopeParent(a), scopeParentB = getScopeParent(b); - return scopeParentA && (scopeParentA === scopeParentB); + return scopeParentA === scopeParentB; } function hasEventDefinition(element, eventDefinition) { @@ -852,9 +867,9 @@ function canConnectAssociation(source, target) { function canConnectMessageFlow(source, target) { - // handle the case where target does not have a parent, - // because it is not dropped within the diagram (bpmn-io/bpmn-js#1033) - if (!target.parent) { + // during connect user might move mouse out of canvas + // https://github.com/bpmn-io/bpmn-js/issues/1033 + if (getRootElement(source) && !getRootElement(target)) { return false; } @@ -955,8 +970,11 @@ function isOutgoingEventBasedGatewayConnection(connection) { } function areOutgoingEventBasedGatewayConnections(connections) { - connections = connections || []; return connections.some(isOutgoingEventBasedGatewayConnection); } + +function getRootElement(element) { + return getParent(element, 'bpmn:Process') || getParent(element, 'bpmn:Collaboration'); +} \ No newline at end of file diff --git a/test/spec/features/auto-resize/AutoResizeSpec.js b/test/spec/features/auto-resize/AutoResizeSpec.js index cedd8922..fede19eb 100644 --- a/test/spec/features/auto-resize/AutoResizeSpec.js +++ b/test/spec/features/auto-resize/AutoResizeSpec.js @@ -277,19 +277,6 @@ describe('features/auto-resize', function() { expect(participantShape).to.have.bounds(originalBounds); })); - - it('should not auto-resize when creating with { root: false } hint', inject(function(modeling) { - - // given - var taskAttrs = { type: 'bpmn:Task' }; - - // when - modeling.createShape(taskAttrs, { x: 600, y: 320 }, participantShape, { root: false }); - - // then - expect(participantShape).to.have.bounds(originalBounds); - })); - }); diff --git a/test/spec/features/modeling/behavior/CreateParticipantBehaviorSpec.js b/test/spec/features/modeling/behavior/CreateParticipantBehaviorSpec.js index 2bf284a7..fecc0bae 100644 --- a/test/spec/features/modeling/behavior/CreateParticipantBehaviorSpec.js +++ b/test/spec/features/modeling/behavior/CreateParticipantBehaviorSpec.js @@ -28,7 +28,7 @@ describe('features/modeling - create participant', function() { describe('process', function() { - describe('should turn diagram into collaboration', function() { + describe('should turn process into collaboration', function() { var processDiagramXML = require('../../../../fixtures/bpmn/collaboration/process-empty.bpmn'); @@ -39,13 +39,17 @@ describe('features/modeling - create participant', function() { collaborationDi, diRoot, participant, + participant2, + participants, participantBo, + participant2Bo, participantDi, + participant2Di, process, processBo, processDi; - beforeEach(inject(function(canvas, elementFactory, modeling) { + beforeEach(inject(function(canvas, elementFactory) { // given process = canvas.getRootElement(); @@ -54,48 +58,116 @@ describe('features/modeling - create participant', function() { diRoot = processBo.di.$parent; - participant = elementFactory.createParticipantShape(); + participant = elementFactory.createParticipantShape({ x: 100, y: 100 }); participantBo = participant.businessObject; participantDi = participantBo.di; - // when - modeling.createShape(participant, { x: 350, y: 200 }, process); + participant2 = elementFactory.createParticipantShape({ x: 100, y: 400 }); + participant2Bo = participant2.businessObject; + participant2Di = participant2Bo.di; - collaboration = canvas.getRootElement(); - collaborationBo = collaboration.businessObject; - collaborationDi = collaborationBo.di; + participants = [ participant, participant2 ]; })); - it('execute', function() { + describe('creating one participant', function() { - // then - expect(participantBo.$parent).to.equal(collaborationBo); - expect(participantBo.processRef).to.equal(processBo); + beforeEach(inject(function(canvas, modeling) { - expect(collaborationBo.$instanceOf('bpmn:Collaboration')).to.be.true; - expect(collaborationBo.$parent).to.equal(processBo.$parent); - expect(collaborationBo.participants).to.include(participantBo); + // when + modeling.createShape(participant, { x: 400, y: 225 }, process); + + collaboration = canvas.getRootElement(); + collaborationBo = collaboration.businessObject; + collaborationDi = collaborationBo.di; + })); + + + it('execute', function() { + + // then + expect(participantBo.$parent).to.equal(collaborationBo); + expect(participantBo.processRef).to.equal(processBo); + + expect(collaborationBo.$instanceOf('bpmn:Collaboration')).to.be.true; + expect(collaborationBo.$parent).to.equal(processBo.$parent); + expect(collaborationBo.participants).to.include(participantBo); + + expect(participantDi.$parent).to.equal(collaborationDi); + expect(collaborationDi.$parent).to.equal(diRoot); + }); + + + it('undo', inject(function(commandStack) { + + // when + commandStack.undo(); + + // then + expect(participantBo.$parent).not.to.exist; + expect(participantBo.processRef).not.to.equal(processBo); + + expect(collaborationBo.$parent).not.to.exist; + expect(collaborationBo.participants).not.to.include(participantBo); + + expect(processDi.$parent).to.equal(diRoot); + })); - expect(participantDi.$parent).to.equal(collaborationDi); - expect(collaborationDi.$parent).to.equal(diRoot); }); - it('undo', inject(function(commandStack) { + describe('creating two participants', function() { - // when - commandStack.undo(); + beforeEach(inject(function(canvas, modeling) { - // then - expect(participantBo.$parent).not.to.exist; - expect(participantBo.processRef).not.to.equal(processBo); + // when + modeling.createElements(participants, { x: 400, y: 375 }, process); - expect(collaborationBo.$parent).not.to.exist; - expect(collaborationBo.participants).not.to.include(participantBo); + collaboration = canvas.getRootElement(); + collaborationBo = collaboration.businessObject; + collaborationDi = collaborationBo.di; + })); - expect(processDi.$parent).to.equal(diRoot); - })); + + it('execute', function() { + + // then + expect(participantBo.$parent).to.equal(collaborationBo); + expect(participantBo.processRef).to.equal(processBo); + + expect(participant2Bo.$parent).to.equal(collaborationBo); + expect(participant2Bo.processRef).not.to.equal(processBo); + + expect(collaborationBo.$instanceOf('bpmn:Collaboration')).to.be.true; + expect(collaborationBo.$parent).to.equal(processBo.$parent); + expect(collaborationBo.participants).to.include(participantBo); + + expect(participantDi.$parent).to.equal(collaborationDi); + expect(participant2Di.$parent).to.equal(collaborationDi); + expect(collaborationDi.$parent).to.equal(diRoot); + }); + + + it('undo', inject(function(commandStack) { + + // when + commandStack.undo(); + + // then + expect(participantBo.$parent).not.to.exist; + expect(participantBo.processRef).not.to.equal(processBo); + + expect(participant2Bo.$parent).not.to.exist; + expect(participant2Bo.processRef).not.to.equal(processBo); + + expect(collaborationBo.$parent).not.to.exist; + expect(collaborationBo.participants).not.to.include(participantBo); + expect(collaborationBo.participants).not.to.include(participant2Bo); + + expect(processDi.$parent).to.equal(diRoot); + })); + + }); }); diff --git a/test/spec/features/palette/PaletteProviderSpec.js b/test/spec/features/palette/PaletteProviderSpec.js index 4956615f..9a784671 100644 --- a/test/spec/features/palette/PaletteProviderSpec.js +++ b/test/spec/features/palette/PaletteProviderSpec.js @@ -1,11 +1,17 @@ import { bootstrapModeler, + getBpmnJS, inject } from 'test/TestHelper'; +import coreModule from 'lib/core'; +import createModule from 'diagram-js/lib/features/create'; import modelingModule from 'lib/features/modeling'; import paletteModule from 'lib/features/palette'; -import coreModule from 'lib/core'; + +import { createMoveEvent } from 'diagram-js/lib/features/mouse/Mouse'; + +import { is } from 'lib/util/ModelUtil'; import { query as domQuery, @@ -17,12 +23,17 @@ describe('features/palette', function() { var diagramXML = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn'); - var testModules = [ coreModule, modelingModule, paletteModule ]; + var testModules = [ + coreModule, + createModule, + modelingModule, + paletteModule + ]; beforeEach(bootstrapModeler(diagramXML, { modules: testModules })); - it('should provide BPMN modeling palette', inject(function(canvas, palette) { + it('should provide BPMN modeling palette', inject(function(canvas) { // when var paletteElement = domQuery('.djs-palette', canvas._container); @@ -32,4 +43,35 @@ describe('features/palette', function() { expect(entries.length).to.equal(14); })); + + describe('sub process', function() { + + it('should create sub process with start event', inject(function(dragging, palette) { + + // when + triggerPaletteEntry('create.subprocess-expanded'); + + // then + var context = dragging.context(), + elements = context.data.elements; + + expect(elements).to.have.length(2); + expect(is(elements[0], 'bpmn:SubProcess')).to.be.true; + expect(is(elements[1], 'bpmn:StartEvent')).to.be.true; + })); + + }); + }); + +// helpers ////////// + +function triggerPaletteEntry(id) { + getBpmnJS().invoke(function(palette) { + var entry = palette.getEntries()[ id ]; + + if (entry && entry.action && entry.action.click) { + entry.action.click(createMoveEvent(0, 0)); + } + }); +} diff --git a/test/spec/features/rules/BpmnRulesSpec.js b/test/spec/features/rules/BpmnRulesSpec.js index 7d9a4f75..e758651e 100644 --- a/test/spec/features/rules/BpmnRulesSpec.js +++ b/test/spec/features/rules/BpmnRulesSpec.js @@ -20,6 +20,69 @@ describe('features/modeling/rules - BpmnRules', function() { var testModules = [ coreModule, modelingModule ]; + describe('create elements', function() { + + var testXML = require('./BpmnRules.process.bpmn'); + + beforeEach(bootstrapModeler(testXML, { modules: testModules })); + + + it('create tasks -> process', inject(function(elementFactory) { + + // given + var task1 = elementFactory.createShape({ type: 'bpmn:Task' }), + task2 = elementFactory.createShape({ type: 'bpmn:Task' }); + + // then + expectCanCreate([ task1, task2 ], 'Process', true); + })); + + + it('create tasks -> task', inject(function(elementFactory) { + + // given + var task1 = elementFactory.createShape({ type: 'bpmn:Task' }), + task2 = elementFactory.createShape({ type: 'bpmn:Task' }); + + // then + expectCanCreate([ task1, task2 ], 'Task', false); + })); + + + it('create tasks and sequence flow -> process', inject(function(elementFactory) { + + // given + var task1 = elementFactory.createShape({ type: 'bpmn:Task' }), + task2 = elementFactory.createShape({ type: 'bpmn:Task' }), + sequenceFlow = elementFactory.createConnection({ + type: 'bpmn:SequenceFlow', + source: task1, + target: task2 + }); + + // then + expectCanCreate([ task1, task2, sequenceFlow ], 'Process', true); + })); + + + it('create tasks and message flow -> process', inject(function(elementFactory) { + + // given + var task1 = elementFactory.createShape({ type: 'bpmn:Task' }), + task2 = elementFactory.createShape({ type: 'bpmn:Task' }), + sequenceFlow = elementFactory.createConnection({ + type: 'bpmn:MessageFlow', + source: task1, + target: task2 + }); + + // then + expectCanCreate([ task1, task2, sequenceFlow ], 'Process', false); + })); + + }); + + describe('on process diagram', function() { var testXML = require('./BpmnRules.process.bpmn'); diff --git a/test/spec/features/rules/Helper.js b/test/spec/features/rules/Helper.js index 430287a2..1c2eedca 100644 --- a/test/spec/features/rules/Helper.js +++ b/test/spec/features/rules/Helper.js @@ -3,7 +3,9 @@ import { } from 'test/TestHelper'; import { - isString + isArray, + isString, + map } from 'min-dash'; @@ -47,10 +49,21 @@ export function expectCanDrop(element, target, expectedResult) { } -export function expectCanCreate(element, target, expectedResult) { +export function expectCanCreate(shape, target, expectedResult) { - var result = getBpmnJS().invoke(function(bpmnRules) { - return bpmnRules.canCreate(get(element), get(target)); + var result = getBpmnJS().invoke(function(rules) { + + if (isArray(shape)) { + return rules.allowed('elements.create', { + elements: get(shape), + target: get(target) + }); + } + + return rules.allowed('shape.create', { + shape: get(shape), + target: get(target) + }); }); expect(result).to.eql(expectedResult); @@ -94,21 +107,25 @@ export function expectCanMove(elements, target, rules) { * Retrieve element, resolving an ID with * the actual element. */ -function get(element) { +function get(elementId) { - var actualElement; - - if (isString(element)) { - actualElement = getBpmnJS().invoke(function(elementRegistry) { - return elementRegistry.get(element); - }); - - if (!actualElement) { - throw new Error('element #' + element + ' not found'); - } - - return actualElement; + if (isArray(elementId)) { + return map(elementId, get); } - return element; + var element; + + if (isString(elementId)) { + element = getBpmnJS().invoke(function(elementRegistry) { + return elementRegistry.get(elementId); + }); + + if (!element) { + throw new Error('element #' + elementId + ' not found'); + } + + return element; + } + + return elementId; } \ No newline at end of file