1
0
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:
Ian Storm Taylor
2016-11-22 15:09:39 -08:00
parent d32904c7c1
commit f393973cfa
2 changed files with 63 additions and 81 deletions

View File

@@ -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)
}
/**

View File

@@ -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) {