From a2f33b8e932357af2348a2190d611568c8eeef65 Mon Sep 17 00:00:00 2001 From: Philipp Fromme Date: Mon, 28 Nov 2016 14:26:42 +0100 Subject: [PATCH] feat(modeling): add API for setting fill/stroke color Closes #629 --- lib/features/modeling/Modeling.js | 15 +- lib/features/modeling/cmd/SetColorHandler.js | 43 ++ .../modeling/cmd/UpdatePropertiesHandler.js | 46 +- test/spec/features/modeling/SetColorSpec.js | 457 ++++++++++++++++++ .../features/modeling/UpdatePropertiesSpec.js | 27 ++ 5 files changed, 581 insertions(+), 7 deletions(-) create mode 100644 lib/features/modeling/cmd/SetColorHandler.js create mode 100644 test/spec/features/modeling/SetColorSpec.js diff --git a/lib/features/modeling/Modeling.js b/lib/features/modeling/Modeling.js index 3cad95db..69d031b1 100644 --- a/lib/features/modeling/Modeling.js +++ b/lib/features/modeling/Modeling.js @@ -10,7 +10,8 @@ var UpdatePropertiesHandler = require('./cmd/UpdatePropertiesHandler'), SplitLaneHandler = require('./cmd/SplitLaneHandler'), ResizeLaneHandler = require('./cmd/ResizeLaneHandler'), UpdateFlowNodeRefsHandler = require('./cmd/UpdateFlowNodeRefsHandler'), - IdClaimHandler = require('./cmd/IdClaimHandler'); + IdClaimHandler = require('./cmd/IdClaimHandler'), + SetColorHandler = require('./cmd/SetColorHandler'); /** @@ -44,6 +45,7 @@ Modeling.prototype.getHandlers = function() { handlers['lane.split'] = SplitLaneHandler; handlers['lane.updateRefs'] = UpdateFlowNodeRefsHandler; handlers['id.updateClaim'] = IdClaimHandler; + handlers['element.setColor'] = SetColorHandler; return handlers; }; @@ -164,3 +166,14 @@ Modeling.prototype.unclaimId = function(id, moddleElement) { element: moddleElement }); }; + +Modeling.prototype.setColor = function(elements, colors) { + if (!elements.length) { + elements = [ elements ]; + } + + this._commandStack.execute('element.setColor', { + elements: elements, + colors: colors + }); +}; diff --git a/lib/features/modeling/cmd/SetColorHandler.js b/lib/features/modeling/cmd/SetColorHandler.js new file mode 100644 index 00000000..8a41263e --- /dev/null +++ b/lib/features/modeling/cmd/SetColorHandler.js @@ -0,0 +1,43 @@ +'use strict'; + +var assign = require('lodash/object/assign'), + forEach = require('lodash/collection/forEach'); + +function SetColorHandler(commandStack) { + this._commandStack = commandStack; +} + +SetColorHandler.$inject = [ 'commandStack' ]; + +module.exports = SetColorHandler; + +SetColorHandler.prototype.postExecute = function(context) { + var elements = context.elements, + colors = context.colors || { fill: undefined, stroke: undefined }; + + var that = this; + + var di = {}; + + if ('fill' in colors) { + assign(di, { fill: colors.fill }); + } + + if ('stroke' in colors) { + assign(di, { stroke: colors.stroke }); + } + + forEach(elements, function(element) { + that._commandStack.execute('element.updateProperties', { + element: element, + properties: { + di: di + } + }); + }); + +}; + +SetColorHandler.prototype.execute = function(context) {}; + +SetColorHandler.prototype.revert = function(context) {}; diff --git a/lib/features/modeling/cmd/UpdatePropertiesHandler.js b/lib/features/modeling/cmd/UpdatePropertiesHandler.js index 06e10997..92b72ed1 100644 --- a/lib/features/modeling/cmd/UpdatePropertiesHandler.js +++ b/lib/features/modeling/cmd/UpdatePropertiesHandler.js @@ -9,7 +9,8 @@ var getBusinessObject = require('../../../util/ModelUtil').getBusinessObject; var DEFAULT_FLOW = 'default', NAME = 'name', - ID = 'id'; + ID = 'id', + DI = 'di'; /** @@ -47,7 +48,7 @@ module.exports = UpdatePropertiesHandler; UpdatePropertiesHandler.prototype.execute = function(context) { var element = context.element, - changed = [ element], + changed = [ element ], translate = this._translate; if (!element) { @@ -59,7 +60,7 @@ UpdatePropertiesHandler.prototype.execute = function(context) { var businessObject = element.businessObject, properties = unwrapBusinessObjects(context.properties), - oldProperties = context.oldProperties || getProperties(businessObject, keys(properties)); + oldProperties = context.oldProperties || getProperties(businessObject, properties); if (isIdChange(properties, businessObject)) { ids.unclaim(businessObject[ID]); @@ -88,6 +89,10 @@ UpdatePropertiesHandler.prototype.execute = function(context) { element.label.hidden = !properties[NAME]; } + if (DI in properties && businessObject.di) { + setDiProperties(businessObject.di, properties.di); + } + // update properties setProperties(businessObject, properties); @@ -115,6 +120,10 @@ UpdatePropertiesHandler.prototype.revert = function(context) { elementRegistry = this._elementRegistry, ids = this._moddle.ids; + if (DI in oldProperties && businessObject.di) { + setDiProperties(businessObject.di, oldProperties.di); + } + // update properties setProperties(businessObject, oldProperties); @@ -135,9 +144,27 @@ function isIdChange(properties, businessObject) { } -function getProperties(businessObject, propertyNames) { +function getProperties(businessObject, properties) { + var propertyNames = keys(properties); + return reduce(propertyNames, function(result, key) { - result[key] = businessObject.get(key); + + // handle DI seperately + if (key !== DI) { + result[key] = businessObject.get(key); + } else { + result[key] = getDiProperties(businessObject.di, keys(properties.di)); + } + + return result; + }, {}); +} + + +function getDiProperties(di, propertyNames) { + return reduce(propertyNames, function(result, key) { + result[key] = di.get(key); + return result; }, {}); } @@ -150,6 +177,13 @@ function setProperties(businessObject, properties) { } +function setDiProperties(di, properties) { + forEach(properties, function(value, key) { + di.set(key, value); + }); +} + + var referencePropertyNames = [ 'default' ]; /** @@ -172,4 +206,4 @@ function unwrapBusinessObjects(properties) { }); return unwrappedProps; -} \ No newline at end of file +} diff --git a/test/spec/features/modeling/SetColorSpec.js b/test/spec/features/modeling/SetColorSpec.js new file mode 100644 index 00000000..fdf83dda --- /dev/null +++ b/test/spec/features/modeling/SetColorSpec.js @@ -0,0 +1,457 @@ +'use strict'; + +require('../../../TestHelper'); + +/* global bootstrapModeler, inject */ + + +var modelingModule = require('../../../../lib/features/modeling'), + coreModule = require('../../../../lib/core'); + + +describe('features/modeling - set color', function() { + + var diagramXML = require('../../../fixtures/bpmn/simple.bpmn'); + + var testModules = [ coreModule, modelingModule ]; + + beforeEach(bootstrapModeler(diagramXML, { modules: testModules })); + + + describe('execute', function() { + + + it('setting fill color', inject(function(elementRegistry, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + + // when + modeling.setColor(taskShape, { fill: 'FUCHSIA' }); + + // then + expect(taskShape.businessObject.di.fill).to.equal('FUCHSIA'); + })); + + + it('unsetting fill color', inject(function(elementRegistry, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + modeling.setColor(taskShape, { fill: 'FUCHSIA' }); + + // when + modeling.setColor(taskShape); + + // then + expect(taskShape.businessObject.di.fill).not.to.exist; + })); + + + it('setting fill color without changing stroke color', inject(function(elementRegistry, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + modeling.setColor(taskShape, { fill: 'FUCHSIA', stroke: 'YELLOW' }); + + // when + modeling.setColor(taskShape, { fill: 'YELLOW' }); + + // then + expect(taskShape.businessObject.di.fill).to.equal('YELLOW'); + expect(taskShape.businessObject.di.stroke).to.equal('YELLOW'); + })); + + + it('unsetting fill color without changing stroke color', inject(function(elementRegistry, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + modeling.setColor(taskShape, { fill: 'FUCHSIA', stroke: 'YELLOW' }); + + // when + modeling.setColor(taskShape, { fill: undefined }); + + // then + expect(taskShape.businessObject.di.fill).not.to.exist; + expect(taskShape.businessObject.di.stroke).to.equal('YELLOW'); + })); + + it('unsetting both fill and stroke color', inject(function(elementRegistry, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + modeling.setColor(taskShape, { fill: 'FUCHSIA' }); + + // when + modeling.setColor(taskShape); + + // then + expect(taskShape.businessObject.di.fill).not.to.exist; + expect(taskShape.businessObject.di.stroke).not.to.exist; + })); + + + it('setting stroke color', inject(function(elementRegistry, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + + // when + modeling.setColor(taskShape, { stroke: 'FUCHSIA' }); + + // then + expect(taskShape.businessObject.di.stroke).to.equal('FUCHSIA'); + expect(taskShape.businessObject.di.fill).not.to.exist; + })); + + + it('unsetting stroke color', inject(function(elementRegistry, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + modeling.setColor(taskShape, { stroke: 'FUCHSIA' }); + + // when + modeling.setColor(taskShape); + + // then + expect(taskShape.businessObject.di.stroke).not.to.exist; + expect(taskShape.businessObject.di.fill).not.to.exist; + })); + + + it('setting fill color (multiple elements)', inject(function(elementRegistry, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + var startEventShape = elementRegistry.get('StartEvent_1'); + + // when + modeling.setColor([ taskShape, startEventShape ], { fill: 'FUCHSIA' }); + + // then + expect(taskShape.businessObject.di.fill).to.equal('FUCHSIA'); + expect(startEventShape.businessObject.di.fill).to.equal('FUCHSIA'); + expect(taskShape.businessObject.di.stroke).not.to.exist; + expect(startEventShape.businessObject.di.stroke).not.to.exist; + })); + + + it('unsetting fill color (multiple elements)', inject(function(elementRegistry, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + var startEventShape = elementRegistry.get('StartEvent_1'); + modeling.setColor([ taskShape, startEventShape ], { fill: 'FUCHSIA' }); + + // when + modeling.setColor([ taskShape, startEventShape ]); + + // then + expect(taskShape.businessObject.di.fill).not.to.exist; + expect(startEventShape.businessObject.di.fill).not.to.exist; + })); + + + it('setting stroke color (multiple elements)', inject(function(elementRegistry, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + var startEventShape = elementRegistry.get('StartEvent_1'); + + // when + modeling.setColor([ taskShape, startEventShape ], { stroke: 'FUCHSIA' }); + + // then + expect(taskShape.businessObject.di.stroke).to.equal('FUCHSIA'); + expect(startEventShape.businessObject.di.stroke).to.equal('FUCHSIA'); + expect(taskShape.businessObject.di.fill).not.to.exist; + expect(startEventShape.businessObject.di.fill).not.to.exist; + })); + + + it('unsetting stroke color (multiple elements)', inject(function(elementRegistry, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + var startEventShape = elementRegistry.get('StartEvent_1'); + modeling.setColor([ taskShape, startEventShape ], { stroke: 'FUCHSIA' }); + + // when + modeling.setColor([ taskShape, startEventShape ]); + + // then + expect(taskShape.businessObject.di.stroke).not.to.exist; + expect(startEventShape.businessObject.di.stroke).not.to.exist; + })); + + }); + + + describe('undo', function() { + + + it('setting fill color', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + + // when + modeling.setColor(taskShape, { fill: 'FUCHSIA' }); + commandStack.undo(); + + // then + expect(taskShape.businessObject.di.fill).not.to.exist; + })); + + + it('unsetting fill color', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + modeling.setColor(taskShape, { fill: 'FUCHSIA' }); + + // when + modeling.setColor(taskShape); + commandStack.undo(); + + // then + expect(taskShape.businessObject.di.fill).to.equal('FUCHSIA'); + })); + + + it('setting stroke color', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + + // when + modeling.setColor(taskShape, { stroke: 'FUCHSIA' }); + commandStack.undo(); + + // then + expect(taskShape.businessObject.di.stroke).not.to.exist; + })); + + + it('unsetting stroke color', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + modeling.setColor(taskShape, { stroke: 'FUCHSIA' }); + + // when + modeling.setColor(taskShape); + commandStack.undo(); + + // then + expect(taskShape.businessObject.di.stroke).to.equal('FUCHSIA'); + })); + + + it('setting fill color (multiple elements)', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + var startEventShape = elementRegistry.get('StartEvent_1'); + + // when + modeling.setColor([ taskShape, startEventShape ], { fill: 'FUCHSIA' }); + commandStack.undo(); + + // then + expect(taskShape.businessObject.di.fill).not.to.exist; + expect(startEventShape.businessObject.di.fill).not.to.exist; + })); + + + it('unsetting fill color (multiple elements)', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + var startEventShape = elementRegistry.get('StartEvent_1'); + modeling.setColor([ taskShape, startEventShape ], { fill: 'FUCHSIA' }); + + // when + modeling.setColor([ taskShape, startEventShape ]); + commandStack.undo(); + + // then + expect(taskShape.businessObject.di.fill).to.equal('FUCHSIA'); + expect(startEventShape.businessObject.di.fill).to.equal('FUCHSIA'); + })); + + + it('setting stroke color (multiple elements)', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + var startEventShape = elementRegistry.get('StartEvent_1'); + + // when + modeling.setColor([ taskShape, startEventShape ], { stroke: 'FUCHSIA' }); + commandStack.undo(); + + // then + expect(taskShape.businessObject.di.stroke).not.to.exist; + expect(startEventShape.businessObject.di.stroke).not.to.exist; + })); + + + it('unsetting stroke color (multiple elements)', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + var startEventShape = elementRegistry.get('StartEvent_1'); + modeling.setColor([ taskShape, startEventShape ], { stroke: 'FUCHSIA' }); + + // when + modeling.setColor([ taskShape, startEventShape ]); + commandStack.undo(); + + // then + expect(taskShape.businessObject.di.stroke).to.equal('FUCHSIA'); + expect(startEventShape.businessObject.di.stroke).to.equal('FUCHSIA'); + })); + + }); + + + describe('redo', function() { + + + it('setting fill color', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + + // when + modeling.setColor(taskShape, { fill: 'FUCHSIA' }); + commandStack.undo(); + commandStack.redo(); + + // then + expect(taskShape.businessObject.di.fill).to.equal('FUCHSIA'); + })); + + + it('unsetting fill color', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + modeling.setColor(taskShape, { fill: 'FUCHSIA' }); + + // when + modeling.setColor(taskShape); + commandStack.undo(); + commandStack.redo(); + + // then + expect(taskShape.businessObject.di.fill).not.to.exist; + })); + + + it('setting stroke color', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + + // when + modeling.setColor(taskShape, { stroke: 'FUCHSIA' }); + commandStack.undo(); + commandStack.redo(); + + // then + expect(taskShape.businessObject.di.stroke).to.equal('FUCHSIA'); + })); + + + it('unsetting stroke color', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + modeling.setColor(taskShape, { stroke: 'FUCHSIA' }); + + // when + modeling.setColor(taskShape); + commandStack.undo(); + commandStack.redo(); + + // then + expect(taskShape.businessObject.di.stroke).not.to.exist; + })); + + + it('setting fill color (multiple elements)', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + var startEventShape = elementRegistry.get('StartEvent_1'); + + // when + modeling.setColor([ taskShape, startEventShape ], { fill: 'FUCHSIA' }); + commandStack.undo(); + commandStack.redo(); + + // then + expect(taskShape.businessObject.di.fill).to.equal('FUCHSIA'); + expect(startEventShape.businessObject.di.fill).to.equal('FUCHSIA'); + })); + + + it('unsetting fill color (multiple elements)', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + var startEventShape = elementRegistry.get('StartEvent_1'); + modeling.setColor([ taskShape, startEventShape ], { fill: 'FUCHSIA' }); + + // when + modeling.setColor([ taskShape, startEventShape ]); + commandStack.undo(); + commandStack.redo(); + + // then + expect(taskShape.businessObject.di.fill).not.to.exist; + expect(startEventShape.businessObject.di.fill).not.to.exist; + })); + + + it('setting stroke color (multiple elements)', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + var startEventShape = elementRegistry.get('StartEvent_1'); + + // when + modeling.setColor([ taskShape, startEventShape ], { stroke: 'FUCHSIA' }); + commandStack.undo(); + commandStack.redo(); + + // then + expect(taskShape.businessObject.di.stroke).to.equal('FUCHSIA'); + expect(startEventShape.businessObject.di.stroke).to.equal('FUCHSIA'); + })); + + + it('unsetting stroke color (multiple elements)', inject(function(elementRegistry, commandStack, modeling) { + + // given + var taskShape = elementRegistry.get('Task_1'); + var startEventShape = elementRegistry.get('StartEvent_1'); + modeling.setColor([ taskShape, startEventShape ], { stroke: 'FUCHSIA' }); + + // when + modeling.setColor([ taskShape, startEventShape ]); + commandStack.undo(); + commandStack.redo(); + + // then + expect(taskShape.businessObject.di.stroke).not.to.exist; + expect(startEventShape.businessObject.di.stroke).not.to.exist; + })); + + }); + +}); diff --git a/test/spec/features/modeling/UpdatePropertiesSpec.js b/test/spec/features/modeling/UpdatePropertiesSpec.js index 0f44b52c..b9b9d98a 100644 --- a/test/spec/features/modeling/UpdatePropertiesSpec.js +++ b/test/spec/features/modeling/UpdatePropertiesSpec.js @@ -227,6 +227,33 @@ describe('features/modeling - update properties', function() { expect(flowConnection.businessObject.get('foo:customAttr')).to.equal('FOO'); })); + + it('setting di properties', inject(function(elementRegistry, modeling) { + + // given + var flowConnection = elementRegistry.get('SequenceFlow_1'); + + // when + modeling.updateProperties(flowConnection, { di: { fill: 'FUCHSIA' } }); + + // then + expect(flowConnection.businessObject.di.fill).to.equal('FUCHSIA'); + })); + + + it('unsetting di properties', inject(function(elementRegistry, modeling) { + + // given + var flowConnection = elementRegistry.get('SequenceFlow_1'); + modeling.updateProperties(flowConnection, { di: { fill: 'FUCHSIA' } }); + + // when + modeling.updateProperties(flowConnection, { di: { fill: undefined } }); + + // then + expect(flowConnection.businessObject.di.fill).not.to.exist; + })); + });