8
0

undo.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /**
  6. * @module undo/undo
  7. */
  8. import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
  9. import UndoEditing from './undoediting';
  10. import UndoUI from './undoui';
  11. /**
  12. * The undo feature.
  13. *
  14. * This is a "glue" plugin which loads the {@link module:undo/undoediting~UndoEditing undo editing feature}
  15. * and {@link module:undo/undoui~UndoUI undo UI feature}.
  16. *
  17. * Below is the explanation of the undo mechanism working together with {@link module:engine/model/history~History History}:
  18. *
  19. * Whenever a {@link module:engine/model/operation/operation~Operation operation} is applied to the
  20. * {@link module:engine/model/document~Document document}, it is saved to `History` as is.
  21. * The {@link module:engine/model/batch~Batch batch} that owns that operation is also saved, in
  22. * {@link module:undo/undocommand~UndoCommand}, together with the selection that was present in the document before the
  23. * operation was applied. A batch is saved instead of the operation because changes are undone batch-by-batch, not operation-by-operation
  24. * and a batch is seen as one undo step.
  25. *
  26. * After some changes happen to the document, the `History` and `UndoCommand` stack can be represented as follows:
  27. *
  28. * History Undo stack
  29. * ============== ==================================
  30. * [operation A1] [batch A]
  31. * [operation B1] [batch B]
  32. * [operation B2] [batch C]
  33. * [operation C1]
  34. * [operation C2]
  35. * [operation B3]
  36. * [operation C3]
  37. *
  38. * Where operations starting with the same letter are from same batch.
  39. *
  40. * Undoing a batch means that a set of operations which will reverse the effects of that batch needs to be generated.
  41. * For example, if a batch added several letters, undoing the batch should remove them. It is important to apply undoing
  42. * operations in the reversed order, so if a batch has operation `X`, `Y`, `Z`, reversed operations `Zr`, `Yr` and `Xr`
  43. * need to be applied. Otherwise reversed operation `Xr` would operate on a wrong document state, because operation `X`
  44. * does not know that operations `Y` and `Z` happened.
  45. *
  46. * After operations from an undone batch got {@link module:engine/model/operation/operation~Operation#getReversed reversed},
  47. * one needs to make sure if they are ready to be applied. In the scenario above, operation `C3` is the last operation and `C3r`
  48. * bases on up-to-date document state, so it can be applied to the document.
  49. *
  50. * History Undo stack
  51. * ================= ==================================
  52. * [ operation A1 ] [ batch A ]
  53. * [ operation B1 ] [ batch B ]
  54. * [ operation B2 ] [ processing undoing batch C ]
  55. * [ operation C1 ]
  56. * [ operation C2 ]
  57. * [ operation B3 ]
  58. * [ operation C3 ]
  59. * [ operation C3r ]
  60. *
  61. * Next is operation `C2`, reversed to `C2r`. `C2r` bases on `C2`, so it bases on the wrong document state. It needs to be
  62. * transformed by operations from history that happened after it, so it "knows" about them. Let us assume that `C2' = C2r * B3 * C3 * C3r`,
  63. * where `*` means "transformed by". Rest of operations from that batch are processed in the same fashion.
  64. *
  65. * History Undo stack Redo stack
  66. * ================= ================================== ==================================
  67. * [ operation A1 ] [ batch A ] [ batch Cr ]
  68. * [ operation B1 ] [ batch B ]
  69. * [ operation B2 ]
  70. * [ operation C1 ]
  71. * [ operation C2 ]
  72. * [ operation B3 ]
  73. * [ operation C3 ]
  74. * [ operation C3r ]
  75. * [ operation C2' ]
  76. * [ operation C1' ]
  77. *
  78. * Selective undo works on the same basis, however, instead of undoing the last batch in the undo stack, any batch can be undone.
  79. * The same algorithm applies: operations from a batch (i.e. `A1`) are reversed and then transformed by operations stored in history.
  80. *
  81. * Redo also is very similar to undo. It has its own stack that is filled with undoing (reversed batches). Operations from
  82. * batch that is re-done are reversed-back, transformed in proper order and applied to the document.
  83. *
  84. * History Undo stack Redo stack
  85. * ================= ================================== ==================================
  86. * [ operation A1 ] [ batch A ]
  87. * [ operation B1 ] [ batch B ]
  88. * [ operation B2 ] [ batch Crr ]
  89. * [ operation C1 ]
  90. * [ operation C2 ]
  91. * [ operation B3 ]
  92. * [ operation C3 ]
  93. * [ operation C3r ]
  94. * [ operation C2' ]
  95. * [ operation C1' ]
  96. * [ operation C1'r]
  97. * [ operation C2'r]
  98. * [ operation C3rr]
  99. *
  100. * @extends module:core/plugin~Plugin
  101. */
  102. export default class Undo extends Plugin {
  103. /**
  104. * @inheritDoc
  105. */
  106. static get requires() {
  107. return [ UndoEditing, UndoUI ];
  108. }
  109. /**
  110. * @inheritDoc
  111. */
  112. static get pluginName() {
  113. return 'Undo';
  114. }
  115. }