/** * Copyright (c) 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule editOnKeyDown * @format * */ 'use strict'; var DraftModifier = require('./DraftModifier'); var EditorState = require('./EditorState'); var KeyBindingUtil = require('./KeyBindingUtil'); var Keys = require('fbjs/lib/Keys'); var SecondaryClipboard = require('./SecondaryClipboard'); var UserAgent = require('fbjs/lib/UserAgent'); var isEventHandled = require('./isEventHandled'); var keyCommandBackspaceToStartOfLine = require('./keyCommandBackspaceToStartOfLine'); var keyCommandBackspaceWord = require('./keyCommandBackspaceWord'); var keyCommandDeleteWord = require('./keyCommandDeleteWord'); var keyCommandInsertNewline = require('./keyCommandInsertNewline'); var keyCommandMoveSelectionToEndOfBlock = require('./keyCommandMoveSelectionToEndOfBlock'); var keyCommandMoveSelectionToStartOfBlock = require('./keyCommandMoveSelectionToStartOfBlock'); var keyCommandPlainBackspace = require('./keyCommandPlainBackspace'); var keyCommandPlainDelete = require('./keyCommandPlainDelete'); var keyCommandTransposeCharacters = require('./keyCommandTransposeCharacters'); var keyCommandUndo = require('./keyCommandUndo'); var isOptionKeyCommand = KeyBindingUtil.isOptionKeyCommand; var isChrome = UserAgent.isBrowser('Chrome'); /** * Map a `DraftEditorCommand` command value to a corresponding function. */ function onKeyCommand(command, editorState) { switch (command) { case 'redo': return EditorState.redo(editorState); case 'delete': return keyCommandPlainDelete(editorState); case 'delete-word': return keyCommandDeleteWord(editorState); case 'backspace': return keyCommandPlainBackspace(editorState); case 'backspace-word': return keyCommandBackspaceWord(editorState); case 'backspace-to-start-of-line': return keyCommandBackspaceToStartOfLine(editorState); case 'split-block': return keyCommandInsertNewline(editorState); case 'transpose-characters': return keyCommandTransposeCharacters(editorState); case 'move-selection-to-start-of-block': return keyCommandMoveSelectionToStartOfBlock(editorState); case 'move-selection-to-end-of-block': return keyCommandMoveSelectionToEndOfBlock(editorState); case 'secondary-cut': return SecondaryClipboard.cut(editorState); case 'secondary-paste': return SecondaryClipboard.paste(editorState); default: return editorState; } } /** * Intercept keydown behavior to handle keys and commands manually, if desired. * * Keydown combinations may be mapped to `DraftCommand` values, which may * correspond to command functions that modify the editor or its contents. * * See `getDefaultKeyBinding` for defaults. Alternatively, the top-level * component may provide a custom mapping via the `keyBindingFn` prop. */ function editOnKeyDown(editor, e) { var keyCode = e.which; var editorState = editor._latestEditorState; switch (keyCode) { case Keys.RETURN: e.preventDefault(); // The top-level component may manually handle newline insertion. If // no special handling is performed, fall through to command handling. if (editor.props.handleReturn && isEventHandled(editor.props.handleReturn(e, editorState))) { return; } break; case Keys.ESC: e.preventDefault(); editor.props.onEscape && editor.props.onEscape(e); return; case Keys.TAB: editor.props.onTab && editor.props.onTab(e); return; case Keys.UP: editor.props.onUpArrow && editor.props.onUpArrow(e); return; case Keys.RIGHT: editor.props.onRightArrow && editor.props.onRightArrow(e); return; case Keys.DOWN: editor.props.onDownArrow && editor.props.onDownArrow(e); return; case Keys.LEFT: editor.props.onLeftArrow && editor.props.onLeftArrow(e); return; case Keys.SPACE: // Handling for OSX where option + space scrolls. if (isChrome && isOptionKeyCommand(e)) { e.preventDefault(); // Insert a nbsp into the editor. var contentState = DraftModifier.replaceText(editorState.getCurrentContent(), editorState.getSelection(), '\xA0'); editor.update(EditorState.push(editorState, contentState, 'insert-characters')); return; } } var command = editor.props.keyBindingFn(e); // If no command is specified, allow keydown event to continue. if (!command) { return; } if (command === 'undo') { // Since undo requires some special updating behavior to keep the editor // in sync, handle it separately. keyCommandUndo(e, editorState, editor.update); return; } // At this point, we know that we're handling a command of some kind, so // we don't want to insert a character following the keydown. e.preventDefault(); // Allow components higher up the tree to handle the command first. if (editor.props.handleKeyCommand && isEventHandled(editor.props.handleKeyCommand(command, editorState))) { return; } var newState = onKeyCommand(command, editorState); if (newState !== editorState) { editor.update(newState); } } module.exports = editOnKeyDown;