mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-25 16:20:49 +02:00
refactor transform, simplify selection updating logic
This commit is contained in:
@@ -108,9 +108,7 @@ export function _delete(transform) {
|
||||
export function deleteBackward(transform, n = 1) {
|
||||
const { state } = transform
|
||||
const { selection } = state
|
||||
transform
|
||||
.deleteBackwardAtRange(selection, n)
|
||||
.collapseToEnd()
|
||||
transform.deleteBackwardAtRange(selection, n)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,9 +121,7 @@ export function deleteBackward(transform, n = 1) {
|
||||
export function deleteForward(transform, n = 1) {
|
||||
const { state } = transform
|
||||
const { selection } = state
|
||||
transform
|
||||
.deleteForwardAtRange(selection, n)
|
||||
.collapseToEnd()
|
||||
transform.deleteForwardAtRange(selection, n)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,19 +132,11 @@ export function deleteForward(transform, n = 1) {
|
||||
*/
|
||||
|
||||
export function insertBlock(transform, block) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
const keys = document.getTexts().map(text => text.key)
|
||||
|
||||
transform.unsetSelection()
|
||||
block = Normalize.block(block)
|
||||
const { state } = transform
|
||||
const { selection } = state
|
||||
transform.insertBlockAtRange(selection, block)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
|
||||
const text = document.getTexts().find(n => !keys.includes(n.key))
|
||||
const after = selection.collapseToEndOf(text)
|
||||
|
||||
transform.moveTo(after)
|
||||
transform.collapseToEndOf(block)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,34 +197,18 @@ export function insertFragment(transform, fragment) {
|
||||
*/
|
||||
|
||||
export function insertInline(transform, inline) {
|
||||
let { state } = transform
|
||||
let { document, selection, startText } = state
|
||||
let after
|
||||
|
||||
const hasVoid = document.hasVoidParent(startText.key)
|
||||
const keys = document.getTexts().map(text => text.key)
|
||||
|
||||
transform.unsetSelection()
|
||||
inline = Normalize.inline(inline)
|
||||
const { state } = transform
|
||||
const { selection, startBlock } = state
|
||||
transform.insertInlineAtRange(selection, inline)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
|
||||
if (hasVoid) {
|
||||
after = selection
|
||||
}
|
||||
// If the start block is void, it won't have inserted at all.
|
||||
if (startBlock.isVoid) return
|
||||
|
||||
else {
|
||||
const text = document.getTexts().find((n) => {
|
||||
if (keys.includes(n.key)) return false
|
||||
const parent = document.getParent(n.key)
|
||||
if (parent.kind != 'inline') return false
|
||||
return true
|
||||
})
|
||||
|
||||
after = selection.collapseToEndOf(text)
|
||||
}
|
||||
|
||||
transform.moveTo(after)
|
||||
// Otherwise, find the inserted inline node, and collapse to the start of it.
|
||||
const { document } = transform.state
|
||||
inline = document.assertNode(inline.key)
|
||||
transform.collapseToEndOf(inline)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -4,6 +4,16 @@ import Normalize from '../utils/normalize'
|
||||
import SCHEMA from '../schemas/core'
|
||||
import { List } from 'immutable'
|
||||
|
||||
/**
|
||||
* An options object with normalize set to `false`.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
const OPTS = {
|
||||
normalize: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new `mark` to the characters at `range`.
|
||||
*
|
||||
@@ -68,8 +78,8 @@ export function deleteAtRange(transform, range, options = {}) {
|
||||
const startOff = (startChild.kind == 'text' ? 0 : startChild.getOffset(startKey)) + startOffset
|
||||
const endOff = (endChild.kind == 'text' ? 0 : endChild.getOffset(endKey)) + endOffset
|
||||
|
||||
transform.splitNodeByKey(startChild.key, startOff, { normalize: false })
|
||||
transform.splitNodeByKey(endChild.key, endOff, { normalize: false })
|
||||
transform.splitNodeByKey(startChild.key, startOff, OPTS)
|
||||
transform.splitNodeByKey(endChild.key, endOff, OPTS)
|
||||
|
||||
state = transform.state
|
||||
document = state.document
|
||||
@@ -87,7 +97,7 @@ export function deleteAtRange(transform, range, options = {}) {
|
||||
if (middles.size) {
|
||||
// remove first nodes directly so the document is not normalized
|
||||
middles.forEach(child => {
|
||||
transform.removeNodeByKey(child.key, { normalize: false })
|
||||
transform.removeNodeByKey(child.key, OPTS)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -95,11 +105,11 @@ export function deleteAtRange(transform, range, options = {}) {
|
||||
endBlock.nodes.forEach((child, i) => {
|
||||
const newKey = startBlock.key
|
||||
const newIndex = startBlock.nodes.size + i
|
||||
transform.moveNodeByKey(child.key, newKey, newIndex, { normalize: false })
|
||||
transform.moveNodeByKey(child.key, newKey, newIndex, OPTS)
|
||||
})
|
||||
|
||||
const lonely = document.getFurthest(endBlock.key, p => p.nodes.size == 1) || endBlock
|
||||
transform.removeNodeByKey(lonely.key, { normalize: false })
|
||||
transform.removeNodeByKey(lonely.key, OPTS)
|
||||
}
|
||||
|
||||
if (normalize) {
|
||||
@@ -316,7 +326,7 @@ export function insertFragmentAtRange(transform, range, fragment, options = {})
|
||||
|
||||
// If the range is expanded, delete it first.
|
||||
if (range.isExpanded) {
|
||||
transform.deleteAtRange(range, { normalize: false })
|
||||
transform.deleteAtRange(range, OPTS)
|
||||
range = range.collapseToStart()
|
||||
}
|
||||
|
||||
@@ -357,13 +367,13 @@ export function insertFragmentAtRange(transform, range, fragment, options = {})
|
||||
|
||||
fragment.nodes.forEach((node, i) => {
|
||||
const newIndex = startIndex + i + 1
|
||||
transform.insertNodeByKey(parent.key, newIndex, node, { normalize: false })
|
||||
transform.insertNodeByKey(parent.key, newIndex, node, OPTS)
|
||||
})
|
||||
}
|
||||
|
||||
// Check if we need to split the node.
|
||||
if (startOffset != 0) {
|
||||
transform.splitNodeByKey(startChild.key, offset, { normalize: false })
|
||||
transform.splitNodeByKey(startChild.key, offset, OPTS)
|
||||
}
|
||||
|
||||
// Update our variables with the new state.
|
||||
@@ -383,15 +393,15 @@ export function insertFragmentAtRange(transform, range, fragment, options = {})
|
||||
|
||||
nextNodes.forEach((node, i) => {
|
||||
const newIndex = lastIndex + i
|
||||
transform.moveNodeByKey(node.key, lastBlock.key, newIndex, { normalize: false })
|
||||
transform.moveNodeByKey(node.key, lastBlock.key, newIndex, OPTS)
|
||||
})
|
||||
}
|
||||
|
||||
// If the starting block is empty, we replace it entirely with the first block
|
||||
// of the fragment, since this leads to a more expected behavior for the user.
|
||||
if (startBlock.isEmpty) {
|
||||
transform.removeNodeByKey(startBlock.key, { normalize: false })
|
||||
transform.insertNodeByKey(parent.key, index, firstBlock, { normalize: false })
|
||||
transform.removeNodeByKey(startBlock.key, OPTS)
|
||||
transform.insertNodeByKey(parent.key, index, firstBlock, OPTS)
|
||||
}
|
||||
|
||||
// Otherwise, we maintain the starting block, and insert all of the first
|
||||
@@ -403,7 +413,7 @@ export function insertFragmentAtRange(transform, range, fragment, options = {})
|
||||
firstBlock.nodes.forEach((inline, i) => {
|
||||
const o = startOffset == 0 ? 0 : 1
|
||||
const newIndex = inlineIndex + i + o
|
||||
transform.insertNodeByKey(startBlock.key, newIndex, inline, { normalize: false })
|
||||
transform.insertNodeByKey(startBlock.key, newIndex, inline, OPTS)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -428,7 +438,7 @@ export function insertInlineAtRange(transform, range, inline, options = {}) {
|
||||
inline = Normalize.inline(inline)
|
||||
|
||||
if (range.isExpanded) {
|
||||
transform.deleteAtRange(range, { normalize: false })
|
||||
transform.deleteAtRange(range, OPTS)
|
||||
range = range.collapseToStart()
|
||||
}
|
||||
|
||||
@@ -441,8 +451,8 @@ export function insertInlineAtRange(transform, range, inline, options = {}) {
|
||||
|
||||
if (parent.isVoid) return
|
||||
|
||||
transform.splitNodeByKey(startKey, startOffset, { normalize: false })
|
||||
transform.insertNodeByKey(parent.key, index + 1, inline, { normalize: false })
|
||||
transform.splitNodeByKey(startKey, startOffset, OPTS)
|
||||
transform.insertNodeByKey(parent.key, index + 1, inline, OPTS)
|
||||
|
||||
if (normalize) {
|
||||
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||
@@ -470,7 +480,7 @@ export function insertTextAtRange(transform, range, text, marks, options = {}) {
|
||||
if (parent.isVoid) return
|
||||
|
||||
if (range.isExpanded) {
|
||||
transform.deleteAtRange(range, { normalize: false })
|
||||
transform.deleteAtRange(range, OPTS)
|
||||
}
|
||||
|
||||
// PERF: Unless specified, don't normalize if only inserting text.
|
||||
@@ -702,17 +712,17 @@ export function unwrapBlockAtRange(transform, range, properties, options = {}) {
|
||||
|
||||
if (first == firstMatch && last == lastMatch) {
|
||||
block.nodes.forEach((child, i) => {
|
||||
transform.moveNodeByKey(child.key, parent.key, index + i, { normalize: false })
|
||||
transform.moveNodeByKey(child.key, parent.key, index + i, OPTS)
|
||||
})
|
||||
|
||||
transform.removeNodeByKey(block.key, { normalize: false })
|
||||
transform.removeNodeByKey(block.key, OPTS)
|
||||
}
|
||||
|
||||
else if (last == lastMatch) {
|
||||
block.nodes
|
||||
.skipUntil(n => n == firstMatch)
|
||||
.forEach((child, i) => {
|
||||
transform.moveNodeByKey(child.key, parent.key, index + 1 + i, { normalize: false })
|
||||
transform.moveNodeByKey(child.key, parent.key, index + 1 + i, OPTS)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -721,23 +731,23 @@ export function unwrapBlockAtRange(transform, range, properties, options = {}) {
|
||||
.takeUntil(n => n == lastMatch)
|
||||
.push(lastMatch)
|
||||
.forEach((child, i) => {
|
||||
transform.moveNodeByKey(child.key, parent.key, index + i, { normalize: false })
|
||||
transform.moveNodeByKey(child.key, parent.key, index + i, OPTS)
|
||||
})
|
||||
}
|
||||
|
||||
else {
|
||||
const offset = block.getOffset(firstMatch.key)
|
||||
|
||||
transform.splitNodeByKey(block.key, offset, { normalize: false })
|
||||
transform.splitNodeByKey(block.key, offset, OPTS)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
const extra = document.getPreviousSibling(firstMatch.key)
|
||||
|
||||
children.forEach((child, i) => {
|
||||
transform.moveNodeByKey(child.key, parent.key, index + 1 + i, { normalize: false })
|
||||
transform.moveNodeByKey(child.key, parent.key, index + 1 + i, OPTS)
|
||||
})
|
||||
|
||||
transform.removeNodeByKey(extra.key, { normalize: false })
|
||||
transform.removeNodeByKey(extra.key, OPTS)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -783,7 +793,7 @@ export function unwrapInlineAtRange(transform, range, properties, options = {})
|
||||
const index = parent.nodes.indexOf(inline)
|
||||
|
||||
inline.nodes.forEach((child, i) => {
|
||||
transform.moveNodeByKey(child.key, parent.key, index + i, { normalize: false })
|
||||
transform.moveNodeByKey(child.key, parent.key, index + i, OPTS)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -850,11 +860,11 @@ export function wrapBlockAtRange(transform, range, block, options = {}) {
|
||||
}
|
||||
|
||||
// inject the new block node into the parent
|
||||
transform.insertNodeByKey(parent.key, index, block, { normalize: false })
|
||||
transform.insertNodeByKey(parent.key, index, block, OPTS)
|
||||
|
||||
// move the sibling nodes into the new block node
|
||||
siblings.forEach((node, i) => {
|
||||
transform.moveNodeByKey(node.key, block.key, i, { normalize: false })
|
||||
transform.moveNodeByKey(node.key, block.key, i, OPTS)
|
||||
})
|
||||
|
||||
if (normalize) {
|
||||
@@ -900,11 +910,11 @@ export function wrapInlineAtRange(transform, range, inline, options = {}) {
|
||||
|
||||
if (startBlock == endBlock) {
|
||||
if (endOff != endChild.length) {
|
||||
transform.splitNodeByKey(endChild.key, endOff, { normalize: false })
|
||||
transform.splitNodeByKey(endChild.key, endOff, OPTS)
|
||||
}
|
||||
|
||||
if (startOff != 0) {
|
||||
transform.splitNodeByKey(startChild.key, startOff, { normalize: false })
|
||||
transform.splitNodeByKey(startChild.key, startOff, OPTS)
|
||||
}
|
||||
|
||||
state = transform.state
|
||||
@@ -926,10 +936,10 @@ export function wrapInlineAtRange(transform, range, inline, options = {}) {
|
||||
|
||||
const node = inline.regenerateKey()
|
||||
|
||||
transform.insertNodeByKey(startBlock.key, startInnerIndex, node, { normalize: false })
|
||||
transform.insertNodeByKey(startBlock.key, startInnerIndex, node, OPTS)
|
||||
|
||||
inlines.forEach((child, i) => {
|
||||
transform.moveNodeByKey(child.key, node.key, i, { normalize: false })
|
||||
transform.moveNodeByKey(child.key, node.key, i, OPTS)
|
||||
})
|
||||
|
||||
if (normalize) {
|
||||
@@ -938,8 +948,8 @@ export function wrapInlineAtRange(transform, range, inline, options = {}) {
|
||||
}
|
||||
|
||||
else {
|
||||
transform.splitNodeByKey(startChild.key, startOff, { normalize: false })
|
||||
transform.splitNodeByKey(endChild.key, endOff, { normalize: false })
|
||||
transform.splitNodeByKey(startChild.key, startOff, OPTS)
|
||||
transform.splitNodeByKey(endChild.key, endOff, OPTS)
|
||||
|
||||
state = transform.state
|
||||
document = state.document
|
||||
@@ -951,15 +961,15 @@ export function wrapInlineAtRange(transform, range, inline, options = {}) {
|
||||
const startNode = inline.regenerateKey()
|
||||
const endNode = inline.regenerateKey()
|
||||
|
||||
transform.insertNodeByKey(startBlock.key, startIndex - 1, startNode, { normalize: false })
|
||||
transform.insertNodeByKey(endBlock.key, endIndex, endNode, { normalize: false })
|
||||
transform.insertNodeByKey(startBlock.key, startIndex - 1, startNode, OPTS)
|
||||
transform.insertNodeByKey(endBlock.key, endIndex, endNode, OPTS)
|
||||
|
||||
startInlines.forEach((child, i) => {
|
||||
transform.moveNodeByKey(child.key, startNode.key, i, { normalize: false })
|
||||
transform.moveNodeByKey(child.key, startNode.key, i, OPTS)
|
||||
})
|
||||
|
||||
endInlines.forEach((child, i) => {
|
||||
transform.moveNodeByKey(child.key, endNode.key, i, { normalize: false })
|
||||
transform.moveNodeByKey(child.key, endNode.key, i, OPTS)
|
||||
})
|
||||
|
||||
if (normalize) {
|
||||
@@ -970,10 +980,10 @@ export function wrapInlineAtRange(transform, range, inline, options = {}) {
|
||||
|
||||
blocks.slice(1, -1).forEach((block) => {
|
||||
const node = inline.regenerateKey()
|
||||
transform.insertNodeByKey(block.key, 0, node, { normalize: false })
|
||||
transform.insertNodeByKey(block.key, 0, node, OPTS)
|
||||
|
||||
block.nodes.forEach((child, i) => {
|
||||
transform.moveNodeByKey(child.key, node.key, i, { normalize: false })
|
||||
transform.moveNodeByKey(child.key, node.key, i, OPTS)
|
||||
})
|
||||
|
||||
if (normalize) {
|
||||
|
Reference in New Issue
Block a user