CKEditor5——Position源码分析(三)

上一节我们学习了比较两个Position之间的关系,它们可能属于不同的根节点,它们可能完全相同,它们也可能存在前后关系。
今天我们继续学习这个类的另一个关键方法:那就是
getTransformedByOperation( operation ) → Position
getTransformedByOperation( operation ) {
let result;
switch ( operation.type ) {
case 'insert':
result = this._getTransformedByInsertOperation( operation );
break;
case 'move':
case 'remove':
case 'reinsert':
result = this._getTransformedByMoveOperation( operation );
break;
case 'split':
result = this._getTransformedBySplitOperation( operation );
break;
case 'merge':
result = this._getTransformedByMergeOperation( operation );
break;
default:
result = Position._createAt( this );
break;
}
return result;
}
首先说明一下这个方法:
返回由给定操作转换的此位置的副本。新位置的参数会根据操作的效果进行相应更新。例如,如果在位置之前插入n个节点,则返回的位置偏移量将增加n。如果该位置在合并元素中,它将相应地移动到新元素等。这种方法可以安全地用于不存在的位置(例如在操作转换期间)。
从以上说明,我们可以看出,这个方法是当前位置应用一个给定的操作后返回一个新的位置,具体的操作有六类:insert,move,remove,reinsert,split,merge
,而move,remove,reinsert
又是同一种情况,我们先看看insert
的情况:this._getTransformedByInsertOperation( operation );
_getTransformedByInsertOperation( operation ) {
return this._getTransformedByInsertion( operation.position, operation.howMany );
}
_getTransformedByInsertion( insertPosition, howMany ) {
const transformed = Position._createAt( this );
// This position can't be affected if insertion was in a different root.
if ( this.root != insertPosition.root ) {
return transformed;
}
if ( compareArrays( insertPosition.getParentPath(), this.getParentPath() ) == 'same' ) {
// If nodes are inserted in the node that is pointed by this position...
if ( insertPosition.offset < this.offset || ( insertPosition.offset == this.offset && this.stickiness != 'toPrevious' ) ) {
// And are inserted before an offset of that position...
// "Push" this positions offset.
transformed.offset += howMany;
}
} else if ( compareArrays( insertPosition.getParentPath(), this.getParentPath() ) == 'prefix' ) {
// If nodes are inserted in a node that is on a path to this position...
const i = insertPosition.path.length - 1;
if ( insertPosition.offset <= this.path[ i ] ) {
// And are inserted before next node of that path...
// "Push" the index on that path.
transformed.path[ i ] += howMany;
}
}
return transformed;
}
我们看到insert
的情况实际上分为三类,
1、如果当前位置的根节点与操作对应的位置的根节点不一致,那么直接返回当前位置,实际上可能啥都没有做,因为操作对应的位置没有啥效果
2、如果当前位置的parentPath
与插入操作的位置的parentPath
一致,那么这里分两种情况:
//第一种情况
// should increment offset if insertion is in the same parent and the same offset
const position = new Position( root, [ 1, 2, 3 ] );
position.stickiness = 'toNext';
const transformed = position._getTransformedByInsertion( new Position( root, [ 1, 2, 3 ] ), 2 );
expect( transformed.offset ).to.equal( 5 );
//第二种情况
//should increment offset if insertion is in the same parent and closer offset
const position = new Position( root, [ 1, 2, 3 ] );
const transformed = position._getTransformedByInsertion( new Position( root, [ 1, 2, 2 ] ), 2 );
expect( transformed.offset ).to.equal( 5 );
3、如果插入位置的parentPath在当前位置的parentPath之前,那么这种情况如下:
//should update path if insertion position parent is a node from that path and offset is before next node on that path
const position = new Position( root, [ 1, 2, 3 ] );
const transformed = position._getTransformedByInsertion( new Position( root, [ 1, 2 ] ), 2 );
expect( transformed.path ).to.deep.equal( [ 1, 4, 3 ] );
另外的其他情况的话,返回的位置都不会发生变化,因此,以上就是插入操作的情况下,可能发生新位置偏移的情况。另外move的情况比较复杂,我们以后分析。