feat: add alignment and distribution menu multi-element context pad
Closes #1680 Closes #1691

![fake-join[bot]](/assets/img/avatar_default.png)
@ -8,7 +8,7 @@
|
||||
--color-grey-225-10-80: hsl(225, 10%, 80%);
|
||||
--color-grey-225-10-85: hsl(225, 10%, 85%);
|
||||
--color-grey-225-10-90: hsl(225, 10%, 90%);
|
||||
--color-grey-225-10-95: hsl(225, 10%, 95%);
|
||||
--color-grey-225-10-95: hsl(225, 10%, 95%);
|
||||
--color-grey-225-10-97: hsl(225, 10%, 97%);
|
||||
|
||||
--color-blue-205-100-45: hsl(205, 100%, 45%);
|
||||
@ -24,8 +24,8 @@
|
||||
--color-red-360-100-97: hsl(360, 100%, 97%);
|
||||
|
||||
--color-white: hsl(0, 0%, 100%);
|
||||
--color-black: hsl(0, 0%, 0%);
|
||||
--color-black-opacity-05: hsla(0, 0%, 0%, 5%);
|
||||
--color-black: hsl(0, 0%, 0%);
|
||||
--color-black-opacity-05: hsla(0, 0%, 0%, 5%);
|
||||
--color-black-opacity-10: hsla(0, 0%, 0%, 10%);
|
||||
|
||||
--breadcrumbs-font-family: var(--bjs-font-family);
|
||||
@ -113,4 +113,33 @@
|
||||
|
||||
.selected .bjs-drilldown-empty {
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
[data-popup="align-elements"] .djs-popup-body {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
[data-popup="align-elements"] .djs-popup-body [data-group] + [data-group] {
|
||||
border-left: 1px solid var(--popup-border-color);
|
||||
}
|
||||
|
||||
[data-popup="align-elements"] [data-group="align"] {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
[data-popup="align-elements"] .djs-popup-body .entry {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
|
||||
padding: 6px 8px;
|
||||
}
|
||||
|
||||
[data-popup="align-elements"] .djs-popup-body .entry img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
[data-popup="align-elements"] .bjs-align-elements-menu-entry {
|
||||
display: inline-block;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas';
|
||||
import TouchModule from 'diagram-js/lib/navigation/touch';
|
||||
import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll';
|
||||
|
||||
import AlignElementsModule from 'diagram-js/lib/features/align-elements';
|
||||
import AlignElementsModule from './features/align-elements';
|
||||
import AutoPlaceModule from './features/auto-place';
|
||||
import AutoResizeModule from './features/auto-resize';
|
||||
import AutoScrollModule from 'diagram-js/lib/features/auto-scroll';
|
||||
|
@ -0,0 +1,87 @@
|
||||
import {
|
||||
assign
|
||||
} from 'min-dash';
|
||||
|
||||
import ICONS from './AlignElementsIcons';
|
||||
|
||||
var LOW_PRIORITY = 900;
|
||||
|
||||
/**
|
||||
* A provider for align elements context pad button
|
||||
*/
|
||||
export default function AlignElementsContextPadProvider(contextPad, popupMenu, translate, canvas) {
|
||||
|
||||
contextPad.registerProvider(LOW_PRIORITY, this);
|
||||
|
||||
this._contextPad = contextPad;
|
||||
this._popupMenu = popupMenu;
|
||||
this._translate = translate;
|
||||
this._canvas = canvas;
|
||||
}
|
||||
|
||||
AlignElementsContextPadProvider.$inject = [
|
||||
'contextPad',
|
||||
'popupMenu',
|
||||
'translate',
|
||||
'canvas'
|
||||
];
|
||||
|
||||
AlignElementsContextPadProvider.prototype.getMultiElementContextPadEntries = function(elements) {
|
||||
var actions = {};
|
||||
|
||||
if (this._isAllowed(elements)) {
|
||||
assign(actions, this._getEntries(elements));
|
||||
}
|
||||
|
||||
return actions;
|
||||
};
|
||||
|
||||
AlignElementsContextPadProvider.prototype._isAllowed = function(elements) {
|
||||
return !this._popupMenu.isEmpty(elements, 'align-elements');
|
||||
};
|
||||
|
||||
AlignElementsContextPadProvider.prototype._getEntries = function(elements) {
|
||||
var self = this;
|
||||
|
||||
return {
|
||||
'align-elements': {
|
||||
group: 'align-elements',
|
||||
title: self._translate('Align elements'),
|
||||
imageUrl: ICONS['align'],
|
||||
action: {
|
||||
click: function(event, elements) {
|
||||
var position = self._getMenuPosition(elements);
|
||||
|
||||
assign(position, {
|
||||
cursor: {
|
||||
x: event.x,
|
||||
y: event.y
|
||||
}
|
||||
});
|
||||
|
||||
self._popupMenu.open(elements, 'align-elements', position);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
AlignElementsContextPadProvider.prototype._getMenuPosition = function(elements) {
|
||||
var Y_OFFSET = 5;
|
||||
|
||||
var diagramContainer = this._canvas.getContainer(),
|
||||
pad = this._contextPad.getPad(elements).html;
|
||||
|
||||
var diagramRect = diagramContainer.getBoundingClientRect(),
|
||||
padRect = pad.getBoundingClientRect();
|
||||
|
||||
var top = padRect.top - diagramRect.top;
|
||||
var left = padRect.left - diagramRect.left;
|
||||
|
||||
var pos = {
|
||||
x: left,
|
||||
y: top + padRect.height + Y_OFFSET
|
||||
};
|
||||
|
||||
return pos;
|
||||
};
|
15
lib/features/align-elements/AlignElementsIcons.js
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* To change the icons, modify the SVGs in `./resources`, execute `npx svgo -f resources --datauri enc -o dist`,
|
||||
* and then replace respective icons with the optimized data URIs in `./dist`.
|
||||
*/
|
||||
var icons = {
|
||||
align: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%202000%202000%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M200%20150v1700%22%2F%3E%3Crect%20x%3D%22500%22%20y%3D%22150%22%20width%3D%221300%22%20height%3D%22700%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22500%22%20y%3D%221150%22%20width%3D%22700%22%20height%3D%22700%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
|
||||
bottom: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M150%201650h1500%22%2F%3E%3Crect%20x%3D%22150%22%20y%3D%22350%22%20width%3D%22600%22%20height%3D%221300%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%221050%22%20y%3D%22850%22%20width%3D%22600%22%20height%3D%22800%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
|
||||
center: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M900%20150v1500%22%2F%3E%3Crect%20x%3D%22250%22%20y%3D%22150%22%20width%3D%221300%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22500%22%20y%3D%221050%22%20width%3D%22800%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
|
||||
left: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M100%20150v1500%22%2F%3E%3Crect%20x%3D%22100%22%20y%3D%22150%22%20width%3D%221300%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22100%22%20y%3D%221050%22%20width%3D%22800%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
|
||||
right: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M1650%20150v1500%22%2F%3E%3Crect%20x%3D%22350%22%20y%3D%22150%22%20width%3D%221300%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22850%22%20y%3D%221050%22%20width%3D%22800%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
|
||||
top: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M150%20150h1500%22%2F%3E%3Crect%20x%3D%22150%22%20y%3D%22150%22%20width%3D%22600%22%20height%3D%221300%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%221050%22%20y%3D%22150%22%20width%3D%22600%22%20height%3D%22800%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
|
||||
middle: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M150%20900h1500%22%2F%3E%3Crect%20x%3D%22150%22%20y%3D%22250%22%20width%3D%22600%22%20height%3D%221300%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%221050%22%20y%3D%22500%22%20width%3D%22600%22%20height%3D%22800%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E'
|
||||
};
|
||||
|
||||
export default icons;
|
72
lib/features/align-elements/AlignElementsMenuProvider.js
Normal file
@ -0,0 +1,72 @@
|
||||
import ICONS from './AlignElementsIcons';
|
||||
|
||||
import {
|
||||
assign,
|
||||
forEach,
|
||||
} from 'min-dash';
|
||||
|
||||
var ALIGNMENT_OPTIONS = [
|
||||
'left',
|
||||
'center',
|
||||
'right',
|
||||
'top',
|
||||
'middle',
|
||||
'bottom'
|
||||
];
|
||||
|
||||
/**
|
||||
* A provider for align elements popup menu.
|
||||
*/
|
||||
export default function AlignElementsMenuProvider(popupMenu, alignElements, translate, rules) {
|
||||
|
||||
this._alignElements = alignElements;
|
||||
this._translate = translate;
|
||||
this._popupMenu = popupMenu;
|
||||
this._rules = rules;
|
||||
|
||||
popupMenu.registerProvider('align-elements', this);
|
||||
}
|
||||
|
||||
AlignElementsMenuProvider.$inject = [
|
||||
'popupMenu',
|
||||
'alignElements',
|
||||
'translate',
|
||||
'rules'
|
||||
];
|
||||
|
||||
AlignElementsMenuProvider.prototype.getPopupMenuEntries = function(elements) {
|
||||
var entries = {};
|
||||
|
||||
if (this._isAllowed(elements)) {
|
||||
assign(entries, this._getEntries(elements));
|
||||
}
|
||||
|
||||
return entries;
|
||||
};
|
||||
|
||||
AlignElementsMenuProvider.prototype._isAllowed = function(elements) {
|
||||
return this._rules.allowed('elements.align', { elements: elements });
|
||||
};
|
||||
|
||||
AlignElementsMenuProvider.prototype._getEntries = function(elements) {
|
||||
var alignElements = this._alignElements,
|
||||
translate = this._translate,
|
||||
popupMenu = this._popupMenu;
|
||||
|
||||
var entries = {};
|
||||
|
||||
forEach(ALIGNMENT_OPTIONS, function(alignment) {
|
||||
entries[ 'align-elements-' + alignment ] = {
|
||||
group: 'align',
|
||||
title: translate('Align elements ' + alignment),
|
||||
className: 'bjs-align-elements-menu-entry',
|
||||
imageUrl: ICONS[alignment],
|
||||
action: function(event, entry) {
|
||||
alignElements.trigger(elements, alignment);
|
||||
popupMenu.close();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return entries;
|
||||
};
|
39
lib/features/align-elements/BpmnAlignElements.js
Normal file
@ -0,0 +1,39 @@
|
||||
import inherits from 'inherits-browser';
|
||||
|
||||
import RuleProvider from 'diagram-js/lib/features/rules/RuleProvider';
|
||||
import { getParents } from 'diagram-js/lib/util/Elements';
|
||||
|
||||
import {
|
||||
filter
|
||||
} from 'min-dash';
|
||||
|
||||
/**
|
||||
* Rule provider for alignment of BPMN elements.
|
||||
*/
|
||||
export default function BpmnAlignElements(eventBus) {
|
||||
RuleProvider.call(this, eventBus);
|
||||
}
|
||||
|
||||
BpmnAlignElements.$inject = [ 'eventBus' ];
|
||||
|
||||
inherits(BpmnAlignElements, RuleProvider);
|
||||
|
||||
BpmnAlignElements.prototype.init = function() {
|
||||
this.addRule('elements.align', function(context) {
|
||||
var elements = context.elements;
|
||||
|
||||
// filter out elements which cannot be aligned
|
||||
var filteredElements = filter(elements, function(element) {
|
||||
return !(element.waypoints || element.host || element.labelTarget);
|
||||
});
|
||||
|
||||
// filter out elements which are children of any of the selected elements
|
||||
filteredElements = getParents(filteredElements);
|
||||
|
||||
if (filteredElements.length < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return filteredElements;
|
||||
});
|
||||
};
|
23
lib/features/align-elements/index.js
Normal file
@ -0,0 +1,23 @@
|
||||
import AlignElementsModule from 'diagram-js/lib/features/align-elements';
|
||||
import ContextPadModule from 'diagram-js/lib/features/context-pad';
|
||||
import PopupMenuModule from 'diagram-js/lib/features/popup-menu';
|
||||
|
||||
import AlignElementsContextPadProvider from './AlignElementsContextPadProvider';
|
||||
import AlignElementsMenuProvider from './AlignElementsMenuProvider';
|
||||
import BpmnAlignElements from './BpmnAlignElements';
|
||||
|
||||
export default {
|
||||
__depends__: [
|
||||
AlignElementsModule,
|
||||
ContextPadModule,
|
||||
PopupMenuModule
|
||||
],
|
||||
__init__: [
|
||||
'alignElementsContextPadProvider',
|
||||
'alignElementsMenuProvider',
|
||||
'bpmnAlignElements'
|
||||
],
|
||||
alignElementsContextPadProvider: [ 'type', AlignElementsContextPadProvider ],
|
||||
alignElementsMenuProvider: [ 'type', AlignElementsMenuProvider ],
|
||||
bpmnAlignElements: [ 'type', BpmnAlignElements]
|
||||
};
|
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
|
||||
<line x1="150" y1="1650" x2="1650" y2="1650" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
|
||||
<rect x="150" y="350" width="600" height="1300" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
|
||||
<rect x="1050" y="850" width="600" height="800" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
|
||||
</svg>
|
After Width: | Height: | Size: 448 B |
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
|
||||
<line x1="900" y1="150" x2="900" y2="1650" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
|
||||
<rect x="250" y="150" width="1300" height="600" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
|
||||
<rect x="500" y="1050" width="800" height="600" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
|
||||
</svg>
|
After Width: | Height: | Size: 446 B |
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
|
||||
<line x1="100" y1="150" x2="100" y2="1650" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
|
||||
<rect x="100" y="150" width="1300" height="600" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
|
||||
<rect x="100" y="1050" width="800" height="600" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
|
||||
</svg>
|
After Width: | Height: | Size: 446 B |
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
|
||||
<line x1="1650" y1="150" x2="1650" y2="1650" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
|
||||
<rect x="350" y="150" width="1300" height="600" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
|
||||
<rect x="850" y="1050" width="800" height="600" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
|
||||
</svg>
|
After Width: | Height: | Size: 448 B |
5
lib/features/align-elements/resources/align-tool.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000">
|
||||
<line x1="200" y1="150" x2="200" y2="1850" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
|
||||
<rect x="500" y="150" width="1300" height="700" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
|
||||
<rect x="500" y="1150" width="700" height="700" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
|
||||
</svg>
|
After Width: | Height: | Size: 446 B |
5
lib/features/align-elements/resources/align-top-tool.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
|
||||
<line x1="150" y1="150" x2="1650" y2="150" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
|
||||
<rect x="150" y="150" width="600" height="1300" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
|
||||
<rect x="1050" y="150" width="600" height="800" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
|
||||
</svg>
|
After Width: | Height: | Size: 446 B |
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
|
||||
<line x1="150" y1="900" x2="1650" y2="900" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
|
||||
<rect x="150" y="250" width="600" height="1300" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
|
||||
<rect x="1050" y="500" width="600" height="800" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
|
||||
</svg>
|
After Width: | Height: | Size: 446 B |
@ -1,3 +1,8 @@
|
||||
import inherits from 'inherits-browser';
|
||||
|
||||
import RuleProvider from 'diagram-js/lib/features/rules/RuleProvider';
|
||||
import { getParents } from 'diagram-js/lib/util/Elements';
|
||||
|
||||
import {
|
||||
filter
|
||||
} from 'min-dash';
|
||||
@ -11,10 +16,19 @@ import {
|
||||
* Registers element exclude filters for elements that
|
||||
* currently do not support distribution.
|
||||
*/
|
||||
export default function BpmnDistributeElements(distributeElements) {
|
||||
export default function BpmnDistributeElements(distributeElements, eventBus, rules) {
|
||||
RuleProvider.call(this, eventBus);
|
||||
}
|
||||
|
||||
distributeElements.registerFilter(function(elements) {
|
||||
return filter(elements, function(element) {
|
||||
BpmnDistributeElements.$inject = [ 'distributeElements', 'eventBus', 'rules' ];
|
||||
|
||||
inherits(BpmnDistributeElements, RuleProvider);
|
||||
|
||||
BpmnDistributeElements.prototype.init = function() {
|
||||
this.addRule('elements.distribute', function(context) {
|
||||
var elements = context.elements;
|
||||
|
||||
elements = filter(elements, function(element) {
|
||||
var cannotDistribute = isAny(element, [
|
||||
'bpmn:Association',
|
||||
'bpmn:BoundaryEvent',
|
||||
@ -22,14 +36,20 @@ export default function BpmnDistributeElements(distributeElements) {
|
||||
'bpmn:DataOutputAssociation',
|
||||
'bpmn:Lane',
|
||||
'bpmn:MessageFlow',
|
||||
'bpmn:Participant',
|
||||
'bpmn:SequenceFlow',
|
||||
'bpmn:TextAnnotation'
|
||||
]);
|
||||
|
||||
return !(element.labelTarget || cannotDistribute);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
BpmnDistributeElements.$inject = [ 'distributeElements' ];
|
||||
// filter out elements which are children of any of the selected elements
|
||||
elements = getParents(elements);
|
||||
|
||||
if (elements.length < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return elements;
|
||||
});
|
||||
};
|
||||
|
10
lib/features/distribute-elements/DistributeElementsIcons.js
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* To change the icons, modify the SVGs in `./resources`, execute `npx svgo -f resources --datauri enc -o dist`,
|
||||
* and then replace respective icons with the optimized data URIs in `./dist`.
|
||||
*/
|
||||
var icons = {
|
||||
horizontal: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linejoin%3Around%22%20d%3D%22M450%20400V150h900v250%22%2F%3E%3Crect%20x%3D%22150%22%20y%3D%22450%22%20width%3D%22600%22%20height%3D%221200%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%221050%22%20y%3D%22450%22%20width%3D%22600%22%20height%3D%22800%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
|
||||
vertical: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linejoin%3Around%22%20d%3D%22M400%201350H150V450h250%22%2F%3E%3Crect%20x%3D%22450%22%20y%3D%22150%22%20width%3D%221200%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22450%22%20y%3D%221050%22%20width%3D%22800%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
|
||||
};
|
||||
|
||||
export default icons;
|
@ -0,0 +1,69 @@
|
||||
import ICONS from './DistributeElementsIcons';
|
||||
|
||||
import { assign } from 'min-dash';
|
||||
|
||||
var LOW_PRIORITY = 900;
|
||||
|
||||
/**
|
||||
* A provider for distribute elements popup menu.
|
||||
*/
|
||||
export default function DistributeElementsMenuProvider(
|
||||
popupMenu, distributeElements, translate, rules) {
|
||||
this._distributeElements = distributeElements;
|
||||
this._translate = translate;
|
||||
this._popupMenu = popupMenu;
|
||||
this._rules = rules;
|
||||
|
||||
popupMenu.registerProvider('align-elements', LOW_PRIORITY, this);
|
||||
}
|
||||
|
||||
DistributeElementsMenuProvider.$inject = [
|
||||
'popupMenu',
|
||||
'distributeElements',
|
||||
'translate',
|
||||
'rules'
|
||||
];
|
||||
|
||||
DistributeElementsMenuProvider.prototype.getPopupMenuEntries = function(elements) {
|
||||
var entries = {};
|
||||
|
||||
if (this._isAllowed(elements)) {
|
||||
assign(entries, this._getEntries(elements));
|
||||
}
|
||||
|
||||
return entries;
|
||||
};
|
||||
|
||||
DistributeElementsMenuProvider.prototype._isAllowed = function(elements) {
|
||||
return this._rules.allowed('elements.distribute', { elements: elements });
|
||||
};
|
||||
|
||||
DistributeElementsMenuProvider.prototype._getEntries = function(elements) {
|
||||
var distributeElements = this._distributeElements,
|
||||
translate = this._translate,
|
||||
popupMenu = this._popupMenu;
|
||||
|
||||
var entries = {
|
||||
'distribute-elements-horizontal': {
|
||||
group: 'distribute',
|
||||
title: translate('Distribute elements horizontally'),
|
||||
className: 'bjs-align-elements-menu-entry',
|
||||
imageUrl: ICONS['horizontal'],
|
||||
action: function(event, entry) {
|
||||
distributeElements.trigger(elements, 'horizontal');
|
||||
popupMenu.close();
|
||||
}
|
||||
},
|
||||
'distribute-elements-vertical': {
|
||||
group: 'distribute',
|
||||
title: translate('Distribute elements vertically'),
|
||||
imageUrl: ICONS['vertical'],
|
||||
action: function(event, entry) {
|
||||
distributeElements.trigger(elements, 'vertical');
|
||||
popupMenu.close();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return entries;
|
||||
};
|
@ -1,12 +1,19 @@
|
||||
import DistributeElementsModule from 'diagram-js/lib/features/distribute-elements';
|
||||
import PopupMenuModule from 'diagram-js/lib/features/popup-menu';
|
||||
|
||||
import BpmnDistributeElements from './BpmnDistributeElements';
|
||||
import DistributeElementsMenuProvider from './DistributeElementsMenuProvider';
|
||||
|
||||
|
||||
export default {
|
||||
__depends__: [
|
||||
PopupMenuModule,
|
||||
DistributeElementsModule
|
||||
],
|
||||
__init__: [ 'bpmnDistributeElements' ],
|
||||
bpmnDistributeElements: [ 'type', BpmnDistributeElements ]
|
||||
__init__: [
|
||||
'bpmnDistributeElements',
|
||||
'distributeElementsMenuProvider'
|
||||
],
|
||||
bpmnDistributeElements: [ 'type', BpmnDistributeElements ],
|
||||
distributeElementsMenuProvider: [ 'type', DistributeElementsMenuProvider ]
|
||||
};
|
||||
|
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
|
||||
<polyline points="450 400 450 150 1350 150 1350 400" style="fill:none;stroke:currentColor;stroke-width:100;stroke-linejoin:round;"/>
|
||||
<rect x="150" y="450" width="600" height="1200" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
|
||||
<rect x="1050" y="450" width="600" height="800" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
|
||||
</svg>
|
After Width: | Height: | Size: 467 B |
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
|
||||
<polyline points="400 1350 150 1350 150 450 400 450" style="fill:none;stroke:currentColor;stroke-width:100;stroke-linejoin:round;"/>
|
||||
<rect x="450" y="150" width="1200" height="600" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
|
||||
<rect x="450" y="1050" width="800" height="600" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
|
||||
</svg>
|
After Width: | Height: | Size: 467 B |
112
test/fixtures/bpmn/align-elements.bpmn
vendored
@ -1,17 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<semantic:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:semantic="http://www.omg.org/spec/BPMN/20100524/MODEL" id="_1275940932088" targetNamespace="http://www.trisotech.com/definitions/_1275940932088" exporter="Camunda Modeler" exporterVersion="1.2.0-dev">
|
||||
<semantic:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:semantic="http://www.omg.org/spec/BPMN/20100524/MODEL" id="_1275940932088" targetNamespace="http://www.trisotech.com/definitions/_1275940932088" exporter="Camunda Modeler" exporterVersion="5.0.0">
|
||||
<semantic:message id="_1275940932310" />
|
||||
<semantic:message id="_1275940932433" />
|
||||
<semantic:message id="_1275940932198" />
|
||||
<semantic:process id="_6-2" isExecutable="false">
|
||||
<semantic:sequenceFlow id="SequenceFlow_08zyuyv" name="hello" sourceRef="Task_boundary_evt" targetRef="Task_hello" />
|
||||
<semantic:boundaryEvent id="BoundaryEvent_0n2gx06" attachedToRef="Task_boundary_evt" />
|
||||
<semantic:task id="Task_hello" name="hello">
|
||||
<semantic:incoming>SequenceFlow_08zyuyv</semantic:incoming>
|
||||
</semantic:task>
|
||||
<semantic:task id="Task_boundary_evt">
|
||||
<semantic:outgoing>SequenceFlow_08zyuyv</semantic:outgoing>
|
||||
</semantic:task>
|
||||
<semantic:boundaryEvent id="BoundaryEvent_1" attachedToRef="Task_boundary_evt" />
|
||||
<semantic:sequenceFlow id="SequenceFlow_08zyuyv" name="hello" sourceRef="Task_boundary_evt" targetRef="Task_hello" />
|
||||
</semantic:process>
|
||||
<semantic:collaboration id="C1275940932557">
|
||||
<semantic:participant id="_6-53" name="" processRef="_6-2" />
|
||||
@ -21,14 +21,14 @@
|
||||
</semantic:collaboration>
|
||||
<semantic:process id="_6-1" isExecutable="false">
|
||||
<semantic:laneSet id="ls_6-438">
|
||||
<semantic:lane id="_6-650" name="">
|
||||
<semantic:flowNodeRef>Task_lane</semantic:flowNodeRef>
|
||||
<semantic:lane id="_6-448" name="">
|
||||
<semantic:flowNodeRef>EndEvent_lane</semantic:flowNodeRef>
|
||||
</semantic:lane>
|
||||
<semantic:lane id="_6-446" name="">
|
||||
<semantic:flowNodeRef>SubProcess_lane</semantic:flowNodeRef>
|
||||
</semantic:lane>
|
||||
<semantic:lane id="_6-448" name="">
|
||||
<semantic:flowNodeRef>EndEvent_lane</semantic:flowNodeRef>
|
||||
<semantic:lane id="_6-650" name="">
|
||||
<semantic:flowNodeRef>Task_lane</semantic:flowNodeRef>
|
||||
</semantic:lane>
|
||||
</semantic:laneSet>
|
||||
<semantic:task id="Task_lane">
|
||||
@ -41,92 +41,92 @@
|
||||
<semantic:incoming>SequenceFlow_1nrce3c</semantic:incoming>
|
||||
<semantic:outgoing>SequenceFlow_0qa7db7</semantic:outgoing>
|
||||
</semantic:subProcess>
|
||||
<semantic:sequenceFlow id="SequenceFlow_1nrce3c" sourceRef="Task_lane" targetRef="SubProcess_lane" />
|
||||
<semantic:sequenceFlow id="SequenceFlow_0qa7db7" sourceRef="SubProcess_lane" targetRef="EndEvent_lane" />
|
||||
<semantic:sequenceFlow id="SequenceFlow_1nrce3c" sourceRef="Task_lane" targetRef="SubProcess_lane" />
|
||||
</semantic:process>
|
||||
<bpmndi:BPMNDiagram id="Trisotech.Visio-_6" name="Untitled Diagram" documentation="" resolution="96.00000267028808">
|
||||
<bpmndi:BPMNPlane bpmnElement="C1275940932557">
|
||||
<bpmndi:BPMNShape id="Trisotech.Visio__6-53" bpmnElement="_6-53" isHorizontal="true">
|
||||
<dc:Bounds x="12" y="12" width="1044" height="294" />
|
||||
<dc:Bounds x="152" y="82" width="1044" height="294" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_08zyuyv_di" bpmnElement="SequenceFlow_08zyuyv">
|
||||
<di:waypoint x="435" y="186" />
|
||||
<di:waypoint x="533" y="186" />
|
||||
<di:waypoint x="533" y="217" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="471" y="160" width="24" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="Task_0s45gnz_di" bpmnElement="Task_hello">
|
||||
<dc:Bounds x="483" y="217" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Task_07vyznk_di" bpmnElement="Task_boundary_evt">
|
||||
<dc:Bounds x="335" y="146" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="BoundaryEvent_0n2gx06_di" bpmnElement="BoundaryEvent_1">
|
||||
<dc:Bounds x="336" y="208" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="169.036" y="173.79" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Trisotech.Visio__6-438" bpmnElement="_6-438" isHorizontal="true">
|
||||
<dc:Bounds x="68" y="358" width="825" height="539" />
|
||||
<dc:Bounds x="208" y="428" width="825" height="539" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Trisotech.Visio__6__6-448" bpmnElement="_6-448" isHorizontal="true">
|
||||
<dc:Bounds x="98" y="712" width="795" height="185" />
|
||||
<dc:Bounds x="238" y="782" width="795" height="185" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Trisotech.Visio__6__6-446" bpmnElement="_6-446" isHorizontal="true">
|
||||
<dc:Bounds x="98" y="472" width="795" height="240" />
|
||||
<dc:Bounds x="238" y="542" width="795" height="240" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Trisotech.Visio__6__6-650" bpmnElement="_6-650" isHorizontal="true">
|
||||
<dc:Bounds x="98" y="358" width="795" height="114" />
|
||||
<dc:Bounds x="238" y="428" width="795" height="114" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Task_0qh67cn_di" bpmnElement="Task_lane">
|
||||
<dc:Bounds x="136" y="375" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0qa7db7_di" bpmnElement="SequenceFlow_0qa7db7">
|
||||
<di:waypoint x="629" y="766" />
|
||||
<di:waypoint x="629" y="893" />
|
||||
<di:waypoint x="924" y="893" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="470.5" y="618.5" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1nrce3c_di" bpmnElement="SequenceFlow_1nrce3c">
|
||||
<di:waypoint xsi:type="dc:Point" x="236" y="415" />
|
||||
<di:waypoint xsi:type="dc:Point" x="275" y="415" />
|
||||
<di:waypoint xsi:type="dc:Point" x="275" y="596" />
|
||||
<di:waypoint xsi:type="dc:Point" x="314" y="596" />
|
||||
<di:waypoint x="376" y="485" />
|
||||
<di:waypoint x="415" y="485" />
|
||||
<di:waypoint x="415" y="666" />
|
||||
<di:waypoint x="454" y="666" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="242" y="468" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="Task_0qh67cn_di" bpmnElement="Task_lane">
|
||||
<dc:Bounds x="276" y="445" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="EndEvent_1jdsxxr_di" bpmnElement="EndEvent_lane">
|
||||
<dc:Bounds x="784" y="805" width="36" height="36" />
|
||||
<dc:Bounds x="924" y="875" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="757" y="841" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="SubProcess_06gy2ot_di" bpmnElement="SubProcess_lane" isExpanded="true">
|
||||
<dc:Bounds x="314" y="496" width="350" height="200" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0qa7db7_di" bpmnElement="SequenceFlow_0qa7db7">
|
||||
<di:waypoint xsi:type="dc:Point" x="489" y="696" />
|
||||
<di:waypoint xsi:type="dc:Point" x="489" y="823" />
|
||||
<di:waypoint xsi:type="dc:Point" x="784" y="823" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="470.5" y="618.5" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="Task_07vyznk_di" bpmnElement="Task_boundary_evt">
|
||||
<dc:Bounds x="195.036" y="75.78999999999999" width="100" height="80" />
|
||||
<dc:Bounds x="454" y="566" width="350" height="200" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="MessageFlow_1pvlume_di" bpmnElement="MessageFlow_1pvlume">
|
||||
<di:waypoint xsi:type="dc:Point" x="245" y="156" />
|
||||
<di:waypoint xsi:type="dc:Point" x="245" y="262" />
|
||||
<di:waypoint xsi:type="dc:Point" x="184" y="262" />
|
||||
<di:waypoint xsi:type="dc:Point" x="184" y="375" />
|
||||
<di:waypoint x="385" y="226" />
|
||||
<di:waypoint x="385" y="332" />
|
||||
<di:waypoint x="324" y="332" />
|
||||
<di:waypoint x="324" y="445" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="98" y="254.5" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="BoundaryEvent_0n2gx06_di" bpmnElement="BoundaryEvent_0n2gx06">
|
||||
<dc:Bounds x="196.036" y="137.79" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="169.036" y="173.79" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Task_0s45gnz_di" bpmnElement="Task_hello">
|
||||
<dc:Bounds x="343.036" y="146.79" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_08zyuyv_di" bpmnElement="SequenceFlow_08zyuyv">
|
||||
<di:waypoint xsi:type="dc:Point" x="295" y="116" />
|
||||
<di:waypoint xsi:type="dc:Point" x="393" y="116" />
|
||||
<di:waypoint xsi:type="dc:Point" x="393" y="147" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="298" y="89.5" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="MessageFlow_1omk2ha_di" bpmnElement="MessageFlow_1omk2ha">
|
||||
<di:waypoint xsi:type="dc:Point" x="393" y="227" />
|
||||
<di:waypoint xsi:type="dc:Point" x="393" y="496" />
|
||||
<di:waypoint x="533" y="297" />
|
||||
<di:waypoint x="533" y="566" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="386" y="349" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.2.2">
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.0.0">
|
||||
<bpmn:process id="Process_1" isExecutable="false">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>SequenceFlow_0vrvkcp</bpmn:outgoing>
|
||||
@ -15,44 +15,53 @@
|
||||
<bpmn:incoming>SequenceFlow_1jet52k</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="SequenceFlow_1jet52k" sourceRef="BoundaryEvent_1" targetRef="EndEvent_1" />
|
||||
<bpmn:subProcess id="SubProcess">
|
||||
<bpmn:startEvent id="SubProcessChild" />
|
||||
</bpmn:subProcess>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1jet52k_di" bpmnElement="SequenceFlow_1jet52k">
|
||||
<di:waypoint x="378" y="119" />
|
||||
<di:waypoint x="601" y="119" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="324.5" y="94" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0vrvkcp_di" bpmnElement="SequenceFlow_0vrvkcp">
|
||||
<di:waypoint x="193" y="79" />
|
||||
<di:waypoint x="260" y="79" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="61.5" y="54" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="37" y="61" width="36" height="36" />
|
||||
<dc:Bounds x="157" y="61" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="10" y="97" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Task_1qacn6w_di" bpmnElement="Task_1">
|
||||
<dc:Bounds x="140" y="39" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0vrvkcp_di" bpmnElement="SequenceFlow_0vrvkcp">
|
||||
<di:waypoint xsi:type="dc:Point" x="73" y="79" />
|
||||
<di:waypoint xsi:type="dc:Point" x="140" y="79" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="61.5" y="54" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="BoundaryEvent_10ce33p_di" bpmnElement="BoundaryEvent_1">
|
||||
<dc:Bounds x="222" y="101" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="195" y="137" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="260" y="39" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="EndEvent_0lfg1uu_di" bpmnElement="EndEvent_1">
|
||||
<dc:Bounds x="481" y="101" width="36" height="36" />
|
||||
<dc:Bounds x="601" y="101" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="454" y="137" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1jet52k_di" bpmnElement="SequenceFlow_1jet52k">
|
||||
<di:waypoint xsi:type="dc:Point" x="258" y="119" />
|
||||
<di:waypoint xsi:type="dc:Point" x="481" y="119" />
|
||||
<bpmndi:BPMNShape id="Activity_1kbeku9_di" bpmnElement="SubProcess" isExpanded="true">
|
||||
<dc:Bounds x="610" y="200" width="350" height="200" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_0h7npxb_di" bpmnElement="SubProcessChild">
|
||||
<dc:Bounds x="650" y="282" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="BoundaryEvent_10ce33p_di" bpmnElement="BoundaryEvent_1">
|
||||
<dc:Bounds x="342" y="101" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="324.5" y="94" width="90" height="20" />
|
||||
<dc:Bounds x="195" y="137" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
||||
|
50
test/fixtures/bpmn/distribute-elements-filtering.collaboration.bpmn
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.0.0">
|
||||
<bpmn:collaboration id="Collaboration_1wywxe9">
|
||||
<bpmn:participant id="Participant_1o654rf" processRef="Process_1" />
|
||||
<bpmn:participant id="Participant_0lc2m2k" processRef="Process_0bbetmh" />
|
||||
<bpmn:participant id="Participant_0cnn1z4" processRef="Process_14ju0cc" />
|
||||
</bpmn:collaboration>
|
||||
<bpmn:process id="Process_1" isExecutable="false" />
|
||||
<bpmn:process id="Process_0bbetmh" isExecutable="false">
|
||||
<bpmn:laneSet id="LaneSet_0ahmhbw">
|
||||
<bpmn:lane id="Lane_0i9fng7" />
|
||||
<bpmn:lane id="Lane_1yxptwb" />
|
||||
<bpmn:lane id="Lane_03o4rm2" />
|
||||
</bpmn:laneSet>
|
||||
</bpmn:process>
|
||||
<bpmn:process id="Process_14ju0cc" isExecutable="false">
|
||||
<bpmn:laneSet id="LaneSet_0jckrsk">
|
||||
<bpmn:lane id="Lane_1jivykj" />
|
||||
<bpmn:lane id="Lane_04b9l7u" />
|
||||
</bpmn:laneSet>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1wywxe9">
|
||||
<bpmndi:BPMNShape id="Participant_1o654rf_di" bpmnElement="Participant_1o654rf" isHorizontal="true">
|
||||
<dc:Bounds x="160" y="80" width="600" height="250" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Participant_0lc2m2k_di" bpmnElement="Participant_0lc2m2k" isHorizontal="true">
|
||||
<dc:Bounds x="160" y="490" width="600" height="250" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Lane_0i9fng7_di" bpmnElement="Lane_0i9fng7" isHorizontal="true">
|
||||
<dc:Bounds x="190" y="490" width="570" height="83" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Lane_1yxptwb_di" bpmnElement="Lane_1yxptwb" isHorizontal="true">
|
||||
<dc:Bounds x="190" y="573" width="570" height="83" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Lane_03o4rm2_di" bpmnElement="Lane_03o4rm2" isHorizontal="true">
|
||||
<dc:Bounds x="190" y="656" width="570" height="84" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Participant_0cnn1z4_di" bpmnElement="Participant_0cnn1z4" isHorizontal="true">
|
||||
<dc:Bounds x="160" y="780" width="600" height="250" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Lane_1jivykj_di" bpmnElement="Lane_1jivykj" isHorizontal="true">
|
||||
<dc:Bounds x="190" y="780" width="570" height="125" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Lane_04b9l7u_di" bpmnElement="Lane_04b9l7u" isHorizontal="true">
|
||||
<dc:Bounds x="190" y="905" width="570" height="125" />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
@ -0,0 +1,100 @@
|
||||
import {
|
||||
bootstrapModeler,
|
||||
getBpmnJS,
|
||||
inject
|
||||
} from 'test/TestHelper';
|
||||
|
||||
import {
|
||||
query as domQuery
|
||||
} from 'min-dom';
|
||||
|
||||
import alignElementsModule from 'lib/features/align-elements';
|
||||
import modelingModule from 'lib/features/modeling';
|
||||
import coreModule from 'lib/core';
|
||||
|
||||
|
||||
|
||||
describe('features/align-elements - context pad', function() {
|
||||
|
||||
var testModules = [ alignElementsModule, modelingModule, coreModule ];
|
||||
|
||||
var basicXML = require('../../../fixtures/bpmn/align-elements.bpmn');
|
||||
|
||||
beforeEach(bootstrapModeler(basicXML, { modules: testModules }));
|
||||
|
||||
|
||||
it('should provide button to open menu', inject(function(elementRegistry, contextPad) {
|
||||
|
||||
// given
|
||||
var elements = [
|
||||
elementRegistry.get('EndEvent_lane'),
|
||||
elementRegistry.get('Task_lane'),
|
||||
elementRegistry.get('SubProcess_lane')
|
||||
];
|
||||
|
||||
// when
|
||||
contextPad.open(elements);
|
||||
|
||||
// then
|
||||
expect(getEntry(elements, 'align-elements')).to.exist;
|
||||
}));
|
||||
|
||||
|
||||
it('should NOT provide button if no actions are available', inject(
|
||||
function(elementRegistry, contextPad, popupMenu) {
|
||||
|
||||
// given
|
||||
var elements = [
|
||||
elementRegistry.get('EndEvent_lane'),
|
||||
elementRegistry.get('Task_lane'),
|
||||
elementRegistry.get('SubProcess_lane')
|
||||
];
|
||||
popupMenu.registerProvider('align-elements', 0, {
|
||||
getPopupMenuEntries: function() {
|
||||
return function() {
|
||||
return {};
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// when
|
||||
contextPad.open(elements);
|
||||
|
||||
// then
|
||||
expect(getEntry(elements, 'align-elements')).not.to.exist;
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
it('should open popup menu when item is clicked', inject(
|
||||
function(elementRegistry, contextPad, popupMenu) {
|
||||
|
||||
// given
|
||||
var elements = [
|
||||
elementRegistry.get('EndEvent_lane'),
|
||||
elementRegistry.get('Task_lane'),
|
||||
elementRegistry.get('SubProcess_lane')
|
||||
];
|
||||
contextPad.open(elements);
|
||||
|
||||
// when
|
||||
var entry = getEntry(elements, 'align-elements');
|
||||
entry.click();
|
||||
|
||||
// then
|
||||
expect(popupMenu.isOpen()).to.be.true;
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
// helper //////////////////////////////////////////////////////////////////////
|
||||
function getEntry(target, actionName) {
|
||||
return padEntry(getBpmnJS().invoke(function(contextPad) {
|
||||
return contextPad.getPad(target).html;
|
||||
}), actionName);
|
||||
}
|
||||
|
||||
function padEntry(element, name) {
|
||||
return domQuery('[data-action="' + name + '"]', element);
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
import {
|
||||
bootstrapModeler,
|
||||
getBpmnJS,
|
||||
inject
|
||||
} from 'test/TestHelper';
|
||||
|
||||
import {
|
||||
query as domQuery
|
||||
} from 'min-dom';
|
||||
|
||||
import {
|
||||
forEach
|
||||
} from 'min-dash';
|
||||
|
||||
import alignElementsModule from 'lib/features/align-elements';
|
||||
import modelingModule from 'lib/features/modeling';
|
||||
import coreModule from 'lib/core';
|
||||
|
||||
|
||||
|
||||
describe('features/align-elements - popup menu', function() {
|
||||
|
||||
var testModules = [ alignElementsModule, modelingModule, coreModule ];
|
||||
|
||||
var basicXML = require('../../../fixtures/bpmn/align-elements.bpmn');
|
||||
|
||||
beforeEach(bootstrapModeler(basicXML, { modules: testModules }));
|
||||
|
||||
|
||||
it('should provide alignment buttons', inject(function(elementRegistry, popupMenu) {
|
||||
|
||||
// given
|
||||
var elements = [
|
||||
elementRegistry.get('EndEvent_lane'),
|
||||
elementRegistry.get('Task_lane'),
|
||||
elementRegistry.get('SubProcess_lane')
|
||||
];
|
||||
|
||||
// when
|
||||
popupMenu.open(elements, 'align-elements', {
|
||||
x: 0,
|
||||
y: 0
|
||||
});
|
||||
|
||||
// then
|
||||
forEach([
|
||||
'left',
|
||||
'center',
|
||||
'right',
|
||||
'top',
|
||||
'middle',
|
||||
'bottom'
|
||||
], function(alignment) {
|
||||
expect(getEntry('align-elements-' + alignment)).to.exist;
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
it('should close popup menu when button is clicked', inject(
|
||||
function(elementRegistry, popupMenu) {
|
||||
|
||||
// given
|
||||
var elements = [
|
||||
elementRegistry.get('EndEvent_lane'),
|
||||
elementRegistry.get('Task_lane'),
|
||||
elementRegistry.get('SubProcess_lane')
|
||||
];
|
||||
popupMenu.open(elements, 'align-elements', {
|
||||
x: 0,
|
||||
y: 0
|
||||
});
|
||||
var entry = getEntry('align-elements-center');
|
||||
|
||||
// when
|
||||
entry.click();
|
||||
|
||||
// then
|
||||
expect(popupMenu.isOpen()).to.be.false;
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
// helper //////////////////////////////////////////////////////////////////////
|
||||
function getEntry(actionName) {
|
||||
return padEntry(getBpmnJS().invoke(function(popupMenu) {
|
||||
return popupMenu._current.container;
|
||||
}), actionName);
|
||||
}
|
||||
|
||||
function padEntry(element, name) {
|
||||
return domQuery('[data-id="' + name + '"]', element);
|
||||
}
|
@ -3,7 +3,7 @@ import {
|
||||
inject
|
||||
} from 'test/TestHelper';
|
||||
|
||||
import alignElementsModule from 'diagram-js/lib/features/align-elements';
|
||||
import alignElementsModule from 'lib/features/align-elements';
|
||||
import modelingModule from 'lib/features/modeling';
|
||||
import coreModule from 'lib/core';
|
||||
|
||||
@ -31,10 +31,10 @@ describe('features/align-elements', function() {
|
||||
alignElements.trigger(elements, 'left');
|
||||
|
||||
// then
|
||||
expect(taskBoundEvt.x).to.equal(136);
|
||||
expect(task.x).to.equal(136);
|
||||
expect(subProcess.x).to.equal(136);
|
||||
expect(endEvent.x).to.equal(136);
|
||||
expect(taskBoundEvt.x).to.equal(276);
|
||||
expect(task.x).to.equal(276);
|
||||
expect(subProcess.x).to.equal(276);
|
||||
expect(endEvent.x).to.equal(276);
|
||||
}));
|
||||
|
||||
|
||||
@ -51,10 +51,10 @@ describe('features/align-elements', function() {
|
||||
alignElements.trigger(elements, 'right');
|
||||
|
||||
// then
|
||||
expect(task.x).to.equal(720);
|
||||
expect(taskHello.x).to.equal(720);
|
||||
expect(subProcess.x).to.equal(470);
|
||||
expect(endEvent.x).to.equal(784);
|
||||
expect(task.x).to.equal(860);
|
||||
expect(taskHello.x).to.equal(860);
|
||||
expect(subProcess.x).to.equal(610);
|
||||
expect(endEvent.x).to.equal(924);
|
||||
}));
|
||||
|
||||
|
||||
@ -71,10 +71,10 @@ describe('features/align-elements', function() {
|
||||
alignElements.trigger(elements, 'center');
|
||||
|
||||
// then
|
||||
expect(task.x).to.equal(428);
|
||||
expect(taskHello.x).to.equal(428);
|
||||
expect(subProcess.x).to.equal(303);
|
||||
expect(endEvent.x).to.equal(460);
|
||||
expect(task.x).to.equal(568);
|
||||
expect(taskHello.x).to.equal(568);
|
||||
expect(subProcess.x).to.equal(443);
|
||||
expect(endEvent.x).to.equal(600);
|
||||
}));
|
||||
|
||||
|
||||
@ -90,9 +90,9 @@ describe('features/align-elements', function() {
|
||||
alignElements.trigger(elements, 'top');
|
||||
|
||||
// then
|
||||
expect(task.y).to.equal(375);
|
||||
expect(subProcess.y).to.equal(375);
|
||||
expect(endEvent.y).to.equal(375);
|
||||
expect(task.y).to.equal(445);
|
||||
expect(subProcess.y).to.equal(445);
|
||||
expect(endEvent.y).to.equal(445);
|
||||
}));
|
||||
|
||||
|
||||
@ -108,9 +108,9 @@ describe('features/align-elements', function() {
|
||||
alignElements.trigger(elements, 'bottom');
|
||||
|
||||
// then
|
||||
expect(task.y).to.equal(761);
|
||||
expect(subProcess.y).to.equal(641);
|
||||
expect(endEvent.y).to.equal(805);
|
||||
expect(task.y).to.equal(831);
|
||||
expect(subProcess.y).to.equal(711);
|
||||
expect(endEvent.y).to.equal(875);
|
||||
}));
|
||||
|
||||
|
||||
@ -126,11 +126,59 @@ describe('features/align-elements', function() {
|
||||
alignElements.trigger(elements, 'middle');
|
||||
|
||||
// then
|
||||
expect(task.y).to.equal(568);
|
||||
expect(subProcess.y).to.equal(508);
|
||||
expect(endEvent.y).to.equal(590);
|
||||
expect(task.y).to.equal(638);
|
||||
expect(subProcess.y).to.equal(578);
|
||||
expect(endEvent.y).to.equal(660);
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('rules', function() {
|
||||
|
||||
it('should not align boundary event', inject(function(alignElements, elementRegistry) {
|
||||
|
||||
// given
|
||||
var boundaryEvent = elementRegistry.get('BoundaryEvent_1'),
|
||||
host = elementRegistry.get('Task_boundary_evt');
|
||||
var elements = [
|
||||
host,
|
||||
elementRegistry.get('Task_hello'),
|
||||
boundaryEvent
|
||||
];
|
||||
var initialRelativePosition = {
|
||||
x: boundaryEvent.x - host.x,
|
||||
y: boundaryEvent.y - host.y
|
||||
};
|
||||
|
||||
// when
|
||||
alignElements.trigger(elements, 'middle');
|
||||
|
||||
// then
|
||||
expect(boundaryEvent.x).to.equal(initialRelativePosition.x + host.x);
|
||||
expect(boundaryEvent.y).to.equal(initialRelativePosition.y + host.y);
|
||||
}));
|
||||
|
||||
|
||||
it('should not align container children', inject(
|
||||
function(alignElements, elementRegistry) {
|
||||
|
||||
// given
|
||||
var elements = elementRegistry.getAll('SubProcessChild').slice(1),
|
||||
child = elementRegistry.get('Task_hello');
|
||||
var initialRelativePosition = {
|
||||
x: child.x - child.parent.x,
|
||||
y: child.y - child.parent.y
|
||||
};
|
||||
|
||||
// when
|
||||
alignElements.trigger(elements, 'middle');
|
||||
|
||||
// then
|
||||
expect(child.x).to.equal(initialRelativePosition.x + child.parent.x);
|
||||
expect(child.y).to.equal(initialRelativePosition.y + child.parent.y);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { forEach } from 'min-dash';
|
||||
|
||||
import {
|
||||
bootstrapModeler,
|
||||
inject
|
||||
@ -7,6 +9,8 @@ import bpmnDistributeElements from 'lib/features/distribute-elements';
|
||||
import modelingModule from 'lib/features/modeling';
|
||||
import coreModule from 'lib/core';
|
||||
|
||||
import { is } from 'lib/util/ModelUtil';
|
||||
|
||||
function last(arr) {
|
||||
return arr[arr.length - 1];
|
||||
}
|
||||
@ -27,7 +31,7 @@ describe('features/distribute-elements', function() {
|
||||
|
||||
beforeEach(inject(function(elementRegistry, canvas) {
|
||||
elements = elementRegistry.filter(function(element) {
|
||||
return element.parent;
|
||||
return element.parent && !is(element, 'bpmn:Participant');
|
||||
});
|
||||
}));
|
||||
|
||||
@ -79,34 +83,96 @@ describe('features/distribute-elements', function() {
|
||||
|
||||
describe('filtering elements', function() {
|
||||
|
||||
var xml = require('../../../fixtures/bpmn/distribute-elements-filtering.bpmn');
|
||||
describe('process', function() {
|
||||
|
||||
beforeEach(bootstrapModeler(xml, { modules: testModules }));
|
||||
var xml = require('../../../fixtures/bpmn/distribute-elements-filtering.bpmn'),
|
||||
elements;
|
||||
|
||||
var elements;
|
||||
|
||||
beforeEach(inject(function(elementRegistry, canvas) {
|
||||
elements = elementRegistry.filter(function(element) {
|
||||
return element.parent;
|
||||
});
|
||||
}));
|
||||
beforeEach(bootstrapModeler(xml, { modules: testModules }));
|
||||
|
||||
|
||||
it('should not distribute boundary events', inject(function(distributeElements, elementRegistry) {
|
||||
beforeEach(inject(function(elementRegistry) {
|
||||
elements = elementRegistry.filter(function(element) {
|
||||
return element.parent;
|
||||
});
|
||||
}));
|
||||
|
||||
// given
|
||||
var boundaryEvent = elementRegistry.get('BoundaryEvent_1');
|
||||
|
||||
// when
|
||||
var rangeGroups = distributeElements.trigger(elements, 'horizontal');
|
||||
it('should not distribute boundary events', inject(function(distributeElements, elementRegistry) {
|
||||
|
||||
// then
|
||||
expect(rangeGroups).to.have.length(3);
|
||||
// given
|
||||
var boundaryEvent = elementRegistry.get('BoundaryEvent_1');
|
||||
|
||||
expect(rangeGroups[1].elements).not.to.include(boundaryEvent);
|
||||
// when
|
||||
var rangeGroups = distributeElements.trigger(elements, 'horizontal');
|
||||
|
||||
}));
|
||||
// then
|
||||
expect(rangeGroups).to.have.length(3);
|
||||
|
||||
forEach(rangeGroups, function(rangeGroup) {
|
||||
expect(rangeGroup.elements).not.to.include(boundaryEvent);
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
it('should not distribute sub process children', inject(
|
||||
function(distributeElements, elementRegistry) {
|
||||
|
||||
// given
|
||||
var childElement = elementRegistry.get('SubProcessChild');
|
||||
|
||||
// when
|
||||
var rangeGroups = distributeElements.trigger(elements, 'horizontal');
|
||||
|
||||
// then
|
||||
expect(rangeGroups).to.have.length(3);
|
||||
|
||||
forEach(rangeGroups, function(rangeGroup) {
|
||||
expect(rangeGroup.elements).not.to.include(childElement);
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
describe('collaboration', function() {
|
||||
|
||||
var xml = require('../../../fixtures/bpmn/distribute-elements-filtering.collaboration.bpmn'),
|
||||
elements;
|
||||
|
||||
beforeEach(bootstrapModeler(xml, { modules: testModules }));
|
||||
|
||||
|
||||
beforeEach(inject(function(elementRegistry) {
|
||||
elements = elementRegistry.filter(function(element) {
|
||||
return element.parent;
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
it('should distribute participants', inject(function(distributeElements, elementRegistry) {
|
||||
|
||||
// given
|
||||
var participants = elementRegistry.filter(function(element) {
|
||||
return is(element, 'bpmn:Participant');
|
||||
});
|
||||
|
||||
// when
|
||||
var rangeGroups = distributeElements.trigger(elements, 'vertical');
|
||||
|
||||
// then
|
||||
expect(rangeGroups).to.have.length(3);
|
||||
|
||||
var distributedElements = [];
|
||||
|
||||
forEach(rangeGroups, function(rangeGroup) {
|
||||
distributedElements = distributedElements.concat(rangeGroup.elements);
|
||||
});
|
||||
|
||||
expect(distributedElements).to.have.length(3);
|
||||
expect(distributedElements).to.have.members(participants);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -0,0 +1,95 @@
|
||||
import {
|
||||
bootstrapModeler,
|
||||
getBpmnJS,
|
||||
inject
|
||||
} from 'test/TestHelper';
|
||||
|
||||
import {
|
||||
query as domQuery
|
||||
} from 'min-dom';
|
||||
|
||||
import {
|
||||
forEach
|
||||
} from 'min-dash';
|
||||
|
||||
import distributeElementsModule from 'lib/features/distribute-elements';
|
||||
import modelingModule from 'lib/features/modeling';
|
||||
import coreModule from 'lib/core';
|
||||
|
||||
|
||||
describe('features/distribute-elements - popup menu', function() {
|
||||
|
||||
var testModules = [ distributeElementsModule, modelingModule, coreModule ];
|
||||
|
||||
var basicXML = require('../../../fixtures/bpmn/distribute-elements.bpmn');
|
||||
|
||||
beforeEach(bootstrapModeler(basicXML, { modules: testModules }));
|
||||
|
||||
|
||||
it('should provide distribution buttons', inject(function(elementRegistry, popupMenu) {
|
||||
|
||||
// given
|
||||
var elements = [
|
||||
elementRegistry.get('ExclusiveGateway_10cec0a'),
|
||||
elementRegistry.get('Task_08pns8h'),
|
||||
elementRegistry.get('Task_0511uak'),
|
||||
elementRegistry.get('EndEvent_0c9irey')
|
||||
];
|
||||
|
||||
// when
|
||||
popupMenu.open(elements, 'align-elements', {
|
||||
x: 0,
|
||||
y: 0
|
||||
});
|
||||
|
||||
// then
|
||||
forEach([
|
||||
'horizontal',
|
||||
'vertical'
|
||||
], function(distribution) {
|
||||
expect(getEntry('distribute-elements-' + distribution)).to.exist;
|
||||
});
|
||||
}));
|
||||
|
||||
forEach([
|
||||
'horizontal',
|
||||
'vertical'
|
||||
], function(distribution) {
|
||||
it('should close popup menu when button is clicked', inject(
|
||||
function(elementRegistry, popupMenu) {
|
||||
|
||||
// given
|
||||
var elements = [
|
||||
elementRegistry.get('ExclusiveGateway_10cec0a'),
|
||||
elementRegistry.get('Task_08pns8h'),
|
||||
elementRegistry.get('Task_0511uak'),
|
||||
elementRegistry.get('EndEvent_0c9irey')
|
||||
];
|
||||
popupMenu.open(elements, 'align-elements', {
|
||||
x: 0,
|
||||
y: 0
|
||||
});
|
||||
var entry = getEntry('distribute-elements-' + distribution);
|
||||
|
||||
// when
|
||||
entry.click();
|
||||
|
||||
// then
|
||||
expect(popupMenu.isOpen()).to.be.false;
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
// helper //////////////////////////////////////////////////////////////////////
|
||||
function getEntry(actionName) {
|
||||
return padEntry(getBpmnJS().invoke(function(popupMenu) {
|
||||
return popupMenu._current.container;
|
||||
}), actionName);
|
||||
}
|
||||
|
||||
function padEntry(element, name) {
|
||||
return domQuery('[data-id="' + name + '"]', element);
|
||||
}
|