chore(label-editing): resize textbox during direct editing

Related to bpmn-io/diagram-js-direct-editing#2
This commit is contained in:
pedesen 2016-08-19 16:16:37 +02:00 committed by Ricardo Matias
parent a8cf097ed0
commit f7f868ec67
4 changed files with 391 additions and 172 deletions

View File

@ -7,12 +7,8 @@ var LabelUtil = require('./LabelUtil');
var is = require('../../util/ModelUtil').is,
isExpanded = require('../../util/DiUtil').isExpanded;
var MIN_BOUNDS = {
width: 150,
height: 50
};
var LINE_HEIGHT = 14,
PADDING = 6;
function LabelEditingProvider(eventBus, canvas, directEditing, commandStack) {
@ -35,9 +31,6 @@ function LabelEditingProvider(eventBus, canvas, directEditing, commandStack) {
});
// activate direct editing for activities and text annotations
if ('ontouchstart' in document.documentElement) {
// we deactivate automatic label editing on mobile devices
// as it breaks the user interaction workflow
@ -71,6 +64,13 @@ LabelEditingProvider.$inject = [ 'eventBus', 'canvas', 'directEditing', 'command
module.exports = LabelEditingProvider;
/**
* Activate direct editing for activities and text annotations.
*
* @param {djs.model.Base} element
*
* @return {Object} an object with properties bounds (position and size) and text
*/
LabelEditingProvider.prototype.activate = function(element) {
var text = LabelUtil.getLabel(element);
@ -79,47 +79,22 @@ LabelEditingProvider.prototype.activate = function(element) {
return;
}
var bbox = this.getEditingBBox(element);
var properties = this.getEditingBBox(element);
// adjust for expanded pools AND lanes
if ((is(element, 'bpmn:Participant') && isExpanded(element)) || is(element, 'bpmn:Lane')) {
properties.text = text;
bbox.width = MIN_BOUNDS.width;
bbox.height = MIN_BOUNDS.height;
bbox.x = bbox.x + 10 - bbox.width / 2;
bbox.y = bbox.mid.y - bbox.height / 2;
}
// ajust minumum size for task and activities
if ((is(element, 'bpmn:Task') || is(element, 'bpmn:Activity') )) {
if (bbox.width < 100) {
bbox.width = 100;
bbox.x = bbox.mid.x - bbox.width / 2;
}
if (bbox.height < 80) {
bbox.height = 80;
bbox.y = bbox.mid.y - bbox.height / 2;
}
}
// adjust for expanded sub processes and collapsed pools
if ((is(element, 'bpmn:SubProcess') && isExpanded(element)) ||
(is(element, 'bpmn:Participant') && !isExpanded(element))) {
bbox.width = element.width;
bbox.height = MIN_BOUNDS.height;
bbox.x = bbox.mid.x - element.width / 2;
}
return { bounds: bbox, text: text };
return properties;
};
LabelEditingProvider.prototype.getEditingBBox = function(element, maxBounds) {
/**
* Get the editing bounding box based on the element's size and position
*
* @param {djs.model.Base} element
*
* @return {Object} an object containing information about position and size (fixed or minimum and/or maximum)
*/
LabelEditingProvider.prototype.getEditingBBox = function(element) {
var target = element.label || element;
@ -130,17 +105,63 @@ LabelEditingProvider.prototype.getEditingBBox = function(element, maxBounds) {
y: bbox.y + bbox.height / 2
};
// external label
if (target.labelTarget) {
bbox.width = Math.max(bbox.width, MIN_BOUNDS.width);
bbox.height = Math.max(bbox.height, MIN_BOUNDS.height);
// default position
var bounds = { x: bbox.x, y: bbox.y };
bbox.x = mid.x - bbox.width / 2;
var style = {};
// adjust for expanded pools AND lanes
if ((is(element, 'bpmn:Participant') && isExpanded(element)) || is(element, 'bpmn:Lane')) {
bounds.width = 150;
bounds.minHeight = LINE_HEIGHT + PADDING;
bounds.maxHeight = LINE_HEIGHT * 2 + PADDING;
bounds.x = bbox.x - bounds.width / 2;
bounds.y = mid.y - bounds.minHeight / 2;
}
bbox.mid = mid;
return bbox;
// internal labels for tasks and collapsed call activities, sub processes and participants
if (
is(element, 'bpmn:Task') ||
(is(element, 'bpmn:CallActivity') && !isExpanded(element)) ||
(is(element, 'bpmn:SubProcess') && !isExpanded(element)) ||
(is(element, 'bpmn:Participant') && !isExpanded(element))
) {
// fixed size for internal labels
bounds.width = bbox.width;
bounds.height = bbox.height;
}
// internal labels for expanded sub processes
if (is(element, 'bpmn:SubProcess') && isExpanded(element)) {
bounds.width = element.width;
bounds.maxHeight = 3 * LINE_HEIGHT + PADDING; // maximum 3 lines
bounds.x = mid.x - element.width / 2;
}
// external labels for events, data elements, gateways and connections
if (target.labelTarget) {
bounds.width = 150;
bounds.minHeight = LINE_HEIGHT + PADDING; // 1 line
bounds.x = mid.x - bounds.width / 2;
}
// text annotations
if (is(element, 'bpmn:TextAnnotation')) {
bounds.minWidth = 100;
bounds.height = element.height;
style.textAlign = 'left';
}
return { bounds: bounds, style: style };
};

View File

@ -42,7 +42,7 @@ module.exports = UpdatePropertiesHandler;
* @param {Object} context.properties a list of properties to set on the element's
* businessObject (the BPMN model element)
*
* @return {Array<djs.mode.Base>} the updated element
* @return {Array<djs.model.Base>} the updated element
*/
UpdatePropertiesHandler.prototype.execute = function(context) {
@ -104,7 +104,7 @@ UpdatePropertiesHandler.prototype.execute = function(context) {
*
* @param {Object} context
*
* @return {djs.mode.Base} the updated element
* @return {djs.model.Base} the updated element
*/
UpdatePropertiesHandler.prototype.revert = function(context) {

View File

@ -1,23 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="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:di="http://www.omg.org/spec/DD/20100524/DI" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" id="_w9Yc0PLSEeOqh_cnoUOA7A" targetNamespace="http://activiti.org/bpmn">
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="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:di="http://www.omg.org/spec/DD/20100524/DI" id="_w9Yc0PLSEeOqh_cnoUOA7A" targetNamespace="http://activiti.org/bpmn" exporter="Camunda Modeler" exporterVersion="1.3.0-nightly" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
<bpmn2:collaboration id="_Collaboration_2">
<bpmn2:participant id="expanded-pool" name="A" processRef="Process_1"/>
<bpmn2:participant id="collapsed-pool" name="A"/>
<bpmn2:messageFlow id="message-flow" name="A" sourceRef="task-nested-embedded" targetRef="collapsed-pool"/>
<bpmn2:messageFlow id="message-flow-unlabeled" name="" sourceRef="collapsed-pool" targetRef="expanded-pool"/>
<bpmn2:participant id="expanded-pool" name="A" processRef="Process_1" />
<bpmn2:participant id="collapsed-pool" name="A" />
<bpmn2:messageFlow id="message-flow" name="A" sourceRef="task-nested-embedded" targetRef="collapsed-pool" />
<bpmn2:messageFlow id="message-flow-unlabeled" name="" sourceRef="collapsed-pool" targetRef="expanded-pool" />
<bpmn2:textAnnotation id="text-annotation"> <bpmn2:text>A</bpmn2:text>
</bpmn2:textAnnotation>
</bpmn2:collaboration>
<bpmn2:process id="Process_1" isExecutable="false">
<bpmn2:ioSpecification id="InputOutputSpecification_1">
<bpmn2:dataInput id="data-input"/>
<bpmn2:dataOutput id="data-output"/>
<bpmn2:dataInput id="data-input" />
<bpmn2:dataOutput id="data-output" />
</bpmn2:ioSpecification>
<bpmn2:laneSet id="LaneSet_1" name="Lane Set 1">
<bpmn2:lane id="lane-1" name="A">
<bpmn2:flowNodeRef>intermediate-throw-event</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>empty-task</bpmn2:flowNodeRef>
<bpmn2:childLaneSet xsi:type="bpmn2:tLaneSet" id="LaneSet_2">
<bpmn2:lane id="nested-lane-1-1" name="A">
<bpmn2:flowNodeRef>start-event</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>exclusive-gateway</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>intermediate-throw-event</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>empty-task</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="nested-lane-1-2" name="A">
<bpmn2:flowNodeRef>call-activity</bpmn2:flowNodeRef>
@ -41,193 +46,203 @@
<bpmn2:dataOutputAssociation id="DataOutputAssociation_1">
<bpmn2:targetRef>data-output</bpmn2:targetRef>
</bpmn2:dataOutputAssociation>
<bpmn2:task id="task-nested-embedded" name="A"/>
<bpmn2:task id="task-nested-embedded" name="A" />
</bpmn2:subProcess>
<bpmn2:subProcess id="subprocess-collapsed" name="A" triggeredByEvent="true">
<bpmn2:dataInputAssociation id="DataInputAssociation_2">
<bpmn2:sourceRef>data-store-reference</bpmn2:sourceRef>
</bpmn2:dataInputAssociation>
<bpmn2:startEvent id="nested-embedded-start-event" name="start event" isInterrupting="false"/>
<bpmn2:startEvent id="nested-embedded-start-event" name="start event" isInterrupting="false" />
</bpmn2:subProcess>
<bpmn2:callActivity id="call-activity" name="A">
<bpmn2:incoming>sequence-flow-no</bpmn2:incoming>
</bpmn2:callActivity>
<bpmn2:userTask id="user-task" name="A"/>
<bpmn2:boundaryEvent id="boundary-event" name="A" attachedToRef="user-task"/>
<bpmn2:userTask id="user-task" name="A" />
<bpmn2:boundaryEvent id="boundary-event" name="A" attachedToRef="user-task" />
<bpmn2:startEvent id="start-event">
<bpmn2:outgoing>sequenceflow-unlabeled</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:sequenceFlow id="sequenceflow-unlabeled" name="" sourceRef="start-event" targetRef="exclusive-gateway"/>
<bpmn2:sequenceFlow id="sequenceflow-unlabeled" name="" sourceRef="start-event" targetRef="exclusive-gateway" />
<bpmn2:exclusiveGateway id="exclusive-gateway" name="A">
<bpmn2:incoming>sequenceflow-unlabeled</bpmn2:incoming>
<bpmn2:outgoing>sequence-flow-no</bpmn2:outgoing>
<bpmn2:outgoing>sequence-flow-yes</bpmn2:outgoing>
</bpmn2:exclusiveGateway>
<bpmn2:sequenceFlow id="sequence-flow-no" name="A" sourceRef="exclusive-gateway" targetRef="call-activity"/>
<bpmn2:sequenceFlow id="sequence-flow-yes" name="A" sourceRef="exclusive-gateway" targetRef="intermediate-throw-event"/>
<bpmn2:sequenceFlow id="sequence-flow-no" name="A" sourceRef="exclusive-gateway" targetRef="call-activity" />
<bpmn2:sequenceFlow id="sequence-flow-yes" name="A" sourceRef="exclusive-gateway" targetRef="intermediate-throw-event" />
<bpmn2:dataStoreReference id="data-store-reference" name="A" dataStoreRef="DataStore_1" />
<bpmn2:dataObject id="DataObject_1" name="Data Object 1" />
<bpmn2:dataObjectReference id="data-object-reference" name="A" dataObjectRef="DataObject_1" />
<bpmn2:intermediateThrowEvent id="intermediate-throw-event" name="A">
<bpmn2:incoming>sequence-flow-yes</bpmn2:incoming>
<bpmn2:outgoing>SequenceFlow_1r751z0</bpmn2:outgoing>
</bpmn2:intermediateThrowEvent>
<bpmn2:dataStoreReference id="data-store-reference" name="A" dataStoreRef="DataStore_1"/>
<bpmn2:dataObject id="DataObject_1" name="Data Object 1"/>
<bpmn2:dataObjectReference id="data-object-reference" name="A" dataObjectRef="DataObject_1"/>
<bpmn2:textAnnotation id="text-annotation">
<bpmn2:text>A</bpmn2:text>
</bpmn2:textAnnotation>
<bpmn2:association id="Association_1" sourceRef="text-annotation" targetRef="subprocess-expanded"/>
<bpmn2:task id="empty-task">
<bpmn2:incoming>SequenceFlow_1r751z0</bpmn2:incoming>
</bpmn2:task>
<bpmn2:sequenceFlow id="SequenceFlow_1r751z0" sourceRef="intermediate-throw-event" targetRef="empty-task" />
<bpmn2:association id="Association_1" sourceRef="text-annotation" targetRef="subprocess-expanded" />
</bpmn2:process>
<bpmn2:dataStore id="DataStore_1" name="Data Store 1"/>
<bpmn2:dataStore id="DataStore_1" name="Data Store 1" />
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="_Collaboration_2">
<bpmndi:BPMNShape id="_BPMNShape_Participant_2" bpmnElement="expanded-pool" isHorizontal="true">
<dc:Bounds height="613.0" width="540.0" x="60.0" y="48.0"/>
<dc:Bounds x="60" y="48" width="540" height="613" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_Lane_2" bpmnElement="lane-1" isHorizontal="true">
<dc:Bounds height="277.0" width="510.0" x="90.0" y="48.0"/>
<dc:Bounds x="90" y="48" width="510" height="277" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_Lane_3" bpmnElement="nested-lane-1-1" isHorizontal="true">
<dc:Bounds height="133.0" width="480.0" x="120.0" y="48.0"/>
<dc:Bounds x="120" y="48" width="480" height="133" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_Lane_4" bpmnElement="nested-lane-1-2" isHorizontal="true">
<dc:Bounds height="145.0" width="480.0" x="120.0" y="180.0"/>
<dc:Bounds x="120" y="180" width="480" height="145" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_Lane_5" bpmnElement="lane-2" isHorizontal="true">
<dc:Bounds height="337.0" width="510.0" x="90.0" y="324.0"/>
<dc:Bounds x="90" y="324" width="510" height="337" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_Lane_6" bpmnElement="nested-lane-no-label" isHorizontal="true">
<dc:Bounds height="337.0" width="480.0" x="120.0" y="324.0"/>
<dc:Bounds x="120" y="324" width="480" height="337" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_SubProcess_2" bpmnElement="subprocess-expanded" isExpanded="true">
<dc:Bounds height="150.0" width="200.0" x="359.0" y="364.0"/>
<dc:Bounds x="359" y="364" width="200" height="150" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_SubProcess_3" bpmnElement="subprocess-collapsed">
<dc:Bounds height="80.0" width="100.0" x="156.0" y="364.0"/>
<dc:Bounds x="156" y="364" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="nested-embedded-start-event">
<dc:Bounds height="36.0" width="36.0" x="188.0" y="386.0"/>
<dc:Bounds x="188" y="386" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds height="22.0" width="66.0" x="173.0" y="427.0"/>
<dc:Bounds x="173" y="427" width="66" height="22" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_Task_2" bpmnElement="task-nested-embedded">
<dc:Bounds height="80.0" width="100.0" x="432.0" y="408.0"/>
<dc:Bounds x="432" y="408" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_Participant_3" bpmnElement="collapsed-pool" isHorizontal="true">
<dc:Bounds height="100.0" width="385.0" x="672.0" y="336.0"/>
<dc:Bounds x="672" y="336" width="385" height="100" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_TextAnnotation_2" bpmnElement="text-annotation">
<dc:Bounds height="98.0" width="147.0" x="660.0" y="198.0"/>
<dc:Bounds x="60" y="669" width="147" height="98" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="BPMNEdge_Association_1" bpmnElement="Association_1" sourceElement="_BPMNShape_TextAnnotation_2" targetElement="_BPMNShape_SubProcess_2">
<di:waypoint xsi:type="dc:Point" x="663.0" y="296.0"/>
<di:waypoint xsi:type="dc:Point" x="559.0" y="369.0"/>
<di:waypoint xsi:type="dc:Point" x="190" y="669" />
<di:waypoint xsi:type="dc:Point" x="371" y="514" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_CallActivity_2" bpmnElement="call-activity">
<dc:Bounds height="80.0" width="100.0" x="422.0" y="202.0"/>
<dc:Bounds x="422" y="202" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_3" bpmnElement="start-event">
<dc:Bounds height="36.0" width="36.0" x="168.0" y="96.0"/>
<dc:Bounds x="168" y="96" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds height="22.0" width="66.0" x="153.0" y="137.0"/>
<dc:Bounds x="153" y="137" width="66" height="22" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_IntermediateThrowEvent_2" bpmnElement="intermediate-throw-event">
<dc:Bounds height="36.0" width="36.0" x="432.0" y="96.0"/>
<dc:Bounds x="397" y="96" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds height="38.0" width="87.0" x="407.0" y="137.0"/>
<dc:Bounds x="371" y="137" width="90" height="38" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_UserTask_2" bpmnElement="user-task">
<dc:Bounds height="80.0" width="100.0" x="180.0" y="192.0"/>
<dc:Bounds x="180" y="192" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_BoundaryEvent_2" bpmnElement="boundary-event">
<dc:Bounds height="36.0" width="36.0" x="228.0" y="254.0"/>
<dc:Bounds x="228" y="254" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds height="22.0" width="93.0" x="200.0" y="295.0"/>
<dc:Bounds x="200" y="295" width="93" height="22" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_ExclusiveGateway_2" bpmnElement="exclusive-gateway" isMarkerVisible="true">
<dc:Bounds height="50.0" width="50.0" x="312.0" y="89.0"/>
<dc:Bounds x="312" y="89" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds height="38.0" width="64.0" x="306.0" y="48.0"/>
<dc:Bounds x="306" y="48" width="64" height="38" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_1" bpmnElement="sequenceflow-unlabeled" sourceElement="_BPMNShape_StartEvent_3" targetElement="_BPMNShape_ExclusiveGateway_2">
<di:waypoint xsi:type="dc:Point" x="204.0" y="114.0"/>
<di:waypoint xsi:type="dc:Point" x="312.0" y="114.0"/>
<di:waypoint xsi:type="dc:Point" x="204" y="114" />
<di:waypoint xsi:type="dc:Point" x="312" y="114" />
<bpmndi:BPMNLabel>
<dc:Bounds height="6.0" width="6.0" x="243.0" y="114.0"/>
<dc:Bounds x="243" y="114" width="6" height="6" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_2" bpmnElement="sequence-flow-no" sourceElement="_BPMNShape_ExclusiveGateway_2" targetElement="_BPMNShape_CallActivity_2">
<di:waypoint xsi:type="dc:Point" x="337.0" y="139.0"/>
<di:waypoint xsi:type="dc:Point" x="337.0" y="242.0"/>
<di:waypoint xsi:type="dc:Point" x="422.0" y="242.0"/>
<di:waypoint xsi:type="dc:Point" x="337" y="139" />
<di:waypoint xsi:type="dc:Point" x="337" y="242" />
<di:waypoint xsi:type="dc:Point" x="422" y="242" />
<bpmndi:BPMNLabel>
<dc:Bounds height="22.0" width="20.0" x="342.0" y="204.0"/>
<dc:Bounds x="342" y="204" width="20" height="22" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_3" bpmnElement="sequence-flow-yes" sourceElement="_BPMNShape_ExclusiveGateway_2" targetElement="_BPMNShape_IntermediateThrowEvent_2">
<di:waypoint xsi:type="dc:Point" x="362.0" y="114.0"/>
<di:waypoint xsi:type="dc:Point" x="432.0" y="114.0"/>
<di:waypoint xsi:type="dc:Point" x="362" y="114" />
<di:waypoint xsi:type="dc:Point" x="397" y="114" />
<bpmndi:BPMNLabel>
<dc:Bounds height="22.0" width="27.0" x="385.0" y="114.0"/>
<dc:Bounds x="335.49989765458423" y="114" width="90" height="22" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_MessageFlow_1" bpmnElement="message-flow" sourceElement="_BPMNShape_Task_2" targetElement="_BPMNShape_Participant_3">
<di:waypoint xsi:type="dc:Point" x="532.0" y="448.0"/>
<di:waypoint xsi:type="dc:Point" x="632.0" y="448.0"/>
<di:waypoint xsi:type="dc:Point" x="632.0" y="386.0"/>
<di:waypoint xsi:type="dc:Point" x="672.0" y="386.0"/>
<di:waypoint xsi:type="dc:Point" x="532" y="448" />
<di:waypoint xsi:type="dc:Point" x="632" y="448" />
<di:waypoint xsi:type="dc:Point" x="632" y="386" />
<di:waypoint xsi:type="dc:Point" x="672" y="386" />
<bpmndi:BPMNLabel>
<dc:Bounds height="38.0" width="91.0" x="612.0" y="456.0"/>
<dc:Bounds x="612" y="456" width="91" height="38" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_DataStoreReference_2" bpmnElement="data-store-reference">
<dc:Bounds height="50.0" width="50.0" x="156.0" y="547.0"/>
<dc:Bounds x="156" y="547" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds height="22.0" width="64.0" x="149.0" y="602.0"/>
<dc:Bounds x="149" y="602" width="64" height="22" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_DataObjectReference_2" bpmnElement="data-object-reference">
<dc:Bounds height="50.0" width="36.0" x="267.0" y="547.0"/>
<dc:Bounds x="267" y="547" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds height="38.0" width="80.0" x="245.0" y="602.0"/>
<dc:Bounds x="245" y="602" width="80" height="38" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_DataInput_2" bpmnElement="data-input">
<dc:Bounds height="50.0" width="36.0" x="372.0" y="547.0"/>
<dc:Bounds x="372" y="547" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="390.0" y="602.0"/>
<dc:Bounds x="390" y="602" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_DataOutput_2" bpmnElement="data-output">
<dc:Bounds height="50.0" width="36.0" x="504.0" y="547.0"/>
<dc:Bounds x="504" y="547" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="522.0" y="602.0"/>
<dc:Bounds x="522" y="602" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="BPMNEdge_DataInputAssociation_1" bpmnElement="DataInputAssociation_1" sourceElement="_BPMNShape_DataInput_2" targetElement="_BPMNShape_SubProcess_2">
<di:waypoint xsi:type="dc:Point" x="403.0" y="547.0"/>
<di:waypoint xsi:type="dc:Point" x="420.0" y="514.0"/>
<di:waypoint xsi:type="dc:Point" x="403" y="547" />
<di:waypoint xsi:type="dc:Point" x="420" y="514" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_DataOutputAssociation_1" bpmnElement="DataOutputAssociation_1" sourceElement="_BPMNShape_SubProcess_2" targetElement="_BPMNShape_DataOutput_2">
<di:waypoint xsi:type="dc:Point" x="495.0" y="514.0"/>
<di:waypoint xsi:type="dc:Point" x="510.0" y="547.0"/>
<di:waypoint xsi:type="dc:Point" x="495" y="514" />
<di:waypoint xsi:type="dc:Point" x="510" y="547" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_DataInputAssociation_2" bpmnElement="DataInputAssociation_2" sourceElement="_BPMNShape_DataStoreReference_2" targetElement="_BPMNShape_SubProcess_3">
<di:waypoint xsi:type="dc:Point" x="185.0" y="547.0"/>
<di:waypoint xsi:type="dc:Point" x="200.0" y="444.0"/>
<di:waypoint xsi:type="dc:Point" x="185" y="547" />
<di:waypoint xsi:type="dc:Point" x="200" y="444" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_MessageFlow_2" bpmnElement="message-flow-unlabeled" sourceElement="_BPMNShape_Participant_3" targetElement="_BPMNShape_Participant_2">
<di:waypoint xsi:type="dc:Point" x="864.0" y="336.0"/>
<di:waypoint xsi:type="dc:Point" x="864.0" y="4.0"/>
<di:waypoint xsi:type="dc:Point" x="326.0" y="4.0"/>
<di:waypoint xsi:type="dc:Point" x="327.0" y="48.0"/>
<di:waypoint xsi:type="dc:Point" x="672" y="386" />
<di:waypoint xsi:type="dc:Point" x="600" y="386" />
<bpmndi:BPMNLabel>
<dc:Bounds height="6.0" width="6.0" x="861.0" y="284.0"/>
<dc:Bounds x="591" y="368" width="90" height="6" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Task_0da8ze1_di" bpmnElement="empty-task">
<dc:Bounds x="472" y="74" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_1r751z0_di" bpmnElement="SequenceFlow_1r751z0">
<di:waypoint xsi:type="dc:Point" x="433" y="114" />
<di:waypoint xsi:type="dc:Point" x="472" y="114" />
<bpmndi:BPMNLabel>
<dc:Bounds x="407.5" y="89" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>
</bpmn2:definitions>

View File

@ -1,9 +1,13 @@
'use strict';
require('../../../TestHelper');
var TestHelper = require('../../../TestHelper');
/* global bootstrapViewer, inject */
TestHelper.insertCSS('diagram-js-label-editing.css',
'div { box-sizing: border-box; }' +
'div[contenteditable=true] { line-height: 14px; font-family: Arial; font-size: 12px }'
);
var labelEditingModule = require('../../../../lib/features/label-editing'),
coreModule = require('../../../../lib/core'),
@ -11,7 +15,6 @@ var labelEditingModule = require('../../../../lib/features/label-editing'),
var LabelUtil = require('../../../../lib/features/label-editing/LabelUtil');
function triggerKeyEvent(element, event, code) {
var e = document.createEvent('Events');
@ -61,13 +64,12 @@ describe('features - label-editing', function() {
// activate
eventBus.fire('element.dblclick', { element: shape });
// a <textarea /> element
var textarea = directEditing._textbox.textarea;
var textbox = directEditing._textbox.content;
// when
// change + ESC is pressed
textarea.value = 'new value';
triggerKeyEvent(textarea, 'keydown', 27);
textbox.innerText = 'new value';
triggerKeyEvent(textbox, 'keydown', 27);
// then
expect(directEditing.isActive()).to.be.false;
@ -83,7 +85,7 @@ describe('features - label-editing', function() {
directEditing.activate(shape);
directEditing._textbox.textarea.value = 'FOO BAR';
directEditing._textbox.content.innerText = 'FOO BAR';
// when
dragging.init(null, { x: 0, y: 0 }, 'foo');
@ -105,11 +107,12 @@ describe('features - label-editing', function() {
var newName = 'new value';
// a <textarea /> element
var textarea = directEditing._textbox.textarea;
var content = directEditing._textbox.content;
content.innerText = newName;
// when
// change + <element.mousedown>
textarea.value = newName;
eventBus.fire('element.mousedown', { element: canvas.getRootElement() });
@ -148,7 +151,7 @@ describe('features - label-editing', function() {
}
function directEditUpdate(value) {
directEditing._textbox.textarea.value = value;
directEditing._textbox.content.innerText = value;
}
function directEditComplete(value) {
@ -342,44 +345,224 @@ describe('features - label-editing', function() {
var testModules = [ labelEditingModule, coreModule ];
function testTextboxSizing(elementId, zoom, width, height, content) {
return inject(function(canvas, elementRegistry, directEditing) {
// zoom in
canvas.zoom(zoom);
// grab one element
var shape = elementRegistry.get(elementId);
// activate label editing
directEditing.activate(shape);
// grab the textarea
var textbox = directEditing._textbox;
// optionally set content text
if (content) {
textbox.content.innerText = content;
}
if (width === 'auto') {
width = shape.width;
}
if (height === 'auto') {
height = shape.height;
}
// then
if (typeof width === 'object' && width.min) {
expect(textbox.content.offsetWidth).to.be.at.least(width.min);
} else {
expect(textbox.content.offsetWidth).to.be.equal(width);
}
if (typeof height === 'object' && height.min) {
expect(textbox.content.offsetHeight).to.be.at.least(height.min);
} else {
expect(textbox.content.offsetHeight).to.be.equal(height);
}
});
}
beforeEach(bootstrapViewer(diagramXML, {
modules: testModules,
canvas: { deferUpdate: false }
}));
describe('textbox should have minimum size', function() {
describe('height', function() {
function testTextboxSizing(elementId, zoom, width, height) {
return inject(function(canvas, elementRegistry, directEditing) {
// zoom in
canvas.zoom(zoom);
// grab one element
var shape = elementRegistry.get(elementId);
// activate label editing
directEditing.activate(shape);
// grab the textarea
var textbox = directEditing._textbox;
// then
expect(textbox.textarea.offsetWidth).to.be.equal(width);
expect(textbox.textarea.offsetHeight).to.be.equal(height);
});
}
var oneLineText = 'One line',
twoLineText = 'Two\nlines',
tenLineText = '1\n2\n3\n4\n5\n6\n7\n8\n9\n0';
it('task', testTextboxSizing('task-nested-embedded', 1, 100, 80));
it('task, low zoom', testTextboxSizing('task-nested-embedded', 1, 100, 80));
describe('external labels', function() {
it('call activity', testTextboxSizing('call-activity', 1, 100, 80));
it('call activity, low zoom', testTextboxSizing('call-activity', 0.4, 100, 80));
it('[no text] should have min height', testTextboxSizing('start-event', 1, 150, 20));
it('subprocess collapsed', testTextboxSizing('subprocess-collapsed', 1, 100, 80));
it('subprocess collapsed, low zoom', testTextboxSizing('subprocess-collapsed', 0.4, 100, 80));
it('[1 line text] should be 1 line high', testTextboxSizing('start-event', 1, 150, 20, oneLineText));
it('subprocess expanded', testTextboxSizing('subprocess-expanded', 1, 200, 50));
it('subprocess expanded, low zoom', testTextboxSizing('subprocess-expanded', 0.4, 200, 50));
it('[2 line text] should be 2 line high', testTextboxSizing('start-event', 1, 150, 34, twoLineText));
it('[10 line text] should be 10 line high', testTextboxSizing('start-event', 1, 150, 146, tenLineText));
});
describe('internal labels', function() {
it('[no text] should have fixed dimensions', testTextboxSizing('empty-task', 1, 'auto', 'auto'));
it('[1 line text] should have fixed dimensions', testTextboxSizing('empty-task', 1, 'auto', 'auto', oneLineText));
it('[2 line text] should have fixed dimensions', testTextboxSizing('empty-task', 1, 'auto', 'auto', twoLineText));
it('[10 line text] should have fixed dimensions', testTextboxSizing('empty-task', 1, 'auto', 'auto', tenLineText));
});
describe('sequence flows', function() {
it('[no text] should have min height', testTextboxSizing('sequenceflow-unlabeled', 1, 150, 20));
it('[1 line text] should be 1 line high', testTextboxSizing('sequenceflow-unlabeled', 1, 150, 20, oneLineText));
it('[2 line text] should be 2 line high', testTextboxSizing('sequenceflow-unlabeled', 1, 150, 34, twoLineText));
it('[10 line text] should be 10 line high', testTextboxSizing('sequenceflow-unlabeled', 1, 150, 146, tenLineText));
});
describe('text annotation', function() {
it('[no text] should have element height', testTextboxSizing('text-annotation', 1, 100, 98));
it('[1 line text] should have element height', testTextboxSizing('text-annotation', 1, 100, 98, oneLineText));
it('[2 line text] should have element height', testTextboxSizing('text-annotation', 1, 100, 98, twoLineText));
it('[10 line text] should have element height', testTextboxSizing('text-annotation', 1, 100, 98, tenLineText));
});
describe('expanded sub process', function() {
it('[no text] should have min height', testTextboxSizing('subprocess-expanded', 1, 200, 20));
it('[1 line text] should be 1 line high', testTextboxSizing('subprocess-expanded', 1, 200, 20, oneLineText));
it('[2 line text] should be 2 line high', testTextboxSizing('subprocess-expanded', 1, 200, 34, twoLineText));
it('[10 line text] should be max 3 line high', testTextboxSizing('subprocess-expanded', 1, 200, 48, tenLineText));
});
describe('pools/lanes', function() {
it('[no text] should have min height', testTextboxSizing('expanded-pool', 1, 150, 20));
it('[1 line text] should be 1 line high', testTextboxSizing('expanded-pool', 1, 150, 20, oneLineText));
it('[2 line text] should be 2 line high', testTextboxSizing('expanded-pool', 1, 150, 34, twoLineText));
it('[10 line text] should be max 2 line high', testTextboxSizing('expanded-pool', 1, 150, 34, tenLineText));
});
});
describe('width', function() {
var oneWord = 'foobar',
fiveWords = 'lorem ipsum dolor foobar foobar',
longWord = 'loremipsumdolorfoobar';
describe('external labels', function() {
it('[no text] should have fixed width', testTextboxSizing('start-event', 1, 150, 20));
it('[one word] should have fixed width', testTextboxSizing('start-event', 1, 150, 20, oneWord));
it('[five words] should have fixed width, line break', testTextboxSizing('start-event', 1, 150, { min: 34 }, fiveWords));
it('[long word] should have fixed width', testTextboxSizing('start-event', 1, 150, { min: 20 }, longWord));
});
describe('internal labels', function() {
it('[no text] should have fixed dimensions (task)', testTextboxSizing('empty-task', 1, 100, 80));
it('[no text] should have fixed dimensions (call activity)', testTextboxSizing('call-activity', 1, 100, 80));
it('[no text] should have fixed dimensions (collapsed sub process)', testTextboxSizing('subprocess-collapsed', 1, 100, 80));
it('[one word] should have fixed dimensions', testTextboxSizing('empty-task', 1, 100, 80, oneWord));
it('[five words] should have fixed dimensions', testTextboxSizing('empty-task', 1, 100, 80, fiveWords));
it('[long word] should have fixed dimensions', testTextboxSizing('empty-task', 1, 100, 80, longWord));
});
describe('sequence flows', function() {
it('[no text] should have fixed width', testTextboxSizing('sequenceflow-unlabeled', 1, 150, 20));
it('[one word] should have fixed width', testTextboxSizing('sequenceflow-unlabeled', 1, 150, 20, oneWord));
it('[five words] should have fixed width, line break', testTextboxSizing('sequenceflow-unlabeled', 1, 150, { min: 34 }, fiveWords));
it('[long word] should have fixed width', testTextboxSizing('sequenceflow-unlabeled', 1, 150, { min: 20 }, longWord));
});
describe('text annotation', function() {
it('[no text] should have min width', testTextboxSizing('text-annotation', 1, 100, 98));
it('[one word] should have min width', testTextboxSizing('text-annotation', 1, 100, 98, oneWord));
it('[five words] should expand width', testTextboxSizing('text-annotation', 1, { min: 176 }, 98, fiveWords));
it('[long word] should expand width', testTextboxSizing('text-annotation', 1, { min: 129 }, 98, longWord));
});
describe('expanded sub process', function() {
it('[no text] should have fixed width', testTextboxSizing('subprocess-expanded', 1, 200, 20));
it('[one word] should have fixed width', testTextboxSizing('subprocess-expanded', 1, 200, 20, oneWord));
it('[five words] should have fixed width, line break', testTextboxSizing('subprocess-expanded', 1, 200, 20, fiveWords));
it('[long word] should have fixed width', testTextboxSizing('subprocess-expanded', 1, 200, 20, longWord));
});
describe('pools/lanes', function() {
it('[no text] should have fixed width', testTextboxSizing('expanded-pool', 1, 150, 20));
it('[one word] should have fixed width', testTextboxSizing('expanded-pool', 1, 150, 20, oneWord));
it('[five words] should have fixed width, line break', testTextboxSizing('expanded-pool', 1, 150, 34, fiveWords));
it('[long word] should have fixed width', testTextboxSizing('expanded-pool', 1, 150, { min: 20 }, longWord));
});
it('collapsed pool expanded', testTextboxSizing('collapsed-pool', 1, 385, 50));
it('collapsed pool, low zoom', testTextboxSizing('collapsed-pool', 0.4, 385, 50));
});
});