Răsfoiți Sursa

Fixed: `AttributeDelta` x `SplitDelta` transformation should not apply special in "undo mode".

Szymon Cofalik 8 ani în urmă
părinte
comite
abdf52228f

+ 24 - 20
packages/ckeditor5-engine/src/model/delta/basic-transformations.js

@@ -50,33 +50,36 @@ addTransformationCase( AttributeDelta, WeakInsertDelta, ( a, b, context ) => {
 
 // Add special case for AttributeDelta x SplitDelta transformation.
 addTransformationCase( AttributeDelta, SplitDelta, ( a, b, context ) => {
+	const undoMode = context.aWasUndone || context.bWasUndone;
 	const splitPosition = new Position( b.position.root, b.position.path.slice( 0, -1 ) );
 
 	const deltas = defaultTransform( a, b, context );
 
-	for ( const operation of a.operations ) {
-		// If a node that has been split has it's attribute updated, we should also update attribute of
-		// the node created during splitting.
-		if ( operation.range.containsPosition( splitPosition ) || operation.range.start.isEqual( splitPosition ) ) {
-			const additionalAttributeDelta = new AttributeDelta();
+	if ( !undoMode ) {
+		for ( const operation of a.operations ) {
+			// If a node that has been split has it's attribute updated, we should also update attribute of
+			// the node created during splitting.
+			if ( operation.range.containsPosition( splitPosition ) || operation.range.start.isEqual( splitPosition ) ) {
+				const additionalAttributeDelta = new AttributeDelta();
 
-			const rangeStart = splitPosition.getShiftedBy( 1 );
-			const rangeEnd = Position.createFromPosition( rangeStart );
-			rangeEnd.path.push( 0 );
+				const rangeStart = splitPosition.getShiftedBy( 1 );
+				const rangeEnd = Position.createFromPosition( rangeStart );
+				rangeEnd.path.push( 0 );
 
-			const oldValue = b._cloneOperation.nodes.getNode( 0 ).getAttribute( operation.key );
+				const oldValue = b._cloneOperation.nodes.getNode( 0 ).getAttribute( operation.key );
 
-			additionalAttributeDelta.addOperation( new AttributeOperation(
-				new Range( rangeStart, rangeEnd ),
-				operation.key,
-				oldValue === undefined ? null : oldValue,
-				operation.newValue,
-				0
-			) );
+				additionalAttributeDelta.addOperation( new AttributeOperation(
+					new Range( rangeStart, rangeEnd ),
+					operation.key,
+					oldValue === undefined ? null : oldValue,
+					operation.newValue,
+					0
+				) );
 
-			deltas.push( additionalAttributeDelta );
+				deltas.push( additionalAttributeDelta );
 
-			break;
+				break;
+			}
 		}
 	}
 
@@ -264,12 +267,13 @@ addTransformationCase( SplitDelta, WrapDelta, ( a, b, context ) => {
 } );
 
 // Add special case for SplitDelta x WrapDelta transformation.
-addTransformationCase( SplitDelta, AttributeDelta, ( a, b ) => {
+addTransformationCase( SplitDelta, AttributeDelta, ( a, b, context ) => {
 	a = a.clone();
 
+	const undoMode = context.aWasUndone || context.bWasUndone;
 	const splitPosition = new Position( a.position.root, a.position.path.slice( 0, -1 ) );
 
-	if ( a._cloneOperation instanceof InsertOperation ) {
+	if ( !undoMode && a._cloneOperation instanceof InsertOperation ) {
 		// If element to split had it's attribute changed, we have to reflect this change in an element
 		// that is in SplitDelta's InsertOperation.
 		for ( const operation of b.operations ) {

+ 51 - 0
packages/ckeditor5-engine/tests/model/delta/transform/attributedelta.js

@@ -15,7 +15,10 @@ import Range from '../../../../src/model/range';
 
 import AttributeDelta from '../../../../src/model/delta/attributedelta';
 import Delta from '../../../../src/model/delta/delta';
+import SplitDelta from '../../../../src/model/delta/splitdelta';
 import AttributeOperation from '../../../../src/model/operation/attributeoperation';
+import MoveOperation from '../../../../src/model/operation/moveoperation';
+import ReinsertOperation from '../../../../src/model/operation/reinsertoperation';
 import NoOperation from '../../../../src/model/operation/nooperation';
 
 import {
@@ -256,6 +259,54 @@ describe( 'transform', () => {
 					]
 				} );
 			} );
+
+			it( 'change attribute of split element that reinserts from graveyard', () => {
+				const gy = doc.graveyard;
+				const splitDelta = new SplitDelta();
+
+				splitDelta.operations[ 0 ] = new ReinsertOperation(
+					new Position( gy, [ 1 ] ),
+					1,
+					new Position( root, [ 2 ] ),
+					baseVersion
+				);
+
+				splitDelta.operations[ 1 ] = new MoveOperation(
+					new Position( root, [ 1, 4 ] ),
+					4,
+					new Position( root, [ 2, 0 ] ),
+					baseVersion
+				);
+
+				const attributeDelta = new AttributeDelta();
+
+				const range = new Range( new Position( root, [ 1 ] ), new Position( root, [ 1, 0 ] ) );
+
+				attributeDelta.addOperation( new AttributeOperation( range, 'key', 'oldValue', 'newValue', baseVersion ) );
+
+				// The split delta was undone.
+				context.bWasUndone = true;
+
+				const transformed = transform( attributeDelta, splitDelta, context );
+
+				baseVersion = attributeDelta.operations.length;
+				// We expect only one delta. Split delta should not affect attribute delta transformation. It was undone.
+				expect( transformed.length ).to.equal( 1 );
+
+				expectDelta( transformed[ 0 ], {
+					type: AttributeDelta,
+					operations: [
+						{
+							type: AttributeOperation,
+							range,
+							key: 'key',
+							oldValue: 'oldValue',
+							newValue: 'newValue',
+							baseVersion
+						}
+					]
+				} );
+			} );
 		} );
 
 		describe( 'AttributeDelta', () => {