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 { import {
getLabel getLabel
} from '../features/label-editing/LabelUtil'; } from '../util/LabelUtil';
import { is } from '../util/ModelUtil'; import { is } from '../util/ModelUtil';

View File

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

View File

@ -1,82 +1,4 @@
import { is } from '../../util/ModelUtil'; export {
getLabel,
/** setLabel
* @typedef { import('../../model').DiagramElement } DiagramElement } from '../../util/LabelUtil';
*/
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

@ -1,7 +1,7 @@
import { import {
setLabel, setLabel,
getLabel getLabel
} from '../LabelUtil'; } from '../../../util/LabelUtil';
import { import {
getExternalLabelMid, getExternalLabelMid,
@ -11,7 +11,6 @@ import {
} from '../../../util/LabelUtil'; } from '../../../util/LabelUtil';
import { import {
getDi,
is is
} from '../../../util/ModelUtil'; } from '../../../util/ModelUtil';
@ -37,29 +36,6 @@ var NULL_DIMENSIONS = {
*/ */
export default function UpdateLabelHandler(modeling, textRenderer, bpmnFactory) { 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. * Set the label and return the changed elements.
* *
@ -77,8 +53,6 @@ export default function UpdateLabelHandler(modeling, textRenderer, bpmnFactory)
setLabel(label, text, labelTarget !== label); setLabel(label, text, labelTarget !== label);
ensureInternalLabelDi(element, text);
return [ label, labelTarget ]; return [ label, labelTarget ];
} }
@ -140,7 +114,7 @@ export default function UpdateLabelHandler(modeling, textRenderer, bpmnFactory)
return; return;
} }
var text = getLabel(label); var text = getLabel(element);
// resize element based on label _or_ pre-defined bounds // resize element based on label _or_ pre-defined bounds
if (typeof newBounds === 'undefined') { if (typeof newBounds === 'undefined') {

View File

@ -18,7 +18,11 @@ import {
import { isAny } from './util/ModelingUtil'; 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'; import { delta } from 'diagram-js/lib/util/PositionUtil';
@ -287,6 +291,28 @@ export default function BpmnUpdater(
this.executed([ 'element.updateAttachment' ], ifBpmn(updateAttachment)); this.executed([ 'element.updateAttachment' ], ifBpmn(updateAttachment));
this.reverted([ '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); inherits(BpmnUpdater, CommandInterceptor);
@ -787,7 +813,7 @@ function ifBpmn(fn) {
return function(event) { return function(event) {
var context = event.context, var context = event.context,
element = context.shape || context.connection; element = context.shape || context.connection || context.element;
if (is(element, 'bpmn:BaseElement')) { if (is(element, 'bpmn:BaseElement')) {
fn(event); fn(event);

View File

@ -6,21 +6,16 @@ import inherits from 'inherits-browser';
import { import {
is, is,
getBusinessObject, getBusinessObject
getDi
} from '../../../util/ModelUtil'; } from '../../../util/ModelUtil';
import { import {
isLabelExternal, isLabelExternal,
getExternalLabelMid, getLabel,
hasExternalLabel, hasExternalLabel,
isLabel isLabel
} from '../../../util/LabelUtil'; } from '../../../util/LabelUtil';
import {
getLabel
} from '../../label-editing/LabelUtil';
import { import {
getLabelAdjustment getLabelAdjustment
} from './util/LabelLayoutUtil'; } from './util/LabelLayoutUtil';
@ -49,11 +44,6 @@ import {
perpendicularFoot perpendicularFoot
} from './util/GeometricUtil'; } from './util/GeometricUtil';
var DEFAULT_LABEL_DIMENSIONS = {
width: 90,
height: 20
};
var NAME_PROPERTY = 'name'; var NAME_PROPERTY = 'name';
var TEXT_PROPERTY = 'text'; var TEXT_PROPERTY = 'text';
@ -86,7 +76,16 @@ export default function LabelBehavior(
CommandInterceptor.call(this, eventBus); CommandInterceptor.call(this, eventBus);
// update label if name property was updated // 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, var context = e.context,
element = context.element, element = context.element,
properties = context.properties; properties = context.properties;
@ -110,7 +109,7 @@ export default function LabelBehavior(
modeling.updateLabel(element, properties.text, newBounds); modeling.updateLabel(element, properties.text, newBounds);
} }
}); }
// create label shape after shape/connection was created // create label shape after shape/connection was created
this.postExecute([ 'shape.create', 'connection.create' ], function(e) { this.postExecute([ 'shape.create', 'connection.create' ], function(e) {
@ -121,8 +120,7 @@ export default function LabelBehavior(
return; return;
} }
var element = context.shape || context.connection, var element = context.shape || context.connection;
businessObject = element.businessObject;
if (isLabel(element) || !isLabelExternal(element)) { if (isLabel(element) || !isLabelExternal(element)) {
return; return;
@ -133,20 +131,7 @@ export default function LabelBehavior(
return; return;
} }
var labelCenter = getExternalLabelMid(element); modeling.updateLabel(element, getLabel(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
});
}); });
// update label after label shape was deleted // 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) { function getVisibleLabelAdjustment(event) {
var context = event.context, var context = event.context,

View File

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

View File

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

View File

@ -178,3 +178,85 @@ export function getExternalLabelBounds(di, element) {
export function isLabel(element) { export function isLabel(element) {
return element && !!element.labelTarget; 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 { import {
getLabel getLabel
} from 'lib/features/label-editing/LabelUtil'; } from 'lib/util/LabelUtil';
import { import {
createCanvasEvent as canvasEvent 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:incoming>SequenceFlow_1</bpmn:incoming>
</bpmn:endEvent> </bpmn:endEvent>
<bpmn:sequenceFlow id="SequenceFlow_1" name="SequenceFlow_1" sourceRef="StartEvent_2" targetRef="EndEvent_1" /> <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:textAnnotation id="TextAnnotation_1">
<bpmn:text>foo</bpmn:text> <bpmn:text>foo</bpmn:text>
</bpmn:textAnnotation> </bpmn:textAnnotation>
@ -24,6 +30,8 @@
<bpmn:group id="Group_4" categoryValueRef="CategoryValue_1" /> <bpmn:group id="Group_4" categoryValueRef="CategoryValue_1" />
<bpmn:group id="Group_5" categoryValueRef="CategoryValue_1" /> <bpmn:group id="Group_5" categoryValueRef="CategoryValue_1" />
</bpmn:process> </bpmn:process>
<bpmn:message id="Message_1" />
<bpmn:message id="Message_2" name="message" />
<bpmndi:BPMNDiagram id="BPMNDiagram_1"> <bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1"> <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_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"> <bpmndi:BPMNShape id="ExclusiveGateway_1gzwevj_di" bpmnElement="ExclusiveGateway_1" isMarkerVisible="true">
<dc:Bounds x="256" y="95" width="50" height="50" /> <dc:Bounds x="256" y="95" width="50" height="50" />
</bpmndi:BPMNShape> </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"> <bpmndi:BPMNShape id="TextAnnotation_1qulyll_di" bpmnElement="TextAnnotation_1">
<dc:Bounds x="453" y="0" width="100" height="30" /> <dc:Bounds x="453" y="0" width="100" height="30" />
</bpmndi:BPMNShape> </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"> <bpmndi:BPMNShape id="Group_1_di" bpmnElement="Group_1">
<dc:Bounds x="162" y="296" width="128" height="110" /> <dc:Bounds x="162" y="296" width="128" height="110" />
<bpmndi:BPMNLabel> <bpmndi:BPMNLabel>
@ -75,12 +94,6 @@
<dc:Bounds x="403" y="583" width="28" height="14" /> <dc:Bounds x="403" y="583" width="28" height="14" />
</bpmndi:BPMNLabel> </bpmndi:BPMNLabel>
</bpmndi:BPMNShape> </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"> <bpmndi:BPMNEdge id="SequenceFlow_0pgg94c_di" bpmnElement="SequenceFlow_1">
<di:waypoint x="600" y="600" /> <di:waypoint x="600" y="600" />
<di:waypoint x="700" y="600" /> <di:waypoint x="700" y="600" />
@ -88,6 +101,10 @@
<dc:Bounds x="608" y="582" width="85" height="14" /> <dc:Bounds x="608" y="582" width="85" height="14" />
</bpmndi:BPMNLabel> </bpmndi:BPMNLabel>
</bpmndi:BPMNEdge> </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:BPMNPlane>
</bpmndi:BPMNDiagram> </bpmndi:BPMNDiagram>
</bpmn:definitions> </bpmn:definitions>

View File

@ -12,7 +12,10 @@ import {
getExternalLabelMid getExternalLabelMid
} from 'lib/util/LabelUtil'; } from 'lib/util/LabelUtil';
import { getDi } from 'lib/util/ModelUtil'; import {
getBusinessObject,
getDi
} from 'lib/util/ModelUtil';
import { import {
assign, assign,
@ -79,6 +82,107 @@ describe('behavior - LabelBehavior', function() {
expect(spy).to.have.been.called; 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(label).to.exist;
expect(elementRegistry.get(label.id)).to.exist; expect(elementRegistry.get(label.id)).to.exist;
expect(label.x).to.within(298, 299); expect(label.x).to.closeTo(299, 1);
expect(label.y).to.be.within(140, 141); expect(label.y).to.be.closeTo(145, 1);
expect(label.width).to.be.within(15, 18); expect(label.width).to.be.within(15, 18);
expect(label.height).to.be.within(13, 15); expect(label.height).to.be.within(13, 15);
} }
@ -406,7 +510,7 @@ describe('behavior - LabelBehavior', function() {
// then // then
expect(sequenceFlowConnection.label.x).to.be.closeTo(273, 1); 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);
} }
)); ));