1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-18 21:21:21 +02:00

add support for spellcheck

This commit is contained in:
Ian Storm Taylor
2016-07-22 20:21:50 -07:00
parent 20874faa69
commit 2a58f71c42
4 changed files with 77 additions and 4 deletions

View File

@@ -37,6 +37,7 @@ class Content extends React.Component {
readOnly: React.PropTypes.bool,
renderMark: React.PropTypes.func.isRequired,
renderNode: React.PropTypes.func.isRequired,
spellCheck: React.PropTypes.bool,
state: React.PropTypes.object.isRequired,
style: React.PropTypes.object
};
@@ -47,6 +48,7 @@ class Content extends React.Component {
static defaultProps = {
readOnly: false,
spellCheck: true,
style: {}
};
@@ -376,6 +378,50 @@ class Content extends React.Component {
this.props.onDrop(e, drop)
}
/**
* On input, handle spellcheck and other similar edits that don't go trigger
* the `onBeforeInput` and instead update the DOM directly.
*
* @param {Event} e
*/
onInput = (e) => {
let { state } = this.props
const { selection } = state
const native = window.getSelection()
const { anchorNode, anchorOffset, focusOffset } = native
const { textContent } = anchorNode
const offsetKey = OffsetKey.findKey(anchorNode)
const { key, index } = OffsetKey.parse(offsetKey)
const { start, end } = OffsetKey.findBounds(key, index, state)
const range = OffsetKey.findRange(anchorNode, state)
const { text, marks } = range
// If the text is no different, abort.
if (textContent == text) return
// Determine what the selection should be after changing the text.
const delta = textContent.length - text.length
const after = selection.collapseToEnd().moveForward(delta)
// Create an updated state with the text replaced.
state = state
.transform()
.moveTo({
anchorKey: key,
anchorOffset: start,
focusKey: key,
focusOffset: end
})
.delete()
.insertText(textContent, marks)
.moveTo(after)
.apply()
// Change the current state.
this.onChange(state)
}
/**
* On key down, prevent the default behavior of certain commands that will
* leave the editor in an out-of-sync state, then bubble up.
@@ -547,6 +593,11 @@ class Content extends React.Component {
...this.props.style,
}
// COMPAT: In Firefox, spellchecking can remove entire wrapping elements
// including inline ones like `<a>`, which is jarring for the user but also
// causes the DOM to get into an irreconilable state.
const spellCheck = IS_FIREFOX ? false : this.props.spellCheck
return (
<div
key={`slate-content-${this.forces}`}
@@ -563,10 +614,12 @@ class Content extends React.Component {
onDragOver={this.onDragOver}
onDragStart={this.onDragStart}
onDrop={this.onDrop}
onInput={this.onInput}
onKeyDown={this.onKeyDown}
onKeyUp={noop}
onPaste={this.onPaste}
onSelect={this.onSelect}
spellCheck={spellCheck}
style={style}
>
{children}

View File

@@ -703,10 +703,11 @@ class State extends new Record(DEFAULTS) {
* Insert a `text` string at the current selection.
*
* @param {String} text
* @param {Set} marks (optional)
* @return {State} state
*/
insertText(text) {
insertText(text, marks) {
let state = this
let { cursorMarks, document, selection } = state
let after = selection
@@ -721,7 +722,7 @@ class State extends new Record(DEFAULTS) {
}
// Insert the text and update the selection.
document = document.insertTextAtRange(selection, text, cursorMarks)
document = document.insertTextAtRange(selection, text, marks || cursorMarks)
selection = after
state = state.merge({ document, selection })
return state

View File

@@ -66,7 +66,7 @@ function findKey(element) {
}
/**
* Find the selection point from an `element`, `offset`, and list of `ranges`.
* Find the selection point from an `element`, `offset`, and `state`.
*
* @param {Element} element
* @param {Offset} offset
@@ -90,6 +90,23 @@ function findPoint(element, offset, state) {
}
}
/**
* Find the range from an `element`.
*
* @param {Element} element
* @param {State} state
* @return {Range} range
*/
function findRange(element, state) {
const offsetKey = findKey(element)
const { key, index } = parse(offsetKey)
const text = state.document.getDescendant(key)
const ranges = text.getDecoratedRanges()
const range = ranges.get(index)
return range
}
/**
* Parse an offset key `string`.
*
@@ -103,7 +120,7 @@ function parse(string) {
const [ original, key, index ] = matches
return {
key,
index
index: parseInt(index, 10)
}
}
@@ -128,6 +145,7 @@ export default {
findBounds,
findKey,
findPoint,
findRange,
parse,
stringify
}

View File

@@ -54,6 +54,7 @@ function clean(html) {
$(el).removeAttr('data-offset-key')
})
$.root().children().removeAttr('spellcheck')
$.root().children().removeAttr('style')
return $.html()