feat(contextPad): add color picker

Related to #1491
This commit is contained in:
Beatriz Mendes 2022-05-19 13:32:13 +02:00
parent 9b1096abbc
commit 3fc2cba013
6 changed files with 318 additions and 15 deletions

View File

@ -114,3 +114,60 @@
.selected .bjs-drilldown-empty { .selected .bjs-drilldown-empty {
display: inherit; display: inherit;
} }
/* COLOR PICKER */
.bpmn-color-picker .djs-popup-header {
display: flex;
width: 66px;
flex-wrap: wrap;
padding: 1px;
}
/* override popup menu to have color grid */
[class^="color-icon-"],
[class*=" color-icon-"] {
padding: 0 !important;
margin: 1px !important;
}
[class^="color-icon-"]:before,
[class*=" color-icon-"]:before {
display: flex;
content: '';
width: 16px;
height: 16px;
border-radius: 0.1em;
border: 0.03em solid black;
padding: 0;
}
.color-icon-default:before {
background-color: white;
border-color: black;
}
.color-icon-blue:before {
background-color: rgb(187, 222, 251);
border-color: rgb(30, 136, 229);
}
.color-icon-orange:before {
background-color: rgb(255, 224, 178);
border-color: rgb(251, 140, 0);
}
.color-icon-green:before {
background-color: rgb(200, 230, 201);
border-color: rgb(67, 160, 71);
}
.color-icon-red:before {
background-color: rgb(255, 205, 210);
border-color: rgb(229, 57, 53);
}
.color-icon-purple:before {
background-color: rgb(225, 190, 231);
border-color: rgb(142, 36, 170);
}

View File

@ -428,6 +428,33 @@ ContextPadProvider.prototype.getContextPadEntries = function(element) {
}); });
} }
// color picker
var colorImageSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048">' +
'<path d="M 1647.63 97.188 L 1248.282 497.465 L 1139.624 606.124 L 940.879 549.473 L 734.703 491.893 L 730.989 495.608 L 564.748 661.847 L 962.238 1059.336 L 1359.728 1456.827 L 1525.969 1290.587 L 1525.969 1289.658 L 1529.684 1286.873 L 1472.104 1080.698 L 1420.096 897.74 L 1534.327 783.509 L 1933.674 384.162 L 1647.63 97.188 Z M 446.802 781.652 L 76.244 1151.28 L 473.734 1548.77 L 871.224 1947.188 L 1241.783 1576.632 L 844.292 1179.142 L 446.802 781.652 Z"/>' +
'</svg>';
var colorImageUrl = 'data:image/svg+xml;utf8,' + encodeURIComponent(colorImageSvg);
assign(actions, {
'set-color': {
group: 'edit',
title: translate('Set color'),
imageUrl: colorImageUrl,
action: {
click: function(event, element) {
popupMenu.open(
element,
'bpmn-color-picker',
assign(getReplaceMenuPosition(element), {
cursor: { x: event.x, y: event.y }
})
);
}
}
} });
// delete element entry, only show if allowed by rules // delete element entry, only show if allowed by rules
var deleteAllowed = rules.allowed('elements.delete', { elements: [ element ] }); var deleteAllowed = rules.allowed('elements.delete', { elements: [ element ] });

View File

@ -0,0 +1,63 @@
var COLORS = [{
title: 'Default',
fill: undefined,
stroke: undefined
}, {
title: 'Blue',
fill: 'rgb(187, 222, 251)',
stroke: 'rgb(30, 136, 229)'
}, {
title: 'Orange',
fill: 'rgb(255, 224, 178)',
stroke: 'rgb(251, 140, 0)'
}, {
title: 'Green',
fill: 'rgb(200, 230, 201)',
stroke: 'rgb(67, 160, 71)'
}, {
title: 'Red',
fill: 'rgb(255, 205, 210)',
stroke: 'rgb(229, 57, 53)'
}, {
title: 'Purple',
fill: 'rgb(225, 190, 231)',
stroke: 'rgb(142, 36, 170)'
}];
export default function ColorMenuProvider(popupMenu, modeling, translate) {
this._popupMenu = popupMenu;
this._modeling = modeling;
this._translate = translate;
this.register();
}
ColorMenuProvider.prototype.register = function() {
this._popupMenu.registerProvider('bpmn-color-picker', this);
};
ColorMenuProvider.prototype.getEntries = function() {
return [];
};
ColorMenuProvider.prototype.getHeaderEntries = function(elements) {
var modeling = this._modeling;
var translate = this._translate;
return COLORS.map(function(color) {
return {
id: color.title.toLowerCase() + '-color',
title: translate(color.title),
className: 'color-icon-' + color.title.toLowerCase(),
action: function() {
modeling.setColor(elements, {
fill: color.fill,
stroke: color.stroke
});
}
};
});
};
ColorMenuProvider.$inject = ['popupMenu', 'modeling', 'translate'];

View File

@ -1,6 +1,6 @@
import PopupMenuModule from 'diagram-js/lib/features/popup-menu'; import PopupMenuModule from 'diagram-js/lib/features/popup-menu';
import ReplaceModule from '../replace'; import ReplaceModule from '../replace';
import ColorMenuProvider from './ColorMenuProvider';
import ReplaceMenuProvider from './ReplaceMenuProvider'; import ReplaceMenuProvider from './ReplaceMenuProvider';
@ -9,6 +9,11 @@ export default {
PopupMenuModule, PopupMenuModule,
ReplaceModule ReplaceModule
], ],
__init__: [ 'replaceMenuProvider' ], __init__: [
replaceMenuProvider: [ 'type', ReplaceMenuProvider ] 'replaceMenuProvider',
'colorMenuProvider'
],
replaceMenuProvider: [ 'type', ReplaceMenuProvider ],
colorMenuProvider: [ 'type', ColorMenuProvider ]
}; };

View File

@ -207,7 +207,8 @@ describe('features - context-pad', function() {
'append.gateway', 'append.gateway',
'append.append-task', 'append.append-task',
'append.intermediate-event', 'append.intermediate-event',
'append.text-annotation' 'append.text-annotation',
'set-color'
]); ]);
})); }));
@ -223,7 +224,8 @@ describe('features - context-pad', function() {
'append.condition-intermediate-event', 'append.condition-intermediate-event',
'append.signal-intermediate-event', 'append.signal-intermediate-event',
'append.text-annotation', 'append.text-annotation',
'!append.task' '!append.task',
'set-color'
]); ]);
})); }));
@ -233,7 +235,8 @@ describe('features - context-pad', function() {
expectContextPadEntries('EndEvent_1', [ expectContextPadEntries('EndEvent_1', [
'connect', 'connect',
'replace', 'replace',
'!append.task' '!append.task',
'set-color'
]); ]);
})); }));
@ -244,7 +247,8 @@ describe('features - context-pad', function() {
'connect', 'connect',
'replace', 'replace',
'!append.end-event', '!append.end-event',
'append.text-annotation' 'append.text-annotation',
'set-color'
]); ]);
})); }));
@ -255,7 +259,8 @@ describe('features - context-pad', function() {
'connect', 'connect',
'replace', 'replace',
'append.compensation-activity', 'append.compensation-activity',
'!append.end-event' '!append.end-event',
'set-color'
]); ]);
})); }));
@ -266,7 +271,8 @@ describe('features - context-pad', function() {
'connect', 'connect',
'append.text-annotation', 'append.text-annotation',
'replace', 'replace',
'!append.end-event' '!append.end-event',
'set-color'
]); ]);
})); }));
@ -277,7 +283,8 @@ describe('features - context-pad', function() {
'connect', 'connect',
'append.text-annotation', 'append.text-annotation',
'replace', 'replace',
'!append.end-event' '!append.end-event',
'set-color'
]); ]);
})); }));
@ -287,7 +294,8 @@ describe('features - context-pad', function() {
expectContextPadEntries('Group_1', [ expectContextPadEntries('Group_1', [
'append.text-annotation', 'append.text-annotation',
'delete', 'delete',
'!replace' '!replace',
'set-color'
]); ]);
})); }));
@ -298,7 +306,8 @@ describe('features - context-pad', function() {
'connect', 'connect',
'delete', 'delete',
'!replace', '!replace',
'!append.text-annotation' '!append.text-annotation',
'set-color'
]); ]);
})); }));
@ -620,6 +629,45 @@ describe('features - context-pad', function() {
}); });
describe('set-color', function() {
var diagramXML = require('../../../fixtures/bpmn/simple.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules
}));
var container;
beforeEach(function() {
container = TestContainer.get(this);
});
it('should show popup menu in the correct position', inject(function(elementRegistry, contextPad) {
// given
var element = elementRegistry.get('StartEvent_1'),
padding = 5,
padMenuRect,
colorMenuRect;
contextPad.open(element);
// when
contextPad.trigger('click', padEvent('set-color'));
padMenuRect = contextPad.getPad(element).html.getBoundingClientRect();
colorMenuRect = domQuery('.bpmn-color-picker', container).getBoundingClientRect();
// then
expect(colorMenuRect.left).to.be.at.most(padMenuRect.left);
expect(colorMenuRect.top).to.be.at.most(padMenuRect.bottom + padding);
}));
});
}); });

View File

@ -0,0 +1,103 @@
import {
bootstrapModeler,
getBpmnJS,
inject
} from 'test/TestHelper';
import {
createEvent as globalEvent
} from '../../../util/MockEvents';
import coreModule from 'lib/core';
import modelingModule from 'lib/features/modeling';
import colorMenuProvider from 'lib/features/popup-menu';
import {
query as domQuery,
queryAll as domQueryAll
} from 'min-dom';
describe('features/popup-menu - replace menu provider', function() {
var simpleXML= require('../../../fixtures/bpmn/simple.bpmn');
var testModules = [
coreModule,
colorMenuProvider,
modelingModule
];
beforeEach(bootstrapModeler(simpleXML, { modules: testModules }));
it('should show all color options', inject(function(elementRegistry) {
var task = elementRegistry.get('Task_1');
openPopup(task);
var entries = queryEntries();
expect(entries).to.have.lengthOf(6);
}));
it('should call setColor', inject(function(modeling, elementRegistry) {
var spy = sinon.spy(modeling, 'setColor');
var task = elementRegistry.get('Task_1');
openPopup(task);
triggerAction('blue-color');
expect(spy).to.have.been.calledWith(
task,
{
fill: 'rgb(187, 222, 251)',
stroke: 'rgb(30, 136, 229)'
}
);
}));
});
// helpers ////////////
function openPopup(element, offset) {
offset = offset || 100;
getBpmnJS().invoke(function(popupMenu) {
popupMenu.open(element, 'bpmn-color-picker', {
x: element.x + offset, y: element.y + offset
});
});
}
function queryEntry(id) {
var container = getBpmnJS().get('canvas').getContainer();
return domQuery('.djs-popup [data-id="' + id + '"]', container);
}
function queryEntries() {
var container = getBpmnJS().get('canvas').getContainer();
return domQueryAll('.djs-popup .entry', container);
}
function triggerAction(id) {
var entry = queryEntry(id);
if (!entry) {
throw new Error('entry "'+ id +'" not found in replace menu');
}
var popupMenu = getBpmnJS().get('popupMenu');
return popupMenu.trigger(globalEvent(entry, { x: 0, y: 0 }));
}