mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-31 02:49:56 +02:00
refactor transforms to take transform
This commit is contained in:
@@ -250,8 +250,7 @@ class Transform {
|
||||
Object.keys(Transforms).forEach((type) => {
|
||||
Transform.prototype[type] = function (...args) {
|
||||
this.operations.push({ type, args })
|
||||
this.state = Transforms[type](this.state, ...args)
|
||||
return this
|
||||
return Transforms[type](this, ...args)
|
||||
}
|
||||
})
|
||||
|
||||
|
@@ -27,38 +27,41 @@ import {
|
||||
/**
|
||||
* Add a `mark` to the characters in the current selection.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Mark} mark
|
||||
* @return {State} state
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function addMark(state, mark) {
|
||||
export function addMark(transform, mark) {
|
||||
mark = Normalize.mark(mark)
|
||||
let { state } = transform
|
||||
let { cursorMarks, document, selection } = state
|
||||
|
||||
// If the selection is collapsed, add the mark to the cursor instead.
|
||||
if (selection.isCollapsed) {
|
||||
const marks = document.getMarksAtRange(selection)
|
||||
state = state.merge({ cursorMarks: marks.add(mark) })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
return addMarkAtRange(state, selection, mark)
|
||||
return addMarkAtRange(transform, selection, mark)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete at the current selection.
|
||||
*
|
||||
* @param {State} state
|
||||
* @return {State}
|
||||
* @param {Transform} transform
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function _delete(state) {
|
||||
export function _delete(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let after
|
||||
|
||||
// When collapsed, there's nothing to do.
|
||||
if (selection.isCollapsed) return state
|
||||
if (selection.isCollapsed) return transform
|
||||
|
||||
// Determine what the selection will be after deleting.
|
||||
const { startText } = state
|
||||
@@ -95,20 +98,23 @@ export function _delete(state) {
|
||||
}
|
||||
|
||||
// Delete and update the selection.
|
||||
state = deleteAtRange(state, selection)
|
||||
transform = deleteAtRange(transform, selection)
|
||||
state = transform.state
|
||||
state = state.merge({ selection: after })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete backward `n` characters at the current selection.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Number} n (optional)
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function deleteBackward(state, n = 1) {
|
||||
export function deleteBackward(transform, n = 1) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let after = selection
|
||||
|
||||
@@ -170,20 +176,23 @@ export function deleteBackward(state, n = 1) {
|
||||
}
|
||||
|
||||
// Delete backward and then update the selection.
|
||||
state = deleteBackwardAtRange(state, selection, n)
|
||||
transform = deleteBackwardAtRange(transform, selection, n)
|
||||
state = transform.state
|
||||
state = state.merge({ selection: after })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete forward `n` characters at the current selection.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Number} n (optional)
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function deleteForward(state, n = 1) {
|
||||
export function deleteForward(transform, n = 1) {
|
||||
let { state } = transform
|
||||
let { document, selection, startText } = state
|
||||
let { startKey, startOffset } = selection
|
||||
let after = selection
|
||||
@@ -226,25 +235,29 @@ export function deleteForward(state, n = 1) {
|
||||
}
|
||||
|
||||
// Delete forward and then update the selection.
|
||||
state = deleteForwardAtRange(state, selection, n)
|
||||
transform = deleteForwardAtRange(transform, selection, n)
|
||||
state = transform.state
|
||||
state = state.merge({ selection: after })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a `block` at the current selection.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {String || Object || Block} block
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertBlock(state, block) {
|
||||
export function insertBlock(transform, block) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
const keys = document.getTexts().map(text => text.key)
|
||||
|
||||
// Insert the block
|
||||
state = insertBlockAtRange(state, selection, block)
|
||||
transform = insertBlockAtRange(transform, selection, block)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
selection = state.selection
|
||||
|
||||
@@ -254,23 +267,25 @@ export function insertBlock(state, block) {
|
||||
|
||||
// Update the document and selection.
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a `fragment` at the current selection.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Document} fragment
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertFragment(state, fragment) {
|
||||
export function insertFragment(transform, fragment) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let after = selection
|
||||
|
||||
// If there's nothing in the fragment, do nothing.
|
||||
if (!fragment.length) return state
|
||||
if (!fragment.length) return transform
|
||||
|
||||
// Lookup some nodes for determining the selection next.
|
||||
const lastText = fragment.getTexts().last()
|
||||
@@ -278,7 +293,8 @@ export function insertFragment(state, fragment) {
|
||||
const beforeTexts = document.getTexts()
|
||||
|
||||
// Insert the fragment.
|
||||
state = insertFragmentAtRange(state, selection, fragment)
|
||||
transform = insertFragmentAtRange(transform, selection, fragment)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
selection = state.selection
|
||||
|
||||
@@ -310,24 +326,27 @@ export function insertFragment(state, fragment) {
|
||||
// Update the document and selection.
|
||||
selection = after
|
||||
state = state.merge({ document, selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a `inline` at the current selection.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {String || Object || Block} inline
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertInline(state, inline) {
|
||||
export function insertInline(transform, inline) {
|
||||
let { state } = transform
|
||||
let { document, selection, startText } = state
|
||||
const hasVoid = document.hasVoidParent(startText)
|
||||
const keys = document.getTexts().map(text => text.key)
|
||||
|
||||
// Insert the inline
|
||||
state = insertInlineAtRange(state, selection, inline)
|
||||
transform = insertInlineAtRange(transform, selection, inline)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
selection = state.selection
|
||||
|
||||
@@ -343,19 +362,21 @@ export function insertInline(state, inline) {
|
||||
|
||||
// Update the document and selection.
|
||||
state = state.merge({ document, selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a `text` string at the current selection.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {String} text
|
||||
* @param {Set} marks (optional)
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertText(state, text, marks) {
|
||||
export function insertText(transform, text, marks) {
|
||||
let { state } = transform
|
||||
let { cursorMarks, document, selection } = state
|
||||
let after
|
||||
const isVoid = document.hasVoidParent(state.startText)
|
||||
@@ -374,46 +395,54 @@ export function insertText(state, text, marks) {
|
||||
}
|
||||
|
||||
// Insert the text and update the selection.
|
||||
state = insertTextAtRange(state, selection, text, marks || cursorMarks)
|
||||
state = insertTextAtRange(transform, selection, text, marks || cursorMarks)
|
||||
state = transform.state
|
||||
state = state.merge({ selection: after })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set `properties` of the block nodes in the current selection.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Object} properties
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function setBlock(state, properties) {
|
||||
return setBlockAtRange(state, state.selection, properties)
|
||||
export function setBlock(transform, properties) {
|
||||
const { state } = transform
|
||||
const { selection } = state
|
||||
return setBlockAtRange(transform, selection, properties)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set `properties` of the inline nodes in the current selection.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Object} properties
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function setInline(state, properties) {
|
||||
return setInlineAtRange(state, state.selection, properties)
|
||||
export function setInline(transform, properties) {
|
||||
const { state } = transform
|
||||
const { selection } = state
|
||||
return setInlineAtRange(transform, selection, properties)
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the block node at the current selection, to optional `depth`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Number} depth (optional)
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function splitBlock(state, depth = 1) {
|
||||
state = splitBlockAtRange(state, state.selection, depth)
|
||||
export function splitBlock(transform, depth = 1) {
|
||||
let { state } = transform
|
||||
transform = splitBlockAtRange(transform, state.selection, depth)
|
||||
state = transform.state
|
||||
let { document, selection } = state
|
||||
|
||||
// Determine what the selection should be after splitting.
|
||||
@@ -422,22 +451,25 @@ export function splitBlock(state, depth = 1) {
|
||||
const nextNode = document.getNextText(startNode)
|
||||
selection = selection.collapseToStartOf(nextNode)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the inline nodes at the current selection, to optional `depth`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Number} depth (optional)
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function splitInline(state, depth = Infinity) {
|
||||
export function splitInline(transform, depth = Infinity) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
|
||||
// Split the document.
|
||||
state = splitInlineAtRange(state, selection, depth)
|
||||
transform = splitInlineAtRange(transform, selection, depth)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
selection = state.selection
|
||||
|
||||
@@ -452,99 +484,111 @@ export function splitInline(state, depth = Infinity) {
|
||||
}
|
||||
|
||||
state = state.merge({ document, selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a `mark` from the characters in the current selection.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Mark} mark
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function removeMark(state, mark) {
|
||||
export function removeMark(transform, mark) {
|
||||
mark = Normalize.mark(mark)
|
||||
let { state } = transform
|
||||
let { cursorMarks, document, selection } = state
|
||||
|
||||
// If the selection is collapsed, remove the mark from the cursor instead.
|
||||
if (selection.isCollapsed) {
|
||||
const marks = document.getMarksAtRange(selection)
|
||||
state = state.merge({ cursorMarks: marks.remove(mark) })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
return removeMarkAtRange(state, state.selection, mark)
|
||||
return removeMarkAtRange(transform, state.selection, mark)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or remove a `mark` from the characters in the current selection,
|
||||
* depending on whether it's already there.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Mark} mark
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function toggleMark(state, mark) {
|
||||
export function toggleMark(transform, mark) {
|
||||
mark = Normalize.mark(mark)
|
||||
const { state } = transform
|
||||
const exists = state.marks.some(m => m.equals(mark))
|
||||
return exists
|
||||
? removeMark(state, mark)
|
||||
: addMark(state, mark)
|
||||
? removeMark(transform, mark)
|
||||
: addMark(transform, mark)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap the current selection from a block parent with `properties`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Object or String} properties
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function unwrapBlock(state, properties) {
|
||||
return unwrapBlockAtRange(state, state.selection, properties)
|
||||
export function unwrapBlock(transform, properties) {
|
||||
const { state } = transform
|
||||
const { selection } = state
|
||||
return unwrapBlockAtRange(transform, selection, properties)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap the current selection from an inline parent with `properties`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Object or String} properties
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function unwrapInline(state, properties) {
|
||||
return unwrapInlineAtRange(state, state.selection, properties)
|
||||
export function unwrapInline(transform, properties) {
|
||||
const { state } = transform
|
||||
const { selection } = state
|
||||
return unwrapInlineAtRange(transform, selection, properties)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the block nodes in the current selection with a new block node with
|
||||
* `properties`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Object or String} properties
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function wrapBlock(state, properties) {
|
||||
return wrapBlockAtRange(state, state.selection, properties)
|
||||
export function wrapBlock(transform, properties) {
|
||||
const { state } = transform
|
||||
const { selection } = state
|
||||
return wrapBlockAtRange(transform, selection, properties)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the current selection in new inline nodes with `properties`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Object or String} properties
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function wrapInline(state, properties) {
|
||||
export function wrapInline(transform, properties) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
const { startKey } = selection
|
||||
const previous = document.getPreviousText(startKey)
|
||||
|
||||
state = wrapInlineAtRange(state, selection, properties)
|
||||
transform = wrapInlineAtRange(transform, selection, properties)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
selection = state.selection
|
||||
|
||||
@@ -577,19 +621,21 @@ export function wrapInline(state, properties) {
|
||||
}
|
||||
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the current selection with prefix/suffix.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {String} prefix
|
||||
* @param {String} suffix
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function wrapText(state, prefix, suffix = prefix) {
|
||||
export function wrapText(transform, prefix, suffix = prefix) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let { anchorOffset, anchorKey, focusOffset, focusKey, isBackward } = selection
|
||||
let after
|
||||
@@ -607,7 +653,9 @@ export function wrapText(state, prefix, suffix = prefix) {
|
||||
}
|
||||
|
||||
// Wrap the text and update the state.
|
||||
state = wrapTextAtRange(state, selection, prefix, suffix)
|
||||
transform = wrapTextAtRange(transform, selection, prefix, suffix)
|
||||
state = transform.state
|
||||
state = state.merge({ selection: after })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
@@ -11,20 +11,21 @@ import { Set } from 'immutable'
|
||||
/**
|
||||
* Add a new `mark` to the characters at `range`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Mark || String || Object} mark
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function addMarkAtRange(state, range, mark) {
|
||||
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 state
|
||||
if (range.isCollapsed) return transform
|
||||
|
||||
// Otherwise, find each of the text nodes within the range.
|
||||
const { startKey, startOffset, endKey, endOffset } = range
|
||||
@@ -49,22 +50,24 @@ export function addMarkAtRange(state, range, mark) {
|
||||
|
||||
// Update the state.
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete everything in a `range`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function deleteAtRange(state, range) {
|
||||
export function deleteAtRange(transform, range) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
|
||||
// If the range is collapsed, there's nothing to delete.
|
||||
if (range.isCollapsed) return state
|
||||
if (range.isCollapsed) return transform
|
||||
|
||||
// Make sure the children exist.
|
||||
const { startKey, startOffset, endKey, endOffset } = range
|
||||
@@ -78,7 +81,8 @@ export function deleteAtRange(state, range) {
|
||||
document = document.updateDescendant(text)
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
// Split the blocks and determine the edge boundaries.
|
||||
@@ -93,8 +97,9 @@ export function deleteAtRange(state, range) {
|
||||
let isAncestor = ancestor == document
|
||||
const ancestorDepth = isAncestor ? 0 : document.getDepth(ancestor)
|
||||
|
||||
state = splitBlockAtRange(state, start, startDepth - ancestorDepth)
|
||||
state = splitBlockAtRange(state, end, endDepth - ancestorDepth)
|
||||
transform = splitBlockAtRange(transform, start, startDepth - ancestorDepth)
|
||||
transform = splitBlockAtRange(transform, end, endDepth - ancestorDepth)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
ancestor = document.getCommonAncestor(startKey, endKey)
|
||||
|
||||
@@ -142,41 +147,45 @@ export function deleteAtRange(state, range) {
|
||||
|
||||
// Update the state.
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete backward `n` characters at a `range`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Number} n (optional)
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function deleteBackwardAtRange(state, range, n = 1) {
|
||||
export function deleteBackwardAtRange(transform, range, n = 1) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
const { startKey, startOffset } = range
|
||||
|
||||
// When the range is still expanded, just do a regular delete.
|
||||
if (range.isExpanded) return deleteAtRange(state, range)
|
||||
if (range.isExpanded) return deleteAtRange(transform, range)
|
||||
|
||||
// When collapsed at the start of the node, there's nothing to do.
|
||||
if (range.isAtStartOf(document)) return state
|
||||
if (range.isAtStartOf(document)) return transform
|
||||
|
||||
// When collapsed in a void node, remove that node.
|
||||
const block = document.getClosestBlock(startKey)
|
||||
if (block && block.isVoid) {
|
||||
document = document.removeDescendant(block)
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
const inline = document.getClosestInline(startKey)
|
||||
if (inline && inline.isVoid) {
|
||||
document = document.removeDescendant(inline)
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
// When at start of a text node, merge forwards into the next text node.
|
||||
@@ -190,59 +199,64 @@ export function deleteBackwardAtRange(state, range, n = 1) {
|
||||
if (prevBlock && prevBlock.isVoid) {
|
||||
document = document.removeDescendant(prevBlock)
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
const prevInline = document.getClosestInline(previous)
|
||||
if (prevInline && prevInline.isVoid) {
|
||||
document = document.removeDescendant(prevInline)
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
range = range.extendToEndOf(previous)
|
||||
range = range.normalize(document)
|
||||
return deleteAtRange(state, range)
|
||||
return deleteAtRange(transform, range)
|
||||
}
|
||||
|
||||
// Otherwise, remove `n` characters behind of the cursor.
|
||||
range = range.extendBackward(n)
|
||||
range = range.normalize(document)
|
||||
return deleteAtRange(state, range)
|
||||
return deleteAtRange(transform, range)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete forward `n` characters at a `range`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Number} n (optional)
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function deleteForwardAtRange(state, range, n = 1) {
|
||||
export function deleteForwardAtRange(transform, range, n = 1) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
const { startKey } = range
|
||||
|
||||
// When the range is still expanded, just do a regular delete.
|
||||
if (range.isExpanded) return deleteAtRange(state, range)
|
||||
if (range.isExpanded) return deleteAtRange(transform, range)
|
||||
|
||||
// When collapsed at the end of the node, there's nothing to do.
|
||||
if (range.isAtEndOf(document)) return state
|
||||
if (range.isAtEndOf(document)) return transform
|
||||
|
||||
// When collapsed in a void node, remove that node.
|
||||
const block = document.getClosestBlock(startKey)
|
||||
if (block && block.isVoid) {
|
||||
document = document.removeDescendant(block)
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
const inline = document.getClosestInline(startKey)
|
||||
if (inline && inline.isVoid) {
|
||||
document = document.removeDescendant(inline)
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
// When at end of a text node, merge forwards into the next text node.
|
||||
@@ -251,25 +265,26 @@ export function deleteForwardAtRange(state, range, n = 1) {
|
||||
const next = document.getNextText(startNode)
|
||||
range = range.extendToStartOf(next)
|
||||
range = range.normalize(document)
|
||||
return deleteAtRange(state, range)
|
||||
return deleteAtRange(transform, range)
|
||||
}
|
||||
|
||||
// Otherwise, remove `n` characters ahead of the cursor.
|
||||
range = range.extendForward(n)
|
||||
range = range.normalize(document)
|
||||
return deleteAtRange(state, range)
|
||||
return deleteAtRange(transform, range)
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a `block` node at `range`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Block or String or Object} block
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertBlockAtRange(state, range, block) {
|
||||
export function insertBlockAtRange(transform, range, block) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
|
||||
// Normalize the block argument.
|
||||
@@ -277,7 +292,8 @@ export function insertBlockAtRange(state, range, block) {
|
||||
|
||||
// If expanded, delete the range first.
|
||||
if (range.isExpanded) {
|
||||
state = deleteAtRange(state, range)
|
||||
transform = deleteAtRange(transform, range)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
range = range.collapseToStart()
|
||||
}
|
||||
@@ -311,7 +327,8 @@ export function insertBlockAtRange(state, range, block) {
|
||||
|
||||
// Otherwise, split the block and insert between.
|
||||
else {
|
||||
state = splitBlockAtRange(state, range)
|
||||
transform = splitBlockAtRange(transform, range)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
parent = document.getParent(startBlock)
|
||||
startBlock = document.getClosestBlock(startKey)
|
||||
@@ -332,19 +349,21 @@ export function insertBlockAtRange(state, range, block) {
|
||||
|
||||
// Return the updated state.
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a `fragment` at a `range`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Document} fragment
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertFragmentAtRange(state, range, fragment) {
|
||||
export function insertFragmentAtRange(transform, range, fragment) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
|
||||
// Ensure that the selection is normalized.
|
||||
@@ -352,20 +371,22 @@ export function insertFragmentAtRange(state, range, fragment) {
|
||||
|
||||
// If the range is expanded, delete first.
|
||||
if (range.isExpanded) {
|
||||
state = deleteAtRange(state, range)
|
||||
transform = deleteAtRange(transform, range)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
range = range.collapseToStart()
|
||||
}
|
||||
|
||||
// If the fragment is empty, do nothing.
|
||||
if (!fragment.length) return state
|
||||
if (!fragment.length) return transform
|
||||
|
||||
// Make sure each node in the fragment has a unique key.
|
||||
fragment = fragment.mapDescendants(child => child.set('key', uid()))
|
||||
|
||||
// Split the inlines if need be.
|
||||
if (!document.isInlineSplitAtRange(range)) {
|
||||
state = splitInlineAtRange(state, range)
|
||||
transform = splitInlineAtRange(transform, range)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
}
|
||||
|
||||
@@ -420,7 +441,8 @@ export function insertFragmentAtRange(state, range, fragment) {
|
||||
if (firstBlock == lastBlock) {
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
// Otherwise, remove the fragment's first block's highest solo parent...
|
||||
@@ -441,19 +463,21 @@ export function insertFragmentAtRange(state, range, fragment) {
|
||||
document = document.insertChildrenAfter(block, fragment.nodes)
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert an `inline` node at `range`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Inline or String or Object} inline
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertInlineAtRange(state, range, inline) {
|
||||
export function insertInlineAtRange(transform, range, inline) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
|
||||
// Normalize the inline argument.
|
||||
@@ -461,7 +485,8 @@ export function insertInlineAtRange(state, range, inline) {
|
||||
|
||||
// If expanded, delete the range first.
|
||||
if (range.isExpanded) {
|
||||
state = deleteAtRange(state, range)
|
||||
transform = deleteAtRange(transform, range)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
range = range.collapseToStart()
|
||||
}
|
||||
@@ -470,13 +495,14 @@ export function insertInlineAtRange(state, range, inline) {
|
||||
|
||||
// If the range is inside a void, abort.
|
||||
const startBlock = document.getClosestBlock(startKey)
|
||||
if (startBlock && startBlock.isVoid) return state
|
||||
if (startBlock && startBlock.isVoid) return transform
|
||||
|
||||
const startInline = document.getClosestInline(startKey)
|
||||
if (startInline && startInline.isVoid) return state
|
||||
if (startInline && startInline.isVoid) return transform
|
||||
|
||||
// Split the text nodes at the cursor.
|
||||
state = splitTextAtRange(state, range)
|
||||
transform = splitTextAtRange(transform, range)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
|
||||
// Insert the inline between the split text nodes.
|
||||
@@ -491,30 +517,33 @@ export function insertInlineAtRange(state, range, inline) {
|
||||
document = document.updateDescendant(parent)
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert text `string` at a `range`, with optional `marks`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {String} string
|
||||
* @param {Set} marks (optional)
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertTextAtRange(state, range, string, marks) {
|
||||
export function insertTextAtRange(transform, range, string, marks) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
const { startKey, startOffset } = range
|
||||
const isVoid = document.hasVoidParent(startKey)
|
||||
|
||||
// If inside a void node, do nothing.
|
||||
if (isVoid) return state
|
||||
if (isVoid) return transform
|
||||
|
||||
// Is the range is expanded, delete it first.
|
||||
if (range.isExpanded) {
|
||||
state = deleteAtRange(state, range)
|
||||
transform = deleteAtRange(transform, range)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
range = range.collapseToStart()
|
||||
}
|
||||
@@ -526,24 +555,26 @@ export function insertTextAtRange(state, range, string, marks) {
|
||||
|
||||
// Return the updated selection.
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an existing `mark` to the characters at `range`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Mark or String} mark (optional)
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function removeMarkAtRange(state, range, mark) {
|
||||
export function removeMarkAtRange(transform, range, mark) {
|
||||
let { state } = transform
|
||||
mark = Normalize.mark(mark)
|
||||
let { document } = state
|
||||
|
||||
// When the range is collapsed, do nothing.
|
||||
if (range.isCollapsed) return state
|
||||
if (range.isCollapsed) return transform
|
||||
|
||||
// Otherwise, find each of the text nodes within the range.
|
||||
let texts = document.getTextsAtRange(range)
|
||||
@@ -568,19 +599,21 @@ export function removeMarkAtRange(state, range, mark) {
|
||||
})
|
||||
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the `properties` of block nodes in a `range`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Object or String} properties
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function setBlockAtRange(state, range, properties = {}) {
|
||||
export function setBlockAtRange(transform, range, properties = {}) {
|
||||
let { state } = transform
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
const blocks = document.getBlocksAtRange(range)
|
||||
@@ -592,19 +625,21 @@ export function setBlockAtRange(state, range, properties = {}) {
|
||||
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the `properties` of inline nodes in a `range`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Object or String} properties
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function setInlineAtRange(state, range, properties = {}) {
|
||||
export function setInlineAtRange(transform, range, properties = {}) {
|
||||
let { state } = transform
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
const inlines = document.getInlinesAtRange(range)
|
||||
@@ -616,30 +651,34 @@ export function setInlineAtRange(state, range, properties = {}) {
|
||||
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the block nodes at a `range`, to optional `depth`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Number} depth (optional)
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function splitBlockAtRange(state, range, depth = 1) {
|
||||
export function splitBlockAtRange(transform, range, depth = 1) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
|
||||
// If the range is expanded, remove it first.
|
||||
if (range.isExpanded) {
|
||||
state = deleteAtRange(state, range)
|
||||
transform = deleteAtRange(transform, range)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
range = range.collapseToStart()
|
||||
}
|
||||
|
||||
// Split the inline nodes at the range.
|
||||
state = splitInlineAtRange(state, range)
|
||||
transform = splitInlineAtRange(transform, range)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
|
||||
// Find the highest inline elements that were split.
|
||||
@@ -682,30 +721,34 @@ export function splitBlockAtRange(state, range, depth = 1) {
|
||||
}
|
||||
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the inline nodes at a `range`, to optional `depth`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Number} depth (optiona)
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function splitInlineAtRange(state, range, depth = Infinity) {
|
||||
export function splitInlineAtRange(transform, range, depth = Infinity) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
|
||||
// If the range is expanded, remove it first.
|
||||
if (range.isExpanded) {
|
||||
state = deleteAtRange(state, range)
|
||||
transform = deleteAtRange(transform, range)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
range = range.collapseToStart()
|
||||
}
|
||||
|
||||
// First split the text nodes.
|
||||
state = splitTextAtRange(state, range)
|
||||
transform = splitTextAtRange(transform, range)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
|
||||
// Find the children that were split.
|
||||
@@ -742,23 +785,26 @@ export function splitInlineAtRange(state, range, depth = Infinity) {
|
||||
}
|
||||
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the text nodes at a `range`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function splitTextAtRange(state, range) {
|
||||
export function splitTextAtRange(transform, range) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
|
||||
// If the range is expanded, remove it first.
|
||||
if (range.isExpanded) {
|
||||
state = deleteAtRange(state, range)
|
||||
transform = deleteAtRange(transform, range)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
range = range.collapseToStart()
|
||||
}
|
||||
@@ -784,45 +830,48 @@ export function splitTextAtRange(state, range) {
|
||||
parent = parent.merge({ nodes })
|
||||
document = document.updateDescendant(parent)
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or remove a `mark` from the characters at `range`, depending on whether
|
||||
* it's already there.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {Mark or String} mark (optional)
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function toggleMarkAtRange(state, range, mark) {
|
||||
export function toggleMarkAtRange(transform, range, mark) {
|
||||
let { state } = transform
|
||||
mark = Normalize.mark(mark)
|
||||
let { document } = state
|
||||
|
||||
// When the range is collapsed, do nothing.
|
||||
if (range.isCollapsed) return state
|
||||
if (range.isCollapsed) return transform
|
||||
|
||||
// Check if the mark exists in the range already.
|
||||
const marks = document.getMarksAtRange(range)
|
||||
const exists = marks.some(m => m.equals(mark))
|
||||
|
||||
return exists
|
||||
? removeMarkAtRange(state, range, mark)
|
||||
: addMarkAtRange(state, range, mark)
|
||||
? removeMarkAtRange(transform, range, mark)
|
||||
: addMarkAtRange(transform, range, mark)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap all of the block nodes in a `range` from a block with `properties`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {String or Object} properties
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function unwrapBlockAtRange(state, range, properties) {
|
||||
export function unwrapBlockAtRange(transform, range, properties) {
|
||||
let { state } = transform
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
|
||||
@@ -905,19 +954,21 @@ export function unwrapBlockAtRange(state, range, properties) {
|
||||
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap the inline nodes in a `range` from an inline with `properties`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {String or Object} properties
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function unwrapInlineAtRange(state, range, properties) {
|
||||
export function unwrapInlineAtRange(transform, range, properties) {
|
||||
let { state } = transform
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
let blocks = document.getInlinesAtRange(range)
|
||||
@@ -953,19 +1004,21 @@ export function unwrapInlineAtRange(state, range, properties) {
|
||||
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap all of the blocks in a `range` in a new block with `properties`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {String or Object} properties
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function wrapBlockAtRange(state, range, properties) {
|
||||
export function wrapBlockAtRange(transform, range, properties) {
|
||||
let { state } = transform
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
|
||||
@@ -1012,28 +1065,31 @@ export function wrapBlockAtRange(state, range, properties) {
|
||||
: document.updateDescendant(parent.merge({ nodes }))
|
||||
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the text and inlines in a `range` in a new inline with `properties`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {String or Object} properties
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function wrapInlineAtRange(state, range, properties) {
|
||||
export function wrapInlineAtRange(transform, range, properties) {
|
||||
let { state } = transform
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
|
||||
// If collapsed, there's nothing to wrap.
|
||||
if (range.isCollapsed) return state
|
||||
if (range.isCollapsed) return transform
|
||||
|
||||
// Split at the start of the range.
|
||||
const start = range.collapseToStart()
|
||||
state = splitInlineAtRange(state, start)
|
||||
transform = splitInlineAtRange(transform, start)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
|
||||
// Determine the new end of the range, and split there.
|
||||
@@ -1049,7 +1105,8 @@ export function wrapInlineAtRange(state, range, properties) {
|
||||
focusOffset: endOffset - startOffset
|
||||
})
|
||||
|
||||
state = splitInlineAtRange(state, end)
|
||||
transform = splitInlineAtRange(transform, end)
|
||||
state = transform.state
|
||||
document = state.document
|
||||
|
||||
// Calculate the new range to wrap around.
|
||||
@@ -1087,28 +1144,30 @@ export function wrapInlineAtRange(state, range, properties) {
|
||||
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the text in a `range` in a prefix/suffix.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {Selection} range
|
||||
* @param {String} prefix
|
||||
* @param {String} suffix
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function wrapTextAtRange(state, range, prefix, suffix = prefix) {
|
||||
export function wrapTextAtRange(transform, range, prefix, suffix = prefix) {
|
||||
let { state } = transform
|
||||
// Insert text at the starting edge.
|
||||
const { startKey, endKey } = range
|
||||
const start = range.collapseToStart()
|
||||
state = insertTextAtRange(state, start, prefix)
|
||||
transform = insertTextAtRange(transform, start, prefix)
|
||||
|
||||
// Determine the new ending edge, and insert text there.
|
||||
let end = range.collapseToEnd()
|
||||
if (startKey == endKey) end = end.moveForward(prefix.length)
|
||||
state = insertTextAtRange(state, end, suffix)
|
||||
return state
|
||||
transform = insertTextAtRange(transform, end, suffix)
|
||||
return transform
|
||||
}
|
||||
|
@@ -4,48 +4,53 @@ import Normalize from '../utils/normalize'
|
||||
/**
|
||||
* Remove a node by `key`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function removeNodeByKey(state, key) {
|
||||
export function removeNodeByKey(transform, key) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
document = document.removeDescendant(key)
|
||||
document = document.normalize()
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Set `properties` on a node by `key`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Object or String} properties
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function setNodeByKey(state, key, properties) {
|
||||
export function setNodeByKey(transform, key, properties) {
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let descendant = document.assertDescendant(key)
|
||||
descendant = descendant.merge(properties)
|
||||
document = document.updateDescendant(descendant)
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a `node` after a node by `key`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Node} node
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertNodeAfterNodeByKey(state, key, node) {
|
||||
export function insertNodeAfterNodeByKey(transform, key, node) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let descendant = document.assertDescendant(key)
|
||||
let parent = document.getParent(key)
|
||||
@@ -54,19 +59,21 @@ export function insertNodeAfterNodeByKey(state, key, node) {
|
||||
parent = parent.merge({ nodes })
|
||||
document = document.updateDescendant(parent)
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a `node` before a node by `key`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Node} node
|
||||
* @return {State}
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertNodeBeforeNodeByKey(state, key, node) {
|
||||
export function insertNodeBeforeNodeByKey(transform, key, node) {
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
let descendant = document.assertDescendant(key)
|
||||
let parent = document.getParent(key)
|
||||
@@ -75,5 +82,6 @@ export function insertNodeBeforeNodeByKey(state, key, node) {
|
||||
parent = parent.merge({ nodes })
|
||||
document = document.updateDescendant(parent)
|
||||
state = state.merge({ document })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
@@ -4,57 +4,66 @@ import Selection from '../models/selection'
|
||||
/**
|
||||
* Blur the selection.
|
||||
*
|
||||
* @return {Selection} selection
|
||||
* @param {Transform} transform
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function blur(state, ...args) {
|
||||
export function blur(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.blur(...args)
|
||||
selection = selection.blur()
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the focus point to the anchor point.
|
||||
*
|
||||
* @return {Selection} selection
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function collapseToAnchor(state, ...args) {
|
||||
export function collapseToAnchor(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.collapseToAnchor(...args)
|
||||
selection = selection.collapseToAnchor()
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the anchor point to the focus point.
|
||||
*
|
||||
* @return {Selection} selection
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function collapseToFocus(state, ...args) {
|
||||
export function collapseToFocus(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.collapseToFocus(...args)
|
||||
selection = selection.collapseToFocus()
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Move to the end of a `node`.
|
||||
*
|
||||
* @return {Selection} selection
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function collapseToEndOf(state, ...args) {
|
||||
export function collapseToEndOf(transform, ...args) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.collapseToEndOf(...args)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,19 +73,21 @@ export function collapseToEndOf(state, ...args) {
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
export function collapseToEndOfNextBlock(state) {
|
||||
export function collapseToEndOfNextBlock(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let blocks = document.getBlocksAtRange(selection)
|
||||
let block = blocks.last()
|
||||
if (!block) return state
|
||||
if (!block) return transform
|
||||
|
||||
let next = document.getNextBlock(block)
|
||||
if (!next) return state
|
||||
if (!next) return transform
|
||||
|
||||
selection = selection.collapseToEndOf(next)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,19 +97,21 @@ export function collapseToEndOfNextBlock(state) {
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
export function collapseToEndOfNextText(state) {
|
||||
export function collapseToEndOfNextText(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let texts = document.getTextsAtRange(selection)
|
||||
let text = texts.last()
|
||||
if (!text) return state
|
||||
if (!text) return transform
|
||||
|
||||
let next = document.getNextText(text)
|
||||
if (!next) return state
|
||||
if (!next) return transform
|
||||
|
||||
selection = selection.collapseToEndOf(next)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,19 +121,21 @@ export function collapseToEndOfNextText(state) {
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
export function collapseToEndOfPreviousBlock(state) {
|
||||
export function collapseToEndOfPreviousBlock(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let blocks = document.getBlocksAtRange(selection)
|
||||
let block = blocks.first()
|
||||
if (!block) return state
|
||||
if (!block) return transform
|
||||
|
||||
let previous = document.getPreviousBlock(block)
|
||||
if (!previous) return state
|
||||
if (!previous) return transform
|
||||
|
||||
selection = selection.collapseToEndOf(previous)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,33 +145,37 @@ export function collapseToEndOfPreviousBlock(state) {
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
export function collapseToEndOfPreviousText(state) {
|
||||
export function collapseToEndOfPreviousText(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let texts = document.getTextsAtRange(selection)
|
||||
let text = texts.first()
|
||||
if (!text) return state
|
||||
if (!text) return transform
|
||||
|
||||
let previous = document.getPreviousText(text)
|
||||
if (!previous) return state
|
||||
if (!previous) return transform
|
||||
|
||||
selection = selection.collapseToEndOf(previous)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Move to the start of a `node`.
|
||||
*
|
||||
* @return {Selection} selection
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function collapseToStartOf(state, ...args) {
|
||||
export function collapseToStartOf(transform, node) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.collapseToStartOf(...args)
|
||||
selection = selection.collapseToStartOf(node)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,19 +185,21 @@ export function collapseToStartOf(state, ...args) {
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
export function collapseToStartOfNextBlock(state) {
|
||||
export function collapseToStartOfNextBlock(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let blocks = document.getBlocksAtRange(selection)
|
||||
let block = blocks.last()
|
||||
if (!block) return state
|
||||
if (!block) return transform
|
||||
|
||||
let next = document.getNextBlock(block)
|
||||
if (!next) return state
|
||||
if (!next) return transform
|
||||
|
||||
selection = selection.collapseToStartOf(next)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,19 +209,21 @@ export function collapseToStartOfNextBlock(state) {
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
export function collapseToStartOfNextText(state) {
|
||||
export function collapseToStartOfNextText(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let texts = document.getTextsAtRange(selection)
|
||||
let text = texts.last()
|
||||
if (!text) return state
|
||||
if (!text) return transform
|
||||
|
||||
let next = document.getNextText(text)
|
||||
if (!next) return state
|
||||
if (!next) return transform
|
||||
|
||||
selection = selection.collapseToStartOf(next)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -210,19 +233,21 @@ export function collapseToStartOfNextText(state) {
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
export function collapseToStartOfPreviousBlock(state) {
|
||||
export function collapseToStartOfPreviousBlock(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let blocks = document.getBlocksAtRange(selection)
|
||||
let block = blocks.first()
|
||||
if (!block) return state
|
||||
if (!block) return transform
|
||||
|
||||
let previous = document.getPreviousBlock(block)
|
||||
if (!previous) return state
|
||||
if (!previous) return transform
|
||||
|
||||
selection = selection.collapseToStartOf(previous)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,123 +257,139 @@ export function collapseToStartOfPreviousBlock(state) {
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
export function collapseToStartOfPreviousText(state) {
|
||||
export function collapseToStartOfPreviousText(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let texts = document.getTextsAtRange(selection)
|
||||
let text = texts.first()
|
||||
if (!text) return state
|
||||
if (!text) return transform
|
||||
|
||||
let previous = document.getPreviousText(text)
|
||||
if (!previous) return state
|
||||
if (!previous) return transform
|
||||
|
||||
selection = selection.collapseToStartOf(previous)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the focus point backward `n` characters.
|
||||
*
|
||||
* @param {Number} n (optional)
|
||||
* @return {Selection} selection
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function extendBackward(state, ...args) {
|
||||
export function extendBackward(transform, ...args) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.extendBackward(...args)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the focus point forward `n` characters.
|
||||
*
|
||||
* @param {Number} n (optional)
|
||||
* @return {Selection} selection
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function extendForward(state, ...args) {
|
||||
export function extendForward(transform, ...args) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.extendForward(...args)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the focus point to the end of a `node`.
|
||||
*
|
||||
* @param {Node} node
|
||||
* @return {Selection} selection
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function extendToEndOf(state, ...args) {
|
||||
export function extendToEndOf(transform, ...args) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.extendToEndOf(...args)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the focus point to the start of a `node`.
|
||||
*
|
||||
* @param {Node} node
|
||||
* @return {Selection} selection
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function extendToStartOf(state, ...args) {
|
||||
export function extendToStartOf(transform, ...args) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.extendToStartOf(...args)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus the selection.
|
||||
*
|
||||
* @return {Selection} selection
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function focus(state, ...args) {
|
||||
export function focus(transform, ...args) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.focus(...args)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the selection backward `n` characters.
|
||||
*
|
||||
* @param {Number} n (optional)
|
||||
* @return {Selection} selection
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function moveBackward(state, ...args) {
|
||||
export function moveBackward(transform, ...args) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.moveBackward(...args)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the selection forward `n` characters.
|
||||
*
|
||||
* @param {Number} n (optional)
|
||||
* @return {Selection} selection
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function moveForward(state, ...args) {
|
||||
export function moveForward(transform, ...args) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.moveForward(...args)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,7 +400,8 @@ export function moveForward(state, ...args) {
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
export function moveTo(state, properties) {
|
||||
export function moveTo(transform, properties) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
|
||||
// Allow for passing a `Selection` object.
|
||||
@@ -381,7 +423,8 @@ export function moveTo(state, properties) {
|
||||
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -389,15 +432,17 @@ export function moveTo(state, properties) {
|
||||
*
|
||||
* @param {Number} anchor
|
||||
* @param {Number} focus (optional)
|
||||
* @return {Selection} selection
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function moveToOffsets(state, ...args) {
|
||||
export function moveToOffsets(transform, ...args) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.moveToOffsets(...args)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -405,13 +450,15 @@ export function moveToOffsets(state, ...args) {
|
||||
*
|
||||
* @param {Node} start
|
||||
* @param {Node} end (optional)
|
||||
* @return {Selection} selection
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function moveToRangeOf(state, ...args) {
|
||||
export function moveToRangeOf(transform, ...args) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.moveToRangeOf(...args)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
return state
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
Reference in New Issue
Block a user