Merge master to develop

This commit is contained in:
bpmn-io-bot
2023-04-24 08:30:59 +00:00
13 changed files with 308 additions and 201 deletions

View File

@ -15,7 +15,7 @@ import {
import {
getLabel
} from '../features/label-editing/LabelUtil';
} from '../util/LabelUtil';
import { is } from '../util/ModelUtil';

View File

@ -4,7 +4,7 @@ import {
import {
getLabel
} from './LabelUtil';
} from '../../util/LabelUtil';
import {
is

View File

@ -1,82 +1,4 @@
import { is } from '../../util/ModelUtil';
/**
* @typedef { import('../../model').DiagramElement } DiagramElement
*/
function getLabelAttr(semantic) {
if (
is(semantic, 'bpmn:FlowElement') ||
is(semantic, 'bpmn:Participant') ||
is(semantic, 'bpmn:Lane') ||
is(semantic, 'bpmn:SequenceFlow') ||
is(semantic, 'bpmn:MessageFlow') ||
is(semantic, 'bpmn:DataInput') ||
is(semantic, 'bpmn:DataOutput')
) {
return 'name';
}
if (is(semantic, 'bpmn:TextAnnotation')) {
return 'text';
}
if (is(semantic, 'bpmn:Group')) {
return 'categoryValueRef';
}
}
function getCategoryValue(semantic) {
var categoryValueRef = semantic['categoryValueRef'];
if (!categoryValueRef) {
return '';
}
return categoryValueRef.value || '';
}
/**
* @param {DiagramElement} element
*
* @return {string} label
*/
export function getLabel(element) {
var semantic = element.businessObject,
attr = getLabelAttr(semantic);
if (attr) {
if (attr === 'categoryValueRef') {
return getCategoryValue(semantic);
}
return semantic[attr] || '';
}
}
/**
* @param {DiagramElement} element
* @param {string} text
*
* @return {DiagramElement} element
*/
export function setLabel(element, text) {
var semantic = element.businessObject,
attr = getLabelAttr(semantic);
if (attr) {
if (attr === 'categoryValueRef') {
semantic['categoryValueRef'].value = text;
} else {
semantic[attr] = text;
}
}
return element;
}
export {
getLabel,
setLabel
} from '../../util/LabelUtil';

View File

@ -1,7 +1,7 @@
import {
setLabel,
getLabel
} from '../LabelUtil';
} from '../../../util/LabelUtil';
import {
getExternalLabelMid,
@ -11,7 +11,6 @@ import {
} from '../../../util/LabelUtil';
import {
getDi,
is
} from '../../../util/ModelUtil';
@ -37,29 +36,6 @@ var NULL_DIMENSIONS = {
*/
export default function UpdateLabelHandler(modeling, textRenderer, bpmnFactory) {
/**
* Creates an empty `diLabel` attribute for embedded labels.
*
* @param {Element} element
* @param {string} text
*/
function ensureInternalLabelDi(element, text) {
if (isLabelExternal(element)) {
return;
}
var di = getDi(element);
if (text && !di.label) {
di.label = bpmnFactory.create('bpmndi:BPMNLabel');
}
if (!text && di.label) {
delete di.label;
}
}
/**
* Set the label and return the changed elements.
*
@ -77,8 +53,6 @@ export default function UpdateLabelHandler(modeling, textRenderer, bpmnFactory)
setLabel(label, text, labelTarget !== label);
ensureInternalLabelDi(element, text);
return [ label, labelTarget ];
}
@ -140,7 +114,7 @@ export default function UpdateLabelHandler(modeling, textRenderer, bpmnFactory)
return;
}
var text = getLabel(label);
var text = getLabel(element);
// resize element based on label _or_ pre-defined bounds
if (typeof newBounds === 'undefined') {

View File

@ -18,7 +18,11 @@ import {
import { isAny } from './util/ModelingUtil';
import { isLabel } from '../../util/LabelUtil';
import {
getLabel,
isLabel,
isLabelExternal
} from '../../util/LabelUtil';
import { delta } from 'diagram-js/lib/util/PositionUtil';
@ -287,6 +291,28 @@ export default function BpmnUpdater(
this.executed([ 'element.updateAttachment' ], ifBpmn(updateAttachment));
this.reverted([ 'element.updateAttachment' ], ifBpmn(updateAttachment));
// update BPMNLabel
this.executed('element.updateLabel', ifBpmn(updateBPMNLabel));
this.reverted('element.updateLabel', ifBpmn(updateBPMNLabel));
function updateBPMNLabel(event) {
const { element } = event.context,
label = getLabel(element);
const di = getDi(element),
diLabel = di && di.get('label');
if (isLabelExternal(element)) {
return;
}
if (label && !diLabel) {
di.set('label', bpmnFactory.create('bpmndi:BPMNLabel'));
} else if (!label && diLabel) {
di.set('label', undefined);
}
}
}
inherits(BpmnUpdater, CommandInterceptor);
@ -787,7 +813,7 @@ function ifBpmn(fn) {
return function(event) {
var context = event.context,
element = context.shape || context.connection;
element = context.shape || context.connection || context.element;
if (is(element, 'bpmn:BaseElement')) {
fn(event);

View File

@ -6,21 +6,16 @@ import inherits from 'inherits-browser';
import {
is,
getBusinessObject,
getDi
getBusinessObject
} from '../../../util/ModelUtil';
import {
isLabelExternal,
getExternalLabelMid,
getLabel,
hasExternalLabel,
isLabel
} from '../../../util/LabelUtil';
import {
getLabel
} from '../../label-editing/LabelUtil';
import {
getLabelAdjustment
} from './util/LabelLayoutUtil';
@ -49,11 +44,6 @@ import {
perpendicularFoot
} from './util/GeometricUtil';
var DEFAULT_LABEL_DIMENSIONS = {
width: 90,
height: 20
};
var NAME_PROPERTY = 'name';
var TEXT_PROPERTY = 'text';
@ -86,7 +76,16 @@ export default function LabelBehavior(
CommandInterceptor.call(this, eventBus);
// update label if name property was updated
this.postExecute('element.updateProperties', function(e) {
this.postExecute('element.updateProperties', onPropertyUpdate);
this.postExecute('element.updateModdleProperties', e => {
const elementBo = getBusinessObject(e.context.element);
if (elementBo === e.context.moddleElement) {
onPropertyUpdate(e);
}
});
function onPropertyUpdate(e) {
var context = e.context,
element = context.element,
properties = context.properties;
@ -110,7 +109,7 @@ export default function LabelBehavior(
modeling.updateLabel(element, properties.text, newBounds);
}
});
}
// create label shape after shape/connection was created
this.postExecute([ 'shape.create', 'connection.create' ], function(e) {
@ -121,8 +120,7 @@ export default function LabelBehavior(
return;
}
var element = context.shape || context.connection,
businessObject = element.businessObject;
var element = context.shape || context.connection;
if (isLabel(element) || !isLabelExternal(element)) {
return;
@ -133,20 +131,7 @@ export default function LabelBehavior(
return;
}
var labelCenter = getExternalLabelMid(element);
// we don't care about x and y
var labelDimensions = textRenderer.getExternalLabelBounds(
DEFAULT_LABEL_DIMENSIONS,
getLabel(element)
);
modeling.createLabel(element, labelCenter, {
id: businessObject.id + '_label',
businessObject: businessObject,
width: labelDimensions.width,
height: labelDimensions.height
});
modeling.updateLabel(element, getLabel(element));
});
// update label after label shape was deleted
@ -161,42 +146,6 @@ export default function LabelBehavior(
}
});
// update di information on label creation
this.postExecute([ 'label.create' ], function(event) {
var context = event.context,
element = context.shape,
labelTarget = context.labelTarget,
di;
// we want to trigger on real labels only
if (!labelTarget) {
return;
}
// we want to trigger on BPMN elements only
if (!is(labelTarget, 'bpmn:BaseElement')) {
return;
}
di = getDi(labelTarget);
if (!di.label) {
di.label = bpmnFactory.create('bpmndi:BPMNLabel', {
bounds: bpmnFactory.create('dc:Bounds')
});
element.di = di;
}
assign(di.label.bounds, {
x: element.x,
y: element.y,
width: element.width,
height: element.height
});
});
function getVisibleLabelAdjustment(event) {
var context = event.context,

View File

@ -6,7 +6,7 @@ import {
import {
getLabel
} from '../label-editing/LabelUtil';
} from '../../util/LabelUtil';
/**
* @typedef {import('diagram-js/lib/core/Canvas').default} Canvas

View File

@ -6,7 +6,8 @@ import { is } from '../util/ModelUtil';
import {
isLabelExternal,
getExternalLabelBounds
getExternalLabelBounds,
getLabel
} from '../util/LabelUtil';
import {
@ -17,10 +18,6 @@ import {
isExpanded
} from '../util/DiUtil';
import {
getLabel
} from '../features/label-editing/LabelUtil';
import {
elementToString
} from './Util';

View File

@ -178,3 +178,85 @@ export function getExternalLabelBounds(di, element) {
export function isLabel(element) {
return element && !!element.labelTarget;
}
/**
* @typedef { import('../model').DiagramElement } DiagramElement
*/
function getLabelAttr(semantic) {
if (
is(semantic, 'bpmn:FlowElement') ||
is(semantic, 'bpmn:Participant') ||
is(semantic, 'bpmn:Lane') ||
is(semantic, 'bpmn:SequenceFlow') ||
is(semantic, 'bpmn:MessageFlow') ||
is(semantic, 'bpmn:DataInput') ||
is(semantic, 'bpmn:DataOutput')
) {
return 'name';
}
if (is(semantic, 'bpmn:TextAnnotation')) {
return 'text';
}
if (is(semantic, 'bpmn:Group')) {
return 'categoryValueRef';
}
}
function getCategoryValue(semantic) {
var categoryValueRef = semantic['categoryValueRef'];
if (!categoryValueRef) {
return '';
}
return categoryValueRef.value || '';
}
/**
* @param {DiagramElement} element
*
* @return {string} label
*/
export function getLabel(element) {
var semantic = element.businessObject,
attr = getLabelAttr(semantic);
if (attr) {
if (attr === 'categoryValueRef') {
return getCategoryValue(semantic);
}
return semantic[attr] || '';
}
}
/**
* @param {DiagramElement} element
* @param {string} text
*
* @return {DiagramElement} element
*/
export function setLabel(element, text) {
var semantic = element.businessObject,
attr = getLabelAttr(semantic);
if (attr) {
if (attr === 'categoryValueRef') {
semantic['categoryValueRef'].value = text;
} else {
semantic[attr] = text;
}
}
return element;
}

View File

@ -11,7 +11,7 @@ import autoPlaceModule from 'lib/features/auto-place';
import {
getLabel
} from 'lib/features/label-editing/LabelUtil';
} from 'lib/util/LabelUtil';
import {
createCanvasEvent as canvasEvent

View File

@ -282,4 +282,40 @@ describe('features - bpmn-updater', function() {
});
describe('BPMNLabel', function() {
describe('embedded', function() {
it('should set BPMNLabel on task', inject(function(modeling, elementRegistry) {
// given
var task = elementRegistry.get('Task_1');
// when
modeling.updateLabel(task, 'foo');
// then
expect(task.businessObject.name).to.equal('foo');
expect(getDi(task).label).to.exist;
}));
it('should unset BPMNLabel on task', inject(function(modeling, elementRegistry) {
// given
var task = elementRegistry.get('Task_3');
// when
modeling.updateLabel(task, '');
// then
expect(task.businessObject.name).to.equal('');
expect(getDi(task)).not.to.have.property('label');
}));
});
});
});

View File

@ -14,6 +14,12 @@
<bpmn:incoming>SequenceFlow_1</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="SequenceFlow_1" name="SequenceFlow_1" sourceRef="StartEvent_2" targetRef="EndEvent_1" />
<bpmn:intermediateCatchEvent id="IntermediateCatchEvent_1">
<bpmn:messageEventDefinition id="MessageEventDefinition_1kowj0h" messageRef="Message_1" />
</bpmn:intermediateCatchEvent>
<bpmn:intermediateCatchEvent id="IntermediateCatchEvent_2" name="name">
<bpmn:messageEventDefinition id="MessageEventDefinition_1kowj0" messageRef="Message_2" />
</bpmn:intermediateCatchEvent>
<bpmn:textAnnotation id="TextAnnotation_1">
<bpmn:text>foo</bpmn:text>
</bpmn:textAnnotation>
@ -24,6 +30,8 @@
<bpmn:group id="Group_4" categoryValueRef="CategoryValue_1" />
<bpmn:group id="Group_5" categoryValueRef="CategoryValue_1" />
</bpmn:process>
<bpmn:message id="Message_1" />
<bpmn:message id="Message_2" name="message" />
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
@ -38,13 +46,24 @@
<bpmndi:BPMNShape id="ExclusiveGateway_1gzwevj_di" bpmnElement="ExclusiveGateway_1" isMarkerVisible="true">
<dc:Bounds x="256" y="95" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="StartEvent_0c95td1_di" bpmnElement="StartEvent_2">
<dc:Bounds x="564" y="582" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="EndEvent_0r7j2ed_di" bpmnElement="EndEvent_1">
<dc:Bounds x="700" y="582" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0rpxpya_di" bpmnElement="IntermediateCatchEvent_1">
<dc:Bounds x="173" y="202" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0rpxpy_di" bpmnElement="IntermediateCatchEvent_2">
<dc:Bounds x="213" y="202" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="217" y="245" width="28" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="TextAnnotation_1qulyll_di" bpmnElement="TextAnnotation_1">
<dc:Bounds x="453" y="0" width="100" height="30" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Association_1w715hc_di" bpmnElement="Association_1w715hc">
<di:waypoint x="441" y="80" />
<di:waypoint x="489" y="30" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Group_1_di" bpmnElement="Group_1">
<dc:Bounds x="162" y="296" width="128" height="110" />
<bpmndi:BPMNLabel>
@ -75,12 +94,6 @@
<dc:Bounds x="403" y="583" width="28" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="StartEvent_0c95td1_di" bpmnElement="StartEvent_2">
<dc:Bounds x="564" y="582" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="EndEvent_0r7j2ed_di" bpmnElement="EndEvent_1">
<dc:Bounds x="700" y="582" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_0pgg94c_di" bpmnElement="SequenceFlow_1">
<di:waypoint x="600" y="600" />
<di:waypoint x="700" y="600" />
@ -88,6 +101,10 @@
<dc:Bounds x="608" y="582" width="85" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Association_1w715hc_di" bpmnElement="Association_1w715hc">
<di:waypoint x="441" y="80" />
<di:waypoint x="489" y="30" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -12,7 +12,10 @@ import {
getExternalLabelMid
} from 'lib/util/LabelUtil';
import { getDi } from 'lib/util/ModelUtil';
import {
getBusinessObject,
getDi
} from 'lib/util/ModelUtil';
import {
assign,
@ -79,6 +82,107 @@ describe('behavior - LabelBehavior', function() {
expect(spy).to.have.been.called;
}));
it('should remove label', inject(function(elementRegistry, modeling) {
// given
var event = elementRegistry.get('StartEvent_1');
// when
modeling.updateProperties(event, {
name: undefined
});
// then
var labelShape = event.label;
expect(labelShape).not.to.exist;
expect(getBusinessObject(event).get('name')).not.to.exist;
}));
});
describe('updating name property via `modeling.updateModdleProperties`', function() {
it('should create label', inject(function(elementRegistry, modeling) {
// given
var gateway = elementRegistry.get('ExclusiveGateway_1'),
bo = getBusinessObject(gateway);
// when
modeling.updateModdleProperties(gateway, bo, {
name: 'foo'
});
// then
var labelShape = gateway.label;
expect(labelShape).to.exist;
expect(gateway.businessObject.name).to.equal('foo');
}));
it('should remove label', inject(function(elementRegistry, modeling) {
// given
var event = elementRegistry.get('StartEvent_1'),
bo = getBusinessObject(event);
// when
modeling.updateModdleProperties(event, bo, {
name: undefined
});
// then
var labelShape = event.label;
expect(labelShape).not.to.exist;
expect(getBusinessObject(event).get('name')).not.to.exist;
}));
it('should NOT create label when message name is added', inject(
function(elementRegistry, modeling) {
// given
var messageEvent = elementRegistry.get('IntermediateCatchEvent_1'),
bo = getBusinessObject(messageEvent);
// when
modeling.updateModdleProperties(messageEvent, bo.eventDefinitions[0].messageRef, {
name: 'foo'
});
// then
var labelShape = messageEvent.label;
expect(labelShape).not.to.exist;
})
);
it('should NOT remove label when message name is removed', inject(
function(elementRegistry, modeling) {
// given
var messageEvent = elementRegistry.get('IntermediateCatchEvent_2'),
bo = getBusinessObject(messageEvent);
// when
modeling.updateModdleProperties(messageEvent, bo.eventDefinitions[0].messageRef, {
name: undefined
});
// then
var labelShape = messageEvent.label;
expect(labelShape).to.exist;
})
);
});
@ -267,8 +371,8 @@ describe('behavior - LabelBehavior', function() {
expect(label).to.exist;
expect(elementRegistry.get(label.id)).to.exist;
expect(label.x).to.within(298, 299);
expect(label.y).to.be.within(140, 141);
expect(label.x).to.closeTo(299, 1);
expect(label.y).to.be.closeTo(145, 1);
expect(label.width).to.be.within(15, 18);
expect(label.height).to.be.within(13, 15);
}
@ -406,7 +510,7 @@ describe('behavior - LabelBehavior', function() {
// then
expect(sequenceFlowConnection.label.x).to.be.closeTo(273, 1);
expect(sequenceFlowConnection.label.y).to.be.closeTo(178, 1);
expect(sequenceFlowConnection.label.y).to.be.closeTo(182, 1);
}
));