diff --git a/docs/reference/components/editor.md b/docs/reference/components/editor.md index 6fd3525c9..ad7368192 100644 --- a/docs/reference/components/editor.md +++ b/docs/reference/components/editor.md @@ -23,6 +23,7 @@ The top-level React component that renders the Slate editor itself. - [Plugin-like Properties](#plugin-like-properties) - [`onBeforeInput`](#onbeforeinput) - [`onBlur`](#onblur) + - [`onFocus`](#onfocus) - [`onCopy`](#oncopy) - [`onCut`](#oncut) - [`onDrop`](#ondrop) @@ -163,6 +164,7 @@ const plugins = [ ### `onBeforeInput` ### `onBlur` +### `onFocus` ### `onCopy` ### `onCut` ### `onDrop` diff --git a/docs/reference/plugins/core.md b/docs/reference/plugins/core.md index 1dcd2f55e..f717b89aa 100644 --- a/docs/reference/plugins/core.md +++ b/docs/reference/plugins/core.md @@ -19,6 +19,10 @@ When text is entered, the core plugin inserts the text from `event.data` into th When the editor is blurred, the core plugin updates the selection in Slate's internal data model without re-rendering. +### `onFocus` + +When the editor is focused, the core plugin updates the selection in Slate's internal data model without re-rendering. + ### `onCopy` When the user copies part of the document, the core plugin adds the copied text to the clipboard with a serialized version of the document intact, so that it can be deserialized and inserted on paste, preserving formatting. diff --git a/docs/reference/plugins/plugin.md b/docs/reference/plugins/plugin.md index a8077a296..9450d6020 100644 --- a/docs/reference/plugins/plugin.md +++ b/docs/reference/plugins/plugin.md @@ -11,6 +11,7 @@ When the editor needs to resolve a plugin-related handler, it will loop through - [Event Handler Properties](#event-handle-properties) - [`onBeforeInput`](#onbeforeinput) - [`onBlur`](#onblur) + - [`onFocus`](#onfocus) - [`onCopy`](#oncopy) - [`onCut`](#oncut) - [`onDrop`](#ondrop) @@ -43,6 +44,7 @@ export default MySlatePlugin(options) { { onBeforeInput: Function, onBlur: Function, + onFocus: Function, onCopy: Function, onCut: Function, onDrop: Function, @@ -70,6 +72,13 @@ This handler is called when the editor's `contenteditable` element is blurred. If no other plugin handles this event, it will be handled by the [Core plugin](./core.md). +### `onFocus` +`Function onFocus(event: Event, data: Object, state: State, editor: Editor) => State || Void` + +This handler is called when the editor's `contenteditable` element is focused. + +If no other plugin handles this event, it will be handled by the [Core plugin](./core.md). + ### `onCopy` `Function onCopy(event: Event, data: Object, state: State, editor: Editor) => State || Void` diff --git a/src/components/content.js b/src/components/content.js index e53a0ca1c..60ca0a964 100644 --- a/src/components/content.js +++ b/src/components/content.js @@ -46,6 +46,7 @@ class Content extends React.Component { onCopy: React.PropTypes.func.isRequired, onCut: React.PropTypes.func.isRequired, onDrop: React.PropTypes.func.isRequired, + onFocus: React.PropTypes.func.isRequired, onKeyDown: React.PropTypes.func.isRequired, onPaste: React.PropTypes.func.isRequired, onSelect: React.PropTypes.func.isRequired, @@ -229,6 +230,23 @@ class Content extends React.Component { this.props.onBlur(event, data) } + /** + * On focus, update the selection to be focused. + * + * @param {Event} event + */ + + onFocus = (event) => { + if (this.props.readOnly) return + if (this.tmp.isCopying) return + if (!this.isInContentEditable(event)) return + + const data = {} + + debug('onFocus', { event, data }) + this.props.onFocus(event, data) + } + /** * On change, bubble up. * @@ -755,6 +773,7 @@ class Content extends React.Component { className={className} onBeforeInput={this.onBeforeInput} onBlur={this.onBlur} + onFocus={this.onFocus} onCompositionEnd={this.onCompositionEnd} onCompositionStart={this.onCompositionStart} onCopy={this.onCopy} diff --git a/src/components/editor.js b/src/components/editor.js index 7e90f18a2..1eec43abe 100644 --- a/src/components/editor.js +++ b/src/components/editor.js @@ -23,6 +23,7 @@ const debug = Debug('slate:editor') const EVENT_HANDLERS = [ 'onBeforeInput', 'onBlur', + 'onFocus', 'onCopy', 'onCut', 'onDrop', diff --git a/src/models/stack.js b/src/models/stack.js index aaab0660f..75ce3397c 100644 --- a/src/models/stack.js +++ b/src/models/stack.js @@ -22,6 +22,7 @@ const debug = Debug('slate:stack') const EVENT_HANDLER_METHODS = [ 'onBeforeInput', 'onBlur', + 'onFocus', 'onCopy', 'onCut', 'onDrop', diff --git a/src/plugins/core.js b/src/plugins/core.js index c5214723e..01a03e47b 100644 --- a/src/plugins/core.js +++ b/src/plugins/core.js @@ -167,6 +167,26 @@ function Plugin(options = {}) { .apply({ isNative }) } + /** + * On focus. + * + * @param {Event} e + * @param {Object} data + * @param {State} state + * @return {State} + */ + + function onFocus(e, data, state) { + const isNative = true + + debug('onFocus', { data, isNative }) + + return state + .transform() + .focus() + .apply({ isNative }) + } + /** * On copy. * @@ -834,6 +854,7 @@ function Plugin(options = {}) { editor={editor} onBeforeInput={editor.onBeforeInput} onBlur={editor.onBlur} + onFocus={editor.onFocus} onChange={editor.onChange} onCopy={editor.onCopy} onCut={editor.onCut} @@ -924,6 +945,7 @@ function Plugin(options = {}) { onBeforeChange, onBeforeInput, onBlur, + onFocus, onCopy, onCut, onDrop, diff --git a/test/helpers/simulate.js b/test/helpers/simulate.js index ccbe4c270..0ab708b17 100644 --- a/test/helpers/simulate.js +++ b/test/helpers/simulate.js @@ -8,6 +8,7 @@ const EVENT_HANDLERS = [ 'onBeforeInput', 'onBlur', + 'onFocus', 'onCopy', 'onCut', 'onDrop',