1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-13 10:44:02 +02:00

holy shit delete range rabbit hole

This commit is contained in:
Ian Storm Taylor
2016-06-23 22:30:26 -07:00
parent a69bf07ee0
commit e0e909f075
19 changed files with 542 additions and 231 deletions

View File

@@ -61,61 +61,90 @@ const Node = {
node.assertHasDescendant(startKey) node.assertHasDescendant(startKey)
node.assertHasDescendant(endKey) node.assertHasDescendant(endKey)
let startNode = node.getDescendant(startKey) // If the start and end nodes are the same, just remove characters.
// If the start and end nodes are the same, remove the matching characters.
if (startKey == endKey) { if (startKey == endKey) {
const startNode = node.getDescendant(startKey)
const characters = startNode.characters.filterNot((char, i) => { const characters = startNode.characters.filterNot((char, i) => {
return startOffset <= i && i < endOffset return startOffset <= i && i < endOffset
}) })
startNode = startNode.merge({ characters }) node = node.updateDescendant(startNode.merge({ characters }))
node = node.updateDescendant(startNode)
return node return node
} }
// Otherwise, remove the text from the first and last nodes... // Determine the start edge text nodes.
const startRange = Selection.create({ const start = range.moveToStart()
anchorKey: startKey, const startFurthest = node.getFurthestBlock(startKey)
anchorOffset: startOffset, let startText
focusKey: startKey, let startEdgeText
focusOffset: startNode.length
})
const endRange = Selection.create({ if (range.hasEdgeAtStartOf(startFurthest)) {
anchorKey: endKey, startText = node.getPreviousText(startKey)
anchorOffset: 0, startEdgeText = node.getDescendant(startKey)
focusKey: endKey, }
focusOffset: endOffset
})
node = node.deleteAtRange(startRange) else if (range.hasEdgeAtEndOf(startFurthest)) {
node = node.deleteAtRange(endRange) startText = node.getDescendant(startKey)
startEdgeText = node.getNextText(startKey)
}
else {
node = node.splitBlockAtRange(start, Infinity)
startText = node.getDescendant(startKey)
startEdgeText = node.getNextText(startKey)
}
// Determine the end edge text nodes.
const end = range.moveToEnd()
const endFurthest = node.getFurthestBlock(endKey)
let endText
let endEdgeText
if (range.hasEdgeAtStartOf(endFurthest)) {
endEdgeText = node.getPreviousText(endKey)
endText = node.getDescendant(endKey)
}
else if (range.hasEdgeAtEndOf(endFurthest)) {
endEdgeText = node.getDescendant(endKey)
endText = node.getNextText(endKey)
}
else {
node = node.splitBlockAtRange(end, Infinity)
endEdgeText = node.getDescendant(endKey)
endText = node.getNextText(endKey)
}
// Remove the new blocks inside the edges.
const startEdgeBlock = node.getFurthestBlock(startEdgeText)
const endEdgeBlock = node.getFurthestBlock(endEdgeText)
// Then remove any nodes in between the top-most start and end nodes...
let startParent = node.getParent(startKey)
let endParent = node.getParent(endKey)
const startAncestor = node.getHighestChild(startParent)
const endAncestor = node.getHighestChild(endParent)
const nodes = node.nodes const nodes = node.nodes
.takeUntil(child => child == startAncestor) .takeUntil(n => n == startEdgeBlock)
.push(startAncestor) .concat(node.nodes.skipUntil(n => n == endEdgeBlock).rest())
.concat(node.nodes.skipUntil(child => child == endAncestor))
node = node.merge({ nodes }) node = node.merge({ nodes })
// Then add the end parent's nodes to the start parent node. // Take the end edge's split text and move it to the start edge.
const newNodes = startParent.nodes.concat(endParent.nodes) let startBlock = node.getFurthestBlock(startText)
startParent = startParent.merge({ nodes: newNodes }) let endChild = node.getFurthestInline(endText) || endText
node = node.updateDescendant(startParent)
// Then remove the end parent. const startNodes = startBlock.nodes.push(endChild)
let endGrandparent = node.getParent(endParent) startBlock = startBlock.merge({ nodes: startNodes })
node = endGrandparent == node node = node.updateDescendant(startBlock)
? node.removeDescendant(endParent)
: node.updateDescendant(endGrandparent.removeDescendant(endParent))
// Normalize the node. // While the end child is an only child, remove the block it's in.
let endParent = node.getClosestBlock(endChild)
while (endParent && endParent.nodes.size == 1) {
endChild = endParent
endParent = node.getClosestBlock(endParent)
}
node = node.removeDescendant(endChild)
// Normalize the adjacent text nodes.
return node.normalize() return node.normalize()
}, },
@@ -774,7 +803,20 @@ const Node = {
removeDescendant(key) { removeDescendant(key) {
key = normalizeKey(key) key = normalizeKey(key)
this.assertHasDescendant(key) this.assertHasDescendant(key)
const nodes = this.nodes.filterNot(node => node.key == key)
const child = this.getChild(key)
if (child) {
const nodes = this.nodes.filterNot(node => node == child)
return this.merge({ nodes })
}
const nodes = this.nodes.map((node) => {
return node.kind == 'text'
? node
: node.removeDescendant(key)
})
return this.merge({ nodes }) return this.merge({ nodes })
}, },
@@ -782,7 +824,7 @@ const Node = {
* Set the block nodes in a range to `type`, with optional `data`. * Set the block nodes in a range to `type`, with optional `data`.
* *
* @param {Selection} range * @param {Selection} range
* @param {String} type * @param {String} type (optional)
* @param {Data} data (optional) * @param {Data} data (optional)
* @return {Node} node * @return {Node} node
*/ */
@@ -797,15 +839,12 @@ const Node = {
type = null type = null
} }
// If data is passed, ensure it's immutable.
if (data) data = Data.create(data)
// Update each of the blocks. // Update each of the blocks.
const blocks = node.getBlocksAtRange(range) const blocks = node.getBlocksAtRange(range)
blocks.forEach((block) => { blocks.forEach((block) => {
const obj = {} const obj = {}
if (type) obj.type = type if (type) obj.type = type
if (data) obj.data = data if (data) obj.data = Data.create(data)
block = block.merge(obj) block = block.merge(obj)
node = node.updateDescendant(block) node = node.updateDescendant(block)
}) })
@@ -817,7 +856,7 @@ const Node = {
* Set the inline nodes in a range to `type`, with optional `data`. * Set the inline nodes in a range to `type`, with optional `data`.
* *
* @param {Selection} range * @param {Selection} range
* @param {String} type * @param {String} type (optional)
* @param {Data} data (optional) * @param {Data} data (optional)
* @return {Node} node * @return {Node} node
*/ */
@@ -832,15 +871,12 @@ const Node = {
type = null type = null
} }
// If data is passed, ensure it's immutable.
if (data) data = Data.create(data)
// Update each of the inlines. // Update each of the inlines.
const inlines = node.getInlinesAtRange(range) const inlines = node.getInlinesAtRange(range)
inlines.forEach((inline) => { inlines.forEach((inline) => {
const obj = {} const obj = {}
if (type) obj.type = type if (type) obj.type = type
if (data) obj.data = data if (data) obj.data = Data.create(data)
inline = inline.merge(obj) inline = inline.merge(obj)
node = node.updateDescendant(inline) node = node.updateDescendant(inline)
}) })
@@ -849,13 +885,14 @@ const Node = {
}, },
/** /**
* Split the block nodes at a `range`. * Split the block nodes at a `range`, to optional `depth`.
* *
* @param {Selection} range * @param {Selection} range
* @param {Number} depth (optional)
* @return {Node} node * @return {Node} node
*/ */
splitBlockAtRange(range) { splitBlockAtRange(range, depth = 1) {
let node = this let node = this
range = range.normalize(node) range = range.normalize(node)
@@ -865,47 +902,68 @@ const Node = {
range = range.moveToStart() range = range.moveToStart()
} }
// Split the inline nodes at the range. // If at the start of end of the node, do nothing.
node = node.splitInlineAtRange(range) if (range.isAtStartOf(node) || range.isAtEndOf(node)) return node
// Find the highest inline elements that were split. // If at the start of end of the closest block, do nothing.
const { startKey } = range const { startKey } = range
const firstText = node.getDescendant(startKey) const block = node.getClosestBlock(startKey)
const firstChild = node.getFurthestInline(firstText) || firstText if (range.isAtStartOf(block) || range.isAtEndOf(block)) return node
const secondText = node.getNextText(startKey)
const secondChild = node.getFurthestInline(secondText) || secondText
// Remove the second inline child from the first block. // If not at the edge of the furthest inline, split it.
let firstBlock = node.getBlocksAtRange(range).first() const text = node.getDescendant(startKey)
firstBlock = firstBlock.removeDescendant(secondChild) const furthest = node.getFurthestInline(text) || text
// Create a new block with the second inline child in it. if (!range.isAtStartOf(furthest) && !range.isAtEndOf(furthest)) {
const secondBlock = Block.create({ node = node.splitInlineAtRange(range)
type: firstBlock.type,
data: firstBlock.data,
nodes: [secondChild]
})
// Replace the block in the parent with the two new blocks.
let parent = node.getParent(firstBlock)
const nodes = parent.nodes.takeUntil(n => n.key == firstBlock.key)
.push(firstBlock)
.push(secondBlock)
.concat(parent.nodes.skipUntil(n => n.key == firstBlock.key).rest())
// If the node is the parent, just merge, otherwise deep merge.
if (parent == node) {
node = node.merge({ nodes })
} else {
parent = parent.merge({ nodes })
node = node.updateDescendant(parent)
} }
// Normalize the node. // Find the highest inline elements that were split.
return node.normalize() const firstText = node.getDescendant(startKey)
const secondText = node.getNextText(startKey)
let firstChild = node.getFurthestInline(firstText) || firstText
let secondChild = node.getFurthestInline(secondText) || secondText
let parent = node.getClosestBlock(firstChild)
let d = 0
// While the parent is a block, split the block nodes.
while (parent && d < depth) {
firstChild = parent.merge({ nodes: Block.createList([firstChild]) })
secondChild = Block.create({
nodes: [secondChild],
type: parent.type,
data: parent.data
})
// Add the new children.
const grandparent = node.getParent(parent)
const nodes = grandparent.nodes
.takeUntil(n => n.key == firstChild.key)
.push(firstChild)
.push(secondChild)
.concat(grandparent.nodes.skipUntil(n => n.key == firstChild.key).rest())
// Update the grandparent.
node = grandparent == node
? node.merge({ nodes })
: node.updateDescendant(grandparent.merge({ nodes }))
d++
parent = node.getClosestBlock(firstChild)
}
return node
}, },
splitInlineAtRange(range) { /**
* Split the inline nodes at a `range`, to optional `depth`.
*
* @param {Selection} range
* @param {Number} depth (optiona)
* @return {Node} node
*/
splitInlineAtRange(range, depth = Infinity) {
range = range.normalize(this) range = range.normalize(this)
const Inline = require('./inline').default const Inline = require('./inline').default
let node = this let node = this
@@ -916,14 +974,41 @@ const Node = {
range = range.moveToStart() range = range.moveToStart()
} }
// First split the text nodes. // If at the start or end of the node, do nothing.
if (range.isAtStartOf(node) || range.isAtEndOf(node)) return node
// If at the start or the end of the furthest inline, do nothing.
const { startKey } = range
const text = node.getDescendant(startKey)
const furthest = node.getFurthestInline(text) || text
if (range.isAtStartOf(furthest) || range.isAtEndOf(furthest)) return node
// Determine the first and next nodes based on the edge.
let firstChild
let secondChild
if (range.isAtStartOf(text)) {
firstChild = node.getPreviousText(startKey)
secondChild = node.getDescendant(startKey)
}
else if (range.isAtEndOf(text)) {
firstChild = node.getDescendant(startKey)
secondChild = node.getNextText(firstChild)
}
else {
node = node.splitTextAtRange(range) node = node.splitTextAtRange(range)
let firstChild = node.getDescendant(range.startKey) firstChild = node.getDescendant(startKey)
let secondChild = node.getNextText(firstChild) secondChild = node.getNextText(firstChild)
let parent }
// First split the text nodes.
let parent = node.getClosestInline(firstChild)
let d = 0
// While the parent is an inline parent, split the inline nodes. // While the parent is an inline parent, split the inline nodes.
while (parent = node.getClosestInline(firstChild)) { while (parent && d < depth) {
firstChild = parent.merge({ nodes: Inline.createList([firstChild]) }) firstChild = parent.merge({ nodes: Inline.createList([firstChild]) })
secondChild = Inline.create({ secondChild = Inline.create({
nodes: [secondChild], nodes: [secondChild],
@@ -934,7 +1019,7 @@ const Node = {
// Split the children. // Split the children.
const grandparent = node.getParent(parent) const grandparent = node.getParent(parent)
const nodes = grandparent.nodes const nodes = grandparent.nodes
.takeUntil(c => c.key == firstChild.key) .takeUntil(n => n.key == firstChild.key)
.push(firstChild) .push(firstChild)
.push(secondChild) .push(secondChild)
.concat(grandparent.nodes.skipUntil(n => n.key == firstChild.key).rest()) .concat(grandparent.nodes.skipUntil(n => n.key == firstChild.key).rest())
@@ -943,6 +1028,9 @@ const Node = {
node = grandparent == node node = grandparent == node
? node.merge({ nodes }) ? node.merge({ nodes })
: node.updateDescendant(grandparent.merge({ nodes })) : node.updateDescendant(grandparent.merge({ nodes }))
d++
parent = node.getClosestInline(firstChild)
} }
return node return node
@@ -965,9 +1053,12 @@ const Node = {
range = range.moveToStart() range = range.moveToStart()
} }
// Split the text node's characters. // If at the start or the end of the text node, do nothing.
const { startKey, startOffset } = range const { startKey, startOffset } = range
const text = node.getDescendant(startKey) const text = node.getDescendant(startKey)
if (range.isAtStartOf(text) || range.isAtEndOf(text)) return node
// Split the text node's characters.
const { characters } = text const { characters } = text
const firstChars = characters.take(startOffset) const firstChars = characters.take(startOffset)
const secondChars = characters.skip(startOffset) const secondChars = characters.skip(startOffset)
@@ -1031,6 +1122,115 @@ const Node = {
return node return node
}, },
/**
* Unwrap all of the block nodes in a `range` from a block node of `type.`
*
* @param {Selection} range
* @param {String} type (optional)
* @param {Data or Object} data (optional)
* @return {Node} node
*/
unwrapBlockAtRange(range, type, data) {
range = range.normalize(this)
let node = this
// Allow for only data.
if (typeof type == 'object') {
data = type
type = null
}
// Ensure that data is immutable.
if (data) data = Data.create(data)
// Find the closest wrapping blocks of each text node.
const texts = node.getBlocksAtRange(range)
const wrappers = texts.reduce((wrappers, text) => {
const match = node.getClosest(text, (parent) => {
if (parent.kind != 'block') return false
if (type && parent.type != type) return false
if (data && !parent.data.isSuperset(data)) return false
return true
})
if (match) wrappers = wrappers.add(match)
return wrappers
}, new Set())
// Replace each of the wrappers with their child nodes.
wrappers.forEach((wrapper) => {
const parent = node.getParent(wrapper)
// Replace the wrapper in the parent's nodes with the block.
const nodes = parent.nodes.takeUntil(n => n == wrapper)
.concat(wrapper.nodes)
.concat(parent.nodes.skipUntil(n => n == wrapper).rest())
// Update the parent.
node = parent == node
? node.merge({ nodes })
: node.updateDescendant(parent.merge({ nodes }))
})
return node.normalize()
},
/**
* Unwrap the inline nodes in a `range` from an parent inline with `type`.
*
* @param {Selection} range
* @param {String} type (optional)
* @param {Data} data (optional)
* @return {Node} node
*/
unwrapInlineAtRange(range, type, data) {
range = range.normalize(this)
let node = this
let blocks = node.getInlinesAtRange(range)
// Allow for no type.
if (typeof type == 'object') {
data = type
type = null
}
// Ensure that data is immutable.
if (data) data = Data.create(data)
// Find the closest matching inline wrappers of each text node.
const texts = this.getTextNodes()
const wrappers = texts.reduce((wrappers, text) => {
const match = node.getClosest(text, (parent) => {
if (parent.kind != 'inline') return false
if (type && parent.type != type) return false
if (data && !parent.data.isSuperset(data)) return false
return true
})
if (match) wrappers = wrappers.add(match)
return wrappers
}, new Set())
// Replace each of the wrappers with their child nodes.
wrappers.forEach((wrapper) => {
const parent = node.getParent(wrapper)
// Replace the wrapper in the parent's nodes with the block.
const nodes = parent.nodes.takeUntil(n => n == wrapper)
.concat(wrapper.nodes)
.concat(parent.nodes.skipUntil(n => n == wrapper).rest())
// Update the parent.
node = parent == node
? node.merge({ nodes })
: node.updateDescendant(parent.merge({ nodes }))
})
return node.normalize()
},
/** /**
* Set a new value for a child node by `key`. * Set a new value for a child node by `key`.
* *
@@ -1097,11 +1297,13 @@ const Node = {
}) })
// Replace the siblings with the wrapper. // Replace the siblings with the wrapper.
const first = siblings.first()
const last = siblings.last()
const parent = node.getParent(highest) const parent = node.getParent(highest)
const nodes = parent.nodes const nodes = parent.nodes
.takeUntil(node => node == highest) .takeUntil(node => node == first)
.push(wrapper) .push(wrapper)
.concat(parent.nodes.skipUntil(node => node == highest).rest()) .concat(parent.nodes.skipUntil(node => node == last).rest())
// Update the parent. // Update the parent.
node = parent == node node = parent == node
@@ -1111,60 +1313,6 @@ const Node = {
return node return node
}, },
/**
* Unwrap all of the block nodes in a `range` from a block node of `type.`
*
* @param {Selection} range
* @param {String} type (optional)
* @param {Data or Object} data (optional)
* @return {Node} node
*/
unwrapBlockAtRange(range, type, data) {
range = range.normalize(this)
let node = this
// Allow for only data.
if (typeof type == 'object') {
data = type
type = null
}
// Ensure that data is immutable.
if (data) data = Data.create(data)
// Find the closest wrapping blocks of each text node.
const texts = node.getBlocksAtRange(range)
const wrappers = texts.reduce((wrappers, text) => {
const match = node.getClosest(text, (parent) => {
if (parent.kind != 'block') return false
if (type && parent.type != type) return false
if (data && !parent.data.isSuperset(data)) return false
return true
})
if (match) wrappers = wrappers.add(match)
return wrappers
}, new Set())
// Replace each of the wrappers with their child nodes.
wrappers.forEach((wrapper) => {
const parent = node.getParent(wrapper)
// Replace the wrapper in the parent's nodes with the block.
const nodes = parent.nodes.takeUntil(n => n == wrapper)
.concat(wrapper.nodes)
.concat(parent.nodes.skipUntil(n => n == wrapper).rest())
// Update the parent.
node = parent == node
? node.merge({ nodes })
: node.updateDescendant(parent.merge({ nodes }))
})
return node.normalize()
},
/** /**
* Wrap the text and inline nodes in a `range` with a new inline node. * Wrap the text and inline nodes in a `range` with a new inline node.
* *
@@ -1176,13 +1324,11 @@ const Node = {
wrapInlineAtRange(range, type, data) { wrapInlineAtRange(range, type, data) {
range = range.normalize(this) range = range.normalize(this)
data = Data.create(data)
const Inline = require('./inline').default const Inline = require('./inline').default
let node = this let node = this
// Ensure that data is immutable.
if (data) data = Data.create(data)
// If collapsed or unset, there's nothing to wrap. // If collapsed or unset, there's nothing to wrap.
if (range.isCollapsed || range.isUnset) return node if (range.isCollapsed || range.isUnset) return node
@@ -1239,61 +1385,6 @@ const Node = {
}) })
return node return node
},
/**
* Unwrap the inline nodes in a `range` from an parent inline with `type`.
*
* @param {Selection} range
* @param {String} type (optional)
* @param {Data} data (optional)
* @return {Node} node
*/
unwrapInlineAtRange(range, type, data) {
range = range.normalize(this)
let node = this
let blocks = node.getInlinesAtRange(range)
// Allow for no type.
if (typeof type == 'object') {
data = type
type = null
}
// Ensure that data is immutable.
if (data) data = Data.create(data)
// Find the closest matching inline wrappers of each text node.
const texts = this.getTextNodes()
const wrappers = texts.reduce((wrappers, text) => {
const match = node.getClosest(text, (parent) => {
if (parent.kind != 'inline') return false
if (type && parent.type != type) return false
if (data && !parent.data.isSuperset(data)) return false
return true
})
if (match) wrappers = wrappers.add(match)
return wrappers
}, new Set())
// Replace each of the wrappers with their child nodes.
wrappers.forEach((wrapper) => {
const parent = node.getParent(wrapper)
// Replace the wrapper in the parent's nodes with the block.
const nodes = parent.nodes.takeUntil(n => n == wrapper)
.concat(wrapper.nodes)
.concat(parent.nodes.skipUntil(n => n == wrapper).rest())
// Update the parent.
node = parent == node
? node.merge({ nodes })
: node.updateDescendant(parent.merge({ nodes }))
})
return node.normalize()
} }
} }

View File

@@ -131,6 +131,38 @@ class Selection extends Record(DEFAULTS) {
return endKey == last.key && endOffset == last.length return endKey == last.key && endOffset == last.length
} }
/**
* Check whether the selection has an edge at the start of a `node`.
*
* @param {Node} node
* @return {Boolean} hasEdgeAtStart
*/
hasEdgeAtStartOf(node) {
const { startKey, startOffset, endKey, endOffset } = this
const first = node.kind == 'text' ? node : node.getTextNodes().first()
return (
(startKey == first.key && startOffset == 0) ||
(endKey == first.key && endOffset == 0)
)
}
/**
* Check whether the selection has an edge at the end of a `node`.
*
* @param {Node} node
* @return {Boolean} hasEdgeAtEnd
*/
hasEdgeAtEndOf(node) {
const { startKey, startOffset, endKey, endOffset } = this
const last = node.kind == 'text' ? node : node.getTextNodes().last()
return (
(startKey == last.key && startOffset == last.length) ||
(endKey == last.key && endOffset == last.length)
)
}
/** /**
* Normalize the selection, relative to a `node`, ensuring that the anchor * Normalize the selection, relative to a `node`, ensuring that the anchor
* and focus nodes of the selection always refer to leaf text nodes. * and focus nodes of the selection always refer to leaf text nodes.

View File

@@ -0,0 +1,18 @@
export default function (state) {
const { document, selection } = state
const texts = document.getTextNodes()
const first = texts.first()
const last = texts.last()
const range = selection.merge({
anchorKey: first.key,
anchorOffset: 2,
focusKey: last.key,
focusOffset: 2
})
return state
.transform()
.deleteAtRange(range, 'code')
.apply()
}

View File

@@ -0,0 +1,20 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: inline
type: link
nodes:
- kind: text
ranges:
- text: word
- kind: block
type: paragraph
nodes:
- kind: inline
type: link
nodes:
- kind: text
ranges:
- text: another

View File

@@ -0,0 +1,17 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: inline
type: link
nodes:
- kind: text
ranges:
- text: wo
- kind: inline
type: link
nodes:
- kind: text
ranges:
- text: other

View File

@@ -0,0 +1,18 @@
export default function (state) {
const { document, selection } = state
const texts = document.getTextNodes()
const first = texts.first()
const last = texts.last()
const range = selection.merge({
anchorKey: first.key,
anchorOffset: 2,
focusKey: last.key,
focusOffset: 2
})
return state
.transform()
.deleteAtRange(range, 'code')
.apply()
}

View File

@@ -0,0 +1,23 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
ranges:
- text: word
- kind: block
type: paragraph
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
ranges:
- text: middle
- kind: block
type: paragraph
nodes:
- kind: text
ranges:
- text: another

View File

@@ -0,0 +1,8 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
ranges:
- text: woother

View File

@@ -6,9 +6,3 @@ nodes:
- kind: text - kind: text
ranges: ranges:
- text: word - text: word
- kind: block
type: paragraph
nodes:
- kind: text
ranges:
- text: ""

View File

@@ -1,11 +1,5 @@
nodes: nodes:
- kind: block
type: paragraph
nodes:
- kind: text
ranges:
- text: ""
- kind: block - kind: block
type: paragraph type: paragraph
nodes: nodes:

View File

@@ -0,0 +1,17 @@
export default function (state) {
const { document, selection } = state
const texts = document.getTextNodes()
const first = texts.first()
const range = selection.merge({
anchorKey: first.key,
anchorOffset: 2,
focusKey: first.key,
focusOffset: 2
})
return state
.transform()
.splitBlockAtRange(range, Infinity)
.apply()
}

View File

@@ -0,0 +1,14 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: block
type: paragraph
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
ranges:
- text: word

View File

@@ -0,0 +1,26 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: block
type: paragraph
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
ranges:
- text: wo
- kind: block
type: paragraph
nodes:
- kind: block
type: paragraph
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
ranges:
- text: rd

View File

@@ -9,9 +9,3 @@ nodes:
- kind: text - kind: text
ranges: ranges:
- text: word - text: word
- kind: inline
type: link
nodes:
- kind: text
ranges:
- text: ""

View File

@@ -3,12 +3,6 @@ nodes:
- kind: block - kind: block
type: paragraph type: paragraph
nodes: nodes:
- kind: inline
type: link
nodes:
- kind: text
ranges:
- text: ""
- kind: inline - kind: inline
type: link type: link
nodes: nodes:

View File

@@ -0,0 +1,17 @@
export default function (state) {
const { document, selection } = state
const texts = document.getTextNodes()
const first = texts.first()
const range = selection.merge({
anchorKey: first.key,
anchorOffset: 2,
focusKey: first.key,
focusOffset: 2
})
return state
.transform()
.splitInlineAtRange(range, 1)
.apply()
}

View File

@@ -0,0 +1,14 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: inline
type: link
nodes:
- kind: inline
type: link
nodes:
- kind: text
ranges:
- text: word

View File

@@ -0,0 +1,20 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: inline
type: link
nodes:
- kind: inline
type: link
nodes:
- kind: text
ranges:
- text: wo
- kind: inline
type: link
nodes:
- kind: text
ranges:
- text: rd

View File

@@ -4,7 +4,7 @@ import fs from 'fs'
import readMetadata from 'read-metadata' import readMetadata from 'read-metadata'
import toCamel from 'to-camel-case' import toCamel from 'to-camel-case'
import { Raw, State } from '../..' import { Raw, State } from '../..'
import { equal } from '../helpers/assert-json' import { equal, strictEqual } from '../helpers/assert-json'
import { resolve } from 'path' import { resolve } from 'path'
/** /**
@@ -30,7 +30,7 @@ describe('transforms', () => {
let state = Raw.deserialize(input) let state = Raw.deserialize(input)
state = fn(state) state = fn(state)
const output = Raw.serialize(state) const output = Raw.serialize(state)
equal(output, expected) strictEqual(output, expected)
}) })
} }
}) })