|
@@ -0,0 +1,351 @@
|
|
|
|
|
+/**
|
|
|
|
|
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
|
|
|
|
|
+ * For licensing, see LICENSE.md.
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+/* bender-tags: model, operation */
|
|
|
|
|
+
|
|
|
|
|
+import transformations from 'ckeditor5/engine/model/delta/basic-transformations.js';
|
|
|
|
|
+/*jshint unused: false*/
|
|
|
|
|
+
|
|
|
|
|
+import { transformDeltaSets } from 'ckeditor5/engine/model/delta/transform.js';
|
|
|
|
|
+
|
|
|
|
|
+import Document from 'ckeditor5/engine/model/document.js';
|
|
|
|
|
+import Element from 'ckeditor5/engine/model/element.js';
|
|
|
|
|
+import Text from 'ckeditor5/engine/model/text.js';
|
|
|
|
|
+import Position from 'ckeditor5/engine/model/position.js';
|
|
|
|
|
+import Range from 'ckeditor5/engine/model/range.js';
|
|
|
|
|
+
|
|
|
|
|
+import Delta from 'ckeditor5/engine/model/delta/delta.js';
|
|
|
|
|
+import InsertDelta from 'ckeditor5/engine/model/delta/insertdelta.js';
|
|
|
|
|
+import RemoveDelta from 'ckeditor5/engine/model/delta/removedelta.js';
|
|
|
|
|
+import SplitDelta from 'ckeditor5/engine/model/delta/splitdelta.js';
|
|
|
|
|
+
|
|
|
|
|
+import NoOperation from 'ckeditor5/engine/model/operation/nooperation.js';
|
|
|
|
|
+import MoveOperation from 'ckeditor5/engine/model/operation/moveoperation.js';
|
|
|
|
|
+import RemoveOperation from 'ckeditor5/engine/model/operation/removeoperation.js';
|
|
|
|
|
+import InsertOperation from 'ckeditor5/engine/model/operation/insertoperation.js';
|
|
|
|
|
+
|
|
|
|
|
+import {
|
|
|
|
|
+ expectDelta,
|
|
|
|
|
+ getInsertDelta,
|
|
|
|
|
+ getSplitDelta,
|
|
|
|
|
+ getRemoveDelta
|
|
|
|
|
+} from 'tests/engine/model/delta/transform/_utils/utils.js';
|
|
|
|
|
+
|
|
|
|
|
+describe( 'transform', () => {
|
|
|
|
|
+ let doc, root, gy, baseVersion;
|
|
|
|
|
+
|
|
|
|
|
+ beforeEach( () => {
|
|
|
|
|
+ doc = new Document();
|
|
|
|
|
+ root = doc.createRoot();
|
|
|
|
|
+
|
|
|
|
|
+ root.appendChildren( new Element( 'p', null, new Text( 'foobar' ) ) );
|
|
|
|
|
+
|
|
|
|
|
+ gy = doc.graveyard;
|
|
|
|
|
+ baseVersion = doc.version;
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ describe( 'transformDeltaSets', () => {
|
|
|
|
|
+ it( 'should transform two deltas', () => {
|
|
|
|
|
+ const insertDelta = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'xxx' ), baseVersion );
|
|
|
|
|
+ const removeDelta = getRemoveDelta( new Position( root, [ 0, 0 ] ), 2, baseVersion );
|
|
|
|
|
+
|
|
|
|
|
+ const { deltasA, deltasB } = transformDeltaSets( [ insertDelta ], [ removeDelta ] );
|
|
|
|
|
+
|
|
|
|
|
+ expect( deltasA.length ).to.equal( 1 );
|
|
|
|
|
+ expect( deltasB.length ).to.equal( 1 );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasA[ 0 ], {
|
|
|
|
|
+ type: InsertDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: InsertOperation,
|
|
|
|
|
+ position: new Position( root, [ 0, 2 ] ),
|
|
|
|
|
+ baseVersion: 1
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasB[ 0 ], {
|
|
|
|
|
+ type: RemoveDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: RemoveOperation,
|
|
|
|
|
+ sourcePosition: new Position( root, [ 0, 0 ] ),
|
|
|
|
|
+ howMany: 2,
|
|
|
|
|
+ baseVersion: 1
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ it( 'should transform two deltas - reverse', () => {
|
|
|
|
|
+ const insertDelta = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'xxx' ), baseVersion );
|
|
|
|
|
+ const removeDelta = getRemoveDelta( new Position( root, [ 0, 0 ] ), 2, baseVersion );
|
|
|
|
|
+
|
|
|
|
|
+ const { deltasA, deltasB } = transformDeltaSets( [ removeDelta ], [ insertDelta ] );
|
|
|
|
|
+
|
|
|
|
|
+ expect( deltasA.length ).to.equal( 1 );
|
|
|
|
|
+ expect( deltasB.length ).to.equal( 1 );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasA[ 0 ], {
|
|
|
|
|
+ type: RemoveDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: RemoveOperation,
|
|
|
|
|
+ sourcePosition: new Position( root, [ 0, 0 ] ),
|
|
|
|
|
+ howMany: 2,
|
|
|
|
|
+ baseVersion: 1
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasB[ 0 ], {
|
|
|
|
|
+ type: InsertDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: InsertOperation,
|
|
|
|
|
+ position: new Position( root, [ 0, 2 ] ),
|
|
|
|
|
+ baseVersion: 1
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ it( 'should transform two arrays of deltas', () => {
|
|
|
|
|
+ const splitDelta = getSplitDelta( new Position( root, [ 0, 3 ] ), new Element( 'p' ), 3, baseVersion );
|
|
|
|
|
+ const insertDeltaX = getInsertDelta( new Position( root, [ 0, 3 ] ), new Text( 'xxx' ), baseVersion + 2 );
|
|
|
|
|
+
|
|
|
|
|
+ const removeDelta = getRemoveDelta( new Position( root, [ 0, 2 ] ), 2, baseVersion );
|
|
|
|
|
+ const insertDeltaY = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'yyy' ), baseVersion + 1 );
|
|
|
|
|
+
|
|
|
|
|
+ const { deltasA, deltasB } = transformDeltaSets( [ splitDelta, insertDeltaX ], [ removeDelta, insertDeltaY ], true );
|
|
|
|
|
+
|
|
|
|
|
+ expect( deltasA.length ).to.equal( 3 );
|
|
|
|
|
+ expect( deltasB.length ).to.equal( 2 );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasA[ 0 ], {
|
|
|
|
|
+ type: SplitDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: InsertOperation,
|
|
|
|
|
+ position: new Position( root, [ 1 ] ),
|
|
|
|
|
+ baseVersion: 2
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ type: MoveOperation,
|
|
|
|
|
+ sourcePosition: new Position( root, [ 0, 2 ] ),
|
|
|
|
|
+ howMany: 5,
|
|
|
|
|
+ targetPosition: new Position( root, [ 1, 0 ] ),
|
|
|
|
|
+ baseVersion: 3
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasA[ 1 ], {
|
|
|
|
|
+ type: InsertDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: InsertOperation,
|
|
|
|
|
+ position: new Position( root, [ 0, 2 ] ),
|
|
|
|
|
+ baseVersion: 4
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasA[ 2 ], {
|
|
|
|
|
+ type: Delta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: NoOperation,
|
|
|
|
|
+ baseVersion: 5
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasB[ 0 ], {
|
|
|
|
|
+ type: RemoveDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: RemoveOperation,
|
|
|
|
|
+ sourcePosition: new Position( root, [ 1, 0 ] ),
|
|
|
|
|
+ howMany: 1,
|
|
|
|
|
+ baseVersion: 3
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ type: RemoveOperation,
|
|
|
|
|
+ sourcePosition: new Position( root, [ 0, 2 ] ),
|
|
|
|
|
+ howMany: 1,
|
|
|
|
|
+ baseVersion: 4
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasB[ 1 ], {
|
|
|
|
|
+ type: InsertDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: InsertOperation,
|
|
|
|
|
+ position: new Position( root, [ 1, 2 ] ),
|
|
|
|
|
+ baseVersion: 5
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ it( 'should transform two arrays of deltas - reverse', () => {
|
|
|
|
|
+ const splitDelta = getSplitDelta( new Position( root, [ 0, 3 ] ), new Element( 'p' ), 3, baseVersion );
|
|
|
|
|
+ const insertDeltaX = getInsertDelta( new Position( root, [ 0, 3 ] ), new Text( 'xxx' ), baseVersion + 2 );
|
|
|
|
|
+
|
|
|
|
|
+ const removeDelta = getRemoveDelta( new Position( root, [ 0, 2 ] ), 2, baseVersion );
|
|
|
|
|
+ const insertDeltaY = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'yyy' ), baseVersion + 1 );
|
|
|
|
|
+
|
|
|
|
|
+ const { deltasA, deltasB } = transformDeltaSets( [ removeDelta, insertDeltaY ], [ splitDelta, insertDeltaX ], true );
|
|
|
|
|
+
|
|
|
|
|
+ expect( deltasA.length ).to.equal( 2 );
|
|
|
|
|
+ expect( deltasB.length ).to.equal( 3 );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasA[ 0 ], {
|
|
|
|
|
+ type: RemoveDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: RemoveOperation,
|
|
|
|
|
+ sourcePosition: new Position( root, [ 1, 0 ] ),
|
|
|
|
|
+ howMany: 1,
|
|
|
|
|
+ baseVersion: 3
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ type: RemoveOperation,
|
|
|
|
|
+ sourcePosition: new Position( root, [ 0, 2 ] ),
|
|
|
|
|
+ howMany: 1,
|
|
|
|
|
+ baseVersion: 4
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasA[ 1 ], {
|
|
|
|
|
+ type: InsertDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: InsertOperation,
|
|
|
|
|
+ position: new Position( root, [ 1, 2 ] ),
|
|
|
|
|
+ baseVersion: 5
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasB[ 0 ], {
|
|
|
|
|
+ type: SplitDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: InsertOperation,
|
|
|
|
|
+ position: new Position( root, [ 1 ] ),
|
|
|
|
|
+ baseVersion: 2
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ type: MoveOperation,
|
|
|
|
|
+ sourcePosition: new Position( root, [ 0, 2 ] ),
|
|
|
|
|
+ howMany: 5,
|
|
|
|
|
+ targetPosition: new Position( root, [ 1, 0 ] ),
|
|
|
|
|
+ baseVersion: 3
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasB[ 1 ], {
|
|
|
|
|
+ type: InsertDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: InsertOperation,
|
|
|
|
|
+ position: new Position( root, [ 0, 2 ] ),
|
|
|
|
|
+ baseVersion: 4
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasB[ 2 ], {
|
|
|
|
|
+ type: Delta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: NoOperation,
|
|
|
|
|
+ baseVersion: 5
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ it( 'importance flag - first set is important', () => {
|
|
|
|
|
+ const insertDeltaA = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'xxx' ), baseVersion );
|
|
|
|
|
+ const insertDeltaB = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'yyy' ), baseVersion );
|
|
|
|
|
+
|
|
|
|
|
+ let { deltasA, deltasB } = transformDeltaSets( [ insertDeltaA ], [ insertDeltaB ], true );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasA[ 0 ], {
|
|
|
|
|
+ type: InsertDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: InsertOperation,
|
|
|
|
|
+ position: new Position( root, [ 0, 4 ] ),
|
|
|
|
|
+ baseVersion: 1
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasB[ 0 ], {
|
|
|
|
|
+ type: InsertDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: InsertOperation,
|
|
|
|
|
+ position: new Position( root, [ 0, 7 ] ),
|
|
|
|
|
+ baseVersion: 1
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ it( 'importance flag - second set is important', () => {
|
|
|
|
|
+ const insertDeltaA = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'xxx' ), baseVersion );
|
|
|
|
|
+ const insertDeltaB = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'yyy' ), baseVersion );
|
|
|
|
|
+
|
|
|
|
|
+ let { deltasA, deltasB } = transformDeltaSets( [ insertDeltaA ], [ insertDeltaB ], false );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasA[ 0 ], {
|
|
|
|
|
+ type: InsertDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: InsertOperation,
|
|
|
|
|
+ position: new Position( root, [ 0, 7 ] ),
|
|
|
|
|
+ baseVersion: 1
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ expectDelta( deltasB[ 0 ], {
|
|
|
|
|
+ type: InsertDelta,
|
|
|
|
|
+ operations: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: InsertOperation,
|
|
|
|
|
+ position: new Position( root, [ 0, 4 ] ),
|
|
|
|
|
+ baseVersion: 1
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ } );
|
|
|
|
|
+ } );
|
|
|
|
|
+
|
|
|
|
|
+ it( 'should not modify original deltas or arrays', () => {
|
|
|
|
|
+ const insertDeltaA = getInsertDelta( new Position( root, [ 0, 0 ] ), new Text( 'x' ), baseVersion );
|
|
|
|
|
+ const insertDeltaB = getInsertDelta( new Position( root, [ 1, 0 ] ), new Text( 'y' ), baseVersion );
|
|
|
|
|
+
|
|
|
|
|
+ const originalDeltasA = [ insertDeltaA ];
|
|
|
|
|
+ const originalDeltasB = [ insertDeltaB ];
|
|
|
|
|
+
|
|
|
|
|
+ let { deltasA, deltasB } = transformDeltaSets( originalDeltasA, originalDeltasB, false );
|
|
|
|
|
+
|
|
|
|
|
+ expect( deltasA ).to.not.equal( originalDeltasA );
|
|
|
|
|
+ expect( deltasB ).to.not.equal( originalDeltasB );
|
|
|
|
|
+ expect( deltasA[ 0 ] ).to.not.equal( originalDeltasA[ 0 ] );
|
|
|
|
|
+ expect( deltasB[ 0 ] ).to.not.equal( originalDeltasB[ 0 ] );
|
|
|
|
|
+ } );
|
|
|
|
|
+ } );
|
|
|
|
|
+} );
|