UndoManager.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import {
  2. TransformUtils,
  3. Command,
  4. Transform,
  5. UndoManagerObserver,
  6. } from "../internal";
  7. export class UndoManager {
  8. protected _redoStack: Array<UndoManager.Wrapped>;
  9. protected _undoStack: Array<UndoManager.Wrapped>;
  10. protected _transform: Transform;
  11. protected _observer: UndoManagerObserver;
  12. protected _transformStack(stack: Array<UndoManager.Wrapped>, command: Command): void {
  13. const transform = this._transform;
  14. const sizeof = stack.length - 1;
  15. for (let i = sizeof; i >= 0; i--) {
  16. const pair1 = transform.transfer(stack[i].redo, command);
  17. const pair2 = transform.transfer(stack[i].undo, pair1[1]);
  18. stack[i].redo = pair1[0];
  19. stack[i].undo = pair2[0];
  20. command = pair2[1];
  21. }
  22. }
  23. public constructor(transform: Transform) {
  24. this._redoStack = [];
  25. this._undoStack = [];
  26. this._transform = transform;
  27. this._observer = new UndoManagerObserver();
  28. }
  29. public transform(command: Command): void {
  30. this._transformStack(this._undoStack, command);
  31. this._transformStack(this._redoStack, command);
  32. }
  33. public canUndo(): boolean {
  34. return this._undoStack.length !== 0;
  35. }
  36. public canRedo(): boolean {
  37. return this._redoStack.length !== 0;
  38. }
  39. public addRedo(redo: Command, undo: Command): void
  40. public addRedo(wrapped: UndoManager.Wrapped): void
  41. public addRedo(...parameter: any): void {
  42. if (TransformUtils.hasLength(parameter, 1)) {
  43. const wrapped = parameter[0];
  44. this._redoStack.push(wrapped);
  45. this._observer.dispatchOnAddRedo(wrapped);
  46. return;
  47. }
  48. if (TransformUtils.hasLength(parameter, 2)) {
  49. const redo = parameter[0];
  50. const undo = parameter[1];
  51. const wrapped = { redo, undo };
  52. this._redoStack.push(wrapped);
  53. this._observer.dispatchOnAddRedo(wrapped);
  54. }
  55. }
  56. public addUndo(redo: Command, undo: Command): void
  57. public addUndo(wrapped: UndoManager.Wrapped): void
  58. public addUndo(...parameter: any): void {
  59. if (TransformUtils.hasLength(parameter, 1)) {
  60. const wrapped = parameter[0];
  61. this._undoStack.push(wrapped);
  62. this._observer.dispatchOnAddUndo(wrapped);
  63. return;
  64. }
  65. if (TransformUtils.hasLength(parameter, 2)) {
  66. const redo = parameter[0];
  67. const undo = parameter[1];
  68. const wrapped = { redo, undo };
  69. this._undoStack.push(wrapped);
  70. this._observer.dispatchOnAddUndo(wrapped);
  71. }
  72. }
  73. public performCommand(redo: Command, undo: Command): void
  74. public performCommand(wrapped: UndoManager.Wrapped): void
  75. public performCommand(...parameter: any): void {
  76. if (TransformUtils.hasLength(parameter, 1)) {
  77. const wrapped = parameter[0];
  78. this.addRedo(wrapped);
  79. return;
  80. }
  81. if (TransformUtils.hasLength(parameter, 2)) {
  82. const redo = parameter[0];
  83. const undo = parameter[1];
  84. const wrapped = { redo, undo };
  85. this.addRedo(wrapped);
  86. }
  87. }
  88. public performRedo(): void {
  89. if (this.canRedo()) {
  90. const wrapped = this._redoStack.pop();
  91. this.addUndo(wrapped);
  92. this._observer.dispatchOnRedo(wrapped);
  93. }
  94. }
  95. public performUndo(): void {
  96. if (this.canUndo()) {
  97. const wrapped = this._undoStack.pop();
  98. this.addRedo(wrapped);
  99. this._observer.dispatchOnUndo(wrapped);
  100. }
  101. }
  102. public getObserver(): UndoManagerObserver {
  103. return this._observer;
  104. }
  105. }
  106. export namespace UndoManager {
  107. export interface Wrapped{
  108. undo: Command,
  109. redo: Command,
  110. }
  111. }