parent
fbf82e83e5
commit
966e3aaa34
|
@ -4,6 +4,7 @@ module.exports = {
|
||||||
require('../label-editing'),
|
require('../label-editing'),
|
||||||
require('./rules'),
|
require('./rules'),
|
||||||
require('./behavior'),
|
require('./behavior'),
|
||||||
|
require('../ordering'),
|
||||||
require('../replace'),
|
require('../replace'),
|
||||||
require('diagram-js/lib/command'),
|
require('diagram-js/lib/command'),
|
||||||
require('diagram-js/lib/features/tooltips'),
|
require('diagram-js/lib/features/tooltips'),
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var inherits = require('inherits');
|
||||||
|
|
||||||
|
var OrderingProvider = require('diagram-js/lib/features/ordering/OrderingProvider');
|
||||||
|
|
||||||
|
|
||||||
|
var findIndex = require('lodash/array/findIndex');
|
||||||
|
|
||||||
|
var find = require('lodash/collection/find');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a simple ordering provider that makes sure:
|
||||||
|
*
|
||||||
|
* (1) elements are ordered by a {level} property
|
||||||
|
* (2) elements with {alwaysOnTop} are always added to the root
|
||||||
|
*/
|
||||||
|
function BpmnOrderingProvider(eventBus) {
|
||||||
|
|
||||||
|
OrderingProvider.call(this, eventBus);
|
||||||
|
|
||||||
|
var orders = [
|
||||||
|
{ type: 'label', order: { level: 7 } },
|
||||||
|
{ type: 'bpmn:SequenceFlow', order: { level: 5 } },
|
||||||
|
{ type: 'bpmn:MessageFlow', order: { level: 6, top: true } },
|
||||||
|
{ type: 'bpmn:BoundaryEvent', order: { level: 4 } },
|
||||||
|
{ type: 'bpmn:Participant', order: { level: -2 } },
|
||||||
|
{ type: 'bpmn:Lane', order: { level: -1 } }
|
||||||
|
];
|
||||||
|
|
||||||
|
function computeOrder(element) {
|
||||||
|
var entry = find(orders, function(o) {
|
||||||
|
return element.type === o.type;
|
||||||
|
});
|
||||||
|
|
||||||
|
return entry && entry.order || { level: 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOrder(element) {
|
||||||
|
|
||||||
|
var order = element.order;
|
||||||
|
|
||||||
|
if (!order) {
|
||||||
|
element.order = order = computeOrder(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getOrdering = function(element, newParent) {
|
||||||
|
|
||||||
|
var elementOrder = getOrder(element);
|
||||||
|
|
||||||
|
|
||||||
|
if (elementOrder.top) {
|
||||||
|
while (newParent.parent) {
|
||||||
|
newParent = newParent.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var currentIndex = newParent.children.indexOf(element);
|
||||||
|
|
||||||
|
var insertIndex = findIndex(newParent.children, function(child) {
|
||||||
|
return elementOrder.level < getOrder(child).level;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// if the element is already in the child list at
|
||||||
|
// a smaller index, we need to adjust the inser index.
|
||||||
|
// this takes into account that the element is being removed
|
||||||
|
// before being re-inserted
|
||||||
|
if (insertIndex !== -1) {
|
||||||
|
if (currentIndex !== -1 && currentIndex < insertIndex) {
|
||||||
|
insertIndex -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
index: insertIndex,
|
||||||
|
parent: newParent
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
BpmnOrderingProvider.$inject = [ 'eventBus' ];
|
||||||
|
|
||||||
|
inherits(BpmnOrderingProvider, OrderingProvider);
|
||||||
|
|
||||||
|
module.exports = BpmnOrderingProvider;
|
|
@ -0,0 +1,4 @@
|
||||||
|
module.exports = {
|
||||||
|
__init__: [ 'bpmnOrderingProvider' ],
|
||||||
|
bpmnOrderingProvider: [ 'type', require('./BpmnOrderingProvider') ]
|
||||||
|
};
|
|
@ -0,0 +1,52 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Helper = require('./Helper');
|
||||||
|
|
||||||
|
/* global bootstrapModeler, inject */
|
||||||
|
|
||||||
|
var move = Helper.move,
|
||||||
|
expectZOrder = Helper.expectZOrder;
|
||||||
|
|
||||||
|
var modelingModule = require('../../../../lib/features/modeling'),
|
||||||
|
coreModule = require('../../../../lib/core');
|
||||||
|
|
||||||
|
|
||||||
|
describe('features/modeling - ordering', function() {
|
||||||
|
|
||||||
|
var diagramXML = require('./ordering.bpmn');
|
||||||
|
|
||||||
|
var testModules = [ coreModule, modelingModule ];
|
||||||
|
|
||||||
|
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
|
||||||
|
|
||||||
|
|
||||||
|
it('should keep Task behind BoundaryEvent', inject(function() {
|
||||||
|
|
||||||
|
// when
|
||||||
|
move('Task_With_Boundary');
|
||||||
|
|
||||||
|
// then
|
||||||
|
expectZOrder('Task_With_Boundary', 'BoundaryEvent');
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should keep Task behind BoundaryEvent, moving both', inject(function() {
|
||||||
|
|
||||||
|
// when
|
||||||
|
move([ 'BoundaryEvent', 'Task_With_Boundary' ], 'Participant_StartEvent');
|
||||||
|
|
||||||
|
// then
|
||||||
|
expectZOrder('Task_With_Boundary', 'BoundaryEvent');
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should keep Participant behind MessageFlow', inject(function() {
|
||||||
|
|
||||||
|
// when
|
||||||
|
move('Participant', 'Collaboration');
|
||||||
|
|
||||||
|
// then
|
||||||
|
expectZOrder('Participant_StartEvent', 'Participant', 'MessageFlow');
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,135 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var TestHelper = require('../../../TestHelper');
|
||||||
|
|
||||||
|
var map = require('lodash/collection/map');
|
||||||
|
|
||||||
|
function move(elementIds, delta, targetId, isAttach) {
|
||||||
|
|
||||||
|
if (typeof elementIds === 'string') {
|
||||||
|
elementIds = [ elementIds ];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof delta !== 'object') {
|
||||||
|
isAttach = targetId;
|
||||||
|
targetId = delta;
|
||||||
|
delta = { x: 0, y: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof targetId !== 'string') {
|
||||||
|
isAttach = targetId;
|
||||||
|
targetId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TestHelper.getBpmnJS().invoke(function(elementRegistry, modeling) {
|
||||||
|
|
||||||
|
function getElement(id) {
|
||||||
|
|
||||||
|
var element = elementRegistry.get(id);
|
||||||
|
expect(element).to.exist;
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
var elements = map(elementIds, getElement),
|
||||||
|
target = targetId && getElement(targetId);
|
||||||
|
|
||||||
|
return modeling.moveElements(elements, delta, target, isAttach);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports.move = move;
|
||||||
|
|
||||||
|
|
||||||
|
function getAncestors(element) {
|
||||||
|
var ancestors = [];
|
||||||
|
|
||||||
|
while (element) {
|
||||||
|
ancestors.push(element);
|
||||||
|
|
||||||
|
element = element.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ancestors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function compareZOrder(aId, bId) {
|
||||||
|
|
||||||
|
var elementA,
|
||||||
|
elementB;
|
||||||
|
|
||||||
|
TestHelper.getBpmnJS().invoke(function(elementRegistry) {
|
||||||
|
|
||||||
|
function getElement(id) {
|
||||||
|
|
||||||
|
var element = elementRegistry.get(id);
|
||||||
|
expect(element).to.exist;
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
elementA = getElement(aId);
|
||||||
|
elementB = getElement(bId);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var aAncestors = getAncestors(elementA),
|
||||||
|
bAncestors = getAncestors(elementB);
|
||||||
|
|
||||||
|
var sharedRoot = aAncestors.reduce(function(result, aAncestor, aParentIndex) {
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bParentIndex = bAncestors.indexOf(aAncestor);
|
||||||
|
|
||||||
|
if (bParentIndex !== -1) {
|
||||||
|
return {
|
||||||
|
a: aAncestors[aParentIndex - 1],
|
||||||
|
b: bAncestors[bParentIndex - 1],
|
||||||
|
parent: aAncestor
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// b contained in a
|
||||||
|
if (!sharedRoot.a) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// a contained in b
|
||||||
|
if (!sharedRoot.b) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var aIndex = sharedRoot.parent.indexOf(sharedRoot.a),
|
||||||
|
bIndex = sharedRoot.parent.indexOf(sharedRoot.b);
|
||||||
|
|
||||||
|
return Math.sign(aIndex - bIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var forEach = require('lodash/collection/forEach');
|
||||||
|
|
||||||
|
function expectZOrder() {
|
||||||
|
|
||||||
|
var elements = Array.prototype.slice.call(arguments);
|
||||||
|
|
||||||
|
var next;
|
||||||
|
|
||||||
|
forEach(elements, function(e, idx) {
|
||||||
|
|
||||||
|
next = elements[idx];
|
||||||
|
|
||||||
|
if (next) {
|
||||||
|
expect(compareZOrder(e, next)).to.eql(-1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.expectZOrder = expectZOrder;
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<bpmn2:definitions xmlns:bpmn2="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="_Sp0bEEZWEeW8AbPIK3dKxg" targetNamespace="http://activiti.org/bpmn" exporter="camunda modeler" exporterVersion="2.6.0" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
|
||||||
|
<bpmn2:collaboration id="Collaboration">
|
||||||
|
<bpmn2:participant id="Participant" name="Participant" processRef="Process_Tasks" />
|
||||||
|
<bpmn2:participant id="Participant_StartEvent" name="Participant_StartEvent" processRef="Process_StartEvent" />
|
||||||
|
<bpmn2:messageFlow id="MessageFlow" name="" sourceRef="Task_With_Boundary" targetRef="Participant_StartEvent" />
|
||||||
|
</bpmn2:collaboration>
|
||||||
|
<bpmn2:process id="Process_Tasks" isExecutable="false">
|
||||||
|
<bpmn2:task id="Task_With_Boundary" />
|
||||||
|
<bpmn2:boundaryEvent id="BoundaryEvent" name="" attachedToRef="Task_With_Boundary">
|
||||||
|
<bpmn2:outgoing>SequenceFlow</bpmn2:outgoing>
|
||||||
|
</bpmn2:boundaryEvent>
|
||||||
|
<bpmn2:task id="Task">
|
||||||
|
<bpmn2:incoming>SequenceFlow</bpmn2:incoming>
|
||||||
|
</bpmn2:task>
|
||||||
|
<bpmn2:sequenceFlow id="SequenceFlow" name="" sourceRef="BoundaryEvent" targetRef="Task" />
|
||||||
|
</bpmn2:process>
|
||||||
|
<bpmn2:process id="Process_StartEvent" isExecutable="false">
|
||||||
|
<bpmn2:startEvent id="StartEvent" name="StartEvent" />
|
||||||
|
</bpmn2:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration">
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_Participant_2" bpmnElement="Participant" isHorizontal="true">
|
||||||
|
<dc:Bounds x="192" y="108" width="457" height="193" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_Participant_3" bpmnElement="Participant_StartEvent" isHorizontal="true">
|
||||||
|
<dc:Bounds x="192" y="444" width="457" height="158" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_Task_2" bpmnElement="Task_With_Boundary">
|
||||||
|
<dc:Bounds x="300" y="144" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_BoundaryEvent_2" bpmnElement="BoundaryEvent">
|
||||||
|
<dc:Bounds x="346" y="206" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_Task_3" bpmnElement="Task">
|
||||||
|
<dc:Bounds x="480" y="144" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_1" bpmnElement="SequenceFlow" sourceElement="_BPMNShape_BoundaryEvent_2" targetElement="_BPMNShape_Task_3">
|
||||||
|
<di:waypoint xsi:type="dc:Point" x="364" y="242" />
|
||||||
|
<di:waypoint xsi:type="dc:Point" x="364" y="272" />
|
||||||
|
<di:waypoint xsi:type="dc:Point" x="530" y="272" />
|
||||||
|
<di:waypoint xsi:type="dc:Point" x="530" y="224" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="471" y="272" width="6" height="6" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="BPMNEdge_MessageFlow_1" bpmnElement="MessageFlow" sourceElement="_BPMNShape_Task_2" targetElement="_BPMNShape_Participant_3">
|
||||||
|
<di:waypoint xsi:type="dc:Point" x="326" y="224" />
|
||||||
|
<di:waypoint xsi:type="dc:Point" x="326" y="444" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="370" y="334" width="6" height="6" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent">
|
||||||
|
<dc:Bounds x="271" y="495" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="244" y="531" width="90" height="20" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn2:definitions>
|
Loading…
Reference in New Issue