8
0
Pārlūkot izejas kodu

Changed: extended comments in model.Range#_getTransformedByDocumentChange and refactored it a bit.

Szymon Cofalik 8 gadi atpakaļ
vecāks
revīzija
53c7661354
1 mainītis faili ar 41 papildinājumiem un 26 dzēšanām
  1. 41 26
      packages/ckeditor5-engine/src/model/range.js

+ 41 - 26
packages/ckeditor5-engine/src/model/range.js

@@ -447,40 +447,55 @@ export default class Range {
 	 * @returns {Array.<module:engine/model/range~Range>}
 	 */
 	_getTransformedByDocumentChange( type, deltaType, targetPosition, howMany, sourcePosition ) {
+		// IMPORTANT! Every special case added here has to be reflected in MarkerDelta transformations!
+		// Check /src/model/delta/basic-transformations.js.
 		if ( type == 'insert' ) {
 			return this._getTransformedByInsertion( targetPosition, howMany, false, false );
 		} else {
 			const ranges = this._getTransformedByMove( sourcePosition, targetPosition, howMany );
 
-			if ( deltaType == 'split' && this.containsPosition( sourcePosition ) ) {
-				// Special case for splitting element inside range.
-				// <p>f[ooba]r</p> -> <p>f[oo</p><p>ba]r</p>
-				ranges[ 0 ].end = ranges[ 1 ].end;
-				ranges.pop();
-			} else if ( deltaType == 'merge' && type == 'move' && this.isCollapsed && ranges[ 0 ].start.isEqual( sourcePosition ) ) {
-				// Special case when collapsed range is in merged element.
-				// <p>foo</p><p>[]bar{}</p> -> <p>foo[]bar{}</p>
-				ranges[ 0 ] = new Range( targetPosition.getShiftedBy( this.start.offset ) );
-			}
 			// Don't ask. Just debug.
 			// Like this: https://github.com/ckeditor/ckeditor5-engine/issues/841#issuecomment-282706488.
-			else if ( type == 'move' && deltaType == 'wrap' ) {
-				// <p>a[b</p><w></w><p>c]d</p> -> <w><p>a[b</p></w><p>c]d</p>
-				if ( this.containsPosition( targetPosition ) ) {
-					return [ new Range( ranges[ 2 ].start, ranges[ 1 ].end ) ];
-				}
-				// <p>a[b</p><p>c]d</p><w></w> -> <p>a[b</p><w><p>c]d</p></w>
-				else if ( this.containsPosition( sourcePosition ) ) {
+			//
+			// In following cases, in examples, the last step is the fix step.
+			// When there are multiple ranges in an example, ranges[] array indices are represented as follows:
+			// * [] is ranges[ 0 ],
+			// * {} is ranges[ 1 ],
+			// * () is ranges[ 2 ].
+			if ( type == 'move' ) {
+				if ( deltaType == 'split' && this.containsPosition( sourcePosition ) ) {
+					// Range contains a position where an element is split.
+					// <p>f[ooba]r</p> -> <p>f[ooba]r</p><p></p> -> <p>f[oo]</p><p>{ba}r</p> -> <p>f[oo</p><p>ba]r</p>
 					return [ new Range( ranges[ 0 ].start, ranges[ 1 ].end ) ];
-				}
-			} else if ( type == 'move' && deltaType == 'unwrap' ) {
-				// <w><p>a[b</p></w><p>c]d</p> -> <p>a[b</p><w></w><p>c]d</p>
-				if ( this.containsPosition( sourcePosition.getShiftedBy( howMany ) ) ) {
-					return [ new Range( ranges[ 1 ].start, ranges[ 0 ].end ) ];
-				}
-				// <p>a[b</p><w><p>c]d</p></w> -> <p>a[b</p><p>c]d</p><w></w>
-				else if ( this.containsPosition( sourcePosition ) ) {
-					return [ new Range( ranges[ 0 ].start, ranges[ 2 ].end ) ];
+				} else if ( deltaType == 'merge' && this.isCollapsed && ranges[ 0 ].start.isEqual( sourcePosition ) ) {
+					// Collapsed range is in merged element.
+					// Without fix, the range would end up in the graveyard, together with removed element.
+					// <p>foo</p><p>[]bar</p> -> <p>foobar</p><p>[]</p> -> <p>foobar</p> -> <p>foo[]bar</p>
+					return [ new Range( targetPosition.getShiftedBy( this.start.offset ) ) ];
+				} else if ( deltaType == 'wrap' ) {
+					// Range intersects (at the start) with wrapped element (<p>ab</p>).
+					// <p>a[b</p><p>c]d</p> -> <p>a[b</p><w></w><p>c]d</p> -> [<w>]<p>a(b</p>){</w><p>c}d</p> -> <w><p>a[b</p></w><p>c]d</p>
+					if ( this.containsPosition( targetPosition ) ) {
+						return [ new Range( ranges[ 2 ].start, ranges[ 1 ].end ) ];
+					}
+					// Range intersects (at the end) with wrapped element (<p>cd</p>).
+					// <p>a[b</p><p>c]d</p> -> <p>a[b</p><p>c]d</p><w></w> -> <p>a[b</p>]<w>{<p>c}d</p></w> -> <p>a[b</p><w><p>c]d</p></w>
+					else if ( this.containsPosition( sourcePosition ) ) {
+						return [ new Range( ranges[ 0 ].start, ranges[ 1 ].end ) ];
+					}
+				} else if ( deltaType == 'unwrap' ) {
+					// Range intersects (at the beginning) with unwrapped element (<w></w>).
+					// <w><p>a[b</p></w><p>c]d</p> -> <p>a{b</p>}<w>[</w><p>c]d</p> -> <p>a[b</p><w></w><p>c]d</p>
+					// <w></w> is removed in next operation, but the remove does not mess up ranges.
+					if ( this.containsPosition( sourcePosition.getShiftedBy( howMany ) ) ) {
+						return [ new Range( ranges[ 1 ].start, ranges[ 0 ].end ) ];
+					}
+					// Range intersects (at the end) with unwrapped element (<w></w>).
+					// <p>a[b</p><w><p>c]d</p></w> -> <p>a[b</p>](<p>c)d</p>{<w>}</w> -> <p>a[b</p><p>c]d</p><w></w>
+					// <w></w> is removed in next operation, but the remove does not mess up ranges.
+					else if ( this.containsPosition( sourcePosition ) ) {
+						return [ new Range( ranges[ 0 ].start, ranges[ 2 ].end ) ];
+					}
 				}
 			}