parent
fbf82e83e5
commit
966e3aaa34
|
@ -4,6 +4,7 @@ module.exports = {
|
|||
require('../label-editing'),
|
||||
require('./rules'),
|
||||
require('./behavior'),
|
||||
require('../ordering'),
|
||||
require('../replace'),
|
||||
require('diagram-js/lib/command'),
|
||||
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