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.6KB

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