Created key bindings for `text` mode

This commit is contained in:
jos 2017-07-24 14:09:10 +02:00
parent e069d3f0b3
commit 1c37b303b9
5 changed files with 84 additions and 51 deletions

View File

@ -40,7 +40,10 @@ export default class CodeMode extends TextMode {
} }
render () { render () {
return h('div', {className: 'jsoneditor jsoneditor-mode-code'}, [ return h('div', {
className: 'jsoneditor jsoneditor-mode-code',
onKeyDown: this.handleKeyDown
}, [
this.renderMenu(), this.renderMenu(),
h('div', {key: 'contents', className: 'jsoneditor-contents'}, h(Ace, { h('div', {key: 'contents', className: 'jsoneditor-contents'}, h(Ace, {

View File

@ -6,6 +6,9 @@ import { parseJSON } from '../utils/jsonUtils'
import { escapeUnicodeChars } from '../utils/stringUtils' import { escapeUnicodeChars } from '../utils/stringUtils'
import { enrichSchemaError, limitErrors } from '../utils/schemaUtils' import { enrichSchemaError, limitErrors } from '../utils/schemaUtils'
import { jsonToData, dataToJson, patchData } from '../jsonData' import { jsonToData, dataToJson, patchData } from '../jsonData'
import { createFindKeyBinding } from '../utils/keyBindings'
import { KEY_BINDINGS } from '../constants'
import ModeButton from './menu/ModeButton' import ModeButton from './menu/ModeButton'
const AJV_OPTIONS = { const AJV_OPTIONS = {
@ -43,9 +46,17 @@ const AJV_OPTIONS = {
export default class TextMode extends Component { export default class TextMode extends Component {
state: Object state: Object
keyDownActions = {
'format': (event) => this.handleCompact(),
'compact': (event) => this.handleFormat()
}
constructor (props) { constructor (props) {
super(props) super(props)
// TODO: make key bindings customizable
this.findKeyBinding = createFindKeyBinding(KEY_BINDINGS)
this.state = { this.state = {
text: '{}', text: '{}',
compiledSchema: null compiledSchema: null
@ -81,7 +92,10 @@ export default class TextMode extends Component {
} }
render () { render () {
return h('div', {className: 'jsoneditor jsoneditor-mode-text'}, [ return h('div', {
className: 'jsoneditor jsoneditor-mode-text',
onKeyDown: this.handleKeyDown
}, [
this.renderMenu(), this.renderMenu(),
h('div', {key: 'contents', className: 'jsoneditor-contents'}, h('div', {key: 'contents', className: 'jsoneditor-contents'},
@ -243,6 +257,16 @@ export default class TextMode extends Component {
// do nothing... // 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 * handle changed text input in the textarea
* @param {Event} event * @param {Event} event

View File

@ -26,7 +26,8 @@ import {
moveUp, moveDown, moveLeft, moveRight, moveDownSibling, moveHome, moveEnd, moveUp, moveDown, moveLeft, moveRight, moveDownSibling, moveHome, moveEnd,
findNode, selectFind, searchHasFocus, setSelection findNode, selectFind, searchHasFocus, setSelection
} from './utils/domSelector' } from './utils/domSelector'
import { keyComboFromEvent } from '../utils/keyBindings' import { createFindKeyBinding } from '../utils/keyBindings'
import { KEY_BINDINGS } from '../constants'
import type { JSONData, JSONPatch } from '../types' 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 SEARCH_DEBOUNCE = 300 // milliseconds
const SCROLL_DURATION = 400 // 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 { export default class TreeMode extends Component {
id: number id: number
state: Object state: Object
@ -88,6 +66,9 @@ export default class TreeMode extends Component {
this.id = Math.round(Math.random() * 1e5) // TODO: create a uuid here? this.id = Math.round(Math.random() * 1e5) // TODO: create a uuid here?
// TODO: make key bindings customizable
this.findKeyBinding = createFindKeyBinding(KEY_BINDINGS)
this.state = { this.state = {
data, data,
@ -113,9 +94,7 @@ export default class TreeMode extends Component {
search: { search: {
text: '', text: '',
active: null // active search result active: null // active search result
}, }
keyCombos: this.bindingsByCombos (KEY_BINDINGS)
} }
} }
@ -181,7 +160,7 @@ export default class TreeMode extends Component {
return h('div', { return h('div', {
className: `jsoneditor jsoneditor-mode-${props.mode}`, className: `jsoneditor jsoneditor-mode-${props.mode}`,
'onKeyDown': this.handleKeyDown, onKeyDown: this.handleKeyDown,
'data-jsoneditor': 'true' 'data-jsoneditor': 'true'
}, [ }, [
this.renderMenu(searchResults), this.renderMenu(searchResults),
@ -276,27 +255,6 @@ export default class TreeMode extends Component {
return h('div', {key: 'menu', className: 'jsoneditor-menu'}, items) return h('div', {key: 'menu', className: 'jsoneditor-menu'}, items)
} }
/**
* Turn a map with key bindings by name into a map by combo
* @param {Object.<String, Array.string>} keyBindings
* @return {Object.<String, string>} 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 * Validate the JSON against the configured JSON schema
* Returns an array with the errors when not valid, returns an empty array * Returns an array with the errors when not valid, returns an empty array

27
src/constants.js Normal file
View File

@ -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+\\'],
}

View File

@ -34,6 +34,27 @@ export function keyComboFromEvent (event) {
return combi.join('+') return combi.join('+')
} }
/**
* Create a function which can quickly find a keyBinding from a set of
* keyBindings.
* @param {Object.<String, String[]>} 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 isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0
const metaCodes = { const metaCodes = {