Ver código fonte

Changed: context.insertBefore now also affects `InsertOperation` transformation.

Szymon Cofalik 8 anos atrás
pai
commit
a26531c90f

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/transform.js

@@ -411,7 +411,7 @@ function _setInsertBeforeContext( a, b, context ) {
 // Simply saying, if delta is going to be transformed by delta `b`, stickiness should not be taken into consideration
 // if delta `b` was already undone or if delta `b` is an undoing delta.
 //
-// Keep in mind that this problem only affects `MoveOperation` (and operations that derive from it).
+// This affects `MoveOperation` (and its derivatives).
 function _setForceNotSticky( b, context ) {
 	// If `b` delta is undoing or undone delta, stickiness should not be taken into consideration.
 	if ( context.document.history.isUndoingDelta( b ) || context.document.history.isUndoneDelta( b ) ) {

+ 12 - 3
packages/ckeditor5-engine/src/model/operation/transform.js

@@ -70,8 +70,11 @@ const ot = {
 			// Transformed operations are always new instances, not references to the original operations.
 			const transformed = a.clone();
 
+			// Check whether there is a forced order of nodes or use `context.isStrong` flag for conflict resolving.
+			const insertBefore = context.insertBefore === undefined ? !context.isStrong : context.insertBefore;
+
 			// Transform insert position by the other operation position.
-			transformed.position = transformed.position._getTransformedByInsertion( b.position, b.nodes.maxOffset, !context.isStrong );
+			transformed.position = transformed.position._getTransformedByInsertion( b.position, b.nodes.maxOffset, insertBefore );
 
 			return [ transformed ];
 		},
@@ -89,12 +92,15 @@ const ot = {
 		MoveOperation( a, b, context ) {
 			const transformed = a.clone();
 
+			// Check whether there is a forced order of nodes or use `context.isStrong` flag for conflict resolving.
+			const insertBefore = context.insertBefore === undefined ? !context.isStrong : context.insertBefore;
+
 			// Transform insert position by the other operation parameters.
 			transformed.position = a.position._getTransformedByMove(
 				b.sourcePosition,
 				b.targetPosition,
 				b.howMany,
-				!context.isStrong,
+				insertBefore,
 				b.isSticky && !context.forceNotSticky
 			);
 
@@ -338,10 +344,13 @@ const ot = {
 			let range = Range.createFromPositionAndShift( a.sourcePosition, a.howMany );
 			range = range._getTransformedByInsertion( b.position, b.nodes.maxOffset, false, a.isSticky && !context.forceNotSticky )[ 0 ];
 
+			// Check whether there is a forced order of nodes or use `context.isStrong` flag for conflict resolving.
+			const insertBefore = context.insertBefore === undefined ? !context.isStrong : context.insertBefore;
+
 			const result = new a.constructor(
 				range.start,
 				range.end.offset - range.start.offset,
-				a.targetPosition._getTransformedByInsertion( b.position, b.nodes.maxOffset, !context.isStrong ),
+				a.targetPosition._getTransformedByInsertion( b.position, b.nodes.maxOffset, insertBefore ),
 				a.baseVersion
 			);
 

+ 74 - 5
packages/ckeditor5-engine/tests/model/operation/transform.js

@@ -127,6 +127,33 @@ describe( 'transform', () => {
 				expectOperation( transOp[ 0 ], expected );
 			} );
 
+			it( 'target at same offset and context.insertBefore = true: no position update', () => {
+				const transformBy = new InsertOperation(
+					new Position( root, [ 0, 2, 2 ] ),
+					[ nodeC, nodeD ],
+					baseVersion
+				);
+
+				const transOp = transform( transformBy, { isStrong: false, insertBefore: false } );
+
+				expect( transOp.length ).to.equal( 1 );
+				expectOperation( transOp[ 0 ], expected );
+			} );
+
+			it( 'target at same offset and context.insertBefore = false: increment offset', () => {
+				const transformBy = new InsertOperation(
+					new Position( root, [ 0, 2, 2 ] ),
+					[ nodeC, nodeD ],
+					baseVersion
+				);
+
+				const transOp = transform( op, transformBy );
+				expected.position.offset += 2;
+
+				expect( transOp.length ).to.equal( 1 );
+				expectOperation( transOp[ 0 ], expected );
+			} );
+
 			it( 'target at offset after: no position update', () => {
 				const transformBy = new InsertOperation(
 					new Position( root, [ 0, 2, 3 ] ),
@@ -304,6 +331,35 @@ describe( 'transform', () => {
 				expectOperation( transOp[ 0 ], expected );
 			} );
 
+			it( 'target offset same as insert position offset and context.insertBefore = true: increment offset', () => {
+				const transformBy = new MoveOperation(
+					new Position( root, [ 1, 1 ] ),
+					2,
+					new Position( root, [ 0, 2, 2 ] ),
+					baseVersion
+				);
+
+				const transOp = transform( op, transformBy, { isStrong: true, insertBefore: true } );
+				expected.position.offset += 2;
+
+				expect( transOp.length ).to.equal( 1 );
+				expectOperation( transOp[ 0 ], expected );
+			} );
+
+			it( 'target offset same as insert position offset and context.insertBefore = false: no position update', () => {
+				const transformBy = new MoveOperation(
+					new Position( root, [ 1, 1 ] ),
+					2,
+					new Position( root, [ 0, 2, 2 ] ),
+					baseVersion
+				);
+
+				const transOp = transform( op, transformBy, { isStrong: false, insertBefore: false } );
+
+				expect( transOp.length ).to.equal( 1 );
+				expectOperation( transOp[ 0 ], expected );
+			} );
+
 			it( 'range is before node from insert position path: decrement index on path', () => {
 				const transformBy = new MoveOperation(
 					new Position( root, [ 0, 0 ] ),
@@ -1767,7 +1823,7 @@ describe( 'transform', () => {
 
 			it( 'target before node from move target position path: increment index on move target position path', () => {
 				const transformBy = new InsertOperation(
-					new Position( root, [ 3, 0 ] ),
+					new Position( root, [ 3, 3 ] ),
 					[ nodeA, nodeB ],
 					baseVersion
 				);
@@ -1821,16 +1877,29 @@ describe( 'transform', () => {
 				expectOperation( transOp[ 0 ], expected );
 			} );
 
-			it( 'target offset same as move target offset: increment target offset', () => {
+			it( 'target offset same as move target offset and context.insertBefore = true: increment target offset', () => {
 				const transformBy = new InsertOperation(
-					new Position( root, [ 3, 3 ] ),
+					new Position( root, [ 3, 3, 3 ] ),
 					[ nodeA, nodeB ],
 					baseVersion
 				);
 
-				const transOp = transform( op, transformBy );
+				const transOp = transform( op, transformBy, { isStrong: true, insertBefore: true } );
 
-				expected.targetPosition.path[ 1 ] += 2;
+				expected.targetPosition.offset += 2;
+
+				expect( transOp.length ).to.equal( 1 );
+				expectOperation( transOp[ 0 ], expected );
+			} );
+
+			it( 'target offset same as move target offset and context.insertBefore = false: no operation update', () => {
+				const transformBy = new InsertOperation(
+					new Position( root, [ 3, 3, 3 ] ),
+					[ nodeA, nodeB ],
+					baseVersion
+				);
+
+				const transOp = transform( op, transformBy, { isStrong: false, insertBefore: false } );
 
 				expect( transOp.length ).to.equal( 1 );
 				expectOperation( transOp[ 0 ], expected );