chore(replace): separate popup menu from replace logic
This commit makes use of the provider concept introduced in diagram-js. The replace menu entries are now created in the replace menu provider. This separates BpmnReplace from the entry creation in the popup menu. Closes #428
This commit is contained in:
parent
93d4bade22
commit
eb7b5d7bb4
|
@ -14,7 +14,7 @@ var assign = require('lodash/object/assign'),
|
|||
* A provider for BPMN 2.0 elements context pad
|
||||
*/
|
||||
function ContextPadProvider(contextPad, modeling, elementFactory,
|
||||
connect, create, bpmnReplace,
|
||||
connect, create, popupMenu,
|
||||
canvas, rules) {
|
||||
|
||||
contextPad.registerProvider(this);
|
||||
|
@ -26,7 +26,7 @@ function ContextPadProvider(contextPad, modeling, elementFactory,
|
|||
this._elementFactory = elementFactory;
|
||||
this._connect = connect;
|
||||
this._create = create;
|
||||
this._bpmnReplace = bpmnReplace;
|
||||
this._popupMenu = popupMenu;
|
||||
this._canvas = canvas;
|
||||
this._rules = rules;
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ ContextPadProvider.$inject = [
|
|||
'elementFactory',
|
||||
'connect',
|
||||
'create',
|
||||
'bpmnReplace',
|
||||
'popupMenu',
|
||||
'canvas',
|
||||
'rules'
|
||||
];
|
||||
|
@ -53,7 +53,7 @@ ContextPadProvider.prototype.getContextPadEntries = function(element) {
|
|||
elementFactory = this._elementFactory,
|
||||
connect = this._connect,
|
||||
create = this._create,
|
||||
bpmnReplace = this._bpmnReplace,
|
||||
popupMenu = this._popupMenu,
|
||||
canvas = this._canvas,
|
||||
rules = this._rules;
|
||||
|
||||
|
@ -225,9 +225,14 @@ ContextPadProvider.prototype.getContextPadEntries = function(element) {
|
|||
}
|
||||
}
|
||||
|
||||
var replaceOptions = bpmnReplace.getReplaceOptions(element);
|
||||
var replaceMenu;
|
||||
|
||||
if (popupMenu._providers['bpmn-replace']) {
|
||||
replaceMenu = popupMenu.create('bpmn-replace', element);
|
||||
}
|
||||
|
||||
if (replaceMenu && !replaceMenu.isEmpty()) {
|
||||
|
||||
if (replaceOptions.length) {
|
||||
// Replace menu entry
|
||||
assign(actions, {
|
||||
'replace': {
|
||||
|
@ -236,7 +241,7 @@ ContextPadProvider.prototype.getContextPadEntries = function(element) {
|
|||
title: 'Change type',
|
||||
action: {
|
||||
click: function(event, element) {
|
||||
bpmnReplace.openChooser(getReplaceMenuPosition(element), element);
|
||||
replaceMenu.open(getReplaceMenuPosition(element));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ module.exports = {
|
|||
require('diagram-js/lib/features/selection'),
|
||||
require('diagram-js/lib/features/connect'),
|
||||
require('diagram-js/lib/features/create'),
|
||||
require('../replace')
|
||||
require('../popup-menu')
|
||||
],
|
||||
__init__: [ 'contextPadProvider' ],
|
||||
contextPadProvider: [ 'type', require('./ContextPadProvider') ]
|
||||
|
|
|
@ -0,0 +1,452 @@
|
|||
'use strict';
|
||||
|
||||
var is = require('../../util/ModelUtil').is,
|
||||
isEventSubProcess = require('../../util/DiUtil').isEventSubProcess,
|
||||
getBusinessObject = require('../../util/ModelUtil').getBusinessObject,
|
||||
isExpanded = require('../../util/DiUtil').isExpanded,
|
||||
isDifferentType = require('./util/TypeUtil').isDifferentType;
|
||||
|
||||
var forEach = require('lodash/collection/forEach'),
|
||||
filter = require('lodash/collection/filter');
|
||||
|
||||
var replaceOptions = require ('../replace/ReplaceOptions');
|
||||
|
||||
|
||||
/**
|
||||
* This module is an element agnostic replace menu provider for the popup menu.
|
||||
*/
|
||||
function ReplaceMenuProvider(popupMenu, modeling, moddle, bpmnReplace, rules) {
|
||||
|
||||
this._popupMenu = popupMenu;
|
||||
this._modeling = modeling;
|
||||
this._moddle = moddle;
|
||||
this._bpmnReplace = bpmnReplace;
|
||||
this._rules = rules;
|
||||
|
||||
this.register();
|
||||
}
|
||||
|
||||
ReplaceMenuProvider.$inject = [ 'popupMenu', 'modeling', 'moddle', 'bpmnReplace', 'rules' ];
|
||||
|
||||
|
||||
/**
|
||||
* Register replace menu provider in the popup menu
|
||||
*/
|
||||
ReplaceMenuProvider.prototype.register = function() {
|
||||
this._popupMenu.registerProvider('bpmn-replace', this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get all entries from replaceOptions for the given element and apply filters
|
||||
* on them. Get for example only elements, which are different from the current one.
|
||||
*
|
||||
* @param {djs.model.Base} element
|
||||
*
|
||||
* @return {Array<Object>} a list of menu entry items
|
||||
*/
|
||||
ReplaceMenuProvider.prototype.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);
|
||||
}
|
||||
|
||||
// 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.eventDefinition == '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';
|
||||
|
||||
return isDifferentType(element, target) && !isTargetSubProcess;
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
return this._createEntries(element, entries);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of header items for the given element. This includes buttons
|
||||
* for multi instance markers and for the ad hoc marker.
|
||||
*
|
||||
* @param {djs.model.Base} element
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
return headerEntries;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates an array of menu entry objects for a given element and filters the replaceOptions
|
||||
* according to a filter function.
|
||||
*
|
||||
* @param {djs.model.Base} element
|
||||
* @param {Object} replaceOptions
|
||||
*
|
||||
* @return {Array<Object>} a list of menu items
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates an array of menu entry objects for a given sequence flow.
|
||||
*
|
||||
* @param {djs.model.Base} element
|
||||
* @param {Object} replaceOptions
|
||||
|
||||
* @return {Array<Object>} a list of menu items
|
||||
*/
|
||||
ReplaceMenuProvider.prototype._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'))) {
|
||||
|
||||
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')) &&
|
||||
businessObject.sourceRef.default === businessObject) {
|
||||
|
||||
return menuEntries.push(self._createMenuEntry(entry, element, function() {
|
||||
modeling.updateProperties(element.source, { default: undefined });
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return menuEntries;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates and returns a single menu entry item.
|
||||
*
|
||||
* @param {Object} definition a single replace options definition object
|
||||
* @param {djs.model.Base} element
|
||||
* @param {Function} [action] an action callback function which gets called when
|
||||
* the menu entry is being triggered.
|
||||
*
|
||||
* @return {Object} menu entry item
|
||||
*/
|
||||
ReplaceMenuProvider.prototype._createMenuEntry = function(definition, element, action) {
|
||||
|
||||
var replaceElement = this._bpmnReplace.replaceElement;
|
||||
|
||||
var replaceAction = function() {
|
||||
return replaceElement(element, definition.target);
|
||||
};
|
||||
|
||||
action = action || replaceAction;
|
||||
|
||||
var menuEntry = {
|
||||
label: definition.label,
|
||||
className: definition.className,
|
||||
id: definition.actionName,
|
||||
action: action
|
||||
};
|
||||
|
||||
return menuEntry;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a list of menu items containing buttons for multi instance markers
|
||||
*
|
||||
* @param {djs.model.Base} element
|
||||
*
|
||||
* @return {Array<Object>} a list of menu items
|
||||
*/
|
||||
ReplaceMenuProvider.prototype._getLoopEntries = function(element) {
|
||||
|
||||
var self = this;
|
||||
|
||||
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: 'Parallel Multi Instance',
|
||||
active: isParallel,
|
||||
action: toggleLoopEntry,
|
||||
options: {
|
||||
loopCharacteristics: 'bpmn:MultiInstanceLoopCharacteristics',
|
||||
isSequential: false
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'toggle-sequential-mi',
|
||||
className: 'bpmn-icon-sequential-mi-marker',
|
||||
title: 'Sequential Multi Instance',
|
||||
active: isSequential,
|
||||
action: toggleLoopEntry,
|
||||
options: {
|
||||
loopCharacteristics: 'bpmn:MultiInstanceLoopCharacteristics',
|
||||
isSequential: true
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'toggle-loop',
|
||||
className: 'bpmn-icon-loop-marker',
|
||||
title: 'Loop',
|
||||
active: isLoop,
|
||||
action: toggleLoopEntry,
|
||||
options: {
|
||||
loopCharacteristics: 'bpmn:StandardLoopCharacteristics'
|
||||
}
|
||||
}
|
||||
];
|
||||
return loopEntries;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the menu items containing a button for the ad hoc marker
|
||||
*
|
||||
* @param {djs.model.Base} element
|
||||
*
|
||||
* @return {Object} a menu item
|
||||
*/
|
||||
ReplaceMenuProvider.prototype._getAdHocEntry = function(element) {
|
||||
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: '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;
|
||||
};
|
||||
|
||||
module.exports = ReplaceMenuProvider;
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
__init__: [ 'replaceMenuProvider' ],
|
||||
replaceMenuProvider: [ 'type', require('./ReplaceMenuProvider') ]
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
'use strict';
|
||||
|
||||
var getBusinessObject = require('../../../util/ModelUtil').getBusinessObject;
|
||||
|
||||
/**
|
||||
* Returns true, if an element is from a different type than a target definition.
|
||||
* Takes into account the type and the event definition type.
|
||||
*
|
||||
* @param {djs.model.Base} element
|
||||
*
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function isDifferentType(element) {
|
||||
|
||||
return function(entry) {
|
||||
var target = entry.target;
|
||||
|
||||
var businessObject = getBusinessObject(element),
|
||||
eventDefinition = businessObject.eventDefinitions && businessObject.eventDefinitions[0].$type;
|
||||
|
||||
var isEventDefinitionEqual = target.eventDefinition == eventDefinition,
|
||||
isTypeEqual = businessObject.$type == target.type;
|
||||
|
||||
return (!isEventDefinitionEqual && isTypeEqual) || !isTypeEqual;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports.isDifferentType = isDifferentType;
|
|
@ -1,30 +1,12 @@
|
|||
'use strict';
|
||||
|
||||
var forEach = require('lodash/collection/forEach'),
|
||||
filter = require('lodash/collection/filter'),
|
||||
pick = require('lodash/object/pick'),
|
||||
var pick = require('lodash/object/pick'),
|
||||
assign = require('lodash/object/assign');
|
||||
|
||||
var REPLACE_OPTIONS = require ('./ReplaceOptions');
|
||||
|
||||
var startEventReplace = REPLACE_OPTIONS.START_EVENT,
|
||||
intermediateEventReplace = REPLACE_OPTIONS.INTERMEDIATE_EVENT,
|
||||
endEventReplace = REPLACE_OPTIONS.END_EVENT,
|
||||
gatewayReplace = REPLACE_OPTIONS.GATEWAY,
|
||||
taskReplace = REPLACE_OPTIONS.TASK,
|
||||
subProcessExpandedReplace = REPLACE_OPTIONS.SUBPROCESS_EXPANDED,
|
||||
transactionReplace = REPLACE_OPTIONS.TRANSACTION,
|
||||
eventSubProcessReplace = REPLACE_OPTIONS.EVENT_SUB_PROCESS,
|
||||
boundaryEventReplace = REPLACE_OPTIONS.BOUNDARY_EVENT,
|
||||
eventSubProcessStartEventReplace = REPLACE_OPTIONS.EVENT_SUB_PROCESS_START_EVENT,
|
||||
sequenceFlowReplace = REPLACE_OPTIONS.SEQUENCE_FLOW;
|
||||
|
||||
var is = require('../../util/ModelUtil').is,
|
||||
getBusinessObject = require('../../util/ModelUtil').getBusinessObject,
|
||||
isExpanded = require('../../util/DiUtil').isExpanded,
|
||||
isEventSubProcess = require('../../util/DiUtil').isEventSubProcess;
|
||||
|
||||
|
||||
var CUSTOM_PROPERTIES = [
|
||||
'cancelActivity',
|
||||
'instantiate',
|
||||
|
@ -35,19 +17,9 @@ var CUSTOM_PROPERTIES = [
|
|||
|
||||
|
||||
/**
|
||||
* A replace menu provider that gives users the controls to choose
|
||||
* and replace BPMN elements with each other.
|
||||
*
|
||||
* @param {BpmnFactory} bpmnFactory
|
||||
* @param {Moddle} moddle
|
||||
* @param {PopupMenu} popupMenu
|
||||
* @param {Replace} replace
|
||||
* This module takes care of replacing BPMN elements
|
||||
*/
|
||||
function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection, modeling, eventBus, rules) {
|
||||
|
||||
var self = this,
|
||||
currentElement;
|
||||
|
||||
function BpmnReplace(bpmnFactory, replace, selection, modeling) {
|
||||
|
||||
/**
|
||||
* Prepares a new business object for the replacement element
|
||||
|
@ -56,6 +28,7 @@ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection, modelin
|
|||
* @param {djs.model.Base} element
|
||||
* @param {Object} target
|
||||
* @param {Object} [hints]
|
||||
*
|
||||
* @return {djs.model.Base} the newly created element
|
||||
*/
|
||||
function replaceElement(element, target, hints) {
|
||||
|
@ -74,7 +47,7 @@ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection, modelin
|
|||
// initialize custom BPMN extensions
|
||||
if (target.eventDefinition) {
|
||||
var eventDefinitions = businessObject.get('eventDefinitions'),
|
||||
eventDefinition = moddle.create(target.eventDefinition);
|
||||
eventDefinition = bpmnFactory.create(target.eventDefinition);
|
||||
|
||||
eventDefinition.$parent = businessObject;
|
||||
eventDefinitions.push(eventDefinition);
|
||||
|
@ -119,335 +92,9 @@ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection, modelin
|
|||
return newElement;
|
||||
}
|
||||
|
||||
|
||||
function toggleLoopEntry(event, entry) {
|
||||
var loopEntries = self.getLoopEntries(currentElement);
|
||||
|
||||
var loopCharacteristics;
|
||||
|
||||
if (entry.active) {
|
||||
loopCharacteristics = undefined;
|
||||
} else {
|
||||
forEach(loopEntries, function(action) {
|
||||
var options = action.options;
|
||||
|
||||
if (entry.id === action.id) {
|
||||
loopCharacteristics = moddle.create(options.loopCharacteristics);
|
||||
|
||||
if (options.isSequential) {
|
||||
loopCharacteristics.isSequential = options.isSequential;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
modeling.updateProperties(currentElement, { loopCharacteristics: loopCharacteristics });
|
||||
}
|
||||
|
||||
|
||||
function getLoopEntries(element) {
|
||||
|
||||
currentElement = element;
|
||||
|
||||
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: 'Parallel Multi Instance',
|
||||
active: isParallel,
|
||||
action: toggleLoopEntry,
|
||||
options: {
|
||||
loopCharacteristics: 'bpmn:MultiInstanceLoopCharacteristics',
|
||||
isSequential: false
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'toggle-sequential-mi',
|
||||
className: 'bpmn-icon-sequential-mi-marker',
|
||||
title: 'Sequential Multi Instance',
|
||||
active: isSequential,
|
||||
action: toggleLoopEntry,
|
||||
options: {
|
||||
loopCharacteristics: 'bpmn:MultiInstanceLoopCharacteristics',
|
||||
isSequential: true
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'toggle-loop',
|
||||
className: 'bpmn-icon-loop-marker',
|
||||
title: 'Loop',
|
||||
active: isLoop,
|
||||
action: toggleLoopEntry,
|
||||
options: {
|
||||
loopCharacteristics: 'bpmn:StandardLoopCharacteristics'
|
||||
}
|
||||
}
|
||||
];
|
||||
return loopEntries;
|
||||
}
|
||||
|
||||
|
||||
function getAdHocEntry(element) {
|
||||
var businessObject = getBusinessObject(element);
|
||||
|
||||
var isAdHoc = is(businessObject, 'bpmn:AdHocSubProcess');
|
||||
|
||||
var adHocEntry = {
|
||||
id: 'toggle-adhoc',
|
||||
className: 'bpmn-icon-ad-hoc-marker',
|
||||
title: '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;
|
||||
}
|
||||
|
||||
|
||||
this.getReplaceOptions = function(element) {
|
||||
|
||||
if (!rules.allowed('shape.replace', { element: element })) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var menuEntries = [];
|
||||
var businessObject = element.businessObject;
|
||||
|
||||
// start events outside event sub processes
|
||||
if (is(businessObject, 'bpmn:StartEvent') && !isEventSubProcess(businessObject.$parent)) {
|
||||
addEntries(startEventReplace, filterEvents);
|
||||
} else
|
||||
|
||||
// start events inside event sub processes
|
||||
if (is(businessObject, 'bpmn:StartEvent') && isEventSubProcess(businessObject.$parent)) {
|
||||
addEntries(eventSubProcessStartEventReplace, filterEvents);
|
||||
} else
|
||||
|
||||
if (is(businessObject, 'bpmn:IntermediateCatchEvent') ||
|
||||
is(businessObject, 'bpmn:IntermediateThrowEvent')) {
|
||||
|
||||
addEntries(intermediateEventReplace, filterEvents);
|
||||
} else
|
||||
|
||||
if (is(businessObject, 'bpmn:EndEvent')) {
|
||||
|
||||
addEntries(endEventReplace, filterEvents);
|
||||
} else
|
||||
|
||||
if (is(businessObject, 'bpmn:Gateway')) {
|
||||
|
||||
addEntries(gatewayReplace, function(entry) {
|
||||
|
||||
return entry.target.type !== businessObject.$type;
|
||||
});
|
||||
} else
|
||||
|
||||
if (is(businessObject, 'bpmn:Transaction')) {
|
||||
|
||||
addEntries(transactionReplace);
|
||||
} else
|
||||
|
||||
if (isEventSubProcess(businessObject) && isExpanded(businessObject)) {
|
||||
|
||||
addEntries(eventSubProcessReplace);
|
||||
} else
|
||||
|
||||
if (is(businessObject, 'bpmn:SubProcess') && isExpanded(businessObject)) {
|
||||
|
||||
addEntries(subProcessExpandedReplace);
|
||||
} else
|
||||
|
||||
if (is(businessObject, 'bpmn:AdHocSubProcess') && !isExpanded(businessObject)) {
|
||||
addEntries(taskReplace, function(entry) {
|
||||
return entry.target.type !== 'bpmn:SubProcess';
|
||||
});
|
||||
} else
|
||||
|
||||
if (is(businessObject, 'bpmn:BoundaryEvent')) {
|
||||
addEntries(boundaryEventReplace, filterEvents);
|
||||
} else
|
||||
|
||||
if (is(businessObject, 'bpmn:SequenceFlow')) {
|
||||
addSequenceFlowEntries(sequenceFlowReplace);
|
||||
} else
|
||||
|
||||
if (is(businessObject, 'bpmn:FlowNode')) {
|
||||
addEntries(taskReplace, function(entry) {
|
||||
return entry.target.type !== businessObject.$type;
|
||||
});
|
||||
}
|
||||
|
||||
function addSequenceFlowEntries(entries) {
|
||||
forEach(entries, 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'))) {
|
||||
|
||||
menuEntries.push(addMenuEntry(entry, function() {
|
||||
modeling.updateProperties(element.source, { default: businessObject });
|
||||
}));
|
||||
}
|
||||
break;
|
||||
case 'replace-with-conditional-flow':
|
||||
if (!businessObject.conditionExpression && is(businessObject.sourceRef, 'bpmn:Activity')) {
|
||||
|
||||
menuEntries.push(addMenuEntry(entry, 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(addMenuEntry(entry, function() {
|
||||
modeling.updateProperties(element, { conditionExpression: undefined });
|
||||
}));
|
||||
}
|
||||
// conditional flows
|
||||
if ((is(businessObject.sourceRef, 'bpmn:ExclusiveGateway') ||
|
||||
is(businessObject.sourceRef, 'bpmn:InclusiveGateway')) &&
|
||||
businessObject.sourceRef.default === businessObject) {
|
||||
|
||||
return menuEntries.push(addMenuEntry(entry, function() {
|
||||
modeling.updateProperties(element.source, { default: undefined });
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function filterEvents(entry) {
|
||||
|
||||
var target = entry.target;
|
||||
|
||||
var eventDefinition = businessObject.eventDefinitions && businessObject.eventDefinitions[0].$type;
|
||||
|
||||
var isEventDefinitionEqual = target.eventDefinition == eventDefinition,
|
||||
isEventTypeEqual = businessObject.$type == target.type;
|
||||
|
||||
// filter for boundary events
|
||||
if (is(businessObject, 'bpmn:BoundaryEvent')) {
|
||||
if (target.eventDefinition == 'bpmn:CancelEventDefinition' &&
|
||||
!is(businessObject.attachedToRef, 'bpmn:Transaction')) {
|
||||
return false;
|
||||
}
|
||||
var cancelActivity = target.cancelActivity !== false;
|
||||
|
||||
var isCancelActivityEqual = businessObject.cancelActivity == cancelActivity;
|
||||
|
||||
return !(isEventDefinitionEqual && isEventTypeEqual && isCancelActivityEqual);
|
||||
}
|
||||
|
||||
// filter for start events inside event sub processes
|
||||
if (is(businessObject, 'bpmn:StartEvent') && isEventSubProcess(businessObject.$parent)) {
|
||||
var isInterrupting = target.isInterrupting !== false;
|
||||
|
||||
var isInterruptingEqual = businessObject.isInterrupting == isInterrupting;
|
||||
|
||||
return !(isEventDefinitionEqual && isEventDefinitionEqual && isInterruptingEqual);
|
||||
}
|
||||
|
||||
if (is(businessObject, 'bpmn:EndEvent') && target.eventDefinition == 'bpmn:CancelEventDefinition' &&
|
||||
!is(businessObject.$parent, 'bpmn:Transaction')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// filter for all other elements
|
||||
return (!isEventDefinitionEqual && isEventTypeEqual) || !isEventTypeEqual;
|
||||
}
|
||||
|
||||
|
||||
function addEntries(entries, filterFun) {
|
||||
// Filter selected type from the array
|
||||
var filteredEntries = filter(entries, filterFun);
|
||||
|
||||
// Add entries to replace menu
|
||||
forEach(filteredEntries, function(definition) {
|
||||
var entry = addMenuEntry(definition);
|
||||
menuEntries.push(entry);
|
||||
});
|
||||
}
|
||||
|
||||
function addMenuEntry(definition, action) {
|
||||
|
||||
var menuEntry = {
|
||||
label: definition.label,
|
||||
className: definition.className,
|
||||
id: definition.actionName,
|
||||
action: action
|
||||
};
|
||||
|
||||
if (!menuEntry.action) {
|
||||
menuEntry.action = function() {
|
||||
return replaceElement(element, definition.target);
|
||||
};
|
||||
}
|
||||
|
||||
return menuEntry;
|
||||
}
|
||||
|
||||
return menuEntries;
|
||||
};
|
||||
|
||||
/**
|
||||
* Open a replace chooser for an element on the specified position.
|
||||
*
|
||||
* @param {Object} position
|
||||
* @param {Object} element
|
||||
*/
|
||||
this.openChooser = function(position, element) {
|
||||
var entries = this.getReplaceOptions(element),
|
||||
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));
|
||||
}
|
||||
|
||||
popupMenu.open({
|
||||
className: 'replace-menu',
|
||||
element: element,
|
||||
position: position,
|
||||
headerEntries: headerEntries,
|
||||
entries: entries
|
||||
});
|
||||
};
|
||||
|
||||
this.getLoopEntries = getLoopEntries;
|
||||
|
||||
this.getAdHocEntry = getAdHocEntry;
|
||||
|
||||
this.replaceElement = replaceElement;
|
||||
}
|
||||
|
||||
BpmnReplace.$inject = [ 'bpmnFactory', 'moddle', 'popupMenu', 'replace', 'selection', 'modeling', 'eventBus', 'rules' ];
|
||||
BpmnReplace.$inject = [ 'bpmnFactory', 'replace', 'selection', 'modeling' ];
|
||||
|
||||
module.exports = BpmnReplace;
|
||||
|
|
|
@ -723,16 +723,16 @@ module.exports.SEQUENCE_FLOW = [
|
|||
{
|
||||
label: 'Sequence Flow',
|
||||
actionName: 'replace-with-sequence-flow',
|
||||
className: 'bpmn-icon-connection',
|
||||
className: 'bpmn-icon-connection'
|
||||
},
|
||||
{
|
||||
label: 'Default Flow',
|
||||
actionName: 'replace-with-default-flow',
|
||||
className: 'bpmn-icon-default-flow',
|
||||
className: 'bpmn-icon-default-flow'
|
||||
},
|
||||
{
|
||||
label: 'Conditional Flow',
|
||||
actionName: 'replace-with-conditional-flow',
|
||||
className: 'bpmn-icon-conditional-flow',
|
||||
className: 'bpmn-icon-conditional-flow'
|
||||
}
|
||||
];
|
||||
|
|
|
@ -13,6 +13,7 @@ var contextPadModule = require('../../../../lib/features/context-pad'),
|
|||
coreModule = require('../../../../lib/core'),
|
||||
modelingModule = require('../../../../lib/features/modeling'),
|
||||
popupModule = require('diagram-js/lib/features/popup-menu'),
|
||||
replaceMenuProvider = require('../../../../lib/features/popup-menu'),
|
||||
replaceModule = require('diagram-js/lib/features/replace'),
|
||||
rulesModule = require('../../../util/custom-rules');
|
||||
|
||||
|
@ -21,14 +22,15 @@ describe('features - context-pad', function() {
|
|||
|
||||
var diagramXML = require('../../../fixtures/bpmn/simple.bpmn');
|
||||
|
||||
var testModules = [ contextPadModule, coreModule, modelingModule, popupModule, replaceModule, rulesModule ];
|
||||
var testModules = [ contextPadModule, coreModule, modelingModule, popupModule,
|
||||
replaceModule, rulesModule, replaceMenuProvider ];
|
||||
|
||||
beforeEach(bootstrapViewer(diagramXML, { modules: testModules }));
|
||||
|
||||
|
||||
describe('bootstrap', function() {
|
||||
|
||||
it('should bootstrap', inject(function(contextPadProvider) {
|
||||
it('should bootstrap', inject(function(contextPadProvider, replaceMenuProvider) {
|
||||
expect(contextPadProvider).to.exist;
|
||||
}));
|
||||
|
||||
|
@ -60,7 +62,8 @@ describe('features - context-pad', function() {
|
|||
}));
|
||||
|
||||
|
||||
it('should include delete action when rule returns true', inject(function (elementRegistry, contextPad, customRules) {
|
||||
it('should include delete action when rule returns true',
|
||||
inject(function (elementRegistry, contextPad, customRules) {
|
||||
|
||||
// given
|
||||
customRules.addRule('elements.delete', function() {
|
||||
|
@ -77,7 +80,8 @@ describe('features - context-pad', function() {
|
|||
}));
|
||||
|
||||
|
||||
it('should NOT include delete action when rule returns false', inject(function(elementRegistry, contextPad, customRules) {
|
||||
it('should NOT include delete action when rule returns false',
|
||||
inject(function(elementRegistry, contextPad, customRules) {
|
||||
|
||||
// given
|
||||
customRules.addRule('elements.delete', function() {
|
||||
|
@ -114,7 +118,8 @@ describe('features - context-pad', function() {
|
|||
}));
|
||||
|
||||
|
||||
it('should include delete action when [ element ] is returned from rule', inject(function(elementRegistry, contextPad, customRules) {
|
||||
it('should include delete action when [ element ] is returned from rule',
|
||||
inject(function(elementRegistry, contextPad, customRules) {
|
||||
|
||||
// given
|
||||
customRules.addRule('elements.delete', function(context) {
|
||||
|
@ -131,7 +136,8 @@ describe('features - context-pad', function() {
|
|||
}));
|
||||
|
||||
|
||||
it('should NOT include delete action when [ ] is returned from rule', inject(function(elementRegistry, contextPad, customRules) {
|
||||
it('should NOT include delete action when [ ] is returned from rule',
|
||||
inject(function(elementRegistry, contextPad, customRules) {
|
||||
|
||||
// given
|
||||
customRules.addRule('elements.delete', function() {
|
||||
|
@ -176,7 +182,7 @@ describe('features - context-pad', function() {
|
|||
|
||||
// when
|
||||
contextPad.trigger('click', event);
|
||||
replaceMenuRect = domQuery('.replace-menu', container).getBoundingClientRect();
|
||||
replaceMenuRect = domQuery('.bpmn-replace', container).getBoundingClientRect();
|
||||
|
||||
// then
|
||||
expect(replaceMenuRect.left).to.be.at.most(padMenuRect.left);
|
||||
|
|
|
@ -1,702 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
/* global bootstrapModeler, inject */
|
||||
|
||||
var TestHelper = require('../../../TestHelper');
|
||||
|
||||
var globalEvent = require('../../../util/MockEvents.js').createEvent;
|
||||
|
||||
var coreModule = require('../../../../lib/core'),
|
||||
popupMenuModule = require('diagram-js/lib/features/popup-menu'),
|
||||
modelingModule = require('../../../../lib/features/modeling'),
|
||||
replaceModule = require('../../../../lib/features/replace');
|
||||
|
||||
var domQuery = require('min-dom/lib/query'),
|
||||
domClasses = require('min-dom/lib/classes');
|
||||
|
||||
var is = require('../../../../lib/util/ModelUtil').is,
|
||||
isExpanded = require('../../../../lib/util/DiUtil').isExpanded;
|
||||
|
||||
function queryEntry(popupMenu, id) {
|
||||
return queryPopup(popupMenu, '[data-id="' + id + '"]');
|
||||
}
|
||||
|
||||
function queryPopup(popupMenu, selector) {
|
||||
return domQuery(selector, popupMenu._current.container);
|
||||
}
|
||||
|
||||
|
||||
describe('features/popup-menu', function() {
|
||||
|
||||
var diagramXMLMarkers = require('../../../fixtures/bpmn/draw/activity-markers-simple.bpmn'),
|
||||
diagramXMLReplace = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn');
|
||||
|
||||
var testModules = [ coreModule, modelingModule, popupMenuModule, replaceModule ];
|
||||
|
||||
var openPopup = function(element, offset) {
|
||||
offset = offset || 100;
|
||||
|
||||
TestHelper.getBpmnJS().invoke(function(bpmnReplace){
|
||||
bpmnReplace.openChooser({ x: element.x + offset, y: element.y + offset }, element);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
describe('toggle', function(){
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXMLMarkers, { modules: testModules }));
|
||||
|
||||
describe('active attribute', function(){
|
||||
|
||||
it('should be true for parallel marker', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('ParallelTask'),
|
||||
loopCharacteristics = task.businessObject.loopCharacteristics;
|
||||
|
||||
// when
|
||||
openPopup(task);
|
||||
|
||||
// then
|
||||
expect(is(loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).to.be.true;
|
||||
|
||||
expect(loopCharacteristics.isSequential).to.be.false;
|
||||
expect(loopCharacteristics.isSequential).to.exist;
|
||||
|
||||
expect(popupMenu._getEntry('toggle-parallel-mi').active).to.be.true;
|
||||
}));
|
||||
|
||||
|
||||
it('should be true for sequential marker', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('SequentialTask'),
|
||||
loopCharacteristics = task.businessObject.loopCharacteristics;
|
||||
|
||||
// when
|
||||
openPopup(task);
|
||||
|
||||
// then
|
||||
expect(loopCharacteristics.isSequential).to.be.true;
|
||||
expect(popupMenu._getEntry('toggle-sequential-mi').active).to.be.true;
|
||||
expect(is(loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).to.be.true;
|
||||
}));
|
||||
|
||||
|
||||
it('should be true for loop marker', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('LoopTask'),
|
||||
loopCharacteristics = task.businessObject.loopCharacteristics;
|
||||
|
||||
// when
|
||||
openPopup(task);
|
||||
|
||||
// then
|
||||
expect(loopCharacteristics.isSequential).not.to.exist;
|
||||
expect(popupMenu._getEntry('toggle-loop').active).to.be.true;
|
||||
expect(is(loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).to.be.false;
|
||||
}));
|
||||
|
||||
|
||||
it('should be true for ad hoc marker', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var AdHocSubProcess = elementRegistry.get('AdHocSubProcess');
|
||||
|
||||
// when
|
||||
openPopup(AdHocSubProcess);
|
||||
|
||||
// then
|
||||
expect(popupMenu._getEntry('toggle-adhoc').active).to.be.true;
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('exclusive toggle buttons', function(){
|
||||
|
||||
it('should not toggle non exclusive buttons off', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
var subProcess = elementRegistry.get('AdHocSubProcess');
|
||||
|
||||
openPopup(subProcess);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// when
|
||||
popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(subProcess);
|
||||
|
||||
// then
|
||||
var adHocEntry = queryEntry(popupMenu, 'toggle-adhoc');
|
||||
|
||||
expect(domClasses(adHocEntry).has('active')).to.be.true;
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('non exclusive toggle buttons', function(){
|
||||
|
||||
it('should not toggle exclusive buttons off',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var subProcess = elementRegistry.get('SubProcess');
|
||||
|
||||
// when
|
||||
|
||||
// toggle parallel on
|
||||
openPopup(subProcess);
|
||||
|
||||
var parallelEntry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
popupMenu.trigger(globalEvent(parallelEntry, { x: 0, y: 0 }));
|
||||
|
||||
// toggle ad hoc on
|
||||
openPopup(subProcess);
|
||||
|
||||
var adHocEntry = queryEntry(popupMenu, 'toggle-adhoc');
|
||||
|
||||
var adHocSubProcess = popupMenu.trigger(globalEvent(adHocEntry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(adHocSubProcess);
|
||||
|
||||
// then
|
||||
parallelEntry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
adHocEntry = queryEntry(popupMenu, 'toggle-adhoc');
|
||||
|
||||
expect(domClasses(parallelEntry).has('active')).to.be.true;
|
||||
expect(domClasses(adHocEntry).has('active')).to.be.true;
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('parallel toggle button', function(){
|
||||
|
||||
it('should toggle parallel marker off',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('ParallelTask');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// when
|
||||
popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var parallelEntry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// then
|
||||
expect(task.businessObject.loopCharacteristics).not.to.exist;
|
||||
expect(domClasses(parallelEntry).has('active')).to.be.false;
|
||||
}));
|
||||
|
||||
|
||||
it('should toggle parallel marker on', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('Task');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// when
|
||||
popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var parallelEntry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// then
|
||||
expect(domClasses(parallelEntry).has('active')).to.be.true;
|
||||
expect(task.businessObject.loopCharacteristics.isSequential).to.be.false;
|
||||
expect(is(task.businessObject.loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).to.be.true;
|
||||
}));
|
||||
|
||||
|
||||
it('should set sequential button inactive', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('SequentialTask');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// when
|
||||
popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var sequentialEntry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// then
|
||||
expect(domClasses(sequentialEntry).has('active')).to.be.false;
|
||||
}));
|
||||
|
||||
|
||||
it('should set loop button inactive', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('LoopTask');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// when
|
||||
popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var loopEntry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// then
|
||||
expect(domClasses(loopEntry).has('active')).to.be.false;
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('sequential toggle button', function(){
|
||||
|
||||
it('should toggle sequential marker off', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('SequentialTask');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// when
|
||||
popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var sequentialEntry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// then
|
||||
expect(task.businessObject.loopCharacteristics).not.to.exist;
|
||||
expect(domClasses(sequentialEntry).has('active')).to.be.false;
|
||||
}));
|
||||
|
||||
|
||||
it('should toggle sequential marker on', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('Task');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// when
|
||||
popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var sequentialEntry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// then
|
||||
expect(domClasses(sequentialEntry).has('active')).to.be.true;
|
||||
expect(task.businessObject.loopCharacteristics.isSequential).to.be.true;
|
||||
expect(is(task.businessObject.loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).to.be.true;
|
||||
}));
|
||||
|
||||
|
||||
it('should set loop button inactive', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('LoopTask');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// when
|
||||
popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var loopEntry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// then
|
||||
expect(domClasses(loopEntry).has('active')).to.be.false;
|
||||
}));
|
||||
|
||||
|
||||
it('should set parallel button inactive', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('ParallelTask');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// when
|
||||
popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var parallelEntry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// then
|
||||
expect(domClasses(parallelEntry).has('active')).to.be.false;
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('loop toggle button', function(){
|
||||
|
||||
it('should toggle loop marker off', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('LoopTask');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// when
|
||||
popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var loopEntry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// then
|
||||
expect(domClasses(loopEntry).has('active')).to.be.false;
|
||||
expect(is(task.businessObject.loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).not.to.exist;
|
||||
}));
|
||||
|
||||
|
||||
it('should toggle loop marker on', inject(function(popupMenu, bpmnReplace, elementRegistry){
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('Task');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// when
|
||||
popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var loopEntry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// then
|
||||
expect(domClasses(loopEntry).has('active')).to.be.true;
|
||||
expect(is(task.businessObject.loopCharacteristics, 'bpmn:StandardLoopCharacteristics')).to.be.true;
|
||||
}));
|
||||
|
||||
|
||||
it('should set sequential button inactive', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('SequentialTask');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// when
|
||||
popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var sequentialEntry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// then
|
||||
expect(domClasses(sequentialEntry).has('active')).to.be.false;
|
||||
}));
|
||||
|
||||
|
||||
it('should set parallel button inactive', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('ParallelTask');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// when
|
||||
popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var parallelEntry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// then
|
||||
expect(domClasses(parallelEntry).has('active')).to.be.false;
|
||||
}));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('replacing', function() {
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXMLMarkers, { modules: testModules }));
|
||||
|
||||
it('should retain the loop characteristics', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('SequentialTask');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'replace-with-send-task');
|
||||
|
||||
// when
|
||||
// replacing the task with a send task
|
||||
var sendTask = popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
// then
|
||||
expect(sendTask.businessObject.loopCharacteristics).to.exist;
|
||||
expect(sendTask.businessObject.loopCharacteristics.isSequential).to.be.true;
|
||||
expect(is(sendTask.businessObject.loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).to.be.true;
|
||||
}));
|
||||
|
||||
|
||||
it('should retain the loop characteristics for call activites',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('SequentialTask');
|
||||
|
||||
openPopup(task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'replace-with-call-activity');
|
||||
|
||||
// when
|
||||
// replacing the task with a call activity
|
||||
var callActivity = popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
// then
|
||||
expect(callActivity.businessObject.loopCharacteristics).to.exist;
|
||||
expect(callActivity.businessObject.loopCharacteristics.isSequential).to.be.true;
|
||||
expect(is(callActivity.businessObject.loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).to.be.true;
|
||||
}));
|
||||
|
||||
|
||||
it('should retain expanded status for sub processes',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var subProcess = elementRegistry.get('SubProcess');
|
||||
|
||||
openPopup(subProcess);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'replace-with-transaction');
|
||||
|
||||
// when
|
||||
// replacing the expanded sub process with a transaction
|
||||
var transaction = popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
// then
|
||||
expect(isExpanded(transaction)).to.equal(isExpanded(subProcess));
|
||||
}));
|
||||
|
||||
|
||||
it('should retain the loop characteristics and the expanded status for transactions',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var transaction = elementRegistry.get('Transaction');
|
||||
|
||||
openPopup(transaction);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'replace-with-subprocess');
|
||||
|
||||
// when
|
||||
// replacing the transaction with an expanded sub process
|
||||
var subProcess = popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
// then
|
||||
expect(isExpanded(subProcess)).to.equal(isExpanded(transaction));
|
||||
}));
|
||||
|
||||
|
||||
it('should not retain the loop characteristics morphing to an event sub process',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry, modeling) {
|
||||
|
||||
// given
|
||||
var transaction = elementRegistry.get('Transaction');
|
||||
|
||||
modeling.updateProperties(transaction, { loopCharacteristics: { isparallel: true } });
|
||||
|
||||
openPopup(transaction);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'replace-with-event-subprocess');
|
||||
|
||||
// when
|
||||
// replacing the transaction with an event sub process
|
||||
var subProcess = popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
// then
|
||||
expect(isExpanded(subProcess)).to.equal(isExpanded(transaction));
|
||||
}));
|
||||
|
||||
|
||||
it('should retain the expanded property morphing to an event sub processes',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var transaction = elementRegistry.get('Transaction');
|
||||
|
||||
openPopup(transaction);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'replace-with-event-subprocess');
|
||||
|
||||
// when
|
||||
// replacing the transaction with an expanded sub process
|
||||
var eventSubProcess = popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
|
||||
|
||||
// then
|
||||
expect(isExpanded(eventSubProcess)).to.equal(isExpanded(transaction));
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('replace menu', function() {
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXMLReplace, { modules: testModules }));
|
||||
|
||||
it('should contain all start events except the current one',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var startEvent = elementRegistry.get('StartEvent_1');
|
||||
|
||||
// when
|
||||
openPopup(startEvent);
|
||||
|
||||
var entriesContainer = queryPopup(popupMenu, '.djs-popup-body');
|
||||
|
||||
// then
|
||||
expect(queryEntry(popupMenu, 'replace-with-none-start')).to.be.null;
|
||||
expect(entriesContainer.childNodes.length).to.equal(6);
|
||||
}));
|
||||
|
||||
|
||||
it('should contain all intermediate events except the current one',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var intermediateEvent = elementRegistry.get('IntermediateThrowEvent_1');
|
||||
|
||||
// when
|
||||
openPopup(intermediateEvent);
|
||||
|
||||
var entriesContainer = queryPopup(popupMenu, '.djs-popup-body');
|
||||
|
||||
// then
|
||||
expect(queryEntry(popupMenu, 'replace-with-none-intermediate-throw')).to.be.null;
|
||||
expect(entriesContainer.childNodes.length).to.equal(12);
|
||||
}));
|
||||
|
||||
|
||||
it('should contain all end events except the current one',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var endEvent = elementRegistry.get('EndEvent_1');
|
||||
|
||||
// when
|
||||
openPopup(endEvent);
|
||||
|
||||
var entriesContainer = queryPopup(popupMenu, '.djs-popup-body');
|
||||
|
||||
// then
|
||||
expect(queryEntry(popupMenu, 'replace-with-none-end')).to.be.null;
|
||||
expect(entriesContainer.childNodes.length).to.equal(8);
|
||||
}));
|
||||
|
||||
|
||||
it('should contain all start events inside event sub process except the current one',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var startEvent = elementRegistry.get('StartEvent_3');
|
||||
|
||||
// when
|
||||
openPopup(startEvent);
|
||||
|
||||
var entriesContainer = queryPopup(popupMenu, '.djs-popup-body');
|
||||
|
||||
// then
|
||||
expect(queryEntry(popupMenu, 'replace-with-non-interrupting-message-start')).to.be.null;
|
||||
expect(queryEntry(popupMenu, 'replace-with-message-start')).to.exist;
|
||||
expect(entriesContainer.childNodes.length).to.equal(11);
|
||||
}));
|
||||
|
||||
|
||||
it('should contain all non interrupting start events inside event sub process except the current one',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var startEvent = elementRegistry.get('StartEvent_3');
|
||||
|
||||
var newElement = bpmnReplace.replaceElement(startEvent, {
|
||||
type: 'bpmn:StartEvent',
|
||||
eventDefinition: 'bpmn:ConditionalEventDefinition',
|
||||
isInterrupting: false
|
||||
});
|
||||
|
||||
// when
|
||||
openPopup(newElement);
|
||||
|
||||
var entriesContainer = queryPopup(popupMenu, '.djs-popup-body');
|
||||
|
||||
// then
|
||||
expect(queryEntry(popupMenu, 'replace-with-conditional-start')).to.exist;
|
||||
expect(queryEntry(popupMenu, 'replace-with-non-interrupting-conditional-start')).to.be.null;
|
||||
expect(entriesContainer.childNodes.length).to.equal(11);
|
||||
}));
|
||||
|
||||
|
||||
it('should contain all boundary events for an interrupting boundary event',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var boundaryEvent = elementRegistry.get('BoundaryEvent_1');
|
||||
|
||||
// when
|
||||
openPopup(boundaryEvent, 40);
|
||||
|
||||
var entriesContainer = queryPopup(popupMenu, '.djs-popup-body');
|
||||
|
||||
// then
|
||||
expect(queryEntry(popupMenu, 'replace-with-conditional-intermediate-catch')).to.be.null;
|
||||
expect(entriesContainer.childNodes.length).to.equal(10);
|
||||
}));
|
||||
|
||||
|
||||
it('should contain all boundary events for a non interrupting boundary event',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var boundaryEvent = elementRegistry.get('BoundaryEvent_2');
|
||||
|
||||
// when
|
||||
openPopup(boundaryEvent, 40);
|
||||
|
||||
var entriesContainer = queryPopup(popupMenu, '.djs-popup-body');
|
||||
|
||||
// then
|
||||
expect(queryEntry(popupMenu, 'replace-with-non-interrupting-message-intermediate-catch')).to.be.null;
|
||||
expect(entriesContainer.childNodes.length).to.equal(10);
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
File diff suppressed because it is too large
Load Diff
|
@ -881,520 +881,6 @@ describe('features/replace', function() {
|
|||
});
|
||||
|
||||
|
||||
describe('Cancel Events', function () {
|
||||
|
||||
var diagramXML = require('../../../fixtures/bpmn/features/replace/cancel-events.bpmn');
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
|
||||
|
||||
describe('- normal -', function() {
|
||||
|
||||
it('should show Cancel Event replace option',
|
||||
inject(function(elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var endEvent = elementRegistry.get('EndEvent_1');
|
||||
|
||||
// when
|
||||
var opts = bpmnReplace.getReplaceOptions(endEvent);
|
||||
|
||||
// then
|
||||
expect(opts).to.have.length(9);
|
||||
}));
|
||||
|
||||
it('should NOT show Cancel Event replace option',
|
||||
inject(function(elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var endEvent = elementRegistry.get('EndEvent_2');
|
||||
|
||||
// when
|
||||
var opts = bpmnReplace.getReplaceOptions(endEvent);
|
||||
|
||||
// then
|
||||
expect(opts).to.have.length(8);
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('- boundary events -', function() {
|
||||
|
||||
it('should NOT show Cancel Event replace option',
|
||||
inject(function(elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var boundaryEvent = elementRegistry.get('BoundaryEvent_1');
|
||||
|
||||
// when
|
||||
var opts = bpmnReplace.getReplaceOptions(boundaryEvent);
|
||||
|
||||
// then
|
||||
expect(opts).to.have.length(12);
|
||||
}));
|
||||
|
||||
it('should NOT show Cancel Event replace option',
|
||||
inject(function(elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var boundaryEvent = elementRegistry.get('BoundaryEvent_2');
|
||||
|
||||
// when
|
||||
var opts = bpmnReplace.getReplaceOptions(boundaryEvent);
|
||||
|
||||
// then
|
||||
expect(opts).to.have.length(11);
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('default flows from inclusive gateways', function () {
|
||||
|
||||
var diagramXML = require('./BpmnReplace.defaultFlowsFromInclusiveGateways.bpmn');
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
|
||||
|
||||
it ('should show Default replace option', inject(function (elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_2');
|
||||
|
||||
// when
|
||||
var opts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// then
|
||||
expect(opts).to.have.length(1);
|
||||
}));
|
||||
|
||||
it ('should NOT show Default replace option', inject(function (elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_1');
|
||||
|
||||
// when
|
||||
var opts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// then
|
||||
expect(opts).to.have.length(1);
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('default flows', function() {
|
||||
|
||||
var diagramXML = require('./BpmnReplace.defaultFlows.bpmn');
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
|
||||
|
||||
|
||||
it('should show Default replace option', inject(function(elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_3');
|
||||
|
||||
// when
|
||||
var opts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// then
|
||||
expect(opts).to.have.length(1);
|
||||
}));
|
||||
|
||||
|
||||
it('should NOT show Default replace option', inject(function(elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_4');
|
||||
|
||||
// when
|
||||
var opts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// then
|
||||
expect(opts).to.have.length(0);
|
||||
}));
|
||||
|
||||
|
||||
it('should replace SequenceFlow with DefaultFlow', inject(function(elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_3');
|
||||
|
||||
// when
|
||||
var opts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// trigger DefaultFlow replacement
|
||||
opts[0].action();
|
||||
|
||||
var gateway = elementRegistry.get('ExclusiveGateway_1');
|
||||
|
||||
// then
|
||||
expect(gateway.businessObject.default).to.equal(sequenceFlow.businessObject);
|
||||
}));
|
||||
|
||||
|
||||
it('should replace SequenceFlow with DefaultFlow -> undo',
|
||||
inject(function(elementRegistry, bpmnReplace, commandStack) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_3');
|
||||
|
||||
// when
|
||||
var opts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// trigger DefaultFlow replacement
|
||||
opts[0].action();
|
||||
|
||||
commandStack.undo();
|
||||
|
||||
var gateway = elementRegistry.get('ExclusiveGateway_1');
|
||||
|
||||
// then
|
||||
expect(gateway.businessObject.default).to.not.exist;
|
||||
}));
|
||||
|
||||
|
||||
it('should only have one DefaultFlow', inject(function(elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_1'),
|
||||
sequenceFlow2 = elementRegistry.get('SequenceFlow_3');
|
||||
|
||||
// when
|
||||
var sequenceFlowOpts = bpmnReplace.getReplaceOptions(sequenceFlow),
|
||||
sequenceFlowOpts2 = bpmnReplace.getReplaceOptions(sequenceFlow2);
|
||||
|
||||
// trigger DefaultFlow replacement
|
||||
sequenceFlowOpts2[0].action();
|
||||
sequenceFlowOpts[0].action();
|
||||
|
||||
var gateway = elementRegistry.get('ExclusiveGateway_1');
|
||||
|
||||
// then
|
||||
expect(gateway.businessObject.default).to.equal(sequenceFlow.businessObject);
|
||||
}));
|
||||
|
||||
|
||||
it('should replace DefaultFlow with SequenceFlow when changing source',
|
||||
inject(function(elementRegistry, bpmnReplace, modeling) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_1'),
|
||||
task = elementRegistry.get('Task_2');
|
||||
|
||||
var sequenceFlowOpts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// trigger DefaultFlow replacement
|
||||
sequenceFlowOpts[0].action();
|
||||
|
||||
// when
|
||||
modeling.reconnectStart(sequenceFlow, task, [
|
||||
{ x: 686, y: 267, original: { x: 686, y: 307 } },
|
||||
{ x: 686, y: 207, original: { x: 686, y: 187 } }
|
||||
]);
|
||||
|
||||
var gateway = elementRegistry.get('ExclusiveGateway_1');
|
||||
|
||||
// then
|
||||
expect(gateway.businessObject.default).to.not.exist;
|
||||
}));
|
||||
|
||||
|
||||
it('should replace DefaultFlow with SequenceFlow when changing source -> undo',
|
||||
inject(function(elementRegistry, bpmnReplace, modeling, commandStack) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_1'),
|
||||
task = elementRegistry.get('Task_2');
|
||||
|
||||
var sequenceFlowOpts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// trigger DefaultFlow replacement
|
||||
sequenceFlowOpts[0].action();
|
||||
|
||||
// when
|
||||
modeling.reconnectStart(sequenceFlow, task, [
|
||||
{ x: 686, y: 267, original: { x: 686, y: 307 } },
|
||||
{ x: 686, y: 207, original: { x: 686, y: 187 } }
|
||||
]);
|
||||
|
||||
commandStack.undo();
|
||||
|
||||
var gateway = elementRegistry.get('ExclusiveGateway_1');
|
||||
|
||||
// then
|
||||
expect(gateway.businessObject.default).equal(sequenceFlow.businessObject);
|
||||
}));
|
||||
|
||||
|
||||
it('should replace DefaultFlow with SequenceFlow when changing target',
|
||||
inject(function(elementRegistry, elementFactory, canvas, bpmnReplace, modeling) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_1'),
|
||||
root = canvas.getRootElement();
|
||||
|
||||
var intermediateEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent'});
|
||||
|
||||
modeling.createShape(intermediateEvent, { x: 686, y: 50 }, root);
|
||||
|
||||
var sequenceFlowOpts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// trigger DefaultFlow replacement
|
||||
sequenceFlowOpts[0].action();
|
||||
|
||||
// when
|
||||
modeling.reconnectEnd(sequenceFlow, intermediateEvent, [
|
||||
{ x: 686, y: 267, original: { x: 686, y: 307 } },
|
||||
{ x: 686, y: 50, original: { x: 686, y: 75 } }
|
||||
]);
|
||||
|
||||
var gateway = elementRegistry.get('ExclusiveGateway_1');
|
||||
|
||||
// then
|
||||
expect(gateway.businessObject.default).to.not.exist;
|
||||
}));
|
||||
|
||||
|
||||
it('should replace DefaultFlow with SequenceFlow when changing target -> undo',
|
||||
inject(function(elementRegistry, elementFactory, canvas, bpmnReplace, modeling, commandStack) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_1'),
|
||||
root = canvas.getRootElement();
|
||||
|
||||
var intermediateEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent'});
|
||||
|
||||
modeling.createShape(intermediateEvent, { x: 686, y: 50 }, root);
|
||||
|
||||
var sequenceFlowOpts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// trigger DefaultFlow replacement
|
||||
sequenceFlowOpts[0].action();
|
||||
|
||||
// when
|
||||
modeling.reconnectEnd(sequenceFlow, intermediateEvent, [
|
||||
{ x: 686, y: 267, original: { x: 686, y: 307 } },
|
||||
{ x: 686, y: 50, original: { x: 686, y: 75 } }
|
||||
]);
|
||||
|
||||
commandStack.undo();
|
||||
|
||||
var gateway = elementRegistry.get('ExclusiveGateway_1');
|
||||
|
||||
// then
|
||||
expect(gateway.businessObject.default).equal(sequenceFlow.businessObject);
|
||||
}));
|
||||
|
||||
|
||||
it('should keep DefaultFlow when morphing Gateway', inject(function(elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_3'),
|
||||
exclusiveGateway = elementRegistry.get('ExclusiveGateway_1');
|
||||
|
||||
// when
|
||||
var opts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// trigger DefaultFlow replacement
|
||||
opts[0].action();
|
||||
|
||||
var inclusiveGateway = bpmnReplace.replaceElement(exclusiveGateway, { type: 'bpmn:InclusiveGateway'});
|
||||
|
||||
// then
|
||||
expect(inclusiveGateway.businessObject.default).to.equal(sequenceFlow.businessObject);
|
||||
}));
|
||||
|
||||
|
||||
it('should keep DefaultFlow when morphing Gateway -> undo',
|
||||
inject(function(elementRegistry, bpmnReplace, commandStack) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_3'),
|
||||
exclusiveGateway = elementRegistry.get('ExclusiveGateway_1');
|
||||
|
||||
// when
|
||||
var opts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// trigger DefaultFlow replacement
|
||||
opts[0].action();
|
||||
|
||||
bpmnReplace.replaceElement(exclusiveGateway, { type: 'bpmn:InclusiveGateway'});
|
||||
|
||||
commandStack.undo();
|
||||
|
||||
// then
|
||||
expect(exclusiveGateway.businessObject.default).to.equal(sequenceFlow.businessObject);
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
describe('conditional flows', function() {
|
||||
|
||||
var diagramXML = require('./BpmnReplace.conditionalFlows.bpmn');
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
|
||||
|
||||
|
||||
it('should show ConditionalFlow replace option', inject(function(elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_3');
|
||||
|
||||
//when
|
||||
var opts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// then
|
||||
expect(opts).to.have.length(1);
|
||||
}));
|
||||
|
||||
|
||||
it('should NOT show ConditionalFlow replace option', inject(function(elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_1');
|
||||
|
||||
//when
|
||||
var opts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// then
|
||||
expect(opts).to.have.length(0);
|
||||
}));
|
||||
|
||||
|
||||
it('should morph into a ConditionalFlow', inject(function(elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_2');
|
||||
|
||||
//when
|
||||
var opts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// replace with ConditionalFlow
|
||||
opts[0].action();
|
||||
|
||||
// then
|
||||
expect(sequenceFlow.businessObject.conditionExpression.$type).to.equal('bpmn:FormalExpression');
|
||||
}));
|
||||
|
||||
|
||||
it('should morph into a ConditionalFlow -> undo', inject(function(elementRegistry, bpmnReplace, commandStack) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_2');
|
||||
|
||||
//when
|
||||
var opts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// replace with ConditionalFlow
|
||||
opts[0].action();
|
||||
|
||||
commandStack.undo();
|
||||
|
||||
// then
|
||||
expect(sequenceFlow.businessObject.conditionExpression).to.not.exist;
|
||||
}));
|
||||
|
||||
|
||||
it('should morph back into a SequenceFlow', inject(function(elementRegistry, bpmnReplace) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_2');
|
||||
|
||||
// when
|
||||
var opts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// replace with ConditionalFlow
|
||||
opts[0].action();
|
||||
|
||||
var conditionalOpts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// replace with SequenceFlow
|
||||
conditionalOpts[0].action();
|
||||
|
||||
// then
|
||||
expect(sequenceFlow.businessObject.conditionExpression).to.not.exist;
|
||||
}));
|
||||
|
||||
|
||||
it('should replace ConditionalFlow with SequenceFlow when changing source',
|
||||
inject(function(elementRegistry, bpmnReplace, modeling) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_3'),
|
||||
startEvent = elementRegistry.get('StartEvent_1');
|
||||
|
||||
var sequenceFlowOpts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// trigger ConditionalFlow replacement
|
||||
sequenceFlowOpts[0].action();
|
||||
|
||||
// when
|
||||
modeling.reconnectStart(sequenceFlow, startEvent, [
|
||||
{ x: 196, y: 197, original: { x: 178, y: 197 } },
|
||||
{ x: 497, y: 278, original: { x: 547, y: 278 } }
|
||||
]);
|
||||
|
||||
// then
|
||||
expect(sequenceFlow.businessObject.conditionExpression).to.not.exist;
|
||||
}));
|
||||
|
||||
|
||||
it('should replace ConditionalFlow with SequenceFlow when changing source -> undo',
|
||||
inject(function(elementRegistry, bpmnReplace, modeling, commandStack) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_3'),
|
||||
startEvent = elementRegistry.get('StartEvent_1');
|
||||
|
||||
var sequenceFlowOpts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// trigger ConditionalFlow replacement
|
||||
sequenceFlowOpts[0].action();
|
||||
|
||||
// when
|
||||
modeling.reconnectStart(sequenceFlow, startEvent, [
|
||||
{ x: 196, y: 197, original: { x: 178, y: 197 } },
|
||||
{ x: 497, y: 278, original: { x: 547, y: 278 } }
|
||||
]);
|
||||
|
||||
commandStack.undo();
|
||||
|
||||
// then
|
||||
expect(sequenceFlow.businessObject.conditionExpression.$type).to.equal('bpmn:FormalExpression');
|
||||
}));
|
||||
|
||||
|
||||
it('should replace ConditionalFlow with SequenceFlow when changing target',
|
||||
inject(function(elementRegistry, elementFactory, canvas, bpmnReplace, modeling) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_3'),
|
||||
root = canvas.getRootElement(),
|
||||
intermediateEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent'});
|
||||
|
||||
modeling.createShape(intermediateEvent, { x: 497, y: 197 }, root);
|
||||
|
||||
var sequenceFlowOpts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// trigger ConditionalFlow replacement
|
||||
sequenceFlowOpts[0].action();
|
||||
|
||||
// when
|
||||
modeling.reconnectEnd(sequenceFlow, intermediateEvent, [
|
||||
{ x: 389, y: 197, original: { x: 389, y: 197 } },
|
||||
{ x: 497, y: 197, original: { x: 497, y: 197 } }
|
||||
]);
|
||||
|
||||
// then
|
||||
expect(sequenceFlow.businessObject.conditionExpression).to.not.exist;
|
||||
}));
|
||||
|
||||
|
||||
it('should replace ConditionalFlow with SequenceFlow when changing target -> undo',
|
||||
inject(function(elementRegistry, elementFactory, canvas, bpmnReplace, modeling, commandStack) {
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow_3'),
|
||||
root = canvas.getRootElement(),
|
||||
intermediateEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent'});
|
||||
|
||||
modeling.createShape(intermediateEvent, { x: 497, y: 197 }, root);
|
||||
|
||||
var sequenceFlowOpts = bpmnReplace.getReplaceOptions(sequenceFlow);
|
||||
|
||||
// trigger ConditionalFlow replacement
|
||||
sequenceFlowOpts[0].action();
|
||||
|
||||
// when
|
||||
modeling.reconnectEnd(sequenceFlow, intermediateEvent, [
|
||||
{ x: 389, y: 197, original: { x: 389, y: 197 } },
|
||||
{ x: 497, y: 197, original: { x: 497, y: 197 } }
|
||||
]);
|
||||
|
||||
commandStack.undo();
|
||||
|
||||
// then
|
||||
expect(sequenceFlow.businessObject.conditionExpression.$type).to.equal('bpmn:FormalExpression');
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('events', function() {
|
||||
|
||||
var diagramXML = require('../../../fixtures/bpmn/basic.bpmn');
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var TestHelper = require('../../../TestHelper');
|
||||
|
||||
/* global bootstrapModeler, inject */
|
||||
|
||||
var modelingModule = require('../../../../lib/features/modeling'),
|
||||
replaceModule = require('../../../../lib/features/replace'),
|
||||
coreModule = require('../../../../lib/core');
|
||||
|
||||
|
||||
|
||||
describe('features/replace - chooser', function() {
|
||||
|
||||
var diagramXML = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn');
|
||||
|
||||
var testModules = [ coreModule, modelingModule, replaceModule ];
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
|
||||
|
||||
|
||||
describe('should show chooser', function() {
|
||||
|
||||
it('for task', inject(function(elementRegistry, modeling, bpmnReplace) {
|
||||
|
||||
// given
|
||||
var element = elementRegistry.get('Task_1');
|
||||
|
||||
// when
|
||||
bpmnReplace.openChooser({ x: 100, y: 100 }, element);
|
||||
|
||||
// then
|
||||
expect(null).not.to.exist;
|
||||
}));
|
||||
|
||||
|
||||
it('for event event', inject(function(elementRegistry, modeling, bpmnReplace) {
|
||||
|
||||
// given
|
||||
var element = elementRegistry.get('StartEvent_1');
|
||||
|
||||
// when
|
||||
bpmnReplace.openChooser({ x: 100, y: 100 }, element);
|
||||
|
||||
// then
|
||||
expect(null).not.to.exist;
|
||||
}));
|
||||
|
||||
|
||||
it('for gateway event', inject(function(elementRegistry, modeling, bpmnReplace) {
|
||||
|
||||
// given
|
||||
var element = elementRegistry.get('ExclusiveGateway_1');
|
||||
|
||||
// when
|
||||
bpmnReplace.openChooser({ x: 100, y: 100 }, element);
|
||||
|
||||
// then
|
||||
expect(null).not.to.exist;
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue