1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-01-18 22:08:18 +01:00

got undo working properly for different transforms!

This commit is contained in:
Ian Storm Taylor 2016-06-18 19:18:47 -07:00
parent 3bc080d967
commit 8f64e8941f
4 changed files with 73 additions and 53 deletions

View File

@ -111,7 +111,7 @@ class Content extends React.Component {
}
state = transform
.insert(data)
.insertText(data)
.apply()
this.onChange(state)

View File

@ -224,14 +224,14 @@ class Document extends Record(DEFAULT_PROPERTIES) {
}
/**
* Insert `data` at a `range`.
* Insert `text` at a `range`.
*
* @param {Selection} range
* @param {String or Node or OrderedMap} data
* @param {String} text
* @return {Document} document
*/
insertAtRange(range, data) {
insertTextAtRange(range, text) {
let document = this
// When still expanded, remove the current range first.
@ -240,33 +240,30 @@ class Document extends Record(DEFAULT_PROPERTIES) {
range = range.moveToStart()
}
// When the data is a string of characters...
if (typeof data == 'string') {
let { startNode, startOffset } = document
let { characters } = startNode
let { startKey, startOffset } = range
let startNode = document.getNode(startKey)
let { characters } = startNode
// Create a list of the new characters, with the right marks.
const marks = characters.has(startOffset)
? characters.get(startOffset).marks
: null
// Create a list of the new characters, with the right marks.
const marks = characters.has(startOffset)
? characters.get(startOffset).marks
: null
const newCharacters = data.split('').reduce((list, char) => {
const obj = { text: char }
if (marks) obj.marks = marks
return list.push(Character.create(obj))
}, Character.createList())
const newCharacters = text.split('').reduce((list, char) => {
const obj = { text }
if (marks) obj.marks = marks
return list.push(Character.create(obj))
}, Character.createList())
// Splice in the new characters.
const resumeOffset = startOffset + data.length - 1
characters = characters.slice(0, startOffset)
.concat(newCharacters)
.concat(characters.slice(resumeOffset, Infinity))
// Splice in the new characters.
const resumeOffset = startOffset + text.length - 1
characters = characters.slice(0, startOffset)
.concat(newCharacters)
.concat(characters.slice(resumeOffset, Infinity))
// Update the existing text node.
startNode = startNode.merge({ characters })
document = document.updateNode(startNode)
return document
}
// Update the existing text node.
startNode = startNode.merge({ characters })
document = document.updateNode(startNode)
// Normalize the document.
return document.normalize()

View File

@ -146,23 +146,17 @@ class State extends Record(DEFAULT_PROPERTIES) {
/**
* Insert a `text` string at the current cursor position.
*
* @param {String or Node or OrderedMap} data
* @param {String} text
* @return {State} state
*/
insert(data) {
insertText(text) {
let state = this
let { document, selection } = state
let after
// Determine what the selection should be after inserting.
if (typeof data == 'string') {
after = selection.moveForward(data.length)
}
// Insert the data and update the selection.
document = document.insertAtRange(selection, data)
selection = after
// Insert the text and update the selection.
document = document.insertTextAtRange(selection, text)
selection = selection.moveForward(text.length)
state = state.merge({ document, selection })
return state
}

View File

@ -1,4 +1,6 @@
import uniq from 'lodash/uniq'
import xor from 'lodash/xor'
import { List, Record } from 'immutable'
/**
@ -7,7 +9,8 @@ import { List, Record } from 'immutable'
const Snapshot = Record({
document: null,
selection: null
selection: null,
steps: new List()
})
/**
@ -39,8 +42,8 @@ const TRANSFORM_TYPES = [
'deleteBackwardAtRange',
'deleteForward',
'deleteForwardAtRange',
'insert',
'insertAtRange',
'insertText',
'insertTextAtRange',
'split',
'splitAtRange'
]
@ -58,9 +61,9 @@ class Transform extends Record(DEFAULT_PROPERTIES) {
*/
snapshot() {
let { state } = this
let { state, steps } = this
let { document, selection } = state
return new Snapshot({ document, selection })
return new Snapshot({ document, selection, steps })
}
/**
@ -70,17 +73,44 @@ class Transform extends Record(DEFAULT_PROPERTIES) {
*/
apply() {
let transform = this
const transform = this
let { state, steps } = transform
let { history } = state
let { undos, redos } = history
// Save the current state into the history before transforming.
let snapshot = transform.snapshot()
undos = undos.unshift(snapshot)
redos = redos.clear()
history = history.merge({ undos, redos })
state = state.merge({ history })
// Determine whether we need to create a new snapshot.
let shouldSnapshot = false
const previous = undos.peek()
// If there isn't a previous state, snapshot.
if (!previous) shouldSnapshot = true
// If there is a previous state but the steps are different, snapshot.
if (!shouldSnapshot && previous) {
const types = steps.map(step => step.type)
const prevTypes = previous.steps.map(step => step.type)
const diff = xor(types.toArray(), prevTypes.toArray())
if (diff.length) shouldSnapshot = true
}
// If the current steps aren't one of the "combinale" types, snapshot.
if (!shouldSnapshot) {
const allCombinable = (
steps.every(step => step.type == 'insertText') ||
steps.every(step => step.type == 'deleteForward') ||
steps.every(step => step.type == 'deleteBackward')
)
if (!allCombinable) shouldSnapshot = true
}
// If we should, save a snapshot into the history before transforming.
if (shouldSnapshot) {
const snapshot = transform.snapshot()
undos = undos.unshift(snapshot)
redos = redos.clear()
history = history.merge({ undos, redos })
state = state.merge({ history })
}
// Apply each of the steps in the transform, arriving at a new state.
state = steps.reduce((state, step) => {
@ -91,7 +121,6 @@ class Transform extends Record(DEFAULT_PROPERTIES) {
return state
}
/**
* Undo to the previous state in the history.
*
@ -99,7 +128,7 @@ class Transform extends Record(DEFAULT_PROPERTIES) {
*/
undo() {
let transform = this
const transform = this
let { state } = transform
let { history } = state
let { undos, redos } = history
@ -129,7 +158,7 @@ class Transform extends Record(DEFAULT_PROPERTIES) {
*/
redo() {
let transform = this
const transform = this
let { state } = transform
let { history } = state
let { undos, redos } = history