diff --git a/lib/features/context-pad/ContextPadProvider.js b/lib/features/context-pad/ContextPadProvider.js index fdf7ae84..54e51249 100644 --- a/lib/features/context-pad/ContextPadProvider.js +++ b/lib/features/context-pad/ContextPadProvider.js @@ -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)); } } } diff --git a/lib/features/context-pad/index.js b/lib/features/context-pad/index.js index 6fb58399..c7b26b32 100644 --- a/lib/features/context-pad/index.js +++ b/lib/features/context-pad/index.js @@ -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') ] diff --git a/lib/features/popup-menu/ReplaceMenuProvider.js b/lib/features/popup-menu/ReplaceMenuProvider.js new file mode 100644 index 00000000..5a6cfdb4 --- /dev/null +++ b/lib/features/popup-menu/ReplaceMenuProvider.js @@ -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} 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} 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} 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} 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} 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; \ No newline at end of file diff --git a/lib/features/popup-menu/index.js b/lib/features/popup-menu/index.js new file mode 100644 index 00000000..db8cc96e --- /dev/null +++ b/lib/features/popup-menu/index.js @@ -0,0 +1,4 @@ +module.exports = { + __init__: [ 'replaceMenuProvider' ], + replaceMenuProvider: [ 'type', require('./ReplaceMenuProvider') ] +}; \ No newline at end of file diff --git a/lib/features/popup-menu/util/TypeUtil.js b/lib/features/popup-menu/util/TypeUtil.js new file mode 100644 index 00000000..6f2d7b5a --- /dev/null +++ b/lib/features/popup-menu/util/TypeUtil.js @@ -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; \ No newline at end of file diff --git a/lib/features/replace/BpmnReplace.js b/lib/features/replace/BpmnReplace.js index 51eef1b1..b03086bc 100644 --- a/lib/features/replace/BpmnReplace.js +++ b/lib/features/replace/BpmnReplace.js @@ -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; diff --git a/lib/features/replace/ReplaceOptions.js b/lib/features/replace/ReplaceOptions.js index eebba97f..f7327806 100644 --- a/lib/features/replace/ReplaceOptions.js +++ b/lib/features/replace/ReplaceOptions.js @@ -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' } ]; diff --git a/test/spec/features/context-pad/ContextPadProviderSpec.js b/test/spec/features/context-pad/ContextPadProviderSpec.js index 92f42aed..9313359c 100644 --- a/test/spec/features/context-pad/ContextPadProviderSpec.js +++ b/test/spec/features/context-pad/ContextPadProviderSpec.js @@ -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); diff --git a/test/spec/features/replace/BpmnReplace.conditionalFlows.bpmn b/test/spec/features/popup-menu/BpmnReplace.conditionalFlows.bpmn similarity index 100% rename from test/spec/features/replace/BpmnReplace.conditionalFlows.bpmn rename to test/spec/features/popup-menu/BpmnReplace.conditionalFlows.bpmn diff --git a/test/spec/features/replace/BpmnReplace.defaultFlows.bpmn b/test/spec/features/popup-menu/BpmnReplace.defaultFlows.bpmn similarity index 100% rename from test/spec/features/replace/BpmnReplace.defaultFlows.bpmn rename to test/spec/features/popup-menu/BpmnReplace.defaultFlows.bpmn diff --git a/test/spec/features/replace/BpmnReplace.defaultFlowsFromInclusiveGateways.bpmn b/test/spec/features/popup-menu/BpmnReplace.defaultFlowsFromInclusiveGateways.bpmn similarity index 100% rename from test/spec/features/replace/BpmnReplace.defaultFlowsFromInclusiveGateways.bpmn rename to test/spec/features/popup-menu/BpmnReplace.defaultFlowsFromInclusiveGateways.bpmn diff --git a/test/spec/features/popup-menu/PopupMenuSpec.js b/test/spec/features/popup-menu/PopupMenuSpec.js deleted file mode 100644 index c3135ba3..00000000 --- a/test/spec/features/popup-menu/PopupMenuSpec.js +++ /dev/null @@ -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); - })); - - }); - -}); diff --git a/test/spec/features/popup-menu/ReplaceMenuProviderSpec.js b/test/spec/features/popup-menu/ReplaceMenuProviderSpec.js new file mode 100644 index 00000000..31764093 --- /dev/null +++ b/test/spec/features/popup-menu/ReplaceMenuProviderSpec.js @@ -0,0 +1,1340 @@ +'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'), + replaceMenuProviderModule = require('../../../../lib/features/popup-menu'); + +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); +} + +/** + * Gets all menu entries from the current open popup menu + * + * @param {PopupMenu} popupMenu + * + * @return {} [description] + */ +function getEntries(popupMenu) { + var element = popupMenu._current.element; + + return popupMenu._current.provider.getEntries(element); +} + + +describe('features/replace-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, replaceMenuProviderModule ]; + + var openPopup = function(element, offset) { + offset = offset || 100; + + TestHelper.getBpmnJS().invoke(function(popupMenu){ + + popupMenu.create('bpmn-replace', element); + + popupMenu.open({ x: element.x + offset, y: element.y + offset }); + + }); + }; + + + 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() { + + + describe('events', function() { + + beforeEach(bootstrapModeler(diagramXMLReplace, { modules: testModules })); + + it('should contain all 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 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 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); + })); + + }); + + + describe('cancel events', function() { + + var diagramXML = require('../../../fixtures/bpmn/features/replace/cancel-events.bpmn'); + + beforeEach(bootstrapModeler(diagramXML, { modules: testModules })); + + it('should contain cancel event replace option', + + inject(function(elementRegistry, bpmnReplace, popupMenu, replaceMenuProvider) { + // given + var endEvent = elementRegistry.get('EndEvent_1'); + + // when + openPopup(endEvent); + + var entries = getEntries(popupMenu); + + // then + expect(entries).to.have.length(9); + })); + + + it('should NOT contain cancel event replace option', + + inject(function(elementRegistry, bpmnReplace, popupMenu, replaceMenuProvider) { + // given + var endEvent = elementRegistry.get('EndEvent_2'); + + + + // when + openPopup(endEvent); + + var entries = getEntries(popupMenu); + + // then + expect(entries).to.have.length(8); + })); + + + it('should contain cancel event replace option (boundary events)', + inject(function(elementRegistry, bpmnReplace, popupMenu) { + + // given + var boundaryEvent = elementRegistry.get('BoundaryEvent_1'); + + openPopup(boundaryEvent); + + // when + var entries = getEntries(popupMenu); + + // then + expect(entries).to.have.length(12); + + })); + + + it('should NOT contain cancel event replace option (boundary events)', + inject(function(elementRegistry, bpmnReplace, popupMenu) { + + // given + var boundaryEvent = elementRegistry.get('BoundaryEvent_2'); + + // when + openPopup(boundaryEvent, 40); + + var entries = getEntries(popupMenu); + + // then + expect(entries).to.have.length(11); + + })); + + }); + + + describe('boundary events', function() { + + beforeEach(bootstrapModeler(diagramXMLReplace, { modules: testModules })); + + 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); + })); + + }); + + + describe('default flows', function() { + + var diagramXML = require('./BpmnReplace.defaultFlows.bpmn'); + + beforeEach(bootstrapModeler(diagramXML, { modules: testModules })); + + it('should show default replace option', inject(function(elementRegistry, popupMenu) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_3'); + + // when + openPopup(sequenceFlow); + + var entriesContainer = queryPopup(popupMenu, '.djs-popup-body'); + + // then + expect(entriesContainer.childNodes.length).to.equal(1); + })); + + + it('should NOT show default replace option', inject(function(elementRegistry, popupMenu) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_4'); + + // when + openPopup(sequenceFlow); + + var entriesContainer = queryPopup(popupMenu, '.djs-popup-body'); + + // then + expect(entriesContainer.childNodes.length).to.equal(0); + })); + + }); + + + 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, popupMenu) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_2'); + + // when + openPopup(sequenceFlow); + + var sequenceFlowEntry = queryEntry(popupMenu, 'replace-with-sequence-flow'), + defaultFlowEntry = queryEntry(popupMenu, 'replace-with-default-flow'); + + // then + expect(sequenceFlowEntry).to.not.exist; + expect(defaultFlowEntry).to.exist; + })); + + + it('should NOT show default replace option', inject(function(elementRegistry, popupMenu) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_1'); + + // when + openPopup(sequenceFlow); + + var sequenceFlowEntry = queryEntry(popupMenu, 'replace-with-sequence-flow'), + defaultFlowEntry = queryEntry(popupMenu, 'replace-with-default-flow'); + + // then + expect(sequenceFlowEntry).to.exist; + expect(defaultFlowEntry).to.not.exist; + })); + + }); + + + describe('conditional flows', function() { + + var diagramXML = require('./BpmnReplace.conditionalFlows.bpmn'); + + beforeEach(bootstrapModeler(diagramXML, { modules: testModules })); + + it('should show ConditionalFlow replace option', inject(function(elementRegistry, popupMenu) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_3'); + + // when + openPopup(sequenceFlow); + + var entriesContainer = queryPopup(popupMenu, '.djs-popup-body'), + conditionalFlowEntry = queryEntry(popupMenu, 'replace-with-conditional-flow'); + + // then + expect(conditionalFlowEntry).to.exist; + expect(entriesContainer.childNodes.length).to.equal(1); + })); + + + it('should NOT show ConditionalFlow replace option', inject(function(elementRegistry, popupMenu) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_1'); + + //when + openPopup(sequenceFlow); + + var entriesContainer = queryPopup(popupMenu, '.djs-popup-body'); + + // then + expect(entriesContainer.childNodes.length).to.equal(0); + })); + + }); + + }); + + + describe('integration', function() { + + + describe('default flows', function() { + + var diagramXML = require('./BpmnReplace.defaultFlows.bpmn'); + + beforeEach(bootstrapModeler(diagramXML, { modules: testModules })); + + + it('should replace SequenceFlow with DefaultFlow', inject(function(elementRegistry, popupMenu) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_3'); + + //when + openPopup(sequenceFlow); + + var entries = getEntries(popupMenu); + + // trigger DefaultFlow replacement + entries[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, popupMenu, commandStack) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_3'); + + // when + openPopup(sequenceFlow); + + var entries = getEntries(popupMenu); + + // trigger DefaultFlow replacement + entries[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, popupMenu) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_1'), + sequenceFlow3 = elementRegistry.get('SequenceFlow_3'); + + var entries; + + // when + // trigger morphing sequenceFlow3 to default flow + openPopup(sequenceFlow3); + + entries = getEntries(popupMenu); + + entries[0].action(); + + // trigger morphing sequenceFlow to default flow + openPopup(sequenceFlow); + + entries = getEntries(popupMenu); + + entries[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, popupMenu, modeling) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_1'), + task = elementRegistry.get('Task_2'); + + openPopup(sequenceFlow); + + var sequenceFlowEntries = getEntries(popupMenu); + + // trigger DefaultFlow replacement + sequenceFlowEntries[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, popupMenu, modeling, commandStack) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_1'), + task = elementRegistry.get('Task_2'); + + openPopup(sequenceFlow); + + var sequenceFlowEntries = getEntries(popupMenu); + + // trigger DefaultFlow replacement + sequenceFlowEntries[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, popupMenu, 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); + + openPopup(sequenceFlow); + + var sequenceFlowEntries = getEntries(popupMenu); + + // trigger DefaultFlow replacement + sequenceFlowEntries[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, popupMenu, 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); + + openPopup(sequenceFlow); + + var sequenceFlowEntries = getEntries(popupMenu); + + // trigger DefaultFlow replacement + sequenceFlowEntries[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, popupMenu, bpmnReplace) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_3'), + exclusiveGateway = elementRegistry.get('ExclusiveGateway_1'); + + // when + openPopup(sequenceFlow); + + var entries = getEntries(popupMenu); + + // trigger DefaultFlow replacement + entries[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, popupMenu, commandStack) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_3'), + exclusiveGateway = elementRegistry.get('ExclusiveGateway_1'); + + // when + openPopup(sequenceFlow); + + var entries = getEntries(popupMenu); + + // trigger DefaultFlow replacement + entries[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 morph into a ConditionalFlow', inject(function(elementRegistry, popupMenu) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_2'); + + // when + openPopup(sequenceFlow); + + var entries = getEntries(popupMenu); + + // trigger ConditionalFlow replacement + entries[0].action(); + + // then + expect(sequenceFlow.businessObject.conditionExpression.$type).to.equal('bpmn:FormalExpression'); + })); + + + it('should morph into a ConditionalFlow -> undo', inject(function(elementRegistry, popupMenu, commandStack) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_2'); + + // when + openPopup(sequenceFlow); + + var entries = getEntries(popupMenu); + + // trigger ConditionalFlow replacement + entries[0].action(); + + commandStack.undo(); + + // then + expect(sequenceFlow.businessObject.conditionExpression).to.not.exist; + })); + + + it('should morph back into a SequenceFlow', inject(function(elementRegistry, popupMenu) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_2'); + + // when + openPopup(sequenceFlow); + + var entries = getEntries(popupMenu); + + // trigger ConditionalFlow replacement + entries[0].action(); + + var conditionalEntries = getEntries(popupMenu, sequenceFlow); + + // replace with SequenceFlow + conditionalEntries[0].action(); + + // then + expect(sequenceFlow.businessObject.conditionExpression).to.not.exist; + })); + + + it('should replace ConditionalFlow with SequenceFlow when changing source', + inject(function(elementRegistry, popupMenu, modeling) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_3'), + startEvent = elementRegistry.get('StartEvent_1'); + + // when + openPopup(sequenceFlow); + + var entries = getEntries(popupMenu); + + // trigger ConditionalFlow replacement + entries[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, popupMenu, modeling, commandStack) { + // given + var sequenceFlow = elementRegistry.get('SequenceFlow_3'), + startEvent = elementRegistry.get('StartEvent_1'); + + // when + openPopup(sequenceFlow); + + var entries = getEntries(popupMenu); + + // trigger ConditionalFlow replacement + entries[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, popupMenu, 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); + + openPopup(sequenceFlow); + + var entries = getEntries(popupMenu); + + // trigger ConditionalFlow replacement + entries[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, popupMenu, 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); + + openPopup(sequenceFlow); + + var entries = getEntries(popupMenu); + + // trigger ConditionalFlow replacement + entries[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'); + })); + + }); + + }); + +}); diff --git a/test/spec/features/replace/BpmnReplaceSpec.js b/test/spec/features/replace/BpmnReplaceSpec.js index d35b7e41..228c75b1 100644 --- a/test/spec/features/replace/BpmnReplaceSpec.js +++ b/test/spec/features/replace/BpmnReplaceSpec.js @@ -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'); diff --git a/test/spec/features/replace/ReplaceOptionsChooserSpec.js b/test/spec/features/replace/ReplaceOptionsChooserSpec.js deleted file mode 100644 index 4fc1a985..00000000 --- a/test/spec/features/replace/ReplaceOptionsChooserSpec.js +++ /dev/null @@ -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; - })); - - }); - -});