tldraw/state/history.ts

135 lines
3 KiB
TypeScript
Raw Normal View History

import { Data } from 'types'
import { BaseCommand } from './commands/command'
const CURRENT_VERSION = 'code_slate_0.0.2'
2021-05-10 12:16:57 +00:00
2021-05-13 06:44:52 +00:00
// A singleton to manage history changes.
class BaseHistory<T> {
2021-05-10 12:16:57 +00:00
private stack: BaseCommand<T>[] = []
private pointer = -1
private maxLength = 100
private _enabled = true
execute = (data: T, command: BaseCommand<T>) => {
command.redo(data, true)
2021-05-10 12:16:57 +00:00
if (this.disabled) return
this.stack = this.stack.slice(0, this.pointer + 1)
this.stack.push(command)
this.pointer++
if (this.stack.length > this.maxLength) {
this.stack = this.stack.slice(this.stack.length - this.maxLength)
this.pointer = this.maxLength - 1
}
this.save(data)
}
undo = (data: T) => {
if (this.pointer === -1) return
const command = this.stack[this.pointer]
command.undo(data)
if (this.disabled) return
2021-05-10 12:16:57 +00:00
this.pointer--
this.save(data)
}
redo = (data: T) => {
if (this.pointer === this.stack.length - 1) return
const command = this.stack[this.pointer + 1]
command.redo(data, false)
if (this.disabled) return
2021-05-10 12:16:57 +00:00
this.pointer++
this.save(data)
}
load(data: T, id = CURRENT_VERSION) {
if (typeof window === 'undefined') return
if (typeof localStorage === 'undefined') return
2021-05-10 12:16:57 +00:00
const savedData = localStorage.getItem(id)
if (savedData !== null) {
Object.assign(data, this.restoreSavedData(JSON.parse(savedData)))
}
}
save = (data: T, id = CURRENT_VERSION) => {
if (typeof window === 'undefined') return
if (typeof localStorage === 'undefined') return
localStorage.setItem(id, JSON.stringify(this.prepareDataForSave(data)))
2021-05-10 12:16:57 +00:00
}
disable = () => {
this._enabled = false
}
enable = () => {
this._enabled = true
}
prepareDataForSave(data: T): any {
return { ...data }
}
restoreSavedData(data: any): T {
return { ...data }
}
2021-05-19 21:24:41 +00:00
pop() {
if (this.stack.length > 0) {
this.stack.pop()
this.pointer--
}
}
2021-05-10 12:16:57 +00:00
get disabled() {
return !this._enabled
}
}
// App-specific
class History extends BaseHistory<Data> {
constructor() {
super()
}
prepareDataForSave(data: Data): any {
const dataToSave: any = { ...data }
dataToSave.selectedIds = Array.from(data.selectedIds.values())
return dataToSave
}
restoreSavedData(data: any): Data {
2021-06-03 12:06:39 +00:00
const restoredData: Data = { ...data }
restoredData.selectedIds = new Set(restoredData.selectedIds)
// Also restore camera position, which is saved separately in this app
const cameraInfo = localStorage.getItem('code_slate_camera')
if (cameraInfo !== null) {
2021-06-03 12:06:39 +00:00
Object.assign(
restoredData.pageStates[data.currentPageId].camera,
JSON.parse(cameraInfo)
)
// And update the CSS property
document.documentElement.style.setProperty(
'--camera-zoom',
2021-06-03 12:06:39 +00:00
restoredData.pageStates[data.currentPageId].camera.zoom.toString()
)
}
return restoredData
}
}
export default new History()