2021-05-10 12:16:57 +00:00
|
|
|
import { Data } from "types"
|
|
|
|
|
|
|
|
/* ------------------ Command Class ----------------- */
|
|
|
|
|
|
|
|
export type CommandFn<T> = (data: T, initial?: boolean) => void
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A command makes changes to some applicate state. Every command has an "undo"
|
|
|
|
* method to reverse its changes. The apps history is a series of commands.
|
|
|
|
*/
|
|
|
|
export class BaseCommand<T extends any> {
|
|
|
|
timestamp = Date.now()
|
2021-05-13 06:44:52 +00:00
|
|
|
name: string
|
|
|
|
category: string
|
2021-05-10 12:16:57 +00:00
|
|
|
private undoFn: CommandFn<T>
|
|
|
|
private doFn: CommandFn<T>
|
|
|
|
protected restoreBeforeSelectionState: (data: T) => void
|
|
|
|
protected restoreAfterSelectionState: (data: T) => void
|
|
|
|
protected saveSelectionState: (data: T) => (data: T) => void
|
|
|
|
protected manualSelection: boolean
|
|
|
|
|
|
|
|
constructor(options: {
|
|
|
|
do: CommandFn<T>
|
|
|
|
undo: CommandFn<T>
|
2021-05-13 06:44:52 +00:00
|
|
|
name: string
|
|
|
|
category: string
|
2021-05-10 12:16:57 +00:00
|
|
|
manualSelection?: boolean
|
|
|
|
}) {
|
2021-05-13 06:44:52 +00:00
|
|
|
this.name = options.name
|
|
|
|
this.category = options.category
|
2021-05-10 12:16:57 +00:00
|
|
|
this.doFn = options.do
|
|
|
|
this.undoFn = options.undo
|
|
|
|
this.manualSelection = options.manualSelection || false
|
|
|
|
this.restoreBeforeSelectionState = () => () => {
|
|
|
|
null
|
|
|
|
}
|
|
|
|
this.restoreAfterSelectionState = () => () => {
|
|
|
|
null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
undo = (data: T) => {
|
|
|
|
if (this.manualSelection) {
|
|
|
|
this.undoFn(data)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to set the selection state to what it was before we after we did the command
|
|
|
|
this.restoreAfterSelectionState(data)
|
|
|
|
this.undoFn(data)
|
|
|
|
this.restoreBeforeSelectionState(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
redo = (data: T, initial = false) => {
|
|
|
|
if (initial) {
|
|
|
|
this.restoreBeforeSelectionState = this.saveSelectionState(data)
|
|
|
|
} else {
|
|
|
|
this.restoreBeforeSelectionState(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to set the selection state to what it was before we did the command
|
|
|
|
this.doFn(data, initial)
|
|
|
|
|
|
|
|
if (initial) {
|
|
|
|
this.restoreAfterSelectionState = this.saveSelectionState(data)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------- Project Specific ---------------- */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A subclass of BaseCommand that sends events to our state. In our case, we want our actions
|
|
|
|
* to mutate the state's data. Actions do not effect the "active states" in
|
|
|
|
* the app.
|
|
|
|
*/
|
2021-05-13 06:44:52 +00:00
|
|
|
export default class Command extends BaseCommand<Data> {
|
2021-05-10 12:16:57 +00:00
|
|
|
saveSelectionState = (data: Data) => {
|
2021-05-13 06:44:52 +00:00
|
|
|
const selectedIds = new Set(data.selectedIds)
|
|
|
|
return (data: Data) => {
|
2021-05-15 13:02:13 +00:00
|
|
|
data.hoveredId = undefined
|
|
|
|
data.pointedId = undefined
|
2021-05-13 06:44:52 +00:00
|
|
|
data.selectedIds = selectedIds
|
|
|
|
}
|
2021-05-10 12:16:57 +00:00
|
|
|
}
|
|
|
|
}
|