From 789c4b30023b7831e8f541b3330fb57ecb8eddef Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Mon, 1 Aug 2016 18:26:27 -0700 Subject: [PATCH] fix void leaf selection handling --- docs/reference/models/transform.md | 4 ++++ examples/images/index.js | 38 +++--------------------------- lib/components/leaf.js | 30 +++++++++++++++++++++-- lib/components/void.js | 1 + 4 files changed, 36 insertions(+), 37 deletions(-) diff --git a/docs/reference/models/transform.md b/docs/reference/models/transform.md index 07c537d6f..5b23d18bd 100644 --- a/docs/reference/models/transform.md +++ b/docs/reference/models/transform.md @@ -17,7 +17,9 @@ Transform methods can either operate on the [`Document`](./document.md), the [`S - [`deleteBackward`](#deletebackward) - [`deleteForward`](#deleteforward) - [`delete`](#delete) + - [`insertBlock`](#insertblock) - [`insertFragment`](#insertfragment) + - [`insertInline`](#insertinline) - [`insertText`](#inserttext) - [`addMark`](#addmark) - [`setBlock`](#setblock) @@ -50,7 +52,9 @@ Transform methods can either operate on the [`Document`](./document.md), the [`S - [`deleteAtRange`](#deleteatrange) - [`deleteBackwardAtRange`](#deletebackwardatrange) - [`deleteForwardAtRange`](#deleteforwardatrange) + - [`insertBlockAtRange`](#insertblockatrange) - [`insertFragmentAtRange`](#insertfragmentatrange) + - [`insertInlineAtRange`](#insertinlineatrange) - [`insertTextAtRange`](#inserttextatrange) - [`addMarkAtRange`](#addmarkatrange) - [`setBlockAtRange`](#setblockatrange) diff --git a/examples/images/index.js b/examples/images/index.js index 21f0eee6e..ab7a2ae88 100644 --- a/examples/images/index.js +++ b/examples/images/index.js @@ -202,41 +202,9 @@ class Images extends React.Component { */ insertImage = (state, src) => { - if (state.isExpanded) { - state = state - .transform() - .delete() - .apply() - } - - const { anchorBlock, selection } = state - let transform = state.transform() - - if (anchorBlock.type == 'image') { - transform = transform.splitBlock() - } - - else if (anchorBlock.text != '') { - if (selection.isAtEndOf(anchorBlock)) { - transform = transform.splitBlock() - } - - else if (selection.isAtStartOf(anchorBlock)) { - transform = transform - .splitBlock() - .collapseToStartOfPreviousBlock() - } - - else { - transform = transform - .splitBlock() - .splitBlock() - .collapseToStartOfPreviousBlock() - } - } - - return transform - .setBlock({ + return state + .transform() + .insertBlock({ type: 'image', isVoid: true, data: { src } diff --git a/lib/components/leaf.js b/lib/components/leaf.js index 52c1dc399..2b8be2a5e 100644 --- a/lib/components/leaf.js +++ b/lib/components/leaf.js @@ -28,6 +28,7 @@ class Leaf extends React.Component { static propTypes = { index: React.PropTypes.number.isRequired, + isVoid: React.PropTypes.bool, marks: React.PropTypes.object.isRequired, node: React.PropTypes.object.isRequired, ranges: React.PropTypes.object.isRequired, @@ -36,6 +37,16 @@ class Leaf extends React.Component { text: React.PropTypes.string.isRequired }; + /** + * Default properties. + * + * @type {Object} + */ + + static defaultProps = { + isVoid: false + }; + /** * Constructor. * @@ -85,6 +96,10 @@ class Leaf extends React.Component { return state.selection.hasEdgeBetween(node, start, end) } + /** + * When the DOM updates, try updating the selection. + */ + componentDidMount() { this.updateSelection() } @@ -93,14 +108,18 @@ class Leaf extends React.Component { this.updateSelection() } + /** + * Update the DOM selection if it's inside the leaf. + */ + updateSelection() { - const { state, ranges } = this.props + const { state, ranges, isVoid } = this.props const { selection } = state // If the selection is blurred we have nothing to do. if (selection.isBlurred) return - const { anchorOffset, focusOffset } = selection + let { anchorOffset, focusOffset } = selection const { node, index } = this.props const { start, end } = OffsetKey.findBounds(index, ranges) @@ -109,6 +128,13 @@ class Leaf extends React.Component { const hasFocus = selection.hasFocusBetween(node, start, end) if (!hasAnchor && !hasFocus) return + // If the leaf is a void leaf, ensure that it has no width. This is due to + // void nodes always rendering an empty leaf, for browser compatibility. + if (isVoid) { + anchorOffset = 0 + focusOffset = 0 + } + // We have a selection to render, so prepare a few things... const native = window.getSelection() const el = findDeepestNode(ReactDOM.findDOMNode(this)) diff --git a/lib/components/void.js b/lib/components/void.js index 6f977ca27..93b7dd4b9 100644 --- a/lib/components/void.js +++ b/lib/components/void.js @@ -164,6 +164,7 @@ class Void extends React.Component { return (