You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

command.ts 2.5KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import { Data } from 'types'
  2. import tld from 'utils/tld'
  3. /* ------------------ Command Class ----------------- */
  4. export type CommandFn<T> = (data: T, initial?: boolean) => void
  5. /**
  6. * A command makes changes to some applicate state. Every command has an "undo"
  7. * method to reverse its changes. The apps history is a series of commands.
  8. */
  9. export class BaseCommand<T extends any> {
  10. timestamp = Date.now()
  11. name: string
  12. category: string
  13. private undoFn: CommandFn<T>
  14. private doFn: CommandFn<T>
  15. protected restoreBeforeSelectionState: (data: T) => void
  16. protected restoreAfterSelectionState: (data: T) => void
  17. protected saveSelectionState: (data: T) => (data: T) => void
  18. protected manualSelection: boolean
  19. constructor(options: {
  20. do: CommandFn<T>
  21. undo: CommandFn<T>
  22. name: string
  23. category: string
  24. manualSelection?: boolean
  25. }) {
  26. this.name = options.name
  27. this.category = options.category
  28. this.doFn = options.do
  29. this.undoFn = options.undo
  30. this.manualSelection = options.manualSelection || false
  31. this.restoreBeforeSelectionState = () => () => {
  32. null
  33. }
  34. this.restoreAfterSelectionState = () => () => {
  35. null
  36. }
  37. }
  38. undo = (data: T): void => {
  39. if (this.manualSelection) {
  40. this.undoFn(data)
  41. return
  42. }
  43. // We need to set the selection state to what it was before we after we did the command
  44. this.restoreAfterSelectionState(data)
  45. this.undoFn(data)
  46. this.restoreBeforeSelectionState(data)
  47. }
  48. redo = (data: T, initial = false): void => {
  49. if (this.manualSelection) {
  50. this.doFn(data, initial)
  51. return
  52. }
  53. if (!initial) {
  54. this.restoreBeforeSelectionState(data)
  55. }
  56. // We need to set the selection state to what it was before we did the command
  57. this.doFn(data, initial)
  58. if (initial) {
  59. this.restoreAfterSelectionState = this.saveSelectionState(data)
  60. }
  61. }
  62. }
  63. /* ---------------- Project Specific ---------------- */
  64. /**
  65. * A subclass of BaseCommand that sends events to our state. In our case, we want our actions
  66. * to mutate the state's data. Actions do not effect the "active states" in
  67. * the app.
  68. */
  69. export default class Command extends BaseCommand<Data> {
  70. saveSelectionState = (data: Data): ((next: Data) => void) => {
  71. const { currentPageId } = data
  72. const selectedIds = [...tld.getSelectedIds(data)]
  73. return (next: Data) => {
  74. next.currentPageId = currentPageId
  75. next.hoveredId = undefined
  76. next.pointedId = undefined
  77. tld.setSelectedIds(next, selectedIds)
  78. }
  79. }
  80. }