-
Notifications
You must be signed in to change notification settings - Fork 496
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(client): add diagram-related keyboard bindings
* properly integrate with command stack when working with properties panel * handle menu accelerators that can't be overridden on Windows/Linux Closes #1027
- Loading branch information
1 parent
d770f51
commit 4b3ab1d
Showing
10 changed files
with
574 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
import { active as isInputActive } from '../../util/dom/isInput'; | ||
|
||
import { isArray } from 'min-dash'; | ||
|
||
|
||
/** | ||
* Fixes two issues when regarding keyboard: | ||
* | ||
* 1. Ensures proper command stack integration when working with properties | ||
* panel. | ||
* | ||
* 2. Fixes issue with Electron applications on Linux and Windows. Checks for | ||
* menu item accelarators that can't be overridden (CommandOrControl+A/C/V) and | ||
* manually triggers corresponding editor actions. | ||
* | ||
* See https://github.com/electron/electron/issues/7165. | ||
*/ | ||
export default class DiagramKeyboardBindings { | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param {Object} options - Options. | ||
* @param {boolean} [options.canCopyPaste] - Wether or not editor can copy and | ||
* paste. | ||
* @param {Object} options.editorActions - Editor actions module. | ||
* @param {boolean} [options.isMac] - Wether platform is Mac or not. | ||
* @param {Object} options.propertiesPanelParent - Parent DOM element of properties | ||
* panel. | ||
*/ | ||
constructor(options) { | ||
this.canCopyPaste = options.canCopyPaste; | ||
this.editorActions = options.editorActions; | ||
this.isMac = options.isMac; | ||
this.propertiesPanelParent = options.propertiesPanelParent; | ||
} | ||
|
||
bind() { | ||
window.addEventListener('keydown', this._keyHandler); | ||
} | ||
|
||
unbind() { | ||
window.removeEventListener('keydown', this._keyHandler); | ||
} | ||
|
||
_keyHandler = (event) => { | ||
const { editorActions } = this; | ||
|
||
const activeElement = getActiveElement(); | ||
|
||
const inputActive = isInputActive(activeElement), | ||
isPropertiesPanel = this.propertiesPanelParent.contains(activeElement); | ||
|
||
// undo | ||
// CmdOrCtrl + Z | ||
if (isUndo(event) && inputActive && isPropertiesPanel) { | ||
editorActions.trigger('undo'); | ||
|
||
event.preventDefault(); | ||
|
||
return; | ||
} | ||
|
||
// redo | ||
// CmdOrCtrl + Y | ||
if (isRedo(event) && inputActive && isPropertiesPanel) { | ||
editorActions.trigger('redo'); | ||
|
||
event.preventDefault(); | ||
|
||
return; | ||
} | ||
|
||
if (this.isMac) { | ||
return; | ||
} | ||
|
||
// select all elements | ||
// CmdOrCtrl + A | ||
if (isSelectAll(event) && !inputActive && !isPropertiesPanel) { | ||
editorActions.trigger('selectElements'); | ||
|
||
event.preventDefault(); | ||
|
||
return; | ||
} | ||
|
||
if (!this.canCopyPaste) { | ||
return; | ||
} | ||
|
||
// copy | ||
// CmdOrCtrl + C | ||
if (isCopy(event) && !inputActive && !isPropertiesPanel) { | ||
editorActions.trigger('copy'); | ||
|
||
event.preventDefault(); | ||
|
||
return; | ||
} | ||
|
||
// paste | ||
// CmdOrCtrl + V | ||
if (isPaste(event) && !inputActive && !isPropertiesPanel) { | ||
editorActions.trigger('paste'); | ||
|
||
event.preventDefault(); | ||
|
||
return; | ||
} | ||
} | ||
} | ||
|
||
// helpers ////////// | ||
|
||
function getActiveElement() { | ||
return document.activeElement; | ||
} | ||
|
||
function isUndo(event) { | ||
return isKey(['z', 'Z'], event) && isCmdOrCtrl(event); | ||
} | ||
|
||
function isRedo(event) { | ||
return isKey(['y', 'Y'], event) && isCmdOrCtrl(event); | ||
} | ||
|
||
function isCopy(event) { | ||
return isKey(['c', 'C'], event) && isCmdOrCtrl(event); | ||
} | ||
|
||
function isPaste(event) { | ||
return isKey(['v', 'V'], event) && isCmdOrCtrl(event); | ||
} | ||
|
||
function isSelectAll(event) { | ||
return isKey(['a', 'A'], event) && isCmdOrCtrl(event); | ||
} | ||
|
||
/** | ||
* @param {KeyboardEvent} event | ||
*/ | ||
export function isCmdOrCtrl(event) { | ||
|
||
// ensure we don't react to AltGr | ||
// (mapped to CTRL + ALT) | ||
if (event.altKey) { | ||
return false; | ||
} | ||
|
||
return event.ctrlKey || event.metaKey; | ||
} | ||
|
||
/** | ||
* Checks if key pressed is one of provided keys. | ||
* | ||
* @param {String|String[]} keys | ||
* @param {KeyboardEvent} event | ||
*/ | ||
export function isKey(keys, event) { | ||
keys = isArray(keys) ? keys : [ keys ]; | ||
|
||
return keys.indexOf(event.key) > -1; | ||
} |
Oops, something went wrong.