From 88c58debeca5f9a4d1835f0543545825d01fb562 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Fri, 17 Jun 2016 12:00:15 -0700 Subject: [PATCH] got insertion working! --- lib/components/content.js | 26 ++++++++++++++++++++++++-- lib/models/state.js | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/lib/components/content.js b/lib/components/content.js index cbc4229a4..4d5b5758a 100644 --- a/lib/components/content.js +++ b/lib/components/content.js @@ -90,6 +90,27 @@ class Content extends React.Component { this.onChange(state) } + /** + * On before input, add the character to the state. + * + * @param {Event} e + */ + + onBeforeInput(e) { + let { state } = this.props + const { data } = e + + // If there is no data to input, there's nothing to do. + if (!data) return + e.preventDefault() + + // If the state is expanded, we will have to re-render. + if (state.isExpanded) state = state.delete() + + state = state.insert(data) + this.onChange(state) + } + /** * Render the editor content. * @@ -113,8 +134,9 @@ class Content extends React.Component { suppressContentEditableWarning spellCheck={false} data-type='content' - onKeyDown={(e) => this.onKeyDown(e)} - onSelect={(e) => this.onSelect(e)} + onKeyDown={e => this.onKeyDown(e)} + onSelect={e => this.onSelect(e)} + onBeforeInput={e => this.onBeforeInput(e)} style={style} > {children} diff --git a/lib/models/state.js b/lib/models/state.js index 7b7cdd894..308ccdc73 100644 --- a/lib/models/state.js +++ b/lib/models/state.js @@ -2,6 +2,7 @@ import Selection from './selection' import Node from './node' import Text from './text' +import convertRangesToCharacters from '../utils/convert-ranges-to-characters' import toCamel from 'to-camel-case' import { OrderedMap, Record } from 'immutable' @@ -281,6 +282,41 @@ class State extends StateRecord { const { startOffset } = state const endOffset = startOffset + 1 state = state.removeCharacters(startNode.key, startOffset, endOffset) + + return state + } + + /** + * Insert a `text` string at the current cursor position. + * + * @param {String} text + * @return {State} state + */ + + insert(text) { + let state = this + + // When still expanded, remove the current range first. + if (state.isExpanded) { + state = state.delete() + } + + // Insert text at the current cursor. + const ranges = [{ text }] + let { startNode, startOffset } = state + let { characters } = startNode + let newCharacters = convertRangesToCharacters(ranges) + const { size } = newCharacters + + // Splice in the new characters. + characters = characters.slice(0, startOffset) + .concat(newCharacters) + .concat(characters.slice(startOffset + size - 1, Infinity)) + + // Update the existing text node and the selection. + startNode = startNode.merge({ characters }) + state = state.updateNode(startNode) + state = state.moveForward(size) return state }