mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-21 14:41:23 +02:00
refactor transforms to apply operations immediately
This commit is contained in:
@@ -383,9 +383,7 @@ class State extends new Record(DEFAULTS) {
|
|||||||
transform = rule.normalize(transform, document, value)
|
transform = rule.normalize(transform, document, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform.steps.size
|
return transform.apply({ snapshot: false })
|
||||||
? transform.apply({ snapshot: false })
|
|
||||||
: state
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -11,14 +11,14 @@ import { List, Record } from 'immutable'
|
|||||||
const Snapshot = new Record({
|
const Snapshot = new Record({
|
||||||
document: null,
|
document: null,
|
||||||
selection: null,
|
selection: null,
|
||||||
steps: new List()
|
operations: new List()
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Step.
|
* Operation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const Step = new Record({
|
const Operation = new Record({
|
||||||
type: null,
|
type: null,
|
||||||
args: null
|
args: null
|
||||||
})
|
})
|
||||||
@@ -29,7 +29,7 @@ const Step = new Record({
|
|||||||
|
|
||||||
const DEFAULT_PROPERTIES = {
|
const DEFAULT_PROPERTIES = {
|
||||||
state: null,
|
state: null,
|
||||||
steps: new List()
|
operations: new List()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -91,7 +91,7 @@ class Transform extends new Record(DEFAULT_PROPERTIES) {
|
|||||||
|
|
||||||
apply(options = {}) {
|
apply(options = {}) {
|
||||||
const transform = this
|
const transform = this
|
||||||
let { state, steps } = transform
|
let { state, operations } = transform
|
||||||
let { cursorMarks, history, selection } = state
|
let { cursorMarks, history, selection } = state
|
||||||
let { undos, redos } = history
|
let { undos, redos } = history
|
||||||
|
|
||||||
@@ -110,9 +110,6 @@ class Transform extends new Record(DEFAULT_PROPERTIES) {
|
|||||||
state = state.merge({ history })
|
state = state.merge({ history })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply each of the steps in the transform, arriving at a new state.
|
|
||||||
state = steps.reduce((memo, step) => this.applyStep(memo, step), state)
|
|
||||||
|
|
||||||
// If there are cursor marks and they haven't changed, remove them.
|
// If there are cursor marks and they haven't changed, remove them.
|
||||||
if (state.cursorMarks && state.cursorMarks == cursorMarks) {
|
if (state.cursorMarks && state.cursorMarks == cursorMarks) {
|
||||||
state = state.merge({
|
state = state.merge({
|
||||||
@@ -130,56 +127,36 @@ class Transform extends new Record(DEFAULT_PROPERTIES) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply a single `step` to a `state`, differentiating between types.
|
* Check whether the current transform operations should create a snapshot.
|
||||||
*
|
|
||||||
* @param {State} state
|
|
||||||
* @param {Step} step
|
|
||||||
* @return {State} state
|
|
||||||
*/
|
|
||||||
|
|
||||||
applyStep(state, step) {
|
|
||||||
const { type, args } = step
|
|
||||||
const transform = Transforms[type]
|
|
||||||
|
|
||||||
if (!transform) {
|
|
||||||
throw new Error(`Unknown transform type: "${type}".`)
|
|
||||||
}
|
|
||||||
|
|
||||||
state = transform(state, ...args)
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether the current transform steps should create a snapshot.
|
|
||||||
*
|
*
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
shouldSnapshot() {
|
shouldSnapshot() {
|
||||||
const transform = this
|
const transform = this
|
||||||
const { state, steps } = transform
|
const { state, operations } = transform
|
||||||
const { cursorMarks, history, selection } = state
|
const { cursorMarks, history, selection } = state
|
||||||
const { undos, redos } = history
|
const { undos, redos } = history
|
||||||
const previous = undos.peek()
|
const previous = undos.peek()
|
||||||
|
|
||||||
// If the only steps applied are selection transforms, don't snapshot.
|
// If the only operations applied are selection transforms, don't snapshot.
|
||||||
const onlySelections = steps.every(step => includes(SELECTION_TRANSFORMS, step.type))
|
const onlySelections = operations.every(operation => includes(SELECTION_TRANSFORMS, operation.type))
|
||||||
if (onlySelections) return false
|
if (onlySelections) return false
|
||||||
|
|
||||||
// If there isn't a previous state, snapshot.
|
// If there isn't a previous state, snapshot.
|
||||||
if (!previous) return true
|
if (!previous) return true
|
||||||
|
|
||||||
// If there is a previous state but the steps are different, snapshot.
|
// If there is a previous state but the operations are different, snapshot.
|
||||||
const types = steps.map(step => step.type)
|
const types = operations.map(operation => operation.type)
|
||||||
const prevTypes = previous.steps.map(step => step.type)
|
const prevTypes = previous.operations.map(operation => operation.type)
|
||||||
const diff = xor(types.toArray(), prevTypes.toArray())
|
const diff = xor(types.toArray(), prevTypes.toArray())
|
||||||
if (diff.length) return true
|
if (diff.length) return true
|
||||||
|
|
||||||
// If the current steps aren't one of the "combinable" types, snapshot.
|
// If the current operations aren't one of the "combinable" types, snapshot.
|
||||||
const allCombinable = (
|
const allCombinable = (
|
||||||
steps.every(step => step.type == 'insertText') ||
|
operations.every(operation => operation.type == 'insertText') ||
|
||||||
steps.every(step => step.type == 'deleteForward') ||
|
operations.every(operation => operation.type == 'deleteForward') ||
|
||||||
steps.every(step => step.type == 'deleteBackward')
|
operations.every(operation => operation.type == 'deleteBackward')
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!allCombinable) return true
|
if (!allCombinable) return true
|
||||||
@@ -195,9 +172,9 @@ class Transform extends new Record(DEFAULT_PROPERTIES) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
snapshot() {
|
snapshot() {
|
||||||
let { state, steps } = this
|
let { state, operations } = this
|
||||||
let { document, selection } = state
|
let { document, selection } = state
|
||||||
return new Snapshot({ document, selection, steps })
|
return new Snapshot({ document, selection, operations })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -275,15 +252,16 @@ class Transform extends new Record(DEFAULT_PROPERTIES) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a step-creating method for each of the transforms.
|
* Add a operation-creating method for each of the transforms.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Object.keys(Transforms).forEach((type) => {
|
Object.keys(Transforms).forEach((type) => {
|
||||||
Transform.prototype[type] = function (...args) {
|
Transform.prototype[type] = function (...args) {
|
||||||
let transform = this
|
let transform = this
|
||||||
let { steps } = transform
|
let { operations, state } = transform
|
||||||
steps = steps.push(new Step({ type, args }))
|
operations = operations.push(new Operation({ type, args }))
|
||||||
transform = transform.merge({ steps })
|
state = Transforms[type](state, ...args)
|
||||||
|
transform = transform.merge({ operations, state })
|
||||||
return transform
|
return transform
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@@ -6,7 +6,7 @@ import Normalize from '../utils/normalize'
|
|||||||
*
|
*
|
||||||
* @param {State} state
|
* @param {State} state
|
||||||
* @param {String} key
|
* @param {String} key
|
||||||
* @return {State} state
|
* @return {State}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function removeNodeByKey(state, key) {
|
export function removeNodeByKey(state, key) {
|
||||||
@@ -23,7 +23,7 @@ export function removeNodeByKey(state, key) {
|
|||||||
* @param {State} state
|
* @param {State} state
|
||||||
* @param {String} key
|
* @param {String} key
|
||||||
* @param {Object or String} properties
|
* @param {Object or String} properties
|
||||||
* @return {State} state
|
* @return {State}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function setNodeByKey(state, key, properties) {
|
export function setNodeByKey(state, key, properties) {
|
||||||
@@ -35,3 +35,45 @@ export function setNodeByKey(state, key, properties) {
|
|||||||
state = state.merge({ document })
|
state = state.merge({ document })
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a `node` after a node by `key`.
|
||||||
|
*
|
||||||
|
* @param {State} state
|
||||||
|
* @param {String} key
|
||||||
|
* @param {Node} node
|
||||||
|
* @return {State}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function insertNodeAfterNodeByKey(state, key, node) {
|
||||||
|
let { document } = state
|
||||||
|
let descendant = document.assertDescendant(key)
|
||||||
|
let parent = document.getParent(key)
|
||||||
|
let index = parent.nodes.indexOf(descendant)
|
||||||
|
let nodes = parent.nodes.splice(index + 1, 0, node)
|
||||||
|
parent = parent.merge({ nodes })
|
||||||
|
document = document.updateDescendant(parent)
|
||||||
|
state = state.merge({ document })
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a `node` before a node by `key`.
|
||||||
|
*
|
||||||
|
* @param {State} state
|
||||||
|
* @param {String} key
|
||||||
|
* @param {Node} node
|
||||||
|
* @return {State}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function insertNodeBeforeNodeByKey(state, key, node) {
|
||||||
|
let { document } = state
|
||||||
|
let descendant = document.assertDescendant(key)
|
||||||
|
let parent = document.getParent(key)
|
||||||
|
let index = parent.nodes.indexOf(descendant)
|
||||||
|
let nodes = parent.nodes.splice(index, 0, node)
|
||||||
|
parent = parent.merge({ nodes })
|
||||||
|
document = document.updateDescendant(parent)
|
||||||
|
state = state.merge({ document })
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user