敲碎时间,铸造不朽的个人专栏
上一篇

CKEditor5——Position源码分析(二)

广告
选中文字可对指定文章内容进行评论啦,→和←可快速切换按钮,绿色背景文字可以点击查看评论额。
大纲

CKEditor5——Position源码分析(二)

上一节,我们学习了Position的基础知识,包括怎么寻找它的parent属性,它的path是什么意思?

今天我们看另一个方法,两个Position之间的关系是什么,也就是这个方法:

compareWith( otherPosition ) → PositionRelation

compareWith( otherPosition ) {
	if ( this.root != otherPosition.root ) {
		return 'different';
	}

	const result = compareArrays( this.path, otherPosition.path );

	switch ( result ) {
		case 'same':
			return 'same';

		case 'prefix':
			return 'before';

		case 'extension':
			return 'after';

		default:
			return this.path[ result ] < otherPosition.path[ result ] ? 'before' : 'after';
	}
}

从以上的代码可以看出,如果两个Position的根节点不一样,它们一定是不同的。它们之间关系的比较是通过一个工具方法:compareArrays( this.path, otherPosition.path );

下面我们看看这个方法:

export default function compareArrays( a, b ) {
	const minLen = Math.min( a.length, b.length );

	for ( let i = 0; i < minLen; i++ ) {
		if ( a[ i ] != b[ i ] ) {
			// The arrays are different.
			return i;
		}
	}

	// Both arrays were same at all points.
	if ( a.length == b.length ) {
		// If their length is also same, they are the same.
		return 'same';
	} else if ( a.length < b.length ) {
		// Compared array is shorter so it is a prefix of the other array.
		return 'prefix';
	} else {
		// Compared array is longer so it is an extension of the other array.
		return 'extension';
	}
}

首先获取两个数组长度最短的值minLen,然后比较前minLen个值,如果不相同的话没救返回不相同的位置的索引;如果前minLen个值都相同,如果a的长度比b的长度小,那么返回prefix;如果a的长度大于b的长度,那么返回extension;否则长度相同,值也相同,则返回same;

有了这个工具方法,我们可以知道,两个Position的关系可能有四种same,before,after,different

如果他们的path数组的值是一样的,那么这两个Position的关系是same;

如果当前PositionpathotherPositionpath之前,那么认为当前PositionotherPosition之前,否则就是之后。

这里的一个默认值是比较它们path的第一个不相等的值对应的大小,小的在前面,大的在后面。

 

有了以上的比较两个Position关系的方法,我们可以看看其他的几个方法,比如:

isAfter( otherPosition ) → Boolean

isBefore( otherPosition ) → Boolean

isEqual( otherPosition ) → Boolean

isTouching( otherPosition ) → Boolean

都是调用我们以上分析的方法来实现的,这里我们重点看看最后一个:

isTouching( otherPosition ) {
	let left = null;
	let right = null;
	const compare = this.compareWith( otherPosition );

	switch ( compare ) {
		case 'same':
			return true;

		case 'before':
			left = Position._createAt( this );
			right = Position._createAt( otherPosition );
			break;

		case 'after':
			left = Position._createAt( otherPosition );
			right = Position._createAt( this );
			break;

		default:
			return false;
	}

	// Cached for optimization purposes.
	let leftParent = left.parent;

	while ( left.path.length + right.path.length ) {
		if ( left.isEqual( right ) ) {
			return true;
		}

		if ( left.path.length > right.path.length ) {
			if ( left.offset !== leftParent.maxOffset ) {
				return false;
			}

			left.path = left.path.slice( 0, -1 );
			leftParent = leftParent.parent;
			left.offset++;
		} else {
			if ( right.offset !== 0 ) {
				return false;
			}

			right.path = right.path.slice( 0, -1 );
		}
	}
}

这里我们先看看什么是touching:检查此位置是否接触给定位置。当它们之间的范围内没有文本节点或空节点时,位置接触。从技术上讲,这些位置并不相同,但在许多情况下,它们非常相似甚至无法区分。

这里我们思考一下,两个Position接触的情况有哪些:

1、两个Position一模一样。

2、第一个Position在前面,第二个Position在后面,但是它们之间没有空隙

3、第一个Position在后面,第二个Position在前面,它们之间也没有空隙。

以上的方法实现就是针对的这三种情况,感兴趣的可以去仔细分析一下。

版权声明:著作权归作者所有。

X

欢迎加群学习交流

联系我们