Browse Source

Refactored ViewSelection API.

Maciej Bukowski 8 years ago
parent
commit
413765bf25

+ 2 - 2
packages/ckeditor5-engine/src/controller/datacontroller.js

@@ -194,8 +194,8 @@ export default class DataController {
 		this.model.enqueueChange( 'transparent', writer => {
 			// Clearing selection is a workaround for ticket #569 (LiveRange loses position after removing data from document).
 			// After fixing it this code should be removed.
-			this.model.document.selection.removeAllRanges();
-			this.model.document.selection.clearAttributes();
+			this.model.document.selection._setTo( null );
+			this.model.document.selection._clearAttributes();
 
 			writer.remove( ModelRange.createIn( modelRoot ) );
 			writer.insert( this.parse( data ), modelRoot );

+ 3 - 4
packages/ckeditor5-engine/src/conversion/model-selection-to-view-converters.js

@@ -35,7 +35,7 @@ export function convertRangeSelection() {
 			return;
 		}
 
-		conversionApi.viewSelection.removeAllRanges();
+		conversionApi.viewSelection.setTo( null );
 
 		for ( const range of selection.getRanges() ) {
 			const viewRange = conversionApi.mapper.toViewRange( range );
@@ -82,8 +82,7 @@ export function convertCollapsedSelection() {
 		const viewPosition = conversionApi.mapper.toViewPosition( modelPosition );
 		const brokenPosition = viewWriter.breakAttributes( viewPosition );
 
-		conversionApi.viewSelection.removeAllRanges();
-		conversionApi.viewSelection.addRange( new ViewRange( brokenPosition, brokenPosition ) );
+		conversionApi.viewSelection.setTo( new ViewRange( brokenPosition, brokenPosition ) );
 	};
 }
 
@@ -122,7 +121,7 @@ export function clearAttributes() {
 				}
 			}
 		}
-		conversionApi.viewSelection.removeAllRanges();
+		conversionApi.viewSelection.setTo( null );
 	};
 }
 

+ 1 - 1
packages/ckeditor5-engine/src/conversion/view-selection-to-model-converters.js

@@ -41,7 +41,7 @@ export function convertSelectionChange( model, mapper ) {
 
 		if ( !modelSelection.isEqual( model.document.selection ) ) {
 			model.change( () => {
-				model.document.selection.setTo( modelSelection );
+				model.document.selection._setTo( modelSelection );
 			} );
 		}
 	};

+ 1 - 1
packages/ckeditor5-engine/src/dev-utils/model.js

@@ -116,7 +116,7 @@ export function setData( model, data, options = {} ) {
 
 		// Clean up previous document selection.
 		model.document.selection._clearAttributes();
-		model.document.selection._removeAllRanges();
+		model.document.selection._setTo( null );
 
 		// Update document selection if specified.
 		if ( selection ) {

+ 1 - 2
packages/ckeditor5-engine/src/dev-utils/view.js

@@ -332,8 +332,7 @@ export function parse( data, options = {} ) {
 
 	// When ranges are present - return object containing view, and selection.
 	if ( ranges.length ) {
-		const selection = new Selection();
-		selection.setRanges( ranges, !!options.lastRangeBackward );
+		const selection = new Selection( ranges, !!options.lastRangeBackward );
 
 		return {
 			view,

+ 0 - 4
packages/ckeditor5-engine/src/model/documentselection.js

@@ -121,10 +121,6 @@ export default class DocumentSelection {
 		this._selection.clearAttributes();
 	}
 
-	_removeAllRanges() {
-		this._selection.setTo( null );
-	}
-
 	_getStoredAttributes() {
 		return this._selection._getStoredAttributes();
 	}

+ 2 - 2
packages/ckeditor5-engine/src/view/observer/fakeselectionobserver.js

@@ -87,12 +87,12 @@ export default class FakeSelectionObserver extends Observer {
 
 		// Left or up arrow pressed - move selection to start.
 		if ( keyCode == keyCodes.arrowleft || keyCode == keyCodes.arrowup ) {
-			newSelection.collapseToStart();
+			newSelection.setTo( newSelection.getFirstPosition() );
 		}
 
 		// Right or down arrow pressed - move selection to end.
 		if ( keyCode == keyCodes.arrowright || keyCode == keyCodes.arrowdown ) {
-			newSelection.collapseToEnd();
+			newSelection.setTo( newSelection.getLastPosition() );
 		}
 
 		const data = {

+ 37 - 92
packages/ckeditor5-engine/src/view/selection.js

@@ -13,6 +13,7 @@ import Position from './position';
 import mix from '@ckeditor/ckeditor5-utils/src/mix';
 import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
 import Element from './element';
+import Text from './text';
 import count from '@ckeditor/ckeditor5-utils/src/count';
 import isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';
 
@@ -74,7 +75,7 @@ export default class Selection {
 		this._fakeSelectionLabel = '';
 
 		if ( ranges ) {
-			this.setRanges( ranges, isLastBackward );
+			this._setRanges( ranges, isLastBackward );
 		}
 	}
 
@@ -211,7 +212,7 @@ export default class Selection {
 	 * @param {module:engine/view/range~Range} range
 	 * @param {Boolean} isBackward
 	 */
-	addRange( range, isBackward ) {
+	_addRange( range, isBackward ) {
 		if ( !( range instanceof Range ) ) {
 			throw new CKEditorError( 'view-selection-invalid-range: Invalid Range.' );
 		}
@@ -397,7 +398,7 @@ export default class Selection {
 	 *
 	 * @fires change
 	 */
-	removeAllRanges() {
+	_removeAllRanges() {
 		if ( this._ranges.length ) {
 			this._ranges = [];
 			this.fire( 'change' );
@@ -405,117 +406,61 @@ export default class Selection {
 	}
 
 	/**
-	 * Replaces all ranges that were added to the selection with given array of ranges. Last range of the array
-	 * is treated like the last added range and is used to set {@link #anchor anchor} and {@link #focus focus}.
-	 * Accepts a flag describing in which way the selection is made (see {@link #addRange addRange}).
-	 *
-	 * @fires change
-	 * @param {Iterable.<module:engine/view/range~Range>} newRanges Iterable object of ranges to set.
-	 * @param {Boolean} [isLastBackward] Flag describing if last added range was selected forward - from start to end
-	 * (`false`) or backward - from end to start (`true`). Defaults to `false`.
-	 */
-	setRanges( newRanges, isLastBackward ) {
-		this._ranges = [];
-
-		for ( const range of newRanges ) {
-			if ( !( range instanceof Range ) ) {
-				throw new CKEditorError( 'view-selection-invalid-range: Invalid Range.' );
-			}
-
-			this._pushRange( range );
-		}
-
-		this._lastRangeBackward = !!isLastBackward;
-		this.fire( 'change' );
-	}
-
-	/**
 	 * Sets this selection's ranges and direction to the specified location based on the given
 	 * {@link module:engine/view/selection~Selection selection}, {@link module:engine/view/position~Position position},
 	 * {@link module:engine/view/range~Range range} or an iterable of {@link module:engine/view/range~Range ranges}.
 	 *
 	 * @param {module:engine/view/selection~Selection|module:engine/view/position~Position|
 	 * Iterable.<module:engine/view/range~Range>|module:engine/view/range~Range} selectable
+	 * @param {Boolean|Number|'before'|'end'|'after'} [backwardSelectionOrOffset]
 	 */
-	setTo( selectable ) {
-		if ( selectable instanceof Selection ) {
+	setTo( selectable, backwardSelectionOrOffset ) {
+		if ( !selectable ) {
+			this._removeAllRanges();
+		} else if ( selectable instanceof Selection ) {
 			this._isFake = selectable.isFake;
 			this._fakeSelectionLabel = selectable.fakeSelectionLabel;
-			this.setRanges( selectable.getRanges(), selectable.isBackward );
+			this._setRanges( selectable.getRanges(), selectable.isBackward );
 		} else if ( selectable instanceof Range ) {
-			this.setRanges( [ selectable ] );
+			this._setRanges( [ selectable ], backwardSelectionOrOffset );
+		} else if ( selectable instanceof Position ) {
+			this._setRanges( [ new Range( selectable ) ] );
+		} else if ( selectable instanceof Text ) {
+			this._setRanges( [ Range.createCollapsedAt( selectable, backwardSelectionOrOffset ) ] );
+		} else if ( selectable instanceof Element ) {
+			this._setRanges( [ Range.createCollapsedAt( selectable, backwardSelectionOrOffset ) ] );
 		} else if ( isIterable( selectable ) ) {
 			// We assume that the selectable is an iterable of ranges.
-			this.setRanges( selectable );
+			this._setRanges( selectable, backwardSelectionOrOffset );
 		} else {
-			// We assume that the selectable is a position.
-			this.setRanges( [ new Range( selectable ) ] );
+			throw new CKEditorError( 'model-selection-set-not-selectable' );
 		}
 	}
 
 	/**
-	 * Sets this selection in the provided element.
-	 *
-	 * @param {module:engine/view/element~Element} element
-	 */
-	setIn( element ) {
-		this.setRanges( [ Range.createIn( element ) ] );
-	}
-
-	/**
-	 * Sets this selection on the provided item.
-	 *
-	 * @param {module:engine/view/item~Item} item
-	 */
-	setOn( item ) {
-		this.setRanges( [ Range.createOn( item ) ] );
-	}
-
-	/**
-	 * Sets collapsed selection at the specified location.
-	 *
-	 * The location can be specified in the same form as {@link module:engine/view/position~Position.createAt} parameters.
+	 * Replaces all ranges that were added to the selection with given array of ranges. Last range of the array
+	 * is treated like the last added range and is used to set {@link #anchor anchor} and {@link #focus focus}.
+	 * Accepts a flag describing in which way the selection is made (see {@link #addRange addRange}).
 	 *
+	 * @protected
 	 * @fires change
-	 * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition
-	 * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
-	 * first parameter is a {@link module:engine/view/item~Item view item}.
+	 * @param {Iterable.<module:engine/view/range~Range>} newRanges Iterable object of ranges to set.
+	 * @param {Boolean} [isLastBackward] Flag describing if last added range was selected forward - from start to end
+	 * (`false`) or backward - from end to start (`true`). Defaults to `false`.
 	 */
-	setCollapsedAt( itemOrPosition, offset ) {
-		const pos = Position.createAt( itemOrPosition, offset );
-		const range = new Range( pos, pos );
-
-		this.setRanges( [ range ] );
-	}
+	_setRanges( newRanges, isLastBackward ) {
+		this._ranges = [];
 
-	/**
-	 * Collapses selection to the selection's {@link #getFirstPosition first position}.
-	 * All ranges, besides the collapsed one, will be removed. Nothing will change if there are no ranges stored
-	 * inside selection.
-	 *
-	 * @fires change
-	 */
-	collapseToStart() {
-		const startPosition = this.getFirstPosition();
+		for ( const range of newRanges ) {
+			if ( !( range instanceof Range ) ) {
+				throw new CKEditorError( 'view-selection-invalid-range: Invalid Range.' );
+			}
 
-		if ( startPosition !== null ) {
-			this.setRanges( [ new Range( startPosition, startPosition ) ] );
+			this._pushRange( range );
 		}
-	}
 
-	/**
-	 * Collapses selection to the selection's {@link #getLastPosition last position}.
-	 * All ranges, besides the collapsed one, will be removed. Nothing will change if there are no ranges stored
-	 * inside selection.
-	 *
-	 * @fires change
-	 */
-	collapseToEnd() {
-		const endPosition = this.getLastPosition();
-
-		if ( endPosition !== null ) {
-			this.setRanges( [ new Range( endPosition, endPosition ) ] );
-		}
+		this._lastRangeBackward = !!isLastBackward;
+		this.fire( 'change' );
 	}
 
 	/**
@@ -551,9 +496,9 @@ export default class Selection {
 		this._ranges.pop();
 
 		if ( newFocus.compareWith( anchor ) == 'before' ) {
-			this.addRange( new Range( newFocus, anchor ), true );
+			this._addRange( new Range( newFocus, anchor ), true );
 		} else {
-			this.addRange( new Range( anchor, newFocus ) );
+			this._addRange( new Range( anchor, newFocus ) );
 		}
 	}
 

+ 2 - 2
packages/ckeditor5-engine/tests/controller/editingcontroller.js

@@ -94,7 +94,7 @@ describe( 'EditingController', () => {
 			buildModelConverter().for( editing.modelToView ).fromMarker( 'marker' ).toHighlight( {} );
 
 			// Note: The below code is highly overcomplicated due to #455.
-			model.document.selection.removeAllRanges();
+			model.document.selection._setTo( null );
 			modelRoot.removeChildren( 0, modelRoot.childCount );
 
 			viewRoot.removeChildren( 0, viewRoot.childCount );
@@ -180,7 +180,7 @@ describe( 'EditingController', () => {
 			editing.view.render();
 
 			const domSelection = document.getSelection();
-			domSelection.removeAllRanges();
+			domSelection.setTo( null );
 			const domBar = domRoot.childNodes[ 2 ].childNodes[ 0 ];
 			const domRange = document.createRange();
 			domRange.setStart( domBar, 1 );

+ 3 - 3
packages/ckeditor5-engine/tests/model/documentselection.js

@@ -287,7 +287,7 @@ describe( 'DocumentSelection', () => {
 		} );
 	} );
 
-	describe( 'removeAllRanges()', () => {
+	describe( 'setTo - removeAllRanges', () => {
 		let spy, ranges;
 
 		beforeEach( () => {
@@ -301,7 +301,7 @@ describe( 'DocumentSelection', () => {
 			sinon.spy( ranges[ 0 ], 'detach' );
 			sinon.spy( ranges[ 1 ], 'detach' );
 
-			selection._removeAllRanges();
+			selection._setTo( null );
 		} );
 
 		afterEach( () => {
@@ -323,7 +323,7 @@ describe( 'DocumentSelection', () => {
 		it( 'should refresh attributes', () => {
 			const spy = sinon.spy( selection._selection, '_updateAttributes' );
 
-			selection._removeAllRanges();
+			selection._setTo( null );
 
 			expect( spy.called ).to.be.true;
 		} );

+ 1 - 1
packages/ckeditor5-engine/tests/view/document/document.js

@@ -383,7 +383,7 @@ describe( 'Document', () => {
 
 		it( 'should log warning when no selection', () => {
 			const logSpy = testUtils.sinon.stub( log, 'warn' );
-			viewDocument.selection.removeAllRanges();
+			viewDocument.selection.setTo( null );
 
 			viewDocument.focus();
 			expect( logSpy.calledOnce ).to.be.true;

+ 1 - 2
packages/ckeditor5-engine/tests/view/document/jumpoverinlinefiller.js

@@ -112,8 +112,7 @@ describe( 'Document', () => {
 			const viewB = viewDocument.selection.getFirstPosition().parent;
 			const viewTextX = parse( 'x' );
 			viewB.appendChildren( viewTextX );
-			viewDocument.selection.removeAllRanges();
-			viewDocument.selection.addRange( ViewRange.createFromParentsAndOffsets( viewTextX, 1, viewTextX, 1 ) );
+			viewDocument.selection.setTo( ViewRange.createFromParentsAndOffsets( viewTextX, 1, viewTextX, 1 ) );
 
 			const domB = viewDocument.getDomRoot( 'main' ).querySelector( 'b' );
 			const domSelection = document.getSelection();

+ 1 - 1
packages/ckeditor5-engine/tests/view/observer/mutationobserver.js

@@ -25,7 +25,7 @@ describe( 'MutationObserver', () => {
 
 		createViewRoot( viewDocument );
 		viewDocument.attachDomRoot( domEditor );
-		viewDocument.selection.removeAllRanges();
+		viewDocument.selection.setTo( null );
 		document.getSelection().removeAllRanges();
 
 		mutationObserver = viewDocument.getObserver( MutationObserver );

+ 1 - 1
packages/ckeditor5-engine/tests/view/observer/selectionobserver.js

@@ -41,7 +41,7 @@ describe( 'SelectionObserver', () => {
 
 		viewDocument.render();
 
-		viewDocument.selection.removeAllRanges();
+		viewDocument.selection.setTo( null );
 		domDocument.getSelection().removeAllRanges();
 
 		viewDocument.isFocused = true;

+ 18 - 33
packages/ckeditor5-engine/tests/view/renderer.js

@@ -122,7 +122,7 @@ describe( 'Renderer', () => {
 			renderer.markedAttributes.clear();
 			renderer.markedChildren.clear();
 
-			selection.removeAllRanges();
+			selection.setTo( null );
 			selection.setFake( false );
 
 			selectionEditable = viewRoot;
@@ -495,8 +495,7 @@ describe( 'Renderer', () => {
 			renderAndExpectNoChanges( renderer, domRoot );
 
 			// Step 3: <p>foo{}<b></b></p>
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets( viewP.getChild( 0 ), 3, viewP.getChild( 0 ), 3 ) );
+			selection.setTo( ViewRange.createFromParentsAndOffsets( viewP.getChild( 0 ), 3, viewP.getChild( 0 ), 3 ) );
 
 			renderer.render();
 
@@ -549,8 +548,7 @@ describe( 'Renderer', () => {
 			renderAndExpectNoChanges( renderer, domRoot );
 
 			// Step 3: <p><b>{}foo</b></p>
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets(
+			selection.setTo( ViewRange.createFromParentsAndOffsets(
 				viewP.getChild( 0 ).getChild( 0 ), 0, viewP.getChild( 0 ).getChild( 0 ), 0 ) );
 
 			renderer.render();
@@ -601,8 +599,7 @@ describe( 'Renderer', () => {
 			renderAndExpectNoChanges( renderer, domRoot );
 
 			// Step 3: <p><b>foo{}</b></p>
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets(
+			selection.setTo( ViewRange.createFromParentsAndOffsets(
 				viewP.getChild( 0 ).getChild( 0 ), 3, viewP.getChild( 0 ).getChild( 0 ), 3 ) );
 
 			renderer.render();
@@ -674,9 +671,8 @@ describe( 'Renderer', () => {
 			expect( domP.childNodes[ 2 ].childNodes.length ).to.equal( 0 );
 
 			// Step 2: <p>foo<b></b><i>"FILLER{}"</i></p>
-			selection.removeAllRanges();
 			const viewI = viewP.getChild( 2 );
-			selection.addRange( ViewRange.createFromParentsAndOffsets( viewI, 0, viewI, 0 ) );
+			selection.setTo( ViewRange.createFromParentsAndOffsets( viewI, 0, viewI, 0 ) );
 
 			renderer.render();
 
@@ -709,14 +705,13 @@ describe( 'Renderer', () => {
 			// Step 2: Add text node.
 			const viewText = new ViewText( 'x' );
 			viewB.appendChildren( viewText );
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
+			selection.setTo( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
 
 			renderer.markToSync( 'children', viewB );
 			renderer.render();
 
 			// Step 3: Remove selection from the view.
-			selection.removeAllRanges();
+			selection.setTo( null );
 
 			renderer.render();
 
@@ -746,8 +741,7 @@ describe( 'Renderer', () => {
 			// Step 2: Remove the <b> and update the selection (<p>bar[]</p>).
 			viewP.removeChildren( 1 );
 
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets( viewP, 1, viewP, 1 ) );
+			selection.setTo( ViewRange.createFromParentsAndOffsets( viewP, 1, viewP, 1 ) );
 
 			renderer.markToSync( 'children', viewP );
 			renderer.render();
@@ -784,8 +778,7 @@ describe( 'Renderer', () => {
 
 			viewP2.appendChildren( removedChildren );
 
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets( viewP, 0, viewP, 0 ) );
+			selection.setTo( ViewRange.createFromParentsAndOffsets( viewP, 0, viewP, 0 ) );
 
 			renderer.markToSync( 'children', viewP );
 			renderer.markToSync( 'children', viewP2 );
@@ -822,8 +815,7 @@ describe( 'Renderer', () => {
 			const viewI = parse( '<attribute:i></attribute:i>' );
 			viewP.appendChildren( viewI );
 
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets( viewI, 0, viewI, 0 ) );
+			selection.setTo( ViewRange.createFromParentsAndOffsets( viewI, 0, viewI, 0 ) );
 
 			renderer.markToSync( 'children', viewP );
 			renderer.render();
@@ -853,8 +845,7 @@ describe( 'Renderer', () => {
 			const viewAbc = parse( 'abc' );
 			viewP.appendChildren( viewAbc );
 
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets( viewP, 3, viewP, 3 ) );
+			selection.setTo( ViewRange.createFromParentsAndOffsets( viewP, 3, viewP, 3 ) );
 
 			renderer.markToSync( 'children', viewP );
 			renderer.render();
@@ -897,8 +888,7 @@ describe( 'Renderer', () => {
 
 			const viewText = new ViewText( 'x' );
 			viewP.appendChildren( viewText );
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
+			selection.setTo( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
 
 			renderer.markToSync( 'children', viewP );
 			renderAndExpectNoChanges( renderer, domRoot );
@@ -928,8 +918,7 @@ describe( 'Renderer', () => {
 			// Add text node only in View <p>x{}</p>
 			const viewText = new ViewText( 'x' );
 			viewP.appendChildren( viewText );
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
+			selection.setTo( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
 
 			renderer.markToSync( 'children', viewP );
 			renderer.render();
@@ -976,8 +965,7 @@ describe( 'Renderer', () => {
 
 			viewP.removeChildren( 0 );
 
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets( viewP, 0, viewP, 0 ) );
+			selection.setTo( ViewRange.createFromParentsAndOffsets( viewP, 0, viewP, 0 ) );
 
 			renderer.markToSync( 'children', viewP );
 			renderAndExpectNoChanges( renderer, domRoot );
@@ -1028,8 +1016,7 @@ describe( 'Renderer', () => {
 
 			const viewText = new ViewText( 'x' );
 			viewB.appendChildren( viewText );
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
+			selection.setTo( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
 
 			renderer.markToSync( 'children', viewP );
 			renderAndExpectNoChanges( renderer, domRoot );
@@ -1072,8 +1059,7 @@ describe( 'Renderer', () => {
 
 			const viewText = new ViewText( 'x' );
 			viewB.appendChildren( viewText );
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
+			selection.setTo( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
 
 			renderer.markToSync( 'children', viewB );
 			renderer.render();
@@ -1136,8 +1122,7 @@ describe( 'Renderer', () => {
 
 			const viewText = new ViewText( 'x' );
 			viewB.appendChildren( viewText );
-			selection.removeAllRanges();
-			selection.addRange( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
+			selection.setTo( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
 
 			renderer.markToSync( 'text', viewText );
 			renderer.render();
@@ -1297,7 +1282,7 @@ describe( 'Renderer', () => {
 			// Remove filler.
 			domB.childNodes[ 0 ].data = '';
 
-			selection.removeAllRanges();
+			selection.setTo( null );
 			renderer.markToSync( 'children', viewB );
 
 			expect( () => {

+ 95 - 200
packages/ckeditor5-engine/tests/view/selection.js

@@ -56,7 +56,7 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'should return start of single range in selection', () => {
-			selection.addRange( range1 );
+			selection.setTo( range1 );
 			const anchor = selection.anchor;
 
 			expect( anchor.isEqual( range1.start ) ).to.be.true;
@@ -64,7 +64,7 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'should return end of single range in selection when added as backward', () => {
-			selection.addRange( range1, true );
+			selection.setTo( range1, true );
 			const anchor = selection.anchor;
 
 			expect( anchor.isEqual( range1.end ) ).to.be.true;
@@ -72,8 +72,7 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'should get anchor from last inserted range', () => {
-			selection.addRange( range1 );
-			selection.addRange( range2 );
+			selection.setTo( [ range1, range2 ] );
 
 			expect( selection.anchor.isEqual( range2.start ) ).to.be.true;
 		} );
@@ -85,14 +84,14 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'should return end of single range in selection', () => {
-			selection.addRange( range1 );
+			selection.setTo( range1 );
 			const focus = selection.focus;
 
 			expect( focus.isEqual( range1.end ) ).to.be.true;
 		} );
 
 		it( 'should return start of single range in selection when added as backward', () => {
-			selection.addRange( range1, true );
+			selection.setTo( range1, true );
 			const focus = selection.focus;
 
 			expect( focus.isEqual( range1.start ) ).to.be.true;
@@ -100,8 +99,7 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'should get focus from last inserted range', () => {
-			selection.addRange( range1 );
-			selection.addRange( range2 );
+			selection.setTo( [ range1, range2 ] );
 
 			expect( selection.focus.isEqual( range2.end ) ).to.be.true;
 		} );
@@ -109,7 +107,7 @@ describe( 'Selection', () => {
 
 	describe( 'moveFocusTo', () => {
 		it( 'keeps all existing ranges when no modifications needed', () => {
-			selection.addRange( range1 );
+			selection.setTo( range1 );
 			selection.moveFocusTo( selection.focus );
 
 			expect( count( selection.getRanges() ) ).to.equal( 1 );
@@ -127,7 +125,7 @@ describe( 'Selection', () => {
 			const startPos = Position.createAt( el, 1 );
 			const endPos = Position.createAt( el, 2 );
 
-			selection.setCollapsedAt( startPos );
+			selection.setTo( startPos );
 
 			selection.moveFocusTo( endPos );
 
@@ -139,7 +137,7 @@ describe( 'Selection', () => {
 			const startPos = Position.createAt( el, 1 );
 			const endPos = Position.createAt( el, 0 );
 
-			selection.setCollapsedAt( startPos );
+			selection.setTo( startPos );
 
 			selection.moveFocusTo( endPos );
 
@@ -153,7 +151,7 @@ describe( 'Selection', () => {
 			const endPos = Position.createAt( el, 2 );
 			const newEndPos = Position.createAt( el, 3 );
 
-			selection.addRange( new Range( startPos, endPos ) );
+			selection.setTo( new Range( startPos, endPos ) );
 
 			selection.moveFocusTo( newEndPos );
 
@@ -166,7 +164,7 @@ describe( 'Selection', () => {
 			const endPos = Position.createAt( el, 2 );
 			const newEndPos = Position.createAt( el, 0 );
 
-			selection.addRange( new Range( startPos, endPos ) );
+			selection.setTo( new Range( startPos, endPos ) );
 
 			selection.moveFocusTo( newEndPos );
 
@@ -180,7 +178,7 @@ describe( 'Selection', () => {
 			const endPos = Position.createAt( el, 2 );
 			const newEndPos = Position.createAt( el, 3 );
 
-			selection.addRange( new Range( startPos, endPos ), true );
+			selection.setTo( new Range( startPos, endPos ), true );
 
 			selection.moveFocusTo( newEndPos );
 
@@ -194,7 +192,7 @@ describe( 'Selection', () => {
 			const endPos = Position.createAt( el, 2 );
 			const newEndPos = Position.createAt( el, 0 );
 
-			selection.addRange( new Range( startPos, endPos ), true );
+			selection.setTo( new Range( startPos, endPos ), true );
 
 			selection.moveFocusTo( newEndPos );
 
@@ -212,8 +210,10 @@ describe( 'Selection', () => {
 
 			const newEndPos = Position.createAt( el, 0 );
 
-			selection.addRange( new Range( startPos1, endPos1 ) );
-			selection.addRange( new Range( startPos2, endPos2 ) );
+			selection.setTo( [
+				new Range( startPos1, endPos1 ),
+				new Range( startPos2, endPos2 )
+			] );
 
 			selection.moveFocusTo( newEndPos );
 
@@ -232,7 +232,7 @@ describe( 'Selection', () => {
 			const startPos = Position.createAt( el, 1 );
 			const endPos = Position.createAt( el, 2 );
 
-			selection.addRange( new Range( startPos, endPos ) );
+			selection.setTo( new Range( startPos, endPos ) );
 
 			selection.moveFocusTo( startPos );
 
@@ -247,7 +247,7 @@ describe( 'Selection', () => {
 
 			const spy = sinon.stub( Position, 'createAt' ).returns( newEndPos );
 
-			selection.addRange( new Range( startPos, endPos ) );
+			selection.setTo( new Range( startPos, endPos ) );
 			selection.moveFocusTo( el, 'end' );
 
 			expect( spy.calledOnce ).to.be.true;
@@ -260,7 +260,7 @@ describe( 'Selection', () => {
 	describe( 'isCollapsed', () => {
 		it( 'should return true when there is single collapsed range', () => {
 			const range = Range.createFromParentsAndOffsets( el, 5, el, 5 );
-			selection.addRange( range );
+			selection.setTo( range );
 
 			expect( selection.isCollapsed ).to.be.true;
 		} );
@@ -268,15 +268,14 @@ describe( 'Selection', () => {
 		it( 'should return false when there are multiple ranges', () => {
 			const range1 = Range.createFromParentsAndOffsets( el, 5, el, 5 );
 			const range2 = Range.createFromParentsAndOffsets( el, 15, el, 15 );
-			selection.addRange( range1 );
-			selection.addRange( range2 );
+			selection.setTo( [ range1, range2 ] );
 
 			expect( selection.isCollapsed ).to.be.false;
 		} );
 
 		it( 'should return false when there is not collapsed range', () => {
 			const range = Range.createFromParentsAndOffsets( el, 15, el, 16 );
-			selection.addRange( range );
+			selection.setTo( range );
 
 			expect( selection.isCollapsed ).to.be.false;
 		} );
@@ -286,11 +285,11 @@ describe( 'Selection', () => {
 		it( 'should return proper range count', () => {
 			expect( selection.rangeCount ).to.equal( 0 );
 
-			selection.addRange( range1 );
+			selection.setTo( range1 );
 
 			expect( selection.rangeCount ).to.equal( 1 );
 
-			selection.addRange( range2 );
+			selection.setTo( [ range1, range2 ] );
 
 			expect( selection.rangeCount ).to.equal( 2 );
 		} );
@@ -301,61 +300,25 @@ describe( 'Selection', () => {
 			const range1 = Range.createFromParentsAndOffsets( el, 5, el, 10 );
 			const range2 = Range.createFromParentsAndOffsets( el, 15, el, 16 );
 
-			selection.addRange( range1, true );
+			selection.setTo( range1, true );
 			expect( selection ).to.have.property( 'isBackward', true );
 
-			selection.addRange( range2 );
+			selection.setTo( [ range1, range2 ] );
 			expect( selection ).to.have.property( 'isBackward', false );
 		} );
 
 		it( 'is false when last range is collapsed', () => {
 			const range = Range.createFromParentsAndOffsets( el, 5, el, 5 );
 
-			selection.addRange( range, true );
+			selection.setTo( range, true );
 
 			expect( selection.isBackward ).to.be.false;
 		} );
 	} );
 
-	describe( 'addRange', () => {
-		it( 'should throw an error when range is invalid', () => {
-			expect( () => {
-				selection.addRange( { invalid: 'range' } );
-			} ).to.throw( CKEditorError, 'view-selection-invalid-range: Invalid Range.' );
-		} );
-
-		it( 'should add range to selection ranges', () => {
-			selection.addRange( range1 );
-			expect( selection._ranges[ 0 ].isEqual( range1 ) ).to.be.true;
-		} );
-
-		it( 'should fire change event', done => {
-			selection.once( 'change', () => {
-				expect( selection._ranges[ 0 ].isEqual( range1 ) ).to.be.true;
-				done();
-			} );
-
-			selection.addRange( range1 );
-		} );
-
-		it( 'should throw when range is intersecting with already added range', () => {
-			const text = el.getChild( 0 );
-			const range2 = Range.createFromParentsAndOffsets( text, 7, text, 15 );
-			selection.addRange( range1 );
-			expect( () => {
-				selection.addRange( range2 );
-			} ).to.throw( CKEditorError, 'view-selection-range-intersects' );
-
-			expect( () => {
-				selection.addRange( range1 );
-			} ).to.throw( CKEditorError, 'view-selection-range-intersects' );
-		} );
-	} );
-
 	describe( 'getRanges', () => {
 		it( 'should return iterator with copies of all ranges', () => {
-			selection.addRange( range1 );
-			selection.addRange( range2 );
+			selection.setTo( [ range1, range2 ] );
 
 			const iterable = selection.getRanges();
 			const ranges = Array.from( iterable );
@@ -370,9 +333,7 @@ describe( 'Selection', () => {
 
 	describe( 'getFirstRange', () => {
 		it( 'should return copy of range with first position', () => {
-			selection.addRange( range1 );
-			selection.addRange( range2 );
-			selection.addRange( range3 );
+			selection.setTo( [ range1, range2, range3 ] );
 
 			const range = selection.getFirstRange();
 
@@ -387,9 +348,7 @@ describe( 'Selection', () => {
 
 	describe( 'getLastRange', () => {
 		it( 'should return copy of range with last position', () => {
-			selection.addRange( range1 );
-			selection.addRange( range2 );
-			selection.addRange( range3 );
+			selection.setTo( [ range1, range2, range3 ] );
 
 			const range = selection.getLastRange();
 
@@ -404,9 +363,7 @@ describe( 'Selection', () => {
 
 	describe( 'getFirstPosition', () => {
 		it( 'should return copy of first position', () => {
-			selection.addRange( range1 );
-			selection.addRange( range2 );
-			selection.addRange( range3 );
+			selection.setTo( [ range1, range2, range3 ] );
 
 			const position = selection.getFirstPosition();
 
@@ -421,9 +378,7 @@ describe( 'Selection', () => {
 
 	describe( 'getLastPosition', () => {
 		it( 'should return copy of range with last position', () => {
-			selection.addRange( range1 );
-			selection.addRange( range2 );
-			selection.addRange( range3 );
+			selection.setTo( [ range1, range2, range3 ] );
 
 			const position = selection.getLastPosition();
 
@@ -438,51 +393,42 @@ describe( 'Selection', () => {
 
 	describe( 'isEqual', () => {
 		it( 'should return true if selections equal', () => {
-			selection.addRange( range1 );
-			selection.addRange( range2 );
+			selection.setTo( [ range1, range2 ] );
 
 			const otherSelection = new Selection();
-			otherSelection.addRange( range1 );
-			otherSelection.addRange( range2 );
+			otherSelection.setTo( [ range1, range2 ] );
 
 			expect( selection.isEqual( otherSelection ) ).to.be.true;
 		} );
 
 		it( 'should return true if backward selections equal', () => {
-			selection.addRange( range1, true );
+			selection.setTo( range1, true );
 
-			const otherSelection = new Selection();
-			otherSelection.addRange( range1, true );
+			const otherSelection = new Selection( [ range1 ], true );
 
 			expect( selection.isEqual( otherSelection ) ).to.be.true;
 		} );
 
 		it( 'should return false if ranges count does not equal', () => {
-			selection.addRange( range1 );
-			selection.addRange( range2 );
+			selection.setTo( [ range1, range2 ] );
 
-			const otherSelection = new Selection();
-			otherSelection.addRange( range1 );
+			const otherSelection = new Selection( [ range1 ] );
 
 			expect( selection.isEqual( otherSelection ) ).to.be.false;
 		} );
 
 		it( 'should return false if ranges (other than the last added one) do not equal', () => {
-			selection.addRange( range1 );
-			selection.addRange( range3 );
+			selection.setTo( [ range1, range3 ] );
 
-			const otherSelection = new Selection();
-			otherSelection.addRange( range2 );
-			otherSelection.addRange( range3 );
+			const otherSelection = new Selection( [ range2, range3 ] );
 
 			expect( selection.isEqual( otherSelection ) ).to.be.false;
 		} );
 
 		it( 'should return false if directions do not equal', () => {
-			selection.addRange( range1 );
+			selection.setTo( range1 );
 
-			const otherSelection = new Selection();
-			otherSelection.addRange( range1, true );
+			const otherSelection = new Selection( [ range1 ], true );
 
 			expect( selection.isEqual( otherSelection ) ).to.be.false;
 		} );
@@ -495,21 +441,19 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'should return true if both selection are fake', () => {
-			const otherSelection = new Selection();
-			otherSelection.addRange( range1 );
+			const otherSelection = new Selection( [ range1 ] );
 			otherSelection.setFake( true );
 			selection.setFake( true );
-			selection.addRange( range1 );
+			selection.setTo( range1 );
 
 			expect( selection.isEqual( otherSelection ) ).to.be.true;
 		} );
 
 		it( 'should return false if both selection are fake but have different label', () => {
-			const otherSelection = new Selection();
-			otherSelection.addRange( range1 );
+			const otherSelection = new Selection( [ range1 ] );
 			otherSelection.setFake( true, { label: 'foo bar baz' } );
 			selection.setFake( true );
-			selection.addRange( range1 );
+			selection.setTo( range1 );
 
 			expect( selection.isEqual( otherSelection ) ).to.be.false;
 		} );
@@ -523,42 +467,33 @@ describe( 'Selection', () => {
 
 	describe( 'isSimilar', () => {
 		it( 'should return true if selections equal', () => {
-			selection.addRange( range1 );
-			selection.addRange( range2 );
+			selection.setTo( [ range1, range2 ] );
 
-			const otherSelection = new Selection();
-			otherSelection.addRange( range1 );
-			otherSelection.addRange( range2 );
+			const otherSelection = new Selection( [ range1, range2 ] );
 
 			expect( selection.isSimilar( otherSelection ) ).to.be.true;
 		} );
 
 		it( 'should return false if ranges count does not equal', () => {
-			selection.addRange( range1 );
-			selection.addRange( range2 );
+			selection.setTo( [ range1, range2 ] );
 
-			const otherSelection = new Selection();
-			otherSelection.addRange( range1 );
+			const otherSelection = new Selection( [ range1 ] );
 
 			expect( selection.isSimilar( otherSelection ) ).to.be.false;
 		} );
 
 		it( 'should return false if trimmed ranges (other than the last added one) are not equal', () => {
-			selection.addRange( range1 );
-			selection.addRange( range3 );
+			selection.setTo( [ range1, range3 ] );
 
-			const otherSelection = new Selection();
-			otherSelection.addRange( range2 );
-			otherSelection.addRange( range3 );
+			const otherSelection = new Selection( [ range2, range3 ] );
 
 			expect( selection.isSimilar( otherSelection ) ).to.be.false;
 		} );
 
 		it( 'should return false if directions are not equal', () => {
-			selection.addRange( range1 );
+			selection.setTo( range1 );
 
-			const otherSelection = new Selection();
-			otherSelection.addRange( range1, true );
+			const otherSelection = new Selection( [ range1 ], true );
 
 			expect( selection.isSimilar( otherSelection ) ).to.be.false;
 		} );
@@ -586,12 +521,9 @@ describe( 'Selection', () => {
 			const rangeA2 = Range.createFromParentsAndOffsets( p2, 0, p2, 1 );
 			const rangeB2 = Range.createFromParentsAndOffsets( span2, 0, span2, 1 );
 
-			selection.addRange( rangeA1 );
-			selection.addRange( rangeA2 );
+			selection.setTo( [ rangeA1, rangeA2 ] );
 
-			const otherSelection = new Selection();
-			otherSelection.addRange( rangeB2 );
-			otherSelection.addRange( rangeB1 );
+			const otherSelection = new Selection( [ rangeB2, rangeB1 ] );
 
 			expect( selection.isSimilar( otherSelection ) ).to.be.true;
 			expect( otherSelection.isSimilar( selection ) ).to.be.true;
@@ -601,37 +533,36 @@ describe( 'Selection', () => {
 		} );
 	} );
 
-	describe( 'removeAllRanges()', () => {
+	describe( 'setTo - removeAllRanges', () => {
 		it( 'should remove all ranges and fire change event', done => {
-			selection.addRange( range1 );
-			selection.addRange( range2 );
+			selection.setTo( [ range1, range2 ] );
 
 			selection.once( 'change', () => {
 				expect( selection.rangeCount ).to.equal( 0 );
 				done();
 			} );
 
-			selection.removeAllRanges();
+			selection.setTo( null );
 		} );
 
 		it( 'should do nothing when no ranges are present', () => {
 			const fireSpy = sinon.spy( selection, 'fire' );
-			selection.removeAllRanges();
+			selection.setTo( null );
 
 			fireSpy.restore();
 			expect( fireSpy.notCalled ).to.be.true;
 		} );
 	} );
 
-	describe( 'setRanges()', () => {
+	describe( '_setRanges()', () => {
 		it( 'should throw an error when range is invalid', () => {
 			expect( () => {
-				selection.setRanges( [ { invalid: 'range' } ] );
+				selection._setRanges( [ { invalid: 'range' } ] );
 			} ).to.throw( CKEditorError, 'view-selection-invalid-range: Invalid Range.' );
 		} );
 
 		it( 'should add ranges and fire change event', done => {
-			selection.addRange( range1 );
+			selection.setTo( range1 );
 
 			selection.once( 'change', () => {
 				expect( selection.rangeCount ).to.equal( 2 );
@@ -642,17 +573,15 @@ describe( 'Selection', () => {
 				done();
 			} );
 
-			selection.setRanges( [ range2, range3 ] );
+			selection._setRanges( [ range2, range3 ] );
 		} );
 	} );
 
 	describe( 'setTo()', () => {
 		it( 'should set selection ranges from the given selection', () => {
-			selection.addRange( range1 );
+			selection.setTo( range1 );
 
-			const otherSelection = new Selection();
-			otherSelection.addRange( range2 );
-			otherSelection.addRange( range3, true );
+			const otherSelection = new Selection( [ range2, range3 ], true );
 
 			selection.setTo( otherSelection );
 
@@ -665,30 +594,30 @@ describe( 'Selection', () => {
 			expect( selection.anchor.isEqual( range3.end ) ).to.be.true;
 		} );
 
-		it( 'should set selection on the given Range using setRanges method', () => {
-			const spy = sinon.spy( selection, 'setRanges' );
+		it( 'should set selection on the given Range using _setRanges method', () => {
+			const spy = sinon.spy( selection, '_setRanges' );
 
 			selection.setTo( range1 );
 
 			expect( Array.from( selection.getRanges() ) ).to.deep.equal( [ range1 ] );
 			expect( selection.isBackward ).to.be.false;
-			expect( selection.setRanges.calledOnce ).to.be.true;
+			expect( selection._setRanges.calledOnce ).to.be.true;
 			spy.restore();
 		} );
 
-		it( 'should set selection on the given iterable of Ranges using setRanges method', () => {
-			const spy = sinon.spy( selection, 'setRanges' );
+		it( 'should set selection on the given iterable of Ranges using _setRanges method', () => {
+			const spy = sinon.spy( selection, '_setRanges' );
 
 			selection.setTo( new Set( [ range1, range2 ] ) );
 
 			expect( Array.from( selection.getRanges() ) ).to.deep.equal( [ range1, range2 ] );
 			expect( selection.isBackward ).to.be.false;
-			expect( selection.setRanges.calledOnce ).to.be.true;
+			expect( selection._setRanges.calledOnce ).to.be.true;
 			spy.restore();
 		} );
 
-		it( 'should set collapsed selection on the given Position using setRanges method', () => {
-			const spy = sinon.spy( selection, 'setRanges' );
+		it( 'should set collapsed selection on the given Position using _setRanges method', () => {
+			const spy = sinon.spy( selection, '_setRanges' );
 
 			selection.setTo( range1.start );
 
@@ -696,7 +625,7 @@ describe( 'Selection', () => {
 			expect( Array.from( selection.getRanges() )[ 0 ].start ).to.deep.equal( range1.start );
 			expect( selection.isBackward ).to.be.false;
 			expect( selection.isCollapsed ).to.be.true;
-			expect( selection.setRanges.calledOnce ).to.be.true;
+			expect( selection._setRanges.calledOnce ).to.be.true;
 			spy.restore();
 		} );
 
@@ -707,8 +636,7 @@ describe( 'Selection', () => {
 				done();
 			} );
 
-			const otherSelection = new Selection();
-			otherSelection.addRange( range1 );
+			const otherSelection = new Selection( [ range1 ] );
 
 			selection.setTo( otherSelection );
 		} );
@@ -724,48 +652,15 @@ describe( 'Selection', () => {
 		} );
 	} );
 
-	describe( 'setIn()', () => {
-		it( 'should set selection inside an element', () => {
-			const element = new Element( 'p', null, [ new Text( 'foo' ), new Text( 'bar' ) ] );
-
-			selection.setIn( element );
-
-			const ranges = Array.from( selection.getRanges() );
-			expect( ranges.length ).to.equal( 1 );
-			expect( ranges[ 0 ].start.parent ).to.equal( element );
-			expect( ranges[ 0 ].start.offset ).to.deep.equal( 0 );
-			expect( ranges[ 0 ].end.parent ).to.equal( element );
-			expect( ranges[ 0 ].end.offset ).to.deep.equal( 2 );
-		} );
-	} );
-
-	describe( 'setOn()', () => {
-		it( 'should set selection on an item', () => {
-			const textNode1 = new Text( 'foo' );
-			const textNode2 = new Text( 'bar' );
-			const textNode3 = new Text( 'baz' );
-			const element = new Element( 'p', null, [ textNode1, textNode2, textNode3 ] );
-
-			selection.setOn( textNode2 );
-
-			const ranges = Array.from( selection.getRanges() );
-			expect( ranges.length ).to.equal( 1 );
-			expect( ranges[ 0 ].start.parent ).to.equal( element );
-			expect( ranges[ 0 ].start.offset ).to.deep.equal( 1 );
-			expect( ranges[ 0 ].end.parent ).to.equal( element );
-			expect( ranges[ 0 ].end.offset ).to.deep.equal( 2 );
-		} );
-	} );
-
-	describe( 'setCollapsedAt()', () => {
+	describe( 'setTo - set collapsed at', () => {
 		beforeEach( () => {
-			selection.setRanges( [ range1, range2 ] );
+			selection.setTo( [ range1, range2 ] );
 		} );
 
 		it( 'should collapse selection at position', () => {
 			const position = new Position( el, 4 );
 
-			selection.setCollapsedAt( position );
+			selection.setTo( position );
 			const range = selection.getFirstRange();
 
 			expect( range.start.parent ).to.equal( el );
@@ -777,14 +672,14 @@ describe( 'Selection', () => {
 			const foo = new Text( 'foo' );
 			const p = new Element( 'p', null, foo );
 
-			selection.setCollapsedAt( foo );
+			selection.setTo( foo );
 			let range = selection.getFirstRange();
 
 			expect( range.start.parent ).to.equal( foo );
 			expect( range.start.offset ).to.equal( 0 );
 			expect( range.start.isEqual( range.end ) ).to.be.true;
 
-			selection.setCollapsedAt( p, 1 );
+			selection.setTo( p, 1 );
 			range = selection.getFirstRange();
 
 			expect( range.start.parent ).to.equal( p );
@@ -796,21 +691,21 @@ describe( 'Selection', () => {
 			const foo = new Text( 'foo' );
 			const p = new Element( 'p', null, foo );
 
-			selection.setCollapsedAt( foo, 'end' );
+			selection.setTo( foo, 'end' );
 			let range = selection.getFirstRange();
 
 			expect( range.start.parent ).to.equal( foo );
 			expect( range.start.offset ).to.equal( 3 );
 			expect( range.start.isEqual( range.end ) ).to.be.true;
 
-			selection.setCollapsedAt( foo, 'before' );
+			selection.setTo( foo, 'before' );
 			range = selection.getFirstRange();
 
 			expect( range.start.parent ).to.equal( p );
 			expect( range.start.offset ).to.equal( 0 );
 			expect( range.start.isEqual( range.end ) ).to.be.true;
 
-			selection.setCollapsedAt( foo, 'after' );
+			selection.setTo( foo, 'after' );
 			range = selection.getFirstRange();
 
 			expect( range.start.parent ).to.equal( p );
@@ -819,9 +714,9 @@ describe( 'Selection', () => {
 		} );
 	} );
 
-	describe( 'collapseToStart()', () => {
+	describe( 'setTo - collapse at start', () => {
 		it( 'should collapse to start position and fire change event', done => {
-			selection.setRanges( [ range1, range2, range3 ] );
+			selection.setTo( [ range1, range2, range3 ] );
 			selection.once( 'change', () => {
 				expect( selection.rangeCount ).to.equal( 1 );
 				expect( selection.isCollapsed ).to.be.true;
@@ -829,22 +724,22 @@ describe( 'Selection', () => {
 				done();
 			} );
 
-			selection.collapseToStart();
+			selection.setTo( selection.getFirstPosition() );
 		} );
 
 		it( 'should do nothing if no ranges present', () => {
 			const fireSpy = sinon.spy( selection, 'fire' );
 
-			selection.collapseToStart();
+			selection.setTo( selection.getFirstPosition() );
 
 			fireSpy.restore();
 			expect( fireSpy.notCalled ).to.be.true;
 		} );
 	} );
 
-	describe( 'collapseToEnd()', () => {
+	describe( 'setTo - collapse to end', () => {
 		it( 'should collapse to end position and fire change event', done => {
-			selection.setRanges( [ range1, range2, range3 ] );
+			selection.setTo( [ range1, range2, range3 ] );
 			selection.once( 'change', () => {
 				expect( selection.rangeCount ).to.equal( 1 );
 				expect( selection.isCollapsed ).to.be.true;
@@ -852,13 +747,13 @@ describe( 'Selection', () => {
 				done();
 			} );
 
-			selection.collapseToEnd();
+			selection.setTo( selection.getLastPosition() );
 		} );
 
 		it( 'should do nothing if no ranges present', () => {
 			const fireSpy = sinon.spy( selection, 'fire' );
 
-			selection.collapseToEnd();
+			selection.setTo( selection.getLastPosition() );
 
 			fireSpy.restore();
 			expect( fireSpy.notCalled ).to.be.true;
@@ -871,7 +766,7 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'should return null if selection is placed in container that is not EditableElement', () => {
-			selection.addRange( range1 );
+			selection.setTo( range1 );
 
 			expect( selection.editableElement ).to.be.null;
 		} );
@@ -883,7 +778,7 @@ describe( 'Selection', () => {
 			const element = new Element( 'p' );
 			root.appendChildren( element );
 
-			selection.addRange( Range.createFromParentsAndOffsets( element, 0, element, 0 ) );
+			selection.setTo( Range.createFromParentsAndOffsets( element, 0, element, 0 ) );
 
 			expect( selection.editableElement ).to.equal( root );
 
@@ -893,7 +788,7 @@ describe( 'Selection', () => {
 
 	describe( 'createFromSelection', () => {
 		it( 'should return a Selection instance with same ranges and direction as given selection', () => {
-			selection.setRanges( [ range1, range2 ], true );
+			selection.setTo( [ range1, range2 ], true );
 
 			const snapshot = Selection.createFromSelection( selection );