mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-27 09:04:31 +02:00
handle lots of splitting cases
This commit is contained in:
@@ -53,6 +53,10 @@ class Inline extends new Record(DEFAULTS) {
|
|||||||
properties.isVoid = !!properties.isVoid
|
properties.isVoid = !!properties.isVoid
|
||||||
properties.nodes = Inline.createList(properties.nodes)
|
properties.nodes = Inline.createList(properties.nodes)
|
||||||
|
|
||||||
|
if (properties.nodes.size == 0) {
|
||||||
|
properties.nodes = properties.nodes.push(Text.create())
|
||||||
|
}
|
||||||
|
|
||||||
return new Inline(properties).normalize()
|
return new Inline(properties).normalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -436,18 +436,38 @@ export function splitBlock(transform, depth = 1) {
|
|||||||
export function splitInline(transform, depth = Infinity) {
|
export function splitInline(transform, depth = Infinity) {
|
||||||
let { state } = transform
|
let { state } = transform
|
||||||
let { document, selection } = state
|
let { document, selection } = state
|
||||||
|
|
||||||
|
// If the selection is expanded, remove it first.
|
||||||
|
if (selection.isExpanded) {
|
||||||
|
transform.delete()
|
||||||
|
state = transform.state
|
||||||
|
document = state.document
|
||||||
|
selection = state.selection
|
||||||
|
}
|
||||||
|
|
||||||
let after = selection
|
let after = selection
|
||||||
|
const { startKey, startOffset } = selection
|
||||||
|
let startNode = document.assertDescendant(startKey)
|
||||||
|
const furthestInline = document.getFurthestInline(startKey)
|
||||||
|
const offset = furthestInline.getOffset(startNode)
|
||||||
|
|
||||||
|
// If the selection is at the start of end of the furthest inline, there isn't
|
||||||
|
// anything to split, so abort.
|
||||||
|
if (
|
||||||
|
(offset + startOffset == 0) ||
|
||||||
|
(offset + startNode.length == startOffset)
|
||||||
|
) {
|
||||||
|
return transform
|
||||||
|
}
|
||||||
|
|
||||||
transform.unsetSelection()
|
transform.unsetSelection()
|
||||||
transform.splitInlineAtRange(selection, depth)
|
transform.splitInlineAtRange(selection, depth)
|
||||||
state = transform.state
|
state = transform.state
|
||||||
document = state.document
|
document = state.document
|
||||||
|
const closestInline = document.getClosestInline(startKey)
|
||||||
|
|
||||||
const { startKey } = selection
|
if (closestInline) {
|
||||||
const inlineParent = document.getClosestInline(startKey)
|
startNode = document.getDescendant(startKey)
|
||||||
|
|
||||||
if (inlineParent) {
|
|
||||||
const startNode = document.getDescendant(startKey)
|
|
||||||
const nextNode = document.getNextText(startNode)
|
const nextNode = document.getNextText(startNode)
|
||||||
after = selection.collapseToStartOf(nextNode)
|
after = selection.collapseToStartOf(nextNode)
|
||||||
}
|
}
|
||||||
|
@@ -268,7 +268,6 @@ export function insertBlockAtRange(transform, range, block) {
|
|||||||
transform.insertNodeByKey(parent.key, index + 1, block)
|
transform.insertNodeByKey(parent.key, index + 1, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
transform.normalizeDocument()
|
|
||||||
return transform
|
return transform
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,7 +384,6 @@ export function insertInlineAtRange(transform, range, inline) {
|
|||||||
|
|
||||||
transform.splitNodeByKey(startKey, startOffset)
|
transform.splitNodeByKey(startKey, startOffset)
|
||||||
transform.insertNodeByKey(parent.key, index + 1, inline)
|
transform.insertNodeByKey(parent.key, index + 1, inline)
|
||||||
transform.normalizeDocument()
|
|
||||||
return transform
|
return transform
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -818,15 +816,25 @@ export function wrapInlineAtRange(transform, range, inline) {
|
|||||||
: endChild.getOffset(endKey) + endOffset
|
: endChild.getOffset(endKey) + endOffset
|
||||||
|
|
||||||
if (startBlock == endBlock) {
|
if (startBlock == endBlock) {
|
||||||
transform.splitNodeByKey(endChild.key, endOff)
|
if (endOff != endChild.length) {
|
||||||
transform.splitNodeByKey(startChild.key, startOff)
|
transform.splitNodeByKey(endChild.key, endOff)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startOff != 0) {
|
||||||
|
transform.splitNodeByKey(startChild.key, startOff)
|
||||||
|
}
|
||||||
|
|
||||||
state = transform.state
|
state = transform.state
|
||||||
document = state.document
|
document = state.document
|
||||||
startBlock = document.getClosestBlock(startKey)
|
startBlock = document.getClosestBlock(startKey)
|
||||||
startChild = startBlock.getHighestChild(startKey)
|
startChild = startBlock.getHighestChild(startKey)
|
||||||
const startInner = document.getNextSibling(startChild)
|
|
||||||
|
const startInner = startOff == 0
|
||||||
|
? startChild
|
||||||
|
: document.getNextSibling(startChild)
|
||||||
|
|
||||||
const startInnerIndex = startBlock.nodes.indexOf(startInner)
|
const startInnerIndex = startBlock.nodes.indexOf(startInner)
|
||||||
|
|
||||||
const endInner = startKey == endKey ? startInner : startBlock.getHighestChild(endKey)
|
const endInner = startKey == endKey ? startInner : startBlock.getHighestChild(endKey)
|
||||||
const inlines = startBlock.nodes
|
const inlines = startBlock.nodes
|
||||||
.skipUntil(n => n == startInner)
|
.skipUntil(n => n == startInner)
|
||||||
@@ -877,7 +885,6 @@ export function wrapInlineAtRange(transform, range, inline) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
transform.normalizeDocument()
|
|
||||||
return transform
|
return transform
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -308,7 +308,7 @@ export function setNodeByKey(transform, key, properties) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the `isVoid` property is being changed to `false` and the node is an
|
// If the `isVoid` property is being changed to `false` and the node is an
|
||||||
// inline node, remove any additional unnecessary text it.
|
// inline node, remove any additional unnecessary text around it.
|
||||||
if (
|
if (
|
||||||
properties.isVoid == false &&
|
properties.isVoid == false &&
|
||||||
node.isVoid == true &&
|
node.isVoid == true &&
|
||||||
@@ -344,8 +344,90 @@ export function setNodeByKey(transform, key, properties) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export function splitNodeByKey(transform, key, offset) {
|
export function splitNodeByKey(transform, key, offset) {
|
||||||
const { state } = transform
|
let { state } = transform
|
||||||
const { document } = state
|
let { document } = state
|
||||||
const path = document.getPath(key)
|
const path = document.getPath(key)
|
||||||
return transform.splitNodeOperation(path, offset)
|
transform.splitNodeOperation(path, offset)
|
||||||
|
|
||||||
|
// Traverse the nodes on both sides of the split, ensuring that there are no
|
||||||
|
// empty inline nodes, or empty text nodes that should be removed.
|
||||||
|
state = transform.state
|
||||||
|
document = state.document
|
||||||
|
const parent = document.getParent(key)
|
||||||
|
|
||||||
|
// Define an iterator that will apply normalization transforms.
|
||||||
|
parent.filterDescendants((d) => {
|
||||||
|
|
||||||
|
// We don't need to do any normalization for block nodes.
|
||||||
|
if (d.kind == 'block') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an inline void node has no text, add a space character.
|
||||||
|
if (
|
||||||
|
d.kind == 'inline' &&
|
||||||
|
d.text == '' &&
|
||||||
|
d.isVoid == true
|
||||||
|
) {
|
||||||
|
transform.insertTextByKey(d.key, 0, ' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an non-void inline node has no text now, remove it.
|
||||||
|
if (
|
||||||
|
d.kind == 'inline' &&
|
||||||
|
d.text == '' &&
|
||||||
|
d.isVoid == false
|
||||||
|
) {
|
||||||
|
transform.removeNodeByKey(d.key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to ensure that extra empty text nodes are preserved around inline
|
||||||
|
// void nodes.
|
||||||
|
if (
|
||||||
|
d.kind == 'inline' &&
|
||||||
|
d.isVoid == true
|
||||||
|
) {
|
||||||
|
const previous = document.getPreviousSibling(d)
|
||||||
|
const next = document.getNextSibling(d)
|
||||||
|
|
||||||
|
if (
|
||||||
|
(!previous) ||
|
||||||
|
(previous.kind == 'block' || previous.kind == 'inline' && previous.isVoid)
|
||||||
|
) {
|
||||||
|
const p = document.getParent(d)
|
||||||
|
const index = p.nodes.indexOf(d)
|
||||||
|
const text = Text.create()
|
||||||
|
transform.insertNodeByKey(p, index, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(!next) ||
|
||||||
|
(next.kind == 'block' || next.kind == 'inline' && next.isVoid)
|
||||||
|
) {
|
||||||
|
const p = document.getParent(d)
|
||||||
|
const index = p.nodes.indexOf(d)
|
||||||
|
const text = Text.create()
|
||||||
|
transform.insertNodeByKey(p, index + 1, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an empty text node is adjacent to an non-void inline node, remove it.
|
||||||
|
if (
|
||||||
|
d.kind == 'text' &&
|
||||||
|
d.text == ''
|
||||||
|
) {
|
||||||
|
const previous = document.getPreviousSibling(d)
|
||||||
|
const next = document.getNextSibling(d)
|
||||||
|
|
||||||
|
if (
|
||||||
|
(previous && previous.kind == 'inline' && previous.isVoid == false) ||
|
||||||
|
(next && next.kind == 'inline' && next.isVoid == false)
|
||||||
|
) {
|
||||||
|
transform.removeNodeByKey(d.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Return the transform.
|
||||||
|
return transform
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,7 @@ export default function (state) {
|
|||||||
|
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
next.selection.toJS(),
|
next.selection.toJS(),
|
||||||
range.collapseToStartOf(updated).toJS()
|
range.collapseToEndOf(updated).toJS()
|
||||||
)
|
)
|
||||||
|
|
||||||
return next
|
return next
|
||||||
|
@@ -8,8 +8,3 @@ nodes:
|
|||||||
nodes:
|
nodes:
|
||||||
- kind: text
|
- kind: text
|
||||||
text: word
|
text: word
|
||||||
- kind: inline
|
|
||||||
type: link
|
|
||||||
nodes:
|
|
||||||
- kind: text
|
|
||||||
text: ""
|
|
||||||
|
@@ -3,11 +3,6 @@ nodes:
|
|||||||
- kind: block
|
- kind: block
|
||||||
type: paragraph
|
type: paragraph
|
||||||
nodes:
|
nodes:
|
||||||
- kind: inline
|
|
||||||
type: link
|
|
||||||
nodes:
|
|
||||||
- kind: text
|
|
||||||
text: ""
|
|
||||||
- kind: inline
|
- kind: inline
|
||||||
type: link
|
type: link
|
||||||
nodes:
|
nodes:
|
||||||
|
@@ -8,8 +8,3 @@ nodes:
|
|||||||
nodes:
|
nodes:
|
||||||
- kind: text
|
- kind: text
|
||||||
text: word
|
text: word
|
||||||
- kind: inline
|
|
||||||
type: link
|
|
||||||
nodes:
|
|
||||||
- kind: text
|
|
||||||
text: ""
|
|
||||||
|
@@ -3,11 +3,6 @@ nodes:
|
|||||||
- kind: block
|
- kind: block
|
||||||
type: paragraph
|
type: paragraph
|
||||||
nodes:
|
nodes:
|
||||||
- kind: inline
|
|
||||||
type: link
|
|
||||||
nodes:
|
|
||||||
- kind: text
|
|
||||||
text: ""
|
|
||||||
- kind: inline
|
- kind: inline
|
||||||
type: link
|
type: link
|
||||||
nodes:
|
nodes:
|
||||||
|
Reference in New Issue
Block a user