Преглед изворни кода

Refactored modifySelection using TreeWalker direction option.

Oskar Wrobel пре 9 година
родитељ
комит
a987da9efd

+ 13 - 14
packages/ckeditor5-engine/src/treemodel/composer/modifyselection.js

@@ -27,48 +27,47 @@ export default function modifySelection( selection, options = {} ) {
 	const focus = selection.focus;
 	const walker = new TreeWalker( {
 		boundaries: getSearchRange( focus, isForward ),
-		singleCharacters: true
+		singleCharacters: true,
+		direction: isForward ? 'FORWARD' : 'BACKWARD'
 	} );
 
-	const items = Array.from( walker );
-	let next = items[ isForward ? 'shift' : 'pop' ]();
+	let next = walker.next();
 
 	// 1. Nothing to do here.
-	if ( !next ) {
+	if ( next.done ) {
 		return;
 	}
 
 	// 2. Consume next character.
-	if ( next.type == 'CHARACTER' ) {
-		selection.setFocus( next[ isForward ? 'nextPosition' : 'previousPosition' ] );
+	if ( next.value.type == 'CHARACTER' ) {
+		selection.setFocus( next.value.nextPosition );
 
 		return;
 	}
 
 	// 3. We're entering an element, so let's consume it fully.
-	if ( next.type == ( isForward ? 'ELEMENT_START' : 'ELEMENT_END' ) ) {
-		selection.setFocus( next.item, isForward ? 'AFTER' : 'BEFORE' );
+	if ( next.value.type == ( isForward ? 'ELEMENT_START' : 'ELEMENT_END' ) ) {
+		selection.setFocus( next.value.item, isForward ? 'AFTER' : 'BEFORE' );
 
 		return;
 	}
 
 	// 4. We're leaving an element. That's more tricky.
-
-	next = items[ isForward ? 'shift' : 'pop' ]();
+	next = walker.next();
 
 	// 4.1. Nothing left, so let's stay where we were.
-	if ( !next ) {
+	if ( next.done ) {
 		return;
 	}
 
 	// 4.2. Character found after element end. Not really a valid case in our data model, but let's
 	// do something sensible and put the selection focus before that character.
-	if ( next.type == 'CHARACTER' ) {
-		selection.setFocus( next[ isForward ? 'previousPosition' : 'nextPosition' ] );
+	if ( next.value.type == 'CHARACTER' ) {
+		selection.setFocus( next.value.previousPosition );
 	}
 	// 4.3. OK, we're entering a new element. So let's place there the focus.
 	else {
-		selection.setFocus( next.item, isForward ? 0 : 'END' );
+		selection.setFocus( next.value.item, isForward ? 0 : 'END' );
 	}
 }
 

+ 7 - 3
packages/ckeditor5-engine/src/treemodel/treewalker.js

@@ -95,9 +95,13 @@ export default class TreeWalker {
 		 *
 		 * @member {engine.treeModel.Position} engine.treeModel.TreeWalker#position
 		 */
-		this.position = startPosition ?
-			Position.createFromPosition( startPosition ) :
-			Position.createFromPosition( boundaries.start );
+		if ( startPosition ) {
+			this.position = Position.createFromPosition( startPosition );
+		} else {
+			this.position = direction == 'BACKWARD' ?
+				Position.createFromPosition( boundaries.end ) :
+				Position.createFromPosition( boundaries.start );
+		}
 
 		/**
 		 * Walking direction. Defaults `FORWARD`.

+ 55 - 16
packages/ckeditor5-engine/tests/treemodel/treewalker.js

@@ -163,10 +163,8 @@ describe( 'TreeWalker', () => {
 	} );
 
 	describe( 'iterate trough the range `boundary`', () => {
-		let start, end, range;
-
 		describe( 'range starts between elements', () => {
-			let expected;
+			let expected, range;
 
 			before( () => {
 				expected = [
@@ -177,9 +175,7 @@ describe( 'TreeWalker', () => {
 					{ type: 'ELEMENT_END', item: img2 }
 				];
 
-				start = new Position( root, [ 1 ] );
-				end = new Position( root, [ 1, 4 ] );
-				range = new Range( start, end );
+				range = new Range( new Position( root, [ 1 ] ), new Position( root, [ 1, 4 ] ) );
 			} );
 
 			it( 'should iterating over the range', () => {
@@ -195,7 +191,7 @@ describe( 'TreeWalker', () => {
 			} );
 
 			it( 'should iterating over the range going backward', () => {
-				let iterator = new TreeWalker( { boundaries: range, startPosition: range.end, direction: 'BACKWARD' } );
+				let iterator = new TreeWalker( { boundaries: range, direction: 'BACKWARD' } );
 				let i = expected.length;
 
 				for ( let value of iterator ) {
@@ -207,7 +203,7 @@ describe( 'TreeWalker', () => {
 		} );
 
 		describe( 'range starts inside the text', () => {
-			let expected;
+			let expected, range;
 
 			before( () => {
 				expected = [
@@ -217,9 +213,7 @@ describe( 'TreeWalker', () => {
 					{ type: 'ELEMENT_END', item: img2 }
 				];
 
-				start = new Position( root, [ 1, 1 ] );
-				end = new Position( root, [ 1, 4 ] );
-				range = new Range( start, end );
+				range = new Range( new Position( root, [ 1, 1 ] ), new Position( root, [ 1, 4 ] ) );
 			} );
 
 			it( 'should return part of the text', () => {
@@ -237,7 +231,6 @@ describe( 'TreeWalker', () => {
 			it( 'should return part of the text going backward', () => {
 				let iterator = new TreeWalker( {
 					boundaries: range,
-					startPosition: range.end,
 					direction: 'BACKWARD' }
 				);
 				let i = expected.length;
@@ -251,7 +244,7 @@ describe( 'TreeWalker', () => {
 		} );
 
 		describe( 'range ends inside the text', () => {
-			let expected;
+			let expected, range;
 
 			before( () => {
 				expected = [
@@ -261,9 +254,7 @@ describe( 'TreeWalker', () => {
 					{ type: 'TEXT', text: 'b', attrs: [ [ 'bold', true ] ] }
 				];
 
-				start = rootBeginning;
-				end = new Position( root, [ 1, 1 ] );
-				range = new Range( start, end );
+				range = new Range( rootBeginning, new Position( root, [ 1, 1 ] ) );
 			} );
 
 			it( 'should return part of the text', () => {
@@ -293,6 +284,54 @@ describe( 'TreeWalker', () => {
 				expect( i ).to.equal( 0 );
 			} );
 		} );
+
+		describe( 'custom start position', () => {
+			it( 'should iterating from the start position', () => {
+				let expected = [
+					{ type: 'TEXT', text: 'r', attrs: [] },
+					{ type: 'ELEMENT_START', item: img2 },
+					{ type: 'ELEMENT_END', item: img2 }
+				];
+
+				let range = new Range( new Position( root, [ 1 ] ), new Position( root, [ 1, 4 ] ) );
+
+				let iterator = new TreeWalker( {
+					boundaries: range,
+					startPosition: new Position( root, [ 1, 2 ] )
+				} );
+				let i = 0;
+
+				for ( let value of iterator ) {
+					expectValue( value, expected[ i ] );
+					i++;
+				}
+
+				expect( i ).to.equal( expected.length );
+			} );
+
+			it( 'should iterating from the start position going backward', () => {
+				let expected = [
+					{ type: 'TEXT', text: 'r', attrs: [] },
+					{ type: 'ELEMENT_START', item: img2 },
+					{ type: 'ELEMENT_END', item: img2 }
+				];
+
+				let range = new Range( new Position( root, [ 1, 2 ] ), new Position( root, [ 1, 6 ] ) );
+
+				let iterator = new TreeWalker( {
+					boundaries: range,
+					startPosition: new Position( root, [ 1, 4 ] ),
+					direction: 'BACKWARD'
+				} );
+				let i = expected.length;
+
+				for ( let value of iterator ) {
+					expectValue( value, expected[ --i ], { direction: 'BACKWARD' } );
+				}
+
+				expect( i ).to.equal( 0 );
+			} );
+		} );
 	} );
 
 	describe( 'iterate by every single characters `singleCharacter`', () => {