function BpmnAutoResize(eventBus, elementRegistry, modeling, rules) {
AutoResize.call(this, eventBus, elementRegistry, modeling, rules);
}n/a
function BpmnAutoResizeProvider(eventBus, modeling) {
AutoResizeProvider.call(this, eventBus);
this._modeling = modeling;
}n/a
function BpmnEditorActions( injector, canvas, elementRegistry, selection, spaceTool, lassoTool, handTool, globalConnect, distributeElements, alignElements, directEditing, searchPad, modeling) {
injector.invoke(EditorActions, this);
this.register({
selectElements: function() {
// select all elements except for the invisible
// root element
var rootElement = canvas.getRootElement();
var elements = elementRegistry.filter(function(element) {
return element !== rootElement;
});
selection.select(elements);
return elements;
},
spaceTool: function() {
spaceTool.toggle();
},
lassoTool: function() {
lassoTool.toggle();
},
handTool: function() {
handTool.toggle();
},
globalConnectTool: function() {
globalConnect.toggle();
},
distributeElements: function(opts) {
var currentSelection = selection.get(),
type = opts.type;
if (currentSelection.length) {
distributeElements.trigger(currentSelection, type);
}
},
alignElements: function(opts) {
var currentSelection = selection.get(),
aligneableElements = [],
type = opts.type;
if (currentSelection.length) {
aligneableElements = filter(currentSelection, function(element) {
return !is(element, 'bpmn:Lane');
});
alignElements.trigger(aligneableElements, type);
}
},
setColor: function(opts) {
var currentSelection = selection.get();
if (currentSelection.length) {
modeling.setColor(currentSelection, opts);
}
},
directEditing: function() {
var currentSelection = selection.get();
if (currentSelection.length) {
directEditing.activate(currentSelection[0]);
}
},
find: function() {
searchPad.toggle();
},
moveToOrigin: function() {
var rootElement = canvas.getRootElement(),
boundingBox,
elements;
if (is(rootElement, 'bpmn:Collaboration')) {
elements = elementRegistry.filter(function(element) {
return is(element.parent, 'bpmn:Collaboration');
});
} else {
elements = elementRegistry.filter(function(element) {
return element !== rootElement && !is(element.parent, 'bpmn:SubProcess');
});
}
boundingBox = getBBox(elements);
modeling.moveElements(elements, { x: -boundingBox.x, y: -boundingBox.y }, rootElement);
}
});
}n/a
function BpmnFactory(moddle) {
this._model = moddle;
}n/a
function BpmnGlobalConnect(globalConnect) {
globalConnect.registerProvider(this);
}n/a
function BpmnImporter(eventBus, canvas, elementFactory, elementRegistry, translate) {
this._eventBus = eventBus;
this._canvas = canvas;
this._elementFactory = elementFactory;
this._elementRegistry = elementRegistry;
this._translate = translate;
this._textUtil = new TextUtil();
}n/a
function BpmnLayouter() {}n/a
function BpmnOrderingProvider(eventBus, translate) {
OrderingProvider.call(this, eventBus);
var orders = [
{ type: 'bpmn:SubProcess', order: { level: 6 } },
{
type: 'bpmn:SequenceFlow',
order: {
level: 5,
containers: [
'bpmn:Participant',
'bpmn:FlowElementsContainer'
]
}
},
// handle DataAssociation(s) like message flows and render them always on top
{ type: 'bpmn:DataAssociation', order: { level: 9, containers: [ 'bpmn:Collaboration', 'bpmn:Process' ] } },
{ type: 'bpmn:MessageFlow', order: { level: 9, containers: [ 'bpmn:Collaboration' ] } },
{
type: 'bpmn:Association',
order: {
level: 6,
containers: [
'bpmn:Participant',
'bpmn:FlowElementsContainer',
'bpmn:Collaboration'
]
}
},
{ type: 'bpmn:BoundaryEvent', order: { level: 8 } },
{ type: 'bpmn:Participant', order: { level: -2 } },
{ type: 'bpmn:Lane', order: { level: -1 } }
];
function computeOrder(element) {
if (element.labelTarget) {
return { level: 10 };
}
var entry = find(orders, function(o) {
return isAny(element, [ o.type ]);
});
return entry && entry.order || { level: 1 };
}
function getOrder(element) {
var order = element.order;
if (!order) {
element.order = order = computeOrder(element);
}
return order;
}
function findActualParent(element, newParent, containers) {
var actualParent = newParent;
while (actualParent) {
if (isAny(actualParent, containers)) {
break;
}
actualParent = actualParent.parent;
}
if (!actualParent) {
throw new Error(translate('no parent for {element} in {parent}', {
element: element.id,
parent: newParent.id
}));
}
return actualParent;
}
this.getOrdering = function(element, newParent) {
var elementOrder = getOrder(element);
if (elementOrder.containers) {
newParent = findActualParent(element, newParent, elementOrder.containers);
}
var currentIndex = newParent.children.indexOf(element);
var insertIndex = findIndex(newParent.children, function(child) {
// do not compare with labels, they are created
// in the wrong order (right after elements) during import and
// mess up the positioning.
if (!element.labelTarget && child.labelTarget) {
return false;
}
return elementOrder.level < getOrder(child).level;
});
// if the element is already in the child list at
// a smaller index, we need to adjust the inser index.
// this takes into account that the element is being removed
// before being re-inserted
if (insertIndex !== -1) {
if (currentIndex !== -1 && currentIndex < insertIndex) {
insertIndex -= 1;
}
}
return {
index: insertIndex,
parent: newParent
};
};
}n/a
function BpmnRenderer(eventBus, styles, pathMap, canvas, priority) {
BaseRenderer.call(this, eventBus, priority);
var textUtil = new TextUtil({
style: LABEL_STYLE,
size: { width: 100 }
});
var markers = {};
var computeStyle = styles.computeStyle;
function addMarker(id, options) {
var attrs = assign({
fill: 'black',
strokeWidth: 1,
strokeLinecap: 'round',
strokeDasharray: 'none'
}, options.attrs);
var ref = options.ref || { x: 0, y: 0 };
var scale = options.scale || 1;
// fix for safari / chrome / firefox bug not correctly
// resetting stroke dash array
if (attrs.strokeDasharray === 'none') {
attrs.strokeDasharray = [10000, 1];
}
var marker = svgCreate('marker');
svgAttr(options.element, attrs);
svgAppend(marker, options.element);
svgAttr(marker, {
id: id,
viewBox: '0 0 20 20',
refX: ref.x,
refY: ref.y,
markerWidth: 20 * scale,
markerHeight: 20 * scale,
orient: 'auto'
});
var defs = domQuery('defs', canvas._svg);
if (!defs) {
defs = svgCreate('defs');
svgAppend(canvas._svg, defs);
}
svgAppend(defs, marker);
markers[id] = marker;
}
function marker(type, fill, stroke) {
var id = type + '-' + fill + '-' + stroke;
if (!markers[id]) {
createMarker(type, fill, stroke);
}
return 'url(#' + id + ')';
}
function createMarker(type, fill, stroke) {
var id = type + '-' + fill + '-' + stroke;
if (type === 'sequenceflow-end') {
var sequenceflowEnd = svgCreate('path');
svgAttr(sequenceflowEnd, { d: 'M 1 5 L 11 10 L 1 15 Z' });
addMarker(id, {
element: sequenceflowEnd,
ref: { x: 11, y: 10 },
scale: 0.5,
attrs: {
fill: stroke,
stroke: stroke
}
});
}
if (type === 'messageflow-start') {
var messageflowStart = svgCreate('circle');
svgAttr(messageflowStart, { cx: 6, cy: 6, r: 3.5 });
addMarker(id, {
element: messageflowStart,
attrs: {
fill: fill,
stroke: stroke
},
ref: { x: 6, y: 6 }
});
}
if (type === 'messageflow-end') {
var messageflowEnd = svgCreate('path');
svgAttr(messageflowEnd, { d: 'm 1 5 l 0 -3 l 7 3 l -7 3 z' });
addMarker(id, {
element: messageflowEnd,
attrs: {
fill: fill,
stroke: stroke,
strokeLinecap: 'butt'
},
ref: { x: 8.5, y: 5 }
});
}
if (type === 'association-start') {
var associationStart = svgCreate('path');
svgAttr(associationStart, { d: 'M 11 5 L 1 10 L 11 15' });
addMarker(id, {
element: associationStart,
attrs: {
fill: 'none',
stroke: stroke,
strokeWidth: 1.5
},
ref: { x: 1, y: 10 },
scale: 0.5
});
}
if (type === 'association-end') {
var associationEnd = svgCreate('path');
svgAttr(associationEnd, { d: 'M 1 5 L 11 10 L 1 15' });
addMarker(id, {
element: associationEnd,
attrs: {
fill: 'none',
stroke: stroke,
strokeWidth: 1.5
},
ref: { x: 12, y: 10 },
scale: 0.5
});
}
if (type === 'conditional-flow-marker') {
var conditionalflowMarker = svgCreate('path');
svgAttr(conditionalflowMarker, { d: 'M 0 10 L 8 6 L 16 10 L 8 14 Z' });
addMarker(id, {
element: conditionalflowMarker,
attrs: {
fill: fill,
stroke: stroke
},
ref: { x: -1, y: 10 },
scale: 0.5
});
}
if (type === 'conditional-default-flow-marker') {
var conditionaldefaultflowMarker = svgCreate('path');
svgAttr(conditionaldefaultflowMarker, { d: 'M 6 4 L 10 16' });
addMarker(id, {
element: conditionaldefaultflowMarker,
attrs: {
stroke: stroke
},
ref: { x: 0, y: 10 },
scale: 0.5
});
}
}
funct ...n/a
function BpmnReplacePreview(eventBus, elementRegistry, elementFactory, canvas, previewSupport) {
CommandInterceptor.call(this, eventBus);
/**
* Replace the visuals of all elements in the context which can be replaced
*
* @param {Object} context
*/
function replaceVisual(context) {
var replacements = context.canExecute.replacements;
forEach(replacements, function(replacement) {
var id = replacement.oldElementId;
var newElement = {
type: replacement.newElementType
};
// if the visual of the element is already replaced
if (context.visualReplacements[id]) {
return;
}
var element = elementRegistry.get(id);
assign(newElement, { x: element.x, y: element.y });
// create a temporary shape
var tempShape = elementFactory.createShape(newElement);
canvas.addShape(tempShape, element.parent);
// select the original SVG element related to the element and hide it
var gfx = domQuery('[data-element-id=' + element.id + ']', context.dragGroup);
if (gfx) {
svgAttr(gfx, { display: 'none' });
}
// clone the gfx of the temporary shape and add it to the drag group
var dragger = previewSupport.addDragger(tempShape, context.dragGroup);
context.visualReplacements[id] = dragger;
canvas.removeShape(tempShape);
});
}
/**
* Restore the original visuals of the previously replaced elements
*
* @param {Object} context
*/
function restoreVisual(context) {
var visualReplacements = context.visualReplacements;
forEach(visualReplacements, function(dragger, id) {
var originalGfx = domQuery('[data-element-id=' + id + ']', context.dragGroup);
if (originalGfx) {
svgAttr(originalGfx, { display: 'inline' });
}
dragger.remove();
if (visualReplacements[id]) {
delete visualReplacements[id];
}
});
}
eventBus.on('shape.move.move', LOW_PRIORITY, function(event) {
var context = event.context,
canExecute = context.canExecute;
if (!context.visualReplacements) {
context.visualReplacements = {};
}
if (canExecute.replacements) {
replaceVisual(context);
} else {
restoreVisual(context);
}
});
}n/a
function BpmnRules(eventBus) {
RuleProvider.call(this, eventBus);
}n/a
function BpmnSearchProvider(elementRegistry, searchPad, canvas) {
this._elementRegistry = elementRegistry;
this._canvas = canvas;
searchPad.registerProvider(this);
}n/a
function BpmnSnapping(eventBus, canvas, bpmnRules, elementRegistry) {
// instantiate super
Snapping.call(this, eventBus, canvas);
/**
* Drop participant on process <> process elements snapping
*/
eventBus.on('create.start', function(event) {
var context = event.context,
shape = context.shape,
rootElement = canvas.getRootElement();
// snap participant around existing elements (if any)
if (is(shape, 'bpmn:Participant') && is(rootElement, 'bpmn:Process')) {
initParticipantSnapping(context, shape, rootElement.children);
}
});
eventBus.on([ 'create.move', 'create.end' ], HIGH_PRIORITY, function(event) {
var context = event.context,
shape = context.shape,
participantSnapBox = context.participantSnapBox;
if (!isSnapped(event) && participantSnapBox) {
snapParticipant(participantSnapBox, shape, event);
}
});
eventBus.on('shape.move.start', function(event) {
var context = event.context,
shape = context.shape,
rootElement = canvas.getRootElement();
// snap participant around existing elements (if any)
if (is(shape, 'bpmn:Participant') && is(rootElement, 'bpmn:Process')) {
initParticipantSnapping(context, shape, rootElement.children);
}
});
function canAttach(shape, target, position) {
return bpmnRules.canAttach([ shape ], target, null, position) === 'attach';
}
function canConnect(source, target) {
return bpmnRules.canConnect(source, target);
}
/**
* Snap boundary events to elements border
*/
eventBus.on([
'create.move',
'create.end',
'shape.move.move',
'shape.move.end'
], HIGH_PRIORITY, function(event) {
var context = event.context,
target = context.target,
shape = context.shape;
if (target && !isSnapped(event) && canAttach(shape, target, event)) {
snapBoundaryEvent(event, shape, target);
}
});
/**
* Adjust parent for flowElements to the target participant
* when droping onto lanes.
*/
eventBus.on([
'shape.move.hover',
'shape.move.move',
'shape.move.end',
'create.hover',
'create.move',
'create.end'
], HIGH_PRIORITY, function(event) {
var context = event.context,
shape = context.shape,
hover = event.hover;
if (is(hover, 'bpmn:Lane') && !isAny(shape, [ 'bpmn:Lane', 'bpmn:Participant' ])) {
event.hover = getLanesRoot(hover);
event.hoverGfx = elementRegistry.getGraphics(event.hover);
}
});
/**
* Snap sequence flows.
*/
eventBus.on([
'connect.move',
'connect.hover',
'connect.end'
], HIGH_PRIORITY, function(event) {
var context = event.context,
source = context.source,
target = context.target;
var connection = canConnect(source, target) || {};
if (!context.initialSourcePosition) {
context.initialSourcePosition = context.sourcePosition;
}
if (target && connection.type === 'bpmn:SequenceFlow') {
// snap source
context.sourcePosition = mid(source);
// snap target
assign(event, mid(target));
} else {
// otherwise reset source snap
context.sourcePosition = context.initialSourcePosition;
}
});
eventBus.on([
'create.move',
'shape.move.move'
], function(event) {
var context = event.context,
shape = context.shape,
target = context.target;
var threshold = 30;
if (is(shape, 'bpmn:Lane')) {
if (isAny(target, [ 'bpmn:Lane', 'bpmn:Participant' ])) {
var childLanes = filter(target.children, function(c) {
return is(c, 'bpmn:Lane');
});
var y = event.y,
targetTrbl;
var insert = childLanes.reduce(function(insert, l) {
var laneTrbl = asTRBL(l);
if (abs(laneTrbl.top - y) < threshold) {
insert = assign(insert || {}, { before: { element: l, y: laneTrbl.top } });
} else
if (abs(laneTrbl.bottom - y) < threshold) {
insert = assign(insert || {}, { after: { element: ...n/a
function BpmnUpdater(eventBus, bpmnFactory, connectionDocking, translate) {
CommandInterceptor.call(this, eventBus);
this._bpmnFactory = bpmnFactory;
this._translate = translate;
var self = this;
////// connection cropping /////////////////////////
// crop connection ends during create/update
function cropConnection(e) {
var context = e.context,
connection;
if (!context.cropped) {
connection = context.connection;
connection.waypoints = connectionDocking.getCroppedWaypoints(connection);
context.cropped = true;
}
}
this.executed([
'connection.layout',
'connection.create',
'connection.reconnectEnd',
'connection.reconnectStart'
], cropConnection);
this.reverted([ 'connection.layout' ], function(e) {
delete e.context.cropped;
});
////// BPMN + DI update /////////////////////////
// update parent
function updateParent(e) {
var context = e.context;
self.updateParent(context.shape || context.connection, context.oldParent);
}
function reverseUpdateParent(e) {
var context = e.context;
var element = context.shape || context.connection,
// oldParent is the (old) new parent, because we are undoing
oldParent = context.parent || context.newParent;
self.updateParent(element, oldParent);
}
this.executed([ 'shape.move',
'shape.create',
'shape.delete',
'connection.create',
'connection.move',
'connection.delete' ], ifBpmn(updateParent));
this.reverted([ 'shape.move',
'shape.create',
'shape.delete',
'connection.create',
'connection.move',
'connection.delete' ], ifBpmn(reverseUpdateParent));
/*
* ## Updating Parent
*
* When morphing a Process into a Collaboration or vice-versa,
* make sure that both the *semantic* and *di* parent of each element
* is updated.
*
*/
function updateRoot(event) {
var context = event.context,
oldRoot = context.oldRoot,
children = oldRoot.children;
forEach(children, function(child) {
if (is(child, 'bpmn:BaseElement')) {
self.updateParent(child);
}
});
}
this.executed([ 'canvas.updateRoot' ], updateRoot);
this.reverted([ 'canvas.updateRoot' ], updateRoot);
// update bounds
function updateBounds(e) {
var shape = e.context.shape;
if (!is(shape, 'bpmn:BaseElement')) {
return;
}
self.updateBounds(shape);
}
this.executed([ 'shape.move', 'shape.create', 'shape.resize' ], ifBpmn(function(event) {
// exclude labels because they're handled separately during shape.changed
if (event.context.shape.type === 'label') {
return;
}
updateBounds(event);
}));
this.reverted([ 'shape.move', 'shape.create', 'shape.resize' ], ifBpmn(function(event) {
// exclude labels because they're handled separately during shape.changed
if (event.context.shape.type === 'label') {
return;
}
updateBounds(event);
}));
// Handle labels separately. This is necessary, because the label bounds have to be updated
// every time its shape changes, not only on move, create and resize.
eventBus.on('shape.changed', function(event) {
if (event.element.type === 'label') {
updateBounds({ context: { shape: event.element } });
}
});
// attach / detach connection
function updateConnection(e) {
self.updateConnection(e.context);
}
this.executed([
'connection.create',
'connection.move',
'connection.delete',
'connection.reconnectEnd',
'connection.reconnectStart'
], ifBpmn(updateConnection));
this.reverted([
'connection.create',
'connection.move',
'connection.delete',
'connection.reconnectEnd',
'connection.reconnectStart'
], ifBpmn(updateConnection));
// update waypoints
function updateConnectionWaypoints(e) {
self.updateConnectionWaypoints(e.context.connection);
}
this.executed([ ...n/a
function ContextPadProvider(eventBus, contextPad, modeling, elementFactory, connect, create, popupMenu, canvas, rules, translate) {
contextPad.registerProvider(this);
this._contextPad = contextPad;
this._modeling = modeling;
this._elementFactory = elementFactory;
this._connect = connect;
this._create = create;
this._popupMenu = popupMenu;
this._canvas = canvas;
this._rules = rules;
this._translate = translate;
eventBus.on('create.end', 250, function(event) {
var shape = event.context.shape;
if (!hasPrimaryModifier(event)) {
return;
}
var entries = contextPad.getEntries(shape);
if (entries.replace) {
entries.replace.action.click(event, shape);
}
});
}n/a
function ElementFactory(bpmnFactory, moddle, translate) {
BaseElementFactory.call(this);
this._bpmnFactory = bpmnFactory;
this._moddle = moddle;
this._translate = translate;
}n/a
function LabelEditingProvider(eventBus, canvas, directEditing, commandStack) {
this._canvas = canvas;
this._commandStack = commandStack;
directEditing.registerProvider(this);
commandStack.registerHandler('element.updateLabel', UpdateLabelHandler);
// listen to dblclick on non-root elements
eventBus.on('element.dblclick', function(event) {
directEditing.activate(event.element);
});
// complete on followup canvas operation
eventBus.on([ 'element.mousedown', 'drag.init', 'canvas.viewbox.changed' ], function(event) {
directEditing.complete();
});
// cancel on command stack changes
eventBus.on([ 'commandStack.changed' ], function() {
directEditing.cancel();
});
if ('ontouchstart' in document.documentElement) {
// we deactivate automatic label editing on mobile devices
// as it breaks the user interaction workflow
// TODO(nre): we should temporarily focus the edited element here
// and release the focused viewport after the direct edit operation is finished
} else {
eventBus.on('create.end', 500, function(e) {
var element = e.shape,
canExecute = e.context.canExecute;
if (!canExecute) {
return;
}
if (is(element, 'bpmn:Task') || is(element, 'bpmn:TextAnnotation') ||
(is(element, 'bpmn:SubProcess') && !isExpanded(element))) {
directEditing.activate(element);
}
});
}
}n/a
function ModelCloneHelper(eventBus) {
this._eventBus = eventBus;
}n/a
function Modeling(eventBus, elementFactory, commandStack, bpmnRules) {
BaseModeling.call(this, eventBus, elementFactory, commandStack);
this._bpmnRules = bpmnRules;
}n/a
function PaletteProvider(palette, create, elementFactory, spaceTool, lassoTool, handTool, globalConnect, translate) {
this._palette = palette;
this._create = create;
this._elementFactory = elementFactory;
this._spaceTool = spaceTool;
this._lassoTool = lassoTool;
this._handTool = handTool;
this._globalConnect = globalConnect;
this._translate = translate;
palette.registerProvider(this);
}n/a
function ReplaceMenuProvider(popupMenu, modeling, moddle, bpmnReplace, rules, translate) {
this._popupMenu = popupMenu;
this._modeling = modeling;
this._moddle = moddle;
this._bpmnReplace = bpmnReplace;
this._rules = rules;
this._translate = translate;
this.register();
}n/a
function BpmnAutoResize(eventBus, elementRegistry, modeling, rules) {
AutoResize.call(this, eventBus, elementRegistry, modeling, rules);
}n/a
function AutoResize(eventBus, elementRegistry, modeling, rules) {
CommandInterceptor.call(this, eventBus);
this._elementRegistry = elementRegistry;
this._modeling = modeling;
this._rules = rules;
var self = this;
this.postExecuted([ 'shape.create' ], function(event) {
var context = event.context,
hints = context.hints,
shape = context.shape,
parent = context.parent || context.newParent;
if (hints && hints.root === false) {
return;
}
self._expand([ shape ], parent);
});
this.postExecuted([ 'elements.move' ], function(event) {
var context = event.context,
elements = flatten(values(context.closure.topLevel)),
hints = context.hints;
if (hints && hints.autoResize === false) {
return;
}
var expandings = groupBy(elements, function(element) {
return element.parent.id;
});
forEach(expandings, function(elements, parentId) {
self._expand(elements, parentId);
});
});
}n/a
resize = function (target, newBounds) {
if (is(target, 'bpmn:Participant')) {
this._modeling.resizeLane(target, newBounds);
} else {
this._modeling.resizeShape(target, newBounds);
}
}n/a
function BpmnAutoResizeProvider(eventBus, modeling) {
AutoResizeProvider.call(this, eventBus);
this._modeling = modeling;
}n/a
function AutoResizeProvider(eventBus) {
RuleProvider.call(this, eventBus);
var self = this;
this.addRule('element.autoResize', function(context) {
return self.canResize(context.elements, context.target);
});
}n/a
canResize = function (elements, target) {
if (!is(target, 'bpmn:Participant') && !is(target, 'bpmn:Lane') && !(is(target, 'bpmn:SubProcess'))) {
return false;
}
var canResize = true;
forEach(elements, function(element) {
if (is(element, 'bpmn:Lane') || element.labelTarget) {
canResize = false;
return;
}
});
return canResize;
}n/a
function BpmnEditorActions( injector, canvas, elementRegistry, selection, spaceTool, lassoTool, handTool, globalConnect, distributeElements, alignElements, directEditing, searchPad, modeling) {
injector.invoke(EditorActions, this);
this.register({
selectElements: function() {
// select all elements except for the invisible
// root element
var rootElement = canvas.getRootElement();
var elements = elementRegistry.filter(function(element) {
return element !== rootElement;
});
selection.select(elements);
return elements;
},
spaceTool: function() {
spaceTool.toggle();
},
lassoTool: function() {
lassoTool.toggle();
},
handTool: function() {
handTool.toggle();
},
globalConnectTool: function() {
globalConnect.toggle();
},
distributeElements: function(opts) {
var currentSelection = selection.get(),
type = opts.type;
if (currentSelection.length) {
distributeElements.trigger(currentSelection, type);
}
},
alignElements: function(opts) {
var currentSelection = selection.get(),
aligneableElements = [],
type = opts.type;
if (currentSelection.length) {
aligneableElements = filter(currentSelection, function(element) {
return !is(element, 'bpmn:Lane');
});
alignElements.trigger(aligneableElements, type);
}
},
setColor: function(opts) {
var currentSelection = selection.get();
if (currentSelection.length) {
modeling.setColor(currentSelection, opts);
}
},
directEditing: function() {
var currentSelection = selection.get();
if (currentSelection.length) {
directEditing.activate(currentSelection[0]);
}
},
find: function() {
searchPad.toggle();
},
moveToOrigin: function() {
var rootElement = canvas.getRootElement(),
boundingBox,
elements;
if (is(rootElement, 'bpmn:Collaboration')) {
elements = elementRegistry.filter(function(element) {
return is(element.parent, 'bpmn:Collaboration');
});
} else {
elements = elementRegistry.filter(function(element) {
return element !== rootElement && !is(element.parent, 'bpmn:SubProcess');
});
}
boundingBox = getBBox(elements);
modeling.moveElements(elements, { x: -boundingBox.x, y: -boundingBox.y }, rootElement);
}
});
}n/a
function EditorActions(eventBus, commandStack, modeling, selection, zoomScroll, copyPaste, canvas, rules, mouseTracking) {
this._actions = {
undo: function() {
commandStack.undo();
},
redo: function() {
commandStack.redo();
},
copy: function() {
var selectedElements = selection.get();
copyPaste.copy(selectedElements);
},
paste: function() {
var context = mouseTracking.getHoverContext();
copyPaste.paste(context);
},
stepZoom: function(opts) {
zoomScroll.stepZoom(opts.value);
},
zoom: function(opts) {
canvas.zoom(opts.value);
},
removeSelection: function() {
var selectedElements = selection.get();
if (selectedElements.length) {
var allowed = rules.allowed('elements.delete', { elements: selectedElements }),
removableElements;
if (allowed === false) {
return;
}
else if (isArray(allowed)) {
removableElements = allowed;
}
else {
removableElements = selectedElements;
}
if (removableElements.length) {
modeling.removeElements(removableElements.slice());
}
}
},
moveCanvas: function(opts) {
var dx = 0,
dy = 0,
invertY = opts.invertY,
speed = opts.speed;
var actualSpeed = speed / Math.min(Math.sqrt(canvas.viewbox().scale), 1);
switch (opts.direction) {
case 'left': // Left
dx = actualSpeed;
break;
case 'up': // Up
dy = actualSpeed;
break;
case 'right': // Right
dx = -actualSpeed;
break;
case 'down': // Down
dy = -actualSpeed;
break;
}
if (dy && invertY) {
dy = -dy;
}
canvas.scroll({ dx: dx, dy: dy });
}
};
}n/a
function BpmnFactory(moddle) {
this._model = moddle;
}n/a
_ensureId = function (element) {
// generate semantic ids for elements
// bpmn:SequenceFlow -> SequenceFlow_ID
var prefix = (element.$type || '').replace(/^[^:]*:/g, '') + '_';
if (!element.id && this._needsId(element)) {
element.id = this._model.ids.nextPrefixed(prefix, element);
}
}...
businessObject = descriptor.businessObject;
// remove the id or else we cannot paste multiple times
delete businessObject.id;
// assign an ID
bpmnFactory._ensureId(businessObject);
if (descriptor.type === 'bpmn:Participant' && descriptor.processRef) {
descriptor.processRef = businessObject.processRef = bpmnFactory.create('bpmn:Process');
}
setProperties(businessObject, descriptor, [
'isExpanded',
..._needsId = function (element) {
return element.$instanceOf('bpmn:RootElement') ||
element.$instanceOf('bpmn:FlowElement') ||
element.$instanceOf('bpmn:MessageFlow') ||
element.$instanceOf('bpmn:DataAssociation') ||
element.$instanceOf('bpmn:Artifact') ||
element.$instanceOf('bpmn:Participant') ||
element.$instanceOf('bpmn:Lane') ||
element.$instanceOf('bpmn:Process') ||
element.$instanceOf('bpmn:Collaboration') ||
element.$instanceOf('bpmndi:BPMNShape') ||
element.$instanceOf('bpmndi:BPMNEdge') ||
element.$instanceOf('bpmndi:BPMNDiagram') ||
element.$instanceOf('bpmndi:BPMNPlane') ||
element.$instanceOf('bpmn:Property');
}...
BpmnFactory.prototype._ensureId = function(element) {
// generate semantic ids for elements
// bpmn:SequenceFlow -> SequenceFlow_ID
var prefix = (element.$type || '').replace(/^[^:]*:/g, '') + '_';
if (!element.id && this._needsId(element)) {
element.id = this._model.ids.nextPrefixed(prefix, element);
}
};
BpmnFactory.prototype.create = function(type, attrs) {
var element = this._model.create(type, attrs || {});
...create = function (type, attrs) {
var element = this._model.create(type, attrs || {});
this._ensureId(element);
return element;
}...
});
}
}
var replaceMenu;
if (popupMenu._providers['bpmn-replace']) {
replaceMenu = popupMenu.create('bpmn-replace', element);
}
if (replaceMenu && !replaceMenu.isEmpty()) {
// Replace menu entry
assign(actions, {
'replace': {
...createDiBounds = function (bounds) {
return this.create('dc:Bounds', bounds);
}...
return element;
};
BpmnFactory.prototype.createDiLabel = function() {
return this.create('bpmndi:BPMNLabel', {
bounds: this.createDiBounds()
});
};
BpmnFactory.prototype.createDiShape = function(semantic, bounds, attrs) {
return this.create('bpmndi:BPMNShape', assign({
...createDiEdge = function (semantic, waypoints, attrs) {
return this.create('bpmndi:BPMNEdge', assign({
bpmnElement: semantic
}, attrs));
}...
if (!businessObject.di) {
if (elementType === 'root') {
businessObject.di = this._bpmnFactory.createDiPlane(businessObject, [], {
id: businessObject.id + '_di'
});
} else
if (elementType === 'connection') {
businessObject.di = this._bpmnFactory.createDiEdge(businessObject, [], {
id: businessObject.id + '_di'
});
} else {
businessObject.di = this._bpmnFactory.createDiShape(businessObject, {}, {
id: businessObject.id + '_di'
});
}
...createDiLabel = function () {
return this.create('bpmndi:BPMNLabel', {
bounds: this.createDiBounds()
});
}...
};
/////// helpers /////////////////////////////////////////
BpmnUpdater.prototype._getLabel = function(di) {
if (!di.label) {
di.label = this._bpmnFactory.createDiLabel();
}
return di.label;
};
/**
...createDiPlane = function (semantic) {
return this.create('bpmndi:BPMNPlane', {
bpmnElement: semantic
});
}...
}
businessObject = this._bpmnFactory.create(attrs.type);
}
if (!businessObject.di) {
if (elementType === 'root') {
businessObject.di = this._bpmnFactory.createDiPlane(businessObject, [], {
id: businessObject.id + '_di'
});
} else
if (elementType === 'connection') {
businessObject.di = this._bpmnFactory.createDiEdge(businessObject, [], {
id: businessObject.id + '_di'
});
...createDiShape = function (semantic, bounds, attrs) {
return this.create('bpmndi:BPMNShape', assign({
bpmnElement: semantic,
bounds: this.createDiBounds(bounds)
}, attrs));
}...
});
} else
if (elementType === 'connection') {
businessObject.di = this._bpmnFactory.createDiEdge(businessObject, [], {
id: businessObject.id + '_di'
});
} else {
businessObject.di = this._bpmnFactory.createDiShape(businessObject, {}, {
id: businessObject.id + '_di'
});
}
}
if (attrs.colors) {
assign(businessObject.di, attrs.colors);
...createDiWaypoint = function (point) {
return this.create('dc:Point', pick(point, [ 'x', 'y' ]));
}...
BpmnFactory.prototype.createDiBounds = function(bounds) {
return this.create('dc:Bounds', bounds);
};
BpmnFactory.prototype.createDiWaypoints = function(waypoints) {
return map(waypoints, function(pos) {
return this.createDiWaypoint(pos);
}, this);
};
BpmnFactory.prototype.createDiWaypoint = function(point) {
return this.create('dc:Point', pick(point, [ 'x', 'y' ]));
};
...createDiWaypoints = function (waypoints) {
return map(waypoints, function(pos) {
return this.createDiWaypoint(pos);
}, this);
}...
diChildren.push(businessObject);
}
}
};
BpmnUpdater.prototype.updateConnectionWaypoints = function(connection) {
connection.businessObject.di.set('waypoint', this._bpmnFactory.createDiWaypoints
span>(connection.waypoints));
};
BpmnUpdater.prototype.updateConnection = function(context) {
var connection = context.connection,
businessObject = getBusinessObject(connection),
...function BpmnGlobalConnect(globalConnect) {
globalConnect.registerProvider(this);
}n/a
canStartConnect = function (source) {
if (nonExistantOrLabel(source)) {
return null;
}
var businessObject = source.businessObject;
return isAny(businessObject, [
'bpmn:FlowNode',
'bpmn:InteractionNode',
'bpmn:DataObjectReference',
'bpmn:DataStoreReference'
]);
}n/a
function BpmnImporter(eventBus, canvas, elementFactory, elementRegistry, translate) {
this._eventBus = eventBus;
this._canvas = canvas;
this._elementFactory = elementFactory;
this._elementRegistry = elementRegistry;
this._translate = translate;
this._textUtil = new TextUtil();
}n/a
_attachBoundary = function (boundarySemantic, boundaryElement) {
var translate = this._translate;
var hostSemantic = boundarySemantic.attachedToRef;
if (!hostSemantic) {
throw new Error(translate('missing {semantic}#attachedToRef', {
semantic: elementToString(boundarySemantic)
}));
}
var host = this._elementRegistry.get(hostSemantic.id),
attachers = host && host.attachers;
if (!host) {
throw notYetDrawn(translate, boundarySemantic, hostSemantic, 'attachedToRef');
}
// wire element.host <> host.attachers
boundaryElement.host = host;
if (!attachers) {
host.attachers = attachers = [];
}
if (attachers.indexOf(boundaryElement) === -1) {
attachers.push(boundaryElement);
}
}...
x: Math.round(bounds.x),
y: Math.round(bounds.y),
width: Math.round(bounds.width),
height: Math.round(bounds.height)
}));
if (is(semantic, 'bpmn:BoundaryEvent')) {
this._attachBoundary(semantic, element);
}
this._canvas.addShape(element, parentElement);
}
// CONNECTION
else if (is(di, 'bpmndi:BPMNEdge')) {
..._getElement = function (semantic) {
return this._elementRegistry.get(semantic.id);
}...
// fix source / target for DataInputAssociation / DataOutputAssociation
if (side === 'source' && type === 'bpmn:DataOutputAssociation' ||
side === 'target' && type === 'bpmn:DataInputAssociation') {
refSemantic = semantic.$parent;
}
element = refSemantic && this._getElement(refSemantic);
if (element) {
return element;
}
if (refSemantic) {
throw notYetDrawn(translate, semantic, refSemantic, side + 'Ref');
..._getEnd = function (semantic, side) {
var element,
refSemantic,
type = semantic.$type,
translate = this._translate;
refSemantic = semantic[side + 'Ref'];
// handle mysterious isMany DataAssociation#sourceRef
if (side === 'source' && type === 'bpmn:DataInputAssociation') {
refSemantic = refSemantic && refSemantic[0];
}
// fix source / target for DataInputAssociation / DataOutputAssociation
if (side === 'source' && type === 'bpmn:DataOutputAssociation' ||
side === 'target' && type === 'bpmn:DataInputAssociation') {
refSemantic = semantic.$parent;
}
element = refSemantic && this._getElement(refSemantic);
if (element) {
return element;
}
if (refSemantic) {
throw notYetDrawn(translate, semantic, refSemantic, side + 'Ref');
} else {
throw new Error(translate('{semantic}#{side} Ref not specified', {
semantic: elementToString(semantic),
side: side
}));
}
}...
semantic: elementToString(semantic),
side: side
}));
}
};
BpmnImporter.prototype._getSource = function(semantic) {
return this._getEnd(semantic, 'source');
};
BpmnImporter.prototype._getTarget = function(semantic) {
return this._getEnd(semantic, 'target');
};
..._getSource = function (semantic) {
return this._getEnd(semantic, 'source');
}...
this._canvas.addShape(element, parentElement);
}
// CONNECTION
else if (is(di, 'bpmndi:BPMNEdge')) {
var source = this._getSource(semantic),
target = this._getTarget(semantic);
hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
element = this._elementFactory.createConnection(elementData(semantic, {
hidden: hidden,
source: source,
..._getTarget = function (semantic) {
return this._getEnd(semantic, 'target');
}...
this._canvas.addShape(element, parentElement);
}
// CONNECTION
else if (is(di, 'bpmndi:BPMNEdge')) {
var source = this._getSource(semantic),
target = this._getTarget(semantic);
hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
element = this._elementFactory.createConnection(elementData(semantic, {
hidden: hidden,
source: source,
target: target,
...add = function (semantic, parentElement) {
var di = semantic.di,
element,
translate = this._translate,
hidden;
// ROOT ELEMENT
// handle the special case that we deal with a
// invisible root element (process or collaboration)
if (is(di, 'bpmndi:BPMNPlane')) {
// add a virtual element (not being drawn)
element = this._elementFactory.createRoot(elementData(semantic));
this._canvas.setRootElement(element);
}
// SHAPE
else if (is(di, 'bpmndi:BPMNShape')) {
var collapsed = !isExpanded(semantic);
hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
var bounds = semantic.di.bounds;
element = this._elementFactory.createShape(elementData(semantic, {
collapsed: collapsed,
hidden: hidden,
x: Math.round(bounds.x),
y: Math.round(bounds.y),
width: Math.round(bounds.width),
height: Math.round(bounds.height)
}));
if (is(semantic, 'bpmn:BoundaryEvent')) {
this._attachBoundary(semantic, element);
}
this._canvas.addShape(element, parentElement);
}
// CONNECTION
else if (is(di, 'bpmndi:BPMNEdge')) {
var source = this._getSource(semantic),
target = this._getTarget(semantic);
hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
element = this._elementFactory.createConnection(elementData(semantic, {
hidden: hidden,
source: source,
target: target,
waypoints: collectWaypoints(semantic.di.waypoint)
}));
if (is(semantic, 'bpmn:DataAssociation')) {
// render always on top; this ensures DataAssociations
// are rendered correctly across different "hacks" people
// love to model such as cross participant / sub process
// associations
parentElement = null;
}
this._canvas.addConnection(element, parentElement);
} else {
throw new Error(translate('unknown di {di} for element {semantic}', {
di: elementToString(di),
semantic: elementToString(semantic)
}));
}
// (optional) LABEL
if (hasExternalLabel(semantic)) {
this.addLabel(semantic, element);
}
this._eventBus.fire('bpmnElement.added', { element: element });
return element;
}...
var banner = grunt.template.process(BANNER, grunt.config.get()),
bannerMin = grunt.template.process(BANNER_MIN, grunt.config.get());
browserify(browserifyOptions)
.plugin(derequire)
.plugin(collapse)
.add(src)
.bundle(function(err, result) {
timer.done('bundled');
if (err) {
return done(err);
}
...addLabel = function (semantic, element) {
var bounds,
text,
label;
bounds = getExternalLabelBounds(semantic, element);
text = semantic.name;
if (text) {
// get corrected bounds from actual layouted text
bounds = getLayoutedBounds(bounds, text, this._textUtil);
}
label = this._elementFactory.createLabel(elementData(semantic, {
id: semantic.id + '_label',
labelTarget: element,
type: 'label',
hidden: element.hidden || !semantic.name,
x: Math.round(bounds.x),
y: Math.round(bounds.y),
width: Math.round(bounds.width),
height: Math.round(bounds.height)
}));
return this._canvas.addShape(label, element.parent);
}...
throw new Error(translate('unknown di {di} for element {semantic}', {
di: elementToString(di),
semantic: elementToString(semantic)
}));
}
// (optional) LABEL
if (hasExternalLabel(semantic)) {
this.addLabel(semantic, element);
}
this._eventBus.fire('bpmnElement.added', { element: element });
return element;
};
...function BpmnLayouter() {}n/a
function BaseLayouter() {}n/a
layoutConnection = function (connection, hints) {
hints = hints || {};
var source = connection.source,
target = connection.target,
waypoints = connection.waypoints,
start = hints.connectionStart,
end = hints.connectionEnd;
var manhattanOptions,
updatedWaypoints;
if (!start) {
start = getConnectionDocking(waypoints && waypoints[0], source);
}
if (!end) {
end = getConnectionDocking(waypoints && waypoints[waypoints.length - 1], target);
}
// TODO(nikku): support vertical modeling
// and invert preferredLayouts accordingly
if (is(connection, 'bpmn:Association') ||
is(connection, 'bpmn:DataAssociation')) {
if (waypoints && !isCompensationAssociation(connection)) {
return [].concat([ start ], waypoints.slice(1, -1), [ end ]);
}
}
// manhattan layout sequence / message flows
if (is(connection, 'bpmn:MessageFlow')) {
manhattanOptions = {
preferredLayouts: [ 'v:v' ]
};
if (is(target, 'bpmn:Participant')) {
manhattanOptions = {
preferredLayouts: [ 'straight', 'v:v' ]
};
}
if (isExpandedSubProcess(target)) {
manhattanOptions = {
preferredLayouts: [ 'straight', 'v:v' ]
};
}
if (isExpandedSubProcess(source) && is(target, 'bpmn:FlowNode')) {
manhattanOptions = {
preferredLayouts: [ 'straight', 'v:v' ],
preserveDocking: isExpandedSubProcess(target) ? 'source' : 'target'
};
}
if (is(source, 'bpmn:Participant') && is(target, 'bpmn:FlowNode')) {
manhattanOptions = {
preferredLayouts: [ 'straight', 'v:v' ],
preserveDocking: 'target'
};
}
if (is(target, 'bpmn:Event')) {
manhattanOptions = {
preferredLayouts: [ 'v:v' ]
};
}
} else
// layout all connection between flow elements h:h,
//
// except for
//
// (1) outgoing of BoundaryEvents -> layout h:v or v:h based on attach orientation
// (2) incoming / outgoing of Gateway -> v:h (outgoing), h:v (incoming)
//
if (is(connection, 'bpmn:SequenceFlow') ||
isCompensationAssociation(connection)) {
// make sure boundary event connections do
// not look ugly =:>
if (is(source, 'bpmn:BoundaryEvent')) {
var orientation = getAttachOrientation(source);
if (/left|right/.test(orientation)) {
manhattanOptions = {
preferredLayouts: [ 'h:v' ]
};
} else
if (/top|bottom/.test(orientation)) {
manhattanOptions = {
preferredLayouts: [ 'v:h' ]
};
}
} else
if (is(source, 'bpmn:Gateway')) {
manhattanOptions = {
preferredLayouts: [ 'v:h' ]
};
} else
if (is(target, 'bpmn:Gateway')) {
manhattanOptions = {
preferredLayouts: [ 'h:v' ]
};
}
// apply horizontal love <3
else {
manhattanOptions = {
preferredLayouts: [ 'h:h' ]
};
}
}
if (manhattanOptions) {
manhattanOptions = assign(manhattanOptions, hints);
updatedWaypoints =
ManhattanLayout.repairConnection(
source, target,
start, end,
waypoints,
manhattanOptions);
}
return updatedWaypoints || [ start, end ];
}n/a
function BpmnOrderingProvider(eventBus, translate) {
OrderingProvider.call(this, eventBus);
var orders = [
{ type: 'bpmn:SubProcess', order: { level: 6 } },
{
type: 'bpmn:SequenceFlow',
order: {
level: 5,
containers: [
'bpmn:Participant',
'bpmn:FlowElementsContainer'
]
}
},
// handle DataAssociation(s) like message flows and render them always on top
{ type: 'bpmn:DataAssociation', order: { level: 9, containers: [ 'bpmn:Collaboration', 'bpmn:Process' ] } },
{ type: 'bpmn:MessageFlow', order: { level: 9, containers: [ 'bpmn:Collaboration' ] } },
{
type: 'bpmn:Association',
order: {
level: 6,
containers: [
'bpmn:Participant',
'bpmn:FlowElementsContainer',
'bpmn:Collaboration'
]
}
},
{ type: 'bpmn:BoundaryEvent', order: { level: 8 } },
{ type: 'bpmn:Participant', order: { level: -2 } },
{ type: 'bpmn:Lane', order: { level: -1 } }
];
function computeOrder(element) {
if (element.labelTarget) {
return { level: 10 };
}
var entry = find(orders, function(o) {
return isAny(element, [ o.type ]);
});
return entry && entry.order || { level: 1 };
}
function getOrder(element) {
var order = element.order;
if (!order) {
element.order = order = computeOrder(element);
}
return order;
}
function findActualParent(element, newParent, containers) {
var actualParent = newParent;
while (actualParent) {
if (isAny(actualParent, containers)) {
break;
}
actualParent = actualParent.parent;
}
if (!actualParent) {
throw new Error(translate('no parent for {element} in {parent}', {
element: element.id,
parent: newParent.id
}));
}
return actualParent;
}
this.getOrdering = function(element, newParent) {
var elementOrder = getOrder(element);
if (elementOrder.containers) {
newParent = findActualParent(element, newParent, elementOrder.containers);
}
var currentIndex = newParent.children.indexOf(element);
var insertIndex = findIndex(newParent.children, function(child) {
// do not compare with labels, they are created
// in the wrong order (right after elements) during import and
// mess up the positioning.
if (!element.labelTarget && child.labelTarget) {
return false;
}
return elementOrder.level < getOrder(child).level;
});
// if the element is already in the child list at
// a smaller index, we need to adjust the inser index.
// this takes into account that the element is being removed
// before being re-inserted
if (insertIndex !== -1) {
if (currentIndex !== -1 && currentIndex < insertIndex) {
insertIndex -= 1;
}
}
return {
index: insertIndex,
parent: newParent
};
};
}n/a
function OrderingProvider(eventBus) {
CommandInterceptor.call(this, eventBus);
var self = this;
this.preExecute([ 'shape.create', 'connection.create' ], function(event) {
var context = event.context,
element = context.shape || context.connection,
parent = context.parent;
var ordering = self.getOrdering(element, parent);
if (ordering) {
if (ordering.parent !== undefined) {
context.parent = ordering.parent;
}
context.parentIndex = ordering.index;
}
});
this.preExecute([ 'shape.move', 'connection.move' ], function(event) {
var context = event.context,
element = context.shape || context.connection,
parent = context.newParent || element.parent;
var ordering = self.getOrdering(element, parent);
if (ordering) {
if (ordering.parent !== undefined) {
context.newParent = ordering.parent;
}
context.newParentIndex = ordering.index;
}
});
}n/a
function BpmnRenderer(eventBus, styles, pathMap, canvas, priority) {
BaseRenderer.call(this, eventBus, priority);
var textUtil = new TextUtil({
style: LABEL_STYLE,
size: { width: 100 }
});
var markers = {};
var computeStyle = styles.computeStyle;
function addMarker(id, options) {
var attrs = assign({
fill: 'black',
strokeWidth: 1,
strokeLinecap: 'round',
strokeDasharray: 'none'
}, options.attrs);
var ref = options.ref || { x: 0, y: 0 };
var scale = options.scale || 1;
// fix for safari / chrome / firefox bug not correctly
// resetting stroke dash array
if (attrs.strokeDasharray === 'none') {
attrs.strokeDasharray = [10000, 1];
}
var marker = svgCreate('marker');
svgAttr(options.element, attrs);
svgAppend(marker, options.element);
svgAttr(marker, {
id: id,
viewBox: '0 0 20 20',
refX: ref.x,
refY: ref.y,
markerWidth: 20 * scale,
markerHeight: 20 * scale,
orient: 'auto'
});
var defs = domQuery('defs', canvas._svg);
if (!defs) {
defs = svgCreate('defs');
svgAppend(canvas._svg, defs);
}
svgAppend(defs, marker);
markers[id] = marker;
}
function marker(type, fill, stroke) {
var id = type + '-' + fill + '-' + stroke;
if (!markers[id]) {
createMarker(type, fill, stroke);
}
return 'url(#' + id + ')';
}
function createMarker(type, fill, stroke) {
var id = type + '-' + fill + '-' + stroke;
if (type === 'sequenceflow-end') {
var sequenceflowEnd = svgCreate('path');
svgAttr(sequenceflowEnd, { d: 'M 1 5 L 11 10 L 1 15 Z' });
addMarker(id, {
element: sequenceflowEnd,
ref: { x: 11, y: 10 },
scale: 0.5,
attrs: {
fill: stroke,
stroke: stroke
}
});
}
if (type === 'messageflow-start') {
var messageflowStart = svgCreate('circle');
svgAttr(messageflowStart, { cx: 6, cy: 6, r: 3.5 });
addMarker(id, {
element: messageflowStart,
attrs: {
fill: fill,
stroke: stroke
},
ref: { x: 6, y: 6 }
});
}
if (type === 'messageflow-end') {
var messageflowEnd = svgCreate('path');
svgAttr(messageflowEnd, { d: 'm 1 5 l 0 -3 l 7 3 l -7 3 z' });
addMarker(id, {
element: messageflowEnd,
attrs: {
fill: fill,
stroke: stroke,
strokeLinecap: 'butt'
},
ref: { x: 8.5, y: 5 }
});
}
if (type === 'association-start') {
var associationStart = svgCreate('path');
svgAttr(associationStart, { d: 'M 11 5 L 1 10 L 11 15' });
addMarker(id, {
element: associationStart,
attrs: {
fill: 'none',
stroke: stroke,
strokeWidth: 1.5
},
ref: { x: 1, y: 10 },
scale: 0.5
});
}
if (type === 'association-end') {
var associationEnd = svgCreate('path');
svgAttr(associationEnd, { d: 'M 1 5 L 11 10 L 1 15' });
addMarker(id, {
element: associationEnd,
attrs: {
fill: 'none',
stroke: stroke,
strokeWidth: 1.5
},
ref: { x: 12, y: 10 },
scale: 0.5
});
}
if (type === 'conditional-flow-marker') {
var conditionalflowMarker = svgCreate('path');
svgAttr(conditionalflowMarker, { d: 'M 0 10 L 8 6 L 16 10 L 8 14 Z' });
addMarker(id, {
element: conditionalflowMarker,
attrs: {
fill: fill,
stroke: stroke
},
ref: { x: -1, y: 10 },
scale: 0.5
});
}
if (type === 'conditional-default-flow-marker') {
var conditionaldefaultflowMarker = svgCreate('path');
svgAttr(conditionaldefaultflowMarker, { d: 'M 6 4 L 10 16' });
addMarker(id, {
element: conditionaldefaultflowMarker,
attrs: {
stroke: stroke
},
ref: { x: 0, y: 10 },
scale: 0.5
});
}
}
funct ...n/a
function BaseRenderer(eventBus, renderPriority) {
var self = this;
renderPriority = renderPriority || DEFAULT_RENDER_PRIORITY;
eventBus.on([ 'render.shape', 'render.connection' ], renderPriority, function(evt, context) {
var type = evt.type,
element = context.element,
visuals = context.gfx;
if (self.canRender(element)) {
if (type === 'render.shape') {
return self.drawShape(visuals, element);
} else {
return self.drawConnection(visuals, element);
}
}
});
eventBus.on([ 'render.getShapePath', 'render.getConnectionPath'], renderPriority, function(evt, element) {
if (self.canRender(element)) {
if (evt.type === 'render.getShapePath') {
return self.getShapePath(element);
} else {
return self.getConnectionPath(element);
}
}
});
}n/a
canRender = function (element) {
return is(element, 'bpmn:BaseElement');
}n/a
drawConnection = function (parentGfx, element) {
var type = element.type;
var h = this.handlers[type];
/* jshint -W040 */
return h(parentGfx, element);
}n/a
drawShape = function (parentGfx, element) {
var type = element.type;
var h = this.handlers[type];
/* jshint -W040 */
return h(parentGfx, element);
}n/a
getShapePath = function (element) {
if (is(element, 'bpmn:Event')) {
return getCirclePath(element);
}
if (is(element, 'bpmn:Activity')) {
return getRoundRectPath(element, TASK_BORDER_RADIUS);
}
if (is(element, 'bpmn:Gateway')) {
return getDiamondPath(element);
}
return getRectPath(element);
}...
expect(elementRegistry.get('triangle')).to.eql(triangle);
expect(elementRegistry.get('circle')).to.eql(circle);
}));
it('should get the correct custom elements path', inject(function(graphicsFactory) {
// when
var trianglePath = graphicsFactory.getShapePath(triangle),
circlePath = graphicsFactory.getShapePath(circle);
// then
expect(trianglePath).to.equal('M720,100l20,40l-40,0z');
expect(circlePath).to.equal('M870,170m0,-70a70,70,0,1,1,0,140a70,70,0,1,1,0,-140z');
}));
...function BpmnReplacePreview(eventBus, elementRegistry, elementFactory, canvas, previewSupport) {
CommandInterceptor.call(this, eventBus);
/**
* Replace the visuals of all elements in the context which can be replaced
*
* @param {Object} context
*/
function replaceVisual(context) {
var replacements = context.canExecute.replacements;
forEach(replacements, function(replacement) {
var id = replacement.oldElementId;
var newElement = {
type: replacement.newElementType
};
// if the visual of the element is already replaced
if (context.visualReplacements[id]) {
return;
}
var element = elementRegistry.get(id);
assign(newElement, { x: element.x, y: element.y });
// create a temporary shape
var tempShape = elementFactory.createShape(newElement);
canvas.addShape(tempShape, element.parent);
// select the original SVG element related to the element and hide it
var gfx = domQuery('[data-element-id=' + element.id + ']', context.dragGroup);
if (gfx) {
svgAttr(gfx, { display: 'none' });
}
// clone the gfx of the temporary shape and add it to the drag group
var dragger = previewSupport.addDragger(tempShape, context.dragGroup);
context.visualReplacements[id] = dragger;
canvas.removeShape(tempShape);
});
}
/**
* Restore the original visuals of the previously replaced elements
*
* @param {Object} context
*/
function restoreVisual(context) {
var visualReplacements = context.visualReplacements;
forEach(visualReplacements, function(dragger, id) {
var originalGfx = domQuery('[data-element-id=' + id + ']', context.dragGroup);
if (originalGfx) {
svgAttr(originalGfx, { display: 'inline' });
}
dragger.remove();
if (visualReplacements[id]) {
delete visualReplacements[id];
}
});
}
eventBus.on('shape.move.move', LOW_PRIORITY, function(event) {
var context = event.context,
canExecute = context.canExecute;
if (!context.visualReplacements) {
context.visualReplacements = {};
}
if (canExecute.replacements) {
replaceVisual(context);
} else {
restoreVisual(context);
}
});
}n/a
function CommandInterceptor(eventBus) {
this._eventBus = eventBus;
}n/a
function BpmnRules(eventBus) {
RuleProvider.call(this, eventBus);
}n/a
function RuleProvider(eventBus) {
CommandInterceptor.call(this, eventBus);
this.init();
}n/a
function canAttach(elements, target, source, position) {
if (!Array.isArray(elements)) {
elements = [ elements ];
}
// disallow appending as boundary event
if (source) {
return false;
}
// only (re-)attach one element at a time
if (elements.length !== 1) {
return false;
}
var element = elements[0];
// do not attach labels
if (isLabel(element)) {
return false;
}
// only handle boundary events
if (!isBoundaryCandidate(element)) {
return false;
}
// allow default move operation
if (!target) {
return true;
}
// disallow drop on event sub processes
if (isEventSubProcess(target)) {
return false;
}
// only allow drop on non compensation activities
if (!is(target, 'bpmn:Activity') || isForCompensation(target)) {
return false;
}
// only attach to subprocess border
if (position && !isBoundaryAttachment(position, target)) {
return false;
}
return 'attach';
}...
if (is(shape, 'bpmn:Participant') && is(rootElement, 'bpmn:Process')) {
initParticipantSnapping(context, shape, rootElement.children);
}
});
function canAttach(shape, target, position) {
return bpmnRules.canAttach([ shape ], target, null, position) === 'attach'
;;
}
function canConnect(source, target) {
return bpmnRules.canConnect(source, target);
}
/**
...function canConnect(source, target, connection) {
if (nonExistantOrLabel(source) || nonExistantOrLabel(target)) {
return null;
}
// See https://github.com/bpmn-io/bpmn-js/issues/178
// as a workround we disallow connections with same
// target and source element.
// This rule must be removed if a auto layout for this
// connections is implemented.
if (isSame(source, target)) {
return false;
}
if (!is(connection, 'bpmn:DataAssociation')) {
if (canConnectMessageFlow(source, target)) {
return { type: 'bpmn:MessageFlow' };
}
if (canConnectSequenceFlow(source, target)) {
return { type: 'bpmn:SequenceFlow' };
}
}
var connectDataAssociation = canConnectDataAssociation(source, target);
if (connectDataAssociation) {
return connectDataAssociation;
}
if (isCompensationBoundary(source) && isForCompensation(target)) {
return {
type: 'bpmn:Association',
associationDirection: 'One'
};
}
if (is(connection, 'bpmn:Association') && canConnectAssociation(source, target)) {
return {
type: 'bpmn:Association'
};
}
if (isTextAnnotation(source) || isTextAnnotation(target)) {
return {
type: 'bpmn:Association'
};
}
return false;
}...
target = createdElements[descriptor.target];
if (source && target) {
source = source.element;
target = target.element;
}
canConnect = bpmnRules.canConnect(source, target);
if (canConnect) {
descriptor.type = canConnect.type;
}
}
businessObject = descriptor.businessObject;
...function canConnectAssociation(source, target) {
// do not connect connections
if (isConnection(source) || isConnection(target)) {
return false;
}
// connect if different parent
return !isParent(target, source) &&
!isParent(source, target);
}n/a
function canConnectDataAssociation(source, target) {
if (isAny(source, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ]) &&
isAny(target, [ 'bpmn:Activity', 'bpmn:ThrowEvent' ])) {
return { type: 'bpmn:DataInputAssociation' };
}
if (isAny(target, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ]) &&
isAny(source, [ 'bpmn:Activity', 'bpmn:CatchEvent' ])) {
return { type: 'bpmn:DataOutputAssociation' };
}
return false;
}n/a
function canConnectMessageFlow(source, target) {
return isMessageFlowSource(source) &&
isMessageFlowTarget(target) &&
!isSameOrganization(source, target);
}n/a
function canConnectSequenceFlow(source, target) {
return isSequenceFlowSource(source) &&
isSequenceFlowTarget(target) &&
isSameScope(source, target) &&
!(is(source, 'bpmn:EventBasedGateway') && !isEventBasedTarget(target));
}n/a
function canCopy(collection, element) {
if (is(element, 'bpmn:Lane') && !contains(collection, element.parent)) {
return false;
}
if (is(element, 'bpmn:BoundaryEvent') && !contains(collection, element.host)) {
return false;
}
return true;
}n/a
function canCreate(shape, target, source, position) {
if (!target) {
return false;
}
if (isLabel(target)) {
return null;
}
if (isSame(source, target)) {
return false;
}
// ensure we do not drop the element
// into source
if (source && isParent(source, target)) {
return false;
}
return canDrop(shape, target, position) || canInsert(shape, target, position);
}n/a
function canDrop(element, target, position) {
// can move labels everywhere
if (isLabel(element) && !isConnection(target)) {
return true;
}
// disallow to create elements on collapsed pools
if (is(target, 'bpmn:Participant') && !isExpanded(target)) {
return false;
}
// allow to create new participants on
// on existing collaboration and process diagrams
if (is(element, 'bpmn:Participant')) {
return is(target, 'bpmn:Process') || is(target, 'bpmn:Collaboration');
}
// allow creating lanes on participants and other lanes only
if (is(element, 'bpmn:Lane')) {
return is(target, 'bpmn:Participant') || is(target, 'bpmn:Lane');
}
if (is(element, 'bpmn:BoundaryEvent')) {
return false;
}
// drop flow elements onto flow element containers
// and participants
if (is(element, 'bpmn:FlowElement')) {
if (is(target, 'bpmn:FlowElementsContainer')) {
return isExpanded(target);
}
return isAny(target, [ 'bpmn:Participant', 'bpmn:Lane' ]);
}
// account for the fact that data associations are always
// rendered and moved to top (Process or Collaboration level)
//
// artifacts may be placed wherever, too
if (isAny(element, [ 'bpmn:Artifact', 'bpmn:DataAssociation' ])) {
return isAny(target, [
'bpmn:Collaboration',
'bpmn:Lane',
'bpmn:Participant',
'bpmn:Process',
'bpmn:SubProcess' ]);
}
if (is(element, 'bpmn:MessageFlow')) {
return is(target, 'bpmn:Collaboration')
|| element.source.parent == target
|| element.target.parent == target;
}
return false;
}n/a
function canInsert(shape, flow, position) {
if (Array.isArray(shape)) {
if (shape.length !== 1) {
return false;
}
shape = shape[0];
}
// return true if we can drop on the
// underlying flow parent
//
// at this point we are not really able to talk
// about connection rules (yet)
return (
isAny(flow, [ 'bpmn:SequenceFlow', 'bpmn:MessageFlow' ]) &&
!isLabel(flow) &&
is(shape, 'bpmn:FlowNode') &&
!is(shape, 'bpmn:BoundaryEvent') &&
canDrop(shape, flow.parent, position));
}n/a
function canMove(elements, target) {
// do not move selection containing boundary events
if (any(elements, isBoundaryEvent)) {
return false;
}
// do not move selection containing lanes
if (any(elements, isLane)) {
return false;
}
// allow default move check to start move operation
if (!target) {
return true;
}
return elements.every(function(element) {
return canDrop(element, target);
});
}n/a
function canReplace(elements, target, position) {
if (!target) {
return false;
}
var canExecute = {
replacements: []
};
forEach(elements, function(element) {
if (!isEventSubProcess(target)) {
if (is(element, 'bpmn:StartEvent') &&
element.type !== 'label' &&
canDrop(element, target)) {
// replace a non-interrupting start event by a blank interrupting start event
// when the target is not an event sub process
if (!isInterrupting(element)) {
canExecute.replacements.push({
oldElementId: element.id,
newElementType: 'bpmn:StartEvent'
});
}
// replace an error/escalation/compansate start event by a blank interrupting start event
// when the target is not an event sub process
if (hasErrorEventDefinition(element) ||
hasEscalationEventDefinition(element) ||
hasCompensateEventDefinition(element)) {
canExecute.replacements.push({
oldElementId: element.id,
newElementType: 'bpmn:StartEvent'
});
}
}
}
if (!is(target, 'bpmn:Transaction')) {
if (hasEventDefinition(element, 'bpmn:CancelEventDefinition') &&
element.type !== 'label') {
if (is(element, 'bpmn:EndEvent') && canDrop(element, target)) {
canExecute.replacements.push({
oldElementId: element.id,
newElementType: 'bpmn:EndEvent'
});
}
if (is(element, 'bpmn:BoundaryEvent') && canAttach(element, target, null, position)) {
canExecute.replacements.push({
oldElementId: element.id,
newElementType: 'bpmn:BoundaryEvent'
});
}
}
}
});
return canExecute.replacements.length ? canExecute : false;
}n/a
function canResize(shape, newBounds) {
if (is(shape, 'bpmn:SubProcess')) {
return (!!isExpanded(shape)) && (
!newBounds || (newBounds.width >= 100 && newBounds.height >= 80)
);
}
if (is(shape, 'bpmn:Lane')) {
return !newBounds || (newBounds.width >= 130 && newBounds.height >= 60);
}
if (is(shape, 'bpmn:Participant')) {
return !newBounds || (newBounds.width >= 250 && newBounds.height >= 50);
}
if (isTextAnnotation(shape)) {
return true;
}
return false;
}n/a
init = function () {
this.addRule('connection.create', function(context) {
var source = context.source,
target = context.target;
return canConnect(source, target);
});
this.addRule('connection.reconnectStart', function(context) {
var connection = context.connection,
source = context.hover || context.source,
target = connection.target;
return canConnect(source, target, connection);
});
this.addRule('connection.reconnectEnd', function(context) {
var connection = context.connection,
source = connection.source,
target = context.hover || context.target;
return canConnect(source, target, connection);
});
this.addRule('connection.updateWaypoints', function(context) {
// OK! but visually ignore
return null;
});
this.addRule('shape.resize', function(context) {
var shape = context.shape,
newBounds = context.newBounds;
return canResize(shape, newBounds);
});
this.addRule('elements.move', function(context) {
var target = context.target,
shapes = context.shapes,
position = context.position;
return canAttach(shapes, target, null, position) ||
canReplace(shapes, target, position) ||
canMove(shapes, target, position) ||
canInsert(shapes, target, position);
});
this.addRule([ 'shape.create', 'shape.append' ], function(context) {
var target = context.target,
shape = context.shape,
source = context.source,
position = context.position;
return canAttach([ shape ], target, source, position) || canCreate(shape, target, source, position);
});
this.addRule('element.copy', function(context) {
var collection = context.collection,
element = context.element;
return canCopy(collection, element);
});
this.addRule('element.paste', function(context) {
var parent = context.parent,
element = context.element,
position = context.position,
source = context.source,
target = context.target;
if (source || target) {
return canConnect(source, target);
}
return canAttach([ element ], parent, null, position) || canCreate(element, parent, null, position);
});
this.addRule('elements.paste', function(context) {
var tree = context.tree,
target = context.target;
return canPaste(tree, target);
});
this.addRule([ 'elements.delete' ], function(context) {
// do not allow deletion of labels
return filter(context.elements, function(e) {
return !isLabel(e);
});
});
}...
clientY: position.y,
offsetX: position.x,
offsetY: position.y
}, data || {});
var event = new EventBus.Event();
event.init(data);
return event;
}
module.exports.createEvent = createEvent;
...function BpmnSearchProvider(elementRegistry, searchPad, canvas) {
this._elementRegistry = elementRegistry;
this._canvas = canvas;
searchPad.registerProvider(this);
}n/a
find = function (pattern) {
var rootElement = this._canvas.getRootElement();
var elements = this._elementRegistry.filter(function(element) {
if (element.labelTarget) {
return false;
}
return true;
});
// do not include root element
elements = filter(elements, function(element) {
return element !== rootElement;
});
elements = map(elements, function(element) {
return {
primaryTokens: matchAndSplit(labelUtil.getLabel(element), pattern),
secondaryTokens: matchAndSplit(element.id, pattern),
element: element
};
});
// exclude non-matched elements
elements = filter(elements, function(element) {
return hasMatched(element.primaryTokens) || hasMatched(element.secondaryTokens);
});
elements = sortBy(elements, function(element) {
return labelUtil.getLabel(element.element) + element.element.id;
});
return elements;
}n/a
function BpmnSnapping(eventBus, canvas, bpmnRules, elementRegistry) {
// instantiate super
Snapping.call(this, eventBus, canvas);
/**
* Drop participant on process <> process elements snapping
*/
eventBus.on('create.start', function(event) {
var context = event.context,
shape = context.shape,
rootElement = canvas.getRootElement();
// snap participant around existing elements (if any)
if (is(shape, 'bpmn:Participant') && is(rootElement, 'bpmn:Process')) {
initParticipantSnapping(context, shape, rootElement.children);
}
});
eventBus.on([ 'create.move', 'create.end' ], HIGH_PRIORITY, function(event) {
var context = event.context,
shape = context.shape,
participantSnapBox = context.participantSnapBox;
if (!isSnapped(event) && participantSnapBox) {
snapParticipant(participantSnapBox, shape, event);
}
});
eventBus.on('shape.move.start', function(event) {
var context = event.context,
shape = context.shape,
rootElement = canvas.getRootElement();
// snap participant around existing elements (if any)
if (is(shape, 'bpmn:Participant') && is(rootElement, 'bpmn:Process')) {
initParticipantSnapping(context, shape, rootElement.children);
}
});
function canAttach(shape, target, position) {
return bpmnRules.canAttach([ shape ], target, null, position) === 'attach';
}
function canConnect(source, target) {
return bpmnRules.canConnect(source, target);
}
/**
* Snap boundary events to elements border
*/
eventBus.on([
'create.move',
'create.end',
'shape.move.move',
'shape.move.end'
], HIGH_PRIORITY, function(event) {
var context = event.context,
target = context.target,
shape = context.shape;
if (target && !isSnapped(event) && canAttach(shape, target, event)) {
snapBoundaryEvent(event, shape, target);
}
});
/**
* Adjust parent for flowElements to the target participant
* when droping onto lanes.
*/
eventBus.on([
'shape.move.hover',
'shape.move.move',
'shape.move.end',
'create.hover',
'create.move',
'create.end'
], HIGH_PRIORITY, function(event) {
var context = event.context,
shape = context.shape,
hover = event.hover;
if (is(hover, 'bpmn:Lane') && !isAny(shape, [ 'bpmn:Lane', 'bpmn:Participant' ])) {
event.hover = getLanesRoot(hover);
event.hoverGfx = elementRegistry.getGraphics(event.hover);
}
});
/**
* Snap sequence flows.
*/
eventBus.on([
'connect.move',
'connect.hover',
'connect.end'
], HIGH_PRIORITY, function(event) {
var context = event.context,
source = context.source,
target = context.target;
var connection = canConnect(source, target) || {};
if (!context.initialSourcePosition) {
context.initialSourcePosition = context.sourcePosition;
}
if (target && connection.type === 'bpmn:SequenceFlow') {
// snap source
context.sourcePosition = mid(source);
// snap target
assign(event, mid(target));
} else {
// otherwise reset source snap
context.sourcePosition = context.initialSourcePosition;
}
});
eventBus.on([
'create.move',
'shape.move.move'
], function(event) {
var context = event.context,
shape = context.shape,
target = context.target;
var threshold = 30;
if (is(shape, 'bpmn:Lane')) {
if (isAny(target, [ 'bpmn:Lane', 'bpmn:Participant' ])) {
var childLanes = filter(target.children, function(c) {
return is(c, 'bpmn:Lane');
});
var y = event.y,
targetTrbl;
var insert = childLanes.reduce(function(insert, l) {
var laneTrbl = asTRBL(l);
if (abs(laneTrbl.top - y) < threshold) {
insert = assign(insert || {}, { before: { element: l, y: laneTrbl.top } });
} else
if (abs(laneTrbl.bottom - y) < threshold) {
insert = assign(insert || {}, { after: { element: ...n/a
function Snapping(eventBus, canvas) {
this._canvas = canvas;
var self = this;
eventBus.on([ 'shape.move.start', 'create.start' ], function(event) {
self.initSnap(event);
});
eventBus.on([ 'shape.move.move', 'shape.move.end', 'create.move', 'create.end' ], HIGHER_PRIORITY, function(event) {
if (event.originalEvent && event.originalEvent.ctrlKey) {
return;
}
if (isSnapped(event)) {
return;
}
self.snap(event);
});
eventBus.on([ 'shape.move.cleanup', 'create.cleanup' ], function(event) {
self.hide();
});
// delay hide by 1000 seconds since last match
this._asyncHide = debounce(this.hide, 1000);
}n/a
addTargetSnaps = function (snapPoints, shape, target) {
// use target parent as snap target
if (is(shape, 'bpmn:BoundaryEvent') && shape.type !== 'label') {
target = target.parent;
}
// add sequence flow parents as snap targets
if (is(target, 'bpmn:SequenceFlow')) {
this.addTargetSnaps(snapPoints, shape, target.parent);
}
var siblings = this.getSiblings(shape, target) || [];
forEach(siblings, function(s) {
// do not snap to lanes
if (is(s, 'bpmn:Lane')) {
return;
}
snapPoints.add('mid', mid(s));
if (is(s, 'bpmn:Participant')) {
snapPoints.add('top-left', topLeft(s));
snapPoints.add('bottom-right', bottomRight(s));
}
});
forEach(shape.incoming, function(c) {
if (siblings.indexOf(c.source) === -1) {
snapPoints.add('mid', mid(c.source));
}
var docking = c.waypoints[0];
snapPoints.add(c.id + '-docking', docking.original || docking);
});
forEach(shape.outgoing, function(c) {
if (siblings.indexOf(c.target) === -1) {
snapPoints.add('mid', mid(c.target));
}
var docking = c.waypoints[c.waypoints.length - 1];
snapPoints.add(c.id + '-docking', docking.original || docking);
});
}...
// use target parent as snap target
if (is(shape, 'bpmn:BoundaryEvent') && shape.type !== 'label') {
target = target.parent;
}
// add sequence flow parents as snap targets
if (is(target, 'bpmn:SequenceFlow')) {
this.addTargetSnaps(snapPoints, shape, target.parent);
}
var siblings = this.getSiblings(shape, target) || [];
forEach(siblings, function(s) {
// do not snap to lanes
...initSnap = function (event) {
var context = event.context,
shape = event.shape,
shapeMid,
shapeBounds,
shapeTopLeft,
shapeBottomRight,
snapContext;
snapContext = Snapping.prototype.initSnap.call(this, event);
if (is(shape, 'bpmn:Participant')) {
// assign higher priority for outer snaps on participants
snapContext.setSnapLocations([ 'top-left', 'bottom-right', 'mid' ]);
}
if (shape) {
shapeMid = mid(shape, event);
shapeBounds = {
width: shape.width,
height: shape.height,
x: isNaN(shape.x) ? round(shapeMid.x - shape.width / 2) : shape.x,
y: isNaN(shape.y) ? round(shapeMid.y - shape.height / 2) : shape.y
};
shapeTopLeft = topLeft(shapeBounds);
shapeBottomRight = bottomRight(shapeBounds);
snapContext.setSnapOrigin('top-left', {
x: shapeTopLeft.x - event.x,
y: shapeTopLeft.y - event.y
});
snapContext.setSnapOrigin('bottom-right', {
x: shapeBottomRight.x - event.x,
y: shapeBottomRight.y - event.y
});
forEach(shape.outgoing, function(c) {
var docking = c.waypoints[0];
docking = docking.original || docking;
snapContext.setSnapOrigin(c.id + '-docking', {
x: docking.x - event.x,
y: docking.y - event.y
});
});
forEach(shape.incoming, function(c) {
var docking = c.waypoints[c.waypoints.length - 1];
docking = docking.original || docking;
snapContext.setSnapOrigin(c.id + '-docking', {
x: docking.x - event.x,
y: docking.y - event.y
});
});
}
var source = context.source;
if (source) {
snapContext.addDefaultSnap('mid', mid(source));
}
}n/a
function getBoundaryAttachment(position, targetBounds) {
var orientation = getOrientation(position, targetBounds, -15);
if (orientation !== 'intersect') {
return orientation;
} else {
return null;
}
}n/a
function getParticipantSizeConstraints(laneShape, resizeDirection, balanced) {
var lanesRoot = getLanesRoot(laneShape);
var isFirst = true,
isLast = true;
///// max top/bottom size for lanes
var allLanes = collectLanes(lanesRoot, [ lanesRoot ]);
var laneTrbl = asTRBL(laneShape);
var maxTrbl = {},
minTrbl = {};
if (/e/.test(resizeDirection)) {
minTrbl.right = laneTrbl.left + LANE_MIN_WIDTH;
} else
if (/w/.test(resizeDirection)) {
minTrbl.left = laneTrbl.right - LANE_MIN_WIDTH;
}
allLanes.forEach(function(other) {
var otherTrbl = asTRBL(other);
if (/n/.test(resizeDirection)) {
if (otherTrbl.top < (laneTrbl.top - 10)) {
isFirst = false;
}
// max top size (based on next element)
if (balanced && abs(laneTrbl.top - otherTrbl.bottom) < 10) {
addMax(maxTrbl, 'top', otherTrbl.top + LANE_MIN_HEIGHT);
}
// min top size (based on self or nested element)
if (abs(laneTrbl.top - otherTrbl.top) < 5) {
addMin(minTrbl, 'top', otherTrbl.bottom - LANE_MIN_HEIGHT);
}
}
if (/s/.test(resizeDirection)) {
if (otherTrbl.bottom > (laneTrbl.bottom + 10)) {
isLast = false;
}
// max bottom size (based on previous element)
if (balanced && abs(laneTrbl.bottom - otherTrbl.top) < 10) {
addMin(maxTrbl, 'bottom', otherTrbl.bottom - LANE_MIN_HEIGHT);
}
// min bottom size (based on self or nested element)
if (abs(laneTrbl.bottom - otherTrbl.bottom) < 5) {
addMax(minTrbl, 'bottom', otherTrbl.top + LANE_MIN_HEIGHT);
}
}
});
///// max top/bottom/left/right size based on flow nodes
var flowElements = lanesRoot.children.filter(function(s) {
return !s.hidden && !s.waypoints && (is(s, 'bpmn:FlowElement') || is(s, 'bpmn:Artifact'));
});
flowElements.forEach(function(flowElement) {
var flowElementTrbl = asTRBL(flowElement);
if (isFirst && /n/.test(resizeDirection)) {
addMin(minTrbl, 'top', flowElementTrbl.top - LANE_TOP_PADDING);
}
if (/e/.test(resizeDirection)) {
addMax(minTrbl, 'right', flowElementTrbl.right + LANE_RIGHT_PADDING);
}
if (isLast && /s/.test(resizeDirection)) {
addMax(minTrbl, 'bottom', flowElementTrbl.bottom + LANE_BOTTOM_PADDING);
}
if (/w/.test(resizeDirection)) {
addMin(minTrbl, 'left', flowElementTrbl.left - LANE_LEFT_PADDING);
}
});
return {
min: minTrbl,
max: maxTrbl
};
}n/a
function BpmnUpdater(eventBus, bpmnFactory, connectionDocking, translate) {
CommandInterceptor.call(this, eventBus);
this._bpmnFactory = bpmnFactory;
this._translate = translate;
var self = this;
////// connection cropping /////////////////////////
// crop connection ends during create/update
function cropConnection(e) {
var context = e.context,
connection;
if (!context.cropped) {
connection = context.connection;
connection.waypoints = connectionDocking.getCroppedWaypoints(connection);
context.cropped = true;
}
}
this.executed([
'connection.layout',
'connection.create',
'connection.reconnectEnd',
'connection.reconnectStart'
], cropConnection);
this.reverted([ 'connection.layout' ], function(e) {
delete e.context.cropped;
});
////// BPMN + DI update /////////////////////////
// update parent
function updateParent(e) {
var context = e.context;
self.updateParent(context.shape || context.connection, context.oldParent);
}
function reverseUpdateParent(e) {
var context = e.context;
var element = context.shape || context.connection,
// oldParent is the (old) new parent, because we are undoing
oldParent = context.parent || context.newParent;
self.updateParent(element, oldParent);
}
this.executed([ 'shape.move',
'shape.create',
'shape.delete',
'connection.create',
'connection.move',
'connection.delete' ], ifBpmn(updateParent));
this.reverted([ 'shape.move',
'shape.create',
'shape.delete',
'connection.create',
'connection.move',
'connection.delete' ], ifBpmn(reverseUpdateParent));
/*
* ## Updating Parent
*
* When morphing a Process into a Collaboration or vice-versa,
* make sure that both the *semantic* and *di* parent of each element
* is updated.
*
*/
function updateRoot(event) {
var context = event.context,
oldRoot = context.oldRoot,
children = oldRoot.children;
forEach(children, function(child) {
if (is(child, 'bpmn:BaseElement')) {
self.updateParent(child);
}
});
}
this.executed([ 'canvas.updateRoot' ], updateRoot);
this.reverted([ 'canvas.updateRoot' ], updateRoot);
// update bounds
function updateBounds(e) {
var shape = e.context.shape;
if (!is(shape, 'bpmn:BaseElement')) {
return;
}
self.updateBounds(shape);
}
this.executed([ 'shape.move', 'shape.create', 'shape.resize' ], ifBpmn(function(event) {
// exclude labels because they're handled separately during shape.changed
if (event.context.shape.type === 'label') {
return;
}
updateBounds(event);
}));
this.reverted([ 'shape.move', 'shape.create', 'shape.resize' ], ifBpmn(function(event) {
// exclude labels because they're handled separately during shape.changed
if (event.context.shape.type === 'label') {
return;
}
updateBounds(event);
}));
// Handle labels separately. This is necessary, because the label bounds have to be updated
// every time its shape changes, not only on move, create and resize.
eventBus.on('shape.changed', function(event) {
if (event.element.type === 'label') {
updateBounds({ context: { shape: event.element } });
}
});
// attach / detach connection
function updateConnection(e) {
self.updateConnection(e.context);
}
this.executed([
'connection.create',
'connection.move',
'connection.delete',
'connection.reconnectEnd',
'connection.reconnectStart'
], ifBpmn(updateConnection));
this.reverted([
'connection.create',
'connection.move',
'connection.delete',
'connection.reconnectEnd',
'connection.reconnectStart'
], ifBpmn(updateConnection));
// update waypoints
function updateConnectionWaypoints(e) {
self.updateConnectionWaypoints(e.context.connection);
}
this.executed([ ...n/a
function CommandInterceptor(eventBus) {
this._eventBus = eventBus;
}n/a
_getLabel = function (di) {
if (!di.label) {
di.label = this._bpmnFactory.createDiLabel();
}
return di.label;
}...
};
BpmnUpdater.prototype.updateBounds = function(shape) {
var di = shape.businessObject.di;
var bounds = (shape instanceof Model.Label) ? this._getLabel(di).bounds : di.bounds;
assign(bounds, {
x: shape.x,
y: shape.y,
width: shape.width,
height: shape.height
});
...getLaneSet = function (container) {
var laneSet, laneSets;
// bpmn:Lane
if (is(container, 'bpmn:Lane')) {
laneSet = container.childLaneSet;
if (!laneSet) {
laneSet = this._bpmnFactory.create('bpmn:LaneSet');
container.childLaneSet = laneSet;
laneSet.$parent = container;
}
return laneSet;
}
// bpmn:Participant
if (is(container, 'bpmn:Participant')) {
container = container.processRef;
}
// bpmn:FlowElementsContainer
laneSets = container.get('laneSets');
laneSet = laneSets[0];
if (!laneSet) {
laneSet = this._bpmnFactory.create('bpmn:LaneSet');
laneSet.$parent = container;
laneSets.push(laneSet);
}
return laneSet;
}...
if (businessObject.$parent === newParent) {
return;
}
if (is(businessObject, 'bpmn:Lane')) {
if (newParent) {
newParent = this.getLaneSet(newParent);
}
containment = 'lanes';
} else
if (is(businessObject, 'bpmn:FlowElement')) {
...updateAttachment = function (context) {
var shape = context.shape,
businessObject = shape.businessObject,
host = shape.host;
businessObject.attachedToRef = host && host.businessObject;
}...
if (context.conditionExpression && is(newSource, 'bpmn:Activity')) {
businessObject.conditionExpression = context.conditionExpression;
}
}));
// update attachments
function updateAttachment(e) {
self.updateAttachment(e.context);
}
this.executed([ 'element.updateAttachment' ], ifBpmn(updateAttachment));
this.reverted([ 'element.updateAttachment' ], ifBpmn(updateAttachment));
}
inherits(BpmnUpdater, CommandInterceptor);
...updateBounds = function (shape) {
var di = shape.businessObject.di;
var bounds = (shape instanceof Model.Label) ? this._getLabel(di).bounds : di.bounds;
assign(bounds, {
x: shape.x,
y: shape.y,
width: shape.width,
height: shape.height
});
}...
function updateBounds(e) {
var shape = e.context.shape;
if (!is(shape, 'bpmn:BaseElement')) {
return;
}
self.updateBounds(shape);
}
this.executed([ 'shape.move', 'shape.create', 'shape.resize' ], ifBpmn(function(event) {
// exclude labels because they're handled separately during shape.changed
if (event.context.shape.type === 'label') {
return;
...updateConnection = function (context) {
var connection = context.connection,
businessObject = getBusinessObject(connection),
newSource = getBusinessObject(connection.source),
newTarget = getBusinessObject(connection.target),
visualParent;
if (!is(businessObject, 'bpmn:DataAssociation')) {
var inverseSet = is(businessObject, 'bpmn:SequenceFlow');
if (businessObject.sourceRef !== newSource) {
if (inverseSet) {
Collections.remove(businessObject.sourceRef && businessObject.sourceRef.get('outgoing'), businessObject);
if (newSource && newSource.get('outgoing')) {
newSource.get('outgoing').push(businessObject);
}
}
businessObject.sourceRef = newSource;
}
if (businessObject.targetRef !== newTarget) {
if (inverseSet) {
Collections.remove(businessObject.targetRef && businessObject.targetRef.get('incoming'), businessObject);
if (newTarget && newTarget.get('incoming')) {
newTarget.get('incoming').push(businessObject);
}
}
businessObject.targetRef = newTarget;
}
} else
if (is(businessObject, 'bpmn:DataInputAssociation')) {
// handle obnoxious isMany sourceRef
businessObject.get('sourceRef')[0] = newSource;
visualParent = context.parent || context.newParent || newTarget;
this.updateSemanticParent(businessObject, newTarget, parent.businessObject);
} else
if (is(businessObject, 'bpmn:DataOutputAssociation')) {
visualParent = context.parent || context.newParent || newSource;
this.updateSemanticParent(businessObject, newSource, visualParent);
// targetRef = new target
businessObject.targetRef = newTarget;
}
this.updateConnectionWaypoints(connection);
this.updateDiConnection(businessObject.di, newSource, newTarget);
}...
if (event.element.type === 'label') {
updateBounds({ context: { shape: event.element } });
}
});
// attach / detach connection
function updateConnection(e) {
self.updateConnection(e.context);
}
this.executed([
'connection.create',
'connection.move',
'connection.delete',
'connection.reconnectEnd',
...updateConnectionWaypoints = function (connection) {
connection.businessObject.di.set('waypoint', this._bpmnFactory.createDiWaypoints(connection.waypoints));
}...
'connection.reconnectEnd',
'connection.reconnectStart'
], ifBpmn(updateConnection));
// update waypoints
function updateConnectionWaypoints(e) {
self.updateConnectionWaypoints(e.context.connection);
}
this.executed([
'connection.layout',
'connection.move',
'connection.updateWaypoints',
'connection.reconnectEnd',
...updateDiConnection = function (di, newSource, newTarget) {
if (di.sourceElement && di.sourceElement.bpmnElement !== newSource) {
di.sourceElement = newSource && newSource.di;
}
if (di.targetElement && di.targetElement.bpmnElement !== newTarget) {
di.targetElement = newTarget && newTarget.di;
}
}...
// targetRef = new target
businessObject.targetRef = newTarget;
}
this.updateConnectionWaypoints(connection);
this.updateDiConnection(businessObject.di, newSource, newTarget);
};
/////// helpers /////////////////////////////////////////
BpmnUpdater.prototype._getLabel = function(di) {
if (!di.label) {
...updateDiParent = function (di, parentDi) {
if (parentDi && !is(parentDi, 'bpmndi:BPMNPlane')) {
parentDi = parentDi.$parent;
}
if (di.$parent === parentDi) {
return;
}
var planeElements = (parentDi || di.$parent).get('planeElement');
if (parentDi) {
planeElements.push(di);
di.$parent = parentDi;
} else {
Collections.remove(planeElements, di);
di.$parent = null;
}
}...
this.updateSemanticParent(businessObject, parentBusinessObject);
if (is(element, 'bpmn:DataObjectReference') && businessObject.dataObjectRef) {
this.updateSemanticParent(businessObject.dataObjectRef, parentBusinessObject);
}
this.updateDiParent(businessObject.di, parentDi);
};
BpmnUpdater.prototype.updateBounds = function(shape) {
var di = shape.businessObject.di;
...updateFlowNodeRefs = function (businessObject, newContainment, oldContainment) {
if (oldContainment === newContainment) {
return;
}
var oldRefs, newRefs;
if (is (oldContainment, 'bpmn:Lane')) {
oldRefs = oldContainment.get('flowNodeRef');
Collections.remove(oldRefs, businessObject);
}
if (is(newContainment, 'bpmn:Lane')) {
newRefs = newContainment.get('flowNodeRef');
Collections.add(newRefs, businessObject);
}
}...
var parentShape = element.parent;
var businessObject = element.businessObject,
parentBusinessObject = parentShape && parentShape.businessObject,
parentDi = parentBusinessObject && parentBusinessObject.di;
if (is(element, 'bpmn:FlowNode')) {
this.updateFlowNodeRefs(businessObject, parentBusinessObject, oldParent &&
; oldParent.businessObject);
}
if (is(element, 'bpmn:DataOutputAssociation')) {
if (element.source) {
parentBusinessObject = element.source.businessObject;
} else {
parentBusinessObject = null;
...updateParent = function (element, oldParent) {
// do not update BPMN 2.0 label parent
if (element instanceof Model.Label) {
return;
}
var parentShape = element.parent;
var businessObject = element.businessObject,
parentBusinessObject = parentShape && parentShape.businessObject,
parentDi = parentBusinessObject && parentBusinessObject.di;
if (is(element, 'bpmn:FlowNode')) {
this.updateFlowNodeRefs(businessObject, parentBusinessObject, oldParent && oldParent.businessObject);
}
if (is(element, 'bpmn:DataOutputAssociation')) {
if (element.source) {
parentBusinessObject = element.source.businessObject;
} else {
parentBusinessObject = null;
}
}
if (is(element, 'bpmn:DataInputAssociation')) {
if (element.target) {
parentBusinessObject = element.target.businessObject;
} else {
parentBusinessObject = null;
}
}
this.updateSemanticParent(businessObject, parentBusinessObject);
if (is(element, 'bpmn:DataObjectReference') && businessObject.dataObjectRef) {
this.updateSemanticParent(businessObject.dataObjectRef, parentBusinessObject);
}
this.updateDiParent(businessObject.di, parentDi);
}...
////// BPMN + DI update /////////////////////////
// update parent
function updateParent(e) {
var context = e.context;
self.updateParent(context.shape || context.connection, context.oldParent);
}
function reverseUpdateParent(e) {
var context = e.context;
var element = context.shape || context.connection,
// oldParent is the (old) new parent, because we are undoing
...updateSemanticParent = function (businessObject, newParent, visualParent) {
var containment,
translate = this._translate;
if (businessObject.$parent === newParent) {
return;
}
if (is(businessObject, 'bpmn:Lane')) {
if (newParent) {
newParent = this.getLaneSet(newParent);
}
containment = 'lanes';
} else
if (is(businessObject, 'bpmn:FlowElement')) {
if (newParent) {
if (is(newParent, 'bpmn:Participant')) {
newParent = newParent.processRef;
} else
if (is(newParent, 'bpmn:Lane')) {
do {
// unwrap Lane -> LaneSet -> (Lane | FlowElementsContainer)
newParent = newParent.$parent.$parent;
} while (is(newParent, 'bpmn:Lane'));
}
}
containment = 'flowElements';
} else
if (is(businessObject, 'bpmn:Artifact')) {
while (newParent &&
!is(newParent, 'bpmn:Process') &&
!is(newParent, 'bpmn:SubProcess') &&
!is(newParent, 'bpmn:Collaboration')) {
if (is(newParent, 'bpmn:Participant')) {
newParent = newParent.processRef;
break;
} else {
newParent = newParent.$parent;
}
}
containment = 'artifacts';
} else
if (is(businessObject, 'bpmn:MessageFlow')) {
containment = 'messageFlows';
} else
if (is(businessObject, 'bpmn:Participant')) {
containment = 'participants';
// make sure the participants process is properly attached / detached
// from the XML document
var process = businessObject.processRef,
definitions;
if (process) {
definitions = getDefinitions(businessObject.$parent || newParent);
if (businessObject.$parent) {
Collections.remove(definitions.get('rootElements'), process);
process.$parent = null;
}
if (newParent) {
Collections.add(definitions.get('rootElements'), process);
process.$parent = definitions;
}
}
} else
if (is(businessObject, 'bpmn:DataOutputAssociation')) {
containment = 'dataOutputAssociations';
} else
if (is(businessObject, 'bpmn:DataInputAssociation')) {
containment = 'dataInputAssociations';
}
if (!containment) {
throw new Error(translate(
'no parent for {element} in {parent}',
{
element: businessObject.id,
parent: newParent.id
}
));
}
var children;
if (businessObject.$parent) {
// remove from old parent
children = businessObject.$parent.get(containment);
Collections.remove(children, businessObject);
}
if (!newParent) {
businessObject.$parent = null;
} else {
// add to new parent
children = newParent.get(containment);
children.push(businessObject);
businessObject.$parent = newParent;
}
if (visualParent) {
var diChildren = visualParent.get(containment);
Collections.remove(children, businessObject);
if (newParent) {
if (!diChildren) {
diChildren = [];
newParent.set(containment, diChildren);
}
diChildren.push(businessObject);
}
}
}...
if (element.target) {
parentBusinessObject = element.target.businessObject;
} else {
parentBusinessObject = null;
}
}
this.updateSemanticParent(businessObject, parentBusinessObject);
if (is(element, 'bpmn:DataObjectReference') && businessObject.dataObjectRef) {
this.updateSemanticParent(businessObject.dataObjectRef, parentBusinessObject);
}
this.updateDiParent(businessObject.di, parentDi);
};
...function ContextPadProvider(eventBus, contextPad, modeling, elementFactory, connect, create, popupMenu, canvas, rules, translate) {
contextPad.registerProvider(this);
this._contextPad = contextPad;
this._modeling = modeling;
this._elementFactory = elementFactory;
this._connect = connect;
this._create = create;
this._popupMenu = popupMenu;
this._canvas = canvas;
this._rules = rules;
this._translate = translate;
eventBus.on('create.end', 250, function(event) {
var shape = event.context.shape;
if (!hasPrimaryModifier(event)) {
return;
}
var entries = contextPad.getEntries(shape);
if (entries.replace) {
entries.replace.action.click(event, shape);
}
});
}n/a
getContextPadEntries = function (element) {
var contextPad = this._contextPad,
modeling = this._modeling,
elementFactory = this._elementFactory,
connect = this._connect,
create = this._create,
popupMenu = this._popupMenu,
canvas = this._canvas,
rules = this._rules,
translate = this._translate;
var actions = {};
if (element.type === 'label') {
return actions;
}
var businessObject = element.businessObject;
function startConnect(event, element, autoActivate) {
connect.start(event, element, autoActivate);
}
function removeElement(e) {
modeling.removeElements([ element ]);
}
function getReplaceMenuPosition(element) {
var Y_OFFSET = 5;
var diagramContainer = canvas.getContainer(),
pad = contextPad.getPad(element).html;
var diagramRect = diagramContainer.getBoundingClientRect(),
padRect = pad.getBoundingClientRect();
var top = padRect.top - diagramRect.top;
var left = padRect.left - diagramRect.left;
var pos = {
x: left,
y: top + padRect.height + Y_OFFSET
};
return pos;
}
/**
* Create an append action
*
* @param {String} type
* @param {String} className
* @param {String} [title]
* @param {Object} [options]
*
* @return {Object} descriptor
*/
function appendAction(type, className, title, options) {
if (typeof title !== 'string') {
options = title;
title = translate('Append {type}', { type: type.replace(/^bpmn\:/, '') });
}
function appendListener(event, element) {
var shape = elementFactory.createShape(assign({ type: type }, options));
create.start(event, shape, element);
}
return {
group: 'model',
className: className,
title: title,
action: {
dragstart: appendListener,
click: appendListener
}
};
}
function splitLaneHandler(count) {
return function(event, element) {
// actual split
modeling.splitLane(element, count);
// refresh context pad after split to
// get rid of split icons
contextPad.open(element, true);
};
}
if (isAny(businessObject, [ 'bpmn:Lane', 'bpmn:Participant' ]) && isExpanded(businessObject)) {
var childLanes = getChildLanes(element);
assign(actions, {
'lane-insert-above': {
group: 'lane-insert-above',
className: 'bpmn-icon-lane-insert-above',
title: translate('Add Lane above'),
action: {
click: function(event, element) {
modeling.addLane(element, 'top');
}
}
}
});
if (childLanes.length < 2) {
if (element.height >= 120) {
assign(actions, {
'lane-divide-two': {
group: 'lane-divide',
className: 'bpmn-icon-lane-divide-two',
title: translate('Divide into two Lanes'),
action: {
click: splitLaneHandler(2)
}
}
});
}
if (element.height >= 180) {
assign(actions, {
'lane-divide-three': {
group: 'lane-divide',
className: 'bpmn-icon-lane-divide-three',
title: translate('Divide into three Lanes'),
action: {
click: splitLaneHandler(3)
}
}
});
}
}
assign(actions, {
'lane-insert-below': {
group: 'lane-insert-below',
className: 'bpmn-icon-lane-insert-below',
title: translate('Add Lane below'),
action: {
click: function(event, element) {
modeling.addLane(element, 'bottom');
}
}
}
});
}
if (is(businessObject, 'bpmn:FlowNode')) {
if (is(businessObject, 'bpmn:EventBasedGateway')) {
assign(actions, {
'append.receive-task': appendAction('bpmn:ReceiveTask', 'bpmn-icon-receive-task'),
'append.message-intermediate-event': appendAction('bpmn:IntermediateCatchEvent',
'bpmn-icon-intermediate-event-catch-message', ...n/a
hasCompensateEventDefinition = function (element) {
return hasEventDefinition(element, 'bpmn:CompensateEventDefinition');
}n/a
hasErrorEventDefinition = function (element) {
return hasEventDefinition(element, 'bpmn:ErrorEventDefinition');
}n/a
hasEscalationEventDefinition = function (element) {
return hasEventDefinition(element, 'bpmn:EscalationEventDefinition');
}n/a
function hasEventDefinition(element, eventType) {
var bo = getBusinessObject(element),
hasEventDefinition = false;
if (bo.eventDefinitions) {
forEach(bo.eventDefinitions, function(event) {
if (is(event, eventType)) {
hasEventDefinition = true;
}
});
}
return hasEventDefinition;
}n/a
isEventSubProcess = function (element) {
return element && !!getBusinessObject(element).triggeredByEvent;
}...
stroke: getStrokeColor(element)
}, attrs);
var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
var expanded = DiUtil.isExpanded(element);
var isEventSubProcess = DiUtil.isEventSubProcess(element);
if (isEventSubProcess) {
svgAttr(rect, {
strokeDasharray: '1,2'
});
}
...isExpanded = function (element) {
if (is(element, 'bpmn:CallActivity')) {
return false;
}
if (is(element, 'bpmn:SubProcess')) {
return !!getBusinessObject(element).di.isExpanded;
}
if (is(element, 'bpmn:Participant')) {
return !!getBusinessObject(element).processRef;
}
return true;
}...
fillOpacity: 0.95,
fill: getFillColor(element),
stroke: getStrokeColor(element)
}, attrs);
var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
var expanded = DiUtil.isExpanded(element);
var isEventSubProcess = DiUtil.isEventSubProcess(element);
if (isEventSubProcess) {
svgAttr(rect, {
strokeDasharray: '1,2'
});
...isInterrupting = function (element) {
return element && getBusinessObject(element).isInterrupting !== false;
}n/a
function ElementFactory(bpmnFactory, moddle, translate) {
BaseElementFactory.call(this);
this._bpmnFactory = bpmnFactory;
this._moddle = moddle;
this._translate = translate;
}n/a
function ElementFactory() {
this._uid = 12;
}n/a
_getDefaultSize = function (semantic) {
if (is(semantic, 'bpmn:SubProcess')) {
if (isExpanded(semantic)) {
return { width: 350, height: 200 };
} else {
return { width: 100, height: 80 };
}
}
if (is(semantic, 'bpmn:Task')) {
return { width: 100, height: 80 };
}
if (is(semantic, 'bpmn:Gateway')) {
return { width: 50, height: 50 };
}
if (is(semantic, 'bpmn:Event')) {
return { width: 36, height: 36 };
}
if (is(semantic, 'bpmn:Participant')) {
if (!isExpanded(semantic)) {
return { width: 400, height: 100 };
} else {
return { width: 600, height: 250 };
}
}
if (is(semantic, 'bpmn:Lane')) {
return { width: 400, height: 100 };
}
if (is(semantic, 'bpmn:DataObjectReference')) {
return { width: 36, height: 50 };
}
if (is(semantic, 'bpmn:DataStoreReference')) {
return { width: 50, height: 50 };
}
if (is(semantic, 'bpmn:TextAnnotation')) {
return { width: 100, height: 30 };
}
return { width: 100, height: 80 };
}...
newEventDefinition.$parent = businessObject;
businessObject.eventDefinitions = eventDefinitions;
delete attrs.eventDefinitionType;
}
size = this._getDefaultSize(businessObject);
attrs = assign({
businessObject: businessObject,
id: businessObject.id
}, size, attrs);
return this.baseCreate(elementType, attrs);
...baseCreate = function (type, attrs) {
attrs = assign({}, attrs || {});
if (!attrs.id) {
attrs.id = type + '_' + (this._uid++);
}
return Model.create(type, attrs);
}...
ElementFactory.prototype.baseCreate = BaseElementFactory.prototype.create;
ElementFactory.prototype.create = function(elementType, attrs) {
// no special magic for labels,
// we assume their businessObjects have already been created
// and wired via attrs
if (elementType === 'label') {
return this.baseCreate(elementType, assign({ type: 'label' }, LabelUtil.DEFAULT_LABEL_SIZE
, attrs));
}
return this.createBpmnElement(elementType, attrs);
};
ElementFactory.prototype.createBpmnElement = function(elementType, attrs) {
var size,
...create = function (elementType, attrs) {
// no special magic for labels,
// we assume their businessObjects have already been created
// and wired via attrs
if (elementType === 'label') {
return this.baseCreate(elementType, assign({ type: 'label' }, LabelUtil.DEFAULT_LABEL_SIZE, attrs));
}
return this.createBpmnElement(elementType, attrs);
}...
});
}
}
var replaceMenu;
if (popupMenu._providers['bpmn-replace']) {
replaceMenu = popupMenu.create('bpmn-replace', element);
}
if (replaceMenu && !replaceMenu.isEmpty()) {
// Replace menu entry
assign(actions, {
'replace': {
...createBpmnElement = function (elementType, attrs) {
var size,
translate = this._translate;
attrs = attrs || {};
var businessObject = attrs.businessObject;
if (!businessObject) {
if (!attrs.type) {
throw new Error(translate('no shape type specified'));
}
businessObject = this._bpmnFactory.create(attrs.type);
}
if (!businessObject.di) {
if (elementType === 'root') {
businessObject.di = this._bpmnFactory.createDiPlane(businessObject, [], {
id: businessObject.id + '_di'
});
} else
if (elementType === 'connection') {
businessObject.di = this._bpmnFactory.createDiEdge(businessObject, [], {
id: businessObject.id + '_di'
});
} else {
businessObject.di = this._bpmnFactory.createDiShape(businessObject, {}, {
id: businessObject.id + '_di'
});
}
}
if (attrs.colors) {
assign(businessObject.di, attrs.colors);
delete attrs.colors;
}
applyAttributes(businessObject, attrs, [
'processRef',
'isInterrupting',
'associationDirection',
'isForCompensation'
]);
if (attrs.isExpanded) {
applyAttribute(businessObject.di, attrs, 'isExpanded');
}
if (is(businessObject, 'bpmn:ExclusiveGateway')) {
businessObject.di.isMarkerVisible = true;
}
var eventDefinitions,
newEventDefinition;
if (attrs.eventDefinitionType) {
eventDefinitions = businessObject.get('eventDefinitions') || [];
newEventDefinition = this._moddle.create(attrs.eventDefinitionType);
eventDefinitions.push(newEventDefinition);
newEventDefinition.$parent = businessObject;
businessObject.eventDefinitions = eventDefinitions;
delete attrs.eventDefinitionType;
}
size = this._getDefaultSize(businessObject);
attrs = assign({
businessObject: businessObject,
id: businessObject.id
}, size, attrs);
return this.baseCreate(elementType, attrs);
}...
// no special magic for labels,
// we assume their businessObjects have already been created
// and wired via attrs
if (elementType === 'label') {
return this.baseCreate(elementType, assign({ type: 'label' }, LabelUtil.DEFAULT_LABEL_SIZE, attrs));
}
return this.createBpmnElement(elementType, attrs);
};
ElementFactory.prototype.createBpmnElement = function(elementType, attrs) {
var size,
translate = this._translate;
attrs = attrs || {};
...createParticipantShape = function (collapsed) {
var attrs = { type: 'bpmn:Participant' };
if (!collapsed) {
attrs.processRef = this._bpmnFactory.create('bpmn:Process');
}
return this.createShape(attrs);
}...
dragstart: createListener,
click: createListener
}
};
}
function createParticipant(event, collapsed) {
create.start(event, elementFactory.createParticipantShape(collapsed));
}
assign(actions, {
'hand-tool': {
group: 'tools',
className: 'bpmn-icon-hand-tool',
title: translate('Activate the hand tool'),
...function importBpmnDiagram(diagram, definitions, done) {
var importer = diagram.get('bpmnImporter'),
eventBus = diagram.get('eventBus'),
translate = diagram.get('translate');
var error,
warnings = [];
/**
* Walk the diagram semantically, importing (=drawing)
* all elements you encounter.
*
* @param {ModdleElement} definitions
*/
function render(definitions) {
var visitor = {
root: function(element) {
return importer.add(element);
},
element: function(element, parentShape) {
return importer.add(element, parentShape);
},
error: function(message, context) {
warnings.push({ message: message, context: context });
}
};
var walker = new BpmnTreeWalker(visitor, translate);
// traverse BPMN 2.0 document model,
// starting at definitions
walker.handleDefinitions(definitions);
}
eventBus.fire('import.render.start', { definitions: definitions });
try {
render(definitions);
} catch (e) {
error = e;
}
eventBus.fire('import.render.complete', {
error: error,
warnings: warnings
});
done(error, warnings);
}...
this.clear();
}
// update definitions
this.definitions = definitions;
// perform graphical import
Importer.importBpmnDiagram(this, definitions, done);
} catch (e) {
// handle synchronous errors
done(e);
}
};
...function LabelEditingProvider(eventBus, canvas, directEditing, commandStack) {
this._canvas = canvas;
this._commandStack = commandStack;
directEditing.registerProvider(this);
commandStack.registerHandler('element.updateLabel', UpdateLabelHandler);
// listen to dblclick on non-root elements
eventBus.on('element.dblclick', function(event) {
directEditing.activate(event.element);
});
// complete on followup canvas operation
eventBus.on([ 'element.mousedown', 'drag.init', 'canvas.viewbox.changed' ], function(event) {
directEditing.complete();
});
// cancel on command stack changes
eventBus.on([ 'commandStack.changed' ], function() {
directEditing.cancel();
});
if ('ontouchstart' in document.documentElement) {
// we deactivate automatic label editing on mobile devices
// as it breaks the user interaction workflow
// TODO(nre): we should temporarily focus the edited element here
// and release the focused viewport after the direct edit operation is finished
} else {
eventBus.on('create.end', 500, function(e) {
var element = e.shape,
canExecute = e.context.canExecute;
if (!canExecute) {
return;
}
if (is(element, 'bpmn:Task') || is(element, 'bpmn:TextAnnotation') ||
(is(element, 'bpmn:SubProcess') && !isExpanded(element))) {
directEditing.activate(element);
}
});
}
}n/a
activate = function (element) {
var text = LabelUtil.getLabel(element);
if (text === undefined) {
return;
}
var properties = this.getEditingBBox(element);
properties.text = text;
return properties;
}...
modeling.setColor(currentSelection, opts);
}
},
directEditing: function() {
var currentSelection = selection.get();
if (currentSelection.length) {
directEditing.activate(currentSelection[0]);
}
},
find: function() {
searchPad.toggle();
},
moveToOrigin: function() {
var rootElement = canvas.getRootElement(),
...getEditingBBox = function (element) {
var canvas = this._canvas;
var target = element.label || element;
var bbox = canvas.getAbsoluteBBox(target);
var mid = {
x: bbox.x + bbox.width / 2,
y: bbox.y + bbox.height / 2
};
// default position
var bounds = { x: bbox.x, y: bbox.y };
var style = {},
zoom;
// adjust for expanded pools AND lanes
if ((is(element, 'bpmn:Participant') && isExpanded(element)) || is(element, 'bpmn:Lane')) {
bounds.width = 150;
bounds.minHeight = LINE_HEIGHT + PADDING;
bounds.maxHeight = LINE_HEIGHT * 2 + PADDING;
bounds.x = bbox.x - bounds.width / 2;
bounds.y = mid.y - bounds.minHeight / 2;
}
// internal labels for tasks and collapsed call activities, sub processes and participants
if (
is(element, 'bpmn:Task') ||
(is(element, 'bpmn:CallActivity') && !isExpanded(element)) ||
(is(element, 'bpmn:SubProcess') && !isExpanded(element)) ||
(is(element, 'bpmn:Participant') && !isExpanded(element))
) {
zoom = canvas.zoom();
// fixed size for internal labels:
// on high zoom levels: text box size === bbox size
// on low zoom levels: text box size === bbox size at 100% zoom
// This ensures minimum bounds at low zoom levels
if (zoom > 1) {
bounds.width = bbox.width;
bounds.height = bbox.height;
} else {
bounds.width = bbox.width / zoom;
bounds.height = bbox.height / zoom;
}
// centering overlapping text box size at low zoom levels
if (zoom < 1) {
bounds.x = bbox.x - (bounds.width / 2 - bbox.width / 2);
bounds.y = bbox.y - (bounds.height / 2 - bbox.height / 2);
}
}
// internal labels for expanded sub processes
if (is(element, 'bpmn:SubProcess') && isExpanded(element)) {
bounds.width = element.width;
bounds.maxHeight = 3 * LINE_HEIGHT + PADDING; // maximum 3 lines
bounds.x = mid.x - element.width / 2;
}
// external labels for events, data elements, gateways and connections
if (target.labelTarget) {
bounds.width = 150;
bounds.minHeight = LINE_HEIGHT + PADDING; // 1 line
bounds.x = mid.x - bounds.width / 2;
}
// text annotations
if (is(element, 'bpmn:TextAnnotation')) {
bounds.minWidth = 100;
bounds.height = element.height;
style.textAlign = 'left';
}
return { bounds: bounds, style: style };
}...
var text = LabelUtil.getLabel(element);
if (text === undefined) {
return;
}
var properties = this.getEditingBBox(element);
properties.text = text;
return properties;
};
...update = function (element, newLabel) {
this._commandStack.execute('element.updateLabel', {
element: element,
newLabel: newLabel
});
}n/a
getExternalLabelBounds = function (semantic, element) {
var mid,
size,
bounds,
di = semantic.di,
label = di.label;
if (label && label.bounds) {
bounds = label.bounds;
size = {
width: Math.max(DEFAULT_LABEL_SIZE.width, bounds.width),
height: bounds.height
};
mid = {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2
};
} else {
mid = getExternalLabelMid(element);
size = DEFAULT_LABEL_SIZE;
}
return assign({
x: mid.x - size.width / 2,
y: mid.y - size.height / 2
}, size);
}n/a
function getExternalLabelMid(element) {
if (element.waypoints) {
return getFlowLabelPosition(element.waypoints);
} else {
return {
x: element.x + element.width / 2,
y: element.y + element.height + DEFAULT_LABEL_SIZE.height / 2
};
}
}n/a
function getFlowLabelPosition(waypoints) {
// get the waypoints mid
var mid = waypoints.length / 2 - 1;
var first = waypoints[Math.floor(mid)];
var second = waypoints[Math.ceil(mid + 0.01)];
// get position
var position = getWaypointsMid(waypoints);
// calculate angle
var angle = Math.atan( (second.y - first.y) / (second.x - first.x) );
var x = position.x,
y = position.y;
if ( Math.abs(angle) < Math.PI / 2 ) {
y -= FLOW_LABEL_INDENT;
} else {
x += FLOW_LABEL_INDENT;
}
return { x: x, y: y };
}n/a
function getWaypointsMid(waypoints) {
var mid = waypoints.length / 2 - 1;
var first = waypoints[Math.floor(mid)];
var second = waypoints[Math.ceil(mid + 0.01)];
return {
x: first.x + (second.x - first.x) / 2,
y: first.y + (second.y - first.y) / 2
};
}n/a
hasExternalLabel = function (semantic) {
return is(semantic, 'bpmn:Event') ||
is(semantic, 'bpmn:Gateway') ||
is(semantic, 'bpmn:DataStoreReference') ||
is(semantic, 'bpmn:DataObjectReference') ||
is(semantic, 'bpmn:SequenceFlow') ||
is(semantic, 'bpmn:MessageFlow');
}n/a
function ModelCloneHelper(eventBus) {
this._eventBus = eventBus;
}n/a
function _deepClone(propertyElement, context) {
var eventBus = this._eventBus;
var newProp = propertyElement.$model.create(propertyElement.$type);
var properties = filter(Object.keys(propertyElement), function(prop) {
var descriptor = newProp.$model.getPropertyDescriptor(newProp, prop);
if (descriptor && (descriptor.isId || descriptor.isReference)) {
return false;
}
// we need to make sure we don't clone certain properties
// which we cannot easily know if they hold references or not
if (IGNORED_PROPERTIES.indexOf(prop) !== -1) {
return false;
}
// make sure we don't copy the type
return prop !== '$type';
});
if (!properties.length) {
context.hasNestedProperty = true;
}
forEach(properties, function(propName) {
// check if the propertyElement has this property defined
if (propertyElement[propName] !== undefined &&
(propertyElement[propName].$type || isArray(propertyElement[propName]))) {
if (isArray(propertyElement[propName])) {
newProp[propName] = [];
forEach(propertyElement[propName], function(property) {
var extProp = propertyElement.$model.getTypeDescriptor(property.$type),
newDeepProp;
// we're not going to copy undefined types
if (!extProp) {
return;
}
var canClone = eventBus.fire('property.clone', {
newElement: context.newElement,
refTopLevelProperty: context.refTopLevelProperty,
propertyDescriptor: extProp
});
if (!canClone) {
// if can clone is 'undefined' or 'false'
// check for the meta information if it is allowed
if (propertyElement.$type === 'bpmn:ExtensionElements' &&
extProp.meta && extProp.meta.allowedIn &&
!isAllowedIn(extProp, context.newElement.$type)) {
return false;
}
}
newDeepProp = this._deepClone(property, context);
newDeepProp.$parent = newProp;
if (!newProp[propName]) {
newProp[propName] = [];
}
context.hasNestedProperty = true;
newProp[propName].push(newDeepProp);
}, this);
} else if (propertyElement[propName].$type) {
newProp[propName] = this._deepClone(propertyElement[propName], context);
if (newProp[propName]) {
context.hasNestedProperty = true;
newProp[propName].$parent = newProp;
}
}
} else {
context.hasNestedProperty = true;
// just assign directly if it's a value
newProp[propName] = propertyElement[propName];
}
}, this);
return newProp;
}...
if (isArray(refElementProp)) {
forEach(refElementProp, function(extElement) {
var newProp;
context.refTopLevelProperty = extElement;
newProp = this._deepClone(extElement, context);
if (context.hasNestedProperty) {
newProp.$parent = newElement;
newElementProp.push(newProp);
}
...clone = function (refElement, newElement, properties) {
// hasNestedProperty: property allows us to avoid ending up with empty (xml) tags
// f.ex: if extensionElements.values is empty, don't set it
var context = {
newElement: newElement,
hasNestedProperty: false
};
// we want the extensionElements to be cloned last
// so that they can check certain properties
properties = sort(properties, function(prop) {
return prop === 'bpmn:extensionElements';
});
forEach(properties, function(propName) {
var refElementProp = refElement.get(propName),
newElementProp = newElement.get(propName),
propDescriptor = newElement.$model.getPropertyDescriptor(newElement, propName),
newProperty, name;
// we're not interested in cloning:
// - same values from simple types
// - cloning id's
// - cloning reference elements
if (newElementProp === refElementProp ||
(propDescriptor && (propDescriptor.isId || propDescriptor.isReference))) {
return;
}
// if the property is of type 'boolean', 'string', 'number' or 'null', just set it
if (isType(refElementProp, [ 'boolean', 'string', 'number' ]) || refElementProp === null) {
newElement.set(propName, refElementProp);
return;
}
if (isArray(refElementProp)) {
forEach(refElementProp, function(extElement) {
var newProp;
context.refTopLevelProperty = extElement;
newProp = this._deepClone(extElement, context);
if (context.hasNestedProperty) {
newProp.$parent = newElement;
newElementProp.push(newProp);
}
context.hasNestedProperty = false;
}, this);
} else {
name = propName.replace(/bpmn:/, '');
context.refTopLevelProperty = refElementProp;
newProperty = this._deepClone(refElementProp, context);
if (context.hasNestedProperty) {
newElement[name] = newProperty;
}
context.hasNestedProperty = false;
}
}, this);
return newElement;
}...
var properties = getProperties(businessObject.$descriptor),
colors = {};
properties = filter(properties, function(property) {
return IGNORED_PROPERTIES.indexOf(property.replace(/bpmn:/, '')) === -1;
});
descriptor.businessObject = helper.clone(businessObject, newBusinessObject, properties
);
descriptor.type = element.type;
setProperties(descriptor, businessObject.di, [ 'isExpanded' ]);
setProperties(colors, businessObject.di, [ 'fill', 'stroke' ]);
...function getProperties(descriptor, keepDefault) {
var properties = [];
forEach(descriptor.properties, function(property) {
if (keepDefault && property.default) {
return;
}
properties.push(property.ns.name);
});
return properties;
}n/a
function getBusinessObject(element) {
return (element && element.businessObject) || element;
}n/a
function is(element, type) {
var bo = getBusinessObject(element);
return bo && (typeof bo.$instanceOf === 'function') && bo.$instanceOf(type);
}n/a
function Modeling(eventBus, elementFactory, commandStack, bpmnRules) {
BaseModeling.call(this, eventBus, elementFactory, commandStack);
this._bpmnRules = bpmnRules;
}n/a
function Modeling(eventBus, elementFactory, commandStack) {
this._eventBus = eventBus;
this._elementFactory = elementFactory;
this._commandStack = commandStack;
var self = this;
eventBus.on('diagram.init', function() {
// register modeling handlers
self.registerHandlers(commandStack);
});
}n/a
addLane = function (targetLaneShape, location) {
var context = {
shape: targetLaneShape,
location: location
};
this._commandStack.execute('lane.add', context);
return context.newLane;
}...
assign(actions, {
'lane-insert-above': {
group: 'lane-insert-above',
className: 'bpmn-icon-lane-insert-above',
title: translate('Add Lane above'),
action: {
click: function(event, element) {
modeling.addLane(element, 'top');
}
}
}
});
if (childLanes.length < 2) {
...claimId = function (id, moddleElement) {
this._commandStack.execute('id.updateClaim', {
id: id,
element: moddleElement,
claiming: true
});
}n/a
connect = function (source, target, attrs, hints) {
var bpmnRules = this._bpmnRules;
if (!attrs) {
attrs = bpmnRules.canConnect(source, target) || { type: 'bpmn:Association' };
}
return this.createConnection(source, target, attrs, source.parent, hints);
}n/a
getHandlers = function () {
var handlers = BaseModeling.prototype.getHandlers.call(this);
handlers['element.updateProperties'] = UpdatePropertiesHandler;
handlers['canvas.updateRoot'] = UpdateCanvasRootHandler;
handlers['lane.add'] = AddLaneHandler;
handlers['lane.resize'] = ResizeLaneHandler;
handlers['lane.split'] = SplitLaneHandler;
handlers['lane.updateRefs'] = UpdateFlowNodeRefsHandler;
handlers['id.updateClaim'] = IdClaimHandler;
handlers['element.setColor'] = SetColorHandler;
return handlers;
}n/a
makeCollaboration = function () {
var collaborationElement = this._create('root', {
type: 'bpmn:Collaboration'
});
var context = {
newRoot: collaborationElement
};
this._commandStack.execute('canvas.updateRoot', context);
return collaborationElement;
}n/a
makeProcess = function () {
var processElement = this._create('root', {
type: 'bpmn:Process'
});
var context = {
newRoot: processElement
};
this._commandStack.execute('canvas.updateRoot', context);
}n/a
resizeLane = function (laneShape, newBounds, balanced) {
this._commandStack.execute('lane.resize', {
shape: laneShape,
newBounds: newBounds,
balanced: balanced
});
}...
*
* @param {djs.model.Shape} target
* @param {Object} newBounds
*/
BpmnAutoResize.prototype.resize = function(target, newBounds) {
if (is(target, 'bpmn:Participant')) {
this._modeling.resizeLane(target, newBounds);
} else {
this._modeling.resizeShape(target, newBounds);
}
};
...setColor = function (elements, colors) {
if (!elements.length) {
elements = [ elements ];
}
this._commandStack.execute('element.setColor', {
elements: elements,
colors: colors
});
}...
alignElements.trigger(aligneableElements, type);
}
},
setColor: function(opts) {
var currentSelection = selection.get();
if (currentSelection.length) {
modeling.setColor(currentSelection, opts);
}
},
directEditing: function() {
var currentSelection = selection.get();
if (currentSelection.length) {
directEditing.activate(currentSelection[0]);
...splitLane = function (targetLane, count) {
this._commandStack.execute('lane.split', {
shape: targetLane,
count: count
});
}...
};
}
function splitLaneHandler(count) {
return function(event, element) {
// actual split
modeling.splitLane(element, count);
// refresh context pad after split to
// get rid of split icons
contextPad.open(element, true);
};
}
...unclaimId = function (id, moddleElement) {
this._commandStack.execute('id.updateClaim', {
id: id,
element: moddleElement
});
}n/a
updateLabel = function (element, newLabel) {
this._commandStack.execute('element.updateLabel', {
element: element,
newLabel: newLabel
});
}n/a
updateLaneRefs = function (flowNodeShapes, laneShapes) {
this._commandStack.execute('lane.updateRefs', {
flowNodeShapes: flowNodeShapes,
laneShapes: laneShapes
});
}n/a
updateProperties = function (element, properties) {
this._commandStack.execute('element.updateProperties', {
element: element,
properties: properties
});
}...
if (businessObject.sourceRef.default !== businessObject &&
(is(businessObject.sourceRef, 'bpmn:ExclusiveGateway') ||
is(businessObject.sourceRef, 'bpmn:InclusiveGateway') ||
is(businessObject.sourceRef, 'bpmn:ComplexGateway') ||
is(businessObject.sourceRef, 'bpmn:Activity'))) {
menuEntries.push(self._createMenuEntry(entry, element, function() {
modeling.updateProperties(element.source, { default: businessObject });
}));
}
break;
case 'replace-with-conditional-flow':
if (!businessObject.conditionExpression && is(businessObject.sourceRef, 'bpmn:Activity')) {
menuEntries.push(self._createMenuEntry(entry, element, function() {
...function PaletteProvider(palette, create, elementFactory, spaceTool, lassoTool, handTool, globalConnect, translate) {
this._palette = palette;
this._create = create;
this._elementFactory = elementFactory;
this._spaceTool = spaceTool;
this._lassoTool = lassoTool;
this._handTool = handTool;
this._globalConnect = globalConnect;
this._translate = translate;
palette.registerProvider(this);
}n/a
getPaletteEntries = function (element) {
var actions = {},
create = this._create,
elementFactory = this._elementFactory,
spaceTool = this._spaceTool,
lassoTool = this._lassoTool,
handTool = this._handTool,
globalConnect = this._globalConnect,
translate = this._translate;
function createAction(type, group, className, title, options) {
function createListener(event) {
var shape = elementFactory.createShape(assign({ type: type }, options));
if (options) {
shape.businessObject.di.isExpanded = options.isExpanded;
}
create.start(event, shape);
}
var shortType = type.replace(/^bpmn\:/, '');
return {
group: group,
className: className,
title: title || translate('Create {type}', { type: shortType }),
action: {
dragstart: createListener,
click: createListener
}
};
}
function createParticipant(event, collapsed) {
create.start(event, elementFactory.createParticipantShape(collapsed));
}
assign(actions, {
'hand-tool': {
group: 'tools',
className: 'bpmn-icon-hand-tool',
title: translate('Activate the hand tool'),
action: {
click: function(event) {
handTool.activateHand(event);
}
}
},
'lasso-tool': {
group: 'tools',
className: 'bpmn-icon-lasso-tool',
title: translate('Activate the lasso tool'),
action: {
click: function(event) {
lassoTool.activateSelection(event);
}
}
},
'space-tool': {
group: 'tools',
className: 'bpmn-icon-space-tool',
title: translate('Activate the create/remove space tool'),
action: {
click: function(event) {
spaceTool.activateSelection(event);
}
}
},
'global-connect-tool': {
group: 'tools',
className: 'bpmn-icon-connection-multi',
title: translate('Activate the global connect tool'),
action: {
click: function(event) {
globalConnect.toggle(event);
}
}
},
'tool-separator': {
group: 'tools',
separator: true
},
'create.start-event': createAction(
'bpmn:StartEvent', 'event', 'bpmn-icon-start-event-none'
),
'create.intermediate-event': createAction('bpmn:IntermediateThrowEvent', 'event',
'bpmn-icon-intermediate-event-none', translate('Create IntermediateThrowEvent/BoundaryEvent')
),
'create.end-event': createAction(
'bpmn:EndEvent', 'event', 'bpmn-icon-end-event-none'
),
'create.exclusive-gateway': createAction(
'bpmn:ExclusiveGateway', 'gateway', 'bpmn-icon-gateway-xor'
),
'create.task': createAction(
'bpmn:Task', 'activity', 'bpmn-icon-task'
),
'create.data-object': createAction(
'bpmn:DataObjectReference', 'data-object', 'bpmn-icon-data-object'
),
'create.data-store': createAction(
'bpmn:DataStoreReference', 'data-store', 'bpmn-icon-data-store'
),
'create.subprocess-expanded': createAction(
'bpmn:SubProcess', 'activity', 'bpmn-icon-subprocess-expanded', translate('Create expanded SubProcess'),
{ isExpanded: true }
),
'create.participant-expanded': {
group: 'collaboration',
className: 'bpmn-icon-participant',
title: translate('Create Pool/Participant'),
action: {
dragstart: createParticipant,
click: createParticipant
}
}
});
return actions;
}n/a
function ReplaceMenuProvider(popupMenu, modeling, moddle, bpmnReplace, rules, translate) {
this._popupMenu = popupMenu;
this._modeling = modeling;
this._moddle = moddle;
this._bpmnReplace = bpmnReplace;
this._rules = rules;
this._translate = translate;
this.register();
}n/a
_createEntries = function (element, replaceOptions) {
var menuEntries = [];
var self = this;
forEach(replaceOptions, function(definition) {
var entry = self._createMenuEntry(definition, element);
menuEntries.push(entry);
});
return menuEntries;
}...
var differentType = isDifferentType(element);
// start events outside event sub processes
if (is(businessObject, 'bpmn:StartEvent') && !isEventSubProcess(businessObject.$parent)) {
entries = filter(replaceOptions.START_EVENT, differentType);
return this._createEntries(element, entries);
}
// expanded/collapsed pools
if (is(businessObject, 'bpmn:Participant')) {
entries = filter(replaceOptions.PARTICIPANT, function(entry) {
return isExpanded(businessObject) !== entry.target.isExpanded;
..._createMenuEntry = function (definition, element, action) {
var translate = this._translate;
var replaceElement = this._bpmnReplace.replaceElement;
var replaceAction = function() {
return replaceElement(element, definition.target);
};
action = action || replaceAction;
var menuEntry = {
label: translate(definition.label),
className: definition.className,
id: definition.actionName,
action: action
};
return menuEntry;
}...
*/
ReplaceMenuProvider.prototype._createEntries = function(element, replaceOptions) {
var menuEntries = [];
var self = this;
forEach(replaceOptions, function(definition) {
var entry = self._createMenuEntry(definition, element);
menuEntries.push(entry);
});
return menuEntries;
};
..._createSequenceFlowEntries = function (element, replaceOptions) {
var businessObject = getBusinessObject(element);
var menuEntries = [];
var modeling = this._modeling,
moddle = this._moddle;
var self = this;
forEach(replaceOptions, function(entry) {
switch (entry.actionName) {
case 'replace-with-default-flow':
if (businessObject.sourceRef.default !== businessObject &&
(is(businessObject.sourceRef, 'bpmn:ExclusiveGateway') ||
is(businessObject.sourceRef, 'bpmn:InclusiveGateway') ||
is(businessObject.sourceRef, 'bpmn:ComplexGateway') ||
is(businessObject.sourceRef, 'bpmn:Activity'))) {
menuEntries.push(self._createMenuEntry(entry, element, function() {
modeling.updateProperties(element.source, { default: businessObject });
}));
}
break;
case 'replace-with-conditional-flow':
if (!businessObject.conditionExpression && is(businessObject.sourceRef, 'bpmn:Activity')) {
menuEntries.push(self._createMenuEntry(entry, element, function() {
var conditionExpression = moddle.create('bpmn:FormalExpression', { body: '' });
modeling.updateProperties(element, { conditionExpression: conditionExpression });
}));
}
break;
default:
// default flows
if (is(businessObject.sourceRef, 'bpmn:Activity') && businessObject.conditionExpression) {
return menuEntries.push(self._createMenuEntry(entry, element, function() {
modeling.updateProperties(element, { conditionExpression: undefined });
}));
}
// conditional flows
if ((is(businessObject.sourceRef, 'bpmn:ExclusiveGateway') ||
is(businessObject.sourceRef, 'bpmn:InclusiveGateway') ||
is(businessObject.sourceRef, 'bpmn:ComplexGateway') ||
is(businessObject.sourceRef, 'bpmn:Activity')) &&
businessObject.sourceRef.default === businessObject) {
return menuEntries.push(self._createMenuEntry(entry, element, function() {
modeling.updateProperties(element.source, { default: undefined });
}));
}
}
});
return menuEntries;
}...
});
return this._createEntries(element, entries);
}
// sequence flows
if (is(businessObject, 'bpmn:SequenceFlow')) {
return this._createSequenceFlowEntries(element, replaceOptions.SEQUENCE_FLOW);
}
// flow nodes
if (is(businessObject, 'bpmn:FlowNode')) {
entries = filter(replaceOptions.TASK, differentType);
// collapsed SubProcess can not be replaced with itself
..._getAdHocEntry = function (element) {
var translate = this._translate;
var businessObject = getBusinessObject(element);
var isAdHoc = is(businessObject, 'bpmn:AdHocSubProcess');
var replaceElement = this._bpmnReplace.replaceElement;
var adHocEntry = {
id: 'toggle-adhoc',
className: 'bpmn-icon-ad-hoc-marker',
title: translate('Ad-hoc'),
active: isAdHoc,
action: function(event, entry) {
if (isAdHoc) {
return replaceElement(element, { type: 'bpmn:SubProcess' });
} else {
return replaceElement(element, { type: 'bpmn:AdHocSubProcess' });
}
}
};
return adHocEntry;
}...
if (is(element, 'bpmn:Activity') && !isEventSubProcess(element)) {
headerEntries = headerEntries.concat(this._getLoopEntries(element));
}
if (is(element, 'bpmn:SubProcess') &&
!is(element, 'bpmn:Transaction') &&
!isEventSubProcess(element)) {
headerEntries.push(this._getAdHocEntry(element));
}
return headerEntries;
};
/**
..._getLoopEntries = function (element) {
var self = this;
var translate = this._translate;
function toggleLoopEntry(event, entry) {
var loopCharacteristics;
if (entry.active) {
loopCharacteristics = undefined;
} else {
loopCharacteristics = self._moddle.create(entry.options.loopCharacteristics);
if (entry.options.isSequential) {
loopCharacteristics.isSequential = entry.options.isSequential;
}
}
self._modeling.updateProperties(element, { loopCharacteristics: loopCharacteristics });
}
var businessObject = getBusinessObject(element),
loopCharacteristics = businessObject.loopCharacteristics;
var isSequential,
isLoop,
isParallel;
if (loopCharacteristics) {
isSequential = loopCharacteristics.isSequential;
isLoop = loopCharacteristics.isSequential === undefined;
isParallel = loopCharacteristics.isSequential !== undefined && !loopCharacteristics.isSequential;
}
var loopEntries = [
{
id: 'toggle-parallel-mi',
className: 'bpmn-icon-parallel-mi-marker',
title: translate('Parallel Multi Instance'),
active: isParallel,
action: toggleLoopEntry,
options: {
loopCharacteristics: 'bpmn:MultiInstanceLoopCharacteristics',
isSequential: false
}
},
{
id: 'toggle-sequential-mi',
className: 'bpmn-icon-sequential-mi-marker',
title: translate('Sequential Multi Instance'),
active: isSequential,
action: toggleLoopEntry,
options: {
loopCharacteristics: 'bpmn:MultiInstanceLoopCharacteristics',
isSequential: true
}
},
{
id: 'toggle-loop',
className: 'bpmn-icon-loop-marker',
title: translate('Loop'),
active: isLoop,
action: toggleLoopEntry,
options: {
loopCharacteristics: 'bpmn:StandardLoopCharacteristics'
}
}
];
return loopEntries;
}...
* @return {Array<Object>} a list of menu entry items
*/
ReplaceMenuProvider.prototype.getHeaderEntries = function(element) {
var headerEntries = [];
if (is(element, 'bpmn:Activity') && !isEventSubProcess(element)) {
headerEntries = headerEntries.concat(this._getLoopEntries(element));
}
if (is(element, 'bpmn:SubProcess') &&
!is(element, 'bpmn:Transaction') &&
!isEventSubProcess(element)) {
headerEntries.push(this._getAdHocEntry(element));
}
...getEntries = function (element) {
var businessObject = element.businessObject;
var rules = this._rules;
var entries;
if (!rules.allowed('shape.replace', { element: element })) {
return [];
}
var differentType = isDifferentType(element);
// start events outside event sub processes
if (is(businessObject, 'bpmn:StartEvent') && !isEventSubProcess(businessObject.$parent)) {
entries = filter(replaceOptions.START_EVENT, differentType);
return this._createEntries(element, entries);
}
// expanded/collapsed pools
if (is(businessObject, 'bpmn:Participant')) {
entries = filter(replaceOptions.PARTICIPANT, function(entry) {
return isExpanded(businessObject) !== entry.target.isExpanded;
});
return this._createEntries(element, entries);
}
// start events inside event sub processes
if (is(businessObject, 'bpmn:StartEvent') && isEventSubProcess(businessObject.$parent)) {
entries = filter(replaceOptions.EVENT_SUB_PROCESS_START_EVENT, function(entry) {
var target = entry.target;
var isInterrupting = target.isInterrupting !== false;
var isInterruptingEqual = getBusinessObject(element).isInterrupting === isInterrupting;
// filters elements which types and event definition are equal but have have different interrupting types
return differentType(entry) || !differentType(entry) && !isInterruptingEqual;
});
return this._createEntries(element, entries);
}
// end events
if (is(businessObject, 'bpmn:EndEvent')) {
entries = filter(replaceOptions.END_EVENT, function(entry) {
var target = entry.target;
// hide cancel end events outside transactions
if (target.eventDefinitionType == 'bpmn:CancelEventDefinition' && !is(businessObject.$parent, 'bpmn:Transaction')) {
return false;
}
return differentType(entry);
});
return this._createEntries(element, entries);
}
// boundary events
if (is(businessObject, 'bpmn:BoundaryEvent')) {
entries = filter(replaceOptions.BOUNDARY_EVENT, function(entry) {
var target = entry.target;
if (target.eventDefinition == 'bpmn:CancelEventDefinition' &&
!is(businessObject.attachedToRef, 'bpmn:Transaction')) {
return false;
}
var cancelActivity = target.cancelActivity !== false;
var isCancelActivityEqual = businessObject.cancelActivity == cancelActivity;
return differentType(entry) || !differentType(entry) && !isCancelActivityEqual;
});
return this._createEntries(element, entries);
}
// intermediate events
if (is(businessObject, 'bpmn:IntermediateCatchEvent') ||
is(businessObject, 'bpmn:IntermediateThrowEvent')) {
entries = filter(replaceOptions.INTERMEDIATE_EVENT, differentType);
return this._createEntries(element, entries);
}
// gateways
if (is(businessObject, 'bpmn:Gateway')) {
entries = filter(replaceOptions.GATEWAY, differentType);
return this._createEntries(element, entries);
}
// transactions
if (is(businessObject, 'bpmn:Transaction')) {
entries = filter(replaceOptions.TRANSACTION, differentType);
return this._createEntries(element, entries);
}
// expanded event sub processes
if (isEventSubProcess(businessObject) && isExpanded(businessObject)) {
entries = filter(replaceOptions.EVENT_SUB_PROCESS, differentType);
return this._createEntries(element, entries);
}
// expanded sub processes
if (is(businessObject, 'bpmn:SubProcess') && isExpanded(businessObject)) {
entries = filter(replaceOptions.SUBPROCESS_EXPANDED, differentType);
return this._createEntries(element, entries);
}
// collapsed ad hoc sub processes
if (is(businessObject, 'bpmn:AdHocSubProcess') && !isExpanded(businessObject)) {
entries = filter(replaceOptions.TASK, function(entry) {
var target = entry.target;
var isTargetSubProcess = target.type === 'bpmn:SubProcess';
var isTargetExpanded = target.isExpanded === true;
return isDifferentType(element, target) && ( !isTargetSubProcess || isTargetExpa ......
eventBus.on('create.end', 250, function(event) {
var shape = event.context.shape;
if (!hasPrimaryModifier(event)) {
return;
}
var entries = contextPad.getEntries(shape);
if (entries.replace) {
entries.replace.action.click(event, shape);
}
});
}
...getHeaderEntries = function (element) {
var headerEntries = [];
if (is(element, 'bpmn:Activity') && !isEventSubProcess(element)) {
headerEntries = headerEntries.concat(this._getLoopEntries(element));
}
if (is(element, 'bpmn:SubProcess') &&
!is(element, 'bpmn:Transaction') &&
!isEventSubProcess(element)) {
headerEntries.push(this._getAdHocEntry(element));
}
return headerEntries;
}n/a
register = function () {
this._popupMenu.registerProvider('bpmn-replace', this);
}...
alignElements,
directEditing,
searchPad,
modeling) {
injector.invoke(EditorActions, this);
this.register({
selectElements: function() {
// select all elements except for the invisible
// root element
var rootElement = canvas.getRootElement();
var elements = elementRegistry.filter(function(element) {
return element !== rootElement;
...elementToString = function (e) {
if (!e) {
return '<null>';
}
return '<' + e.$type + (e.id ? ' id="' + e.id : '') + '" />';
}n/a