From 1d44f5f2bea79c23212f2cd6456866908273ff1c Mon Sep 17 00:00:00 2001 From: Kirill Shumilov Date: Wed, 24 Oct 2018 20:50:47 +0300 Subject: [PATCH] tweak(xod-client-browser): add "Select All" menu item into browser IDE --- .../xod-client-browser/src/containers/App.jsx | 19 ++++++++- .../src/view/containers/App.jsx | 29 ++++++++------ packages/xod-client/src/utils/browser.js | 2 + packages/xod-client/src/utils/constants.js | 4 +- packages/xod-client/src/utils/menu.js | 40 ++++++++++++++++++- 5 files changed, 77 insertions(+), 17 deletions(-) diff --git a/packages/xod-client-browser/src/containers/App.jsx b/packages/xod-client-browser/src/containers/App.jsx index 70ebce4e0..bf5622b93 100644 --- a/packages/xod-client-browser/src/containers/App.jsx +++ b/packages/xod-client-browser/src/containers/App.jsx @@ -54,6 +54,17 @@ class App extends client.App { props.actions.openProject(props.tutorialProject); props.actions.fetchGrant(); + + document.addEventListener('keydown', event => { + // Prevent selecting all contents with "Ctrl+a" or "Command+a" + // Ctrl+a or Command+a + const key = event.keyCode || event.which; + const mod = event.metaKey || event.ctrlKey; + if (mod && key === 65 && !client.isInputTarget(event)) { + event.preventDefault(); + this.props.actions.selectAll(); + } + }); } onDocumentClick(e) { @@ -249,6 +260,8 @@ class App extends client.App { onClick(items.undo, this.props.actions.undoCurrentPatch), onClick(items.redo, this.props.actions.redoCurrentPatch), items.separator, + onClick(items.selectall, this.props.actions.selectAll), + items.separator, onClick(items.insertNode, () => this.props.actions.showSuggester(null)), onClick(items.insertComment, this.props.actions.addComment), items.separator, @@ -325,7 +338,11 @@ class App extends client.App { render() { return ( - + { - // We can't use `role: 'selectall'` here, cause it ignores `onClick`. - // So we have to handle all cases manually: - - // - select all in inputs - if (client.isInput(document.activeElement)) { - document.activeElement.select(); - return; - } - - // - select entities on Patch - this.props.actions.selectAll(); - }), + onClick(items.selectall, this.selectAll), items.separator, onClick(items.insertNode, () => this.props.actions.showSuggester(null)), onClick(items.insertComment, this.props.actions.addComment), @@ -766,6 +754,21 @@ class App extends client.App { this.props.actions.hideAllPopups(); } + selectAll() { + // Handler for menu item "Select All" + // We can't use `role: 'selectall'` here, because it ignores `onClick`. + // So we have to handle all cases manually: + + // - select all in inputs + if (client.isInput(document.activeElement)) { + document.activeElement.select(); + return; + } + + // - select entities on Patch + this.props.actions.selectAll(); + } + static listPorts() { return new Promise((resolve, reject) => { ipcRenderer.send(EVENTS.LIST_PORTS); diff --git a/packages/xod-client/src/utils/browser.js b/packages/xod-client/src/utils/browser.js index 8ca1b8a17..52d5ced21 100644 --- a/packages/xod-client/src/utils/browser.js +++ b/packages/xod-client/src/utils/browser.js @@ -46,3 +46,5 @@ export const isInputTarget = event => isInput(event.target || event.srcElement); export const isEdge = () => R.compose(R.test(/Edge/), R.pathOr('', ['navigator', 'userAgent']))(window); + +export const isMacOS = () => window.navigator.appVersion.indexOf('Mac') !== -1; diff --git a/packages/xod-client/src/utils/constants.js b/packages/xod-client/src/utils/constants.js index 7e6236712..c7fdda5aa 100644 --- a/packages/xod-client/src/utils/constants.js +++ b/packages/xod-client/src/utils/constants.js @@ -38,7 +38,7 @@ export const HOTKEY = { [COMMAND.DELETE_SELECTION]: ['del', 'backspace'], [COMMAND.DESELECT]: 'escape', - [COMMAND.SELECT_ALL]: ['ctrl+a', 'command+a'], + [COMMAND.SELECT_ALL]: 'CmdOrCtrl+a', [COMMAND.UNDO]: 'ctrl+z', [COMMAND.REDO]: ['ctrl+y', 'ctrl+shift+z'], @@ -61,7 +61,7 @@ export const HOTKEY = { [COMMAND.MAKE_BUS]: ['b'], [COMMAND.PAN_TO_ORIGIN]: ['home'], - [COMMAND.PAN_TO_CENTER]: ['ctrl+home', 'command+home'], + [COMMAND.PAN_TO_CENTER]: 'CmdOrCtrl+home', }; export const ELECTRON_ACCELERATOR = { diff --git a/packages/xod-client/src/utils/menu.js b/packages/xod-client/src/utils/menu.js index 9d465de4d..90e34f2b2 100644 --- a/packages/xod-client/src/utils/menu.js +++ b/packages/xod-client/src/utils/menu.js @@ -1,5 +1,6 @@ import * as R from 'ramda'; import { HOTKEY, ELECTRON_ACCELERATOR, COMMAND } from './constants'; +import { isMacOS } from './browser'; const rawItems = { file: { @@ -152,11 +153,45 @@ const rawItems = { }, }; +const containsCmd = R.contains('command'); + +// :: String -> String +const unfoldCmdOrCtrl = R.ifElse( + () => isMacOS(), + R.replace(/CmdOrCtrl/gi, 'command'), + R.replace(/CmdOrCtrl/gi, 'ctrl') +); + +/** + * Filters OS-specific hotkeys. + * + * E.G., + * `['ctrl+a', 'command+a']` + * will become ['ctrl+a'] on Windows / Linux + * and ['command+a'] on MacOS + * + * But in case there are only 'ctrl+a' hotkey defined + * it will be left untouched on MacOS. + * + * :: String|[String] -> [String] + */ +export const filterOsHotkeys = R.compose( + R.map(unfoldCmdOrCtrl), + R.ifElse( + () => isMacOS(), + R.when(R.any(containsCmd), R.filter(containsCmd)), + R.reject(containsCmd) + ), + R.unless(R.is(Array), R.of) +); + const assignHotkeys = menuItem => R.when( R.prop('command'), R.merge({ - hotkey: HOTKEY[menuItem.command], + hotkey: R.compose(filterOsHotkeys, R.propOr([], menuItem.command))( + HOTKEY + ), accelerator: ELECTRON_ACCELERATOR[menuItem.command], }), menuItem @@ -174,3 +209,6 @@ export const onClick = R.flip(R.assoc('click')); /** add children items to menu item */ export const submenu = R.flip(R.assoc('submenu')); + +/** returns hotkeys key map with filtered OS specific key mapping */ +export const getOsSpecificHotkeys = () => R.map(filterOsHotkeys, HOTKEY);