feat(modeler): add label editing

Related to #7
This commit is contained in:
Nico Rehwaldt 2014-06-11 15:08:45 +02:00
parent 4e00114409
commit 73fbeb3d27
10 changed files with 260 additions and 28 deletions

View File

@ -9,6 +9,30 @@ module.exports = function(grunt) {
// any of [ 'PhantomJS', 'Chrome', 'Firefox', 'IE'] // any of [ 'PhantomJS', 'Chrome', 'Firefox', 'IE']
var TEST_BROWSERS = ((process.env.TEST_BROWSERS || '').replace(/^\s+|\s+$/, '') || 'PhantomJS').split(/\s*,\s*/g); var TEST_BROWSERS = ((process.env.TEST_BROWSERS || '').replace(/^\s+|\s+$/, '') || 'PhantomJS').split(/\s*,\s*/g);
function bundleAlias(components) {
var alias = [];
if (components.indexOf('libs-external') >= 0) {
alias.push('node_modules/jquery:jquery');
alias.push('node_modules/lodash:lodash');
}
if (components.indexOf('libs-local') >= 0) {
alias.push('node_modules/bpmn-moddle:bpmn-moddle');
}
if (components.indexOf('viewer') >= 0) {
alias.push('index.js:bpmn-js');
alias.push('<%= config.sources %>/Viewer.js:bpmn-js/Viewer');
}
if (components.indexOf('modeler') >= 0) {
alias.push('<%= config.sources %>/Modeler.js:bpmn-js/Modeler');
}
return alias;
}
// project configuration // project configuration
grunt.initConfig({ grunt.initConfig({
@ -80,22 +104,13 @@ module.exports = function(grunt) {
browserify: { browserify: {
options: { options: {
browserifyOptions: { browserifyOptions: {
builtins: false, builtins: false
commondir: false
}, },
bundleOptions: { bundleOptions: {
detectGlobals: false, detectGlobals: false,
insertGlobalVars: [], insertGlobalVars: [],
debug: true debug: true
}, }
alias: [
'node_modules/jquery:jquery',
'node_modules/lodash:lodash',
'node_modules/bpmn-moddle:bpmn-moddle',
'<%= config.sources %>/main.js:bpmn-js',
'<%= config.sources %>/Viewer.js:bpmn-js/Viewer',
'<%= config.sources %>/Modeler.js:bpmn-js/Modeler'
]
}, },
watch: { watch: {
files: { files: {
@ -103,13 +118,38 @@ module.exports = function(grunt) {
'<%= config.dist %>/bpmn-viewer.js': [ '<%= config.sources %>/lib/Viewer.js' ] '<%= config.dist %>/bpmn-viewer.js': [ '<%= config.sources %>/lib/Viewer.js' ]
}, },
options: { options: {
watch: true watch: true,
alias: bundleAlias([
'viewer',
'modeler',
'libs-external',
'libs-local'
])
} }
}, },
lib: { standaloneViewer: {
files: {
'<%= config.dist %>/bpmn-viewer.js': [ '<%= config.sources %>/lib/Viewer.js' ]
},
options: {
alias: bundleAlias([
'viewer',
'libs-external',
'libs-local'
])
}
},
standaloneModeler: {
files: { files: {
'<%= config.dist %>/bpmn.js': [ '<%= config.sources %>/**/*.js' ], '<%= config.dist %>/bpmn.js': [ '<%= config.sources %>/**/*.js' ],
'<%= config.dist %>/bpmn-viewer.js': [ '<%= config.sources %>/lib/Viewer.js' ] },
options: {
alias: bundleAlias([
'viewer',
'modeler',
'libs-external',
'libs-local'
])
} }
} }
}, },
@ -225,7 +265,7 @@ module.exports = function(grunt) {
tasks.push('uglify:modeler', 'uglify:viewer'); tasks.push('uglify:modeler', 'uglify:viewer');
} }
return grunt.task.run(['browserify:lib'].concat(tasks)); return grunt.task.run(['browserify:standaloneViewer', 'browserify:standaloneModeler'].concat(tasks));
} }
if (target === 'samples') { if (target === 'samples') {

View File

@ -25,6 +25,7 @@ Modeler.prototype.createDiagram = function(modules) {
Modeler.modules = [ Modeler.modules = [
// TODO (nre): buggy in conjunction with zoomscroll / move canvas // TODO (nre): buggy in conjunction with zoomscroll / move canvas
// require('diagram-js/lib/features/move'), // require('diagram-js/lib/features/move'),
require('./features/label-editing'),
require('./core'), require('./core'),
require('./features/zoomscroll'), require('./features/zoomscroll'),
require('./features/movecanvas') require('./features/movecanvas')

View File

@ -0,0 +1,90 @@
'use strict';
var UpdateTextHandler = require('./cmd/UpdateTextHandler');
function LabelEditingProvider(eventBus, canvas, directEditing, commandStack, bpmnRegistry) {
directEditing.registerProvider(this);
commandStack.registerHandler('bpmnElement.updateText', UpdateTextHandler);
// per default, listen to double click events
eventBus.on('shape.dblclick', function(event) {
directEditing.activate(event.element);
}.bind(this));
// intercept direct canvas clicks to deselect all
// selected shapes
eventBus.on('canvas.click', function(event) {
directEditing.complete();
});
this._bpmnRegistry = bpmnRegistry;
this._canvas = canvas;
this._commandStack = commandStack;
}
LabelEditingProvider.prototype.activate = function(element) {
var semantic = this._bpmnRegistry.getSemantic(element);
var text;
if (semantic.$instanceOf('bpmn:Pool') ||
semantic.$instanceOf('bpmn:Lane')) {
// TODO: Editing for pool / lane
}
if (semantic.$instanceOf('bpmn:TextAnnotation')) {
text = semantic.text;
}
if (semantic.$instanceOf('bpmn:FlowElement')) {
text = semantic.name;
}
var bbox = this.getEditingBBox(element);
if (semantic) {
return { bounds: bbox, text: text };
}
};
LabelEditingProvider.prototype.getEditingBBox = function(element) {
var bbox = this._canvas.getAbsoluteBBox(element.label || element);
var mid = {
x: bbox.x + bbox.width / 2,
y: bbox.y + bbox.height / 2
};
var minWidth = 150;
var minHeight = 100;
bbox.width = Math.max(bbox.width, minWidth);
bbox.height = Math.max(bbox.height, minHeight);
bbox.x = mid.x - bbox.width / 2;
bbox.y = mid.y - bbox.height / 2;
return bbox;
};
LabelEditingProvider.prototype.update = function(element, newText, oldText) {
this._commandStack.execute('bpmnElement.updateText', {
element: element,
oldText: oldText,
newText: newText
});
};
LabelEditingProvider.$inject = [ 'eventBus', 'canvas', 'directEditing', 'commandStack', 'bpmnRegistry' ];
module.exports = LabelEditingProvider;

View File

@ -0,0 +1,51 @@
'use strict';
/**
* A handler that updates the text a BPMN element.
*
* @param {EventBus} eventBus
* @param {BpmnRegistry} bpmnRegistry
* @param {ElementRegistry} elementRegistry
*/
function UpdateTextHandler(eventBus, bpmnRegistry, elementRegistry) {
function setText(element, text) {
var semantic = bpmnRegistry.getSemantic(element);
if (semantic.$instanceOf('bpmn:TextAnnotation')) {
semantic.text = text;
}
if (semantic.$instanceOf('bpmn:FlowElement')) {
semantic.name = text;
}
eventBus.fire('shape.changed', { element: element.label || element });
}
function execute(ctx) {
setText(ctx.element, ctx.newText);
}
function revert(ctx) {
setText(ctx.element, ctx.oldText);
}
function canExecute(ctx) {
return true;
}
// API
this.execute = execute;
this.revert = revert;
this.canExecute = canExecute;
}
UpdateTextHandler.$inject = [ 'eventBus', 'bpmnRegistry' ];
module.exports = UpdateTextHandler;

View File

@ -0,0 +1,8 @@
module.exports = {
__depends__: [
require('../../core'),
require('diagram-js-direct-editing')
],
__init__: [ 'labelEditingProvider' ],
labelEditingProvider: [ 'type', require('./LabelEditingProvider') ]
};

View File

@ -48,26 +48,23 @@
"karma-phantomjs-launcher": "0.1.2", "karma-phantomjs-launcher": "0.1.2",
"karma-ie-launcher": "~0.1.4", "karma-ie-launcher": "~0.1.4",
"karma-firefox-launcher": "~0.1.3", "karma-firefox-launcher": "~0.1.3",
"karma-bro": "~0.1.0", "karma-bro": "~0.2.0",
"jsondiffpatch": "~0.1.4", "jsondiffpatch": "~0.1.4",
"xsd-schema-validator": "0.0.3",
"sax": "~0.6.0",
"brfs": "~1.0.0", "brfs": "~1.0.0",
"lodash": "~2.4.0",
"didi": "~0.0.4",
"jquery": "~2.1.0",
"jquery-mousewheel": "~3.1.11",
"through": "~2.3.4" "through": "~2.3.4"
}, },
"dependencies": { "dependencies": {
"bpmn-moddle": "~0.0.1", "bpmn-moddle": "~0.0.1",
"moddle": "~0.0.5", "diagram-js": "~0.1.0",
"diagram-js": "~0.1.0" "diagram-js-direct-editing": "0.0.1",
},
"peerDependencies": {
"lodash": "~2.4.0",
"didi": "~0.0.4", "didi": "~0.0.4",
"jquery": "~2.1.0", "jquery": "~2.1.0",
"jquery-mousewheel": "~3.1.11" "jquery-mousewheel": "~3.1.11",
"lodash": "~2.4.0"
},
"browser": {
"lodash": "./vendor/lodash.js",
"jquery": "./vendor/jquery.js",
"jquery-mousewheel": "./vendor/jquery-mousewheel.js"
} }
} }

View File

@ -0,0 +1,33 @@
'use strict'
var fs = require('fs');
var Modeler = require('../../../../../lib/Modeler');
var Matchers = require('../../../Matchers');
describe('features/label-editing', function() {
beforeEach(Matchers.add);
var container;
beforeEach(function() {
container = document.createElement('div');
document.getElementsByTagName('body')[0].appendChild(container);
});
it('should register on dblclick', function(done) {
done();
});
it('should save on escape', function(done) {
done();
});
});

10
vendor/jquery-mousewheel.js vendored Normal file
View File

@ -0,0 +1,10 @@
'use strict';
var $;
if (!window.$) {
$ = require('jquery');
require('../node_modules/jquery-mousewheel')($);
}
module.exports = window.$ || $;

1
vendor/jquery.js vendored Normal file
View File

@ -0,0 +1 @@
module.exports = window.$ || require('../node_modules/jquery');

1
vendor/lodash.js vendored Normal file
View File

@ -0,0 +1 @@
module.exports = window._ || require('../node_modules/lodash');