From 1c37b303b9773424c38c8050c572832ac5dabe67 Mon Sep 17 00:00:00 2001 From: jos Date: Mon, 24 Jul 2017 14:09:10 +0200 Subject: [PATCH] Created key bindings for `text` mode --- src/components/CodeMode.js | 5 +++- src/components/TextMode.js | 26 +++++++++++++++++- src/components/TreeMode.js | 56 +++++--------------------------------- src/constants.js | 27 ++++++++++++++++++ src/utils/keyBindings.js | 21 ++++++++++++++ 5 files changed, 84 insertions(+), 51 deletions(-) create mode 100644 src/constants.js diff --git a/src/components/CodeMode.js b/src/components/CodeMode.js index 16689d4..7b2ac0d 100644 --- a/src/components/CodeMode.js +++ b/src/components/CodeMode.js @@ -40,7 +40,10 @@ export default class CodeMode extends TextMode { } render () { - return h('div', {className: 'jsoneditor jsoneditor-mode-code'}, [ + return h('div', { + className: 'jsoneditor jsoneditor-mode-code', + onKeyDown: this.handleKeyDown + }, [ this.renderMenu(), h('div', {key: 'contents', className: 'jsoneditor-contents'}, h(Ace, { diff --git a/src/components/TextMode.js b/src/components/TextMode.js index 4c2196e..9955391 100644 --- a/src/components/TextMode.js +++ b/src/components/TextMode.js @@ -6,6 +6,9 @@ import { parseJSON } from '../utils/jsonUtils' import { escapeUnicodeChars } from '../utils/stringUtils' import { enrichSchemaError, limitErrors } from '../utils/schemaUtils' import { jsonToData, dataToJson, patchData } from '../jsonData' +import { createFindKeyBinding } from '../utils/keyBindings' +import { KEY_BINDINGS } from '../constants' + import ModeButton from './menu/ModeButton' const AJV_OPTIONS = { @@ -43,9 +46,17 @@ const AJV_OPTIONS = { export default class TextMode extends Component { state: Object + keyDownActions = { + 'format': (event) => this.handleCompact(), + 'compact': (event) => this.handleFormat() + } + constructor (props) { super(props) + // TODO: make key bindings customizable + this.findKeyBinding = createFindKeyBinding(KEY_BINDINGS) + this.state = { text: '{}', compiledSchema: null @@ -81,7 +92,10 @@ export default class TextMode extends Component { } render () { - return h('div', {className: 'jsoneditor jsoneditor-mode-text'}, [ + return h('div', { + className: 'jsoneditor jsoneditor-mode-text', + onKeyDown: this.handleKeyDown + }, [ this.renderMenu(), h('div', {key: 'contents', className: 'jsoneditor-contents'}, @@ -243,6 +257,16 @@ export default class TextMode extends Component { // do nothing... } + handleKeyDown = (event) => { + const keyBinding = this.findKeyBinding(event) + const action = this.keyDownActions[keyBinding] + + if (action) { + event.preventDefault() + action(event) + } + } + /** * handle changed text input in the textarea * @param {Event} event diff --git a/src/components/TreeMode.js b/src/components/TreeMode.js index c380c6a..e9efc01 100644 --- a/src/components/TreeMode.js +++ b/src/components/TreeMode.js @@ -26,7 +26,8 @@ import { moveUp, moveDown, moveLeft, moveRight, moveDownSibling, moveHome, moveEnd, findNode, selectFind, searchHasFocus, setSelection } from './utils/domSelector' -import { keyComboFromEvent } from '../utils/keyBindings' +import { createFindKeyBinding } from '../utils/keyBindings' +import { KEY_BINDINGS } from '../constants' import type { JSONData, JSONPatch } from '../types' @@ -40,29 +41,6 @@ const MAX_HISTORY_ITEMS = 1000 // maximum number of undo/redo items to be kept const SEARCH_DEBOUNCE = 300 // milliseconds const SCROLL_DURATION = 400 // milliseconds -// TODO: make key bindings configurable -const KEY_BINDINGS = { - 'duplicate': ['Ctrl+D', 'Command+D'], - 'insert': ['Ctrl+Insert', 'Command+Insert'], - 'remove': ['Ctrl+Delete', 'Command+Delete'], - 'expand': ['Ctrl+E', 'Command+E'], - 'actionMenu': ['Ctrl+M', 'Command+M'], - 'undo': ['Ctrl+Z', 'Command+Z'], - 'redo': ['Ctrl+Shift+Z', 'Command+Shift+Z'], - 'find': ['Ctrl+F', 'Command+F'], - 'findNext': ['F3', 'Ctrl+G', 'Command+G'], - 'findPrevious': ['Shift+F3', 'Ctrl+Shift+G', 'Command+Shift+G'], - 'up': ['Alt+Up', 'Option+Up'], - 'down': ['Alt+Down', 'Option+Down'], - 'left': ['Alt+Left', 'Option+Left'], - 'right': ['Alt+Right', 'Option+Right'], - 'home': ['Alt+Home', 'Option+Home'], - 'end': ['Alt+End', 'Option+End'], - 'openUrl': ['Ctrl+Enter', 'Command+Enter'] - // TODO: implement Ctrl+Shift+Arrow Up/Down Select multiple fields - // TODO: implement Shift+Alt+Arrows Move current field or selected fields up/down/left/right -} - export default class TreeMode extends Component { id: number state: Object @@ -88,6 +66,9 @@ export default class TreeMode extends Component { this.id = Math.round(Math.random() * 1e5) // TODO: create a uuid here? + // TODO: make key bindings customizable + this.findKeyBinding = createFindKeyBinding(KEY_BINDINGS) + this.state = { data, @@ -113,9 +94,7 @@ export default class TreeMode extends Component { search: { text: '', active: null // active search result - }, - - keyCombos: this.bindingsByCombos (KEY_BINDINGS) + } } } @@ -181,7 +160,7 @@ export default class TreeMode extends Component { return h('div', { className: `jsoneditor jsoneditor-mode-${props.mode}`, - 'onKeyDown': this.handleKeyDown, + onKeyDown: this.handleKeyDown, 'data-jsoneditor': 'true' }, [ this.renderMenu(searchResults), @@ -276,27 +255,6 @@ export default class TreeMode extends Component { return h('div', {key: 'menu', className: 'jsoneditor-menu'}, items) } - /** - * Turn a map with key bindings by name into a map by combo - * @param {Object.} keyBindings - * @return {Object.} Returns keyCombos - */ - bindingsByCombos (keyBindings) { - const keyCombos = {} - - Object.keys(keyBindings).forEach ((name) => { - keyBindings[name].forEach(combo => keyCombos[combo.toUpperCase()] = name) - }) - - return keyCombos - } - - findKeyBinding = (event) => { - const keyCombo = keyComboFromEvent(event) - - return this.state.keyCombos[keyCombo.toUpperCase()] || null - } - /** * Validate the JSON against the configured JSON schema * Returns an array with the errors when not valid, returns an empty array diff --git a/src/constants.js b/src/constants.js new file mode 100644 index 0000000..b83304e --- /dev/null +++ b/src/constants.js @@ -0,0 +1,27 @@ + +export const KEY_BINDINGS = { + // tree mode + 'duplicate': ['Ctrl+D', 'Command+D'], + 'insert': ['Ctrl+Insert', 'Command+Insert'], + 'remove': ['Ctrl+Delete', 'Command+Delete'], + 'expand': ['Ctrl+E', 'Command+E'], + 'actionMenu': ['Ctrl+M', 'Command+M'], + 'undo': ['Ctrl+Z', 'Command+Z'], + 'redo': ['Ctrl+Shift+Z', 'Command+Shift+Z'], + 'find': ['Ctrl+F', 'Command+F'], + 'findNext': ['F3', 'Ctrl+G', 'Command+G'], + 'findPrevious': ['Shift+F3', 'Ctrl+Shift+G', 'Command+Shift+G'], + 'up': ['Alt+Up', 'Option+Up'], + 'down': ['Alt+Down', 'Option+Down'], + 'left': ['Alt+Left', 'Option+Left'], + 'right': ['Alt+Right', 'Option+Right'], + 'home': ['Alt+Home', 'Option+Home'], + 'end': ['Alt+End', 'Option+End'], + 'openUrl': ['Ctrl+Enter', 'Command+Enter'], + // TODO: implement Ctrl+Shift+Arrow Up/Down Select multiple fields + // TODO: implement Shift+Alt+Arrows Move current field or selected fields up/down/left/right + + // text and code mode + 'compact': ['Ctrl+\\', 'Command+\\'], + 'format': ['Ctrl+Shift+\\', 'Command+Shift+\\'], +} diff --git a/src/utils/keyBindings.js b/src/utils/keyBindings.js index f3d9b23..9454028 100644 --- a/src/utils/keyBindings.js +++ b/src/utils/keyBindings.js @@ -34,6 +34,27 @@ export function keyComboFromEvent (event) { return combi.join('+') } +/** + * Create a function which can quickly find a keyBinding from a set of + * keyBindings. + * @param {Object.} keyBindings + * @return {function} Returns a findKeyBinding function + */ +export function createFindKeyBinding (keyBindings) { + // turn the map with key bindings by name (multiple per binding) into a map by key combo + const keyCombos = {} + Object.keys(keyBindings).forEach ((name) => { + keyBindings[name].forEach(combo => keyCombos[combo.toUpperCase()] = name) + }) + + return function findKeyBinding (event){ + const keyCombo = keyComboFromEvent(event) + + return keyCombos[keyCombo.toUpperCase()] || null + } +} + + const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0 const metaCodes = {