From df292f50b8645c5b72d2c15a4672791e499d530c Mon Sep 17 00:00:00 2001 From: Beatriz Mendes Date: Fri, 17 Feb 2023 10:54:28 +0100 Subject: [PATCH] feat(client): add `create-append-anything` shortcuts Closes #3472 --- client/src/app/KeyboardBindings.js | 30 +++++++ .../src/app/__tests__/KeyboardBindingsSpec.js | 80 ++++++++++++++++++- client/src/app/tabs/bpmn/BpmnEditor.js | 2 + client/src/app/tabs/cloud-bpmn/BpmnEditor.js | 2 + client/src/app/tabs/getEditMenu.js | 24 +++++- 5 files changed, 136 insertions(+), 2 deletions(-) diff --git a/client/src/app/KeyboardBindings.js b/client/src/app/KeyboardBindings.js index f340e91ca3..20e6da6bef 100644 --- a/client/src/app/KeyboardBindings.js +++ b/client/src/app/KeyboardBindings.js @@ -142,6 +142,16 @@ export default class KeyboardBindings { action = getAction(this.replaceElement); } + // create + if (isCreate(event) && isEnabled(this.createElement)) { + action = getAction(this.createElement); + } + + // append + if (isAppend(event) && isEnabled(this.appendElement)) { + action = getAction(this.appendElement); + } + // custom if (this.hasCustomEntry(event)) { action = this.getCustomAction(event, 'keydown'); @@ -206,6 +216,8 @@ export default class KeyboardBindings { this.undo = findUndo(menu); this.redo = findRedo(menu); this.replaceElement = findReplaceElement(menu); + this.createElement = findCreateElement(menu); + this.appendElement = findAppendElement(menu); this.updateCustomEntries(menu); return menu; @@ -303,6 +315,16 @@ function isReplace(event) { return isKey([ 'r', 'R' ], event) && !isCommandOrControl(event) && !isShift(event); } +// n +function isCreate(event) { + return isKey([ 'n', 'N' ], event) && !isCommandOrControl(event) && !isShift(event); +} + +// a +function isAppend(event) { + return isKey([ 'a', 'A' ], event) && !isCommandOrControl(event) && !isShift(event); +} + // Secondary delete shortcut // Delete (Mac), Backspace (Linux, Windows) function isSecondaryRemoveSelection(event, isMac) { @@ -440,6 +462,14 @@ function findReplaceElement(menu) { return find(menu, ({ accelerator }) => isAccelerator(accelerator, 'R')); } +function findCreateElement(menu) { + return find(menu, ({ accelerator }) => isAccelerator(accelerator, 'N')); +} + +function findAppendElement(menu) { + return find(menu, ({ accelerator }) => isAccelerator(accelerator, 'A')); +} + /** * Check wether entry is enabled. If not specified it is enabled. * diff --git a/client/src/app/__tests__/KeyboardBindingsSpec.js b/client/src/app/__tests__/KeyboardBindingsSpec.js index 42a935aae2..4ea1715276 100644 --- a/client/src/app/__tests__/KeyboardBindingsSpec.js +++ b/client/src/app/__tests__/KeyboardBindingsSpec.js @@ -360,7 +360,6 @@ describe('KeyboardBindings', function() { // then expect(actionSpy).to.have.been.calledWith('replaceElement', event); - }); @@ -379,7 +378,86 @@ describe('KeyboardBindings', function() { // then expect(actionSpy).to.not.have.been.called; + }); + + }); + + + describe('createElement', function() { + + it('should trigger for N', function() { + + // given + event = createKeyEvent('N'); + + keyboardBindings.update([ { + accelerator: 'N', + action: 'createElement' + } ]); + + // when + keyboardBindings._keyDownHandler(event); + + // then + expect(actionSpy).to.have.been.calledWith('createElement'); + }); + + + it('should not trigger for Cmd+N', function() { + + // given + event = createKeyEvent('N', { ctrlKey: true }); + + keyboardBindings.update([ { + accelerator: 'N', + action: 'createElement' + } ]); + + // when + keyboardBindings._keyDownHandler(event); + + // then + expect(actionSpy).to.not.have.been.called; + }); + + }); + + + describe('appendElement', function() { + + it('should trigger for N', function() { + + // given + event = createKeyEvent('A'); + + keyboardBindings.update([ { + accelerator: 'A', + action: 'appendElement' + } ]); + + // when + keyboardBindings._keyDownHandler(event); + // then + expect(actionSpy).to.have.been.calledWith('appendElement'); + }); + + + it('should not trigger for Cmd+A', function() { + + // given + event = createKeyEvent('A', { ctrlKey: true }); + + keyboardBindings.update([ { + accelerator: 'A', + action: 'appendElement' + } ]); + + // when + keyboardBindings._keyDownHandler(event); + + // then + expect(actionSpy).to.not.have.been.called; }); }); diff --git a/client/src/app/tabs/bpmn/BpmnEditor.js b/client/src/app/tabs/bpmn/BpmnEditor.js index eb7af738a6..fd9f43e141 100644 --- a/client/src/app/tabs/bpmn/BpmnEditor.js +++ b/client/src/app/tabs/bpmn/BpmnEditor.js @@ -396,9 +396,11 @@ export class BpmnEditor extends CachedComponent { const newState = { align: selectionLength > 1, + appendElement: !inputActive, close: true, copy: !!selectionLength, cut: false, + createElement: !inputActive, defaultCopyCutPaste: inputActive, defaultUndoRedo: inputActive, dirty, diff --git a/client/src/app/tabs/cloud-bpmn/BpmnEditor.js b/client/src/app/tabs/cloud-bpmn/BpmnEditor.js index 1154b29115..5c53b4a269 100644 --- a/client/src/app/tabs/cloud-bpmn/BpmnEditor.js +++ b/client/src/app/tabs/cloud-bpmn/BpmnEditor.js @@ -354,9 +354,11 @@ export class BpmnEditor extends CachedComponent { const newState = { align: selectionLength > 1, + appendElement: !inputActive, close: true, copy: !!selectionLength, cut: false, + createElement: !inputActive, defaultCopyCutPaste: inputActive, defaultUndoRedo: inputActive, dirty, diff --git a/client/src/app/tabs/getEditMenu.js b/client/src/app/tabs/getEditMenu.js index 69d26f7756..7230f5c09e 100644 --- a/client/src/app/tabs/getEditMenu.js +++ b/client/src/app/tabs/getEditMenu.js @@ -231,7 +231,9 @@ export function getSelectionEntries({ inputActive, removeSelected, selectAll, - replaceElement + replaceElement, + createElement, + appendElement }) { const menuEntries = []; @@ -256,6 +258,26 @@ export function getSelectionEntries({ }); } + if (isDefined(appendElement)) { + menuEntries.push({ + label: 'Append Element', + accelerator: 'A', + enabled: appendElement, + action: 'appendElement' + }); + } + + if (isDefined(createElement)) { + menuEntries.push({ + label: 'Create Element', + accelerator: 'N', + enabled: createElement, + action: 'createElement', + options: { + opt: 'bpmn:Task' + } + }); + } if (isDefined(replaceElement)) { menuEntries.push({