mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-29 18:09:49 +02:00
refactor more transforms
This commit is contained in:
@@ -110,7 +110,7 @@ class Text extends new Record(DEFAULTS) {
|
||||
addMark(index, length, mark) {
|
||||
const characters = this.characters.map((char, i) => {
|
||||
if (i < index) return char
|
||||
if (i > index + length) return char
|
||||
if (i >= index + length) return char
|
||||
let { marks } = char
|
||||
marks = marks.add(mark)
|
||||
char = char.merge({ marks })
|
||||
|
@@ -13,44 +13,30 @@ import { Set } from 'immutable'
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Mark || String || Object} mark
|
||||
* @param {Mixed} mark
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function addMarkAtRange(transform, range, mark) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
|
||||
// Normalize the mark.
|
||||
mark = Normalize.mark(mark)
|
||||
|
||||
// When the range is collapsed, do nothing.
|
||||
if (range.isCollapsed) return transform
|
||||
|
||||
// Otherwise, find each of the text nodes within the range.
|
||||
const { state } = transform
|
||||
const { document } = state
|
||||
const { startKey, startOffset, endKey, endOffset } = range
|
||||
let texts = document.getTextsAtRange(range)
|
||||
const texts = document.getTextsAtRange(range)
|
||||
|
||||
// Apply the mark to each of the text nodes's matching characters.
|
||||
texts = texts.map((text) => {
|
||||
let characters = text.characters.map((char, i) => {
|
||||
if (!isInRange(i, text, range)) return char
|
||||
let { marks } = char
|
||||
marks = marks.add(mark)
|
||||
return char.merge({ marks })
|
||||
})
|
||||
|
||||
return text.merge({ characters })
|
||||
})
|
||||
|
||||
// Update each of the text nodes.
|
||||
texts.forEach((text) => {
|
||||
document = document.updateDescendant(text)
|
||||
const { key } = text
|
||||
let index = 0
|
||||
let length = text.length
|
||||
|
||||
if (key == startKey) index = startOffset
|
||||
if (key == endKey) length = endOffset
|
||||
if (key == startKey && key == endKey) length = endOffset - startOffset
|
||||
|
||||
transform.addMarkByKey(key, index, length, mark)
|
||||
})
|
||||
|
||||
// Update the state.
|
||||
state = state.merge({ document })
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
@@ -522,40 +508,30 @@ export function insertInlineAtRange(transform, range, inline) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert text `string` at a `range`, with optional `marks`.
|
||||
* Insert `text` at a `range`, with optional `marks`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {String} string
|
||||
* @param {String} text
|
||||
* @param {Set} marks (optional)
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertTextAtRange(transform, range, string, marks) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
export function insertTextAtRange(transform, range, text, marks) {
|
||||
const { state } = transform
|
||||
const { document } = state
|
||||
const { startKey, startOffset } = range
|
||||
const isVoid = document.hasVoidParent(startKey)
|
||||
|
||||
// If inside a void node, do nothing.
|
||||
if (isVoid) return transform
|
||||
|
||||
// Is the range is expanded, delete it first.
|
||||
if (range.isExpanded) {
|
||||
transform = deleteAtRange(transform, range)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
range = range.collapseToStart()
|
||||
if (isVoid) {
|
||||
return transform
|
||||
}
|
||||
|
||||
// Insert text at the range's offset.
|
||||
let text = document.getDescendant(startKey)
|
||||
text = text.insertText(startOffset, string, marks)
|
||||
document = document.updateDescendant(text)
|
||||
if (range.isExpanded) {
|
||||
transform.deleteAtRange(range)
|
||||
}
|
||||
|
||||
// Return the updated selection.
|
||||
state = state.merge({ document })
|
||||
transform.state = state
|
||||
transform.insertTextByKey(startKey, startOffset, text, marks)
|
||||
return transform
|
||||
}
|
||||
|
||||
@@ -608,11 +584,11 @@ export function removeMarkAtRange(transform, range, mark) {
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Object or String} properties
|
||||
* @param {Object || String} properties
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function setBlockAtRange(transform, range, properties = {}) {
|
||||
export function setBlockAtRange(transform, range, properties) {
|
||||
const { state } = transform
|
||||
const { document } = state
|
||||
const blocks = document.getBlocksAtRange(range)
|
||||
@@ -629,24 +605,19 @@ export function setBlockAtRange(transform, range, properties = {}) {
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Object or String} properties
|
||||
* @param {Object || String} properties
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function setInlineAtRange(transform, range, properties = {}) {
|
||||
let { state } = transform
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
export function setInlineAtRange(transform, range, properties) {
|
||||
const { state } = transform
|
||||
const { document } = state
|
||||
const inlines = document.getInlinesAtRange(range)
|
||||
|
||||
inlines.forEach((inline) => {
|
||||
inline = inline.merge(properties)
|
||||
document = document.updateDescendant(inline)
|
||||
transform.setNodeByKey(inline.key, properties)
|
||||
})
|
||||
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,73 @@
|
||||
|
||||
import Normalize from '../utils/normalize'
|
||||
|
||||
/**
|
||||
* Add mark to text at `index` and `length` in node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Number} index
|
||||
* @param {Number} length
|
||||
* @param {Mixed} mark
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function addMarkByKey(transform, key, index, length, mark) {
|
||||
mark = Normalize.mark(mark)
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let node = document.assertDescendant(key)
|
||||
const path = document.getPath(node)
|
||||
|
||||
node = node.addMark(index, length, mark)
|
||||
document = document.updateDescendant(node)
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'add-mark',
|
||||
index,
|
||||
length,
|
||||
mark,
|
||||
path,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a `node` at `index` in a node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Number} index
|
||||
* @param {Node} node
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertNodeByKey(transform, key, index, node) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let parent = document.assertDescendant(key)
|
||||
const path = document.getPath(parent)
|
||||
const nodes = parent.nodes.splice(index + 1, 0, node)
|
||||
|
||||
parent = parent.merge({ nodes })
|
||||
document = document.updateDescendant(parent)
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'insert-node',
|
||||
index,
|
||||
node,
|
||||
path,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert `text` at `index` in node by `key`.
|
||||
*
|
||||
@@ -34,234 +101,6 @@ export function insertTextByKey(transform, key, index, text, marks) {
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove text at `index` and `length` in node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Number} index
|
||||
* @param {Number} length
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function removeTextByKey(transform, key, index, length) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let node = document.assertDescendant(key)
|
||||
const path = document.getPath(node)
|
||||
|
||||
node = node.removeText(index, length)
|
||||
document = document.updateDescendant(node)
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'remove-text',
|
||||
index,
|
||||
length,
|
||||
path,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Add mark to text at `index` and `length` in node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Number} index
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function addMarkByKey(transform, key, index, length, mark) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let node = document.assertDescendant(key)
|
||||
const path = document.getPath(node)
|
||||
|
||||
node = node.addMark(index, length, mark)
|
||||
document = document.updateDescendant(node)
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'add-mark',
|
||||
index,
|
||||
length,
|
||||
mark,
|
||||
path,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove mark from text at `index` and `length` in node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Number} index
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function removeMarkByKey(transform, key, index, length, mark) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let node = document.assertDescendant(key)
|
||||
const path = document.getPath(node)
|
||||
|
||||
node = node.removeMark(index, length, mark)
|
||||
document = document.updateDescendant(node)
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'remove-mark',
|
||||
index,
|
||||
length,
|
||||
mark,
|
||||
path,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Set `properties` on mark on text at `index` and `length` in node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Number} index
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function setMarkByKey(transform, key, index, length, mark, properties) {
|
||||
properties = Normalize.markProperties(properties)
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let node = document.assertDescendant(key)
|
||||
const path = document.getPath(node)
|
||||
|
||||
node = node.updateMark(index, length, mark, properties)
|
||||
document = document.updateDescendant(node)
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'set-mark',
|
||||
index,
|
||||
length,
|
||||
mark,
|
||||
path,
|
||||
properties,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a `node` at `index` in a node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Number} index
|
||||
* @param {Node} node
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertNodeAfterNodeByKey(transform, key, index, node) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let parent = document.assertDescendant(key)
|
||||
const path = document.getPath(parent)
|
||||
const nodes = parent.nodes.splice(index + 1, 0, node)
|
||||
|
||||
parent = parent.merge({ nodes })
|
||||
document = document.updateDescendant(parent)
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'insert-node',
|
||||
index,
|
||||
node,
|
||||
path,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function removeNodeByKey(transform, key) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
const node = document.assertDescendant(key)
|
||||
const path = document.getPath(node)
|
||||
let parent = document.getParent(node)
|
||||
const index = parent.nodes.indexOf(node)
|
||||
const isParent = document == parent
|
||||
|
||||
parent = parent.removeNode(index)
|
||||
document = isParent ? parent : document.updateDescendant(parent)
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'remove-node',
|
||||
path,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Set `properties` on a node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Object || String} properties
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function setNodeByKey(transform, key, properties) {
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let node = document.assertDescendant(key)
|
||||
const path = document.getPath(node)
|
||||
|
||||
node = node.merge(properties)
|
||||
document = document.updateDescendant(node)
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'set-node',
|
||||
path,
|
||||
properties,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a node by `key` to a new parent by `key` and `index`.
|
||||
*
|
||||
@@ -303,3 +142,165 @@ export function moveNodeByKey(transform, key, newKey, newIndex) {
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove mark from text at `index` and `length` in node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Number} index
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function removeMarkByKey(transform, key, index, length, mark) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let node = document.assertDescendant(key)
|
||||
const path = document.getPath(node)
|
||||
|
||||
node = node.removeMark(index, length, mark)
|
||||
document = document.updateDescendant(node)
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'remove-mark',
|
||||
index,
|
||||
length,
|
||||
mark,
|
||||
path,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function removeNodeByKey(transform, key) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
const node = document.assertDescendant(key)
|
||||
const path = document.getPath(node)
|
||||
let parent = document.getParent(node)
|
||||
const index = parent.nodes.indexOf(node)
|
||||
const isParent = document == parent
|
||||
|
||||
parent = parent.removeNode(index)
|
||||
document = isParent ? parent : document.updateDescendant(parent)
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'remove-node',
|
||||
path,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove text at `index` and `length` in node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Number} index
|
||||
* @param {Number} length
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function removeTextByKey(transform, key, index, length) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let node = document.assertDescendant(key)
|
||||
const path = document.getPath(node)
|
||||
|
||||
node = node.removeText(index, length)
|
||||
document = document.updateDescendant(node)
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'remove-text',
|
||||
index,
|
||||
length,
|
||||
path,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Set `properties` on mark on text at `index` and `length` in node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Number} index
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function setMarkByKey(transform, key, index, length, mark, properties) {
|
||||
properties = Normalize.markProperties(properties)
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let node = document.assertDescendant(key)
|
||||
const path = document.getPath(node)
|
||||
|
||||
node = node.updateMark(index, length, mark, properties)
|
||||
document = document.updateDescendant(node)
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'set-mark',
|
||||
index,
|
||||
length,
|
||||
mark,
|
||||
path,
|
||||
properties,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Set `properties` on a node by `key`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Object || String} properties
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function setNodeByKey(transform, key, properties) {
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let node = document.assertDescendant(key)
|
||||
const path = document.getPath(node)
|
||||
|
||||
node = node.merge(properties)
|
||||
document = document.updateDescendant(node)
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
|
||||
transform.state = state
|
||||
transform.operations.push({
|
||||
type: 'set-node',
|
||||
path,
|
||||
properties,
|
||||
})
|
||||
|
||||
return transform
|
||||
}
|
||||
|
@@ -56,8 +56,15 @@ import {
|
||||
*/
|
||||
|
||||
import {
|
||||
insertTextByKey,
|
||||
removeTextByKey,
|
||||
addMarkByKey,
|
||||
removeMarkByKey,
|
||||
setMarkByKey,
|
||||
insertNodeAfterNodeByKey,
|
||||
removeNodeByKey,
|
||||
setNodeByKey,
|
||||
moveNodeByKey,
|
||||
} from './by-key'
|
||||
|
||||
/**
|
||||
@@ -152,8 +159,15 @@ export default {
|
||||
* By key.
|
||||
*/
|
||||
|
||||
insertTextByKey,
|
||||
removeTextByKey,
|
||||
addMarkByKey,
|
||||
removeMarkByKey,
|
||||
setMarkByKey,
|
||||
insertNodeAfterNodeByKey,
|
||||
removeNodeByKey,
|
||||
setNodeByKey,
|
||||
moveNodeByKey,
|
||||
|
||||
/**
|
||||
* On selection.
|
||||
|
Reference in New Issue
Block a user