fix(modeling): support newBounds

This fixes a bug where Modeling#updateLabel would not work on
text annotations, because these need to have labels pre-configured.

* Modeling#updateLabel now takes the (optional) newBounds
* newBounds must now explicitly be passed to trigger resize
  for text annotations
* newBounds is _only_ passed for text annotations via
  LabelEditingProvider (it was discarded before anyway)
* lib/features/label-editing did not depend on lib/features/modeling
  for historical reasons. It now uses the offical #updateLabel
  API provided by Modeling
* Localize test diagrams

Closes #753
This commit is contained in:
Nico Rehwaldt 2018-01-24 20:25:28 +01:00 committed by Philipp Fromme
parent d32da90013
commit f1daf4841f
14 changed files with 565 additions and 410 deletions

View File

@ -5,11 +5,11 @@ module.exports = {
require('diagram-js/lib/features/hand-tool'),
require('diagram-js/lib/features/lasso-tool'),
require('diagram-js/lib/features/space-tool'),
require('diagram-js-direct-editing'),
require('../global-connect'),
require('../copy-paste'),
require('../distribute-elements'),
require('../search'),
require('../modeling')
require('../search')
],
editorActions: [ 'type', require('./BpmnEditorActions') ]
};

View File

@ -2,8 +2,6 @@
var assign = require('lodash/object/assign');
var UpdateLabelHandler = require('./cmd/UpdateLabelHandler');
var LabelUtil = require('./LabelUtil');
var is = require('../../util/ModelUtil').is,
@ -15,22 +13,27 @@ var SMALL_FONT_SIZE = 11,
MEDIUM_FONT_SIZE = 12,
MEDIUM_LINE_HEIGHT = 14;
function LabelEditingProvider(eventBus, canvas, directEditing, commandStack, resizeHandles) {
function LabelEditingProvider(
eventBus, canvas, directEditing,
modeling, resizeHandles) {
this._canvas = canvas;
this._commandStack = commandStack;
this._modeling = modeling;
directEditing.registerProvider(this);
commandStack.registerHandler('element.updateLabel', UpdateLabelHandler);
// listen to dblclick on non-root elements
eventBus.on('element.dblclick', function(event) {
activateDirectEdit(event.element, true);
});
// complete on followup canvas operation
eventBus.on([ 'element.mousedown', 'drag.init', 'canvas.viewbox.changing' ], function(event) {
eventBus.on([
'element.mousedown',
'drag.init',
'canvas.viewbox.changing'
], function(event) {
directEditing.complete();
});
@ -50,12 +53,14 @@ function LabelEditingProvider(eventBus, canvas, directEditing, commandStack, res
canExecute = event.context.canExecute,
isTouch = event.isTouch;
// TODO(nikku): we need to find a way to support the direct editing
// on mobile devices; right now this will break for desworkflowediting on mobile devices
// TODO(nikku): we need to find a way to support the
// direct editing on mobile devices; right now this will
// break for desworkflowediting on mobile devices
// as it breaks the user interaction workflow
// TODO(nre): we should temporarily focus the edited element here
// and release the focused viewport after the direct edit operation is finished
// TODO(nre): we should temporarily focus the edited element
// here and release the focused viewport after the direct edit
// operation is finished
if (isTouch) {
return;
}
@ -83,7 +88,13 @@ function LabelEditingProvider(eventBus, canvas, directEditing, commandStack, res
}
LabelEditingProvider.$inject = [ 'eventBus', 'canvas', 'directEditing', 'commandStack', 'resizeHandles' ];
LabelEditingProvider.$inject = [
'eventBus',
'canvas',
'directEditing',
'modeling',
'resizeHandles'
];
module.exports = LabelEditingProvider;
@ -119,8 +130,15 @@ LabelEditingProvider.prototype.activate = function(element) {
var options = {};
// tasks
if (isAny(element, [ 'bpmn:Task', 'bpmn:Participant', 'bpmn:Lane', 'bpmn:CallActivity' ]) ||
isCollapsedSubProcess(element)) {
if (
isAny(element, [
'bpmn:Task',
'bpmn:Participant',
'bpmn:Lane',
'bpmn:CallActivity'
]) ||
isCollapsedSubProcess(element)
) {
assign(options, {
centerVertically: true
});
@ -154,7 +172,8 @@ LabelEditingProvider.prototype.activate = function(element) {
*
* @param {djs.model.Base} element
*
* @return {Object} an object containing information about position and size (fixed or minimum and/or maximum)
* @return {Object} an object containing information about position
* and size (fixed or minimum and/or maximum)
*/
LabelEditingProvider.prototype.getEditingBBox = function(element) {
var canvas = this._canvas;
@ -203,7 +222,8 @@ LabelEditingProvider.prototype.getEditingBBox = function(element) {
}
// internal labels for tasks and collapsed call activities, sub processes and participants
// internal labels for tasks and collapsed call activities,
// sub processes and participants
if (isAny(element, [ 'bpmn:Task', 'bpmn:CallActivity']) ||
isCollapsedPool(element) ||
isCollapsedSubProcess(element)) {
@ -288,19 +308,26 @@ LabelEditingProvider.prototype.getEditingBBox = function(element) {
};
LabelEditingProvider.prototype.update = function(element, newLabel, activeContextText, bounds) {
var absoluteElementBBox = this._canvas.getAbsoluteBBox(element);
LabelEditingProvider.prototype.update = function(
element, newLabel,
activeContextText, bounds) {
this._commandStack.execute('element.updateLabel', {
element: element,
newLabel: newLabel,
bounds: {
var newBounds,
bbox;
if (is(element, 'bpmn:TextAnnotation')) {
bbox = this._canvas.getAbsoluteBBox(element);
newBounds = {
x: element.x,
y: element.y,
width: element.width / absoluteElementBBox.width * bounds.width,
height: element.height / absoluteElementBBox.height * bounds.height
}
});
width: element.width / bbox.width * bounds.width,
height: element.height / bbox.height * bounds.height
};
}
this._modeling.updateLabel(element, newLabel, newBounds);
};

View File

@ -54,7 +54,7 @@ function UpdateLabelHandler(modeling) {
function postExecute(ctx) {
var element = ctx.element,
label = element.label || element,
bounds = ctx.bounds;
newBounds = ctx.newBounds;
// ignore internal labels for elements except text annotations
if (!hasExternalLabel(element) && !is(element, 'bpmn:TextAnnotation')) {
@ -65,15 +65,21 @@ function UpdateLabelHandler(modeling) {
var text = bo.name || bo.text;
// don't resize without text
if (!text) {
return;
}
// get layouted text bounds and resize external
// external label accordingly
var newBounds = is(element, 'bpmn:TextAnnotation') ? bounds : getLayoutedBounds(label, text, textUtil);
// resize element based on label _or_ pre-defined bounds
if (typeof newBounds === 'undefined') {
newBounds = getLayoutedBounds(label, text, textUtil);
}
modeling.resizeShape(label, newBounds, NULL_DIMENSIONS);
// setting newBounds to false or _null_ will
// disable the postExecute resize operation
if (newBounds) {
modeling.resizeShape(label, newBounds, NULL_DIMENSIONS);
}
}
// API

View File

@ -1,6 +1,5 @@
module.exports = {
__depends__: [
require('diagram-js/lib/command'),
require('diagram-js/lib/features/change-support'),
require('diagram-js/lib/features/resize'),
require('diagram-js-direct-editing')

View File

@ -13,6 +13,8 @@ var UpdatePropertiesHandler = require('./cmd/UpdatePropertiesHandler'),
IdClaimHandler = require('./cmd/IdClaimHandler'),
SetColorHandler = require('./cmd/SetColorHandler');
var UpdateLabelHandler = require('../label-editing/cmd/UpdateLabelHandler');
/**
* BPMN 2.0 modeling features activator
@ -46,15 +48,17 @@ Modeling.prototype.getHandlers = function() {
handlers['lane.updateRefs'] = UpdateFlowNodeRefsHandler;
handlers['id.updateClaim'] = IdClaimHandler;
handlers['element.setColor'] = SetColorHandler;
handlers['element.updateLabel'] = UpdateLabelHandler;
return handlers;
};
Modeling.prototype.updateLabel = function(element, newLabel) {
Modeling.prototype.updateLabel = function(element, newLabel, newBounds) {
this._commandStack.execute('element.updateLabel', {
element: element,
newLabel: newLabel
newLabel: newLabel,
newBounds: newBounds
});
};

View File

@ -2,7 +2,6 @@ module.exports = {
__init__: [ 'modeling', 'bpmnUpdater' ],
__depends__: [
require('./behavior'),
require('../label-editing'),
require('../rules'),
require('../ordering'),
require('../replace'),

View File

@ -157,7 +157,8 @@ describe('features/auto-place', function() {
coreModule,
modelingModule,
autoPlaceModule,
selectionModule
selectionModule,
labelEditingModule
]
}));

View File

@ -28,7 +28,14 @@ describe('features/editor-actions', function() {
return function() {
beforeEach(bootstrapModeler(xml, { modules: [ bpmnEditorActionsModule, modelingModule, coreModule ] }));
beforeEach(bootstrapModeler(xml, {
modules: [
bpmnEditorActionsModule,
modelingModule,
coreModule
]
}));
it('should move to origin', inject(function(editorActions) {
// given
@ -43,28 +50,42 @@ describe('features/editor-actions', function() {
// then
expect(pick(boundingBox, [ 'x', 'y' ])).to.eql({ x: 0, y: 0 });
}));
};
}
describe('single process', testMoveToOrigin(basicXML));
describe('collaboration', testMoveToOrigin(collaborationXML));
describe('subprocesses', function() {
beforeEach(bootstrapModeler(basicXML, { modules: [ bpmnEditorActionsModule, modelingModule, coreModule ] }));
it('should ignore children of subprocesses', inject(function(editorActions, elementRegistry) {
// given
var startEvent = elementRegistry.get('StartEvent_3'),
startEventParent = getParent(startEvent);
// when
editorActions.trigger('moveToOrigin');
// then
expect(getParent(startEvent)).to.equal(startEventParent);
beforeEach(bootstrapModeler(basicXML, {
modules: [
bpmnEditorActionsModule,
modelingModule,
coreModule
]
}));
it('should ignore children of subprocesses', inject(
function(editorActions, elementRegistry) {
// given
var startEvent = elementRegistry.get('StartEvent_3'),
startEventParent = getParent(startEvent);
// when
editorActions.trigger('moveToOrigin');
// then
expect(getParent(startEvent)).to.equal(startEventParent);
}
));
});
});

View File

@ -7,129 +7,147 @@ var pick = require('lodash/object/pick');
var labelEditingModule = require('lib/features/label-editing'),
coreModule = require('lib/core'),
draggingModule = require('diagram-js/lib/features/dragging'),
modelingModule = require('diagram-js/lib/features/modeling');
modelingModule = require('lib/features/modeling');
describe('features - label-editing preview', function() {
var diagramXML = require('../../../fixtures/bpmn/features/label-editing/labels.bpmn');
var diagramXML = require('./LabelEditing.bpmn');
var testModules = [ labelEditingModule, coreModule, draggingModule, modelingModule ];
beforeEach(bootstrapViewer(diagramXML, {
modules: [
labelEditingModule,
coreModule,
draggingModule,
modelingModule
]
}));
beforeEach(bootstrapViewer(diagramXML, { modules: testModules }));
describe('activate', function() {
it('[external labels AND text annotations ] should add marker to hide element on activate', inject(function(directEditing, elementRegistry) {
it('[external labels AND text annotations ] should add marker to hide element on activate', inject(
function(directEditing, elementRegistry) {
// given
var textAnnotation = elementRegistry.get('TextAnnotation_1');
// given
var textAnnotation = elementRegistry.get('TextAnnotation_1');
// when
directEditing.activate(textAnnotation);
// when
directEditing.activate(textAnnotation);
// then
var gfx = elementRegistry.getGraphics(textAnnotation);
// then
var gfx = elementRegistry.getGraphics(textAnnotation);
expect(gfx.classList.contains('djs-element-hidden')).to.be.true;
}));
expect(gfx.classList.contains('djs-element-hidden')).to.be.true;
}
));
it('[internal labels] should add marker to hide label on activate', inject(function(directEditing, elementRegistry) {
it('[internal labels] should add marker to hide label on activate', inject(
function(directEditing, elementRegistry) {
// given
var task = elementRegistry.get('Task_1');
// given
var task = elementRegistry.get('Task_1');
// when
directEditing.activate(task);
// when
directEditing.activate(task);
// then
var gfx = elementRegistry.getGraphics(task);
// then
var gfx = elementRegistry.getGraphics(task);
expect(gfx.classList.contains('djs-label-hidden')).to.be.true;
}));
expect(gfx.classList.contains('djs-label-hidden')).to.be.true;
}
));
});
describe('resize', function() {
it('[text annotations] should resize preview on resize', inject(function(directEditing, elementRegistry, eventBus, labelEditingPreview) {
it('[text annotations] should resize preview on resize', inject(
function(directEditing, elementRegistry, eventBus, labelEditingPreview) {
// given
var textAnnotation = elementRegistry.get('TextAnnotation_1');
directEditing.activate(textAnnotation);
// given
var textAnnotation = elementRegistry.get('TextAnnotation_1');
directEditing.activate(textAnnotation);
// when
eventBus.fire('directEditing.resize', {
width: 200,
height: 200,
dx: 100,
dy: 100
});
// when
eventBus.fire('directEditing.resize', {
width: 200,
height: 200,
dx: 100,
dy: 100
});
// then
var bounds = bbox(labelEditingPreview.path);
// then
var bounds = bbox(labelEditingPreview.path);
expect(bounds).to.eql({ x: 0, y: 0, width: 10, height: 300 });
}));
expect(bounds).to.eql({ x: 0, y: 0, width: 10, height: 300 });
}
));
it('[text annotations] should resize preview below 0', inject(function(directEditing, elementRegistry, eventBus, labelEditingPreview) {
it('[text annotations] should resize preview below 0', inject(
function(directEditing, elementRegistry, eventBus, labelEditingPreview) {
// given
var textAnnotation = elementRegistry.get('TextAnnotation_1');
directEditing.activate(textAnnotation);
// given
var textAnnotation = elementRegistry.get('TextAnnotation_1');
directEditing.activate(textAnnotation);
// when
eventBus.fire('directEditing.resize', {
width: 200,
height: 200,
dx: -300,
dy: -300
});
// when
eventBus.fire('directEditing.resize', {
width: 200,
height: 200,
dx: -300,
dy: -300
});
// then
var bounds = bbox(labelEditingPreview.path);
// then
var bounds = bbox(labelEditingPreview.path);
expect(bounds).to.eql({ x: 0, y: 0, width: 10, height: 0 });
}));
expect(bounds).to.eql({ x: 0, y: 0, width: 10, height: 0 });
}
));
});
describe('complete/cancel', function() {
it('[external labels AND text annotations] should remove marker to hide element on complete', inject(function(directEditing, elementRegistry) {
it('[external labels AND text annotations] should remove marker to hide element on complete', inject(
function(directEditing, elementRegistry) {
// given
var textAnnotation = elementRegistry.get('TextAnnotation_1');
directEditing.activate(textAnnotation);
// given
var textAnnotation = elementRegistry.get('TextAnnotation_1');
directEditing.activate(textAnnotation);
// when
directEditing.complete();
// when
directEditing.complete();
// then
var gfx = elementRegistry.getGraphics(textAnnotation);
// then
var gfx = elementRegistry.getGraphics(textAnnotation);
expect(gfx.classList.contains('djs-element-hidden')).to.be.false;
}));
expect(gfx.classList.contains('djs-element-hidden')).to.be.false;
}
));
it('[internal labels] should remove marker to hide label on complete', inject(function(directEditing, elementRegistry) {
it('[internal labels] should remove marker to hide label on complete', inject(
function(directEditing, elementRegistry) {
// given
var task = elementRegistry.get('Task_1');
directEditing.activate(task);
// given
var task = elementRegistry.get('Task_1');
directEditing.activate(task);
// when
directEditing.complete();
// when
directEditing.complete();
// then
var gfx = elementRegistry.getGraphics(task);
// then
var gfx = elementRegistry.getGraphics(task);
expect(gfx.classList.contains('djs-label-hidden')).to.be.false;
}));
expect(gfx.classList.contains('djs-label-hidden')).to.be.false;
}
));
});

View File

@ -6,7 +6,7 @@
var labelEditingModule = require('lib/features/label-editing'),
coreModule = require('lib/core'),
draggingModule = require('diagram-js/lib/features/dragging'),
modelingModule = require('diagram-js/lib/features/modeling');
modelingModule = require('lib/features/modeling');
var LabelUtil = require('lib/features/label-editing/LabelUtil');
@ -36,118 +36,138 @@ function expectBounds(parent, bounds) {
describe('features - label-editing', function() {
var diagramXML = require('../../../fixtures/bpmn/features/label-editing/labels.bpmn');
var diagramXML = require('./LabelEditing.bpmn');
describe('basics', function() {
var testModules = [ labelEditingModule, coreModule, draggingModule, modelingModule ];
beforeEach(bootstrapViewer(diagramXML, { modules: testModules }));
it('should register on dblclick', inject(function(elementRegistry, directEditing, eventBus) {
// given
var shape = elementRegistry.get('Task_1');
// when
eventBus.fire('element.dblclick', { element: shape });
// then
expect(directEditing.isActive()).to.be.true;
// clean up
directEditing._textbox.destroy();
beforeEach(bootstrapViewer(diagramXML, {
modules: [
labelEditingModule,
coreModule,
draggingModule,
modelingModule
]
}));
it('should cancel on <ESC>', inject(function(elementRegistry, directEditing, eventBus) {
it('should register on dblclick', inject(
function(elementRegistry, directEditing, eventBus) {
// given
var shape = elementRegistry.get('Task_1'),
task = shape.businessObject;
// given
var shape = elementRegistry.get('Task_1');
var oldName = task.name;
// when
eventBus.fire('element.dblclick', { element: shape });
// activate
eventBus.fire('element.dblclick', { element: shape });
// then
expect(directEditing.isActive()).to.be.true;
var textbox = directEditing._textbox.content;
// when
// change + ESC is pressed
textbox.innerText = 'new value';
triggerKeyEvent(textbox, 'keydown', 27);
// then
expect(directEditing.isActive()).to.be.false;
expect(task.name).to.equal(oldName);
}));
// clean up
directEditing._textbox.destroy();
}
));
it('should complete on drag start', inject(function(elementRegistry, directEditing, dragging) {
it('should cancel on <ESC>', inject(
function(elementRegistry, directEditing, eventBus) {
// given
var shape = elementRegistry.get('Task_1'),
task = shape.businessObject;
// given
var shape = elementRegistry.get('Task_1'),
task = shape.businessObject;
directEditing.activate(shape);
var oldName = task.name;
directEditing._textbox.content.textContent = 'FOO BAR';
// activate
eventBus.fire('element.dblclick', { element: shape });
// when
dragging.init(null, { x: 0, y: 0 }, 'foo');
var textbox = directEditing._textbox.content;
// then
expect(task.name).to.equal('FOO BAR');
}));
// when
// change + ESC is pressed
textbox.innerText = 'new value';
triggerKeyEvent(textbox, 'keydown', 27);
// then
expect(directEditing.isActive()).to.be.false;
expect(task.name).to.equal(oldName);
}
));
it('should submit on root element click', inject(function(elementRegistry, directEditing, canvas, eventBus) {
it('should complete on drag start', inject(
function(elementRegistry, directEditing, dragging) {
// given
var shape = elementRegistry.get('Task_1'),
task = shape.businessObject;
// given
var shape = elementRegistry.get('Task_1'),
task = shape.businessObject;
// activate
eventBus.fire('element.dblclick', { element: shape });
directEditing.activate(shape);
var newName = 'new value';
directEditing._textbox.content.textContent = 'FOO BAR';
// a <textarea /> element
var content = directEditing._textbox.content;
// when
dragging.init(null, { x: 0, y: 0 }, 'foo');
content.innerText = newName;
// then
expect(task.name).to.equal('FOO BAR');
}
));
// when
// change + <element.mousedown>
eventBus.fire('element.mousedown', { element: canvas.getRootElement() });
it('should submit on root element click', inject(
function(elementRegistry, directEditing, canvas, eventBus) {
// then
expect(directEditing.isActive()).to.be.false;
expect(task.name).to.equal(newName);
}));
// given
var shape = elementRegistry.get('Task_1'),
task = shape.businessObject;
// activate
eventBus.fire('element.dblclick', { element: shape });
var newName = 'new value';
// a <textarea /> element
var content = directEditing._textbox.content;
content.innerText = newName;
// when
// change + <element.mousedown>
eventBus.fire('element.mousedown', { element: canvas.getRootElement() });
// then
expect(directEditing.isActive()).to.be.false;
expect(task.name).to.equal(newName);
}
));
});
describe('details', function() {
var testModules = [ labelEditingModule, coreModule, modelingModule ];
beforeEach(bootstrapViewer(diagramXML, { modules: testModules }));
beforeEach(bootstrapViewer(diagramXML, {
modules: [
labelEditingModule,
coreModule,
modelingModule
]
}));
var elementRegistry,
eventBus,
directEditing;
beforeEach(inject([ 'elementRegistry', 'eventBus', 'directEditing', function(_elementRegistry, _eventBus, _directEditing) {
elementRegistry = _elementRegistry;
eventBus = _eventBus;
directEditing = _directEditing;
}]));
beforeEach(inject([
'elementRegistry', 'eventBus', 'directEditing',
function(_elementRegistry, _eventBus, _directEditing) {
elementRegistry = _elementRegistry;
eventBus = _eventBus;
directEditing = _directEditing;
}
]));
function directEditActivate(element) {
@ -351,11 +371,12 @@ describe('features - label-editing', function() {
describe('sizes', function() {
var testModules = [ labelEditingModule, coreModule, modelingModule ];
beforeEach(bootstrapViewer(diagramXML, {
modules: testModules,
modules: [
labelEditingModule,
coreModule,
modelingModule
],
canvas: { deferUpdate: false }
}));
@ -364,268 +385,292 @@ describe('features - label-editing', function() {
describe('external labels', function() {
it('[zoom 1] should have fixed width and element height', inject(function(canvas, directEditing, elementRegistry) {
var zoom = 1;
it('[zoom 1] should have fixed width and element height', inject(
function(canvas, directEditing, elementRegistry) {
var zoom = 1;
canvas.zoom(zoom);
canvas.zoom(zoom);
var startEvent = elementRegistry.get('StartEvent_1');
var startEvent = elementRegistry.get('StartEvent_1');
var bounds = canvas.getAbsoluteBBox(startEvent.label);
var mid = {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2
};
var bounds = canvas.getAbsoluteBBox(startEvent.label);
var mid = {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2
};
directEditing.activate(startEvent);
directEditing.activate(startEvent);
expectBounds(directEditing._textbox.parent, {
x: mid.x - (45 * zoom),
y: bounds.y - (7 * zoom),
width: (90 * zoom),
height: bounds.height + (5 * zoom) + 7
});
}));
expectBounds(directEditing._textbox.parent, {
x: mid.x - (45 * zoom),
y: bounds.y - (7 * zoom),
width: (90 * zoom),
height: bounds.height + (5 * zoom) + 7
});
}
));
it('[zoom 1.5] should have fixed width and element height', inject(function(canvas, directEditing, elementRegistry) {
var zoom = 1.5;
it('[zoom 1.5] should have fixed width and element height', inject(
function(canvas, directEditing, elementRegistry) {
var zoom = 1.5;
canvas.zoom(zoom);
canvas.zoom(zoom);
var startEvent = elementRegistry.get('StartEvent_1');
var startEvent = elementRegistry.get('StartEvent_1');
var bounds = canvas.getAbsoluteBBox(startEvent.label);
var mid = {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2
};
var bounds = canvas.getAbsoluteBBox(startEvent.label);
var mid = {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2
};
directEditing.activate(startEvent);
directEditing.activate(startEvent);
expectBounds(directEditing._textbox.parent, {
x: mid.x - (45 * zoom),
y: bounds.y - (7 * zoom),
width: (90 * zoom),
height: bounds.height + (5 * zoom) + (7 * zoom)
});
}));
expectBounds(directEditing._textbox.parent, {
x: mid.x - (45 * zoom),
y: bounds.y - (7 * zoom),
width: (90 * zoom),
height: bounds.height + (5 * zoom) + (7 * zoom)
});
}
));
});
describe('internal labels', function() {
it('[zoom 1] should have element size', inject(function(canvas, directEditing, elementRegistry) {
var zoom = 1;
it('[zoom 1] should have element size', inject(
function(canvas, directEditing, elementRegistry) {
var zoom = 1;
canvas.zoom(zoom);
canvas.zoom(zoom);
var task = elementRegistry.get('Task_1');
var task = elementRegistry.get('Task_1');
var bounds = canvas.getAbsoluteBBox(task);
var bounds = canvas.getAbsoluteBBox(task);
directEditing.activate(task);
directEditing.activate(task);
expectBounds(directEditing._textbox.parent, bounds);
}));
expectBounds(directEditing._textbox.parent, bounds);
}
));
it('[zoom 1.5] should have element size', inject(function(canvas, directEditing, elementRegistry) {
var zoom = 1.5;
it('[zoom 1.5] should have element size', inject(
function(canvas, directEditing, elementRegistry) {
var zoom = 1.5;
canvas.zoom(zoom);
canvas.zoom(zoom);
var task = elementRegistry.get('Task_1');
var task = elementRegistry.get('Task_1');
var bounds = canvas.getAbsoluteBBox(task);
var bounds = canvas.getAbsoluteBBox(task);
directEditing.activate(task);
directEditing.activate(task);
expectBounds(directEditing._textbox.parent, bounds);
}));
expectBounds(directEditing._textbox.parent, bounds);
}
));
});
describe('sequence flows', function() {
it('[zoom 1] should have fixed width and element height', inject(function(canvas, directEditing, elementRegistry) {
var zoom = 1;
it('[zoom 1] should have fixed width and element height', inject(
function(canvas, directEditing, elementRegistry) {
var zoom = 1;
canvas.zoom(zoom);
canvas.zoom(zoom);
var sequenceFlow = elementRegistry.get('SequenceFlow_1');
var sequenceFlow = elementRegistry.get('SequenceFlow_1');
var bounds = canvas.getAbsoluteBBox(sequenceFlow.label);
var mid = {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2
};
var bounds = canvas.getAbsoluteBBox(sequenceFlow.label);
var mid = {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2
};
directEditing.activate(sequenceFlow);
directEditing.activate(sequenceFlow);
expectBounds(directEditing._textbox.parent, {
x: mid.x - (45 * zoom),
y: bounds.y - (7 * zoom),
width: (90 * zoom),
height: bounds.height + (5 * zoom) + 7
});
}));
expectBounds(directEditing._textbox.parent, {
x: mid.x - (45 * zoom),
y: bounds.y - (7 * zoom),
width: (90 * zoom),
height: bounds.height + (5 * zoom) + 7
});
}
));
it('[zoom 1.5] should have fixed width and element height', inject(function(canvas, directEditing, elementRegistry) {
var zoom = 1.5;
it('[zoom 1.5] should have fixed width and element height', inject(
function(canvas, directEditing, elementRegistry) {
var zoom = 1.5;
canvas.zoom(zoom);
canvas.zoom(zoom);
var sequenceflow = elementRegistry.get('SequenceFlow_1');
var sequenceflow = elementRegistry.get('SequenceFlow_1');
var bounds = canvas.getAbsoluteBBox(sequenceflow.label);
var mid = {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2
};
var bounds = canvas.getAbsoluteBBox(sequenceflow.label);
var mid = {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2
};
directEditing.activate(sequenceflow);
directEditing.activate(sequenceflow);
expectBounds(directEditing._textbox.parent, {
x: mid.x - (45 * zoom),
y: bounds.y - (7 * zoom),
width: (90 * zoom),
height: bounds.height + (5 * zoom) + (7 * zoom)
});
}));
expectBounds(directEditing._textbox.parent, {
x: mid.x - (45 * zoom),
y: bounds.y - (7 * zoom),
width: (90 * zoom),
height: bounds.height + (5 * zoom) + (7 * zoom)
});
}
));
});
describe('text annotations', function() {
it('[zoom 1] should have element size', inject(function(canvas, directEditing, elementRegistry) {
var zoom = 1;
it('[zoom 1] should have element size', inject(
function(canvas, directEditing, elementRegistry) {
var zoom = 1;
canvas.zoom(zoom);
canvas.zoom(zoom);
var textAnnotation = elementRegistry.get('TextAnnotation_1');
var textAnnotation = elementRegistry.get('TextAnnotation_1');
var bounds = canvas.getAbsoluteBBox(textAnnotation);
var bounds = canvas.getAbsoluteBBox(textAnnotation);
directEditing.activate(textAnnotation);
directEditing.activate(textAnnotation);
expectBounds(directEditing._textbox.parent, bounds);
}));
expectBounds(directEditing._textbox.parent, bounds);
}
));
it('[zoom 1.5] should have element size', inject(function(canvas, directEditing, elementRegistry) {
var zoom = 1.5;
it('[zoom 1.5] should have element size', inject(
function(canvas, directEditing, elementRegistry) {
var zoom = 1.5;
canvas.zoom(zoom);
canvas.zoom(zoom);
var textAnnotation = elementRegistry.get('TextAnnotation_1');
var textAnnotation = elementRegistry.get('TextAnnotation_1');
var bounds = canvas.getAbsoluteBBox(textAnnotation);
var bounds = canvas.getAbsoluteBBox(textAnnotation);
directEditing.activate(textAnnotation);
directEditing.activate(textAnnotation);
expectBounds(directEditing._textbox.parent, bounds);
}));
expectBounds(directEditing._textbox.parent, bounds);
}
));
});
describe('expanded sub processes', function() {
it('[zoom 1] should have element width and height to fit text', inject(function(canvas, directEditing, elementRegistry) {
var zoom = 1;
it('[zoom 1] should have element width and height to fit text', inject(
function(canvas, directEditing, elementRegistry) {
var zoom = 1;
canvas.zoom(zoom);
canvas.zoom(zoom);
var subProcess = elementRegistry.get('SubProcess_1');
var subProcess = elementRegistry.get('SubProcess_1');
var bounds = canvas.getAbsoluteBBox(subProcess);
var bounds = canvas.getAbsoluteBBox(subProcess);
directEditing.activate(subProcess);
directEditing.activate(subProcess);
expectBounds(directEditing._textbox.parent, {
x: bounds.x,
y: bounds.y,
width: bounds.width,
height: (MEDIUM_LINE_HEIGHT * zoom) + (7 * 2 * zoom)
});
}));
expectBounds(directEditing._textbox.parent, {
x: bounds.x,
y: bounds.y,
width: bounds.width,
height: (MEDIUM_LINE_HEIGHT * zoom) + (7 * 2 * zoom)
});
}
));
it('[zoom 1.5] should have element width and height to fit text', inject(function(canvas, directEditing, elementRegistry) {
var zoom = 1.5;
it('[zoom 1.5] should have element width and height to fit text', inject(
function(canvas, directEditing, elementRegistry) {
var zoom = 1.5;
canvas.zoom(zoom);
canvas.zoom(zoom);
var subProcess = elementRegistry.get('SubProcess_1');
var subProcess = elementRegistry.get('SubProcess_1');
var bounds = canvas.getAbsoluteBBox(subProcess);
var bounds = canvas.getAbsoluteBBox(subProcess);
directEditing.activate(subProcess);
directEditing.activate(subProcess);
expectBounds(directEditing._textbox.parent, {
x: bounds.x,
y: bounds.y,
width: bounds.width,
height: (MEDIUM_LINE_HEIGHT * zoom) + (7 * 2 * zoom)
});
}));
expectBounds(directEditing._textbox.parent, {
x: bounds.x,
y: bounds.y,
width: bounds.width,
height: (MEDIUM_LINE_HEIGHT * zoom) + (7 * 2 * zoom)
});
}
));
});
describe('pools/lanes', function() {
it('[zoom 1] should have width of element height, height of 30', inject(function(canvas, directEditing, elementRegistry) {
var zoom = 1;
it('[zoom 1] should have width of element height, height of 30', inject(
function(canvas, directEditing, elementRegistry) {
var zoom = 1;
canvas.zoom(zoom);
canvas.zoom(zoom);
var pool = elementRegistry.get('Participant_1');
var pool = elementRegistry.get('Participant_1');
var bounds = canvas.getAbsoluteBBox(pool);
var mid = {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2
};
var bounds = canvas.getAbsoluteBBox(pool);
var mid = {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2
};
directEditing.activate(pool);
directEditing.activate(pool);
expectBounds(directEditing._textbox.parent, {
x: bounds.x - (bounds.height / 2) + (15 * zoom),
y: mid.y - (30 * zoom) / 2,
width: bounds.height * zoom,
height: 30 * zoom
});
}));
expectBounds(directEditing._textbox.parent, {
x: bounds.x - (bounds.height / 2) + (15 * zoom),
y: mid.y - (30 * zoom) / 2,
width: bounds.height * zoom,
height: 30 * zoom
});
}
));
it('[zoom 1.5] should have width of element height, height of 30', inject(function(canvas, directEditing, elementRegistry) {
var zoom = 1.5;
it('[zoom 1.5] should have width of element height, height of 30', inject(
function(canvas, directEditing, elementRegistry) {
var zoom = 1.5;
canvas.zoom(zoom);
canvas.zoom(zoom);
var pool = elementRegistry.get('Participant_1');
var pool = elementRegistry.get('Participant_1');
var bounds = canvas.getAbsoluteBBox(pool);
var mid = {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2
};
var bounds = canvas.getAbsoluteBBox(pool);
var mid = {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2
};
directEditing.activate(pool);
directEditing.activate(pool);
expectBounds(directEditing._textbox.parent, {
x: bounds.x - (bounds.height / 2) + (15 * zoom),
y: mid.y - (30 * zoom) / 2,
width: bounds.height,
height: 30 * zoom
});
}));
expectBounds(directEditing._textbox.parent, {
x: bounds.x - (bounds.height / 2) + (15 * zoom),
y: mid.y - (30 * zoom) / 2,
width: bounds.height,
height: 30 * zoom
});
}
));
});

View File

@ -33,7 +33,7 @@ describe('direct editing - touch integration', function() {
it('should edit labels via double tap (manual test)', function(done) {
var xml = require('../../../fixtures/bpmn/features/label-editing/labels.bpmn');
var xml = require('./LabelEditing.bpmn');
createModeler(xml, done);
});

View File

@ -1,9 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="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="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="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" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:startEvent id="StartEvent_1" name="Foo" />
<bpmn:startEvent id="StartEvent_2" />
<bpmn:task id="Task_1" />
<bpmn:textAnnotation id="TextAnnotation_1">
<bpmn:text></bpmn:text>
</bpmn:textAnnotation>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
@ -19,6 +22,9 @@
<bpmndi:BPMNShape id="Task_16agoun_di" bpmnElement="Task_1">
<dc:Bounds x="339" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="TextAnnotation_1_di" bpmnElement="TextAnnotation_1">
<dc:Bounds x="426" y="220" width="100" height="30" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -8,68 +8,79 @@ var modelingModule = require('lib/features/modeling'),
describe('features/modeling - update label', function() {
var diagramXML = require('../../../fixtures/bpmn/features/modeling/update-label.bpmn');
var diagramXML = require('./UpdateLabel.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: [ coreModule, modelingModule ]
modules: [
coreModule,
modelingModule
]
}));
it('should change name of start event', inject(function(modeling, elementRegistry, eventBus) {
it('should change name of start event', inject(
function(modeling, elementRegistry, eventBus) {
// given
var startEvent_1 = elementRegistry.get('StartEvent_1');
// given
var startEvent_1 = elementRegistry.get('StartEvent_1');
// when
modeling.updateLabel(startEvent_1, 'bar');
// when
modeling.updateLabel(startEvent_1, 'bar');
// then
expect(startEvent_1.businessObject.name).to.equal('bar');
expect(startEvent_1.label.hidden).to.be.false;
}));
// then
expect(startEvent_1.businessObject.name).to.equal('bar');
expect(startEvent_1.label.hidden).to.be.false;
}
));
it('should change name of start event with hidden label', inject(function(modeling, elementRegistry) {
it('should change name of start event with hidden label', inject(
function(modeling, elementRegistry) {
// given
var startEvent_2 = elementRegistry.get('StartEvent_2');
// given
var startEvent_2 = elementRegistry.get('StartEvent_2');
// when
modeling.updateLabel(startEvent_2, 'bar');
// when
modeling.updateLabel(startEvent_2, 'bar');
// then
expect(startEvent_2.businessObject.name).to.equal('bar');
expect(startEvent_2.label.hidden).to.be.false;
}));
// then
expect(startEvent_2.businessObject.name).to.equal('bar');
expect(startEvent_2.label.hidden).to.be.false;
}
));
it('should hide label when setting empty string', inject(function(modeling, elementRegistry) {
it('should hide label when setting empty string', inject(
function(modeling, elementRegistry) {
// given
var startEvent_1 = elementRegistry.get('StartEvent_1');
// given
var startEvent_1 = elementRegistry.get('StartEvent_1');
// when
modeling.updateLabel(startEvent_1, '');
// when
modeling.updateLabel(startEvent_1, '');
// then
expect(startEvent_1.businessObject.name).to.equal('');
expect(startEvent_1.label.hidden).to.be.true;
}));
// then
expect(startEvent_1.businessObject.name).to.equal('');
expect(startEvent_1.label.hidden).to.be.true;
}
));
it('should change name of start event when editing label', inject(function(modeling, elementRegistry) {
it('should change name of start event when editing label', inject(
function(modeling, elementRegistry) {
// given
var startEvent_1 = elementRegistry.get('StartEvent_1');
var startEvent_1_label = elementRegistry.get('StartEvent_1_label');
// given
var startEvent_1 = elementRegistry.get('StartEvent_1');
var startEvent_1_label = elementRegistry.get('StartEvent_1_label');
// when
modeling.updateLabel(startEvent_1_label, 'bar');
// when
modeling.updateLabel(startEvent_1_label, 'bar');
// then
expect(startEvent_1.businessObject.name).to.equal('bar');
expect(startEvent_1.label.hidden).to.be.false;
}));
// then
expect(startEvent_1.businessObject.name).to.equal('bar');
expect(startEvent_1.label.hidden).to.be.false;
}
));
it('should change name of task', inject(function(modeling, elementRegistry) {
@ -86,8 +97,26 @@ describe('features/modeling - update label', function() {
}));
it('should propertly fire events.changed after event name change',
inject(function(modeling, elementRegistry, eventBus) {
it('should change text annotation text and bounds', inject(
function(modeling, elementRegistry) {
// given
var element = elementRegistry.get('TextAnnotation_1');
var newBounds = { x: 100, y: 100, width: 100, height: 30 };
// when
modeling.updateLabel(element, 'bar', newBounds);
// then
expect(element.businessObject.text).to.equal('bar');
expect(element).to.have.bounds(newBounds);
}
));
it('should propertly fire events.changed after event name change', inject(
function(modeling, elementRegistry, eventBus) {
// given
var startEvent_1 = elementRegistry.get('StartEvent_1');
@ -103,12 +132,12 @@ describe('features/modeling - update label', function() {
// then
expect(changedEvent.elements).to.include(startEvent_1);
})
);
}
));
it('should propertly fire events.changed after event label change',
inject(function(modeling, elementRegistry, eventBus) {
it('should propertly fire events.changed after event label change', inject(
function(modeling, elementRegistry, eventBus) {
// given
var startEvent_1 = elementRegistry.get('StartEvent_1');
@ -125,7 +154,7 @@ describe('features/modeling - update label', function() {
// then
expect(changedEvent.elements).to.include(startEvent_1);
})
);
}
));
});