8
0
Szymon Cofalik 8 лет назад
Родитель
Сommit
7a07e15a3f

+ 7 - 10
packages/ckeditor5-undo/src/basecommand.js

@@ -79,7 +79,7 @@ export default class BaseCommand extends Command {
 	 * @protected
 	 * @param {Array.<module:engine/model/range~Range>} ranges Ranges to be restored.
 	 * @param {Boolean} isBackward A flag describing whether the restored range was selected forward or backward.
-	 * @param {Array.<module:engine/model/delta~Delta>} deltas Deltas which has been applied since selection has been stored.
+	 * @param {Array.<module:engine/model/delta/delta~Delta>} deltas Deltas which has been applied since selection has been stored.
 	 */
 	_restoreSelection( ranges, isBackward, deltas ) {
 		const document = this.editor.document;
@@ -113,7 +113,7 @@ export default class BaseCommand extends Command {
 
 	/**
 	 * Undoes a batch by reversing that batch, transforming reversed batch and finally applying it.
-	 * This is a helper method for {@link #_doExecute}.
+	 * This is a helper method for {@link #execute}.
 	 *
 	 * @protected
 	 * @param {module:engine/model/batch~Batch} batchToUndo The batch to be undone.
@@ -135,13 +135,12 @@ export default class BaseCommand extends Command {
 			// deltas, so we need arrays to handle them. To simplify algorithms, it is better to always operate on arrays.
 			const nextBaseVersion = deltaToUndo.baseVersion + deltaToUndo.operations.length;
 
-			// 2. Reverse delta from the history.
-			// let reversedDelta = [ deltaToUndo.getReversed() ];
+			// Reverse delta from the history.
 			const historyDeltas = Array.from( document.history.getDeltas( nextBaseVersion ) );
 			const transformedSets = document.transformDeltas( [ deltaToUndo.getReversed() ], historyDeltas, true );
 			const reversedDeltas = transformedSets.deltasA;
 
-			// 4. After reversed delta has been transformed by all history deltas, apply it.
+			// After reversed delta has been transformed by all history deltas, apply it.
 			for ( const delta of reversedDeltas ) {
 				// Fix base version.
 				delta.baseVersion = document.version;
@@ -162,17 +161,14 @@ export default class BaseCommand extends Command {
 	}
 }
 
-// Transforms given range `range` by deltas from `document` history, starting from a delta with given `baseVersion`.
+// Transforms given range `range` by given `deltas`.
 // Returns an array containing one or more ranges, which are result of the transformation.
 function transformSelectionRange( range, deltas ) {
-	// The range will be transformed by history deltas that happened after the selection got stored.
-	// Note, that at this point, the document history is already updated by undo command execution. We will
-	// not transform the range by deltas that got undone or their reversing counterparts.
 	const transformed = transformRangesByDeltas( [ range ], deltas );
 
 	// After `range` got transformed, we have an array of ranges. Some of those
 	// ranges may be "touching" -- they can be next to each other and could be merged.
-	// First, we have to sort those ranges because they don't have to be in an order.
+	// First, we have to sort those ranges to assure that they are in order.
 	transformed.sort( ( a, b ) => a.start.isBefore( b.start ) ? -1 : 1 );
 
 	// Then, we check if two consecutive ranges are touching.
@@ -181,6 +177,7 @@ function transformSelectionRange( range, deltas ) {
 		const b = transformed[ i ];
 
 		if ( a.end.isTouching( b.start ) ) {
+			// And join them together if they are.
 			a.end = b.end;
 			transformed.splice( i, 1 );
 			i--;

+ 3 - 4
packages/ckeditor5-undo/src/redocommand.js

@@ -12,11 +12,10 @@ import BaseCommand from './basecommand';
 /**
  * The redo command stores {@link module:engine/model/batch~Batch batches} that were used to undo a batch by
  * {@link module:undo/undocommand~UndoCommand}. It is able to redo a previously undone batch by reversing the undoing
- * batches created by `UndoCommand`. The reversed batch is also transformed by batches from
- * {@link module:engine/model/document~Document#history history} that happened after it and are not other redo batches.
+ * batches created by `UndoCommand`. The reversed batch is transformed by all the batches from
+ * {@link module:engine/model/document~Document#history history} that happened after the reversed undo batch.
  *
- * The redo command also takes care of restoring the {@link module:engine/model/document~Document#selection document selection}
- * to the state before an undone batch was applied.
+ * The redo command also takes care of restoring the {@link module:engine/model/document~Document#selection document selection}.
  *
  * @extends module:undo/basecommand~BaseCommand
  */

+ 46 - 72
packages/ckeditor5-undo/src/undo.js

@@ -30,9 +30,9 @@ import redoIcon from '../theme/icons/redo.svg';
  *
  *		  History                           Undo stack
  *		===========             ==================================
- *		[delta A1]              [batch A with selection before A1]
- *		[delta B1]              [batch B with selection before B1]
- *		[delta B2]              [batch C with selection before C1]
+ *		[delta A1]                          [batch A]
+ *		[delta B1]                          [batch B]
+ *		[delta B2]                          [batch C]
  *		[delta C1]
  *		[delta C2]
  *		[delta B3]
@@ -50,80 +50,54 @@ import redoIcon from '../theme/icons/redo.svg';
  * bases on up-to-date document state, so it can be applied to the document.
  *
  *		  History                           Undo stack
- *		===========             ==================================
- *		[delta A1 ]             [batch A with selection before A1]
- *		[delta B1 ]             [batch B with selection before B1]
- *		[delta B2 ]             [   processing undoing batch C   ]
- *		[delta C1 ]
- *		[delta C2 ]
- *		[delta B3 ]
- *		[delta C3 ]
- *		[delta C3r]
+ *		=============             ==================================
+ *		[ delta A1  ]                      [  batch A  ]
+ *		[ delta B1  ]                      [  batch B  ]
+ *		[ delta B2  ]             [   processing undoing batch C   ]
+ *		[ delta C1  ]
+ *		[ delta C2  ]
+ *		[ delta B3  ]
+ *		[ delta C3  ]
+ *		[ delta C3r ]
  *
  * Next is delta `C2`, reversed to `C2r`. `C2r` bases on `C2`, so it bases on the wrong document state. It needs to be
  * transformed by deltas from history that happened after it, so it "knows" about them. Let us assume that `C2' = C2r * B3 * C3 * C3r`,
- * where `*` means "transformed by". As can be seen, `C2r` is transformed by a delta which is undone afterwards anyway.
- * This brings two problems: lower effectiveness (obvious) and incorrect results. Bad results come from the fact that
- * operational transformation algorithms assume there is no connection between two transformed operations when resolving
- * conflicts, which is true for example for collaborative editing, but is not true for the undo algorithm.
- *
- * To prevent both problems, `History` introduces an API to {@link module:engine/model/history~History#removeDelta remove}
- * deltas from history. It is used to remove undone and undoing deltas after they are applied. It feels right &mdash; since when a
- * delta is undone or reversed, it is "removed" and there should be no sign of it in the history (fig. 1).
- *
- * Notes:
- *
- * * `---` symbolizes a removed delta.
- * * `'` symbolizes a reversed delta that was later transformed.
- *
- *		History (fig. 1)            History (fig. 2)            History (fig. 3)
- *		================            ================            ================
- *		   [delta A1]                  [delta A1]                  [delta A1]
- *		   [delta B1]                  [delta B1]                  [delta B1]
- *		   [delta B2]                  [delta B2]                  [delta B2]
- *		   [delta C1]                  [delta C1]                  [---C1---]
- *		   [delta C2]                  [---C2---]                  [---C2---]
- *		   [delta B3]                  [delta B3]                  [delta B3]
- *		   [---C3---]                  [---C3---]                  [---C3---]
- *		   [---C3r--]                  [---C3r--]                  [---C3r--]
- *		                               [---C2'--]                  [---C2'--]
- *		                                                           [---C1'--]
- *
- * `C2r` can now be transformed only by `B3` and both `C2'` and `C2` can be removed (fig. 2). Same with `C1` (fig. 3).
- *
- * But what about that selection? For batch `C`, undo feature remembers the selection just before `C1` was applied. It can be
- * visualized between delta `B2` and `B3` (see fig. 3). As can be seen, some operations were applied to the document since the selection
- * state was remembered. Setting the document selection as it was remembered would be incorrect. It feels natural that
- * the selection state should also be transformed by deltas from history. The same pattern applies as with transforming deltas &mdash;
- * ranges should not be transformed by undone and undoing deltas. Thankfully, those deltas are already removed from history.
- *
- * Unfortunately, a problem appears with delta `B3`. It still remembers the context of deltas `C2` and `C1` on which it bases.
- * It is an obvious error &mdash; transforming by that delta would lead to incorrect results or "repeating" history would
- * produce a different document than the actual one.
- *
- * To prevent this situation, `B3` needs to also be {@link module:engine/model/history~History#updateDelta updated} in history.
- * It should be kept in a state that "does not remember" deltas that were removed from history. It is easily
- * achieved while transforming the reversed delta. For example, when `C2r` is transformed by `B3`, at the same time `B3` is
- * transformed by `C2r`. Transforming `B3` that remembers `C2` by a delta reversing `C2` effectively makes `B3` "forget" about `C2`.
- * By doing these transformations you effectively make `B3` base on `B2` which is the correct state of history (fig. 4).
- *
- *		     History (fig. 4)                         History (fig. 5)
- *		===========================            ===============================
- *		        [delta A1]                               [---A1---]
- *		        [delta B1]                         [delta B1 "without A1"]
- *		        [delta B2]                         [delta B2 "without A1"]
- *		        [---C1---]                               [---C1---]
- *		        [---C2---]                               [---C2---]
- *		[delta B3 "without C2, C1"]            [delta B3 "without C2, C1, A1"]
- *		        [---C3---]                               [---C3---]
- *		        [---C3r--]                               [---C3r--]
- *		        [---C2'--]                               [---C2'--]
- *		        [---C1'--]                               [---C1'--]
- *		                                                 [---A1'--]
+ * where `*` means "transformed by". Rest of deltas from that batch are processed in the same fashion.
+ *
+ *		  History                           Undo stack                                     Redo stack
+ *		=============             ==================================             ==================================
+ *		[ delta A1  ]                      [  batch A  ]                                  [ batch Cr ]
+ *		[ delta B1  ]                      [  batch B  ]
+ *		[ delta B2  ]
+ *		[ delta C1  ]
+ *		[ delta C2  ]
+ *		[ delta B3  ]
+ *		[ delta C3  ]
+ *		[ delta C3r ]
+ *		[ delta C2' ]
+ *		[ delta C1' ]
  *
  * Selective undo works on the same basis, however, instead of undoing the last batch in the undo stack, any batch can be undone.
- * The same algorithm applies: deltas from a batch (i.e. `A1`) are reversed and then transformed by deltas stored in history,
- * simultaneously updating them. Then deltas are applied to the document and removed from history (fig. 5).
+ * The same algorithm applies: deltas from a batch (i.e. `A1`) are reversed and then transformed by deltas stored in history.
+ *
+ * Redo also is very similar to undo. It has its own stack that is filled with undoing (reversed batches). Deltas from
+ * batch that is re-done are reversed-back, transformed in proper order and applied to the document.
+ *
+ *		  History                           Undo stack                                     Redo stack
+ *		=============             ==================================             ==================================
+ *		[ delta A1  ]                      [  batch A  ]
+ *		[ delta B1  ]                      [  batch B  ]
+ *		[ delta B2  ]                      [ batch Crr ]
+ *		[ delta C1  ]
+ *		[ delta C2  ]
+ *		[ delta B3  ]
+ *		[ delta C3  ]
+ *		[ delta C3r ]
+ *		[ delta C2' ]
+ *		[ delta C1' ]
+ *		[ delta C1'r]
+ *		[ delta C2'r]
+ *		[ delta C3rr]
  *
  * @extends module:core/plugin~Plugin
  */

+ 2 - 3
packages/ckeditor5-undo/src/undocommand.js

@@ -12,10 +12,9 @@ import BaseCommand from './basecommand';
 /**
  * The undo command stores {@link module:engine/model/batch~Batch batches} applied to the
  * {@link module:engine/model/document~Document document} and is able to undo a batch by reversing it and transforming by
- * other batches from {@link module:engine/model/document~Document#history history} that happened after the reversed batch.
+ * batches from {@link module:engine/model/document~Document#history history} that happened after the reversed batch.
  *
- * The undo command also takes care of restoring the {@link module:engine/model/document~Document#selection document selection}
- * to the state before the undone batch was applied.
+ * The undo command also takes care of restoring the {@link module:engine/model/document~Document#selection document selection}.
  *
  * @extends module:undo/basecommand~BaseCommand
  */