mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-27 17:09:53 +02:00
Apply no-children normalization fix before normalization (#4208)
* Test cases for failure condition * Before normalizing ensure all elements have at least one text child. This is a normalization requirement that some normalization fixes require, so it must be done as an initial dedicated pass.
This commit is contained in:
5
.changeset/silver-snakes-perform.md
Normal file
5
.changeset/silver-snakes-perform.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'slate': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix `Error: Cannot get the start point in the node at path [...] because it has no start text node` caused by normalizing a document where some elements have no children
|
@@ -16,6 +16,7 @@ import {
|
|||||||
RangeRef,
|
RangeRef,
|
||||||
Span,
|
Span,
|
||||||
Text,
|
Text,
|
||||||
|
Transforms,
|
||||||
} from '..'
|
} from '..'
|
||||||
import {
|
import {
|
||||||
DIRTY_PATHS,
|
DIRTY_PATHS,
|
||||||
@@ -988,6 +989,27 @@ export const Editor: EditorInterface = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Editor.withoutNormalizing(editor, () => {
|
Editor.withoutNormalizing(editor, () => {
|
||||||
|
/*
|
||||||
|
Fix dirty elements with no children.
|
||||||
|
editor.normalizeNode() does fix this, but some normalization fixes also require it to work.
|
||||||
|
Running an initial pass avoids the catch-22 race condition.
|
||||||
|
*/
|
||||||
|
for (const dirtyPath of getDirtyPaths(editor)) {
|
||||||
|
if (Node.has(editor, dirtyPath)) {
|
||||||
|
const [node, _] = Editor.node(editor, dirtyPath)
|
||||||
|
|
||||||
|
// Add a text child to elements with no children.
|
||||||
|
// This is safe to do in any order, by definition it can't cause other paths to change.
|
||||||
|
if (Element.isElement(node) && node.children.length === 0) {
|
||||||
|
const child = { text: '' }
|
||||||
|
Transforms.insertNodes(editor, child, {
|
||||||
|
at: dirtyPath.concat(0),
|
||||||
|
voids: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const max = getDirtyPaths(editor).length * 42 // HACK: better way?
|
const max = getDirtyPaths(editor).length * 42 // HACK: better way?
|
||||||
let m = 0
|
let m = 0
|
||||||
|
|
||||||
|
21
packages/slate/test/transforms/normalization/move_node.tsx
Normal file
21
packages/slate/test/transforms/normalization/move_node.tsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
import { Transforms } from 'slate'
|
||||||
|
import { jsx } from '../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>one</block>
|
||||||
|
<block>two</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
export const run = editor => {
|
||||||
|
Transforms.moveNodes(editor, { at: [0, 0], to: [1, 0] })
|
||||||
|
}
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
<block>onetwo</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,84 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
import { Editor, Transforms } from 'slate'
|
||||||
|
import { jsx } from '../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline>one</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline>two</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.withoutNormalizing(editor, () => {
|
||||||
|
const operations = [
|
||||||
|
{
|
||||||
|
type: 'split_node',
|
||||||
|
path: [0, 1],
|
||||||
|
position: 0,
|
||||||
|
properties: { inline: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'split_node',
|
||||||
|
path: [0],
|
||||||
|
position: 1,
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'split_node',
|
||||||
|
path: [2, 1, 0],
|
||||||
|
position: 0,
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'split_node',
|
||||||
|
path: [2, 1],
|
||||||
|
position: 0,
|
||||||
|
properties: { inline: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'split_node',
|
||||||
|
path: [2],
|
||||||
|
position: 1,
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
{ type: 'insert_node', path: [2, 1], node: { text: '' } },
|
||||||
|
]
|
||||||
|
operations.forEach(editor.apply)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline>
|
||||||
|
<text />
|
||||||
|
</inline>
|
||||||
|
<text />
|
||||||
|
<inline>one</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline>
|
||||||
|
<text />
|
||||||
|
</inline>
|
||||||
|
<text />
|
||||||
|
<inline>two</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
Reference in New Issue
Block a user