mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-20 06:01:24 +02:00
Fix handling of editor.isSelectable
in Editor.positions
(#5929)
* Fix handling of `editor.isSelectable` in `Editor.positions` * Clean-up
This commit is contained in:
7
.changeset/eleven-clocks-begin.md
Normal file
7
.changeset/eleven-clocks-begin.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
'slate': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
- Fix error when a non-selectable node has no next or previous node
|
||||||
|
- Do not return points from `Editor.positions` that are inside non-selectable nodes
|
||||||
|
- Previously, `editor.isSelectable` was handled incorrectly inside `Editor.positions`. When encountering a non-selectable node, it would immediately return the point before or after it (depending on `reverse`), but it would not skip returning points inside the non-selectable node if more than one point was consumed from `Editor.positions`.
|
@@ -51,6 +51,7 @@ export function* positions(
|
|||||||
let distance = 0 // Distance for leafText to catch up to blockText.
|
let distance = 0 // Distance for leafText to catch up to blockText.
|
||||||
let leafTextRemaining = 0
|
let leafTextRemaining = 0
|
||||||
let leafTextOffset = 0
|
let leafTextOffset = 0
|
||||||
|
const skippedPaths: Path[] = []
|
||||||
|
|
||||||
// Iterate through all nodes in range, grabbing entire textual content
|
// Iterate through all nodes in range, grabbing entire textual content
|
||||||
// of block nodes in blockText, and text nodes in leafText.
|
// of block nodes in blockText, and text nodes in leafText.
|
||||||
@@ -63,19 +64,35 @@ export function* positions(
|
|||||||
reverse,
|
reverse,
|
||||||
voids,
|
voids,
|
||||||
})) {
|
})) {
|
||||||
|
// If the node is inside a skipped ancestor, do not return any points, but
|
||||||
|
// still process its content so that the iteration state remains correct.
|
||||||
|
const hasSkippedAncestor = skippedPaths.some(p => Path.isAncestor(p, path))
|
||||||
|
|
||||||
|
function* maybeYield(point: Point) {
|
||||||
|
if (!hasSkippedAncestor) {
|
||||||
|
yield point
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ELEMENT NODE - Yield position(s) for voids, collect blockText for blocks
|
* ELEMENT NODE - Yield position(s) for voids, collect blockText for blocks
|
||||||
*/
|
*/
|
||||||
if (Element.isElement(node)) {
|
if (Element.isElement(node)) {
|
||||||
if (!editor.isSelectable(node)) {
|
if (!editor.isSelectable(node)) {
|
||||||
/**
|
/**
|
||||||
* If the node is not selectable, skip it
|
* If the node is not selectable, skip it and its descendants
|
||||||
*/
|
*/
|
||||||
|
skippedPaths.push(path)
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
yield Editor.end(editor, Path.previous(path))
|
if (Path.hasPrevious(path)) {
|
||||||
|
yield* maybeYield(Editor.end(editor, Path.previous(path)))
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
yield Editor.start(editor, Path.next(path))
|
const nextPath = Path.next(path)
|
||||||
|
if (Editor.hasPath(editor, nextPath)) {
|
||||||
|
yield* maybeYield(Editor.start(editor, nextPath))
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,7 +101,7 @@ export function* positions(
|
|||||||
// yield their first point. If the `voids` option is set to true,
|
// yield their first point. If the `voids` option is set to true,
|
||||||
// then we will iterate over their content.
|
// then we will iterate over their content.
|
||||||
if (!voids && (editor.isVoid(node) || editor.isElementReadOnly(node))) {
|
if (!voids && (editor.isVoid(node) || editor.isElementReadOnly(node))) {
|
||||||
yield Editor.start(editor, path)
|
yield* maybeYield(Editor.start(editor, path))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +160,7 @@ export function* positions(
|
|||||||
|
|
||||||
// Yield position at the start of node (potentially).
|
// Yield position at the start of node (potentially).
|
||||||
if (isFirst || isNewBlock || unit === 'offset') {
|
if (isFirst || isNewBlock || unit === 'offset') {
|
||||||
yield { path, offset: leafTextOffset }
|
yield* maybeYield({ path, offset: leafTextOffset })
|
||||||
isNewBlock = false
|
isNewBlock = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +195,7 @@ export function* positions(
|
|||||||
// to catch up with `blockText`, so we can reset `distance`
|
// to catch up with `blockText`, so we can reset `distance`
|
||||||
// and yield this position in this node.
|
// and yield this position in this node.
|
||||||
distance = 0
|
distance = 0
|
||||||
yield { path, offset: leafTextOffset }
|
yield* maybeYield({ path, offset: leafTextOffset })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,17 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>one</block>
|
||||||
|
<block nonSelectable>two</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const test = editor => {
|
||||||
|
return Editor.after(editor, { path: [0, 0], offset: 3 })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = undefined
|
@@ -0,0 +1,18 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>one</block>
|
||||||
|
<block nonSelectable>two</block>
|
||||||
|
<block>three</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const test = editor => {
|
||||||
|
return Editor.after(editor, { path: [0, 0], offset: 3 })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = { path: [2, 0], offset: 0 }
|
@@ -0,0 +1,20 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
// This is invalid due to the lack of a text node after the inline, but this
|
||||||
|
// case can arise prior to normalization so it needs to be handled anyway.
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
one<inline nonSelectable>two</inline>
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const test = editor => {
|
||||||
|
return Editor.after(editor, { path: [0, 0], offset: 3 })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = undefined
|
@@ -0,0 +1,17 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block nonSelectable>two</block>
|
||||||
|
<block>three</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const test = editor => {
|
||||||
|
return Editor.before(editor, { path: [1, 0], offset: 0 })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = undefined
|
@@ -0,0 +1,18 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>one</block>
|
||||||
|
<block nonSelectable>two</block>
|
||||||
|
<block>three</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const test = editor => {
|
||||||
|
return Editor.before(editor, { path: [2, 0], offset: 0 })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = { path: [0, 0], offset: 3 }
|
@@ -0,0 +1,20 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
// This is invalid due to the lack of a text node before the inline, but this
|
||||||
|
// case can arise prior to normalization so it needs to be handled anyway.
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<inline nonSelectable>two</inline>three
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const test = editor => {
|
||||||
|
return Editor.before(editor, { path: [0, 1], offset: 0 })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = undefined
|
Reference in New Issue
Block a user