feat(popup-menu): add toggle buttons for loop and MI markers
Closes #275
This commit is contained in:
parent
6da0d166e3
commit
af5354e337
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
var forEach = require('lodash/collection/forEach'),
|
||||
filter = require('lodash/collection/filter');
|
||||
var forEach = require('lodash/collection/forEach'),
|
||||
filter = require('lodash/collection/filter');
|
||||
|
||||
var REPLACE_OPTIONS = require ('./ReplaceOptions');
|
||||
|
||||
|
@ -11,6 +11,9 @@ var startEventReplace = REPLACE_OPTIONS.START_EVENT,
|
|||
gatewayReplace = REPLACE_OPTIONS.GATEWAY,
|
||||
taskReplace = REPLACE_OPTIONS.TASK;
|
||||
|
||||
var is = require('../../util/ModelUtil').is,
|
||||
getBusinessObject = require('../../util/ModelUtil').getBusinessObject;
|
||||
|
||||
|
||||
/**
|
||||
* A replace menu provider that gives users the controls to choose
|
||||
|
@ -21,7 +24,7 @@ var startEventReplace = REPLACE_OPTIONS.START_EVENT,
|
|||
* @param {PopupMenu} popupMenu
|
||||
* @param {Replace} replace
|
||||
*/
|
||||
function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection) {
|
||||
function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection, modeling) {
|
||||
|
||||
/**
|
||||
* Prepares a new business object for the replacement element
|
||||
|
@ -70,7 +73,6 @@ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection) {
|
|||
|
||||
// TODO: copy other elligable properties from old business object
|
||||
businessObject.name = oldBusinessObject.name;
|
||||
|
||||
businessObject.loopCharacteristics = oldBusinessObject.loopCharacteristics;
|
||||
|
||||
newElement = replace.replaceElement(element, newElement);
|
||||
|
@ -80,6 +82,92 @@ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection) {
|
|||
return newElement;
|
||||
}
|
||||
|
||||
var toggleEntries,
|
||||
toggledElement;
|
||||
|
||||
|
||||
function toggleMi(event, entry) {
|
||||
var loopCharacteristics;
|
||||
|
||||
if (entry.active) {
|
||||
popupMenu.update(entry, { active: false });
|
||||
modeling.updateProperties(toggledElement, { loopCharacteristics: undefined });
|
||||
return;
|
||||
}
|
||||
|
||||
forEach(toggleEntries, function(action) {
|
||||
var options = action.options;
|
||||
|
||||
if (entry.id === action.id) {
|
||||
popupMenu.update(action.id, { active: true });
|
||||
|
||||
loopCharacteristics = moddle.create(options.loopCharacteristics);
|
||||
|
||||
if (options.isSequential) {
|
||||
loopCharacteristics.isSequential = options.isSequential;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
popupMenu.update(action.id, { active: false });
|
||||
});
|
||||
|
||||
modeling.updateProperties(toggledElement, { loopCharacteristics: loopCharacteristics });
|
||||
}
|
||||
|
||||
|
||||
function getToggleOptions(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;
|
||||
}
|
||||
|
||||
toggledElement = element;
|
||||
|
||||
toggleEntries = [
|
||||
{
|
||||
id: 'toggle-parallel-mi',
|
||||
className: 'icon-parallel-mi-marker',
|
||||
active: isParallel,
|
||||
action: toggleMi,
|
||||
options: {
|
||||
loopCharacteristics: 'bpmn:MultiInstanceLoopCharacteristics',
|
||||
isSequential: false
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'toggle-sequential-mi',
|
||||
className: 'icon-sequential-mi-marker',
|
||||
active: isSequential,
|
||||
action: toggleMi,
|
||||
options: {
|
||||
loopCharacteristics: 'bpmn:MultiInstanceLoopCharacteristics',
|
||||
isSequential: true
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'toggle-loop',
|
||||
className: 'icon-loop-marker',
|
||||
active: isLoop,
|
||||
action: toggleMi,
|
||||
options: {
|
||||
loopCharacteristics: 'bpmn:StandardLoopCharacteristics'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
return toggleEntries;
|
||||
}
|
||||
|
||||
|
||||
function getReplaceOptions(element) {
|
||||
|
||||
|
@ -159,12 +247,18 @@ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection) {
|
|||
// API
|
||||
|
||||
this.openChooser = function(position, element) {
|
||||
var entries = this.getReplaceOptions(element);
|
||||
var entries = this.getReplaceOptions(element),
|
||||
headerEntries;
|
||||
|
||||
if (is(element, 'bpmn:Activity')) {
|
||||
headerEntries = this.getToggleOptions(element);
|
||||
}
|
||||
|
||||
popupMenu.open(
|
||||
{
|
||||
className: 'replace-menu',
|
||||
position: position,
|
||||
headerEntries: headerEntries,
|
||||
entries: entries
|
||||
}
|
||||
);
|
||||
|
@ -172,9 +266,11 @@ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection) {
|
|||
|
||||
this.getReplaceOptions = getReplaceOptions;
|
||||
|
||||
this.getToggleOptions = getToggleOptions;
|
||||
|
||||
this.replaceElement = replaceElement;
|
||||
}
|
||||
|
||||
BpmnReplace.$inject = [ 'bpmnFactory', 'moddle', 'popupMenu', 'replace', 'selection' ];
|
||||
BpmnReplace.$inject = [ 'bpmnFactory', 'moddle', 'popupMenu', 'replace', 'selection', 'modeling' ];
|
||||
|
||||
module.exports = BpmnReplace;
|
||||
module.exports = BpmnReplace;
|
||||
|
|
|
@ -8,6 +8,7 @@ var TestHelper = require('../../../TestHelper'),
|
|||
modelingModule = require('../../../../lib/features/modeling'),
|
||||
replaceModule = require('../../../../lib/features/replace'),
|
||||
domQuery = require('min-dom/lib/query'),
|
||||
domClasses = require('min-dom/lib/classes'),
|
||||
is = require('../../../../lib/util/ModelUtil').is;
|
||||
|
||||
function queryEntry(popupMenu, id) {
|
||||
|
@ -26,9 +27,328 @@ describe('features/popup-menu', function() {
|
|||
|
||||
beforeEach(bootstrapModeler(diagramXML, { 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
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
// then
|
||||
expect(is(loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).toBe(true);
|
||||
expect(loopCharacteristics.isSequential).not.toBe(undefined);
|
||||
expect(loopCharacteristics.isSequential).toBe(false);
|
||||
expect(popupMenu._getEntry('toggle-parallel-mi').active).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it('should be true for sequential marker', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('SequentialTask'),
|
||||
loopCharacteristics = task.businessObject.loopCharacteristics;
|
||||
|
||||
// when
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
// then
|
||||
expect(is(loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).toBe(true);
|
||||
expect(loopCharacteristics.isSequential).toBe(true);
|
||||
expect(popupMenu._getEntry('toggle-sequential-mi').active).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it('should be true for loop marker', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('LoopTask'),
|
||||
loopCharacteristics = task.businessObject.loopCharacteristics;
|
||||
|
||||
// when
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
// then
|
||||
expect(is(loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).toBe(false);
|
||||
expect(loopCharacteristics.isSequential).toBe(undefined);
|
||||
expect(popupMenu._getEntry('toggle-loop').active).toBe(true);
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
describe('parallel toggle button', function(){
|
||||
|
||||
it('should toggle parallel marker off', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('ParallelTask');
|
||||
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-parallel-mi'),
|
||||
evt = { target: entry, preventDefault: function(){} };
|
||||
|
||||
// when
|
||||
popupMenu.trigger(evt);
|
||||
var parallelEntry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// then
|
||||
expect(task.businessObject.loopCharacteristics).toBe(undefined);
|
||||
expect(domClasses(parallelEntry).has('active')).toBe(false);
|
||||
}));
|
||||
|
||||
|
||||
it('should toggle parallel marker on', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('Task');
|
||||
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-parallel-mi'),
|
||||
evt = { target: entry, preventDefault: function(){} };
|
||||
|
||||
// when
|
||||
popupMenu.trigger(evt);
|
||||
var parallelEntry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// then
|
||||
expect(is(task.businessObject.loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).toBe(true);
|
||||
expect(task.businessObject.loopCharacteristics.isSequential).toBe(false);
|
||||
expect(domClasses(parallelEntry).has('active')).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it('should set sequential button inactive', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('SequentialTask');
|
||||
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// when
|
||||
popupMenu.trigger({ target: entry, preventDefault: function(){} });
|
||||
|
||||
var sequentialEntry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// then
|
||||
expect(domClasses(sequentialEntry).has('active')).toBe(false);
|
||||
}));
|
||||
|
||||
|
||||
it('should set loop button inactive', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('LoopTask');
|
||||
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// when
|
||||
popupMenu.trigger({ target: entry, preventDefault: function(){} });
|
||||
|
||||
var loopEntry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// then
|
||||
expect(domClasses(loopEntry).has('active')).toBe(false);
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
describe('sequential toggle button', function(){
|
||||
|
||||
it('should toggle sequential marker off', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('SequentialTask');
|
||||
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-sequential-mi'),
|
||||
evt = { target: entry, preventDefault: function(){} };
|
||||
|
||||
// when
|
||||
popupMenu.trigger(evt);
|
||||
var sequentialEntry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// then
|
||||
expect(task.businessObject.loopCharacteristics).toBe(undefined);
|
||||
expect(domClasses(sequentialEntry).has('active')).toBe(false);
|
||||
}));
|
||||
|
||||
|
||||
it('should toggle sequential marker on', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('Task');
|
||||
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-sequential-mi'),
|
||||
evt = { target: entry, preventDefault: function(){} };
|
||||
|
||||
// when
|
||||
popupMenu.trigger(evt);
|
||||
var sequentialEntry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// then
|
||||
expect(is(task.businessObject.loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).toBe(true);
|
||||
expect(task.businessObject.loopCharacteristics.isSequential).toBe(true);
|
||||
expect(domClasses(sequentialEntry).has('active')).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it('should set loop button inactive', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('LoopTask');
|
||||
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// when
|
||||
popupMenu.trigger({ target: entry, preventDefault: function(){} });
|
||||
|
||||
var loopEntry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// then
|
||||
expect(domClasses(loopEntry).has('active')).toBe(false);
|
||||
}));
|
||||
|
||||
|
||||
it('should set parallel button inactive', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('ParallelTask');
|
||||
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// when
|
||||
popupMenu.trigger({ target: entry, preventDefault: function(){} });
|
||||
|
||||
var parallelEntry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// then
|
||||
expect(domClasses(parallelEntry).has('active')).toBe(false);
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
describe('loop toggle button', function(){
|
||||
|
||||
it('should toggle loop marker off', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('LoopTask');
|
||||
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-loop'),
|
||||
evt = { target: entry, preventDefault: function(){} };
|
||||
|
||||
// when
|
||||
popupMenu.trigger(evt);
|
||||
var loopEntry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// then
|
||||
expect(is(task.businessObject.loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).toBe(undefined);
|
||||
expect(domClasses(loopEntry).has('active')).toBe(false);
|
||||
}));
|
||||
|
||||
|
||||
it('should toggle loop marker on', inject(function(popupMenu, bpmnReplace, elementRegistry){
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('Task');
|
||||
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-loop'),
|
||||
evt = { target: entry, preventDefault: function(){} };
|
||||
|
||||
// when
|
||||
popupMenu.trigger(evt);
|
||||
var loopEntry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// then
|
||||
expect(is(task.businessObject.loopCharacteristics, 'bpmn:StandardLoopCharacteristics')).toBe(true);
|
||||
expect(domClasses(loopEntry).has('active')).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it('should set sequential button inactive', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('SequentialTask');
|
||||
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// when
|
||||
popupMenu.trigger({ target: entry, preventDefault: function(){} });
|
||||
|
||||
var sequentialEntry = queryEntry(popupMenu, 'toggle-sequential-mi');
|
||||
|
||||
// then
|
||||
expect(domClasses(sequentialEntry).has('active')).toBe(false);
|
||||
}));
|
||||
|
||||
|
||||
it('should set parallel button inactive', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('ParallelTask');
|
||||
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'toggle-loop');
|
||||
|
||||
// when
|
||||
popupMenu.trigger({ target: entry, preventDefault: function(){} });
|
||||
|
||||
var parallelEntry = queryEntry(popupMenu, 'toggle-parallel-mi');
|
||||
|
||||
// then
|
||||
expect(domClasses(parallelEntry).has('active')).toBe(false);
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
describe('replacing a task', function() {
|
||||
|
||||
it('should retain the loop characteristics', inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('SequentialTask');
|
||||
|
||||
bpmnReplace.openChooser({ x: task.x + 100, y: task.y + 100 }, task);
|
||||
|
||||
var entry = queryEntry(popupMenu, 'replace-with-send-task');
|
||||
|
||||
// when
|
||||
// replacing the task with a send task
|
||||
popupMenu.trigger({ target: entry, preventDefault: function(){} });
|
||||
|
||||
// then
|
||||
// get the send task from the registry
|
||||
var sendTask = elementRegistry.filter(function(element, gfx) { return element.type === 'bpmn:SendTask';})[0];
|
||||
|
||||
expect(sendTask.businessObject.loopCharacteristics).toBeDefined();
|
||||
expect(is(sendTask.businessObject.loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).toBe(true);
|
||||
expect(sendTask.businessObject.loopCharacteristics.isSequential).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it('should retain the loop characteristics for call activites',
|
||||
inject(function(popupMenu, bpmnReplace, elementRegistry) {
|
||||
|
||||
|
@ -52,6 +372,7 @@ describe('features/popup-menu', function() {
|
|||
expect(callActivity.businessObject.loopCharacteristics).toBeDefined();
|
||||
expect(is(callActivity.businessObject.loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics')).toBe(true);
|
||||
expect(callActivity.businessObject.loopCharacteristics.isSequential).toBe(true);
|
||||
|
||||
}));
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue