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

Fix improper selection after insertFragment (#2976)

* Fix typo & remove useless check

* No need to check the end of the selection, as this part is called after the
  `deleteExpanded` call. Selection is collapsed at this point.

* Fix insertFragment selection not place properly
This commit is contained in:
Charley DAVID
2019-08-22 04:39:38 +02:00
committed by Ian Storm Taylor
parent 3ed981aedf
commit 2ea6d40ad0
8 changed files with 158 additions and 39 deletions

View File

@@ -735,7 +735,7 @@ Commands.insertFragmentAtRange = (editor, range, fragment) => {
// Regenerate the keys for all of the fragments nodes, so that they're
// guaranteed not to collide with the existing keys in the document. Otherwise
// they will be rengerated automatically and we won't have an easy way to
// they will be regenerated automatically and we won't have an easy way to
// reference them.
fragment = fragment.mapDescendants(child => child.regenerateKey())

View File

@@ -252,46 +252,41 @@ Commands.insertFragment = (editor, fragment) => {
let { value } = editor
let { document, selection } = value
const { start, end } = selection
const { startText, endText, startInline } = value
const lastText = fragment.getLastText()
const lastInline = fragment.getClosestInline(lastText.key)
const lastBlock = fragment.getClosestBlock(lastText.key)
const firstChild = fragment.nodes.first()
const lastChild = fragment.nodes.last()
const { start } = selection
const keys = Array.from(document.texts(), ([text]) => text.key)
const isAppending =
!startInline ||
(start.isAtStartOfNode(startText) || end.isAtStartOfNode(startText)) ||
(start.isAtEndOfNode(endText) || end.isAtEndOfNode(endText))
const isInserting =
firstChild.hasBlockChildren() || lastChild.hasBlockChildren()
editor.insertFragmentAtRange(selection, fragment)
value = editor.value
document = value.document
const newTexts = document.getTexts().filter(n => !keys.includes(n.key))
const newText = isAppending ? newTexts.last() : newTexts.takeLast(2).first()
if (newTexts.size === 0) return
const fragmentLength = fragment.text.length
if (newText && (lastInline || isInserting)) {
editor.moveToEndOfNode(newText)
} else if (newText) {
// The position within the last text node needs to be calculated. This is the length
// of all text nodes within the last block, but if the last block contains inline nodes,
// these have to be skipped.
const { nodes } = lastBlock
const lastIndex = nodes.findLastIndex(
node => node && node.object === 'inline'
)
const remainingTexts = nodes.takeLast(nodes.size - lastIndex - 1)
const remainingTextLength = remainingTexts.reduce(
(acc, val) => acc + val.text.length,
0
)
editor.moveToStartOfNode(newText).moveForward(remainingTextLength)
// Either startText is still here, or we want the first un-previously known text
const startText = document.getNode(start.key) || newTexts.first()
// We want the last un-previously known text
let endText = newTexts.last() || startText
if (startText === endText) {
editor.moveTo(endText.key, fragmentLength)
return
}
// Everything will be calculated relative to the first common ancestor to optimize speed
const parent = document.getCommonAncestor(startText.key, endText.key)
const startOffset =
parent.getOffset(startText.key) +
(start.key === startText.key ? start.offset : 0)
// endText might not be the last un-previously known text node, so we precisely pick it by offset
endText = parent.getTextAtOffset(startOffset + fragmentLength - 1) || endText
editor.moveTo(
endText.key,
startOffset + fragmentLength - parent.getOffset(endText.key)
)
}
/**

View File

@@ -0,0 +1,41 @@
/** @jsx h */
import h from '../../../helpers/h'
export default function(editor) {
editor.insertFragment(
<document>
<paragraph>
<b>b</b>
<u>u</u>
<i>i</i>
</paragraph>
</document>
)
}
export const input = (
<value>
<document>
<paragraph>
wo<cursor />rd
</paragraph>
</document>
</value>
)
export const output = (
<value>
<document>
<paragraph>
wo
<b>b</b>
<u>u</u>
<i>
i<cursor />
</i>
rd
</paragraph>
</document>
</value>
)

View File

@@ -29,11 +29,11 @@ export const output = (
<paragraph>wo</paragraph>
<quote>
<quote>one</quote>
<quote>two</quote>
<quote>
two<cursor />
</quote>
</quote>
<paragraph>
rd<cursor />
</paragraph>
<paragraph>rd</paragraph>
</document>
</value>
)

View File

@@ -0,0 +1,41 @@
/** @jsx h */
import h from '../../../helpers/h'
export default function(editor) {
editor.insertFragment(
<document>
<paragraph>
<inline type="link">bar</inline>
</paragraph>
</document>
)
}
export const input = (
<value>
<document>
<code>
<paragraph>
Foo<cursor />baz
</paragraph>
</code>
</document>
</value>
)
export const output = (
<value>
<document>
<code>
<paragraph>
Foo
<inline type="link">
bar<cursor />
</inline>
baz
</paragraph>
</code>
</document>
</value>
)

View File

@@ -0,0 +1,41 @@
/** @jsx h */
import h from '../../../helpers/h'
export default function(editor) {
editor.insertFragment(
<document>
<paragraph>
<b>bar</b>
</paragraph>
</document>
)
}
export const input = (
<value>
<document>
<code>
<paragraph>
Foo<cursor />baz
</paragraph>
</code>
</document>
</value>
)
export const output = (
<value>
<document>
<code>
<paragraph>
Foo
<b>
bar<cursor />
</b>
baz
</paragraph>
</code>
</document>
</value>
)

View File

@@ -29,8 +29,9 @@ export const output = (
<document>
<paragraph>
<link>wo</link>
<hashtag>fragment</hashtag>
<cursor />
<hashtag>
fragment<cursor />
</hashtag>
<link>rd</link>
</paragraph>
</document>

View File

@@ -31,7 +31,7 @@ export const output = (
<quote>
<paragraph>woone</paragraph>
<quote>
tword<cursor />
two<cursor />rd
</quote>
</quote>
</document>