mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-17 20:51:20 +02:00
fix deleteAtRange to split only to common ancestor
This commit is contained in:
@@ -296,6 +296,32 @@ const Node = {
|
|||||||
return this.nodes.find(node => node.key == key)
|
return this.nodes.find(node => node.key == key)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the common ancestor of nodes `one` and `two` by keys.
|
||||||
|
*
|
||||||
|
* @param {String or Node} one
|
||||||
|
* @param {String or Node} two
|
||||||
|
* @return {Node}
|
||||||
|
*/
|
||||||
|
|
||||||
|
getCommonAncestor(one, two) {
|
||||||
|
this.assertDescendant(one)
|
||||||
|
this.assertDescendant(two)
|
||||||
|
let ancestors = new List()
|
||||||
|
let oneParent = this.getParent(one)
|
||||||
|
let twoParent = this.getParent(two)
|
||||||
|
|
||||||
|
while (oneParent) {
|
||||||
|
ancestors = ancestors.push(oneParent)
|
||||||
|
oneParent = this.getParent(oneParent)
|
||||||
|
}
|
||||||
|
|
||||||
|
while (twoParent) {
|
||||||
|
if (ancestors.includes(twoParent)) return twoParent
|
||||||
|
twoParent = this.getParent(twoParent)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a descendant node by `key`.
|
* Get a descendant node by `key`.
|
||||||
*
|
*
|
||||||
|
@@ -86,42 +86,50 @@ const Transforms = {
|
|||||||
// Split the blocks and determine the edge boundaries.
|
// Split the blocks and determine the edge boundaries.
|
||||||
const start = range.collapseToStart()
|
const start = range.collapseToStart()
|
||||||
const end = range.collapseToEnd()
|
const end = range.collapseToEnd()
|
||||||
node = node.splitBlockAtRange(start, Infinity)
|
let ancestor = node.getCommonAncestor(startKey, endKey)
|
||||||
node = node.splitBlockAtRange(end, Infinity)
|
const isAncestor = ancestor == node
|
||||||
|
|
||||||
const startText = node.getDescendant(startKey)
|
ancestor = ancestor.splitBlockAtRange(start, Infinity)
|
||||||
const startEdgeText = node.getNextText(startKey)
|
ancestor = ancestor.splitBlockAtRange(end, Infinity)
|
||||||
|
|
||||||
const endText = node.getNextText(endKey)
|
const startText = ancestor.getDescendant(startKey)
|
||||||
const endEdgeText = node.getDescendant(endKey)
|
const startEdgeText = ancestor.getNextText(startKey)
|
||||||
|
|
||||||
|
const endText = ancestor.getNextText(endKey)
|
||||||
|
const endEdgeText = ancestor.getDescendant(endKey)
|
||||||
|
|
||||||
// Remove the new blocks inside the edges.
|
// Remove the new blocks inside the edges.
|
||||||
const startEdgeBlock = node.getFurthestBlock(startEdgeText)
|
const startEdgeBlock = ancestor.getFurthestBlock(startEdgeText)
|
||||||
const endEdgeBlock = node.getFurthestBlock(endEdgeText)
|
const endEdgeBlock = ancestor.getFurthestBlock(endEdgeText)
|
||||||
|
|
||||||
const nodes = node.nodes
|
const nodes = ancestor.nodes
|
||||||
.takeUntil(n => n == startEdgeBlock)
|
.takeUntil(n => n == startEdgeBlock)
|
||||||
.concat(node.nodes.skipUntil(n => n == endEdgeBlock).rest())
|
.concat(ancestor.nodes.skipUntil(n => n == endEdgeBlock).rest())
|
||||||
|
|
||||||
node = node.merge({ nodes })
|
ancestor = ancestor.merge({ nodes })
|
||||||
|
|
||||||
// Take the end edge's split text and move it to the start edge.
|
// Take the end edge's split text and move it to the start edge.
|
||||||
let startBlock = node.getClosestBlock(startText)
|
let startBlock = ancestor.getClosestBlock(startText)
|
||||||
let endChild = node.getFurthestInline(endText) || endText
|
let endChild = ancestor.getFurthestInline(endText) || endText
|
||||||
|
|
||||||
const startNodes = startBlock.nodes.push(endChild)
|
const startNodes = startBlock.nodes.push(endChild)
|
||||||
startBlock = startBlock.merge({ nodes: startNodes })
|
startBlock = startBlock.merge({ nodes: startNodes })
|
||||||
node = node.updateDescendant(startBlock)
|
ancestor = ancestor.updateDescendant(startBlock)
|
||||||
|
|
||||||
// While the end child is an only child, remove the block it's in.
|
// While the end child is an only child, remove the block it's in.
|
||||||
let endParent = node.getClosestBlock(endChild)
|
let endParent = ancestor.getClosestBlock(endChild)
|
||||||
|
|
||||||
while (endParent && endParent.nodes.size == 1) {
|
while (endParent && endParent.nodes.size == 1) {
|
||||||
endChild = endParent
|
endChild = endParent
|
||||||
endParent = node.getClosestBlock(endParent)
|
endParent = ancestor.getClosestBlock(endParent)
|
||||||
}
|
}
|
||||||
|
|
||||||
node = node.removeDescendant(endChild)
|
ancestor = ancestor.removeDescendant(endChild)
|
||||||
|
|
||||||
|
// Update the node.
|
||||||
|
node = isAncestor
|
||||||
|
? ancestor
|
||||||
|
: node.updateDescendant(ancestor)
|
||||||
|
|
||||||
// Normalize the adjacent text nodes.
|
// Normalize the adjacent text nodes.
|
||||||
return node.normalize()
|
return node.normalize()
|
||||||
|
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
export default function (state) {
|
||||||
|
const { document, selection } = state
|
||||||
|
const texts = document.getTexts()
|
||||||
|
const first = texts.get(0)
|
||||||
|
const second = texts.get(1)
|
||||||
|
const third = texts.get(2)
|
||||||
|
const range = selection.merge({
|
||||||
|
anchorKey: first.key,
|
||||||
|
anchorOffset: first.length,
|
||||||
|
focusKey: second.key,
|
||||||
|
focusOffset: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
return state
|
||||||
|
.transform()
|
||||||
|
.deleteAtRange(range)
|
||||||
|
.apply()
|
||||||
|
}
|
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
nodes:
|
||||||
|
- kind: block
|
||||||
|
type: list
|
||||||
|
nodes:
|
||||||
|
- kind: block
|
||||||
|
type: item
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
text: one
|
||||||
|
- kind: block
|
||||||
|
type: item
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
text: two
|
||||||
|
- kind: block
|
||||||
|
type: item
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
text: three
|
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
nodes:
|
||||||
|
- kind: block
|
||||||
|
type: list
|
||||||
|
nodes:
|
||||||
|
- kind: block
|
||||||
|
type: item
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
text: onetwo
|
||||||
|
- kind: block
|
||||||
|
type: item
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
text: three
|
@@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
import assert from 'assert'
|
||||||
|
|
||||||
|
export default function (state) {
|
||||||
|
const { document, selection } = state
|
||||||
|
const texts = document.getTexts()
|
||||||
|
const first = texts.get(0)
|
||||||
|
const second = texts.get(1)
|
||||||
|
const third = texts.get(2)
|
||||||
|
const range = selection.merge({
|
||||||
|
anchorKey: first.key,
|
||||||
|
anchorOffset: first.length,
|
||||||
|
focusKey: second.key,
|
||||||
|
focusOffset: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const next = state
|
||||||
|
.transform()
|
||||||
|
.moveTo(range)
|
||||||
|
.delete()
|
||||||
|
.apply()
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
next.selection.toJS(),
|
||||||
|
range.collapseToStart().toJS()
|
||||||
|
)
|
||||||
|
|
||||||
|
return next
|
||||||
|
}
|
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
nodes:
|
||||||
|
- kind: block
|
||||||
|
type: list
|
||||||
|
nodes:
|
||||||
|
- kind: block
|
||||||
|
type: item
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
text: one
|
||||||
|
- kind: block
|
||||||
|
type: item
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
text: two
|
||||||
|
- kind: block
|
||||||
|
type: item
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
text: three
|
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
nodes:
|
||||||
|
- kind: block
|
||||||
|
type: list
|
||||||
|
nodes:
|
||||||
|
- kind: block
|
||||||
|
type: item
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
text: onetwo
|
||||||
|
- kind: block
|
||||||
|
type: item
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
text: three
|
Reference in New Issue
Block a user