Browse Source

Merge pull request #853 from ckeditor/t/852

Fix: Collapsed model.Range no longer sticks to it's neighbour node when that node is moved. Closes #852.
Piotr Jasiun 8 năm trước cách đây
mục cha
commit
a0949a7e2b

+ 9 - 3
packages/ckeditor5-engine/src/model/range.js

@@ -453,8 +453,14 @@ export default class Range {
 			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 ) );
 			}
 
 			return ranges;
@@ -534,7 +540,7 @@ export default class Range {
 	 */
 	_getTransformedByMove( sourcePosition, targetPosition, howMany ) {
 		if ( this.isCollapsed ) {
-			const newPos = this.start._getTransformedByMove( sourcePosition, targetPosition, howMany, true, true );
+			const newPos = this.start._getTransformedByMove( sourcePosition, targetPosition, howMany, true, false );
 
 			return [ new Range( newPos ) ];
 		}
@@ -549,7 +555,7 @@ export default class Range {
 		const common = this.getIntersection( moveRange );
 
 		if ( differenceSet.length == 1 ) {
-			// `moveRange` and this range intersects.
+			// `moveRange` and this range may intersect.
 			difference = new Range(
 				differenceSet[ 0 ].start._getTransformedByDeletion( sourcePosition, howMany ),
 				differenceSet[ 0 ].end._getTransformedByDeletion( sourcePosition, howMany )
@@ -560,7 +566,7 @@ export default class Range {
 				this.start,
 				this.end._getTransformedByDeletion( sourcePosition, howMany )
 			);
-		} // else, `moveRange` wholly contains this range.
+		} // else, `moveRange` contains this range.
 
 		const insertPosition = targetPosition._getTransformedByDeletion( sourcePosition, howMany );
 

+ 28 - 7
packages/ckeditor5-engine/tests/model/range.js

@@ -18,7 +18,8 @@ import {
 	getMoveDelta,
 	getRemoveDelta,
 	getRenameDelta,
-	getSplitDelta
+	getSplitDelta,
+	getMergeDelta
 } from '../../tests/model/delta/transform/_utils/utils';
 
 describe( 'Range', () => {
@@ -593,20 +594,22 @@ describe( 'Range', () => {
 			expect( transformed[ 0 ].end.path ).to.deep.equal( [ 4, 7 ] );
 		} );
 
-		it( 'should stick to moved range, if the transformed range is collapsed #1', () => {
+		it( 'should not stick to moved range, if the transformed range is collapsed #1', () => {
 			const range = new Range( new Position( root, [ 3, 2 ] ), new Position( root, [ 3, 2 ] ) );
 			const transformed = range._getTransformedByMove( new Position( root, [ 3, 0 ] ), new Position( root, [ 6 ] ), 2 );
 
-			expect( transformed[ 0 ].start.path ).to.deep.equal( [ 8 ] );
-			expect( transformed[ 0 ].end.path ).to.deep.equal( [ 8 ] );
+			expect( transformed.length ).to.equal( 1 );
+			expect( transformed[ 0 ].start.path ).to.deep.equal( [ 3, 0 ] );
+			expect( transformed[ 0 ].end.path ).to.deep.equal( [ 3, 0 ] );
 		} );
 
-		it( 'should stick to moved range, if the transformed range is collapsed #2', () => {
+		it( 'should not stick to moved range, if the transformed range is collapsed #2', () => {
 			const range = new Range( new Position( root, [ 3, 2 ] ), new Position( root, [ 3, 2 ] ) );
 			const transformed = range._getTransformedByMove( new Position( root, [ 3, 2 ] ), new Position( root, [ 6 ] ), 2 );
 
-			expect( transformed[ 0 ].start.path ).to.deep.equal( [ 6 ] );
-			expect( transformed[ 0 ].end.path ).to.deep.equal( [ 6 ] );
+			expect( transformed.length ).to.equal( 1 );
+			expect( transformed[ 0 ].start.path ).to.deep.equal( [ 3, 2 ] );
+			expect( transformed[ 0 ].end.path ).to.deep.equal( [ 3, 2 ] );
 		} );
 	} );
 
@@ -836,6 +839,24 @@ describe( 'Range', () => {
 				expect( transformed[ 0 ].start.path ).to.deep.equal( [ 0, 2 ] );
 				expect( transformed[ 0 ].end.path ).to.deep.equal( [ 1, 1 ] );
 			} );
+
+			describe( 'by MergeDelta', () => {
+				it( 'merge element with collapsed range', () => {
+					root.removeChildren( root.childCount );
+					root.appendChildren( [ new Element( 'p', null, new Text( 'foo' ) ), new Element( 'p', null, new Text( 'bar' ) ) ] );
+
+					range.start = new Position( root, [ 1, 0 ] );
+					range.end = new Position( root, [ 1, 0 ] );
+
+					const delta = getMergeDelta( new Position( root, [ 1 ] ), 3, 3, 1 );
+
+					const transformed = range.getTransformedByDelta( delta );
+
+					expect( transformed.length ).to.equal( 1 );
+					expect( transformed[ 0 ].start.path ).to.deep.equal( [ 0, 3 ] );
+					expect( transformed[ 0 ].end.path ).to.deep.equal( [ 0, 3 ] );
+				} );
+			} );
 		} );
 	} );