소스 검색

Other: Make view Position immutable.

Maciej Gołaszewski 8 년 전
부모
커밋
9117e564ff
3개의 변경된 파일47개의 추가작업 그리고 38개의 파일을 삭제
  1. 27 19
      packages/ckeditor5-engine/src/view/position.js
  2. 9 8
      packages/ckeditor5-engine/src/view/treewalker.js
  3. 11 11
      packages/ckeditor5-engine/src/view/writer.js

+ 27 - 19
packages/ckeditor5-engine/src/view/position.js

@@ -13,6 +13,9 @@ import compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import EditableElement from './editableelement';
 
+const _parent = Symbol( 'parent' );
+const _offset = Symbol( 'offset' );
+
 /**
  * Position in the tree. Position is always located before or after a node.
  */
@@ -24,20 +27,28 @@ export default class Position {
 	 * @param {Number} offset Position offset.
 	 */
 	constructor( parent, offset ) {
-		/**
-		 * Position parent.
-		 *
-		 * @member {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}
-		 * module:engine/view/position~Position#parent
-		 */
-		this.parent = parent;
-
-		/**
-		 * Position offset.
-		 *
-		 * @member {Number} module:engine/view/position~Position#offset
-		 */
-		this.offset = offset;
+		this[ _parent ] = parent;
+		this[ _offset ] = offset;
+	}
+
+	/**
+	 * Position parent.
+	 *
+	 * @readonly
+	 * @type {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}
+	 */
+	get parent() {
+		return this[ _parent ];
+	}
+
+	/**
+	 * Position offset.
+	 *
+	 * @readonly
+	 * @type {Number}
+	 */
+	get offset() {
+		return this[ _offset ];
 	}
 
 	/**
@@ -129,12 +140,9 @@ export default class Position {
 	 * @returns {module:engine/view/position~Position} Shifted position.
 	 */
 	getShiftedBy( shift ) {
-		const shifted = Position.createFromPosition( this );
-
-		const offset = shifted.offset + shift;
-		shifted.offset = offset < 0 ? 0 : offset;
+		const offset = this.offset + shift;
 
-		return shifted;
+		return new Position( this.parent, offset < 0 ? 0 : offset );
 	}
 
 	/**

+ 9 - 8
packages/ckeditor5-engine/src/view/treewalker.js

@@ -73,9 +73,9 @@ export default class TreeWalker {
 		 * @member {module:engine/view/position~Position} module:engine/view/treewalker~TreeWalker#position
 		 */
 		if ( options.startPosition ) {
-			this.position = Position.createFromPosition( options.startPosition );
+			this.position = options.startPosition;
 		} else {
-			this.position = Position.createFromPosition( options.boundaries[ options.direction == 'backward' ? 'end' : 'start' ] );
+			this.position = options.boundaries[ options.direction == 'backward' ? 'end' : 'start' ];
 		}
 
 		/**
@@ -222,7 +222,7 @@ export default class TreeWalker {
 			if ( !this.shallow ) {
 				position = new Position( node, 0 );
 			} else {
-				position.offset++;
+				position = position.getShiftedBy( 1 );
 			}
 
 			this.position = position;
@@ -245,7 +245,7 @@ export default class TreeWalker {
 					position = Position.createAfter( item );
 				} else {
 					// If not just keep moving forward.
-					position.offset++;
+					position = position.getShiftedBy( 1 );
 				}
 
 				this.position = position;
@@ -266,7 +266,8 @@ export default class TreeWalker {
 
 			const textProxy = new TextProxy( parent, position.offset, textLength );
 
-			position.offset += textLength;
+			position = position.getShiftedBy( textLength );
+
 			this.position = position;
 
 			return this._formatReturnValue( 'text', textProxy, previousPosition, position, textLength );
@@ -334,7 +335,7 @@ export default class TreeWalker {
 					return this._formatReturnValue( 'elementEnd', node, previousPosition, position );
 				}
 			} else {
-				position.offset--;
+				position = position.getShiftedBy( -1 );
 				this.position = position;
 
 				return this._formatReturnValue( 'elementStart', node, previousPosition, position, 1 );
@@ -358,7 +359,7 @@ export default class TreeWalker {
 					position = Position.createBefore( item );
 				} else {
 					// If not just keep moving backward.
-					position.offset--;
+					position = position.getShiftedBy( -1 );
 				}
 
 				this.position = position;
@@ -377,7 +378,7 @@ export default class TreeWalker {
 				textLength = 1;
 			}
 
-			position.offset -= textLength;
+			position = position.getShiftedBy( -textLength );
 
 			const textProxy = new TextProxy( parent, position.offset, textLength );
 

+ 11 - 11
packages/ckeditor5-engine/src/view/writer.js

@@ -305,7 +305,7 @@ export function insert( position, nodes ) {
 	const insertionPosition = _breakAttributes( position, true );
 
 	const length = container.insertChildren( insertionPosition.offset, nodes );
-	const endPosition = insertionPosition.getShiftedBy( length );
+	let endPosition = insertionPosition.getShiftedBy( length );
 	const start = mergeAttributes( insertionPosition );
 
 	// When no nodes were inserted - return collapsed range.
@@ -314,7 +314,7 @@ export function insert( position, nodes ) {
 	} else {
 		// If start position was merged - move end position.
 		if ( !start.isEqual( insertionPosition ) ) {
-			endPosition.offset--;
+			endPosition = endPosition.getShiftedBy( -1 );
 		}
 
 		const end = mergeAttributes( endPosition );
@@ -447,7 +447,7 @@ export function move( sourceRange, targetPosition ) {
 
 		nodes = remove( sourceRange );
 
-		targetPosition.offset += ( parent.childCount - countBefore );
+		targetPosition = targetPosition.getShiftedBy( parent.childCount - countBefore );
 	} else {
 		nodes = remove( sourceRange );
 	}
@@ -512,7 +512,7 @@ export function wrap( range, attribute ) {
 
 	// If start position was merged - move end position back.
 	if ( !start.isEqual( newRange.start ) ) {
-		newRange.end.offset--;
+		newRange.end = newRange.end.getShiftedBy( -1 );
 	}
 	const end = mergeAttributes( newRange.end );
 
@@ -626,7 +626,7 @@ export function unwrap( range, attribute ) {
 
 	// If start position was merged - move end position back.
 	if ( !start.isEqual( newRange.start ) ) {
-		newRange.end.offset--;
+		newRange.end = newRange.end.getShiftedBy( -1 );
 	}
 	const end = mergeAttributes( newRange.end );
 
@@ -702,12 +702,12 @@ function _breakAttributesRange( range, forceSplitText = false ) {
 		return new Range( position, position );
 	}
 
-	const breakEnd = _breakAttributes( rangeEnd, forceSplitText );
+	let breakEnd = _breakAttributes( rangeEnd, forceSplitText );
 	const count = breakEnd.parent.childCount;
 	const breakStart = _breakAttributes( rangeStart, forceSplitText );
 
 	// Calculate new break end offset.
-	breakEnd.offset += breakEnd.parent.childCount - count;
+	breakEnd = breakEnd.getShiftedBy( breakEnd.parent.childCount - count );
 
 	return new Range( breakStart, breakEnd );
 }
@@ -857,8 +857,8 @@ function unwrapChildren( parent, startOffset, endOffset, attribute ) {
 	// Merge at each unwrap.
 	let offsetChange = 0;
 
-	for ( const position of unwrapPositions ) {
-		position.offset -= offsetChange;
+	for ( let position of unwrapPositions ) {
+		position = position.getShiftedBy( -offsetChange );
 
 		// Do not merge with elements outside selected children.
 		if ( position.offset == startOffset || position.offset == endOffset ) {
@@ -918,8 +918,8 @@ function wrapChildren( parent, startOffset, endOffset, attribute ) {
 	// Merge at each wrap.
 	let offsetChange = 0;
 
-	for ( const position of wrapPositions ) {
-		position.offset -= offsetChange;
+	for ( let position of wrapPositions ) {
+		position = position.getShiftedBy( -offsetChange );
 
 		// Do not merge with elements outside selected children.
 		if ( position.offset == startOffset ) {