Explorar o código

Merge pull request #1585 from ckeditor/t/1555

Other: Moved `Position`, `Range` and `Selection` factories from those classes to the model/view writers and `Model`/`View` instances. Previously, those factories were available as static methods of the `Position`, `Range` and `Selection` classes which meant that you needed to import those classes to your plugin's code to create new instances. That required your package to depend on `@ckeditor/ckeditor5-engine` and was not very useful in general. After this change, you can create instances of those classes without importing anything. See the "Breaking changes" section for more details. Closes #1555.

BREAKING CHANGE: The model `Position.createAt()` method was removed from the public API. Use `writer.createPositionAt()` instead. This method is also available on the `Model` instance.
BREAKING CHANGE: The model `Position.createAfter()` method was removed from the public API. Use `writer.createPositionAfter()` instead. This method is also available on the `Model` instance.
BREAKING CHANGE: The model `Position.createBefore()` method was removed from the public API. Use `writer.createPositionBefore()` instead. This method is also available on the `Model` instance.
BREAKING CHANGE: The model `Position.createFromPosition()` method was removed. Use `writer.createPositionAt( position )` to create a new position instance. This method is also available on the `Model` instance.
BREAKING CHANGE: The model `Position.createFromParentAndOffset()` method was removed. Use `writer.createPositionAt( parent, offset )` instead. This method is also available on the `Model` instance.

BREAKING CHANGE: The model `Range.createIn()` method was removed from the public API. Use `writer.createRangeIn()` instead. This method is also available on the `Model` instance.
BREAKING CHANGE: The model `Range.createOn()` method was removed from the public API. Use `writer.createRangeOn()` instead. This method is also available on the `Model` instance.
BREAKING CHANGE: The model `Range.createFromRange()` method was removed from the public API.
BREAKING CHANGE: The model `Range.createFromParentsAndOffsets()` method was removed from the public API.
BREAKING CHANGE: The model `Range.createFromPositionAndShift()` method was removed from the public API.
BREAKING CHANGE: The model `Range.createCollapsedAt()` method removed method was removed. Use `writer.createRange( position )` to create collapsed range. This method is also available on the `Model` instance.
BREAKING CHANGE: The model `Range.createFromRanges()` method was removed from the public API.

BREAKING CHANGE: The view `Position.createAt()` method was removed from the public API. Use `writer.createPositionAt()` instead. This method is also available on the `View` instance.
BREAKING CHANGE: The view `Position.createAfter()` method was removed from the public API. Use `writer.createPositionAfter()` instead. This method is also available on the `View` instance.
BREAKING CHANGE: The view `Position.createBefore()` method was removed from the public API. Use `writer.createPositionBefore()` instead. This method is also available on the `View` instance.
BREAKING CHANGE: The view `Position.createFromPosition()` method was removed. Use `writer.createPositionAt( position )` to create a new position instance. This method is also available on the `View` instance.

BREAKING CHANGE: The view `Range.createIn()` method was removed from the public API. Use `writer.createRangeIn()` instead. This method is also available on the `View` instance.
BREAKING CHANGE: The view `Range.createOn()` method was removed from the public API. Use `writer.createRangeOn()` instead. This method is also available on the `View` instance.
BREAKING CHANGE: The view `Range.createFromRange()` method was removed from the public API.
BREAKING CHANGE: The view `Range.createFromPositionAndShift()` method was removed from the public API.
BREAKING CHANGE: The view `Range.createFromParentsAndOffsets()` method was removed from the public API.
BREAKING CHANGE: The view `Range.createCollapsedAt()` method removed method was removed. Use `writer.createRange( position )` to create a collapsed range. This method is also available on the `View` instance.
Piotrek Koszuliński %!s(int64=7) %!d(string=hai) anos
pai
achega
893d1e2981
Modificáronse 100 ficheiros con 2422 adicións e 1539 borrados
  1. 3 3
      packages/ckeditor5-engine/src/controller/datacontroller.js
  2. 5 6
      packages/ckeditor5-engine/src/conversion/downcast-converters.js
  3. 4 4
      packages/ckeditor5-engine/src/conversion/downcastdispatcher.js
  4. 1 1
      packages/ckeditor5-engine/src/conversion/mapper.js
  5. 5 6
      packages/ckeditor5-engine/src/conversion/upcast-converters.js
  6. 13 7
      packages/ckeditor5-engine/src/conversion/upcastdispatcher.js
  7. 2 2
      packages/ckeditor5-engine/src/dev-utils/enableenginedebug.js
  8. 8 8
      packages/ckeditor5-engine/src/dev-utils/model.js
  9. 5 5
      packages/ckeditor5-engine/src/dev-utils/view.js
  10. 8 8
      packages/ckeditor5-engine/src/model/differ.js
  11. 4 5
      packages/ckeditor5-engine/src/model/document.js
  12. 4 4
      packages/ckeditor5-engine/src/model/documentselection.js
  13. 23 18
      packages/ckeditor5-engine/src/model/liveposition.js
  14. 31 20
      packages/ckeditor5-engine/src/model/liverange.js
  15. 5 7
      packages/ckeditor5-engine/src/model/markercollection.js
  16. 212 7
      packages/ckeditor5-engine/src/model/model.js
  17. 1 1
      packages/ckeditor5-engine/src/model/operation/attributeoperation.js
  18. 2 3
      packages/ckeditor5-engine/src/model/operation/detachoperation.js
  19. 1 1
      packages/ckeditor5-engine/src/model/operation/insertoperation.js
  20. 2 2
      packages/ckeditor5-engine/src/model/operation/markeroperation.js
  21. 5 5
      packages/ckeditor5-engine/src/model/operation/mergeoperation.js
  22. 3 3
      packages/ckeditor5-engine/src/model/operation/moveoperation.js
  23. 2 2
      packages/ckeditor5-engine/src/model/operation/renameoperation.js
  24. 6 5
      packages/ckeditor5-engine/src/model/operation/splitoperation.js
  25. 24 24
      packages/ckeditor5-engine/src/model/operation/transform.js
  26. 69 78
      packages/ckeditor5-engine/src/model/position.js
  27. 60 76
      packages/ckeditor5-engine/src/model/range.js
  28. 15 5
      packages/ckeditor5-engine/src/model/schema.js
  29. 35 34
      packages/ckeditor5-engine/src/model/selection.js
  30. 6 9
      packages/ckeditor5-engine/src/model/treewalker.js
  31. 6 8
      packages/ckeditor5-engine/src/model/utils/deletecontent.js
  32. 8 11
      packages/ckeditor5-engine/src/model/utils/getselectedcontent.js
  33. 17 18
      packages/ckeditor5-engine/src/model/utils/insertcontent.js
  34. 2 2
      packages/ckeditor5-engine/src/model/utils/modifyselection.js
  35. 4 4
      packages/ckeditor5-engine/src/model/utils/selection-post-fixer.js
  36. 123 28
      packages/ckeditor5-engine/src/model/writer.js
  37. 17 22
      packages/ckeditor5-engine/src/view/documentselection.js
  38. 2 2
      packages/ckeditor5-engine/src/view/domconverter.js
  39. 181 34
      packages/ckeditor5-engine/src/view/downcastwriter.js
  40. 11 0
      packages/ckeditor5-engine/src/view/editableelement.js
  41. 35 24
      packages/ckeditor5-engine/src/view/position.js
  42. 29 43
      packages/ckeditor5-engine/src/view/range.js
  43. 1 1
      packages/ckeditor5-engine/src/view/renderer.js
  44. 47 45
      packages/ckeditor5-engine/src/view/selection.js
  45. 21 21
      packages/ckeditor5-engine/src/view/treewalker.js
  46. 153 6
      packages/ckeditor5-engine/src/view/upcastwriter.js
  47. 144 0
      packages/ckeditor5-engine/src/view/view.js
  48. 5 5
      packages/ckeditor5-engine/tests/controller/datacontroller.js
  49. 29 22
      packages/ckeditor5-engine/tests/controller/editingcontroller.js
  50. 4 2
      packages/ckeditor5-engine/tests/conversion/conversion.js
  51. 40 30
      packages/ckeditor5-engine/tests/conversion/downcast-converters.js
  52. 25 28
      packages/ckeditor5-engine/tests/conversion/downcast-selection-converters.js
  53. 48 43
      packages/ckeditor5-engine/tests/conversion/downcastdispatcher.js
  54. 4 4
      packages/ckeditor5-engine/tests/conversion/mapper.js
  55. 4 4
      packages/ckeditor5-engine/tests/conversion/upcast-converters.js
  56. 7 7
      packages/ckeditor5-engine/tests/conversion/upcast-selection-converters.js
  57. 15 15
      packages/ckeditor5-engine/tests/conversion/upcastdispatcher.js
  58. 19 19
      packages/ckeditor5-engine/tests/dev-utils/enableenginedebug.js
  59. 10 8
      packages/ckeditor5-engine/tests/dev-utils/model.js
  60. 34 34
      packages/ckeditor5-engine/tests/dev-utils/view.js
  61. 2 5
      packages/ckeditor5-engine/tests/manual/highlight.js
  62. 1 1
      packages/ckeditor5-engine/tests/manual/markers.js
  63. 2 2
      packages/ckeditor5-engine/tests/manual/tickets/475/1.js
  64. 1 1
      packages/ckeditor5-engine/tests/manual/tickets/ckeditor5-721/1.js
  65. 2 1
      packages/ckeditor5-engine/tests/model/_utils/utils.js
  66. 85 85
      packages/ckeditor5-engine/tests/model/differ.js
  67. 8 9
      packages/ckeditor5-engine/tests/model/document.js
  68. 20 20
      packages/ckeditor5-engine/tests/model/documentselection.js
  69. 25 28
      packages/ckeditor5-engine/tests/model/liveposition.js
  70. 34 46
      packages/ckeditor5-engine/tests/model/liverange.js
  71. 12 12
      packages/ckeditor5-engine/tests/model/markercollection.js
  72. 76 5
      packages/ckeditor5-engine/tests/model/model.js
  73. 5 5
      packages/ckeditor5-engine/tests/model/operation/detachoperation.js
  74. 3 4
      packages/ckeditor5-engine/tests/model/operation/markeroperation.js
  75. 5 5
      packages/ckeditor5-engine/tests/model/operation/renameoperation.js
  76. 18 18
      packages/ckeditor5-engine/tests/model/operation/transform.js
  77. 4 4
      packages/ckeditor5-engine/tests/model/operation/transform/utils.js
  78. 13 13
      packages/ckeditor5-engine/tests/model/operation/utils.js
  79. 105 96
      packages/ckeditor5-engine/tests/model/position.js
  80. 26 56
      packages/ckeditor5-engine/tests/model/range.js
  81. 28 21
      packages/ckeditor5-engine/tests/model/schema.js
  82. 30 44
      packages/ckeditor5-engine/tests/model/selection.js
  83. 18 18
      packages/ckeditor5-engine/tests/model/treewalker.js
  84. 1 1
      packages/ckeditor5-engine/tests/model/utils-tests/utils.js
  85. 4 5
      packages/ckeditor5-engine/tests/model/utils/insertcontent.js
  86. 2 3
      packages/ckeditor5-engine/tests/model/utils/modifyselection.js
  87. 69 50
      packages/ckeditor5-engine/tests/model/utils/selection-post-fixer.js
  88. 125 29
      packages/ckeditor5-engine/tests/model/writer.js
  89. 2 2
      packages/ckeditor5-engine/tests/tickets/1267.js
  90. 4 4
      packages/ckeditor5-engine/tests/tickets/1281.js
  91. 1 2
      packages/ckeditor5-engine/tests/tickets/1323.js
  92. 2 2
      packages/ckeditor5-engine/tests/utils/bindtwostepcarettoattribute.js
  93. 48 61
      packages/ckeditor5-engine/tests/view/documentselection.js
  94. 1 1
      packages/ckeditor5-engine/tests/view/domconverter/dom-to-view.js
  95. 4 4
      packages/ckeditor5-engine/tests/view/downcastwriter/breakattributes.js
  96. 1 1
      packages/ckeditor5-engine/tests/view/downcastwriter/breakcontainer.js
  97. 2 2
      packages/ckeditor5-engine/tests/view/downcastwriter/clear.js
  98. 6 6
      packages/ckeditor5-engine/tests/view/downcastwriter/move.js
  99. 5 5
      packages/ckeditor5-engine/tests/view/downcastwriter/remove.js
  100. 13 13
      packages/ckeditor5-engine/tests/view/downcastwriter/unwrap.js

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

@@ -149,7 +149,7 @@ export default class DataController {
 		this.mapper.clearBindings();
 
 		// First, convert elements.
-		const modelRange = ModelRange.createIn( modelElementOrFragment );
+		const modelRange = ModelRange._createIn( modelElementOrFragment );
 
 		const viewDocumentFragment = new ViewDocumentFragment();
 
@@ -227,7 +227,7 @@ export default class DataController {
 			writer.setSelection( null );
 			writer.removeSelectionAttribute( this.model.document.selection.getAttributeKeys() );
 
-			writer.remove( ModelRange.createIn( modelRoot ) );
+			writer.remove( writer.createRangeIn( modelRoot ) );
 			writer.insert( this.parse( data, modelRoot ), modelRoot, 0 );
 		} );
 	}
@@ -297,7 +297,7 @@ function _getMarkersRelativeToElement( element ) {
 		return [];
 	}
 
-	const elementRange = ModelRange.createIn( element );
+	const elementRange = ModelRange._createIn( element );
 
 	for ( const marker of doc.model.markers ) {
 		const intersection = elementRange.getIntersection( marker.getRange() );

+ 5 - 6
packages/ckeditor5-engine/src/conversion/downcast-converters.js

@@ -8,7 +8,6 @@ import ModelSelection from '../model/selection';
 import ModelElement from '../model/element';
 
 import ViewAttributeElement from '../view/attributeelement';
-import ViewRange from '../view/range';
 import DocumentSelection from '../model/documentselection';
 
 import { cloneDeep } from 'lodash-es';
@@ -535,14 +534,14 @@ export function remove() {
 		const modelEnd = data.position.getShiftedBy( data.length );
 		const viewEnd = conversionApi.mapper.toViewPosition( modelEnd, { isPhantom: true } );
 
-		const viewRange = new ViewRange( viewStart, viewEnd );
+		const viewRange = conversionApi.writer.createRange( viewStart, viewEnd );
 
 		// Trim the range to remove in case some UI elements are on the view range boundaries.
 		const removed = conversionApi.writer.remove( viewRange.getTrimmed() );
 
 		// After the range is removed, unbind all view elements from the model.
 		// Range inside view document fragment is used to unbind deeply.
-		for ( const child of ViewRange.createIn( removed ).getItems() ) {
+		for ( const child of conversionApi.writer.createRangeIn( removed ).getItems() ) {
 			conversionApi.mapper.unbindViewElement( child );
 		}
 	};
@@ -628,7 +627,7 @@ export function removeUIElement() {
 		conversionApi.mapper.unbindElementsFromMarkerName( data.markerName );
 
 		for ( const element of elements ) {
-			conversionApi.writer.clear( ViewRange.createOn( element ), element );
+			conversionApi.writer.clear( conversionApi.writer.createRangeOn( element ), element );
 		}
 
 		conversionApi.writer.clearClonedElementsGroup( data.markerName );
@@ -903,7 +902,7 @@ export function highlightElement( highlightDescriptor ) {
 			conversionApi.consumable.consume( data.item, evt.name );
 
 			// Consume all children nodes.
-			for ( const value of ModelRange.createIn( data.item ) ) {
+			for ( const value of ModelRange._createIn( data.item ) ) {
 				conversionApi.consumable.consume( value.item, evt.name );
 			}
 
@@ -965,7 +964,7 @@ export function removeHighlight( highlightDescriptor ) {
 
 		for ( const element of elements ) {
 			if ( element.is( 'attributeElement' ) ) {
-				conversionApi.writer.unwrap( ViewRange.createOn( element ), viewHighlightElement );
+				conversionApi.writer.unwrap( conversionApi.writer.createRangeOn( element ), viewHighlightElement );
 			} else {
 				// if element.is( 'containerElement' ).
 				element.getCustomProperty( 'removeHighlight' )( element, descriptor.id, conversionApi.writer );

+ 4 - 4
packages/ckeditor5-engine/src/conversion/downcastdispatcher.js

@@ -131,7 +131,7 @@ export default class DowncastDispatcher {
 		// Convert changes that happened on model tree.
 		for ( const entry of differ.getChanges() ) {
 			if ( entry.type == 'insert' ) {
-				this.convertInsert( Range.createFromPositionAndShift( entry.position, entry.length ), writer );
+				this.convertInsert( Range._createFromPositionAndShift( entry.position, entry.length ), writer );
 			} else if ( entry.type == 'remove' ) {
 				this.convertRemove( entry.position, entry.length, entry.name, writer );
 			} else {
@@ -166,7 +166,7 @@ export default class DowncastDispatcher {
 		// Fire a separate insert event for each node and text fragment contained in the range.
 		for ( const value of range ) {
 			const item = value.item;
-			const itemRange = Range.createFromPositionAndShift( value.previousPosition, value.length );
+			const itemRange = Range._createFromPositionAndShift( value.previousPosition, value.length );
 			const data = {
 				item,
 				range: itemRange
@@ -226,7 +226,7 @@ export default class DowncastDispatcher {
 		// Create a separate attribute event for each node in the range.
 		for ( const value of range ) {
 			const item = value.item;
-			const itemRange = Range.createFromPositionAndShift( value.previousPosition, value.length );
+			const itemRange = Range._createFromPositionAndShift( value.previousPosition, value.length );
 			const data = {
 				item,
 				range: itemRange,
@@ -343,7 +343,7 @@ export default class DowncastDispatcher {
 				continue;
 			}
 
-			const data = { item, range: Range.createOn( item ), markerName, markerRange };
+			const data = { item, range: Range._createOn( item ), markerName, markerRange };
 
 			this.fire( eventName, data, this.conversionApi );
 		}

+ 1 - 1
packages/ckeditor5-engine/src/conversion/mapper.js

@@ -101,7 +101,7 @@ export default class Mapper {
 
 			const modelOffset = this._toModelOffset( data.viewPosition.parent, data.viewPosition.offset, viewBlock );
 
-			data.modelPosition = ModelPosition.createFromParentAndOffset( modelParent, modelOffset );
+			data.modelPosition = ModelPosition._createAt( modelParent, modelOffset );
 		}, { priority: 'low' } );
 	}
 

+ 5 - 6
packages/ckeditor5-engine/src/conversion/upcast-converters.js

@@ -6,7 +6,6 @@
 import Matcher from '../view/matcher';
 
 import ModelRange from '../model/range';
-import ModelPosition from '../model/position';
 
 import { cloneDeep } from 'lodash-es';
 
@@ -358,7 +357,7 @@ function _prepareToElementConverter( config ) {
 		conversionApi.writer.insert( modelElement, splitResult.position );
 
 		// Convert children and insert to element.
-		const childrenResult = conversionApi.convertChildren( data.viewItem, ModelPosition.createAt( modelElement, 0 ) );
+		const childrenResult = conversionApi.convertChildren( data.viewItem, conversionApi.writer.createPositionAt( modelElement, 0 ) );
 
 		// Consume appropriate value from consumable values list.
 		conversionApi.consumable.consume( data.viewItem, match.match );
@@ -366,12 +365,12 @@ function _prepareToElementConverter( config ) {
 		// Set conversion result range.
 		data.modelRange = new ModelRange(
 			// Range should start before inserted element
-			ModelPosition.createBefore( modelElement ),
+			conversionApi.writer.createPositionBefore( modelElement ),
 			// Should end after but we need to take into consideration that children could split our
 			// element, so we need to move range after parent of the last converted child.
 			// before: <allowed>[]</allowed>
 			// after: <allowed>[<converted><child></child></converted><child></child><converted>]</converted></allowed>
-			ModelPosition.createAfter( childrenResult.modelCursor.parent )
+			conversionApi.writer.createPositionAfter( childrenResult.modelCursor.parent )
 		);
 
 		// Now we need to check where the modelCursor should be.
@@ -380,7 +379,7 @@ function _prepareToElementConverter( config ) {
 		// before: <allowed><notAllowed>[]</notAllowed></allowed>
 		// after:  <allowed><notAllowed></notAllowed><converted></converted><notAllowed>[]</notAllowed></allowed>
 		if ( splitResult.cursorParent ) {
-			data.modelCursor = ModelPosition.createAt( splitResult.cursorParent, 0 );
+			data.modelCursor = conversionApi.writer.createPositionAt( splitResult.cursorParent, 0 );
 
 			// Otherwise just continue after inserted element.
 		} else {
@@ -602,7 +601,7 @@ export function convertText() {
 
 				conversionApi.writer.insert( text, data.modelCursor );
 
-				data.modelRange = ModelRange.createFromPositionAndShift( data.modelCursor, text.offsetSize );
+				data.modelRange = ModelRange._createFromPositionAndShift( data.modelCursor, text.offsetSize );
 				data.modelCursor = data.modelRange.end;
 			}
 		}

+ 13 - 7
packages/ckeditor5-engine/src/conversion/upcastdispatcher.js

@@ -71,10 +71,16 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
  *  	 				conversionApi.writer.insert( paragraph, splitResult.position );
  *
  *  	 				// Convert children to paragraph.
- *  	 				const { modelRange } = conversionApi.convertChildren( data.viewItem, Position.createAt( paragraph, 0 ) );
+ *  	 				const { modelRange } = conversionApi.convertChildren(
+ *  	 					data.viewItem,
+ *  	 					conversionApi.writer.createPositionAt( paragraph, 0 )
+ *  	 				);
  *
  * 						// Set as conversion result, attribute converters may use this property.
- *  	 				data.modelRange = new Range( Position.createBefore( paragraph ), modelRange.end );
+ *  	 				data.modelRange = conversionApi.writer.createRange(
+ *  	 					conversionApi.writer.createPositionBefore( paragraph ),
+ *  	 					modelRange.end
+ *  	 				);
  *
  *  	 				// Continue conversion inside paragraph.
  *  	 				data.modelCursor = data.modelRange.end;
@@ -372,7 +378,7 @@ function extractMarkersFromModelFragment( modelItem, writer ) {
 	const markers = new Map();
 
 	// Create ModelTreeWalker.
-	const range = ModelRange.createIn( modelItem ).getItems();
+	const range = ModelRange._createIn( modelItem ).getItems();
 
 	// Walk through DocumentFragment and collect marker elements.
 	for ( const item of range ) {
@@ -385,14 +391,14 @@ function extractMarkersFromModelFragment( modelItem, writer ) {
 	// Walk through collected marker elements store its path and remove its from the DocumentFragment.
 	for ( const markerElement of markerElements ) {
 		const markerName = markerElement.getAttribute( 'data-name' );
-		const currentPosition = ModelPosition.createBefore( markerElement );
+		const currentPosition = writer.createPositionBefore( markerElement );
 
 		// When marker of given name is not stored it means that we have found the beginning of the range.
 		if ( !markers.has( markerName ) ) {
-			markers.set( markerName, new ModelRange( ModelPosition.createFromPosition( currentPosition ) ) );
+			markers.set( markerName, new ModelRange( currentPosition.clone() ) );
 		// Otherwise is means that we have found end of the marker range.
 		} else {
-			markers.get( markerName ).end = ModelPosition.createFromPosition( currentPosition );
+			markers.get( markerName ).end = currentPosition.clone();
 		}
 
 		// Remove marker element from DocumentFragment.
@@ -419,7 +425,7 @@ function createContextTree( contextDefinition, writer ) {
 			writer.append( current, position );
 		}
 
-		position = ModelPosition.createAt( current, 0 );
+		position = ModelPosition._createAt( current, 0 );
 	}
 
 	return position;

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

@@ -311,7 +311,7 @@ function enableLoggingTools() {
 	} );
 
 	sandbox.mock( DetachOperation.prototype, 'toString', function() {
-		const range = ModelRange.createFromPositionAndShift( this.sourcePosition, this.howMany );
+		const range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany );
 		const nodes = Array.from( range.getItems() );
 		const nodeString = nodes.length > 1 ? `[ ${ nodes.length } ]` : nodes[ 0 ];
 
@@ -330,7 +330,7 @@ function enableLoggingTools() {
 	} );
 
 	sandbox.mock( MoveOperation.prototype, 'toString', function() {
-		const range = ModelRange.createFromPositionAndShift( this.sourcePosition, this.howMany );
+		const range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany );
 
 		return getClassName( this ) + `( ${ this.baseVersion } ): ${ range } -> ${ this.targetPosition }`;
 	} );

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

@@ -115,7 +115,7 @@ export function setData( model, data, options = {} ) {
 
 	model.change( writer => {
 		// Replace existing model in document by new one.
-		writer.remove( ModelRange.createIn( modelRoot ) );
+		writer.remove( writer.createRangeIn( modelRoot ) );
 		writer.insert( modelDocumentFragment, modelRoot );
 
 		// Clean up previous document selection.
@@ -169,16 +169,16 @@ export function stringify( node, selectionOrPositionOrRange = null, markers = nu
 
 	// Create a range witch wraps passed node.
 	if ( node instanceof RootElement || node instanceof ModelDocumentFragment ) {
-		range = ModelRange.createIn( node );
+		range = model.createRangeIn( node );
 	} else {
 		// Node is detached - create new document fragment.
 		if ( !node.parent ) {
 			const fragment = new ModelDocumentFragment( node );
-			range = ModelRange.createIn( fragment );
+			range = model.createRangeIn( fragment );
 		} else {
 			range = new ModelRange(
-				ModelPosition.createBefore( node ),
-				ModelPosition.createAfter( node )
+				model.createPositionBefore( node ),
+				model.createPositionAfter( node )
 			);
 		}
 	}
@@ -391,9 +391,9 @@ function convertToModelElement() {
 
 		conversionApi.mapper.bindElements( element, data.viewItem );
 
-		conversionApi.convertChildren( data.viewItem, ModelPosition.createAt( element, 0 ) );
+		conversionApi.convertChildren( data.viewItem, ModelPosition._createAt( element, 0 ) );
 
-		data.modelRange = ModelRange.createOn( element );
+		data.modelRange = ModelRange._createOn( element );
 		data.modelCursor = data.modelRange.end;
 
 		evt.stop();
@@ -420,7 +420,7 @@ function convertToModelText( withAttributes = false ) {
 
 		conversionApi.writer.insert( node, data.modelCursor );
 
-		data.modelRange = ModelRange.createFromPositionAndShift( data.modelCursor, node.offsetSize );
+		data.modelRange = ModelRange._createFromPositionAndShift( data.modelCursor, node.offsetSize );
 		data.modelCursor = data.modelRange.end;
 
 		evt.stop();

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

@@ -138,7 +138,7 @@ setData._parse = parse;
  *		const b = new Element( 'b', null, text );
  *		const p = new Element( 'p', null, b );
  *		const selection = new Selection(
- *			Range.createFromParentsAndOffsets( p, 0, p, 1 )
+ *			Range._createFromParentsAndOffsets( p, 0, p, 1 )
  *		);
  *
  *		stringify( p, selection ); // '<p>[<b>foobar</b>]</p>'
@@ -148,7 +148,7 @@ setData._parse = parse;
  *		const text = new Text( 'foobar' );
  *		const b = new Element( 'b', null, text );
  *		const p = new Element( 'p', null, b );
- *		const selection = new Selection( Range.createFromParentsAndOffsets( text, 1, text, 5 ) );
+ *		const selection = new Selection( Range._createFromParentsAndOffsets( text, 1, text, 5 ) );
  *
  *		stringify( p, selection ); // '<p><b>f{ooba}r</b></p>'
  *
@@ -161,8 +161,8 @@ setData._parse = parse;
  *
  *		const text = new Text( 'foobar' );
  *		const selection = new Selection( [
- *			Range.createFromParentsAndOffsets( text, 0, text, 1 ) ),
- *			Range.createFromParentsAndOffsets( text, 3, text, 5 ) )
+ *			Range._createFromParentsAndOffsets( text, 0, text, 1 ) ),
+ *			Range._createFromParentsAndOffsets( text, 3, text, 5 ) )
  *		] );
  *
  *		stringify( text, selection ); // '{f}oo{ba}r'
@@ -173,7 +173,7 @@ setData._parse = parse;
  * be converted to a selection containing one range collapsed at this position.
  *
  *		const text = new Text( 'foobar' );
- *		const range = Range.createFromParentsAndOffsets( text, 0, text, 1 );
+ *		const range = Range._createFromParentsAndOffsets( text, 0, text, 1 );
  *		const position = new Position( text, 3 );
  *
  *		stringify( text, range ); // '{f}oobar'

+ 8 - 8
packages/ckeditor5-engine/src/model/differ.js

@@ -170,7 +170,7 @@ export default class Differ {
 				this._markRemove( operation.position.parent, operation.position.offset, 1 );
 				this._markInsert( operation.position.parent, operation.position.offset, 1 );
 
-				const range = Range.createFromPositionAndShift( operation.position, 1 );
+				const range = Range._createFromPositionAndShift( operation.position, 1 );
 
 				for ( const marker of this._markerCollection.getMarkersIntersectingRange( range ) ) {
 					const markerRange = marker.getRange();
@@ -391,10 +391,10 @@ export default class Differ {
 					let range;
 
 					if ( elementChildren[ i ].name == '$text' ) {
-						range = Range.createFromParentsAndOffsets( element, i, element, i + 1 );
+						range = new Range( Position._createAt( element, i ), Position._createAt( element, i + 1 ) );
 					} else {
 						const index = element.offsetToIndex( i );
-						range = Range.createFromParentsAndOffsets( element, i, element.getChild( index ), 0 );
+						range = new Range( Position._createAt( element, i ), Position._createAt( element.getChild( index ), 0 ) );
 					}
 
 					// Generate diff items for this change (there might be multiple attributes changed and
@@ -826,7 +826,7 @@ export default class Differ {
 	_getInsertDiff( parent, offset, name ) {
 		return {
 			type: 'insert',
-			position: Position.createFromParentAndOffset( parent, offset ),
+			position: Position._createAt( parent, offset ),
 			name,
 			length: 1,
 			changeCount: this._changeCount++
@@ -845,7 +845,7 @@ export default class Differ {
 	_getRemoveDiff( parent, offset, name ) {
 		return {
 			type: 'remove',
-			position: Position.createFromParentAndOffset( parent, offset ),
+			position: Position._createAt( parent, offset ),
 			name,
 			length: 1,
 			changeCount: this._changeCount++
@@ -879,7 +879,7 @@ export default class Differ {
 				diffs.push( {
 					type: 'attribute',
 					position: range.start,
-					range: Range.createFromRange( range ),
+					range: range.clone(),
 					length: 1,
 					attributeKey: key,
 					attributeOldValue: oldValue,
@@ -898,7 +898,7 @@ export default class Differ {
 			diffs.push( {
 				type: 'attribute',
 				position: range.start,
-				range: Range.createFromRange( range ),
+				range: range.clone(),
 				length: 1,
 				attributeKey: key,
 				attributeOldValue: null,
@@ -948,7 +948,7 @@ export default class Differ {
 	 * @param {Number} howMany
 	 */
 	_removeAllNestedChanges( parent, offset, howMany ) {
-		const range = Range.createFromParentsAndOffsets( parent, offset, parent, offset + howMany );
+		const range = new Range( Position._createAt( parent, offset ), Position._createAt( parent, offset + howMany ) );
 
 		for ( const item of range.getItems( { shallow: true } ) ) {
 			if ( item.is( 'element' ) ) {

+ 4 - 5
packages/ckeditor5-engine/src/model/document.js

@@ -8,8 +8,6 @@
  */
 
 import Differ from './differ';
-import Range from './range';
-import Position from './position';
 import RootElement from './rootelement';
 import History from './history';
 import DocumentSelection from './documentselection';
@@ -334,14 +332,15 @@ export default class Document {
 	 */
 	_getDefaultRange() {
 		const defaultRoot = this._getDefaultRoot();
-		const schema = this.model.schema;
+		const model = this.model;
+		const schema = model.schema;
 
 		// Find the first position where the selection can be put.
-		const position = new Position( defaultRoot, [ 0 ] );
+		const position = model.createPositionFromPath( defaultRoot, [ 0 ] );
 		const nearestRange = schema.getNearestSelectionRange( position );
 
 		// If valid selection range is not found - return range collapsed at the beginning of the root.
-		return nearestRange || new Range( position );
+		return nearestRange || model.createRange( position );
 	}
 
 	/**

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

@@ -11,7 +11,6 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
 import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
 
 import Selection from './selection';
-import Position from './position';
 import LiveRange from './liverange';
 import Text from './text';
 import TextProxy from './textproxy';
@@ -332,7 +331,8 @@ export default class DocumentSelection {
 	 * Moves {@link module:engine/model/documentselection~DocumentSelection#focus} to the specified location.
 	 * Should be used only within the {@link module:engine/model/writer~Writer#setSelectionFocus} method.
 	 *
-	 * The location can be specified in the same form as {@link module:engine/model/position~Position.createAt} parameters.
+	 * The location can be specified in the same form as
+	 * {@link module:engine/model/writer~Writer#createPositionAt writer.createPositionAt()} parameters.
 	 *
 	 * @see module:engine/model/writer~Writer#setSelectionFocus
 	 * @protected
@@ -750,7 +750,7 @@ class LiveSelection extends Selection {
 			return;
 		}
 
-		const liveRange = LiveRange.createFromRange( range );
+		const liveRange = LiveRange.fromRange( range );
 
 		liveRange.on( 'change:range', ( evt, oldRange, data ) => {
 			this._hasChangedRange = true;
@@ -1014,7 +1014,7 @@ class LiveSelection extends Selection {
 	_fixGraveyardSelection( liveRange, removedRangeStart ) {
 		// The start of the removed range is the closest position to the `liveRange` - the original selection range.
 		// This is a good candidate for a fixed selection range.
-		const positionCandidate = Position.createFromPosition( removedRangeStart );
+		const positionCandidate = removedRangeStart.clone();
 
 		// Find a range that is a correct selection range and is closest to the start of removed range.
 		const selectionRange = this._model.schema.getNearestSelectionRange( positionCandidate );

+ 23 - 18
packages/ckeditor5-engine/src/model/liveposition.js

@@ -63,35 +63,40 @@ export default class LivePosition extends Position {
 	}
 
 	/**
-	 * @static
-	 * @method module:engine/model/liveposition~LivePosition.createAfter
-	 * @see module:engine/model/position~Position.createAfter
-	 * @param {module:engine/model/node~Node} node
-	 * @returns {module:engine/model/liveposition~LivePosition}
+	 * Creates a {@link module:engine/model/position~Position position instance}, which is equal to this live position.
+	 *
+	 * @returns {module:engine/model/position~Position}
 	 */
+	toPosition() {
+		return new Position( this.root, this.path.slice(), this.stickiness );
+	}
 
 	/**
-	 * @static
-	 * @method module:engine/model/liveposition~LivePosition.createBefore
-	 * @see module:engine/model/position~Position.createBefore
-	 * @param {module:engine/model/node~Node} node
-	 * @returns {module:engine/model/liveposition~LivePosition}
+	 * Creates a `LivePosition` instance that is equal to position.
+	 *
+	 * @param {module:engine/model/position~Position} position
+	 * @param {module:engine/model/position~PositionStickiness} [stickiness]
+	 * @returns {module:engine/model/position~Position}
 	 */
+	static fromPosition( position, stickiness ) {
+		return new this( position.root, position.path.slice(), stickiness ? stickiness : position.stickiness );
+	}
 
 	/**
 	 * @static
-	 * @method module:engine/model/liveposition~LivePosition.createFromParentAndOffset
-	 * @see module:engine/model/position~Position.createFromParentAndOffset
-	 * @param {module:engine/model/element~Element} parent
-	 * @param {Number} offset
+	 * @protected
+	 * @method module:engine/model/liveposition~LivePosition._createAfter
+	 * @see module:engine/model/position~Position._createAfter
+	 * @param {module:engine/model/node~Node} node
 	 * @returns {module:engine/model/liveposition~LivePosition}
 	 */
 
 	/**
 	 * @static
-	 * @method module:engine/model/liveposition~LivePosition.createFromPosition
-	 * @see module:engine/model/position~Position.createFromPosition
-	 * @param {module:engine/model/position~Position} position
+	 * @protected
+	 * @method module:engine/model/liveposition~LivePosition._createBefore
+	 * @see module:engine/model/position~Position._createBefore
+	 * @param {module:engine/model/node~Node} node
 	 * @returns {module:engine/model/liveposition~LivePosition}
 	 */
 
@@ -132,7 +137,7 @@ function transform( operation ) {
 	const result = this.getTransformedByOperation( operation );
 
 	if ( !this.isEqual( result ) ) {
-		const oldPosition = Position.createFromPosition( this );
+		const oldPosition = this.toPosition();
 
 		this.path = result.path;
 		this.root = result.root;

+ 31 - 20
packages/ckeditor5-engine/src/model/liverange.js

@@ -41,38 +41,49 @@ export default class LiveRange extends Range {
 	}
 
 	/**
-	 * @see module:engine/model/range~Range.createIn
-	 * @static
-	 * @method module:engine/model/liverange~LiveRange.createIn
-	 * @param {module:engine/model/element~Element} element
+	 * Creates a {@link module:engine/model/range~Range range instance} that is equal to this live range.
+	 *
+	 * @returns {module:engine/model/range~Range}
+	 */
+	toRange() {
+		return new Range( this.start, this.end );
+	}
+
+	/**
+	 * Creates a `LiveRange` instance that is equal to the given range.
+	 *
+	 * @param {module:engine/model/range~Range} range
 	 * @returns {module:engine/model/liverange~LiveRange}
 	 */
+	static fromRange( range ) {
+		return new LiveRange( range.start, range.end );
+	}
 
 	/**
-	 * @see module:engine/model/range~Range.createFromPositionAndShift
+	 * @see module:engine/model/range~Range._createIn
 	 * @static
-	 * @method module:engine/model/liverange~LiveRange.createFromPositionAndShift
-	 * @param {module:engine/model/position~Position} position
-	 * @param {Number} shift
+	 * @protected
+	 * @method module:engine/model/liverange~LiveRange._createIn
+	 * @param {module:engine/model/element~Element} element
 	 * @returns {module:engine/model/liverange~LiveRange}
 	 */
 
 	/**
-	 * @see module:engine/model/range~Range.createFromParentsAndOffsets
+	 * @see module:engine/model/range~Range._createOn
 	 * @static
-	 * @method module:engine/model/liverange~LiveRange.createFromParentsAndOffsets
-	 * @param {module:engine/model/element~Element} startElement
-	 * @param {Number} startOffset
-	 * @param {module:engine/model/element~Element} endElement
-	 * @param {Number} endOffset
+	 * @protected
+	 * @method module:engine/model/liverange~LiveRange._createOn
+	 * @param {module:engine/model/element~Element} element
 	 * @returns {module:engine/model/liverange~LiveRange}
 	 */
 
 	/**
-	 * @see module:engine/model/range~Range.createFromRange
+	 * @see module:engine/model/range~Range._createFromPositionAndShift
 	 * @static
-	 * @method module:engine/model/liverange~LiveRange.createFromRange
-	 * @param {module:engine/model/range~Range} range
+	 * @protected
+	 * @method module:engine/model/liverange~LiveRange._createFromPositionAndShift
+	 * @param {module:engine/model/position~Position} position
+	 * @param {Number} shift
 	 * @returns {module:engine/model/liverange~LiveRange}
 	 */
 
@@ -129,7 +140,7 @@ function bindWithDocument() {
 function transform( operation ) {
 	// Transform the range by the operation. Join the result ranges if needed.
 	const ranges = this.getTransformedByOperation( operation );
-	const result = Range.createFromRanges( ranges );
+	const result = Range._createFromRanges( ranges );
 
 	const boundariesChanged = !result.isEqual( this );
 	const contentChanged = doesOperationChangeRangeContent( this, operation );
@@ -149,7 +160,7 @@ function transform( operation ) {
 			}
 		}
 
-		const oldRange = Range.createFromRange( this );
+		const oldRange = this.toRange();
 
 		this.start = result.start;
 		this.end = result.end;
@@ -157,7 +168,7 @@ function transform( operation ) {
 		this.fire( 'change:range', oldRange, { deletionPosition } );
 	} else if ( contentChanged ) {
 		// If range boundaries have not changed, but there was change inside the range, fire `change:content` event.
-		this.fire( 'change:content', Range.createFromRange( this ), { deletionPosition } );
+		this.fire( 'change:content', this.toRange(), { deletionPosition } );
 	}
 }
 

+ 5 - 7
packages/ckeditor5-engine/src/model/markercollection.js

@@ -8,8 +8,6 @@
  */
 
 import LiveRange from './liverange';
-import Position from './position';
-import Range from './range';
 import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import mix from '@ckeditor/ckeditor5-utils/src/mix';
@@ -101,7 +99,7 @@ export default class MarkerCollection {
 			let hasChanged = false;
 
 			if ( !oldRange.isEqual( range ) ) {
-				oldMarker._attachLiveRange( LiveRange.createFromRange( range ) );
+				oldMarker._attachLiveRange( LiveRange.fromRange( range ) );
 				hasChanged = true;
 			}
 
@@ -122,7 +120,7 @@ export default class MarkerCollection {
 			return oldMarker;
 		}
 
-		const liveRange = LiveRange.createFromRange( range );
+		const liveRange = LiveRange.fromRange( range );
 		const marker = new Marker( markerName, liveRange, managedUsingOperations, affectsData );
 
 		this._markers.set( markerName, marker );
@@ -396,7 +394,7 @@ class Marker {
 			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.' );
 		}
 
-		return Position.createFromPosition( this._liveRange.start );
+		return this._liveRange.start.clone();
 	}
 
 	/**
@@ -409,7 +407,7 @@ class Marker {
 			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.' );
 		}
 
-		return Position.createFromPosition( this._liveRange.end );
+		return this._liveRange.end.clone();
 	}
 
 	/**
@@ -429,7 +427,7 @@ class Marker {
 			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.' );
 		}
 
-		return Range.createFromRange( this._liveRange );
+		return this._liveRange.toRange();
 	}
 
 	/**

+ 212 - 7
packages/ckeditor5-engine/src/model/model.js

@@ -16,6 +16,8 @@ import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
 import mix from '@ckeditor/ckeditor5-utils/src/mix';
 import ModelElement from './element';
 import ModelRange from './range';
+import ModelPosition from './position';
+import ModelSelection from './selection';
 
 import insertContent from './utils/insertcontent';
 import deleteContent from './utils/deletecontent';
@@ -310,16 +312,16 @@ export default class Model {
 	 *			editor.model.insertContent( writer.createText( 'x' ), doc.getRoot(), 2 );
 	 *
 	 *			// Which is a shorthand for:
-	 *			editor.model.insertContent( writer.createText( 'x' ), Position.createAt( doc.getRoot(), 2 ) );
+	 *			editor.model.insertContent( writer.createText( 'x' ), writer.createPositionAt( doc.getRoot(), 2 ) );
 	 *		} );
 	 *
 	 * If an instance of {@link module:engine/model/selection~Selection} is passed as `selectable`
 	 * it will be moved to the target position (where the document selection should be moved after the insertion).
 	 *
-	 *		// Insert text replacing the given selection instance.
-	 *		const selection = new Selection( paragraph, 'in' );
-	 *
 	 *		editor.model.change( writer => {
+	 *			// Insert text replacing the given selection instance.
+	 *			const selection = writer.createSelection( paragraph, 'in' );
+	 *
 	 *			editor.model.insertContent( writer.createText( 'x' ), selection );
 	 *
 	 *			// insertContent() modifies the passed selection instance so it can be used to set the document selection.
@@ -444,17 +446,18 @@ export default class Model {
 	}
 
 	/**
-	 * Checks whether given {@link module:engine/model/range~Range range} or {@link module:engine/model/element~Element element}
+	 * Checks whether the given {@link module:engine/model/range~Range range} or
+	 * {@link module:engine/model/element~Element element}
 	 * has any content.
 	 *
-	 * Content is any text node or element which is registered in {@link module:engine/model/schema~Schema schema}.
+	 * Content is any text node or element which is registered in the {@link module:engine/model/schema~Schema schema}.
 	 *
 	 * @param {module:engine/model/range~Range|module:engine/model/element~Element} rangeOrElement Range or element to check.
 	 * @returns {Boolean}
 	 */
 	hasContent( rangeOrElement ) {
 		if ( rangeOrElement instanceof ModelElement ) {
-			rangeOrElement = ModelRange.createIn( rangeOrElement );
+			rangeOrElement = ModelRange._createIn( rangeOrElement );
 		}
 
 		if ( rangeOrElement.isCollapsed ) {
@@ -471,6 +474,208 @@ export default class Model {
 		return false;
 	}
 
+	/**
+	 * Creates a position from the given root and path in that root.
+	 *
+	 * Note: This method is also available as
+	 * {@link module:engine/model/writer~Writer#createPositionFromPath `Writer#createPositionFromPath()`}.
+	 *
+	 * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} root Root of the position.
+	 * @param {Array.<Number>} path Position path. See {@link module:engine/model/position~Position#path}.
+	 * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.
+	 * See {@link module:engine/model/position~PositionStickiness}.
+	 * @returns {module:engine/model/position~Position}
+	 */
+	createPositionFromPath( root, path, stickiness ) {
+		return new ModelPosition( root, path, stickiness );
+	}
+
+	/**
+	 * Creates position at the given location. The location can be specified as:
+	 *
+	 * * a {@link module:engine/model/position~Position position},
+	 * * a parent element and offset in that element,
+	 * * a parent element and `'end'` (the position will be set at the end of that element),
+	 * * a {@link module:engine/model/item~Item model item} and `'before'` or `'after'`
+	 * (the position will be set before or after the given model item).
+	 *
+	 * This method is a shortcut to other factory methods such as:
+	 *
+	 * * {@link module:engine/model/model~Model#createPositionBefore `createPositionBefore()`},
+	 * * {@link module:engine/model/model~Model#createPositionAfter `createPositionAfter()`}.
+	 *
+	 * Note: This method is also available as
+	 * {@link module:engine/model/writer~Writer#createPositionAt `Writer#createPositionAt()`},
+	 *
+	 * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
+	 * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
+	 * first parameter is a {@link module:engine/model/item~Item model item}.
+	 */
+	createPositionAt( itemOrPosition, offset ) {
+		return ModelPosition._createAt( itemOrPosition, offset );
+	}
+
+	/**
+	 * Creates a new position after the given {@link module:engine/model/item~Item model item}.
+	 *
+	 * Note: This method is also available as
+	 * {@link module:engine/model/writer~Writer#createPositionAfter `Writer#createPositionAfter()`}.
+	 *
+	 * @param {module:engine/model/item~Item} item Item after which the position should be placed.
+	 * @returns {module:engine/model/position~Position}
+	 */
+	createPositionAfter( item ) {
+		return ModelPosition._createAfter( item );
+	}
+
+	/**
+	 * Creates a new position before the given {@link module:engine/model/item~Item model item}.
+	 *
+	 * Note: This method is also available as
+	 * {@link module:engine/model/writer~Writer#createPositionBefore `Writer#createPositionBefore()`}.
+	 *
+	 * @param {module:engine/model/item~Item} item Item before which the position should be placed.
+	 * @returns {module:engine/model/position~Position}
+	 */
+	createPositionBefore( item ) {
+		return ModelPosition._createBefore( item );
+	}
+
+	/**
+	 * Creates a range spanning from the `start` position to the `end` position.
+	 *
+	 * Note: This method is also available as
+	 * {@link module:engine/model/writer~Writer#createRange `Writer#createRange()`}:
+	 *
+	 *		model.change( writer => {
+	 *			const range = writer.createRange( start, end );
+	 *		} );
+	 *
+	 * @param {module:engine/model/position~Position} start Start position.
+	 * @param {module:engine/model/position~Position} [end] End position. If not set, the range will be collapsed
+	 * to the `start` position.
+	 * @returns {module:engine/model/range~Range}
+	 */
+	createRange( start, end ) {
+		return new ModelRange( start, end );
+	}
+
+	/**
+	 * Creates a range inside the given element which starts before the first child of
+	 * that element and ends after the last child of that element.
+	 *
+	 * Note: This method is also available as
+	 * {@link module:engine/model/writer~Writer#createRangeIn `Writer#createRangeIn()`}:
+	 *
+	 *		model.change( writer => {
+	 *			const range = writer.createRangeIn( paragraph );
+	 *		} );
+	 *
+	 * @param {module:engine/model/element~Element} element Element which is a parent for the range.
+	 * @returns {module:engine/model/range~Range}
+	 */
+	createRangeIn( element ) {
+		return ModelRange._createIn( element );
+	}
+
+	/**
+	 * Creates a range that starts before the given {@link module:engine/model/item~Item model item} and ends after it.
+	 *
+	 * Note: This method is also available on `writer` instance as
+	 * {@link module:engine/model/writer~Writer#createRangeOn `Writer.createRangeOn()`}:
+	 *
+	 *		model.change( writer => {
+	 *			const range = writer.createRangeOn( paragraph );
+	 *		} );
+	 *
+	 * @param {module:engine/model/item~Item} item
+	 * @returns {module:engine/model/range~Range}
+	 */
+	createRangeOn( item ) {
+		return ModelRange._createOn( item );
+	}
+
+	/**
+	 * Creates a new selection instance based on:
+	 *
+	 * * the given {@link module:engine/model/selection~Selection selection},
+	 * * or based on the given {@link module:engine/model/range~Range range},
+	 * * or based on the given iterable collection of {@link module:engine/model/range~Range ranges}
+	 * * or at the given {@link module:engine/model/position~Position position},
+	 * * or on the given {@link module:engine/model/element~Element element},
+	 * * or creates an empty selection if no arguments were passed.
+	 *
+	 * Note: This method is also available as
+	 * {@link module:engine/model/writer~Writer#createSelection `Writer#createSelection()`}.
+	 *
+	 *		// Creates empty selection without ranges.
+	 *		const selection = writer.createSelection();
+	 *
+	 *		// Creates selection at the given range.
+	 *		const range = writer.createRange( start, end );
+	 *		const selection = writer.createSelection( range );
+	 *
+	 *		// Creates selection at the given ranges
+	 *		const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
+	 *		const selection = writer.createSelection( ranges );
+	 *
+	 *		// Creates selection from the other selection.
+	 *		// Note: It doesn't copies selection attributes.
+	 *		const otherSelection = writer.createSelection();
+	 *		const selection = writer.createSelection( otherSelection );
+	 *
+	 *		// Creates selection from the given document selection.
+	 *		// Note: It doesn't copies selection attributes.
+	 *		const documentSelection = model.document.selection;
+	 *		const selection = writer.createSelection( documentSelection );
+	 *
+	 *		// Creates selection at the given position.
+	 *		const position = writer.createPositionFromPath( root, path );
+	 *		const selection = writer.createSelection( position );
+	 *
+	 *		// Creates selection at the given offset in the given element.
+	 *		const paragraph = writer.createElement( 'paragraph' );
+	 *		const selection = writer.createSelection( paragraph, offset );
+	 *
+	 *		// Creates a range inside an {@link module:engine/model/element~Element element} which starts before the
+	 *		// first child of that element and ends after the last child of that element.
+	 *		const selection = writer.createSelection( paragraph, 'in' );
+	 *
+	 *		// Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends
+	 *		// just after the item.
+	 *		const selection = writer.createSelection( paragraph, 'on' );
+	 *
+	 *		// Additional options (`'backward'`) can be specified as the last argument.
+	 *
+	 *		// Creates backward selection.
+	 *		const selection = writer.createSelection( range, { backward: true } );
+	 *
+	 * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection|
+	 * module:engine/model/position~Position|module:engine/model/element~Element|
+	 * Iterable.<module:engine/model/range~Range>|module:engine/model/range~Range|null} selectable
+	 * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.
+	 * @param {Object} [options]
+	 * @param {Boolean} [options.backward] Sets this selection instance to be backward.
+	 * @returns {module:engine/model/selection~Selection}
+	 */
+	createSelection( selectable, placeOrOffset, options ) {
+		return new ModelSelection( selectable, placeOrOffset, options );
+	}
+
+	/**
+	 * Creates a {@link module:engine/model/batch~Batch} instance.
+	 *
+	 * **Note:** In most cases creating a batch instance is not necessary as they are created when using:
+	 *
+	 * * {@link #change `change()`},
+	 * * {@link #enqueueChange `enqueueChange()`}.
+	 *
+	 * @returns {module:engine/model/batch~Batch}
+	 */
+	createBatch() {
+		return new Batch();
+	}
+
 	/**
 	 * Removes all events listeners set by model instance and destroys {@link module:engine/model/document~Document}.
 	 */

+ 1 - 1
packages/ckeditor5-engine/src/model/operation/attributeoperation.js

@@ -49,7 +49,7 @@ export default class AttributeOperation extends Operation {
 		 * @readonly
 		 * @member {module:engine/model/range~Range}
 		 */
-		this.range = Range.createFromRange( range );
+		this.range = range.clone();
 
 		/**
 		 * Key of an attribute to change or remove.

+ 2 - 3
packages/ckeditor5-engine/src/model/operation/detachoperation.js

@@ -8,7 +8,6 @@
  */
 
 import Operation from './operation';
-import Position from '../position';
 import Range from '../range';
 import { _remove } from './utils';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
@@ -36,7 +35,7 @@ export default class DetachOperation extends Operation {
 		 *
 		 * @member {module:engine/model/position~Position} #sourcePosition
 		 */
-		this.sourcePosition = Position.createFromPosition( sourcePosition );
+		this.sourcePosition = sourcePosition.clone();
 
 		/**
 		 * Offset size of moved range.
@@ -82,7 +81,7 @@ export default class DetachOperation extends Operation {
 	 * @inheritDoc
 	 */
 	_execute() {
-		_remove( Range.createFromPositionAndShift( this.sourcePosition, this.howMany ) );
+		_remove( Range._createFromPositionAndShift( this.sourcePosition, this.howMany ) );
 	}
 
 	/**

+ 1 - 1
packages/ckeditor5-engine/src/model/operation/insertoperation.js

@@ -39,7 +39,7 @@ export default class InsertOperation extends Operation {
 		 * @readonly
 		 * @member {module:engine/model/position~Position} module:engine/model/operation/insertoperation~InsertOperation#position
 		 */
-		this.position = Position.createFromPosition( position );
+		this.position = position.clone();
 		this.position.stickiness = 'toNone';
 
 		/**

+ 2 - 2
packages/ckeditor5-engine/src/model/operation/markeroperation.js

@@ -41,7 +41,7 @@ export default class MarkerOperation extends Operation {
 		 * @readonly
 		 * @member {module:engine/model/range~Range}
 		 */
-		this.oldRange = oldRange ? Range.createFromRange( oldRange ) : null;
+		this.oldRange = oldRange ? oldRange.clone() : null;
 
 		/**
 		 * Marker range after the change.
@@ -49,7 +49,7 @@ export default class MarkerOperation extends Operation {
 		 * @readonly
 		 * @member {module:engine/model/range~Range}
 		 */
-		this.newRange = newRange ? Range.createFromRange( newRange ) : null;
+		this.newRange = newRange ? newRange.clone() : null;
 
 		/**
 		 * Specifies whether the marker operation affects the data produced by the data pipeline

+ 5 - 5
packages/ckeditor5-engine/src/model/operation/mergeoperation.js

@@ -45,7 +45,7 @@ export default class MergeOperation extends Operation {
 		 *
 		 * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#sourcePosition
 		 */
-		this.sourcePosition = Position.createFromPosition( sourcePosition );
+		this.sourcePosition = sourcePosition.clone();
 		// This is, and should always remain, the first position in its parent.
 		this.sourcePosition.stickiness = 'toPrevious';
 
@@ -61,7 +61,7 @@ export default class MergeOperation extends Operation {
 		 *
 		 * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#targetPosition
 		 */
-		this.targetPosition = Position.createFromPosition( targetPosition );
+		this.targetPosition = targetPosition.clone();
 		// Except of a rare scenario in `MergeOperation` x `MergeOperation` transformation,
 		// this is, and should always remain, the last position in its parent.
 		this.targetPosition.stickiness = 'toNext';
@@ -71,7 +71,7 @@ export default class MergeOperation extends Operation {
 		 *
 		 * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#graveyardPosition
 		 */
-		this.graveyardPosition = Position.createFromPosition( graveyardPosition );
+		this.graveyardPosition = graveyardPosition.clone();
 	}
 
 	/**
@@ -170,10 +170,10 @@ export default class MergeOperation extends Operation {
 	 */
 	_execute() {
 		const mergedElement = this.sourcePosition.parent;
-		const sourceRange = Range.createIn( mergedElement );
+		const sourceRange = Range._createIn( mergedElement );
 
 		_move( sourceRange, this.targetPosition );
-		_move( Range.createOn( mergedElement ), this.graveyardPosition );
+		_move( Range._createOn( mergedElement ), this.graveyardPosition );
 	}
 
 	/**

+ 3 - 3
packages/ckeditor5-engine/src/model/operation/moveoperation.js

@@ -40,7 +40,7 @@ export default class MoveOperation extends Operation {
 		 *
 		 * @member {module:engine/model/position~Position} module:engine/model/operation/moveoperation~MoveOperation#sourcePosition
 		 */
-		this.sourcePosition = Position.createFromPosition( sourcePosition );
+		this.sourcePosition = sourcePosition.clone();
 		// `'toNext'` because `sourcePosition` is a bit like a start of the moved range.
 		this.sourcePosition.stickiness = 'toNext';
 
@@ -56,7 +56,7 @@ export default class MoveOperation extends Operation {
 		 *
 		 * @member {module:engine/model/position~Position} module:engine/model/operation/moveoperation~MoveOperation#targetPosition
 		 */
-		this.targetPosition = Position.createFromPosition( targetPosition );
+		this.targetPosition = targetPosition.clone();
 		this.targetPosition.stickiness = 'toNone';
 	}
 
@@ -172,7 +172,7 @@ export default class MoveOperation extends Operation {
 	 * @inheritDoc
 	 */
 	_execute() {
-		_move( Range.createFromPositionAndShift( this.sourcePosition, this.howMany ), this.targetPosition );
+		_move( Range._createFromPositionAndShift( this.sourcePosition, this.howMany ), this.targetPosition );
 	}
 
 	/**

+ 2 - 2
packages/ckeditor5-engine/src/model/operation/renameoperation.js

@@ -69,7 +69,7 @@ export default class RenameOperation extends Operation {
 	 * @returns {module:engine/model/operation/renameoperation~RenameOperation} Clone of this operation.
 	 */
 	clone() {
-		return new RenameOperation( Position.createFromPosition( this.position ), this.oldName, this.newName, this.baseVersion );
+		return new RenameOperation( this.position.clone(), this.oldName, this.newName, this.baseVersion );
 	}
 
 	/**
@@ -78,7 +78,7 @@ export default class RenameOperation extends Operation {
 	 * @returns {module:engine/model/operation/renameoperation~RenameOperation}
 	 */
 	getReversed() {
-		return new RenameOperation( Position.createFromPosition( this.position ), this.newName, this.oldName, this.baseVersion + 1 );
+		return new RenameOperation( this.position.clone(), this.newName, this.oldName, this.baseVersion + 1 );
 	}
 
 	/**

+ 6 - 5
packages/ckeditor5-engine/src/model/operation/splitoperation.js

@@ -41,7 +41,7 @@ export default class SplitOperation extends Operation {
 		 *
 		 * @member {module:engine/model/position~Position} module:engine/model/operation/splitoperation~SplitOperation#splitPosition
 		 */
-		this.splitPosition = Position.createFromPosition( splitPosition );
+		this.splitPosition = splitPosition.clone();
 		// Keep position sticking to the next node. This way any new content added at the place where the element is split
 		// will be left in the original element.
 		this.splitPosition.stickiness = 'toNext';
@@ -69,7 +69,7 @@ export default class SplitOperation extends Operation {
 		 *
 		 * @member {module:engine/model/position~Position|null} #graveyardPosition
 		 */
-		this.graveyardPosition = graveyardPosition ? Position.createFromPosition( graveyardPosition ) : null;
+		this.graveyardPosition = graveyardPosition ? graveyardPosition.clone() : null;
 
 		if ( this.graveyardPosition ) {
 			this.graveyardPosition.stickiness = 'toNext';
@@ -181,15 +181,16 @@ export default class SplitOperation extends Operation {
 		const splitElement = this.splitPosition.parent;
 
 		if ( this.graveyardPosition ) {
-			_move( Range.createFromPositionAndShift( this.graveyardPosition, 1 ), this.insertionPosition );
+			_move( Range._createFromPositionAndShift( this.graveyardPosition, 1 ), this.insertionPosition );
 		} else {
 			const newElement = splitElement._clone();
 
 			_insert( this.insertionPosition, newElement );
 		}
 
-		const sourceRange = Range.createFromParentsAndOffsets(
-			splitElement, this.splitPosition.offset, splitElement, splitElement.maxOffset
+		const sourceRange = new Range(
+			Position._createAt( splitElement, this.splitPosition.offset ),
+			Position._createAt( splitElement, splitElement.maxOffset )
 		);
 
 		_move( sourceRange, this.moveTargetPosition );

+ 24 - 24
packages/ckeditor5-engine/src/model/operation/transform.js

@@ -806,7 +806,7 @@ setTransformation( AttributeOperation, MergeOperation, ( a, b ) => {
 	//
 	if ( a.range.start.hasSameParentAs( b.deletionPosition ) ) {
 		if ( a.range.containsPosition( b.deletionPosition ) || a.range.start.isEqual( b.deletionPosition ) ) {
-			ranges.push( Range.createFromPositionAndShift( b.graveyardPosition, 1 ) );
+			ranges.push( Range._createFromPositionAndShift( b.graveyardPosition, 1 ) );
 		}
 	}
 
@@ -845,7 +845,7 @@ setTransformation( AttributeOperation, MoveOperation, ( a, b ) => {
 // @param {module:engine/model/operation/moveoperation~MoveOperation} moveOp
 // @returns {Array.<module:engine/model/range~Range>}
 function _breakRangeByMoveOperation( range, moveOp ) {
-	const moveRange = Range.createFromPositionAndShift( moveOp.sourcePosition, moveOp.howMany );
+	const moveRange = Range._createFromPositionAndShift( moveOp.sourcePosition, moveOp.howMany );
 
 	// We are transforming `range` (original range) by `moveRange` (range moved by move operation). As usual when it comes to
 	// transforming a ranges, we may have a common part of the ranges and we may have a difference part (zero to two ranges).
@@ -943,11 +943,11 @@ setTransformation( AttributeOperation, SplitOperation, ( a, b ) => {
 		const secondPart = a.clone();
 
 		secondPart.range = new Range(
-			Position.createFromPosition( b.moveTargetPosition ),
+			b.moveTargetPosition.clone(),
 			a.range.end._getCombined( b.splitPosition, b.moveTargetPosition )
 		);
 
-		a.range.end = Position.createFromPosition( b.splitPosition );
+		a.range.end = b.splitPosition.clone();
 		a.range.end.stickiness = 'toPrevious';
 
 		return [ a, secondPart ];
@@ -1047,7 +1047,7 @@ setTransformation( MarkerOperation, InsertOperation, ( a, b ) => {
 setTransformation( MarkerOperation, MarkerOperation, ( a, b, context ) => {
 	if ( a.name == b.name ) {
 		if ( context.aIsStrong ) {
-			a.oldRange = b.newRange ? Range.createFromRange( b.newRange ) : null;
+			a.oldRange = b.newRange ? b.newRange.clone() : null;
 		} else {
 			return [ new NoOperation( 0 ) ];
 		}
@@ -1070,11 +1070,11 @@ setTransformation( MarkerOperation, MergeOperation, ( a, b ) => {
 
 setTransformation( MarkerOperation, MoveOperation, ( a, b ) => {
 	if ( a.oldRange ) {
-		a.oldRange = Range.createFromRanges( a.oldRange._getTransformedByMoveOperation( b ) );
+		a.oldRange = Range._createFromRanges( a.oldRange._getTransformedByMoveOperation( b ) );
 	}
 
 	if ( a.newRange ) {
-		a.newRange = Range.createFromRanges( a.newRange._getTransformedByMoveOperation( b ) );
+		a.newRange = Range._createFromRanges( a.newRange._getTransformedByMoveOperation( b ) );
 	}
 
 	return [ a ];
@@ -1221,7 +1221,7 @@ setTransformation( MergeOperation, MoveOperation, ( a, b, context ) => {
 	//
 	// The exception of this rule would be if the remove operation was later undone.
 	//
-	const removedRange = Range.createFromPositionAndShift( b.sourcePosition, b.howMany );
+	const removedRange = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );
 
 	if ( b.type == 'remove' && !context.bWasUndone ) {
 		if ( a.deletionPosition.hasSameParentAs( b.sourcePosition ) && removedRange.containsPosition( a.sourcePosition ) ) {
@@ -1348,7 +1348,7 @@ setTransformation( MergeOperation, SplitOperation, ( a, b, context ) => {
 	// So now we are fixing situation which was skipped in `MergeOperation` x `MergeOperation` case.
 	//
 	if ( a.sourcePosition.isEqual( b.splitPosition ) && ( context.abRelation == 'mergeSameElement' || a.sourcePosition.offset > 0 ) ) {
-		a.sourcePosition = Position.createFromPosition( b.moveTargetPosition );
+		a.sourcePosition = b.moveTargetPosition.clone();
 		a.targetPosition = a.targetPosition._getTransformedBySplitOperation( b );
 
 		return [ a ];
@@ -1369,7 +1369,7 @@ setTransformation( MergeOperation, SplitOperation, ( a, b, context ) => {
 // -----------------------
 
 setTransformation( MoveOperation, InsertOperation, ( a, b ) => {
-	const moveRange = Range.createFromPositionAndShift( a.sourcePosition, a.howMany );
+	const moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );
 	const transformed = moveRange._getTransformedByInsertOperation( b, false )[ 0 ];
 
 	a.sourcePosition = transformed.start;
@@ -1393,8 +1393,8 @@ setTransformation( MoveOperation, MoveOperation, ( a, b, context ) => {
 	// Setting and evaluating some variables that will be used in special cases and default algorithm.
 	//
 	// Create ranges from `MoveOperations` properties.
-	const rangeA = Range.createFromPositionAndShift( a.sourcePosition, a.howMany );
-	const rangeB = Range.createFromPositionAndShift( b.sourcePosition, b.howMany );
+	const rangeA = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );
+	const rangeB = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );
 
 	// Assign `context.aIsStrong` to a different variable, because the value may change during execution of
 	// this algorithm and we do not want to override original `context.aIsStrong` that will be used in later transformations.
@@ -1574,7 +1574,7 @@ setTransformation( MoveOperation, MoveOperation, ( a, b, context ) => {
 } );
 
 setTransformation( MoveOperation, SplitOperation, ( a, b, context ) => {
-	let newTargetPosition = Position.createFromPosition( a.targetPosition );
+	let newTargetPosition = a.targetPosition.clone();
 
 	// Do not transform if target position is same as split insertion position and this split comes from undo.
 	// This should be done on relations but it is too much work for now as it would require relations working in collaboration.
@@ -1590,7 +1590,7 @@ setTransformation( MoveOperation, SplitOperation, ( a, b, context ) => {
 	// In this case the default range transformation will not work correctly as the element created by
 	// split operation would be outside the range. The range to move needs to be fixed manually.
 	//
-	const moveRange = Range.createFromPositionAndShift( a.sourcePosition, a.howMany );
+	const moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );
 
 	if ( moveRange.end.isEqual( b.insertionPosition ) ) {
 		// Do it only if this is a "natural" split, not a one that comes from undo.
@@ -1679,7 +1679,7 @@ setTransformation( MoveOperation, SplitOperation, ( a, b, context ) => {
 		const movesGraveyardElement = moveRange.start.isEqual( b.graveyardPosition ) || moveRange.containsPosition( b.graveyardPosition );
 
 		if ( a.howMany > 1 && movesGraveyardElement ) {
-			ranges.push( Range.createFromPositionAndShift( b.insertionPosition, 1 ) );
+			ranges.push( Range._createFromPositionAndShift( b.insertionPosition, 1 ) );
 		}
 	}
 
@@ -1687,7 +1687,7 @@ setTransformation( MoveOperation, SplitOperation, ( a, b, context ) => {
 } );
 
 setTransformation( MoveOperation, MergeOperation, ( a, b, context ) => {
-	const movedRange = Range.createFromPositionAndShift( a.sourcePosition, a.howMany );
+	const movedRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );
 
 	if ( b.deletionPosition.hasSameParentAs( a.sourcePosition ) && movedRange.containsPosition( b.sourcePosition ) ) {
 		if ( a.type == 'remove' ) {
@@ -1703,8 +1703,8 @@ setTransformation( MoveOperation, MergeOperation, ( a, b, context ) => {
 			if ( !context.aWasUndone ) {
 				const results = [];
 
-				let gyMoveSource = Position.createFromPosition( b.graveyardPosition );
-				let splitNodesMoveSource = Position.createFromPosition( b.targetPosition );
+				let gyMoveSource = b.graveyardPosition.clone();
+				let splitNodesMoveSource = b.targetPosition.clone();
 
 				if ( a.howMany > 1 ) {
 					results.push( new MoveOperation( a.sourcePosition, a.howMany - 1, a.targetPosition, 0 ) );
@@ -1737,7 +1737,7 @@ setTransformation( MoveOperation, MergeOperation, ( a, b, context ) => {
 				if ( !context.bWasUndone ) {
 					return [ new NoOperation( 0 ) ];
 				} else {
-					a.sourcePosition = Position.createFromPosition( b.graveyardPosition );
+					a.sourcePosition = b.graveyardPosition.clone();
 					a.targetPosition = a.targetPosition._getTransformedByMergeOperation( b );
 
 					return [ a ];
@@ -1748,7 +1748,7 @@ setTransformation( MoveOperation, MergeOperation, ( a, b, context ) => {
 
 	// The default case.
 	//
-	const moveRange = Range.createFromPositionAndShift( a.sourcePosition, a.howMany );
+	const moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );
 	const transformed = moveRange._getTransformedByMergeOperation( b );
 
 	a.sourcePosition = transformed.start;
@@ -1772,7 +1772,7 @@ setTransformation( RenameOperation, MergeOperation, ( a, b ) => {
 	// Element to rename got merged, so it was moved to `b.graveyardPosition`.
 	//
 	if ( a.position.isEqual( b.deletionPosition ) ) {
-		a.position = Position.createFromPosition( b.graveyardPosition );
+		a.position = b.graveyardPosition.clone();
 		a.position.stickiness = 'toNext';
 
 		return [ a ];
@@ -1925,7 +1925,7 @@ setTransformation( SplitOperation, MergeOperation, ( a, b, context ) => {
 
 		a.splitPosition = a.splitPosition._getTransformedByMergeOperation( b );
 		a.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );
-		a.graveyardPosition = Position.createFromPosition( additionalSplit.insertionPosition );
+		a.graveyardPosition = additionalSplit.insertionPosition.clone();
 		a.graveyardPosition.stickiness = 'toNext';
 
 		return [ additionalSplit, a ];
@@ -1952,7 +1952,7 @@ setTransformation( SplitOperation, MergeOperation, ( a, b, context ) => {
 } );
 
 setTransformation( SplitOperation, MoveOperation, ( a, b, context ) => {
-	const rangeToMove = Range.createFromPositionAndShift( b.sourcePosition, b.howMany );
+	const rangeToMove = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );
 
 	if ( a.graveyardPosition ) {
 		// Case 1:
@@ -2002,7 +2002,7 @@ setTransformation( SplitOperation, MoveOperation, ( a, b, context ) => {
 			a.howMany += b.howMany;
 		}
 
-		a.splitPosition = Position.createFromPosition( b.sourcePosition );
+		a.splitPosition = b.sourcePosition.clone();
 		a.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );
 
 		return [ a ];

+ 69 - 78
packages/ckeditor5-engine/src/model/position.js

@@ -16,20 +16,25 @@ import { last } from 'lodash-es';
 /**
  * Represents a position in the model tree.
  *
- * **Note:** Position is based on offsets, not indexes. This means that position in element containing two text nodes
- * with data `foo` and `bar`, position between them has offset `3`, not `1`.
- * See {@link module:engine/model/position~Position#path} for more.
+ * A position is represented by its {@link module:engine/model/position~Position#root} and
+ * a {@link module:engine/model/position~Position#path} in that root.
  *
- * Since position in a model is represented by a {@link module:engine/model/position~Position#root position root} and
- * {@link module:engine/model/position~Position#path position path} it is possible to create positions placed in non-existing elements.
- * This requirement is important for operational transformation.
+ * You can create position instances via its constructor or the `createPosition*()` factory methods of
+ * {@link module:engine/model/model~Model} and {@link module:engine/model/writer~Writer}.
+ *
+ * **Note:** Position is based on offsets, not indexes. This means that a position between two text nodes
+ * `foo` and `bar` has offset `3`, not `1`. See {@link module:engine/model/position~Position#path} for more information.
+ *
+ * Since a position in the model is represented by a {@link module:engine/model/position~Position#root position root} and
+ * {@link module:engine/model/position~Position#path position path} it is possible to create positions placed in non-existing places.
+ * This requirement is important for operational transformation algorithms.
  *
  * Also, {@link module:engine/model/operation/operation~Operation operations}
- * kept in {@link module:engine/model/document~Document#history document history}
+ * kept in the {@link module:engine/model/document~Document#history document history}
  * are storing positions (and ranges) which were correct when those operations were applied, but may not be correct
- * after document got changed.
+ * after the document has changed.
  *
- * When changes are applied to model, it may also happen that {@link module:engine/model/position~Position#parent position parent}
+ * When changes are applied to the model, it may also happen that {@link module:engine/model/position~Position#parent position parent}
  * will change even if position path has not changed. Keep in mind, that if a position leads to non-existing element,
  * {@link module:engine/model/position~Position#parent} and some other properties and methods will throw errors.
  *
@@ -360,7 +365,7 @@ export default class Position {
 	 * @returns {module:engine/model/position~Position} Shifted position.
 	 */
 	getShiftedBy( shift ) {
-		const shifted = Position.createFromPosition( this );
+		const shifted = this.clone();
 
 		const offset = shifted.offset + shift;
 		shifted.offset = offset < 0 ? 0 : offset;
@@ -448,13 +453,13 @@ export default class Position {
 				return true;
 
 			case 'before':
-				left = Position.createFromPosition( this );
-				right = Position.createFromPosition( otherPosition );
+				left = Position._createAt( this );
+				right = Position._createAt( otherPosition );
 				break;
 
 			case 'after':
-				left = Position.createFromPosition( otherPosition );
-				right = Position.createFromPosition( this );
+				left = Position._createAt( otherPosition );
+				right = Position._createAt( this );
 				break;
 
 			default:
@@ -538,7 +543,7 @@ export default class Position {
 				result = this._getTransformedByMergeOperation( operation );
 				break;
 			default:
-				result = Position.createFromPosition( this );
+				result = Position._createAt( this );
 				break;
 		}
 
@@ -612,7 +617,7 @@ export default class Position {
 				pos = pos._getTransformedByDeletion( operation.deletionPosition, 1 );
 			}
 		} else if ( this.isEqual( operation.deletionPosition ) ) {
-			pos = Position.createFromPosition( operation.deletionPosition );
+			pos = Position._createAt( operation.deletionPosition );
 		} else {
 			pos = this._getTransformedByMove( operation.deletionPosition, operation.graveyardPosition, 1 );
 		}
@@ -630,7 +635,7 @@ export default class Position {
 	 * @returns {module:engine/model/position~Position|null} Transformed position or `null`.
 	 */
 	_getTransformedByDeletion( deletePosition, howMany ) {
-		const transformed = Position.createFromPosition( this );
+		const transformed = Position._createAt( this );
 
 		// This position can't be affected if deletion was in a different root.
 		if ( this.root != deletePosition.root ) {
@@ -678,7 +683,7 @@ export default class Position {
 	 * @returns {module:engine/model/position~Position} Transformed position.
 	 */
 	_getTransformedByInsertion( insertPosition, howMany ) {
-		const transformed = Position.createFromPosition( this );
+		const transformed = Position._createAt( this );
 
 		// This position can't be affected if insertion was in a different root.
 		if ( this.root != insertPosition.root ) {
@@ -721,7 +726,7 @@ export default class Position {
 
 		if ( sourcePosition.isEqual( targetPosition ) ) {
 			// If `targetPosition` is equal to `sourcePosition` this isn't really any move. Just return position as it is.
-			return Position.createFromPosition( this );
+			return Position._createAt( this );
 		}
 
 		// Moving a range removes nodes from their original position. We acknowledge this by proper transformation.
@@ -751,9 +756,9 @@ export default class Position {
 	 *
 	 * Example:
 	 *
-	 *		let original = new Position( root, [ 2, 3, 1 ] );
-	 *		let source = new Position( root, [ 2, 2 ] );
-	 *		let target = new Position( otherRoot, [ 1, 1, 3 ] );
+	 *		let original = model.createPositionFromPath( root, [ 2, 3, 1 ] );
+	 *		let source = model.createPositionFromPath( root, [ 2, 2 ] );
+	 *		let target = model.createPositionFromPath( otherRoot, [ 1, 1, 3 ] );
 	 *		original._getCombined( source, target ); // path is [ 1, 1, 4, 1 ], root is `otherRoot`
 	 *
 	 * Explanation:
@@ -774,7 +779,7 @@ export default class Position {
 		const i = source.path.length - 1;
 
 		// The first part of a path to combined position is a path to the place where nodes were moved.
-		const combined = Position.createFromPosition( target );
+		const combined = Position._createAt( target );
 		combined.stickiness = this.stickiness;
 
 		// Then we have to update the rest of the path.
@@ -800,6 +805,15 @@ export default class Position {
 		};
 	}
 
+	/**
+	 * Returns a new position that is equal to current position.
+	 *
+	 * @returns {module:engine/model/position~Position}
+	 */
+	clone() {
+		return new this.constructor( this.root, this.path, this.stickiness );
+	}
+
 	/**
 	 * Creates position at the given location. The location can be specified as:
 	 *
@@ -808,42 +822,54 @@ export default class Position {
 	 * * parent element and `'end'` (sets position at the end of that element),
 	 * * {@link module:engine/model/item~Item model item} and `'before'` or `'after'` (sets position before or after given model item).
 	 *
-	 * This method is a shortcut to other constructors such as:
+	 * This method is a shortcut to other factory methods such as:
 	 *
-	 * * {@link module:engine/model/position~Position.createBefore},
-	 * * {@link module:engine/model/position~Position.createAfter},
-	 * * {@link module:engine/model/position~Position.createFromParentAndOffset},
-	 * * {@link module:engine/model/position~Position.createFromPosition}.
+	 * * {@link module:engine/model/position~Position._createBefore},
+	 * * {@link module:engine/model/position~Position._createAfter}.
 	 *
 	 * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
 	 * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
 	 * first parameter is a {@link module:engine/model/item~Item model item}.
+	 * @protected
 	 */
-	static createAt( itemOrPosition, offset ) {
+	static _createAt( itemOrPosition, offset ) {
 		if ( itemOrPosition instanceof Position ) {
-			return this.createFromPosition( itemOrPosition );
+			return new Position( itemOrPosition.root, itemOrPosition.path, itemOrPosition.stickiness );
 		} else {
 			const node = itemOrPosition;
 
 			if ( offset == 'end' ) {
 				offset = node.maxOffset;
 			} else if ( offset == 'before' ) {
-				return this.createBefore( node );
+				return this._createBefore( node );
 			} else if ( offset == 'after' ) {
-				return this.createAfter( node );
+				return this._createAfter( node );
 			} else if ( offset !== 0 && !offset ) {
 				/**
-				 * {@link module:engine/model/position~Position.createAt `Position.createAt()`}
+				 * {@link module:engine/model/model~Model#createPositionAt `Model#createPositionAt()`}
 				 * requires the offset to be specified when the first parameter is a model item.
 				 *
-				 * @error model-position-createAt-offset-required
+				 * @error model-createPositionAt-offset-required
 				 */
 				throw new CKEditorError(
-					'model-position-createAt-offset-required: ' +
-					'Position.createAt() requires the offset when the first parameter is a model item.' );
+					'model-createPositionAt-offset-required: ' +
+					'Model#createPositionAt() requires the offset when the first parameter is a model item.' );
 			}
 
-			return this.createFromParentAndOffset( node, offset );
+			if ( !node.is( 'element' ) && !node.is( 'documentFragment' ) ) {
+				/**
+				 * Position parent have to be a model element or model document fragment.
+				 *
+				 * @error model-position-parent-incorrect
+				 */
+				throw new CKEditorError( 'model-position-parent-incorrect: Position parent have to be a element or document fragment.' );
+			}
+
+			const path = node.getPath();
+
+			path.push( offset );
+
+			return new this( node.root, path );
 		}
 	}
 
@@ -852,8 +878,9 @@ export default class Position {
 	 *
 	 * @param {module:engine/model/item~Item} item Item after which the position should be placed.
 	 * @returns {module:engine/model/position~Position}
+	 * @protected
 	 */
-	static createAfter( item ) {
+	static _createAfter( item ) {
 		if ( !item.parent ) {
 			/**
 			 * You can not make a position after a root element.
@@ -864,7 +891,7 @@ export default class Position {
 			throw new CKEditorError( 'model-position-after-root: You cannot make a position after root.', { root: item } );
 		}
 
-		return this.createFromParentAndOffset( item.parent, item.endOffset );
+		return this._createAt( item.parent, item.endOffset );
 	}
 
 	/**
@@ -872,8 +899,9 @@ export default class Position {
 	 *
 	 * @param {module:engine/model/item~Item} item Item before which the position should be placed.
 	 * @returns {module:engine/model/position~Position}
+	 * @protected
 	 */
-	static createBefore( item ) {
+	static _createBefore( item ) {
 		if ( !item.parent ) {
 			/**
 			 * You can not make a position before a root element.
@@ -884,44 +912,7 @@ export default class Position {
 			throw new CKEditorError( 'model-position-before-root: You cannot make a position before root.', { root: item } );
 		}
 
-		return this.createFromParentAndOffset( item.parent, item.startOffset );
-	}
-
-	/**
-	 * Creates a new position from the parent element and an offset in that element.
-	 *
-	 * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} parent Position's parent.
-	 * @param {Number} offset Position's offset.
-	 * @returns {module:engine/model/position~Position}
-	 */
-	static createFromParentAndOffset( parent, offset ) {
-		if ( !parent.is( 'element' ) && !parent.is( 'documentFragment' ) ) {
-			/**
-			 * Position parent have to be a model element or model document fragment.
-			 *
-			 * @error model-position-parent-incorrect
-			 */
-			throw new CKEditorError( 'model-position-parent-incorrect: Position parent have to be a element or document fragment.' );
-		}
-
-		const path = parent.getPath();
-
-		path.push( offset );
-
-		return new this( parent.root, path );
-	}
-
-	/**
-	 * Creates a new position, which is equal to passed position.
-	 *
-	 * @param {module:engine/model/position~Position} position Position to be cloned.
-	 * @returns {module:engine/model/position~Position}
-	 */
-	static createFromPosition( position ) {
-		const newPos = new this( position.root, position.path.slice() );
-		newPos.stickiness = position.stickiness;
-
-		return newPos;
+		return this._createAt( item.parent, item.startOffset );
 	}
 
 	/**

+ 60 - 76
packages/ckeditor5-engine/src/model/range.js

@@ -13,14 +13,18 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';
 
 /**
- * Range class. Range is iterable.
+ * Represents a range in the model tree.
+ *
+ * A range is defined by its {@link module:engine/model/range~Range#start} and {@link module:engine/model/range~Range#end}
+ * positions.
+ *
+ * You can create range instances via its constructor or the `createRange*()` factory methods of
+ * {@link module:engine/model/model~Model} and {@link module:engine/model/writer~Writer}.
  */
 export default class Range {
 	/**
 	 * Creates a range spanning from `start` position to `end` position.
 	 *
-	 * **Note:** Constructor creates it's own {@link module:engine/model/position~Position Position} instances basing on passed values.
-	 *
 	 * @param {module:engine/model/position~Position} start Start position.
 	 * @param {module:engine/model/position~Position} [end] End position. If not set, range will be collapsed at `start` position.
 	 */
@@ -31,7 +35,7 @@ export default class Range {
 		 * @readonly
 		 * @member {module:engine/model/position~Position}
 		 */
-		this.start = Position.createFromPosition( start );
+		this.start = Position._createAt( start );
 
 		/**
 		 * End position.
@@ -39,7 +43,7 @@ export default class Range {
 		 * @readonly
 		 * @member {module:engine/model/position~Position}
 		 */
-		this.end = end ? Position.createFromPosition( end ) : Position.createFromPosition( start );
+		this.end = end ? Position._createAt( end ) : Position._createAt( start );
 
 		// If the range is collapsed, treat in a similar way as a position and set its boundaries stickiness to 'toNone'.
 		// In other case, make the boundaries stick to the "inside" of the range.
@@ -134,7 +138,7 @@ export default class Range {
 	 * @param {module:engine/model/item~Item} item Model item to check.
 	 */
 	containsItem( item ) {
-		const pos = Position.createBefore( item );
+		const pos = Position._createBefore( item );
 
 		return this.containsPosition( pos ) || this.start.isEqual( pos );
 	}
@@ -165,16 +169,19 @@ export default class Range {
 	 *
 	 * Examples:
 	 *
-	 *		let range = new Range( new Position( root, [ 2, 7 ] ), new Position( root, [ 4, 0, 1 ] ) );
-	 *		let otherRange = new Range( new Position( root, [ 1 ] ), new Position( root, [ 5 ] ) );
+	 *		let range = model.createRange(
+	 *			model.createPositionFromPath( root, [ 2, 7 ] ),
+	 *			model.createPositionFromPath( root, [ 4, 0, 1 ] )
+	 *		);
+	 *		let otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 5 ] ) );
 	 *		let transformed = range.getDifference( otherRange );
 	 *		// transformed array has no ranges because `otherRange` contains `range`
 	 *
-	 *		otherRange = new Range( new Position( root, [ 1 ] ), new Position( root, [ 3 ] ) );
+	 *		otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 3 ] ) );
 	 *		transformed = range.getDifference( otherRange );
 	 *		// transformed array has one range: from [ 3 ] to [ 4, 0, 1 ]
 	 *
-	 *		otherRange = new Range( new Position( root, [ 3 ] ), new Position( root, [ 4 ] ) );
+	 *		otherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 4 ] ) );
 	 *		transformed = range.getDifference( otherRange );
 	 *		// transformed array has two ranges: from [ 2, 7 ] to [ 3 ] and from [ 4 ] to [ 4, 0, 1 ]
 	 *
@@ -200,7 +207,7 @@ export default class Range {
 			}
 		} else {
 			// Ranges do not intersect, return the original range.
-			ranges.push( Range.createFromRange( this ) );
+			ranges.push( new Range( this.start, this.end ) );
 		}
 
 		return ranges;
@@ -212,11 +219,14 @@ export default class Range {
 	 *
 	 * Examples:
 	 *
-	 *		let range = new Range( new Position( root, [ 2, 7 ] ), new Position( root, [ 4, 0, 1 ] ) );
-	 *		let otherRange = new Range( new Position( root, [ 1 ] ), new Position( root, [ 2 ] ) );
+	 *		let range = model.createRange(
+	 *			model.createPositionFromPath( root, [ 2, 7 ] ),
+	 *			model.createPositionFromPath( root, [ 4, 0, 1 ] )
+	 *		);
+	 *		let otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 2 ] ) );
 	 *		let transformed = range.getIntersection( otherRange ); // null - ranges have no common part
 	 *
-	 *		otherRange = new Range( new Position( root, [ 3 ] ), new Position( root, [ 5 ] ) );
+	 *		otherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 5 ] ) );
 	 *		transformed = range.getIntersection( otherRange ); // range from [ 3 ] to [ 4, 0, 1 ]
 	 *
 	 * @param {module:engine/model/range~Range} otherRange Range to check for intersection.
@@ -291,7 +301,7 @@ export default class Range {
 		const ranges = [];
 		const diffAt = this.start.getCommonPath( this.end ).length;
 
-		const pos = Position.createFromPosition( this.start );
+		const pos = Position._createAt( this.start );
 		let posParent = pos.parent;
 
 		// Go up.
@@ -413,7 +423,7 @@ export default class Range {
 				return [ this._getTransformedByMergeOperation( operation ) ];
 		}
 
-		return [ Range.createFromRange( this ) ];
+		return [ new Range( this.start, this.end ) ];
 	}
 
 	/**
@@ -424,7 +434,7 @@ export default class Range {
 	 * @returns {Array.<module:engine/model/range~Range>} Range which is the result of transformation.
 	 */
 	getTransformedByOperations( operations ) {
-		const ranges = [ Range.createFromRange( this ) ];
+		const ranges = [ new Range( this.start, this.end ) ];
 
 		for ( const operation of operations ) {
 			for ( let i = 0; i < ranges.length; i++ ) {
@@ -476,6 +486,15 @@ export default class Range {
 		};
 	}
 
+	/**
+	 * Returns a new range that is equal to current range.
+	 *
+	 * @returns {module:engine/model/range~Range}
+	 */
+	clone() {
+		return new this.constructor( this.start, this.end );
+	}
+
 	/**
 	 * Returns a result of transforming a copy of this range by insert operation.
 	 *
@@ -582,7 +601,7 @@ export default class Range {
 
 			if ( operation.sourcePosition.isBefore( operation.targetPosition ) ) {
 				// Case 1.
-				start = Position.createFromPosition( end );
+				start = Position._createAt( end );
 				start.offset = 0;
 			} else {
 				if ( !operation.deletionPosition.isEqual( start ) ) {
@@ -607,17 +626,20 @@ export default class Range {
 	 *
 	 * Examples:
 	 *
-	 *		let range = new Range( new Position( root, [ 2, 7 ] ), new Position( root, [ 4, 0, 1 ] ) );
-	 *		let transformed = range._getTransformedByInsertion( new Position( root, [ 1 ] ), 2 );
+	 *		let range = model.createRange(
+	 *			model.createPositionFromPath( root, [ 2, 7 ] ),
+	 *			model.createPositionFromPath( root, [ 4, 0, 1 ] )
+	 *		);
+	 *		let transformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 1 ] ), 2 );
 	 *		// transformed array has one range from [ 4, 7 ] to [ 6, 0, 1 ]
 	 *
-	 *		transformed = range._getTransformedByInsertion( new Position( root, [ 4, 0, 0 ] ), 4 );
+	 *		transformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 4, 0, 0 ] ), 4 );
 	 *		// transformed array has one range from [ 2, 7 ] to [ 4, 0, 5 ]
 	 *
-	 *		transformed = range._getTransformedByInsertion( new Position( root, [ 3, 2 ] ), 4 );
+	 *		transformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4 );
 	 *		// transformed array has one range, which is equal to original range
 	 *
-	 *		transformed = range._getTransformedByInsertion( new Position( root, [ 3, 2 ] ), 4, true );
+	 *		transformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4, true );
 	 *		// transformed array has two ranges: from [ 2, 7 ] to [ 3, 2 ] and from [ 3, 6 ] to [ 4, 0, 1 ]
 	 *
 	 * @protected
@@ -641,7 +663,7 @@ export default class Range {
 				)
 			];
 		} else {
-			const range = Range.createFromRange( this );
+			const range = new Range( this.start, this.end );
 
 			range.start = range.start._getTransformedByInsertion( insertPosition, howMany );
 			range.end = range.end._getTransformedByInsertion( insertPosition, howMany );
@@ -681,7 +703,7 @@ export default class Range {
 		// <div><p>ab</p><p>c[d</p></div><p>e]f</p> --> <div><p>ab</p>{</div>}<p>c[d</p><p>e]f</p>
 		//
 		// This special case is applied only if the range is to be kept together (not spread).
-		const moveRange = Range.createFromPositionAndShift( sourcePosition, howMany );
+		const moveRange = Range._createFromPositionAndShift( sourcePosition, howMany );
 		const insertPosition = targetPosition._getTransformedByDeletion( sourcePosition, howMany );
 
 		if ( this.containsPosition( targetPosition ) && !spread ) {
@@ -772,77 +794,39 @@ export default class Range {
 	 * Creates a new range, spreading from specified {@link module:engine/model/position~Position position} to a position moved by
 	 * given `shift`. If `shift` is a negative value, shifted position is treated as the beginning of the range.
 	 *
+	 * @protected
 	 * @param {module:engine/model/position~Position} position Beginning of the range.
 	 * @param {Number} shift How long the range should be.
 	 * @returns {module:engine/model/range~Range}
 	 */
-	static createFromPositionAndShift( position, shift ) {
+	static _createFromPositionAndShift( position, shift ) {
 		const start = position;
 		const end = position.getShiftedBy( shift );
 
 		return shift > 0 ? new this( start, end ) : new this( end, start );
 	}
 
-	/**
-	 * Creates a range from given parents and offsets.
-	 *
-	 * @param {module:engine/model/element~Element} startElement Start position parent element.
-	 * @param {Number} startOffset Start position offset.
-	 * @param {module:engine/model/element~Element} endElement End position parent element.
-	 * @param {Number} endOffset End position offset.
-	 * @returns {module:engine/model/range~Range}
-	 */
-	static createFromParentsAndOffsets( startElement, startOffset, endElement, endOffset ) {
-		return new this(
-			Position.createFromParentAndOffset( startElement, startOffset ),
-			Position.createFromParentAndOffset( endElement, endOffset )
-		);
-	}
-
-	/**
-	 * Creates a new instance of `Range` which is equal to passed range.
-	 *
-	 * @param {module:engine/model/range~Range} range Range to clone.
-	 * @returns {module:engine/model/range~Range}
-	 */
-	static createFromRange( range ) {
-		return new this( range.start, range.end );
-	}
-
 	/**
 	 * Creates a range inside an {@link module:engine/model/element~Element element} which starts before the first child of
 	 * that element and ends after the last child of that element.
 	 *
+	 * @protected
 	 * @param {module:engine/model/element~Element} element Element which is a parent for the range.
 	 * @returns {module:engine/model/range~Range}
 	 */
-	static createIn( element ) {
-		return this.createFromParentsAndOffsets( element, 0, element, element.maxOffset );
+	static _createIn( element ) {
+		return new this( Position._createAt( element, 0 ), Position._createAt( element, element.maxOffset ) );
 	}
 
 	/**
 	 * Creates a range that starts before given {@link module:engine/model/item~Item model item} and ends after it.
 	 *
+	 * @protected
 	 * @param {module:engine/model/item~Item} item
 	 * @returns {module:engine/model/range~Range}
 	 */
-	static createOn( item ) {
-		return this.createFromPositionAndShift( Position.createBefore( item ), item.offsetSize );
-	}
-
-	/**
-	 * Creates a collapsed range at given {@link module:engine/model/position~Position position}
-	 * or on the given {@link module:engine/model/item~Item item}.
-	 *
-	 * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
-	 * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
-	 * first parameter is a {@link module:engine/model/item~Item model item}.
-	 */
-	static createCollapsedAt( itemOrPosition, offset ) {
-		const start = Position.createAt( itemOrPosition, offset );
-		const end = Position.createFromPosition( start );
-
-		return new Range( start, end );
+	static _createOn( item ) {
+		return this._createFromPositionAndShift( Position._createBefore( item ), item.offsetSize );
 	}
 
 	/**
@@ -860,17 +844,17 @@ export default class Range {
 	 * @param {Array.<module:engine/model/range~Range>} ranges Ranges to combine.
 	 * @returns {module:engine/model/range~Range} Combined range.
 	 */
-	static createFromRanges( ranges ) {
+	static _createFromRanges( ranges ) {
 		if ( ranges.length === 0 ) {
 			/**
 			 * At least one range has to be passed to
-			 * {@link module:engine/model/range~Range.createFromRanges `Range.createFromRanges()`}.
+			 * {@link module:engine/model/range~Range._createFromRanges `Range._createFromRanges()`}.
 			 *
 			 * @error range-create-from-ranges-empty-array
 			 */
 			throw new CKEditorError( 'range-create-from-ranges-empty-array: At least one range has to be passed.' );
 		} else if ( ranges.length == 1 ) {
-			return this.createFromRange( ranges[ 0 ] );
+			return ranges[ 0 ].clone();
 		}
 
 		// 1. Set the first range in `ranges` array as a reference range.
@@ -896,7 +880,7 @@ export default class Range {
 		if ( refIndex > 0 ) {
 			for ( let i = refIndex - 1; true; i++ ) {
 				if ( ranges[ i ].end.isEqual( result.start ) ) {
-					result.start = Position.createFromPosition( ranges[ i ].start );
+					result.start = Position._createAt( ranges[ i ].start );
 				} else {
 					// If ranges are not starting/ending at the same position there is no point in looking further.
 					break;
@@ -908,7 +892,7 @@ export default class Range {
 		// Since ranges are sorted, start with the range with index that is closest to reference range index.
 		for ( let i = refIndex + 1; i < ranges.length; i++ ) {
 			if ( ranges[ i ].start.isEqual( result.end ) ) {
-				result.end = Position.createFromPosition( ranges[ i ].end );
+				result.end = Position._createAt( ranges[ i ].end );
 			} else {
 				// If ranges are not starting/ending at the same position there is no point in looking further.
 				break;

+ 15 - 5
packages/ckeditor5-engine/src/model/schema.js

@@ -547,7 +547,7 @@ export default class Schema {
 
 		for ( const item of range.getItems( { shallow: true } ) ) {
 			if ( item.is( 'element' ) ) {
-				yield* this._getValidRangesForRange( Range.createIn( item ), attribute );
+				yield* this._getValidRangesForRange( Range._createIn( item ), attribute );
 			}
 
 			if ( !this.checkAttribute( item, attribute ) ) {
@@ -555,10 +555,10 @@ export default class Schema {
 					yield new Range( start, end );
 				}
 
-				start = Position.createAfter( item );
+				start = Position._createAfter( item );
 			}
 
-			end = Position.createAfter( item );
+			end = Position._createAfter( item );
 		}
 
 		if ( !start.isEqual( end ) ) {
@@ -607,7 +607,7 @@ export default class Schema {
 			const value = data.value;
 
 			if ( value.type == type && this.isObject( value.item ) ) {
-				return Range.createOn( value.item );
+				return Range._createOn( value.item );
 			}
 
 			if ( this.checkChild( value.nextPosition, '$text' ) ) {
@@ -667,6 +667,16 @@ export default class Schema {
 		}
 	}
 
+	/**
+	 * Creates an instance of the schema context.
+	 *
+	 * @param {module:engine/model/schema~SchemaContextDefinition} context
+	 * @returns {module:engine/model/schema~SchemaContext}
+	 */
+	createContext( context ) {
+		return new SchemaContext( context );
+	}
+
 	/**
 	 * @private
 	 */
@@ -1162,7 +1172,7 @@ export class SchemaContext {
  *		schema.checkChild( contextDefinition, childToCheck );
  *
  *		// Also check in [ rootElement, blockQuoteElement, paragraphElement ].
- *		schema.checkChild( Position.createAt( paragraphElement, 0 ), 'foo' );
+ *		schema.checkChild( model.createPositionAt( paragraphElement, 0 ), 'foo' );
  *
  *		// Check in [ rootElement, paragraphElement ].
  *		schema.checkChild( [ rootElement, paragraphElement ], 'foo' );

+ 35 - 34
packages/ckeditor5-engine/src/model/selection.js

@@ -36,46 +36,46 @@ export default class Selection {
 	 * or creates an empty selection if no arguments were passed.
 	 *
 	 *		// Creates empty selection without ranges.
-	 *		const selection = new Selection();
+	 *		const selection = writer.createSelection();
 	 *
 	 *		// Creates selection at the given range.
-	 *		const range = new Range( start, end );
-	 *		const selection = new Selection( range );
+	 *		const range = writer.createRange( start, end );
+	 *		const selection = writer.createSelection( range );
 	 *
 	 *		// Creates selection at the given ranges
-	 *		const ranges = [ new Range( start1, end2 ), new Range( star2, end2 ) ];
-	 *		const selection = new Selection( ranges );
+	 *		const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
+	 *		const selection = writer.createSelection( ranges );
 	 *
 	 *		// Creates selection from the other selection.
 	 *		// Note: It doesn't copies selection attributes.
-	 *		const otherSelection = new Selection();
-	 *		const selection = new Selection( otherSelection );
+	 *		const otherSelection = writer.createSelection();
+	 *		const selection = writer.createSelection( otherSelection );
 	 *
 	 *		// Creates selection from the given document selection.
 	 *		// Note: It doesn't copies selection attributes.
-	 *		const documentSelection = new DocumentSelection( doc );
-	 *		const selection = new Selection( documentSelection );
+	 *		const documentSelection = model.document.selection;
+	 *		const selection = writer.createSelection( documentSelection );
 	 *
 	 *		// Creates selection at the given position.
-	 *		const position = new Position( root, path );
-	 *		const selection = new Selection( position );
+	 *		const position = writer.createPositionFromPath( root, path );
+	 *		const selection = writer.createSelection( position );
 	 *
 	 *		// Creates selection at the given offset in the given element.
 	 *		const paragraph = writer.createElement( 'paragraph' );
-	 *		const selection = new Selection( paragraph, offset );
+	 *		const selection = writer.createSelection( paragraph, offset );
 	 *
 	 *		// Creates a range inside an {@link module:engine/model/element~Element element} which starts before the
 	 *		// first child of that element and ends after the last child of that element.
-	 *		const selection = new Selection( paragraph, 'in' );
+	 *		const selection = writer.createSelection( paragraph, 'in' );
 	 *
 	 *		// Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends
 	 *		// just after the item.
-	 *		const selection = new Selection( paragraph, 'on' );
+	 *		const selection = writer.createSelection( paragraph, 'on' );
 	 *
 	 * Selection's constructor allow passing additional options (`'backward'`) as the last argument.
 	 *
 	 *		// Creates backward selection.
-	 *		const selection = new Selection( range, { backward: true } );
+	 *		const selection = writer.createSelection( range, { backward: true } );
 	 *
 	 * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection|
 	 * module:engine/model/position~Position|module:engine/model/element~Element|
@@ -242,7 +242,7 @@ export default class Selection {
 	 */
 	* getRanges() {
 		for ( const range of this._ranges ) {
-			yield Range.createFromRange( range );
+			yield new Range( range.start, range.end );
 		}
 	}
 
@@ -265,7 +265,7 @@ export default class Selection {
 			}
 		}
 
-		return first ? Range.createFromRange( first ) : null;
+		return first ? new Range( first.start, first.end ) : null;
 	}
 
 	/**
@@ -287,7 +287,7 @@ export default class Selection {
 			}
 		}
 
-		return last ? Range.createFromRange( last ) : null;
+		return last ? new Range( last.start, last.end ) : null;
 	}
 
 	/**
@@ -302,7 +302,7 @@ export default class Selection {
 	getFirstPosition() {
 		const first = this.getFirstRange();
 
-		return first ? Position.createFromPosition( first.start ) : null;
+		return first ? first.start.clone() : null;
 	}
 
 	/**
@@ -317,7 +317,7 @@ export default class Selection {
 	getLastPosition() {
 		const lastRange = this.getLastRange();
 
-		return lastRange ? Position.createFromPosition( lastRange.end ) : null;
+		return lastRange ? lastRange.end.clone() : null;
 	}
 
 	/**
@@ -330,16 +330,16 @@ export default class Selection {
 	 *		selection.setTo( null );
 	 *
 	 *		// Sets selection to the given range.
-	 *		const range = new Range( start, end );
+	 *		const range = writer.createRange( start, end );
 	 *		selection.setTo( range );
 	 *
 	 *		// Sets selection to given ranges.
-	 *		const ranges = [ new Range( start1, end2 ), new Range( star2, end2 ) ];
+	 *		const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
 	 *		selection.setTo( ranges );
 	 *
 	 *		// Sets selection to other selection.
 	 *		// Note: It doesn't copies selection attributes.
-	 *		const otherSelection = new Selection();
+	 *		const otherSelection = writer.createSelection();
 	 *		selection.setTo( otherSelection );
 	 *
 	 *		// Sets selection to the given document selection.
@@ -348,7 +348,7 @@ export default class Selection {
 	 *		selection.setTo( documentSelection );
 	 *
 	 *		// Sets collapsed selection at the given position.
-	 *		const position = new Position( root, path );
+	 *		const position = writer.createPositionFromPath( root, path );
 	 *		selection.setTo( position );
 	 *
 	 *		// Sets collapsed selection at the position of the given node and an offset.
@@ -366,7 +366,7 @@ export default class Selection {
 	 * `Selection#setTo()`' method allow passing additional options (`backward`) as the last argument.
 	 *
 	 *		// Sets backward selection.
-	 *		const selection = new Selection( range, { backward: true } );
+	 *		const selection = writer.createSelection( range, { backward: true } );
 	 *
 	 * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection|
 	 * module:engine/model/position~Position|module:engine/model/node~Node|
@@ -393,11 +393,11 @@ export default class Selection {
 			let range;
 
 			if ( placeOrOffset == 'in' ) {
-				range = Range.createIn( selectable );
+				range = Range._createIn( selectable );
 			} else if ( placeOrOffset == 'on' ) {
-				range = Range.createOn( selectable );
+				range = Range._createOn( selectable );
 			} else if ( placeOrOffset !== undefined ) {
-				range = Range.createCollapsedAt( selectable, placeOrOffset );
+				range = new Range( Position._createAt( selectable, placeOrOffset ) );
 			} else {
 				/**
 				 * selection.setTo requires the second parameter when the first parameter is a node.
@@ -481,7 +481,8 @@ export default class Selection {
 	/**
 	 * Moves {@link module:engine/model/selection~Selection#focus} to the specified location.
 	 *
-	 * The location can be specified in the same form as {@link module:engine/model/position~Position.createAt} parameters.
+	 * The location can be specified in the same form as
+	 * {@link module:engine/model/writer~Writer#createPositionAt writer.createPositionAt()} parameters.
 	 *
 	 * @fires change:range
 	 * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
@@ -500,7 +501,7 @@ export default class Selection {
 			);
 		}
 
-		const newFocus = Position.createAt( itemOrPosition, offset );
+		const newFocus = Position._createAt( itemOrPosition, offset );
 
 		if ( newFocus.compareWith( this.focus ) == 'same' ) {
 			return;
@@ -665,7 +666,7 @@ export default class Selection {
 			const endBlock = getParentBlock( range.end, visited );
 
 			// #984. Don't return the end block if the range ends right at its beginning.
-			if ( endBlock && !range.end.isTouching( Position.createAt( endBlock, 0 ) ) ) {
+			if ( endBlock && !range.end.isTouching( Position._createAt( endBlock, 0 ) ) ) {
 				yield endBlock;
 			}
 		}
@@ -683,8 +684,8 @@ export default class Selection {
 	 * @returns {Boolean}
 	 */
 	containsEntireContent( element = this.anchor.root ) {
-		const limitStartPosition = Position.createAt( element, 0 );
-		const limitEndPosition = Position.createAt( element, 'end' );
+		const limitStartPosition = Position._createAt( element, 0 );
+		const limitEndPosition = Position._createAt( element, 'end' );
 
 		return limitStartPosition.isTouching( this.getFirstPosition() ) &&
 			limitEndPosition.isTouching( this.getLastPosition() );
@@ -699,7 +700,7 @@ export default class Selection {
 	 */
 	_pushRange( range ) {
 		this._checkRange( range );
-		this._ranges.push( Range.createFromRange( range ) );
+		this._ranges.push( new Range( range.start, range.end ) );
 	}
 
 	/**

+ 6 - 9
packages/ckeditor5-engine/src/model/treewalker.js

@@ -85,9 +85,9 @@ export default class TreeWalker {
 		 * @member {module:engine/model/position~Position} module:engine/model/treewalker~TreeWalker#position
 		 */
 		if ( options.startPosition ) {
-			this.position = Position.createFromPosition( options.startPosition );
+			this.position = options.startPosition.clone();
 		} else {
-			this.position = Position.createFromPosition( this.boundaries[ this.direction == 'backward' ? 'end' : 'start' ] );
+			this.position = Position._createAt( this.boundaries[ this.direction == 'backward' ? 'end' : 'start' ] );
 		}
 
 		// Reset position stickiness in case it was set to other value, as the stickiness is kept after cloning.
@@ -208,7 +208,7 @@ export default class TreeWalker {
 	 */
 	_next() {
 		const previousPosition = this.position;
-		const position = Position.createFromPosition( this.position );
+		const position = this.position.clone();
 		const parent = this._visitedParent;
 
 		// We are at the end of the root.
@@ -282,7 +282,7 @@ export default class TreeWalker {
 	 */
 	_previous() {
 		const previousPosition = this.position;
-		const position = Position.createFromPosition( this.position );
+		const position = this.position.clone();
 		const parent = this._visitedParent;
 
 		// We are at the beginning of the root.
@@ -379,10 +379,7 @@ function formatReturnValue( type, item, previousPosition, nextPosition, length )
  * @property {module:engine/model/item~Item} item Item between old and new positions of {@link module:engine/model/treewalker~TreeWalker}.
  * @property {module:engine/model/position~Position} previousPosition Previous position of the iterator.
  * * Forward iteration: For `'elementEnd'` it is the last position inside the element. For all other types it is the
- * position before the item. Note that it is more efficient to use this position then calculate the position before
- * the node using {@link module:engine/model/position~Position.createBefore}. It is also more efficient to get the
- * position after node by shifting `previousPosition` by `length`, using {@link module:engine/model/position~Position#getShiftedBy},
- * then calculate the position using {@link module:engine/model/position~Position.createAfter}.
+ * position before the item.
  * * Backward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is
  * the position after item.
  * @property {module:engine/model/position~Position} nextPosition Next position of the iterator.
@@ -391,7 +388,7 @@ function formatReturnValue( type, item, previousPosition, nextPosition, length )
  * * Backward iteration: For `'elementEnd'` it is last position inside element. For all other types it is the position
  * before the item.
  * @property {Number} [length] Length of the item. For `'elementStart'` and `'character'` it is 1. For `'text'` it is
- * the length of the text. For `'elementEnd'` it is undefined.
+ * the length of the text. For `'elementEnd'` it is `undefined`.
  */
 
 /**

+ 6 - 8
packages/ckeditor5-engine/src/model/utils/deletecontent.js

@@ -8,7 +8,6 @@
  */
 
 import LivePosition from '../liveposition';
-import Position from '../position';
 import Range from '../range';
 import DocumentSelection from '../documentselection';
 
@@ -62,8 +61,7 @@ export default function deleteContent( model, selection, options = {} ) {
 
 		const selRange = selection.getFirstRange();
 		const startPos = selRange.start;
-		const endPos = LivePosition.createFromPosition( selRange.end );
-		endPos.stickiness = 'toNext';
+		const endPos = LivePosition.fromPosition( selRange.end, 'toNext' );
 
 		// 2. Remove the content if there is any.
 		if ( !selRange.start.isTouching( selRange.end ) ) {
@@ -134,8 +132,8 @@ function mergeBranches( writer, startPos, endPos ) {
 	// <a><b>x[]</b></a><c><d>{}y</d></c>
 	// will become:
 	// <a><b>xy</b>[]</a><c>{}</c>
-	startPos = Position.createAfter( startParent );
-	endPos = Position.createBefore( endParent );
+	startPos = writer.createPositionAfter( startParent );
+	endPos = writer.createPositionBefore( endParent );
 
 	if ( !endPos.isEqual( startPos ) ) {
 		// In this case, before we merge, we need to move `endParent` to the `startPos`:
@@ -158,7 +156,7 @@ function mergeBranches( writer, startPos, endPos ) {
 	while ( endPos.parent.isEmpty ) {
 		const parentToRemove = endPos.parent;
 
-		endPos = Position.createBefore( parentToRemove );
+		endPos = writer.createPositionBefore( parentToRemove );
 
 		writer.remove( parentToRemove );
 	}
@@ -207,8 +205,8 @@ function insertParagraph( writer, position, selection ) {
 function replaceEntireContentWithParagraph( writer, selection ) {
 	const limitElement = writer.model.schema.getLimitElement( selection );
 
-	writer.remove( Range.createIn( limitElement ) );
-	insertParagraph( writer, Position.createAt( limitElement, 0 ), selection );
+	writer.remove( writer.createRangeIn( limitElement ) );
+	insertParagraph( writer, writer.createPositionAt( limitElement, 0 ), selection );
 }
 
 // We want to replace the entire content with a paragraph when:

+ 8 - 11
packages/ckeditor5-engine/src/model/utils/getselectedcontent.js

@@ -7,9 +7,6 @@
  * @module engine/model/utils/getselectedcontent
  */
 
-import Range from '../range';
-import Position from '../position';
-
 /**
  * Gets a clone of the selected content.
  *
@@ -63,9 +60,9 @@ export default function getSelectedContent( model, selection ) {
 			// The original range is flat, so take it.
 			flatSubtreeRange = range;
 		} else {
-			flatSubtreeRange = Range.createFromParentsAndOffsets(
-				commonParent, range.start.path[ commonPath.length ],
-				commonParent, range.end.path[ commonPath.length ] + 1
+			flatSubtreeRange = writer.createRange(
+				writer.createPositionAt( commonParent, range.start.path[ commonPath.length ] ),
+				writer.createPositionAt( commonParent, range.end.path[ commonPath.length ] + 1 )
 			);
 		}
 
@@ -97,10 +94,10 @@ export default function getSelectedContent( model, selection ) {
 		// [<quote><p>y</p><h>fir]st</h></quote><p>se[cond</p>]
 		if ( flatSubtreeRange != range ) {
 			// Find the position of the original range in the cloned fragment.
-			const newRange = range._getTransformedByMove( flatSubtreeRange.start, Position.createAt( frag, 0 ), howMany )[ 0 ];
+			const newRange = range._getTransformedByMove( flatSubtreeRange.start, writer.createPositionAt( frag, 0 ), howMany )[ 0 ];
 
-			const leftExcessRange = new Range( Position.createAt( frag, 0 ), newRange.start );
-			const rightExcessRange = new Range( newRange.end, Position.createAt( frag, 'end' ) );
+			const leftExcessRange = writer.createRange( writer.createPositionAt( frag, 0 ), newRange.start );
+			const rightExcessRange = writer.createRange( newRange.end, writer.createPositionAt( frag, 'end' ) );
 
 			removeRangeContent( rightExcessRange, writer );
 			removeRangeContent( leftExcessRange, writer );
@@ -118,7 +115,7 @@ function removeRangeContent( range, writer ) {
 	Array.from( range.getItems( { direction: 'backward' } ) )
 		// We should better store ranges because text proxies will lose integrity
 		// with the text nodes when we'll start removing content.
-		.map( item => Range.createOn( item ) )
+		.map( item => writer.createRangeOn( item ) )
 		// Filter only these items which are fully contained in the passed range.
 		//
 		// E.g. for the following range: [<quote><p>y</p><h>fir]st</h>
@@ -143,7 +140,7 @@ function removeRangeContent( range, writer ) {
 		let parent = parentToCheck;
 
 		while ( parent.parent && parent.isEmpty ) {
-			const removeRange = Range.createOn( parent );
+			const removeRange = writer.createRangeOn( parent );
 
 			parent = parent.parent;
 

+ 17 - 18
packages/ckeditor5-engine/src/model/utils/insertcontent.js

@@ -44,7 +44,7 @@ export default function insertContent( model, content, selectable, placeOrOffset
 		} else if ( selectable instanceof Selection || selectable instanceof DocumentSelection ) {
 			selection = selectable;
 		} else {
-			selection = new Selection( selectable, placeOrOffset );
+			selection = writer.createSelection( selectable, placeOrOffset );
 		}
 
 		if ( !selection.isCollapsed ) {
@@ -174,7 +174,7 @@ class Insertion {
 	 */
 	getSelectionRange() {
 		if ( this.nodeToSelect ) {
-			return Range.createOn( this.nodeToSelect );
+			return Range._createOn( this.nodeToSelect );
 		}
 
 		return this.model.schema.getNearestSelectionRange( this.position );
@@ -276,12 +276,11 @@ class Insertion {
 			return;
 		}
 
-		const livePos = LivePosition.createFromPosition( this.position );
-		livePos.stickiness = 'toNext';
+		const livePos = LivePosition.fromPosition( this.position, 'toNext' );
 
 		this.writer.insert( node, this.position );
 
-		this.position = Position.createFromPosition( livePos );
+		this.position = livePos.toPosition();
 		livePos.detach();
 
 		// The last inserted object should be selected because we can't put a collapsed selection after it.
@@ -306,19 +305,19 @@ class Insertion {
 
 		const mergeLeft = this._canMergeLeft( node, context );
 		const mergeRight = this._canMergeRight( node, context );
-		const mergePosLeft = LivePosition.createBefore( node );
+		const mergePosLeft = LivePosition._createBefore( node );
 		mergePosLeft.stickiness = 'toNext';
-		const mergePosRight = LivePosition.createAfter( node );
+		const mergePosRight = LivePosition._createAfter( node );
 		mergePosRight.stickiness = 'toNext';
 
 		if ( mergeLeft ) {
-			const position = LivePosition.createFromPosition( this.position );
-			position.stickiness = 'toNext';
+			const livePosition = LivePosition.fromPosition( this.position );
+			livePosition.stickiness = 'toNext';
 
 			this.writer.merge( mergePosLeft );
 
-			this.position = Position.createFromPosition( position );
-			position.detach();
+			this.position = livePosition.toPosition();
+			livePosition.detach();
 		}
 
 		if ( mergeRight ) {
@@ -332,16 +331,16 @@ class Insertion {
 
 			// Move the position to the previous node, so it isn't moved to the graveyard on merge.
 			// <p>x</p>[]<p>y</p> => <p>x[]</p><p>y</p>
-			this.position = Position.createAt( mergePosRight.nodeBefore, 'end' );
+			this.position = Position._createAt( mergePosRight.nodeBefore, 'end' );
 
 			// OK:  <p>xx[]</p> + <p>yy</p> => <p>xx[]yy</p> (when sticks to previous)
 			// NOK: <p>xx[]</p> + <p>yy</p> => <p>xxyy[]</p> (when sticks to next)
-			const position = new LivePosition( this.position.root, this.position.path, 'toPrevious' );
+			const livePosition = new LivePosition( this.position.root, this.position.path, 'toPrevious' );
 
 			this.writer.merge( mergePosRight );
 
-			this.position = Position.createFromPosition( position );
-			position.detach();
+			this.position = livePosition.toPosition();
+			livePosition.detach();
 		}
 
 		if ( mergeLeft || mergeRight ) {
@@ -428,7 +427,7 @@ class Insertion {
 
 			if ( this.position.isAtStart ) {
 				const parent = this.position.parent;
-				this.position = Position.createBefore( parent );
+				this.position = this.writer.createPositionBefore( parent );
 
 				// Special case – parent is empty (<p>^</p>) so isAtStart == isAtEnd == true.
 				// We can remove the element after moving selection out of it.
@@ -436,9 +435,9 @@ class Insertion {
 					this.writer.remove( parent );
 				}
 			} else if ( this.position.isAtEnd ) {
-				this.position = Position.createAfter( this.position.parent );
+				this.position = this.writer.createPositionAfter( this.position.parent );
 			} else {
-				const tempPos = Position.createAfter( this.position.parent );
+				const tempPos = this.writer.createPositionAfter( this.position.parent );
 
 				this.writer.split( this.position );
 

+ 2 - 2
packages/ckeditor5-engine/src/model/utils/modifyselection.js

@@ -106,7 +106,7 @@ function tryExtendingTo( data, value ) {
 	if ( value.type == ( data.isForward ? 'elementStart' : 'elementEnd' ) ) {
 		// If it's an object, we can select it now.
 		if ( data.schema.isObject( value.item ) ) {
-			return Position.createAt( value.item, data.isForward ? 'after' : 'before' );
+			return Position._createAt( value.item, data.isForward ? 'after' : 'before' );
 		}
 
 		// If text allowed on this position, extend to this place.
@@ -195,7 +195,7 @@ function getCorrectWordBreakPosition( walker, isForward ) {
 
 function getSearchRange( start, isForward ) {
 	const root = start.root;
-	const searchEnd = Position.createAt( root, isForward ? 'end' : 0 );
+	const searchEnd = Position._createAt( root, isForward ? 'end' : 0 );
 
 	if ( isForward ) {
 		return new Range( start, searchEnd );

+ 4 - 4
packages/ckeditor5-engine/src/model/utils/selection-post-fixer.js

@@ -149,7 +149,7 @@ function tryFixingCollapsedRange( range, schema ) {
 
 	// Check single node selection (happens in tables).
 	if ( fixedPosition.nodeAfter && schema.isLimit( fixedPosition.nodeAfter ) ) {
-		return new Range( fixedPosition, Position.createAfter( fixedPosition.nodeAfter ) );
+		return new Range( fixedPosition, Position._createAfter( fixedPosition.nodeAfter ) );
 	}
 
 	return new Range( fixedPosition );
@@ -199,8 +199,8 @@ function tryFixingNonCollapsedRage( range, schema ) {
 	if ( isStartInLimit || isEndInLimit ) {
 		// Although we've already found limit element on start/end positions we must find the outer-most limit element.
 		// as limit elements might be nested directly inside (ie table > tableRow > tableCell).
-		const startPosition = Position.createAt( startLimitElement, 0 );
-		const endPosition = Position.createAt( endLimitElement, 0 );
+		const startPosition = Position._createAt( startLimitElement, 0 );
+		const endPosition = Position._createAt( endLimitElement, 0 );
 
 		const fixedStart = isStartInLimit ? expandSelectionOnIsLimitNode( startPosition, schema, 'start' ) : start;
 		const fixedEnd = isEndInLimit ? expandSelectionOnIsLimitNode( endPosition, schema, 'end' ) : end;
@@ -229,7 +229,7 @@ function expandSelectionOnIsLimitNode( position, schema, expandToDirection ) {
 	}
 
 	// Depending on direction of expanding selection return position before or after found node.
-	return expandToDirection === 'start' ? Position.createBefore( node ) : Position.createAfter( node );
+	return expandToDirection === 'start' ? Position._createBefore( node ) : Position._createAfter( node );
 }
 
 // Checks whether both range ends are placed around non-limit elements.

+ 123 - 28
packages/ckeditor5-engine/src/model/writer.js

@@ -137,7 +137,7 @@ export default class Writer {
 	 *		const paragraph = writer.createElement( 'paragraph' );
 	 *		writer.insert( paragraph, anotherParagraph, 'after' );
 	 *
-	 * These parameters works the same way as {@link module:engine/model/position~Position.createAt `Position.createAt()`}.
+	 * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.
 	 *
 	 * Note that if the item already has parent it will be removed from the previous parent.
 	 *
@@ -159,14 +159,14 @@ export default class Writer {
 	insert( item, itemOrPosition, offset = 0 ) {
 		this._assertWriterUsedCorrectly();
 
-		const position = Position.createAt( itemOrPosition, offset );
+		const position = Position._createAt( itemOrPosition, offset );
 
 		// If item has a parent already.
 		if ( item.parent ) {
 			// We need to check if item is going to be inserted within the same document.
 			if ( isSameTree( item.root, position.root ) ) {
 				// If it's we just need to move it.
-				this.move( Range.createOn( item ), position );
+				this.move( Range._createOn( item ), position );
 
 				return;
 			}
@@ -198,7 +198,7 @@ export default class Writer {
 		if ( item instanceof DocumentFragment ) {
 			for ( const [ markerName, markerRange ] of item.markers ) {
 				// We need to migrate marker range from DocumentFragment to Document.
-				const rangeRootPosition = Position.createAt( markerRange.root, 0 );
+				const rangeRootPosition = Position._createAt( markerRange.root, 0 );
 				const range = new Range(
 					markerRange.start._getCombined( rangeRootPosition, position ),
 					markerRange.end._getCombined( rangeRootPosition, position )
@@ -225,7 +225,7 @@ export default class Writer {
 	 *		// Inserts 'foo' after an image:
 	 *		writer.insertText( 'foo', image, 'after' );
 	 *
-	 * These parameters work in the same way as {@link module:engine/model/position~Position.createAt `Position.createAt()`}.
+	 * These parameters work in the same way as {@link #createPositionAt `writer.createPositionAt()`}.
 	 *
 	 * @param {String} data Text data.
 	 * @param {Object} [attributes] Text attributes.
@@ -257,7 +257,7 @@ export default class Writer {
 	 *		// Inserts after an image:
 	 *		writer.insertElement( 'paragraph', image, 'after' );
 	 *
-	 * These parameters works the same way as {@link module:engine/model/position~Position.createAt `Position.createAt()`}.
+	 * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.
 	 *
 	 * @param {String} name Name of the element.
 	 * @param {Object} [attributes] Elements attributes.
@@ -431,7 +431,7 @@ export default class Writer {
 	 *		// Moves all items in the range to a position after an image:
 	 *		writer.move( sourceRange, image, 'after' );
 	 *
-	 * These parameters works the same way as {@link module:engine/model/position~Position.createAt `Position.createAt()`}.
+	 * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.
 	 *
 	 * Note that items can be moved only within the same tree. It means that you can move items within the same root
 	 * (element or document fragment) or between {@link module:engine/model/document~Document#roots documents roots},
@@ -464,7 +464,7 @@ export default class Writer {
 			throw new CKEditorError( 'writer-move-range-not-flat: Range to move is not flat.' );
 		}
 
-		const position = Position.createAt( itemOrPosition, offset );
+		const position = Position._createAt( itemOrPosition, offset );
 
 		if ( !isSameTree( range.root, position.root ) ) {
 			/**
@@ -501,7 +501,7 @@ export default class Writer {
 		} else {
 			const howMany = itemOrRange.is( 'text' ) ? itemOrRange.offsetSize : 1;
 
-			applyRemoveOperation( Position.createBefore( itemOrRange ), howMany, this.batch, this.model );
+			applyRemoveOperation( Position._createBefore( itemOrRange ), howMany, this.batch, this.model );
 		}
 	}
 
@@ -544,6 +544,97 @@ export default class Writer {
 		}
 	}
 
+	/**
+	 * Shortcut for {@link module:engine/model/model~Model#createPositionFromPath `Model#createPositionFromPath()`}.
+	 *
+	 * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} root Root of the position.
+	 * @param {Array.<Number>} path Position path. See {@link module:engine/model/position~Position#path}.
+	 * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.
+	 * See {@link module:engine/model/position~PositionStickiness}.
+	 * @returns {module:engine/model/position~Position}
+	 */
+	createPositionFromPath( root, path, stickiness ) {
+		return this.model.createPositionFromPath( root, path, stickiness );
+	}
+
+	/**
+	 * Shortcut for {@link module:engine/model/model~Model#createPositionAt `Model#createPositionAt()`}.
+	 *
+	 * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
+	 * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
+	 * first parameter is a {@link module:engine/model/item~Item model item}.
+	 * @returns {module:engine/model/position~Position}
+	 */
+	createPositionAt( itemOrPosition, offset ) {
+		return this.model.createPositionAt( itemOrPosition, offset );
+	}
+
+	/**
+	 * Shortcut for {@link module:engine/model/model~Model#createPositionAfter `Model#createPositionAfter()`}.
+	 *
+	 * @param {module:engine/model/item~Item} item Item after which the position should be placed.
+	 * @returns {module:engine/model/position~Position}
+	 */
+	createPositionAfter( item ) {
+		return this.model.createPositionAfter( item );
+	}
+
+	/**
+	 * Shortcut for {@link module:engine/model/model~Model#createPositionBefore `Model#createPositionBefore()`}.
+	 *
+	 * @param {module:engine/model/item~Item} item Item after which the position should be placed.
+	 * @returns {module:engine/model/position~Position}
+	 */
+	createPositionBefore( item ) {
+		return this.model.createPositionBefore( item );
+	}
+
+	/**
+	 * Shortcut for {@link module:engine/model/model~Model#createRange `Model#createRange()`}.
+	 *
+	 * @param {module:engine/model/position~Position} start Start position.
+	 * @param {module:engine/model/position~Position} [end] End position. If not set, range will be collapsed at `start` position.
+	 * @returns {module:engine/model/range~Range}
+	 */
+	createRange( start, end ) {
+		return this.model.createRange( start, end );
+	}
+
+	/**
+	 * Shortcut for {@link module:engine/model/model~Model#createRangeIn `Model#createRangeIn()`}.
+	 *
+	 * @param {module:engine/model/element~Element} element Element which is a parent for the range.
+	 * @returns {module:engine/model/range~Range}
+	 */
+	createRangeIn( element ) {
+		return this.model.createRangeIn( element );
+	}
+
+	/**
+	 * Shortcut for {@link module:engine/model/model~Model#createRangeOn `Model#createRangeOn()`}.
+	 *
+	 * @param {module:engine/model/element~Element} element Element which is a parent for the range.
+	 * @returns {module:engine/model/range~Range}
+	 */
+	createRangeOn( element ) {
+		return this.model.createRangeOn( element );
+	}
+
+	/**
+	 * Shortcut for {@link module:engine/model/model~Model#createSelection `Model#createSelection()`}.
+	 *
+	 * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection|
+	 * module:engine/model/position~Position|module:engine/model/element~Element|
+	 * Iterable.<module:engine/model/range~Range>|module:engine/model/range~Range|null} selectable
+	 * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.
+	 * @param {Object} [options]
+	 * @param {Boolean} [options.backward] Sets this selection instance to be backward.
+	 * @returns {module:engine/model/selection~Selection}
+	 */
+	createSelection( selectable, placeOrOffset, options ) {
+		return this.model.createSelection( selectable, placeOrOffset, options );
+	}
+
 	/**
 	 * Performs merge action in a detached tree.
 	 *
@@ -554,7 +645,7 @@ export default class Writer {
 		const nodeBefore = position.nodeBefore;
 		const nodeAfter = position.nodeAfter;
 
-		this.move( Range.createIn( nodeAfter ), Position.createAt( nodeBefore, 'end' ) );
+		this.move( Range._createIn( nodeAfter ), Position._createAt( nodeBefore, 'end' ) );
 		this.remove( nodeAfter );
 	}
 
@@ -565,8 +656,8 @@ export default class Writer {
 	 * @param {module:engine/model/position~Position} position Position between merged elements.
 	 */
 	_merge( position ) {
-		const targetPosition = Position.createAt( position.nodeBefore, 'end' );
-		const sourcePosition = Position.createAt( position.nodeAfter, 0 );
+		const targetPosition = Position._createAt( position.nodeBefore, 'end' );
+		const sourcePosition = Position._createAt( position.nodeAfter, 0 );
 
 		const graveyard = position.root.document.graveyard;
 		const graveyardPosition = new Position( graveyard, [ 0 ] );
@@ -600,7 +691,7 @@ export default class Writer {
 		}
 
 		const version = element.root.document ? element.root.document.version : null;
-		const renameOperation = new RenameOperation( Position.createBefore( element ), element.name, newName, version );
+		const renameOperation = new RenameOperation( Position._createBefore( element ), element.name, newName, version );
 
 		this.batch.addOperation( renameOperation );
 		this.model.applyOperation( renameOperation );
@@ -662,13 +753,13 @@ export default class Writer {
 				firstCopyElement = position.parent.nextSibling;
 			}
 
-			position = Position.createAfter( position.parent );
+			position = this.createPositionAfter( position.parent );
 			splitElement = position.parent;
 		} while ( splitElement !== limitElement );
 
 		return {
 			position,
-			range: new Range( Position.createAt( firstSplitElement, 'end' ), Position.createAt( firstCopyElement, 0 ) )
+			range: new Range( Position._createAt( firstSplitElement, 'end' ), Position._createAt( firstCopyElement, 0 ) )
 		};
 	}
 
@@ -723,7 +814,7 @@ export default class Writer {
 		const move = new MoveOperation(
 			range.start.getShiftedBy( 1 ),
 			range.end.offset - range.start.offset,
-			Position.createAt( element, 0 ),
+			Position._createAt( element, 0 ),
 			version === null ? null : version + 1
 		);
 
@@ -749,7 +840,7 @@ export default class Writer {
 			throw new CKEditorError( 'writer-unwrap-element-no-parent: Trying to unwrap an element which has no parent.' );
 		}
 
-		this.move( Range.createIn( element ), Position.createAfter( element ) );
+		this.move( Range._createIn( element ), this.createPositionAfter( element ) );
 		this.remove( element );
 	}
 
@@ -976,29 +1067,33 @@ export default class Writer {
 	}
 
 	/**
-	 * Sets this selection's ranges and direction to the specified location based on the given
-	 * {@link module:engine/model/selection~Selection selection}, {@link module:engine/model/position~Position position},
-	 * {@link module:engine/model/node~Node node}, {@link module:engine/model/position~Position position},
-	 * {@link module:engine/model/range~Range range}, an iterable of {@link module:engine/model/range~Range ranges} or null.
+	 * Sets the document's selection (ranges and direction) to the specified location based on:
+	 *
+	 * * the given {@link module:engine/model/selection~Selection selection},
+	 * * or the given {@link module:engine/model/position~Position position},
+	 * * or the given {@link module:engine/model/range~Range range},
+	 * * or the given iterable of {@link module:engine/model/range~Range ranges},
+	 * * or the given {@link module:engine/model/node~Node node},
+	 * * or `null`.
 	 *
 	 *		// Sets selection to the given range.
-	 *		const range = new Range( start, end );
+	 *		const range = writer.createRange( start, end );
 	 *		writer.setSelection( range );
 	 *
 	 *		// Sets selection to given ranges.
-	 *		const ranges = [ new Range( start1, end2 ), new Range( star2, end2 ) ];
+	 *		const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
 	 *		writer.setSelection( range );
 	 *
 	 *		// Sets selection to other selection.
-	 *		const otherSelection = new Selection();
+	 *		const otherSelection = writer.createSelection();
 	 *		writer.setSelection( otherSelection );
 	 *
 	 *		// Sets selection to the given document selection.
-	 *		const documentSelection = new DocumentSelection( doc );
+	 *		const documentSelection = model.document.selection;
 	 *		writer.setSelection( documentSelection );
 	 *
 	 *		// Sets collapsed selection at the given position.
-	 *		const position = new Position( root, path );
+	 *		const position = writer.createPosition( root, path );
 	 *		writer.setSelection( position );
 	 *
 	 *		// Sets collapsed selection at the position of the given node and an offset.
@@ -1040,7 +1135,7 @@ export default class Writer {
 	 * Moves {@link module:engine/model/documentselection~DocumentSelection#focus} to the specified location.
 	 *
 	 * The location can be specified in the same form as
-	 * {@link module:engine/model/position~Position.createAt `Position.createAt()`} parameters.
+	 * {@link #createPositionAt `writer.createPositionAt()`} parameters.
 	 *
 	 * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
 	 * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
@@ -1286,7 +1381,7 @@ function setAttributeOnItem( writer, key, value, item ) {
 
 			operation = new RootAttributeOperation( item, key, previousValue, value, version );
 		} else {
-			range = new Range( Position.createBefore( item ), Position.createAfter( item ) );
+			range = new Range( Position._createBefore( item ), writer.createPositionAfter( item ) );
 
 			const version = range.root.document ? doc.version : null;
 

+ 17 - 22
packages/ckeditor5-engine/src/view/documentselection.js

@@ -12,20 +12,14 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
 import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
 
 /**
- * Class representing document selection in tree view. It's instance is stored at
- * {@link module:engine/view/document~Document#selection}. It is similar to {@link module:engine/view/selection~Selection} but
- * it has read-only API and can be modified only by writer obtained from {@link module:engine/view/view~View#change} method.
+ * Class representing the document selection in the view.
  *
- * Selection can consist of {@link module:engine/view/range~Range ranges}.
- * Selection's ranges can be obtained via {@link module:engine/view/documentselection~DocumentSelection#getRanges getRanges},
- * {@link module:engine/view/documentselection~DocumentSelection#getFirstRange getFirstRange}
- * and {@link module:engine/view/documentselection~DocumentSelection#getLastRange getLastRange}
- * methods, which return copies of ranges stored inside selection. Modifications made on these copies will not change
- * selection's state. Similar situation occurs when getting {@link module:engine/view/documentselection~DocumentSelection#anchor anchor},
- * {@link module:engine/view/documentselection~DocumentSelection#focus focus},
- * {@link module:engine/view/documentselection~DocumentSelection#getFirstPosition first} and
- * {@link module:engine/view/documentselection~DocumentSelection#getLastPosition last} positions - all will return
- * copies of requested positions.
+ * Its instance is available in {@link module:engine/view/document~Document#selection `Document#selection`}.
+ *
+ * It is similar to {@link module:engine/view/selection~Selection} but
+ * it has a read-only API and can be modified only by the writer available in
+ * the {@link module:engine/view/view~View#change `View#change()`} block
+ * (so via {@link module:engine/view/downcastwriter~DowncastWriter#setSelection `DowncastWriter#setSelection()`}).
  */
 export default class DocumentSelection {
 	/**
@@ -35,19 +29,19 @@ export default class DocumentSelection {
 	 *		const selection = new DocumentSelection();
 	 *
 	 *		// Creates selection at the given range.
-	 *		const range = new Range( start, end );
+	 *		const range = writer.createRange( start, end );
 	 *		const selection = new DocumentSelection( range );
 	 *
 	 *		// Creates selection at the given ranges
-	 * 		const ranges = [ new Range( start1, end2 ), new Range( star2, end2 ) ];
+	 * 		const ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];
 	 *		const selection = new DocumentSelection( ranges );
 	 *
 	 *		// Creates selection from the other selection.
-	 *		const otherSelection = new Selection();
+	 *		const otherSelection = writer.createSelection();
 	 *		const selection = new DocumentSelection( otherSelection );
 	 *
 	 * 		// Creates selection at the given position.
-	 *		const position = new Position( root, path );
+	 *		const position = writer.createPositionAt( root, offset );
 	 *		const selection = new DocumentSelection( position );
 	 *
 	 *		// Creates collapsed selection at the position of given item and offset.
@@ -290,19 +284,19 @@ export default class DocumentSelection {
 	 * an iterable of {@link module:engine/view/range~Range ranges} or null.
 	 *
 	 *		// Sets selection to the given range.
-	 *		const range = new Range( start, end );
+	 *		const range = writer.createRange( start, end );
 	 *		documentSelection._setTo( range );
 	 *
 	 *		// Sets selection to given ranges.
-	 * 		const ranges = [ new Range( start1, end2 ), new Range( star2, end2 ) ];
+	 * 		const ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];
 	 *		documentSelection._setTo( range );
 	 *
 	 *		// Sets selection to the other selection.
-	 *		const otherSelection = new Selection();
+	 *		const otherSelection = writer.createSelection();
 	 *		documentSelection._setTo( otherSelection );
 	 *
 	 * 		// Sets collapsed selection at the given position.
-	 *		const position = new Position( root, path );
+	 *		const position = writer.createPositionAt( root, offset );
 	 *		documentSelection._setTo( position );
 	 *
 	 * 		// Sets collapsed selection at the position of given item and offset.
@@ -352,7 +346,8 @@ export default class DocumentSelection {
 	/**
 	 * Moves {@link #focus} to the specified location.
 	 *
-	 * The location can be specified in the same form as {@link module:engine/view/position~Position.createAt} parameters.
+	 * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}
+	 * parameters.
 	 *
 	 * @protected
 	 * @fires change

+ 2 - 2
packages/ckeditor5-engine/src/view/domconverter.js

@@ -534,7 +534,7 @@ export default class DomConverter {
 		const viewElement = this.mapDomToView( domParent );
 
 		if ( viewElement && viewElement.is( 'uiElement' ) ) {
-			return ViewPosition.createBefore( viewElement );
+			return ViewPosition._createBefore( viewElement );
 		}
 
 		if ( isText( domParent ) ) {
@@ -1066,7 +1066,7 @@ export default class DomConverter {
 	 */
 	_getTouchingViewTextNode( node, getNext ) {
 		const treeWalker = new ViewTreeWalker( {
-			startPosition: getNext ? ViewPosition.createAfter( node ) : ViewPosition.createBefore( node ),
+			startPosition: getNext ? ViewPosition._createAfter( node ) : ViewPosition._createBefore( node ),
 			direction: getNext ? 'forward' : 'backward'
 		} );
 

+ 181 - 34
packages/ckeditor5-engine/src/view/downcastwriter.js

@@ -8,11 +8,12 @@
  */
 
 import Position from './position';
+import Range from './range';
+import Selection from './selection';
 import ContainerElement from './containerelement';
 import AttributeElement from './attributeelement';
 import EmptyElement from './emptyelement';
 import UIElement from './uielement';
-import Range from './range';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import DocumentFragment from './documentfragment';
 import isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';
@@ -21,11 +22,15 @@ import EditableElement from './editableelement';
 import { isPlainObject } from 'lodash-es';
 
 /**
- * View downcast writer class. Provides set of methods used to properly manipulate nodes attached to
- * {@link module:engine/view/document~Document view document}. It is not recommended to use it directly. To get an instance
- * of view writer associated with the document use {@link module:engine/view/view~View#change view.change()) method.
- * The `DowncastWriter` is designed to work with semantic view which is the view downcasted from model. For working with
- * ordinary view (e.g. parsed from string) {@link module:engine/view/upcastwriter~UpcastWriter upcast writer} should be used.
+ * View downcast writer.
+ *
+ * It provides a set of methods used to manipulate view nodes.
+ *
+ * The `DowncastWriter` is designed to work with semantic views which are the views that were/are being downcasted from the model.
+ * To work with ordinary views (e.g. parsed from a string) use the {@link module:engine/view/upcastwriter~UpcastWriter upcast writer}.
+ *
+ * Do not create an instance of this writer manually. To modify a view structure, use
+ * the {@link module:engine/view/view~View#change View#change()) block.
  */
 export default class DowncastWriter {
 	constructor( document ) {
@@ -52,26 +57,26 @@ export default class DowncastWriter {
 	 * {@link module:engine/view/item~Item item}, {@link module:engine/view/range~Range range},
 	 * an iterable of {@link module:engine/view/range~Range ranges} or null.
 	 *
-	 * ### Usage:
+	 * Usage:
 	 *
 	 *		// Sets selection to the given range.
-	 *		const range = new Range( start, end );
+	 *		const range = writer.createRange( start, end );
 	 *		writer.setSelection( range );
 	 *
 	 *		// Sets backward selection to the given range.
-	 *		const range = new Range( start, end );
+	 *		const range = writer.createRange( start, end );
 	 *		writer.setSelection( range );
 	 *
 	 *		// Sets selection to given ranges.
-	 * 		const ranges = [ new Range( start1, end2 ), new Range( star2, end2 ) ];
+	 * 		const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
 	 *		writer.setSelection( range );
 	 *
 	 *		// Sets selection to the other selection.
-	 *		const otherSelection = new Selection();
+	 *		const otherSelection = writer.createSelection();
 	 *		writer.setSelection( otherSelection );
 	 *
 	 * 		// Sets collapsed selection at the given position.
-	 *		const position = new Position( root, path );
+	 *		const position = writer.createPositionFromPath( root, path );
 	 *		writer.setSelection( position );
 	 *
 	 * 		// Sets collapsed selection at the position of given item and offset.
@@ -120,7 +125,8 @@ export default class DowncastWriter {
 	/**
 	 * Moves {@link module:engine/view/documentselection~DocumentSelection#focus selection's focus} to the specified location.
 	 *
-	 * The location can be specified in the same form as {@link module:engine/view/position~Position.createAt} parameters.
+	 * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}
+	 * parameters.
 	 *
 	 * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition
 	 * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
@@ -452,19 +458,19 @@ export default class DowncastWriter {
 		}
 
 		if ( position.isAtStart ) {
-			return Position.createBefore( element );
+			return Position._createBefore( element );
 		} else if ( !position.isAtEnd ) {
 			const newElement = element._clone( false );
 
-			this.insert( Position.createAfter( element ), newElement );
+			this.insert( Position._createAfter( element ), newElement );
 
-			const sourceRange = new Range( position, Position.createAt( element, 'end' ) );
+			const sourceRange = new Range( position, Position._createAt( element, 'end' ) );
 			const targetPosition = new Position( newElement, 0 );
 
 			this.move( sourceRange, targetPosition );
 		}
 
-		return Position.createAfter( element );
+		return Position._createAfter( element );
 	}
 
 	/**
@@ -575,10 +581,10 @@ export default class DowncastWriter {
 		}
 
 		const lastChild = prev.getChild( prev.childCount - 1 );
-		const newPosition = lastChild instanceof Text ? Position.createAt( lastChild, 'end' ) : Position.createAt( prev, 'end' );
+		const newPosition = lastChild instanceof Text ? Position._createAt( lastChild, 'end' ) : Position._createAt( prev, 'end' );
 
-		this.move( Range.createIn( next ), Position.createAt( prev, 'end' ) );
-		this.remove( Range.createOn( next ) );
+		this.move( Range._createIn( next ), Position._createAt( prev, 'end' ) );
+		this.remove( Range._createOn( next ) );
 
 		return newPosition;
 	}
@@ -657,7 +663,7 @@ export default class DowncastWriter {
 	 * @returns {module:engine/view/documentfragment~DocumentFragment} Document fragment containing removed nodes.
 	 */
 	remove( rangeOrItem ) {
-		const range = rangeOrItem instanceof Range ? rangeOrItem : Range.createOn( rangeOrItem );
+		const range = rangeOrItem instanceof Range ? rangeOrItem : Range._createOn( rangeOrItem );
 
 		validateRangeContainer( range );
 
@@ -682,7 +688,7 @@ export default class DowncastWriter {
 		// Merge after removing.
 		const mergePosition = this.mergeAttributes( breakStart );
 		range.start = mergePosition;
-		range.end = Position.createFromPosition( mergePosition );
+		range.end = mergePosition.clone();
 
 		// Return removed nodes.
 		return new DocumentFragment( removed );
@@ -716,7 +722,7 @@ export default class DowncastWriter {
 			// When current item matches to the given element.
 			if ( item.is( 'element' ) && element.isSimilar( item ) ) {
 				// Create range on this element.
-				rangeToRemove = Range.createOn( item );
+				rangeToRemove = Range._createOn( item );
 				// When range starts inside Text or TextProxy element.
 			} else if ( !current.nextPosition.isAfter( range.start ) && item.is( 'textProxy' ) ) {
 				// We need to check if parent of this text matches to given element.
@@ -726,7 +732,7 @@ export default class DowncastWriter {
 
 				// If it is then create range inside this element.
 				if ( parentElement ) {
-					rangeToRemove = Range.createIn( parentElement );
+					rangeToRemove = Range._createIn( parentElement );
 				}
 			}
 
@@ -914,9 +920,9 @@ export default class DowncastWriter {
 	rename( newName, viewElement ) {
 		const newElement = new ContainerElement( newName, viewElement.getAttributes() );
 
-		this.insert( Position.createAfter( viewElement ), newElement );
-		this.move( Range.createIn( viewElement ), Position.createAt( newElement, 0 ) );
-		this.remove( Range.createOn( viewElement ) );
+		this.insert( Position._createAfter( viewElement ), newElement );
+		this.move( Range._createIn( viewElement ), Position._createAt( newElement, 0 ) );
+		this.remove( Range._createOn( viewElement ) );
 
 		return newElement;
 	}
@@ -939,6 +945,147 @@ export default class DowncastWriter {
 		this._cloneGroups.delete( groupName );
 	}
 
+	/**
+	 * Creates position at the given location. The location can be specified as:
+	 *
+	 * * a {@link module:engine/view/position~Position position},
+	 * * parent element and offset (offset defaults to `0`),
+	 * * parent element and `'end'` (sets position at the end of that element),
+	 * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).
+	 *
+	 * This method is a shortcut to other constructors such as:
+	 *
+	 * * {@link #createPositionBefore},
+	 * * {@link #createPositionAfter},
+	 *
+	 * @param {module:engine/view/item~Item|module:engine/model/position~Position} itemOrPosition
+	 * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
+	 * first parameter is a {@link module:engine/view/item~Item view item}.
+	 */
+	createPositionAt( itemOrPosition, offset ) {
+		return Position._createAt( itemOrPosition, offset );
+	}
+
+	/**
+	 * Creates a new position after given view item.
+	 *
+	 * @param {module:engine/view/item~Item} item View item after which the position should be located.
+	 * @returns {module:engine/view/position~Position}
+	 */
+	createPositionAfter( item ) {
+		return Position._createAfter( item );
+	}
+
+	/**
+	 * Creates a new position before given view item.
+	 *
+	 * @param {module:engine/view/item~Item} item View item before which the position should be located.
+	 * @returns {module:engine/view/position~Position}
+	 */
+	createPositionBefore( item ) {
+		return Position._createBefore( item );
+	}
+
+	/**
+	 * Creates a range spanning from `start` position to `end` position.
+	 *
+	 * **Note:** This factory method creates it's own {@link module:engine/view/position~Position} instances basing on passed values.
+	 *
+	 * @param {module:engine/view/position~Position} start Start position.
+	 * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position.
+	 * @returns {module:engine/view/range~Range}
+	 */
+	createRange( start, end ) {
+		return new Range( start, end );
+	}
+
+	/**
+	 * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.
+	 *
+	 * @param {module:engine/view/item~Item} item
+	 * @returns {module:engine/view/range~Range}
+	 */
+	createRangeOn( item ) {
+		return Range._createOn( item );
+	}
+
+	/**
+	 * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of
+	 * that element and ends after the last child of that element.
+	 *
+	 * @param {module:engine/view/element~Element} element Element which is a parent for the range.
+	 * @returns {module:engine/view/range~Range}
+	 */
+	createRangeIn( element ) {
+		return Range._createIn( element );
+	}
+
+	/**
+	 Creates new {@link module:engine/view/selection~Selection} instance.
+	 *
+	 * 		// Creates empty selection without ranges.
+	 *		const selection = writer.createSelection();
+	 *
+	 *		// Creates selection at the given range.
+	 *		const range = writer.createRange( start, end );
+	 *		const selection = writer.createSelection( range );
+	 *
+	 *		// Creates selection at the given ranges
+	 * 		const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
+	 *		const selection = writer.createSelection( ranges );
+	 *
+	 *		// Creates selection from the other selection.
+	 *		const otherSelection = writer.createSelection();
+	 *		const selection = writer.createSelection( otherSelection );
+	 *
+	 *		// Creates selection from the document selection.
+	 *		const selection = writer.createSelection( editor.editing.view.document.selection );
+	 *
+	 * 		// Creates selection at the given position.
+	 *		const position = writer.createPositionFromPath( root, path );
+	 *		const selection = writer.createSelection( position );
+	 *
+	 *		// Creates collapsed selection at the position of given item and offset.
+	 *		const paragraph = writer.createContainerElement( 'paragraph' );
+	 *		const selection = writer.createSelection( paragraph, offset );
+	 *
+	 *		// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the
+	 *		// first child of that element and ends after the last child of that element.
+	 *		const selection = writer.createSelection( paragraph, 'in' );
+	 *
+	 *		// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends
+	 *		// just after the item.
+	 *		const selection = writer.createSelection( paragraph, 'on' );
+	 *
+	 * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.
+	 *
+	 *		// Creates backward selection.
+	 *		const selection = writer.createSelection( range, { backward: true } );
+	 *
+	 * Fake selection does not render as browser native selection over selected elements and is hidden to the user.
+	 * This way, no native selection UI artifacts are displayed to the user and selection over elements can be
+	 * represented in other way, for example by applying proper CSS class.
+	 *
+	 * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM
+	 * (and be  properly handled by screen readers).
+	 *
+	 *		// Creates fake selection with label.
+	 *		const selection = writer.createSelection( range, { fake: true, label: 'foo' } );
+	 *
+	 * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection|
+	 * module:engine/view/position~Position|Iterable.<module:engine/view/range~Range>|module:engine/view/range~Range|
+	 * module:engine/view/item~Item|null} [selectable=null]
+	 * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.
+	 * @param {Object} [options]
+	 * @param {Boolean} [options.backward] Sets this selection instance to be backward.
+	 * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.
+	 * @param {String} [options.label] Label for the fake selection.
+	 * @returns {module:engine/view/selection~Selection}
+	 */
+	createSelection( selectable, placeOrOffset, options ) {
+		return new Selection( selectable, placeOrOffset, options );
+	}
+
 	/**
 	 * Wraps children with provided `attribute`. Only children contained in `parent` element between
 	 * `startOffset` and `endOffset` will be wrapped.
@@ -1002,7 +1149,7 @@ export default class DowncastWriter {
 			}
 		}
 
-		return Range.createFromParentsAndOffsets( parent, startOffset, parent, endOffset );
+		return Range._createFromParentsAndOffsets( parent, startOffset, parent, endOffset );
 	}
 
 	/**
@@ -1074,7 +1221,7 @@ export default class DowncastWriter {
 			}
 		}
 
-		return Range.createFromParentsAndOffsets( parent, startOffset, parent, endOffset );
+		return Range._createFromParentsAndOffsets( parent, startOffset, parent, endOffset );
 	}
 
 	/**
@@ -1094,8 +1241,8 @@ export default class DowncastWriter {
 		if ( rangeSpansOnAllChildren( range ) && this._wrapAttributeElement( attribute, range.start.parent ) ) {
 			const parent = range.start.parent;
 
-			const end = this.mergeAttributes( Position.createAfter( parent ) );
-			const start = this.mergeAttributes( Position.createBefore( parent ) );
+			const end = this.mergeAttributes( Position._createAfter( parent ) );
+			const start = this.mergeAttributes( Position._createBefore( parent ) );
 
 			return new Range( start, end );
 		}
@@ -1155,7 +1302,7 @@ export default class DowncastWriter {
 	_wrapPosition( position, attribute ) {
 		// Return same position when trying to wrap with attribute similar to position parent.
 		if ( attribute.isSimilar( position.parent ) ) {
-			return movePositionToTextNode( Position.createFromPosition( position ) );
+			return movePositionToTextNode( position.clone() );
 		}
 
 		// When position is inside text node - break it and place new position between two text nodes.
@@ -1399,12 +1546,12 @@ export default class DowncastWriter {
 
 		// There are no attributes to break and text nodes breaking is not forced.
 		if ( !forceSplitText && positionParent.is( 'text' ) && isContainerOrFragment( positionParent.parent ) ) {
-			return Position.createFromPosition( position );
+			return position.clone();
 		}
 
 		// Position's parent is container, so no attributes to break.
 		if ( isContainerOrFragment( positionParent ) ) {
-			return Position.createFromPosition( position );
+			return position.clone();
 		}
 
 		// Break text and start again in new position.

+ 11 - 0
packages/ckeditor5-engine/src/view/editableelement.js

@@ -63,6 +63,17 @@ export default class EditableElement extends ContainerElement {
 		 */
 	}
 
+	/**
+	 * @inheritDoc
+	 */
+	is( type, name = null ) {
+		if ( !name ) {
+			return type == 'editableElement' || super.is( type );
+		} else {
+			return ( type == 'editableElement' && name == this.name ) || super.is( type, name );
+		}
+	}
+
 	/**
 	 * Returns document associated with the editable.
 	 *

+ 35 - 24
packages/ckeditor5-engine/src/view/position.js

@@ -131,7 +131,7 @@ export default class Position {
 	 * @returns {module:engine/view/position~Position} Shifted position.
 	 */
 	getShiftedBy( shift ) {
-		const shifted = Position.createFromPosition( this );
+		const shifted = Position._createAt( this );
 
 		const offset = shifted.offset + shift;
 		shifted.offset = offset < 0 ? 0 : offset;
@@ -274,6 +274,25 @@ export default class Position {
 		}
 	}
 
+	/**
+	 * Creates a {@link module:engine/view/treewalker~TreeWalker TreeWalker} instance with this positions as a start position.
+	 *
+	 * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}
+	 * @param {module:engine/view/range~Range} [options.boundaries=null] Range to define boundaries of the iterator.
+	 * @param {Boolean} [options.singleCharacters=false]
+	 * @param {Boolean} [options.shallow=false]
+	 * @param {Boolean} [options.ignoreElementEnd=false]
+	 */
+	getWalker( options = {} ) {
+		options.startPosition = this;
+
+		return new TreeWalker( options );
+	}
+
+	clone() {
+		return new Position( this.parent, this.offset );
+	}
+
 	/**
 	 * Creates position at the given location. The location can be specified as:
 	 *
@@ -284,36 +303,36 @@ export default class Position {
 	 *
 	 * This method is a shortcut to other constructors such as:
 	 *
-	 * * {@link module:engine/view/position~Position.createBefore},
-	 * * {@link module:engine/view/position~Position.createAfter},
-	 * * {@link module:engine/view/position~Position.createFromPosition}.
+	 * * {@link module:engine/view/position~Position._createBefore},
+	 * * {@link module:engine/view/position~Position._createAfter}.
 	 *
+	 * @protected
 	 * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition
 	 * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
 	 * first parameter is a {@link module:engine/view/item~Item view item}.
 	 */
-	static createAt( itemOrPosition, offset ) {
+	static _createAt( itemOrPosition, offset ) {
 		if ( itemOrPosition instanceof Position ) {
-			return this.createFromPosition( itemOrPosition );
+			return new this( itemOrPosition.parent, itemOrPosition.offset );
 		} else {
 			const node = itemOrPosition;
 
 			if ( offset == 'end' ) {
 				offset = node.is( 'text' ) ? node.data.length : node.childCount;
 			} else if ( offset == 'before' ) {
-				return this.createBefore( node );
+				return this._createBefore( node );
 			} else if ( offset == 'after' ) {
-				return this.createAfter( node );
+				return this._createAfter( node );
 			} else if ( offset !== 0 && !offset ) {
 				/**
-				 * {@link module:engine/view/position~Position.createAt `Position.createAt()`}
+				 * {@link module:engine/view/view~View#createPositionAt `View#createPositionAt()`}
 				 * requires the offset to be specified when the first parameter is a view item.
 				 *
-				 * @error view-position-createAt-offset-required
+				 * @error view-createPositionAt-offset-required
 				 */
 				throw new CKEditorError(
-					'view-position-createAt-offset-required: ' +
-					'Position.createAt() requires the offset when the first parameter is a view item.' );
+					'view-createPositionAt-offset-required: ' +
+					'View#createPositionAt() requires the offset when the first parameter is a view item.' );
 			}
 
 			return new Position( node, offset );
@@ -323,10 +342,11 @@ export default class Position {
 	/**
 	 * Creates a new position after given view item.
 	 *
+	 * @protected
 	 * @param {module:engine/view/item~Item} item View item after which the position should be located.
 	 * @returns {module:engine/view/position~Position}
 	 */
-	static createAfter( item ) {
+	static _createAfter( item ) {
 		// TextProxy is not a instance of Node so we need do handle it in specific way.
 		if ( item.is( 'textProxy' ) ) {
 			return new Position( item.textNode, item.offsetInText + item.data.length );
@@ -348,10 +368,11 @@ export default class Position {
 	/**
 	 * Creates a new position before given view item.
 	 *
+	 * @protected
 	 * @param {module:engine/view/item~Item} item View item before which the position should be located.
 	 * @returns {module:engine/view/position~Position}
 	 */
-	static createBefore( item ) {
+	static _createBefore( item ) {
 		// TextProxy is not a instance of Node so we need do handle it in specific way.
 		if ( item.is( 'textProxy' ) ) {
 			return new Position( item.textNode, item.offsetInText );
@@ -369,16 +390,6 @@ export default class Position {
 
 		return new Position( item.parent, item.index );
 	}
-
-	/**
-	 * Creates and returns a new instance of `Position`, which is equal to the passed position.
-	 *
-	 * @param {module:engine/view/position~Position} position Position to be cloned.
-	 * @returns {module:engine/view/position~Position}
-	 */
-	static createFromPosition( position ) {
-		return new this( position.parent, position.offset );
-	}
 }
 
 /**

+ 29 - 43
packages/ckeditor5-engine/src/view/range.js

@@ -29,7 +29,7 @@ export default class Range {
 		 * @readonly
 		 * @member {module:engine/view/position~Position}
 		 */
-		this.start = Position.createFromPosition( start );
+		this.start = start.clone();
 
 		/**
 		 * End position.
@@ -37,7 +37,7 @@ export default class Range {
 		 * @readonly
 		 * @member {module:engine/view/position~Position}
 		 */
-		this.end = end ? Position.createFromPosition( end ) : Position.createFromPosition( start );
+		this.end = end ? end.clone() : start.clone();
 	}
 
 	/**
@@ -107,11 +107,11 @@ export default class Range {
 
 		// Fix positions, in case if they are in Text node.
 		if ( start.parent.is( 'text' ) && start.isAtStart ) {
-			start = Position.createBefore( start.parent );
+			start = Position._createBefore( start.parent );
 		}
 
 		if ( end.parent.is( 'text' ) && end.isAtEnd ) {
-			end = Position.createAfter( end.parent );
+			end = Position._createAfter( end.parent );
 		}
 
 		return new Range( start, end );
@@ -210,16 +210,19 @@ export default class Range {
 	 *		let bar = new Text( 'bar' );
 	 *		let p = new ContainerElement( 'p', null, [ foo, img, bar ] );
 	 *
-	 *		let range = new Range( new Position( foo, 2 ), new Position( bar, 1 ); // "o", img, "b" are in range.
-	 *		let otherRange = new Range( new Position( foo, 1 ), new Position( bar, 2 ); "oo", img, "ba" are in range.
+	 *		let range = view.createRange( view.createPositionAt( foo, 2 ), view.createPositionAt( bar, 1 ); // "o", img, "b" are in range.
+	 *		let otherRange = view.createRange( // "oo", img, "ba" are in range.
+	 *			view.createPositionAt( foo, 1 ),
+	 *			view.createPositionAt( bar, 2 )
+	 *		);
 	 *		let transformed = range.getDifference( otherRange );
 	 *		// transformed array has no ranges because `otherRange` contains `range`
 	 *
-	 *		otherRange = new Range( new Position( foo, 1 ), new Position( p, 2 ); // "oo", img are in range.
+	 *		otherRange = view.createRange( view.createPositionAt( foo, 1 ), view.createPositionAt( p, 2 ); // "oo", img are in range.
 	 *		transformed = range.getDifference( otherRange );
 	 *		// transformed array has one range: from ( p, 2 ) to ( bar, 1 )
 	 *
-	 *		otherRange = new Range( new Position( p, 1 ), new Position( p, 2 ) ); // img is in range.
+	 *		otherRange = view.createRange( view.createPositionAt( p, 1 ), view.createPositionAt( p, 2 ) ); // img is in range.
 	 *		transformed = range.getDifference( otherRange );
 	 *		// transformed array has two ranges: from ( foo, 1 ) to ( p, 1 ) and from ( p, 2 ) to ( bar, 1 )
 	 *
@@ -245,7 +248,7 @@ export default class Range {
 			}
 		} else {
 			// Ranges do not intersect, return the original range.
-			ranges.push( Range.createFromRange( this ) );
+			ranges.push( this.clone() );
 		}
 
 		return ranges;
@@ -262,11 +265,11 @@ export default class Range {
 	 *		let bar = new Text( 'bar' );
 	 *		let p = new ContainerElement( 'p', null, [ foo, img, bar ] );
 	 *
-	 *		let range = new Range( new Position( foo, 2 ), new Position( bar, 1 ); // "o", img, "b" are in range.
-	 *		let otherRange = new Range( new Position( foo, 1 ), new Position( p, 2 ); // "oo", img are in range.
+	 *		let range = view.createRange( view.createPositionAt( foo, 2 ), view.createPositionAt( bar, 1 ); // "o", img, "b" are in range.
+	 *		let otherRange = view.createRange( view.createPositionAt( foo, 1 ), view.createPositionAt( p, 2 ); // "oo", img are in range.
 	 *		let transformed = range.getIntersection( otherRange ); // range from ( foo, 1 ) to ( p, 2 ).
 	 *
-	 *		otherRange = new Range( new Position( bar, 1 ), new Position( bar, 3 ); "ar" is in range.
+	 *		otherRange = view.createRange( view.createPositionAt( bar, 1 ), view.createPositionAt( bar, 3 ); "ar" is in range.
 	 *		transformed = range.getIntersection( otherRange ); // null - no common part.
 	 *
 	 * @param {module:engine/view/range~Range} otherRange Range to check for intersection.
@@ -323,6 +326,10 @@ export default class Range {
 		return this.start.getCommonAncestor( this.end );
 	}
 
+	clone() {
+		return new Range( this.start, this.end );
+	}
+
 	/**
 	 * Returns an iterator that iterates over all {@link module:engine/view/item~Item view items} that are in this range and returns
 	 * them.
@@ -386,6 +393,7 @@ export default class Range {
 	/**
 	 * Creates a range from given parents and offsets.
 	 *
+	 * @protected
 	 * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} startElement Start position
 	 * parent element.
 	 * @param {Number} startOffset Start position offset.
@@ -394,32 +402,23 @@ export default class Range {
 	 * @param {Number} endOffset End position offset.
 	 * @returns {module:engine/view/range~Range} Created range.
 	 */
-	static createFromParentsAndOffsets( startElement, startOffset, endElement, endOffset ) {
+	static _createFromParentsAndOffsets( startElement, startOffset, endElement, endOffset ) {
 		return new this(
 			new Position( startElement, startOffset ),
 			new Position( endElement, endOffset )
 		);
 	}
 
-	/**
-	 * Creates and returns a new instance of Range which is equal to passed range.
-	 *
-	 * @param {module:engine/view/range~Range} range Range to clone.
-	 * @returns {module:engine/view/range~Range}
-	 */
-	static createFromRange( range ) {
-		return new this( range.start, range.end );
-	}
-
 	/**
 	 * Creates a new range, spreading from specified {@link module:engine/view/position~Position position} to a position moved by
 	 * given `shift`. If `shift` is a negative value, shifted position is treated as the beginning of the range.
 	 *
+	 * @protected
 	 * @param {module:engine/view/position~Position} position Beginning of the range.
 	 * @param {Number} shift How long the range should be.
 	 * @returns {module:engine/view/range~Range}
 	 */
-	static createFromPositionAndShift( position, shift ) {
+	static _createFromPositionAndShift( position, shift ) {
 		const start = position;
 		const end = position.getShiftedBy( shift );
 
@@ -430,38 +429,25 @@ export default class Range {
 	 * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of
 	 * that element and ends after the last child of that element.
 	 *
+	 * @protected
 	 * @param {module:engine/view/element~Element} element Element which is a parent for the range.
 	 * @returns {module:engine/view/range~Range}
 	 */
-	static createIn( element ) {
-		return this.createFromParentsAndOffsets( element, 0, element, element.childCount );
+	static _createIn( element ) {
+		return this._createFromParentsAndOffsets( element, 0, element, element.childCount );
 	}
 
 	/**
 	 * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.
 	 *
+	 * @protected
 	 * @param {module:engine/view/item~Item} item
 	 * @returns {module:engine/view/range~Range}
 	 */
-	static createOn( item ) {
+	static _createOn( item ) {
 		const size = item.is( 'textProxy' ) ? item.offsetSize : 1;
 
-		return this.createFromPositionAndShift( Position.createBefore( item ), size );
-	}
-
-	/**
-	 * Creates a collapsed range at given {@link module:engine/view/position~Position position}
-	 * or on the given {@link module:engine/view/item~Item item}.
-	 *
-	 * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition
-	 * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
-	 * first parameter is a {@link module:engine/view/item~Item view item}.
-	 */
-	static createCollapsedAt( itemOrPosition, offset ) {
-		const start = Position.createAt( itemOrPosition, offset );
-		const end = Position.createFromPosition( start );
-
-		return new Range( start, end );
+		return this._createFromPositionAndShift( Position._createBefore( item ), size );
 	}
 }
 

+ 1 - 1
packages/ckeditor5-engine/src/view/renderer.js

@@ -333,7 +333,7 @@ export default class Renderer {
 		const firstPos = this.selection.getFirstPosition();
 
 		if ( firstPos.parent.is( 'text' ) ) {
-			return ViewPosition.createBefore( this.selection.getFirstPosition().parent );
+			return ViewPosition._createBefore( this.selection.getFirstPosition().parent );
 		} else {
 			return firstPos;
 		}

+ 47 - 45
packages/ckeditor5-engine/src/view/selection.js

@@ -19,63 +19,64 @@ import isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';
 import DocumentSelection from './documentselection';
 
 /**
- * Class representing selection in tree view.
+ * Class representing an arbirtary selection in the view.
+ * See also {@link module:engine/view/documentselection~DocumentSelection}.
  *
- * Selection can consist of {@link module:engine/view/range~Range ranges} that can be set using
- * {@link module:engine/view/selection~Selection#setTo setTo} method.
- * That method create copies of provided ranges and store those copies internally. Further modifications to passed
- * ranges will not change selection's state.
- * Selection's ranges can be obtained via {@link module:engine/view/selection~Selection#getRanges getRanges},
- * {@link module:engine/view/selection~Selection#getFirstRange getFirstRange} and
- * {@link module:engine/view/selection~Selection#getLastRange getLastRange} methods, which return copies of ranges
- * stored inside selection. Modifications made on these copies will not change selection's state. Similar situation
- * occurs when getting {@link module:engine/view/selection~Selection#anchor anchor},
- * {@link module:engine/view/selection~Selection#focus focus}, {@link module:engine/view/selection~Selection#getFirstPosition first}
- * and {@link module:engine/view/selection~Selection#getLastPosition last} positions - all will return
- * copies of requested positions.
+ * New selection instances can be created via the constructor or one these methods:
+ *
+ * * {@link module:engine/view/view~View#createSelection `View#createSelection()`},
+ * * {@link module:engine/view/upcastwriter~UpcastWriter#createSelection `UpcastWriter#createSelection()`}.
+ *
+ * A selection can consist of {@link module:engine/view/range~Range ranges} that can be set by using
+ * the {@link module:engine/view/selection~Selection#setTo `Selection#setTo()`} method.
  */
 export default class Selection {
 	/**
 	 * Creates new selection instance.
 	 *
+	 * **Note**: The selection constructor is available as a factory method:
+	 *
+	 * * {@link module:engine/view/view~View#createSelection `View#createSelection()`},
+	 * * {@link module:engine/view/upcastwriter~UpcastWriter#createSelection `UpcastWriter#createSelection()`}.
+	 *
 	 * 		// Creates empty selection without ranges.
-	 *		const selection = new Selection();
+	 *		const selection = writer.createSelection();
 	 *
 	 *		// Creates selection at the given range.
-	 *		const range = new Range( start, end );
-	 *		const selection = new Selection( range );
+	 *		const range = writer.createRange( start, end );
+	 *		const selection = writer.createSelection( range );
 	 *
 	 *		// Creates selection at the given ranges
-	 * 		const ranges = [ new Range( start1, end2 ), new Range( star2, end2 ) ];
-	 *		const selection = new Selection( ranges );
+	 * 		const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
+	 *		const selection = writer.createSelection( ranges );
 	 *
 	 *		// Creates selection from the other selection.
-	 *		const otherSelection = new Selection();
-	 *		const selection = new Selection( otherSelection );
+	 *		const otherSelection = writer.createSelection();
+	 *		const selection = writer.createSelection( otherSelection );
 	 *
 	 *		// Creates selection from the document selection.
-	 *		const selection = new Selection( editor.editing.view.document.selection );
+	 *		const selection = writer.createSelection( editor.editing.view.document.selection );
 	 *
 	 * 		// Creates selection at the given position.
-	 *		const position = new Position( root, path );
-	 *		const selection = new Selection( position );
+	 *		const position = writer.createPositionFromPath( root, path );
+	 *		const selection = writer.createSelection( position );
 	 *
 	 *		// Creates collapsed selection at the position of given item and offset.
 	 *		const paragraph = writer.createContainerElement( 'paragraph' );
-	 *		const selection = new Selection( paragraph, offset );
+	 *		const selection = writer.createSelection( paragraph, offset );
 	 *
 	 *		// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the
 	 *		// first child of that element and ends after the last child of that element.
-	 *		const selection = new Selection( paragraph, 'in' );
+	 *		const selection = writer.createSelection( paragraph, 'in' );
 	 *
 	 *		// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends
 	 *		// just after the item.
-	 *		const selection = new Selection( paragraph, 'on' );
+	 *		const selection = writer.createSelection( paragraph, 'on' );
 	 *
 	 * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.
 	 *
 	 *		// Creates backward selection.
-	 *		const selection = new Selection( range, { backward: true } );
+	 *		const selection = writer.createSelection( range, { backward: true } );
 	 *
 	 * Fake selection does not render as browser native selection over selected elements and is hidden to the user.
 	 * This way, no native selection UI artifacts are displayed to the user and selection over elements can be
@@ -85,7 +86,7 @@ export default class Selection {
 	 * (and be  properly handled by screen readers).
 	 *
 	 *		// Creates fake selection with label.
-	 *		const selection = new Selection( range, { fake: true, label: 'foo' } );
+	 *		const selection = writer.createSelection( range, { fake: true, label: 'foo' } );
 	 *
 	 * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection|
 	 * module:engine/view/position~Position|Iterable.<module:engine/view/range~Range>|module:engine/view/range~Range|
@@ -168,7 +169,7 @@ export default class Selection {
 		const range = this._ranges[ this._ranges.length - 1 ];
 		const anchor = this._lastRangeBackward ? range.end : range.start;
 
-		return Position.createFromPosition( anchor );
+		return anchor.clone();
 	}
 
 	/**
@@ -184,7 +185,7 @@ export default class Selection {
 		const range = this._ranges[ this._ranges.length - 1 ];
 		const focus = this._lastRangeBackward ? range.start : range.end;
 
-		return Position.createFromPosition( focus );
+		return focus.clone();
 	}
 
 	/**
@@ -236,7 +237,7 @@ export default class Selection {
 	 */
 	* getRanges() {
 		for ( const range of this._ranges ) {
-			yield Range.createFromRange( range );
+			yield range.clone();
 		}
 	}
 
@@ -257,7 +258,7 @@ export default class Selection {
 			}
 		}
 
-		return first ? Range.createFromRange( first ) : null;
+		return first ? first.clone() : null;
 	}
 
 	/**
@@ -276,7 +277,7 @@ export default class Selection {
 			}
 		}
 
-		return last ? Range.createFromRange( last ) : null;
+		return last ? last.clone() : null;
 	}
 
 	/**
@@ -289,7 +290,7 @@ export default class Selection {
 	getFirstPosition() {
 		const firstRange = this.getFirstRange();
 
-		return firstRange ? Position.createFromPosition( firstRange.start ) : null;
+		return firstRange ? firstRange.start.clone() : null;
 	}
 
 	/**
@@ -302,7 +303,7 @@ export default class Selection {
 	getLastPosition() {
 		const lastRange = this.getLastRange();
 
-		return lastRange ? Position.createFromPosition( lastRange.end ) : null;
+		return lastRange ? lastRange.end.clone() : null;
 	}
 
 	/**
@@ -429,22 +430,22 @@ export default class Selection {
 	 * an iterable of {@link module:engine/view/range~Range ranges} or null.
 	 *
 	 *		// Sets selection to the given range.
-	 *		const range = new Range( start, end );
+	 *		const range = writer.createRange( start, end );
 	 *		selection.setTo( range );
 	 *
 	 *		// Sets selection to given ranges.
-	 * 		const ranges = [ new Range( start1, end2 ), new Range( star2, end2 ) ];
+	 * 		const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
 	 *		selection.setTo( range );
 	 *
 	 *		// Sets selection to the other selection.
-	 *		const otherSelection = new Selection();
+	 *		const otherSelection = writer.createSelection();
 	 *		selection.setTo( otherSelection );
 	 *
 	 *	 	// Sets selection to contents of DocumentSelection.
 	 *		selection.setTo( editor.editing.view.document.selection );
 	 *
 	 * 		// Sets collapsed selection at the given position.
-	 *		const position = new Position( root, path );
+	 *		const position = writer.createPositionAt( root, path );
 	 *		selection.setTo( position );
 	 *
 	 * 		// Sets collapsed selection at the position of given item and offset.
@@ -515,11 +516,11 @@ export default class Selection {
 					'selection.setTo requires the second parameter when the first parameter is a node.'
 				);
 			} else if ( placeOrOffset == 'in' ) {
-				range = Range.createIn( selectable );
+				range = Range._createIn( selectable );
 			} else if ( placeOrOffset == 'on' ) {
-				range = Range.createOn( selectable );
+				range = Range._createOn( selectable );
 			} else {
-				range = Range.createCollapsedAt( selectable, placeOrOffset );
+				range = new Range( Position._createAt( selectable, placeOrOffset ) );
 			}
 
 			this._setRanges( [ range ], backward );
@@ -544,7 +545,8 @@ export default class Selection {
 	/**
 	 * Moves {@link #focus} to the specified location.
 	 *
-	 * The location can be specified in the same form as {@link module:engine/view/position~Position.createAt} parameters.
+	 * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}
+	 * parameters.
 	 *
 	 * @fires change
 	 * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition
@@ -563,7 +565,7 @@ export default class Selection {
 			);
 		}
 
-		const newFocus = Position.createAt( itemOrPosition, offset );
+		const newFocus = Position._createAt( itemOrPosition, offset );
 
 		if ( newFocus.compareWith( this.focus ) == 'same' ) {
 			return;
@@ -684,7 +686,7 @@ export default class Selection {
 			}
 		}
 
-		this._ranges.push( Range.createFromRange( range ) );
+		this._ranges.push( new Range( range.start, range.end ) );
 	}
 
 	/**

+ 21 - 21
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 = Position._createAt( options.startPosition );
 		} else {
-			this.position = Position.createFromPosition( options.boundaries[ options.direction == 'backward' ? 'end' : 'start' ] );
+			this.position = Position._createAt( options.boundaries[ options.direction == 'backward' ? 'end' : 'start' ] );
 		}
 
 		/**
@@ -189,7 +189,7 @@ export default class TreeWalker {
 	 * @returns {module:engine/view/treewalker~TreeWalkerValue} return.value Information about taken step.
 	 */
 	_next() {
-		let position = Position.createFromPosition( this.position );
+		let position = this.position.clone();
 		const previousPosition = this.position;
 		const parent = position.parent;
 
@@ -210,7 +210,7 @@ export default class TreeWalker {
 		if ( parent instanceof Text ) {
 			if ( position.isAtEnd ) {
 				// Prevent returning "elementEnd" for Text node. Skip that value and return the next walker step.
-				this.position = Position.createAfter( parent );
+				this.position = Position._createAfter( parent );
 
 				return this._next();
 			}
@@ -244,7 +244,7 @@ export default class TreeWalker {
 				if ( node == this._boundaryEndParent ) {
 					charactersCount = this.boundaries.end.offset;
 					item = new TextProxy( node, 0, charactersCount );
-					position = Position.createAfter( item );
+					position = Position._createAfter( item );
 				} else {
 					item = new TextProxy( node, 0, node.data.length );
 					// If not just keep moving forward.
@@ -275,7 +275,7 @@ export default class TreeWalker {
 			return this._formatReturnValue( 'text', textProxy, previousPosition, position, textLength );
 		} else {
 			// `node` is not set, we reached the end of current `parent`.
-			position = Position.createAfter( parent );
+			position = Position._createAfter( parent );
 			this.position = position;
 
 			if ( this.ignoreElementEnd ) {
@@ -295,7 +295,7 @@ export default class TreeWalker {
 	 * @returns {module:engine/view/treewalker~TreeWalkerValue} return.value Information about taken step.
 	 */
 	_previous() {
-		let position = Position.createFromPosition( this.position );
+		let position = this.position.clone();
 		const previousPosition = this.position;
 		const parent = position.parent;
 
@@ -316,7 +316,7 @@ export default class TreeWalker {
 		if ( parent instanceof Text ) {
 			if ( position.isAtStart ) {
 				// Prevent returning "elementStart" for Text node. Skip that value and return the next walker step.
-				this.position = Position.createBefore( parent );
+				this.position = Position._createBefore( parent );
 
 				return this._previous();
 			}
@@ -358,7 +358,7 @@ export default class TreeWalker {
 
 					item = new TextProxy( node, offset, node.data.length - offset );
 					charactersCount = item.data.length;
-					position = Position.createBefore( item );
+					position = Position._createBefore( item );
 				} else {
 					item = new TextProxy( node, 0, node.data.length );
 					// If not just keep moving backward.
@@ -390,7 +390,7 @@ export default class TreeWalker {
 			return this._formatReturnValue( 'text', textProxy, previousPosition, position, textLength );
 		} else {
 			// `node` is not set, we reached the beginning of current `parent`.
-			position = Position.createBefore( parent );
+			position = Position._createBefore( parent );
 			this.position = position;
 
 			return this._formatReturnValue( 'elementStart', parent, previousPosition, position, 1 );
@@ -417,22 +417,22 @@ export default class TreeWalker {
 			// Position is at the end of Text.
 			if ( item.offsetInText + item.data.length == item.textNode.data.length ) {
 				if ( this.direction == 'forward' && !( this.boundaries && this.boundaries.end.isEqual( this.position ) ) ) {
-					nextPosition = Position.createAfter( item.textNode );
+					nextPosition = Position._createAfter( item.textNode );
 					// When we change nextPosition of returned value we need also update walker current position.
 					this.position = nextPosition;
 				} else {
-					previousPosition = Position.createAfter( item.textNode );
+					previousPosition = Position._createAfter( item.textNode );
 				}
 			}
 
 			// Position is at the begining ot the text.
 			if ( item.offsetInText === 0 ) {
 				if ( this.direction == 'backward' && !( this.boundaries && this.boundaries.start.isEqual( this.position ) ) ) {
-					nextPosition = Position.createBefore( item.textNode );
+					nextPosition = Position._createBefore( item.textNode );
 					// When we change nextPosition of returned value we need also update walker current position.
 					this.position = nextPosition;
 				} else {
-					previousPosition = Position.createBefore( item.textNode );
+					previousPosition = Position._createBefore( item.textNode );
 				}
 			}
 		}
@@ -464,24 +464,24 @@ export default class TreeWalker {
  *
  * @typedef {Object} module:engine/view/treewalker~TreeWalkerValue
  * @property {module:engine/view/treewalker~TreeWalkerValueType} type
- * @property {module:engine/view/item~Item} item Item between old and new positions of {@link module:engine/view/treewalker~TreeWalker}.
+ * @property {module:engine/view/item~Item} item Item between the old and the new positions
+ * of the tree walker.
  * @property {module:engine/view/position~Position} previousPosition Previous position of the iterator.
  * * Forward iteration: For `'elementEnd'` it is the last position inside the element. For all other types it is the
- * position before the item. Note that it is more efficient to use this position then calculate the position before
- * the node using {@link module:engine/view/position~Position.createBefore}.
+ * position before the item.
  * * Backward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is
  * the position after item.
  * * If the position is at the beginning or at the end of the {@link module:engine/view/text~Text} it is always moved from the
- * inside of the Text to its parent just before or just after Text.
+ * inside of the text to its parent just before or just after that text.
  * @property {module:engine/view/position~Position} nextPosition Next position of the iterator.
  * * Forward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is
  * the position after the item.
  * * Backward iteration: For `'elementEnd'` it is last position inside element. For all other types it is the position
  * before the item.
  * * If the position is at the beginning or at the end of the {@link module:engine/view/text~Text} it is always moved from the
- * inside of the Text to its parent just before or just after Text.
- * @property {Number} [length] Length of the item. For `'elementStart'` it is 1. For `'text'` it is
- * the length of the text. For `'elementEnd'` it is undefined.
+ * inside of the text to its parent just before or just after that text.
+ * @property {Number} [length] Length of the item. For `'elementStart'` it is `1`. For `'text'` it is
+ * the length of that text. For `'elementEnd'` it is `undefined`.
  */
 
 /**

+ 153 - 6
packages/ckeditor5-engine/src/view/upcastwriter.js

@@ -9,16 +9,22 @@
 
 import Element from './element';
 import { isPlainObject } from 'lodash-es';
+import Position from './position';
+import Range from './range';
+import Selection from './selection';
 
 /**
- * View upcast writer class. Provides set of methods used to properly manipulate nodes attached to
- * {@link module:engine/view/view~View view instance}. It should be only used to manipulate non-semantic view
- * (view created from HTML string). For view which was downcasted from the {@link module:engine/model/model~Model model}
- * see {@link module:engine/view/downcastwriter~DowncastWriter writer}.
+ * View upcast writer.
+ *
+ * It provides a set of methods used to manipulate view nodes.
+ * It should be used only while working on a non-semantic view
+ * (e.g. a view created from HTML string on paste).
+ * To manipulate a view which was or is being downcasted from the the model use the
+ * {@link module:engine/view/downcastwriter~DowncastWriter downcast writer}.
  */
 export default class UpcastWriter {
 	/**
-	 * Clones provided element.
+	 * Clones the provided element.
 	 *
 	 * @see module:engine/view/element~Element#_clone
 	 * @param {module:engine/view/element~Element} element Element to be cloned.
@@ -62,7 +68,7 @@ export default class UpcastWriter {
 	}
 
 	/**
-	 * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.
+	 * Removes the given number of child nodes starting at the given index and set the parent of these nodes to `null`.
 	 *
 	 * @see module:engine/view/element~Element#_removeChildren
 	 * @param {Number} index Offset from which nodes will be removed.
@@ -245,4 +251,145 @@ export default class UpcastWriter {
 	removeCustomProperty( key, element ) {
 		return element._removeCustomProperty( key );
 	}
+
+	/**
+	 * Creates position at the given location. The location can be specified as:
+	 *
+	 * * a {@link module:engine/view/position~Position position},
+	 * * parent element and offset (offset defaults to `0`),
+	 * * parent element and `'end'` (sets position at the end of that element),
+	 * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).
+	 *
+	 * This method is a shortcut to other constructors such as:
+	 *
+	 * * {@link #createPositionBefore},
+	 * * {@link #createPositionAfter},
+	 *
+	 * @param {module:engine/view/item~Item|module:engine/model/position~Position} itemOrPosition
+	 * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
+	 * first parameter is a {@link module:engine/view/item~Item view item}.
+	 */
+	createPositionAt( itemOrPosition, offset ) {
+		return Position._createAt( itemOrPosition, offset );
+	}
+
+	/**
+	 * Creates a new position after given view item.
+	 *
+	 * @param {module:engine/view/item~Item} item View item after which the position should be located.
+	 * @returns {module:engine/view/position~Position}
+	 */
+	createPositionAfter( item ) {
+		return Position._createAfter( item );
+	}
+
+	/**
+	 * Creates a new position before given view item.
+	 *
+	 * @param {module:engine/view/item~Item} item View item before which the position should be located.
+	 * @returns {module:engine/view/position~Position}
+	 */
+	createPositionBefore( item ) {
+		return Position._createBefore( item );
+	}
+
+	/**
+	 * Creates a range spanning from `start` position to `end` position.
+	 *
+	 * **Note:** This factory method creates it's own {@link module:engine/view/position~Position} instances basing on passed values.
+	 *
+	 * @param {module:engine/view/position~Position} start Start position.
+	 * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position.
+	 * @returns {module:engine/view/range~Range}
+	 */
+	createRange( start, end ) {
+		return new Range( start, end );
+	}
+
+	/**
+	 * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.
+	 *
+	 * @param {module:engine/view/item~Item} item
+	 * @returns {module:engine/view/range~Range}
+	 */
+	createRangeOn( item ) {
+		return Range._createOn( item );
+	}
+
+	/**
+	 * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of
+	 * that element and ends after the last child of that element.
+	 *
+	 * @param {module:engine/view/element~Element} element Element which is a parent for the range.
+	 * @returns {module:engine/view/range~Range}
+	 */
+	createRangeIn( element ) {
+		return Range._createIn( element );
+	}
+
+	/**
+	 * Creates a new {@link module:engine/view/selection~Selection} instance.
+	 *
+	 * 		// Creates empty selection without ranges.
+	 *		const selection = writer.createSelection();
+	 *
+	 *		// Creates selection at the given range.
+	 *		const range = writer.createRange( start, end );
+	 *		const selection = writer.createSelection( range );
+	 *
+	 *		// Creates selection at the given ranges
+	 * 		const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
+	 *		const selection = writer.createSelection( ranges );
+	 *
+	 *		// Creates selection from the other selection.
+	 *		const otherSelection = writer.createSelection();
+	 *		const selection = writer.createSelection( otherSelection );
+	 *
+	 *		// Creates selection from the document selection.
+	 *		const selection = writer.createSelection( editor.editing.view.document.selection );
+	 *
+	 * 		// Creates selection at the given position.
+	 *		const position = writer.createPositionFromPath( root, path );
+	 *		const selection = writer.createSelection( position );
+	 *
+	 *		// Creates collapsed selection at the position of given item and offset.
+	 *		const paragraph = writer.createContainerElement( 'paragraph' );
+	 *		const selection = writer.createSelection( paragraph, offset );
+	 *
+	 *		// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the
+	 *		// first child of that element and ends after the last child of that element.
+	 *		const selection = writer.createSelection( paragraph, 'in' );
+	 *
+	 *		// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends
+	 *		// just after the item.
+	 *		const selection = writer.createSelection( paragraph, 'on' );
+	 *
+	 * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.
+	 *
+	 *		// Creates backward selection.
+	 *		const selection = writer.createSelection( range, { backward: true } );
+	 *
+	 * Fake selection does not render as browser native selection over selected elements and is hidden to the user.
+	 * This way, no native selection UI artifacts are displayed to the user and selection over elements can be
+	 * represented in other way, for example by applying proper CSS class.
+	 *
+	 * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM
+	 * (and be  properly handled by screen readers).
+	 *
+	 *		// Creates fake selection with label.
+	 *		const selection = writer.createSelection( range, { fake: true, label: 'foo' } );
+	 *
+	 * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection|
+	 * module:engine/view/position~Position|Iterable.<module:engine/view/range~Range>|module:engine/view/range~Range|
+	 * module:engine/view/item~Item|null} [selectable=null]
+	 * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.
+	 * @param {Object} [options]
+	 * @param {Boolean} [options.backward] Sets this selection instance to be backward.
+	 * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.
+	 * @param {String} [options.label] Label for the fake selection.
+	 * @returns {module:engine/view/selection~Selection}
+	 */
+	createSelection( selectable, placeOrOffset, options ) {
+		return new Selection( selectable, placeOrOffset, options );
+	}
 }

+ 144 - 0
packages/ckeditor5-engine/src/view/view.js

@@ -11,6 +11,9 @@ import Document from './document';
 import DowncastWriter from './downcastwriter';
 import Renderer from './renderer';
 import DomConverter from './domconverter';
+import Position from './position';
+import Range from './range';
+import Selection from './selection';
 
 import MutationObserver from './observer/mutationobserver';
 import KeyObserver from './observer/keyobserver';
@@ -394,6 +397,147 @@ export default class View {
 		this.stopListening();
 	}
 
+	/**
+	 * Creates position at the given location. The location can be specified as:
+	 *
+	 * * a {@link module:engine/view/position~Position position},
+	 * * parent element and offset (offset defaults to `0`),
+	 * * parent element and `'end'` (sets position at the end of that element),
+	 * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).
+	 *
+	 * This method is a shortcut to other constructors such as:
+	 *
+	 * * {@link #createPositionBefore},
+	 * * {@link #createPositionAfter},
+	 *
+	 * @param {module:engine/view/item~Item|module:engine/model/position~Position} itemOrPosition
+	 * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
+	 * first parameter is a {@link module:engine/view/item~Item view item}.
+	 */
+	createPositionAt( itemOrPosition, offset ) {
+		return Position._createAt( itemOrPosition, offset );
+	}
+
+	/**
+	 * Creates a new position after given view item.
+	 *
+	 * @param {module:engine/view/item~Item} item View item after which the position should be located.
+	 * @returns {module:engine/view/position~Position}
+	 */
+	createPositionAfter( item ) {
+		return Position._createAfter( item );
+	}
+
+	/**
+	 * Creates a new position before given view item.
+	 *
+	 * @param {module:engine/view/item~Item} item View item before which the position should be located.
+	 * @returns {module:engine/view/position~Position}
+	 */
+	createPositionBefore( item ) {
+		return Position._createBefore( item );
+	}
+
+	/**
+	 * Creates a range spanning from `start` position to `end` position.
+	 *
+	 * **Note:** This factory method creates it's own {@link module:engine/view/position~Position} instances basing on passed values.
+	 *
+	 * @param {module:engine/view/position~Position} start Start position.
+	 * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position.
+	 * @returns {module:engine/view/range~Range}
+	 */
+	createRange( start, end ) {
+		return new Range( start, end );
+	}
+
+	/**
+	 * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.
+	 *
+	 * @param {module:engine/view/item~Item} item
+	 * @returns {module:engine/view/range~Range}
+	 */
+	createRangeOn( item ) {
+		return Range._createOn( item );
+	}
+
+	/**
+	 * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of
+	 * that element and ends after the last child of that element.
+	 *
+	 * @param {module:engine/view/element~Element} element Element which is a parent for the range.
+	 * @returns {module:engine/view/range~Range}
+	 */
+	createRangeIn( element ) {
+		return Range._createIn( element );
+	}
+
+	/**
+	 Creates new {@link module:engine/view/selection~Selection} instance.
+	 *
+	 * 		// Creates empty selection without ranges.
+	 *		const selection = view.createSelection();
+	 *
+	 *		// Creates selection at the given range.
+	 *		const range = view.createRange( start, end );
+	 *		const selection = view.createSelection( range );
+	 *
+	 *		// Creates selection at the given ranges
+	 * 		const ranges = [ view.createRange( start1, end2 ), view.createRange( star2, end2 ) ];
+	 *		const selection = view.createSelection( ranges );
+	 *
+	 *		// Creates selection from the other selection.
+	 *		const otherSelection = view.createSelection();
+	 *		const selection = view.createSelection( otherSelection );
+	 *
+	 *		// Creates selection from the document selection.
+	 *		const selection = view.createSelection( editor.editing.view.document.selection );
+	 *
+	 * 		// Creates selection at the given position.
+	 *		const position = view.createPositionFromPath( root, path );
+	 *		const selection = view.createSelection( position );
+	 *
+	 *		// Creates collapsed selection at the position of given item and offset.
+	 *		const paragraph = view.createContainerElement( 'paragraph' );
+	 *		const selection = view.createSelection( paragraph, offset );
+	 *
+	 *		// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the
+	 *		// first child of that element and ends after the last child of that element.
+	 *		const selection = view.createSelection( paragraph, 'in' );
+	 *
+	 *		// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends
+	 *		// just after the item.
+	 *		const selection = view.createSelection( paragraph, 'on' );
+	 *
+	 * `Selection`'s factory method allow passing additional options (`backward`, `fake` and `label`) as the last argument.
+	 *
+	 *		// Creates backward selection.
+	 *		const selection = view.createSelection( range, { backward: true } );
+	 *
+	 * Fake selection does not render as browser native selection over selected elements and is hidden to the user.
+	 * This way, no native selection UI artifacts are displayed to the user and selection over elements can be
+	 * represented in other way, for example by applying proper CSS class.
+	 *
+	 * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM
+	 * (and be  properly handled by screen readers).
+	 *
+	 *		// Creates fake selection with label.
+	 *		const selection = view.createSelection( range, { fake: true, label: 'foo' } );
+	 *
+	 * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection|
+	 * module:engine/view/position~Position|Iterable.<module:engine/view/range~Range>|module:engine/view/range~Range|
+	 * module:engine/view/item~Item|null} [selectable=null]
+	 * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.
+	 * @param {Object} [options]
+	 * @param {Boolean} [options.backward] Sets this selection instance to be backward.
+	 * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.
+	 * @param {String} [options.label] Label for the fake selection.
+	 * @returns {module:engine/view/selection~Selection}
+	 */
+	createSelection( selectable, placeOrOffset, options ) {
+		return new Selection( selectable, placeOrOffset, options );
+	}
+
 	/**
 	 * Renders all changes. In order to avoid triggering the observers (e.g. mutations) all observers are disabled
 	 * before rendering and re-enabled after that.

+ 5 - 5
packages/ckeditor5-engine/tests/controller/datacontroller.js

@@ -407,7 +407,7 @@ describe( 'DataController', () => {
 
 			model.change( writer => {
 				writer.insert( modelElement, modelRoot, 0 );
-				const range = ModelRange.createFromParentsAndOffsets( modelRoot, 0, modelRoot, 1 );
+				const range = writer.createRange( writer.createPositionAt( modelRoot, 0 ), writer.createPositionAt( modelRoot, 1 ) );
 				writer.addMarker( 'marker:a', { range, usingOperation: true } );
 			} );
 
@@ -430,8 +430,8 @@ describe( 'DataController', () => {
 			model.change( writer => {
 				writer.insert( modelElement, modelRoot, 0 );
 
-				const rangeA = ModelRange.createFromParentsAndOffsets( modelP1, 1, modelP1, 3 );
-				const rangeB = ModelRange.createFromParentsAndOffsets( modelP2, 0, modelP2, 2 );
+				const rangeA = writer.createRange( writer.createPositionAt( modelP1, 1 ), writer.createPositionAt( modelP1, 3 ) );
+				const rangeB = writer.createRange( writer.createPositionAt( modelP2, 0 ), writer.createPositionAt( modelP2, 2 ) );
 
 				writer.addMarker( 'marker:a', { range: rangeA, usingOperation: true } );
 				writer.addMarker( 'marker:b', { range: rangeB, usingOperation: true } );
@@ -463,8 +463,8 @@ describe( 'DataController', () => {
 			const firstModelElement = modelDocumentFragment.getChild( 0 );
 			const firstViewElement = viewDocumentFragment.getChild( 0 );
 
-			const modelRange = ModelRange.createOn( firstModelElement );
-			const viewRange = ViewRange.createOn( firstViewElement );
+			const modelRange = ModelRange._createOn( firstModelElement );
+			const viewRange = ViewRange._createOn( firstViewElement );
 
 			const mappedModelRange = data.mapper.toModelRange( viewRange );
 			const mappedViewRange = data.mapper.toViewRange( modelRange );

+ 29 - 22
packages/ckeditor5-engine/tests/controller/editingcontroller.js

@@ -114,9 +114,10 @@ describe( 'EditingController', () => {
 			model.change( writer => {
 				writer.insert( modelData, model.document.getRoot() );
 
-				writer.setSelection( ModelRange.createFromParentsAndOffsets(
-					modelRoot.getChild( 0 ), 1, modelRoot.getChild( 0 ), 1 )
-				);
+				writer.setSelection( writer.createRange(
+					writer.createPositionAt( modelRoot.getChild( 0 ), 1 ),
+					writer.createPositionAt( modelRoot.getChild( 0 ), 1 )
+				) );
 			} );
 		} );
 
@@ -136,9 +137,10 @@ describe( 'EditingController', () => {
 			model.change( writer => {
 				writer.split( model.document.selection.getFirstPosition() );
 
-				writer.setSelection(
-					ModelRange.createFromParentsAndOffsets(	modelRoot.getChild( 1 ), 0, modelRoot.getChild( 1 ), 0 )
-				);
+				writer.setSelection( writer.createRange(
+					writer.createPositionAt( modelRoot.getChild( 1 ), 0 ),
+					writer.createPositionAt( modelRoot.getChild( 1 ), 0 )
+				) );
 			} );
 
 			expect( getViewData( editing.view ) ).to.equal( '<p>f</p><p>{}oo</p><p></p><p>bar</p>' );
@@ -157,12 +159,13 @@ describe( 'EditingController', () => {
 		it( 'should convert delete', () => {
 			model.change( writer => {
 				writer.remove(
-					ModelRange.createFromPositionAndShift( model.document.selection.getFirstPosition(), 1 )
+					ModelRange._createFromPositionAndShift( model.document.selection.getFirstPosition(), 1 )
 				);
 
-				writer.setSelection(
-					ModelRange.createFromParentsAndOffsets( modelRoot.getChild( 0 ), 1, modelRoot.getChild( 0 ), 1 )
-				);
+				writer.setSelection( writer.createRange(
+					writer.createPositionAt( modelRoot.getChild( 0 ), 1 ),
+					writer.createPositionAt( modelRoot.getChild( 0 ), 1 )
+				) );
 			} );
 
 			expect( getViewData( editing.view ) ).to.equal( '<p>f{}o</p><p></p><p>bar</p>' );
@@ -195,9 +198,10 @@ describe( 'EditingController', () => {
 
 		it( 'should convert collapsed selection', () => {
 			model.change( writer => {
-				writer.setSelection(
-					ModelRange.createFromParentsAndOffsets( modelRoot.getChild( 2 ), 1, modelRoot.getChild( 2 ), 1 )
-				);
+				writer.setSelection( writer.createRange(
+					writer.createPositionAt( modelRoot.getChild( 2 ), 1 ),
+					writer.createPositionAt( modelRoot.getChild( 2 ), 1 )
+				) );
 			} );
 
 			expect( getViewData( editing.view ) ).to.equal( '<p>foo</p><p></p><p>b{}ar</p>' );
@@ -205,9 +209,10 @@ describe( 'EditingController', () => {
 
 		it( 'should convert not collapsed selection', () => {
 			model.change( writer => {
-				writer.setSelection(
-					ModelRange.createFromParentsAndOffsets( modelRoot.getChild( 2 ), 1, modelRoot.getChild( 2 ), 2 )
-				);
+				writer.setSelection( writer.createRange(
+					writer.createPositionAt( modelRoot.getChild( 2 ), 1 ),
+					writer.createPositionAt( modelRoot.getChild( 2 ), 2 )
+				) );
 			} );
 
 			expect( getViewData( editing.view ) ).to.equal( '<p>foo</p><p></p><p>b{a}r</p>' );
@@ -215,17 +220,19 @@ describe( 'EditingController', () => {
 
 		it( 'should clear previous selection', () => {
 			model.change( writer => {
-				writer.setSelection(
-					ModelRange.createFromParentsAndOffsets( modelRoot.getChild( 2 ), 1, modelRoot.getChild( 2 ), 1 )
-				);
+				writer.setSelection( writer.createRange(
+					writer.createPositionAt( modelRoot.getChild( 2 ), 1 ),
+					writer.createPositionAt( modelRoot.getChild( 2 ), 1 )
+				) );
 			} );
 
 			expect( getViewData( editing.view ) ).to.equal( '<p>foo</p><p></p><p>b{}ar</p>' );
 
 			model.change( writer => {
-				writer.setSelection(
-					ModelRange.createFromParentsAndOffsets( modelRoot.getChild( 2 ), 2, modelRoot.getChild( 2 ), 2 )
-				);
+				writer.setSelection( writer.createRange(
+					writer.createPositionAt( modelRoot.getChild( 2 ), 2 ),
+					writer.createPositionAt( modelRoot.getChild( 2 ), 2 )
+				) );
 			} );
 
 			expect( getViewData( editing.view ) ).to.equal( '<p>foo</p><p></p><p>ba{}r</p>' );

+ 4 - 2
packages/ckeditor5-engine/tests/conversion/conversion.js

@@ -13,7 +13,6 @@ import { convertText, convertToModelFragment } from '../../src/conversion/upcast
 import EditingController from '../../src/controller/editingcontroller';
 
 import Model from '../../src/model/model';
-import ModelRange from '../../src/model/range';
 
 import { stringify as viewStringify, parse as viewParse } from '../../src/dev-utils/view';
 import { stringify as modelStringify } from '../../src/dev-utils/model';
@@ -644,7 +643,10 @@ describe( 'Conversion', () => {
 			} );
 
 			model.change( writer => {
-				writer.remove( ModelRange.createFromParentsAndOffsets( modelRoot, 0, modelRoot, modelRoot.maxOffset ) );
+				writer.remove( writer.createRange(
+					writer.createPositionAt( modelRoot, 0 ),
+					writer.createPositionAt( modelRoot, modelRoot.maxOffset ) )
+				);
 				writer.insert( convertedModel, modelRoot, 0 );
 			} );
 		}

+ 40 - 30
packages/ckeditor5-engine/tests/conversion/downcast-converters.js

@@ -10,8 +10,6 @@ import Conversion from '../../src/conversion/conversion';
 import Model from '../../src/model/model';
 import ModelElement from '../../src/model/element';
 import ModelText from '../../src/model/text';
-import ModelRange from '../../src/model/range';
-import ModelPosition from '../../src/model/position';
 
 import ViewElement from '../../src/view/element';
 import ViewAttributeElement from '../../src/view/attributeelement';
@@ -473,7 +471,7 @@ describe( 'downcast-helpers', () => {
 			model.change( writer => {
 				writer.insertText( 'foo', modelRoot, 0 );
 
-				const range = ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 2 );
+				const range = writer.createRange( writer.createPositionAt( modelRoot, 1 ), writer.createPositionAt( modelRoot, 2 ) );
 				writer.addMarker( 'search', { range, usingOperation: false } );
 			} );
 
@@ -488,7 +486,7 @@ describe( 'downcast-helpers', () => {
 
 			model.change( writer => {
 				writer.insertText( 'foo', modelRoot, 0 );
-				const range = ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 2 );
+				const range = writer.createRange( writer.createPositionAt( modelRoot, 1 ), writer.createPositionAt( modelRoot, 2 ) );
 				writer.addMarker( 'search', { range, usingOperation: false } );
 			} );
 
@@ -510,7 +508,7 @@ describe( 'downcast-helpers', () => {
 
 			model.change( writer => {
 				writer.insertText( 'foo', modelRoot, 0 );
-				const range = ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 2 );
+				const range = writer.createRange( writer.createPositionAt( modelRoot, 1 ), writer.createPositionAt( modelRoot, 2 ) );
 				writer.addMarker( 'search', { range, usingOperation: false } );
 			} );
 
@@ -529,7 +527,7 @@ describe( 'downcast-helpers', () => {
 
 			model.change( writer => {
 				writer.insertText( 'foo', modelRoot, 0 );
-				const range = ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 2 );
+				const range = writer.createRange( writer.createPositionAt( modelRoot, 1 ), writer.createPositionAt( modelRoot, 2 ) );
 				writer.addMarker( 'search', { range, usingOperation: false } );
 			} );
 
@@ -545,7 +543,7 @@ describe( 'downcast-helpers', () => {
 
 			model.change( writer => {
 				writer.insertText( 'foo', modelRoot, 0 );
-				const range = ModelRange.createFromParentsAndOffsets( modelRoot, 0, modelRoot, 3 );
+				const range = writer.createRange( writer.createPositionAt( modelRoot, 0 ), writer.createPositionAt( modelRoot, 3 ) );
 				writer.addMarker( 'comment', { range, usingOperation: false } );
 			} );
 
@@ -560,7 +558,7 @@ describe( 'downcast-helpers', () => {
 
 			model.change( writer => {
 				writer.insertText( 'foo', modelRoot, 0 );
-				const range = ModelRange.createFromParentsAndOffsets( modelRoot, 0, modelRoot, 3 );
+				const range = writer.createRange( writer.createPositionAt( modelRoot, 0 ), writer.createPositionAt( modelRoot, 3 ) );
 				writer.addMarker( 'comment', { range, usingOperation: false } );
 			} );
 
@@ -583,7 +581,7 @@ describe( 'downcast-helpers', () => {
 
 			model.change( writer => {
 				writer.insertText( 'foo', modelRoot, 0 );
-				const range = ModelRange.createFromParentsAndOffsets( modelRoot, 0, modelRoot, 3 );
+				const range = writer.createRange( writer.createPositionAt( modelRoot, 0 ), writer.createPositionAt( modelRoot, 3 ) );
 				writer.addMarker( 'comment:abc', { range, usingOperation: false } );
 			} );
 
@@ -622,7 +620,7 @@ describe( 'downcast-converters', () => {
 
 		dispatcher.on( 'attribute:class', changeAttribute() );
 
-		modelRootStart = ModelPosition.createAt( modelRoot, 0 );
+		modelRootStart = model.createPositionAt( modelRoot, 0 );
 	} );
 
 	function viewAttributesToString( item ) {
@@ -815,7 +813,7 @@ describe( 'downcast-converters', () => {
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p><b>foobar</b></p></div>' );
 
 			model.change( writer => {
-				writer.removeAttribute( 'bold', ModelRange.createIn( modelElement ) );
+				writer.removeAttribute( 'bold', writer.createRangeIn( modelElement ) );
 			} );
 
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
@@ -839,7 +837,7 @@ describe( 'downcast-converters', () => {
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p><b>foobar</b></p></div>' );
 
 			model.change( writer => {
-				writer.removeAttribute( 'style', ModelRange.createIn( modelElement ) );
+				writer.removeAttribute( 'style', writer.createRangeIn( modelElement ) );
 			} );
 
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
@@ -866,7 +864,7 @@ describe( 'downcast-converters', () => {
 
 			// Set new attribute on old link but also on non-linked characters.
 			model.change( writer => {
-				writer.setAttribute( 'link', 'http://foobar.com', ModelRange.createIn( modelElement ) );
+				writer.setAttribute( 'link', 'http://foobar.com', writer.createRangeIn( modelElement ) );
 			} );
 
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p><a href="http://foobar.com">xfoox</a></p></div>' );
@@ -885,7 +883,7 @@ describe( 'downcast-converters', () => {
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p>நி<b>லைக்</b>கு</p></div>' );
 
 			model.change( writer => {
-				writer.removeAttribute( 'bold', ModelRange.createIn( modelElement ) );
+				writer.removeAttribute( 'bold', writer.createRangeIn( modelElement ) );
 			} );
 
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p>நிலைக்கு</p></div>' );
@@ -945,7 +943,7 @@ describe( 'downcast-converters', () => {
 
 		describe( 'collapsed range', () => {
 			beforeEach( () => {
-				range = ModelRange.createFromParentsAndOffsets( modelElement, 3, modelElement, 3 );
+				range = model.createRange( model.createPositionAt( modelElement, 3 ), model.createPositionAt( modelElement, 3 ) );
 			} );
 
 			it( 'should insert and remove ui element', () => {
@@ -1006,7 +1004,7 @@ describe( 'downcast-converters', () => {
 
 		describe( 'non-collapsed range', () => {
 			beforeEach( () => {
-				range = ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 5 );
+				range = model.createRange( model.createPositionAt( modelElement, 2 ), model.createPositionAt( modelElement, 5 ) );
 			} );
 
 			it( 'should insert and remove ui element - element as a creator', () => {
@@ -1106,7 +1104,9 @@ describe( 'downcast-converters', () => {
 			} );
 
 			model.change( writer => {
-				writer.remove( ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 4 ) );
+				writer.remove(
+					writer.createRange( writer.createPositionAt( modelElement, 2 ), writer.createPositionAt( modelElement, 4 ) )
+				);
 			} );
 
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foar</p></div>' );
@@ -1122,7 +1122,9 @@ describe( 'downcast-converters', () => {
 			} );
 
 			model.change( writer => {
-				writer.remove( ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 4 ) );
+				writer.remove(
+					writer.createRange( writer.createPositionAt( modelElement, 2 ), writer.createPositionAt( modelElement, 4 ) )
+				);
 			} );
 
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
@@ -1136,7 +1138,9 @@ describe( 'downcast-converters', () => {
 			} );
 
 			model.change( writer => {
-				writer.remove( ModelRange.createFromParentsAndOffsets( modelElement, 0, modelElement, 6 ) );
+				writer.remove(
+					writer.createRange( writer.createPositionAt( modelElement, 0 ), writer.createPositionAt( modelElement, 6 ) )
+				);
 			} );
 
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p>கு</p></div>' );
@@ -1152,14 +1156,18 @@ describe( 'downcast-converters', () => {
 
 			// Remove 'b'.
 			model.change( writer => {
-				writer.remove( ModelRange.createFromParentsAndOffsets( modelRoot, 3, modelRoot, 4 ) );
+				writer.remove(
+					writer.createRange( writer.createPositionAt( modelRoot, 3 ), writer.createPositionAt( modelRoot, 4 ) )
+				);
 			} );
 
 			expect( viewToString( viewRoot ) ).to.equal( '<div>foz<span></span>ar</div>' );
 
 			// Remove 'z'.
 			model.change( writer => {
-				writer.remove( ModelRange.createFromParentsAndOffsets( modelRoot, 2, modelRoot, 3 ) );
+				writer.remove(
+					writer.createRange( writer.createPositionAt( modelRoot, 2 ), writer.createPositionAt( modelRoot, 3 ) )
+				);
 			} );
 
 			expect( viewToString( viewRoot ) ).to.equal( '<div>fo<span></span>ar</div>' );
@@ -1175,7 +1183,9 @@ describe( 'downcast-converters', () => {
 
 			// Remove 'z<span></span>b'.
 			model.change( writer => {
-				writer.remove( ModelRange.createFromParentsAndOffsets( modelRoot, 2, modelRoot, 4 ) );
+				writer.remove(
+					writer.createRange( writer.createPositionAt( modelRoot, 2 ), writer.createPositionAt( modelRoot, 4 ) )
+				);
 			} );
 
 			expect( viewToString( viewRoot ) ).to.equal( '<div>foar</div>' );
@@ -1250,7 +1260,7 @@ describe( 'downcast-converters', () => {
 
 			// Remove second paragraph element.
 			model.change( writer => {
-				writer.remove( ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 2 ) );
+				writer.remove( writer.createRange( writer.createPositionAt( modelRoot, 1 ), writer.createPositionAt( modelRoot, 2 ) ) );
 			} );
 
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p></p><span></span><span></span></div>' );
@@ -1290,7 +1300,7 @@ describe( 'downcast-converters', () => {
 					writer.insert( [ modelElement1, modelElement2 ], modelRootStart );
 				} );
 
-				markerRange = ModelRange.createIn( modelRoot );
+				markerRange = model.createRangeIn( modelRoot );
 			} );
 
 			it( 'should wrap and unwrap text nodes', () => {
@@ -1378,7 +1388,7 @@ describe( 'downcast-converters', () => {
 				dispatcher.on( 'addMarker:marker', highlightElement( descriptor ), { priority: 'high' } );
 				dispatcher.on( 'removeMarker:marker', removeHighlight( descriptor ), { priority: 'high' } );
 
-				markerRange = ModelRange.createFromParentsAndOffsets( modelRoot, 0, modelRoot, 0 );
+				markerRange = model.createRange( model.createPositionAt( modelRoot, 0 ), model.createPositionAt( modelRoot, 0 ) );
 
 				model.change( writer => {
 					writer.addMarker( 'marker', { range: markerRange, usingOperation: false } );
@@ -1410,7 +1420,7 @@ describe( 'downcast-converters', () => {
 				const p2 = modelRoot.getChild( 1 );
 
 				model.change( writer => {
-					const range = ModelRange.createFromParentsAndOffsets( p1, 0, p1, 3 );
+					const range = writer.createRange( writer.createPositionAt( p1, 0 ), writer.createPositionAt( p1, 3 ) );
 					writer.addMarker( 'markerFoo', { range, usingOperation: false } );
 				} );
 
@@ -1424,7 +1434,7 @@ describe( 'downcast-converters', () => {
 				);
 
 				model.change( writer => {
-					const range = ModelRange.createFromParentsAndOffsets( p1, 1, p2, 2 );
+					const range = writer.createRange( writer.createPositionAt( p1, 1 ), writer.createPositionAt( p2, 2 ) );
 					writer.addMarker( 'markerBar', { range, usingOperation: false } );
 				} );
 
@@ -1444,7 +1454,7 @@ describe( 'downcast-converters', () => {
 				);
 
 				model.change( writer => {
-					const range = ModelRange.createFromParentsAndOffsets( p1, 2, p2, 3 );
+					const range = writer.createRange( writer.createPositionAt( p1, 2 ), writer.createPositionAt( p2, 3 ) );
 					writer.addMarker( 'markerXyz', { range, usingOperation: false } );
 				} );
 
@@ -1516,7 +1526,7 @@ describe( 'downcast-converters', () => {
 				const p1 = modelRoot.getChild( 0 );
 				const p2 = modelRoot.getChild( 1 );
 
-				const markerRange = ModelRange.createFromParentsAndOffsets( p1, 3, p2, 0 );
+				const markerRange = model.createRange( model.createPositionAt( p1, 3 ), model.createPositionAt( p2, 0 ) );
 
 				model.change( writer => {
 					writer.addMarker( 'marker', { range: markerRange, usingOperation: false } );
@@ -1564,7 +1574,7 @@ describe( 'downcast-converters', () => {
 					writer.insert( modelElement, modelRootStart );
 				} );
 
-				markerRange = ModelRange.createOn( modelElement );
+				markerRange = model.createRangeOn( modelElement );
 
 				dispatcher.on( 'addMarker:marker', highlightText( highlightDescriptor ) );
 				dispatcher.on( 'addMarker:marker', highlightElement( highlightDescriptor ) );

+ 25 - 28
packages/ckeditor5-engine/tests/conversion/downcast-selection-converters.js

@@ -4,9 +4,6 @@
  */
 
 import Model from '../../src/model/model';
-import ModelElement from '../../src/model/element';
-import ModelRange from '../../src/model/range';
-import ModelPosition from '../../src/model/position';
 
 import View from '../../src/view/view';
 import ViewUIElement from '../../src/view/uielement';
@@ -197,9 +194,9 @@ describe( 'downcast-selection-converters', () => {
 				setModelData( model, 'fo<$text bold="true">ob</$text>ar' );
 
 				model.change( writer => {
-					const range = ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 5 );
+					const range = writer.createRange( writer.createPositionAt( modelRoot, 1 ), writer.createPositionAt( modelRoot, 5 ) );
 					marker = writer.addMarker( 'marker', { range, usingOperation: false } );
-					writer.setSelection( new ModelRange( ModelPosition.createAt( modelRoot, 3 ) ) );
+					writer.setSelection( modelRoot, 3 );
 				} );
 
 				// Remove view children manually (without firing additional conversion).
@@ -207,7 +204,7 @@ describe( 'downcast-selection-converters', () => {
 
 				// Convert model to view.
 				view.change( writer => {
-					dispatcher.convertInsert( ModelRange.createIn( modelRoot ), writer );
+					dispatcher.convertInsert( model.createRangeIn( modelRoot ), writer );
 					dispatcher.convertMarkerAdd( marker.name, marker.getRange(), writer );
 					dispatcher.convertSelection( docSelection, model.markers, writer );
 				} );
@@ -222,9 +219,9 @@ describe( 'downcast-selection-converters', () => {
 				setModelData( model, 'fo<$text bold="true">ob</$text>ar' );
 
 				model.change( writer => {
-					const range = ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 5 );
+					const range = writer.createRange( writer.createPositionAt( modelRoot, 1 ), writer.createPositionAt( modelRoot, 5 ) );
 					marker = writer.addMarker( 'marker', { range, usingOperation: false } );
-					writer.setSelection( new ModelRange( ModelPosition.createAt( modelRoot, 3 ) ) );
+					writer.setSelection( modelRoot, 3 );
 					writer.removeSelectionAttribute( 'bold' );
 				} );
 
@@ -233,7 +230,7 @@ describe( 'downcast-selection-converters', () => {
 
 				// Convert model to view.
 				view.change( writer => {
-					dispatcher.convertInsert( ModelRange.createIn( modelRoot ), writer );
+					dispatcher.convertInsert( model.createRangeIn( modelRoot ), writer );
 					dispatcher.convertMarkerAdd( marker.name, marker.getRange(), writer );
 					dispatcher.convertSelection( docSelection, model.markers, writer );
 				} );
@@ -251,9 +248,9 @@ describe( 'downcast-selection-converters', () => {
 				setModelData( model, 'foobar' );
 
 				model.change( writer => {
-					const range = ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 5 );
+					const range = writer.createRange( writer.createPositionAt( modelRoot, 1 ), writer.createPositionAt( modelRoot, 5 ) );
 					marker = writer.addMarker( 'marker2', { range, usingOperation: false } );
-					writer.setSelection( new ModelRange( ModelPosition.createAt( modelRoot, 3 ) ) );
+					writer.setSelection( modelRoot, 3 );
 				} );
 
 				// Remove view children manually (without firing additional conversion).
@@ -261,7 +258,7 @@ describe( 'downcast-selection-converters', () => {
 
 				// Convert model to view.
 				view.change( writer => {
-					dispatcher.convertInsert( ModelRange.createIn( modelRoot ), writer );
+					dispatcher.convertInsert( model.createRangeIn( modelRoot ), writer );
 					dispatcher.convertMarkerAdd( marker.name, marker.getRange(), writer );
 					dispatcher.convertSelection( docSelection, model.markers, writer );
 				} );
@@ -277,9 +274,9 @@ describe( 'downcast-selection-converters', () => {
 				setModelData( model, 'foobar' );
 
 				model.change( writer => {
-					const range = ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 5 );
+					const range = writer.createRange( writer.createPositionAt( modelRoot, 1 ), writer.createPositionAt( modelRoot, 5 ) );
 					marker = writer.addMarker( 'marker3', { range, usingOperation: false } );
-					writer.setSelection( new ModelRange( ModelPosition.createAt( modelRoot, 3 ) ) );
+					writer.setSelection( modelRoot, 3 );
 				} );
 
 				// Remove view children manually (without firing additional conversion).
@@ -287,7 +284,7 @@ describe( 'downcast-selection-converters', () => {
 
 				// Convert model to view.
 				view.change( writer => {
-					dispatcher.convertInsert( ModelRange.createIn( modelRoot ), writer );
+					dispatcher.convertInsert( model.createRangeIn( modelRoot ), writer );
 					dispatcher.convertMarkerAdd( marker.name, marker.getRange(), writer );
 					dispatcher.convertSelection( docSelection, model.markers, writer );
 				} );
@@ -308,7 +305,7 @@ describe( 'downcast-selection-converters', () => {
 				] );
 
 				model.change( writer => {
-					writer.setSelection( new ModelRange( new ModelPosition( modelRoot, [ 0 ] ) ) );
+					writer.setSelection( writer.createRange( writer.createPositionFromPath( modelRoot, [ 0 ] ) ) );
 					writer.setSelectionAttribute( 'bold', true );
 				} );
 
@@ -327,13 +324,13 @@ describe( 'downcast-selection-converters', () => {
 				setModelData( model, 'x' );
 
 				model.change( writer => {
-					writer.setSelection( new ModelRange( new ModelPosition( modelRoot, [ 1 ] ) ) );
+					writer.setSelection( writer.createRange( writer.createPositionFromPath( modelRoot, [ 1 ] ) ) );
 					writer.setSelectionAttribute( 'bold', true );
 				} );
 
 				// Convert model to view.
 				view.change( writer => {
-					dispatcher.convertInsert( ModelRange.createIn( modelRoot ), writer );
+					dispatcher.convertInsert( model.createRangeIn( modelRoot ), writer );
 
 					// Add ui element to view.
 					const uiElement = new ViewUIElement( 'span' );
@@ -352,13 +349,13 @@ describe( 'downcast-selection-converters', () => {
 				setModelData( model, '<$text bold="true">x</$text>y' );
 
 				model.change( writer => {
-					writer.setSelection( new ModelRange( new ModelPosition( modelRoot, [ 1 ] ) ) );
+					writer.setSelection( writer.createRange( writer.createPositionFromPath( modelRoot, [ 1 ] ) ) );
 					writer.setSelectionAttribute( 'bold', true );
 				} );
 
 				// Convert model to view.
 				view.change( writer => {
-					dispatcher.convertInsert( ModelRange.createIn( modelRoot ), writer );
+					dispatcher.convertInsert( model.createRangeIn( modelRoot ), writer );
 
 					// Add ui element to view.
 					const uiElement = new ViewUIElement( 'span' );
@@ -439,7 +436,7 @@ describe( 'downcast-selection-converters', () => {
 				);
 
 				view.change( writer => {
-					const modelRange = ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 1 );
+					const modelRange = model.createRange( model.createPositionAt( modelRoot, 1 ), model.createPositionAt( modelRoot, 1 ) );
 					model.change( writer => {
 						writer.setSelection( modelRange );
 					} );
@@ -465,7 +462,7 @@ describe( 'downcast-selection-converters', () => {
 					// Remove <strong></strong> manually.
 					writer.mergeAttributes( viewSelection.getFirstPosition() );
 
-					const modelRange = ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 1 );
+					const modelRange = model.createRange( model.createPositionAt( modelRoot, 1 ), model.createPositionAt( modelRoot, 1 ) );
 					model.change( writer => {
 						writer.setSelection( modelRange );
 					} );
@@ -480,7 +477,7 @@ describe( 'downcast-selection-converters', () => {
 			} );
 
 			it( 'should clear fake selection', () => {
-				const modelRange = ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 1 );
+				const modelRange = model.createRange( model.createPositionAt( modelRoot, 1 ), model.createPositionAt( modelRoot, 1 ) );
 
 				view.change( writer => {
 					writer.setSelection( modelRange, { fake: true } );
@@ -521,7 +518,7 @@ describe( 'downcast-selection-converters', () => {
 				for ( const range of selection.getRanges() ) {
 					const node = range.start.parent;
 
-					if ( node instanceof ModelElement && node.name == 'td' ) {
+					if ( !!node && node.is( 'td' ) ) {
 						conversionApi.consumable.consume( selection, 'selection' );
 
 						const viewNode = conversionApi.mapper.toViewElement( node );
@@ -571,12 +568,12 @@ describe( 'downcast-selection-converters', () => {
 		const startPath = typeof selectionPaths[ 0 ] == 'number' ? [ selectionPaths[ 0 ] ] : selectionPaths[ 0 ];
 		const endPath = typeof selectionPaths[ 1 ] == 'number' ? [ selectionPaths[ 1 ] ] : selectionPaths[ 1 ];
 
-		const startPos = new ModelPosition( modelRoot, startPath );
-		const endPos = new ModelPosition( modelRoot, endPath );
+		const startPos = model.createPositionFromPath( modelRoot, startPath );
+		const endPos = model.createPositionFromPath( modelRoot, endPath );
 
 		const isBackward = selectionPaths[ 2 ] === 'backward';
 		model.change( writer => {
-			writer.setSelection( new ModelRange( startPos, endPos ), { backward: isBackward } );
+			writer.setSelection( writer.createRange( startPos, endPos ), { backward: isBackward } );
 
 			// And add or remove passed attributes.
 			for ( const key in selectionAttributes ) {
@@ -595,7 +592,7 @@ describe( 'downcast-selection-converters', () => {
 
 		// Convert model to view.
 		view.change( writer => {
-			dispatcher.convertInsert( ModelRange.createIn( modelRoot ), writer );
+			dispatcher.convertInsert( model.createRangeIn( modelRoot ), writer );
 			dispatcher.convertSelection( docSelection, model.markers, writer );
 		} );
 

+ 48 - 43
packages/ckeditor5-engine/tests/conversion/downcastdispatcher.js

@@ -8,7 +8,6 @@ import Model from '../../src/model/model';
 import ModelText from '../../src/model/text';
 import ModelElement from '../../src/model/element';
 import ModelRange from '../../src/model/range';
-import ModelPosition from '../../src/model/position';
 
 import View from '../../src/view/view';
 import ViewContainerElement from '../../src/view/containerelement';
@@ -43,8 +42,8 @@ describe( 'DowncastDispatcher', () => {
 		it( 'should call convertInsert for insert change', () => {
 			sinon.stub( dispatcher, 'convertInsert' );
 
-			const position = new ModelPosition( root, [ 0 ] );
-			const range = ModelRange.createFromPositionAndShift( position, 1 );
+			const position = model.createPositionFromPath( root, [ 0 ] );
+			const range = ModelRange._createFromPositionAndShift( position, 1 );
 
 			differStub.getChanges = () => [ { type: 'insert', position, length: 1 } ];
 
@@ -59,7 +58,7 @@ describe( 'DowncastDispatcher', () => {
 		it( 'should call convertRemove for remove change', () => {
 			sinon.stub( dispatcher, 'convertRemove' );
 
-			const position = new ModelPosition( root, [ 0 ] );
+			const position = model.createPositionFromPath( root, [ 0 ] );
 
 			differStub.getChanges = () => [ { type: 'remove', position, length: 2, name: '$text' } ];
 
@@ -73,8 +72,8 @@ describe( 'DowncastDispatcher', () => {
 		it( 'should call convertAttribute for attribute change', () => {
 			sinon.stub( dispatcher, 'convertAttribute' );
 
-			const position = new ModelPosition( root, [ 0 ] );
-			const range = ModelRange.createFromPositionAndShift( position, 1 );
+			const position = model.createPositionFromPath( root, [ 0 ] );
+			const range = ModelRange._createFromPositionAndShift( position, 1 );
 
 			differStub.getChanges = () => [
 				{ type: 'attribute', position, range, attributeKey: 'key', attributeOldValue: null, attributeNewValue: 'foo' }
@@ -92,8 +91,8 @@ describe( 'DowncastDispatcher', () => {
 			sinon.stub( dispatcher, 'convertRemove' );
 			sinon.stub( dispatcher, 'convertAttribute' );
 
-			const position = new ModelPosition( root, [ 0 ] );
-			const range = ModelRange.createFromPositionAndShift( position, 1 );
+			const position = model.createPositionFromPath( root, [ 0 ] );
+			const range = ModelRange._createFromPositionAndShift( position, 1 );
 
 			differStub.getChanges = () => [
 				{ type: 'insert', position, length: 1 },
@@ -114,8 +113,8 @@ describe( 'DowncastDispatcher', () => {
 		it( 'should call convertMarkerAdd when markers are added', () => {
 			sinon.stub( dispatcher, 'convertMarkerAdd' );
 
-			const fooRange = ModelRange.createFromParentsAndOffsets( root, 0, root, 1 );
-			const barRange = ModelRange.createFromParentsAndOffsets( root, 3, root, 6 );
+			const fooRange = model.createRange( model.createPositionAt( root, 0 ), model.createPositionAt( root, 1 ) );
+			const barRange = model.createRange( model.createPositionAt( root, 3 ), model.createPositionAt( root, 6 ) );
 
 			differStub.getMarkersToAdd = () => [
 				{ name: 'foo', range: fooRange },
@@ -133,8 +132,8 @@ describe( 'DowncastDispatcher', () => {
 		it( 'should call convertMarkerRemove when markers are removed', () => {
 			sinon.stub( dispatcher, 'convertMarkerRemove' );
 
-			const fooRange = ModelRange.createFromParentsAndOffsets( root, 0, root, 1 );
-			const barRange = ModelRange.createFromParentsAndOffsets( root, 3, root, 6 );
+			const fooRange = model.createRange( model.createPositionAt( root, 0 ), model.createPositionAt( root, 1 ) );
+			const barRange = model.createRange( model.createPositionAt( root, 3 ), model.createPositionAt( root, 6 ) );
 
 			differStub.getMarkersToRemove = () => [
 				{ name: 'foo', range: fooRange },
@@ -159,7 +158,7 @@ describe( 'DowncastDispatcher', () => {
 				new ModelElement( 'paragraph', { class: 'nice' }, new ModelText( 'xx', { italic: true } ) )
 			] );
 
-			const range = ModelRange.createIn( root );
+			const range = model.createRangeIn( root );
 			const loggedEvents = [];
 
 			// We will check everything connected with insert event:
@@ -219,7 +218,7 @@ describe( 'DowncastDispatcher', () => {
 				conversionApi.consumable.consume( data.item, 'attribute:bold' );
 			} );
 
-			const range = ModelRange.createIn( root );
+			const range = model.createRangeIn( root );
 
 			dispatcher.convertInsert( range );
 
@@ -242,7 +241,7 @@ describe( 'DowncastDispatcher', () => {
 				loggedEvents.push( log );
 			} );
 
-			dispatcher.convertRemove( ModelPosition.createFromParentAndOffset( root, 3 ), 3, '$text' );
+			dispatcher.convertRemove( model.createPositionAt( root, 3 ), 3, '$text' );
 
 			expect( loggedEvents ).to.deep.equal( [ 'remove:3:3' ] );
 		} );
@@ -255,8 +254,8 @@ describe( 'DowncastDispatcher', () => {
 			root._appendChild( new ModelText( 'foobar' ) );
 			model.change( writer => {
 				writer.setSelection( [
-					new ModelRange( new ModelPosition( root, [ 1 ] ), new ModelPosition( root, [ 3 ] ) ),
-					new ModelRange( new ModelPosition( root, [ 4 ] ), new ModelPosition( root, [ 5 ] ) )
+					writer.createRange( writer.createPositionFromPath( root, [ 1 ] ), writer.createPositionFromPath( root, [ 3 ] ) ),
+					writer.createRange( writer.createPositionFromPath( root, [ 4 ] ), writer.createPositionFromPath( root, [ 5 ] ) )
 				] );
 			} );
 		} );
@@ -274,8 +273,10 @@ describe( 'DowncastDispatcher', () => {
 
 		it( 'should prepare correct list of consumable values', () => {
 			model.change( writer => {
-				writer.setAttribute( 'bold', true, ModelRange.createIn( root ) );
-				writer.setAttribute( 'italic', true, ModelRange.createFromParentsAndOffsets( root, 4, root, 5 ) );
+				writer.setAttribute( 'bold', true, writer.createRangeIn( root ) );
+				writer.setAttribute( 'italic', true,
+					writer.createRange( writer.createPositionAt( root, 4 ), writer.createPositionAt( root, 5 ) )
+				);
 			} );
 
 			dispatcher.on( 'selection', ( evt, data, conversionApi ) => {
@@ -289,8 +290,10 @@ describe( 'DowncastDispatcher', () => {
 
 		it( 'should not fire attributes events for non-collapsed selection', () => {
 			model.change( writer => {
-				writer.setAttribute( 'bold', true, ModelRange.createIn( root ) );
-				writer.setAttribute( 'italic', true, ModelRange.createFromParentsAndOffsets( root, 4, root, 5 ) );
+				writer.setAttribute( 'bold', true, writer.createRangeIn( root ) );
+				writer.setAttribute( 'italic', true,
+					writer.createRange( writer.createPositionAt( root, 4 ), writer.createPositionAt( root, 5 ) )
+				);
 			} );
 
 			sinon.spy( dispatcher, 'fire' );
@@ -304,12 +307,12 @@ describe( 'DowncastDispatcher', () => {
 		it( 'should fire attributes events for collapsed selection', () => {
 			model.change( writer => {
 				writer.setSelection(
-					new ModelRange( new ModelPosition( root, [ 2 ] ), new ModelPosition( root, [ 2 ] ) )
+					writer.createRange( writer.createPositionFromPath( root, [ 2 ] ), writer.createPositionFromPath( root, [ 2 ] ) )
 				);
 			} );
 
 			model.change( writer => {
-				writer.setAttribute( 'bold', true, ModelRange.createIn( root ) );
+				writer.setAttribute( 'bold', true, writer.createRangeIn( root ) );
 			} );
 
 			sinon.spy( dispatcher, 'fire' );
@@ -322,13 +325,15 @@ describe( 'DowncastDispatcher', () => {
 		it( 'should not fire attributes events if attribute has been consumed', () => {
 			model.change( writer => {
 				writer.setSelection(
-					new ModelRange( new ModelPosition( root, [ 2 ] ), new ModelPosition( root, [ 2 ] ) )
+					writer.createRange( writer.createPositionFromPath( root, [ 2 ] ), writer.createPositionFromPath( root, [ 2 ] ) )
 				);
 			} );
 
 			model.change( writer => {
-				writer.setAttribute( 'bold', true, ModelRange.createIn( root ) );
-				writer.setAttribute( 'italic', true, ModelRange.createFromParentsAndOffsets( root, 4, root, 5 ) );
+				writer.setAttribute( 'bold', true, writer.createRangeIn( root ) );
+				writer.setAttribute( 'italic', true,
+					writer.createRange( writer.createPositionAt( root, 4 ), writer.createPositionAt( root, 5 ) )
+				);
 			} );
 
 			dispatcher.on( 'selection', ( evt, data, conversionApi ) => {
@@ -345,9 +350,9 @@ describe( 'DowncastDispatcher', () => {
 		it( 'should fire events for markers for collapsed selection', () => {
 			model.change( writer => {
 				writer.setSelection(
-					new ModelRange( new ModelPosition( root, [ 1 ] ), new ModelPosition( root, [ 1 ] ) )
+					writer.createRange( writer.createPositionFromPath( root, [ 1 ] ), writer.createPositionFromPath( root, [ 1 ] ) )
 				);
-				const range = ModelRange.createFromParentsAndOffsets( root, 0, root, 2 );
+				const range = writer.createRange( writer.createPositionAt( root, 0 ), writer.createPositionAt( root, 2 ) );
 				writer.addMarker( 'name', { range, usingOperation: false } );
 			} );
 
@@ -361,7 +366,7 @@ describe( 'DowncastDispatcher', () => {
 
 		it( 'should not fire events for markers for non-collapsed selection', () => {
 			model.change( writer => {
-				const range = ModelRange.createFromParentsAndOffsets( root, 0, root, 2 );
+				const range = writer.createRange( writer.createPositionAt( root, 0 ), writer.createPositionAt( root, 2 ) );
 				writer.addMarker( 'name', { range, usingOperation: false } );
 			} );
 
@@ -402,9 +407,9 @@ describe( 'DowncastDispatcher', () => {
 			};
 
 			model.change( writer => {
-				const range = ModelRange.createFromParentsAndOffsets( root, 0, root, 1 );
+				const range = writer.createRange( writer.createPositionAt( root, 0 ), writer.createPositionAt( root, 1 ) );
 				writer.addMarker( 'name', { range, usingOperation: false } );
-				writer.setSelection( ModelRange.createFromParentsAndOffsets( caption, 1, caption, 1 ) );
+				writer.setSelection( caption, 1 );
 			} );
 			sinon.spy( dispatcher, 'fire' );
 
@@ -418,10 +423,10 @@ describe( 'DowncastDispatcher', () => {
 		it( 'should not fire events if information about marker has been consumed', () => {
 			model.change( writer => {
 				writer.setSelection(
-					new ModelRange( new ModelPosition( root, [ 1 ] ), new ModelPosition( root, [ 1 ] ) )
+					writer.createRange( writer.createPositionFromPath( root, [ 1 ] ), writer.createPositionFromPath( root, [ 1 ] ) )
 				);
 
-				const range = ModelRange.createFromParentsAndOffsets( root, 0, root, 2 );
+				const range = writer.createRange( writer.createPositionAt( root, 0 ), writer.createPositionAt( root, 2 ) );
 				writer.addMarker( 'foo', { range, usingOperation: false } );
 				writer.addMarker( 'bar', { range, usingOperation: false } );
 			} );
@@ -448,7 +453,7 @@ describe( 'DowncastDispatcher', () => {
 			element = new ModelElement( 'paragraph', null, [ text ] );
 			root._appendChild( [ element ] );
 
-			range = ModelRange.createFromParentsAndOffsets( element, 0, element, 4 );
+			range = model.createRange( model.createPositionAt( element, 0 ), model.createPositionAt( element, 4 ) );
 		} );
 
 		it( 'should fire addMarker event', () => {
@@ -460,7 +465,7 @@ describe( 'DowncastDispatcher', () => {
 		} );
 
 		it( 'should not convert marker if it is in graveyard', () => {
-			const gyRange = ModelRange.createFromParentsAndOffsets( doc.graveyard, 0, doc.graveyard, 0 );
+			const gyRange = model.createRange( model.createPositionAt( doc.graveyard, 0 ), model.createPositionAt( doc.graveyard, 0 ) );
 			sinon.spy( dispatcher, 'fire' );
 
 			dispatcher.convertMarkerAdd( 'name', gyRange );
@@ -470,7 +475,7 @@ describe( 'DowncastDispatcher', () => {
 
 		it( 'should not convert marker if it is not in model root', () => {
 			const element = new ModelElement( 'element', null, new ModelText( 'foo' ) );
-			const eleRange = ModelRange.createFromParentsAndOffsets( element, 1, element, 2 );
+			const eleRange = model.createRange( model.createPositionAt( element, 1 ), model.createPositionAt( element, 2 ) );
 			sinon.spy( dispatcher, 'fire' );
 
 			dispatcher.convertMarkerAdd( 'name', eleRange );
@@ -479,7 +484,7 @@ describe( 'DowncastDispatcher', () => {
 		} );
 
 		it( 'should fire conversion for each item in the range', () => {
-			range = ModelRange.createIn( root );
+			range = model.createRangeIn( root );
 
 			const items = [];
 
@@ -498,7 +503,7 @@ describe( 'DowncastDispatcher', () => {
 		} );
 
 		it( 'should be possible to override', () => {
-			range = ModelRange.createIn( root );
+			range = model.createRangeIn( root );
 
 			const addMarkerSpy = sinon.spy();
 			const highAddMarkerSpy = sinon.spy();
@@ -528,7 +533,7 @@ describe( 'DowncastDispatcher', () => {
 			element = new ModelElement( 'paragraph', null, [ text ] );
 			root._appendChild( [ element ] );
 
-			range = ModelRange.createFromParentsAndOffsets( element, 0, element, 4 );
+			range = model.createRange( model.createPositionAt( element, 0 ), model.createPositionAt( element, 4 ) );
 		} );
 
 		it( 'should fire removeMarker event', () => {
@@ -540,7 +545,7 @@ describe( 'DowncastDispatcher', () => {
 		} );
 
 		it( 'should not convert marker if it is in graveyard', () => {
-			const gyRange = ModelRange.createFromParentsAndOffsets( doc.graveyard, 0, doc.graveyard, 0 );
+			const gyRange = model.createRange( model.createPositionAt( doc.graveyard, 0 ), model.createPositionAt( doc.graveyard, 0 ) );
 			sinon.spy( dispatcher, 'fire' );
 
 			dispatcher.convertMarkerRemove( 'name', gyRange );
@@ -550,7 +555,7 @@ describe( 'DowncastDispatcher', () => {
 
 		it( 'should not convert marker if it is not in model root', () => {
 			const element = new ModelElement( 'element', null, new ModelText( 'foo' ) );
-			const eleRange = ModelRange.createFromParentsAndOffsets( element, 1, element, 2 );
+			const eleRange = model.createRange( model.createPositionAt( element, 1 ), model.createPositionAt( element, 2 ) );
 			sinon.spy( dispatcher, 'fire' );
 
 			dispatcher.convertMarkerRemove( 'name', eleRange );
@@ -559,7 +564,7 @@ describe( 'DowncastDispatcher', () => {
 		} );
 
 		it( 'should fire conversion for the range', () => {
-			range = ModelRange.createIn( root );
+			range = model.createRangeIn( root );
 
 			dispatcher.on( 'addMarker:name', ( evt, data ) => {
 				expect( data.markerName ).to.equal( 'name' );
@@ -570,7 +575,7 @@ describe( 'DowncastDispatcher', () => {
 		} );
 
 		it( 'should be possible to override', () => {
-			range = ModelRange.createIn( root );
+			range = model.createRangeIn( root );
 
 			const removeMarkerSpy = sinon.spy();
 			const highRemoveMarkerSpy = sinon.spy();

+ 4 - 4
packages/ckeditor5-engine/tests/conversion/mapper.js

@@ -379,7 +379,7 @@ describe( 'Mapper', () => {
 
 		describe( 'toModelRange', () => {
 			it( 'should transform range', () => {
-				const viewRange = ViewRange.createFromParentsAndOffsets( viewDiv, 0, viewTextFOO, 2 );
+				const viewRange = ViewRange._createFromParentsAndOffsets( viewDiv, 0, viewTextFOO, 2 );
 				const modelRange = mapper.toModelRange( viewRange );
 				expect( modelRange.start.parent ).to.equal( modelDiv );
 				expect( modelRange.start.offset ).to.equal( 0 );
@@ -390,7 +390,7 @@ describe( 'Mapper', () => {
 
 		describe( 'toViewRange', () => {
 			it( 'should transform range', () => {
-				const modelRange = ModelRange.createFromParentsAndOffsets( modelDiv, 0, modelP, 3 );
+				const modelRange = new ModelRange( ModelPosition._createAt( modelDiv, 0 ), ModelPosition._createAt( modelP, 3 ) );
 				const viewRange = mapper.toViewRange( modelRange );
 				expect( viewRange.start.parent ).to.equal( viewTextX );
 				expect( viewRange.start.offset ).to.equal( 0 );
@@ -400,7 +400,7 @@ describe( 'Mapper', () => {
 		} );
 
 		function createToViewTest( modelElement, modelOffset, viewElement, viewOffset ) {
-			const modelPosition = ModelPosition.createFromParentAndOffset( modelElement, modelOffset );
+			const modelPosition = ModelPosition._createAt( modelElement, modelOffset );
 			const viewPosition = mapper.toViewPosition( modelPosition );
 			expect( viewPosition.parent ).to.equal( viewElement );
 			expect( viewPosition.offset ).to.equal( viewOffset );
@@ -530,7 +530,7 @@ describe( 'Mapper', () => {
 		} );
 
 		function createToViewTest( modelElement, modelOffset, viewElement, viewOffset ) {
-			const modelPosition = ModelPosition.createFromParentAndOffset( modelElement, modelOffset );
+			const modelPosition = ModelPosition._createAt( modelElement, modelOffset );
 			const viewPosition = mapper.toViewPosition( modelPosition );
 			expect( viewPosition.parent ).to.equal( viewElement );
 			expect( viewPosition.offset ).to.equal( viewOffset );

+ 4 - 4
packages/ckeditor5-engine/tests/conversion/upcast-converters.js

@@ -761,7 +761,7 @@ describe( 'upcast-converters', () => {
 				if ( conversionApi.consumable.consume( data.viewItem ) ) {
 					const text = conversionApi.writer.createText( data.viewItem.data.replace( /fuck/gi, '****' ) );
 					conversionApi.writer.insert( text, data.modelCursor );
-					data.modelRange = ModelRange.createFromPositionAndShift( data.modelCursor, text.offsetSize );
+					data.modelRange = ModelRange._createFromPositionAndShift( data.modelCursor, text.offsetSize );
 					data.modelCursor = data.modelRange.end;
 				}
 			} );
@@ -841,9 +841,9 @@ describe( 'upcast-converters', () => {
 					const paragraph = conversionApi.writer.createElement( 'paragraph' );
 
 					conversionApi.writer.insert( paragraph, data.modelCursor );
-					conversionApi.convertChildren( data.viewItem, ModelPosition.createAt( paragraph, 0 ) );
+					conversionApi.convertChildren( data.viewItem, ModelPosition._createAt( paragraph, 0 ) );
 
-					data.modelRange = ModelRange.createOn( paragraph );
+					data.modelRange = ModelRange._createOn( paragraph );
 					data.modelCursor = data.modelRange.end;
 				}
 			} );
@@ -863,7 +863,7 @@ describe( 'upcast-converters', () => {
 				new ViewContainerElement( 'div', null, [ new ViewText( 'abc' ), new ViewContainerElement( 'foo' ) ] ),
 				new ViewContainerElement( 'bar' )
 			] );
-			const position = ModelPosition.createAt( new ModelElement( 'element' ), 0 );
+			const position = ModelPosition._createAt( new ModelElement( 'element' ), 0 );
 
 			dispatcher.on( 'documentFragment', convertToModelFragment() );
 			dispatcher.on( 'element', convertToModelFragment(), { priority: 'lowest' } );

+ 7 - 7
packages/ckeditor5-engine/tests/conversion/upcast-selection-converters.js

@@ -46,7 +46,7 @@ describe( 'convertSelectionChange', () => {
 
 	it( 'should convert collapsed selection', () => {
 		const viewSelection = new ViewSelection();
-		viewSelection.setTo( ViewRange.createFromParentsAndOffsets(
+		viewSelection.setTo( ViewRange._createFromParentsAndOffsets(
 			viewRoot.getChild( 0 ).getChild( 0 ), 1, viewRoot.getChild( 0 ).getChild( 0 ), 1 ) );
 
 		convertSelection( null, { newSelection: viewSelection } );
@@ -63,7 +63,7 @@ describe( 'convertSelectionChange', () => {
 		mapper.bindElements( modelRoot.getChild( 0 ), viewRoot.getChild( 0 ) );
 
 		const viewSelection = new ViewSelection( [
-			ViewRange.createFromParentsAndOffsets( viewRoot.getChild( 0 ).getChild( 0 ), 2, viewRoot.getChild( 0 ).getChild( 0 ), 6 )
+			ViewRange._createFromParentsAndOffsets( viewRoot.getChild( 0 ).getChild( 0 ), 2, viewRoot.getChild( 0 ).getChild( 0 ), 6 )
 		] );
 
 		convertSelection( null, { newSelection: viewSelection } );
@@ -73,9 +73,9 @@ describe( 'convertSelectionChange', () => {
 
 	it( 'should convert multi ranges selection', () => {
 		const viewSelection = new ViewSelection( [
-			ViewRange.createFromParentsAndOffsets(
+			ViewRange._createFromParentsAndOffsets(
 				viewRoot.getChild( 0 ).getChild( 0 ), 1, viewRoot.getChild( 0 ).getChild( 0 ), 2 ),
-			ViewRange.createFromParentsAndOffsets(
+			ViewRange._createFromParentsAndOffsets(
 				viewRoot.getChild( 1 ).getChild( 0 ), 1, viewRoot.getChild( 1 ).getChild( 0 ), 2 )
 		] );
 
@@ -100,9 +100,9 @@ describe( 'convertSelectionChange', () => {
 
 	it( 'should convert reverse selection', () => {
 		const viewSelection = new ViewSelection( [
-			ViewRange.createFromParentsAndOffsets(
+			ViewRange._createFromParentsAndOffsets(
 				viewRoot.getChild( 0 ).getChild( 0 ), 1, viewRoot.getChild( 0 ).getChild( 0 ), 2 ),
-			ViewRange.createFromParentsAndOffsets(
+			ViewRange._createFromParentsAndOffsets(
 				viewRoot.getChild( 1 ).getChild( 0 ), 1, viewRoot.getChild( 1 ).getChild( 0 ), 2 )
 		], { backward: true } );
 
@@ -114,7 +114,7 @@ describe( 'convertSelectionChange', () => {
 
 	it( 'should not enqueue changes if selection has not changed', () => {
 		const viewSelection = new ViewSelection( [
-			ViewRange.createFromParentsAndOffsets(
+			ViewRange._createFromParentsAndOffsets(
 				viewRoot.getChild( 0 ).getChild( 0 ), 1, viewRoot.getChild( 0 ).getChild( 0 ), 1 )
 		] );
 

+ 15 - 15
packages/ckeditor5-engine/tests/conversion/upcastdispatcher.js

@@ -162,7 +162,7 @@ describe( 'UpcastDispatcher', () => {
 
 				// Set conversion result to `modelRange` property of `data`.
 				// Later we will check if it was returned by `convert` method.
-				data.modelRange = ModelRange.createOn( text );
+				data.modelRange = ModelRange._createOn( text );
 			} );
 
 			const conversionResult = model.change( writer => dispatcher.convert( viewText, writer ) );
@@ -199,7 +199,7 @@ describe( 'UpcastDispatcher', () => {
 
 				// Set conversion result to `modelRange` property of `data`.
 				// Later we will check if it was returned by `convert` method.
-				data.modelRange = ModelRange.createOn( paragraph );
+				data.modelRange = ModelRange._createOn( paragraph );
 			} );
 
 			// Use `additionalData` parameter to check if it was passed to the event.
@@ -236,7 +236,7 @@ describe( 'UpcastDispatcher', () => {
 
 				// Set conversion result to `modelRange` property of `data`.
 				// Later we will check if it was returned by `convert` method.
-				data.modelRange = ModelRange.createOn( text );
+				data.modelRange = ModelRange._createOn( text );
 			} );
 
 			const conversionResult = model.change( writer => dispatcher.convert( viewFragment, writer ) );
@@ -262,25 +262,25 @@ describe( 'UpcastDispatcher', () => {
 
 				// Create and insert empty split element before target element.
 				const emptySplit = conversionApi.writer.createElement( 'paragraph' );
-				conversionApi.writer.insert( emptySplit, ModelPosition.createAfter( paragraph ) );
+				conversionApi.writer.insert( emptySplit, ModelPosition._createAfter( paragraph ) );
 
 				// Create and insert not empty split after target element.
 				const notEmptySplit = conversionApi.writer.createElement( 'paragraph' );
 				conversionApi.writer.appendText( 'foo', notEmptySplit );
-				conversionApi.writer.insert( notEmptySplit, ModelPosition.createAfter( emptySplit ) );
+				conversionApi.writer.insert( notEmptySplit, ModelPosition._createAfter( emptySplit ) );
 
 				// Create and insert split with other split inside (both should be removed)
 				const outerSplit = conversionApi.writer.createElement( 'paragraph' );
 				const innerSplit = conversionApi.writer.createElement( 'paragraph' );
 				conversionApi.writer.append( innerSplit, outerSplit );
-				conversionApi.writer.insert( outerSplit, ModelPosition.createBefore( paragraph ) );
+				conversionApi.writer.insert( outerSplit, ModelPosition._createBefore( paragraph ) );
 
 				dispatcher._removeIfEmpty.add( emptySplit );
 				dispatcher._removeIfEmpty.add( notEmptySplit );
 				dispatcher._removeIfEmpty.add( outerSplit );
 				dispatcher._removeIfEmpty.add( innerSplit );
 
-				data.modelRange = ModelRange.createOn( paragraph );
+				data.modelRange = ModelRange._createOn( paragraph );
 				data.modelCursor = data.modelRange.end;
 
 				// We have the following result:
@@ -321,7 +321,7 @@ describe( 'UpcastDispatcher', () => {
 				conversionApi.writer.insert( fragment, data.modelCursor );
 
 				// Create range on this fragment as a conversion result.
-				data.modelRange = ModelRange.createIn( data.modelCursor.parent );
+				data.modelRange = ModelRange._createIn( data.modelCursor.parent );
 			} );
 
 			const conversionResult = model.change( writer => dispatcher.convert( viewFragment, writer ) );
@@ -404,14 +404,14 @@ describe( 'UpcastDispatcher', () => {
 			dispatcher.on( 'element:p', ( evt, data ) => {
 				spyP();
 
-				data.modelRange = ModelRange.createOn( modelP );
+				data.modelRange = ModelRange._createOn( modelP );
 				data.modelCursor = data.modelRange.end;
 			} );
 
 			dispatcher.on( 'text', ( evt, data ) => {
 				spyText();
 
-				data.modelRange = ModelRange.createOn( modelText );
+				data.modelRange = ModelRange._createOn( modelText );
 				data.modelCursor = data.modelRange.end;
 			} );
 
@@ -501,7 +501,7 @@ describe( 'UpcastDispatcher', () => {
 				dispatcher.on( 'documentFragment', ( evt, data, conversionApi ) => {
 					spy();
 
-					const result = conversionApi.convertChildren( data.viewItem, ModelPosition.createAt( rootMock, 0 ) );
+					const result = conversionApi.convertChildren( data.viewItem, ModelPosition._createAt( rootMock, 0 ) );
 
 					expect( result.modelRange ).to.be.instanceof( ModelRange );
 					expect( result.modelRange.start.path ).to.deep.equal( [ 0 ] );
@@ -540,7 +540,7 @@ describe( 'UpcastDispatcher', () => {
 				dispatcher.on( 'documentFragment', ( evt, data, conversionApi ) => {
 					const paragraph = conversionApi.writer.createElement( 'paragraph' );
 					const span = conversionApi.writer.createElement( 'span' );
-					const position = ModelPosition.createAt( paragraph, 0 );
+					const position = ModelPosition._createAt( paragraph, 0 );
 
 					const result = conversionApi.splitToAllowedParent( span, position );
 
@@ -572,13 +572,13 @@ describe( 'UpcastDispatcher', () => {
 					conversionApi.writer.insert( paragraph, section );
 					conversionApi.writer.insert( span, paragraph );
 
-					const position = ModelPosition.createAt( span, 0 );
+					const position = ModelPosition._createAt( span, 0 );
 
 					const paragraph2 = conversionApi.writer.createElement( 'paragraph' );
 					const result = conversionApi.splitToAllowedParent( paragraph2, position );
 
 					expect( result ).to.deep.equal( {
-						position: ModelPosition.createAfter( paragraph ),
+						position: ModelPosition._createAfter( paragraph ),
 						cursorParent: paragraph.parent.getChild( 1 ).getChild( 0 )
 					} );
 
@@ -597,7 +597,7 @@ describe( 'UpcastDispatcher', () => {
 				dispatcher.on( 'documentFragment', ( evt, data, conversionApi ) => {
 					const paragraph = conversionApi.writer.createElement( 'paragraph' );
 					const span = conversionApi.writer.createElement( 'span' );
-					const position = ModelPosition.createAt( paragraph, 0 );
+					const position = ModelPosition._createAt( paragraph, 0 );
 
 					const result = conversionApi.splitToAllowedParent( span, position );
 

+ 19 - 19
packages/ckeditor5-engine/tests/dev-utils/enableenginedebug.js

@@ -183,9 +183,9 @@ describe( 'debug tools', () => {
 		} );
 
 		it( 'for ModelRange', () => {
-			const rangeInRoot = ModelRange.createIn( modelRoot );
-			const rangeInElement = ModelRange.createIn( modelElement );
-			const rangeInDocFrag = ModelRange.createIn( modelDocFrag );
+			const rangeInRoot = ModelRange._createIn( modelRoot );
+			const rangeInElement = ModelRange._createIn( modelElement );
+			const rangeInDocFrag = ModelRange._createIn( modelDocFrag );
 
 			expect( rangeInRoot.toString() ).to.equal( 'main [ 0 ] - [ 0 ]' );
 			expect( rangeInElement.toString() ).to.equal( '<paragraph> [ 0 ] - [ 3 ]' );
@@ -226,7 +226,7 @@ describe( 'debug tools', () => {
 			} );
 
 			it( 'AttributeOperation', () => {
-				const op = new AttributeOperation( ModelRange.createIn( modelRoot ), 'key', null, { foo: 'bar' }, 0 );
+				const op = new AttributeOperation( ModelRange._createIn( modelRoot ), 'key', null, { foo: 'bar' }, 0 );
 
 				expect( op.toString() ).to.equal( 'AttributeOperation( 0 ): "key": null -> {"foo":"bar"}, main [ 0 ] - [ 6 ]' );
 
@@ -235,7 +235,7 @@ describe( 'debug tools', () => {
 			} );
 
 			it( 'DetachOperation (text node)', () => {
-				const op = new DetachOperation( ModelPosition.createAt( modelRoot, 0 ), 3 );
+				const op = new DetachOperation( ModelPosition._createAt( modelRoot, 0 ), 3 );
 
 				expect( op.toString() ).to.equal( 'DetachOperation( null ): #foo -> main [ 0 ] - [ 3 ]' );
 
@@ -247,7 +247,7 @@ describe( 'debug tools', () => {
 				const element = new ModelElement( 'element' );
 				modelRoot._insertChild( 0, element );
 
-				const op = new DetachOperation( ModelPosition.createBefore( element ), 1 );
+				const op = new DetachOperation( ModelPosition._createBefore( element ), 1 );
 
 				expect( op.toString() ).to.equal( 'DetachOperation( null ): <element> -> main [ 0 ] - [ 1 ]' );
 
@@ -259,7 +259,7 @@ describe( 'debug tools', () => {
 				const element = new ModelElement( 'element' );
 				modelRoot._insertChild( 0, element );
 
-				const op = new DetachOperation( ModelPosition.createBefore( element ), 2 );
+				const op = new DetachOperation( ModelPosition._createBefore( element ), 2 );
 
 				expect( op.toString() ).to.equal( 'DetachOperation( null ): [ 2 ] -> main [ 0 ] - [ 2 ]' );
 
@@ -268,7 +268,7 @@ describe( 'debug tools', () => {
 			} );
 
 			it( 'InsertOperation (text node)', () => {
-				const op = new InsertOperation( ModelPosition.createAt( modelRoot, 3 ), [ new ModelText( 'abc' ) ], 0 );
+				const op = new InsertOperation( ModelPosition._createAt( modelRoot, 3 ), [ new ModelText( 'abc' ) ], 0 );
 
 				expect( op.toString() ).to.equal( 'InsertOperation( 0 ): #abc -> main [ 3 ]' );
 
@@ -277,7 +277,7 @@ describe( 'debug tools', () => {
 			} );
 
 			it( 'InsertOperation (element)', () => {
-				const op = new InsertOperation( ModelPosition.createAt( modelRoot, 3 ), [ new ModelElement( 'paragraph' ) ], 0 );
+				const op = new InsertOperation( ModelPosition._createAt( modelRoot, 3 ), [ new ModelElement( 'paragraph' ) ], 0 );
 
 				expect( op.toString() ).to.equal( 'InsertOperation( 0 ): <paragraph> -> main [ 3 ]' );
 
@@ -287,7 +287,7 @@ describe( 'debug tools', () => {
 
 			it( 'InsertOperation (multiple nodes)', () => {
 				const nodes = [ new ModelText( 'x' ), new ModelElement( 'y' ), new ModelText( 'z' ) ];
-				const op = new InsertOperation( ModelPosition.createAt( modelRoot, 3 ), nodes, 0 );
+				const op = new InsertOperation( ModelPosition._createAt( modelRoot, 3 ), nodes, 0 );
 
 				expect( op.toString() ).to.equal( 'InsertOperation( 0 ): [ 3 ] -> main [ 3 ]' );
 
@@ -296,7 +296,7 @@ describe( 'debug tools', () => {
 			} );
 
 			it( 'MarkerOperation', () => {
-				const op = new MarkerOperation( 'marker', null, ModelRange.createIn( modelRoot ), modelDoc.markers, false, 0 );
+				const op = new MarkerOperation( 'marker', null, ModelRange._createIn( modelRoot ), modelDoc.markers, false, 0 );
 
 				expect( op.toString() ).to.equal( 'MarkerOperation( 0 ): "marker": null -> main [ 0 ] - [ 6 ]' );
 
@@ -305,7 +305,7 @@ describe( 'debug tools', () => {
 			} );
 
 			it( 'MoveOperation', () => {
-				const op = new MoveOperation( ModelPosition.createAt( modelRoot, 1 ), 2, ModelPosition.createAt( modelRoot, 6 ), 0 );
+				const op = new MoveOperation( ModelPosition._createAt( modelRoot, 1 ), 2, ModelPosition._createAt( modelRoot, 6 ), 0 );
 
 				expect( op.toString() ).to.equal( 'MoveOperation( 0 ): main [ 1 ] - [ 3 ] -> main [ 6 ]' );
 
@@ -323,7 +323,7 @@ describe( 'debug tools', () => {
 			} );
 
 			it( 'RenameOperation', () => {
-				const op = new RenameOperation( ModelPosition.createAt( modelRoot, 1 ), 'old', 'new', 0 );
+				const op = new RenameOperation( ModelPosition._createAt( modelRoot, 1 ), 'old', 'new', 0 );
 
 				expect( op.toString() ).to.equal( 'RenameOperation( 0 ): main [ 1 ]: "old" -> "new"' );
 
@@ -383,7 +383,7 @@ describe( 'debug tools', () => {
 		} );
 
 		it( 'for applied operations', () => {
-			const op = new InsertOperation( ModelPosition.createAt( modelRoot, 0 ), [ new ModelText( 'foo' ) ], 0 );
+			const op = new InsertOperation( ModelPosition._createAt( modelRoot, 0 ), [ new ModelText( 'foo' ) ], 0 );
 
 			model.applyOperation( op );
 
@@ -559,11 +559,11 @@ describe( 'debug tools', () => {
 			const viewDoc = view.document;
 
 			model.change( () => {
-				const insert = new InsertOperation( ModelPosition.createAt( modelRoot, 0 ), new ModelText( 'foobar' ), 0 );
+				const insert = new InsertOperation( ModelPosition._createAt( modelRoot, 0 ), new ModelText( 'foobar' ), 0 );
 				model.applyOperation( insert );
 
 				const graveyard = modelDoc.graveyard;
-				const move = new MoveOperation( ModelPosition.createAt( modelRoot, 1 ), 2, ModelPosition.createAt( graveyard, 0 ), 1 );
+				const move = new MoveOperation( ModelPosition._createAt( modelRoot, 1 ), 2, ModelPosition._createAt( graveyard, 0 ), 1 );
 				model.applyOperation( move );
 			} );
 
@@ -651,7 +651,7 @@ describe( 'debug tools', () => {
 			const modelRoot = model.document.getRoot();
 
 			for ( let i = 0; i < 25; i++ ) {
-				const insert = new InsertOperation( ModelPosition.createAt( modelRoot, 0 ), new ModelText( 'foobar' ), modelDoc.version );
+				const insert = new InsertOperation( ModelPosition._createAt( modelRoot, 0 ), new ModelText( 'foobar' ), modelDoc.version );
 				model.applyOperation( insert );
 			}
 
@@ -672,7 +672,7 @@ describe( 'debug tools', () => {
 
 			otherRoot._appendChild( element );
 
-			const insert = new InsertOperation( ModelPosition.createAt( element, 0 ), new ModelText( 'foo' ), 0 );
+			const insert = new InsertOperation( ModelPosition._createAt( element, 0 ), new ModelText( 'foo' ), 0 );
 			model.applyOperation( insert );
 
 			const stringifiedOperations = model.getAppliedOperations();
@@ -689,7 +689,7 @@ describe( 'debug tools', () => {
 
 			otherRoot._appendChild( element );
 
-			const insert = new InsertOperation( ModelPosition.createAt( element, 0 ), new ModelText( 'foo' ), 0 );
+			const insert = new InsertOperation( ModelPosition._createAt( element, 0 ), new ModelText( 'foo' ), 0 );
 			model.applyOperation( insert );
 
 			const stringifiedOperations = model.getAppliedOperations();

+ 10 - 8
packages/ckeditor5-engine/tests/dev-utils/model.js

@@ -67,7 +67,7 @@ describe( 'model test utils', () => {
 			const stringifySpy = sinon.spy( getData, '_stringify' );
 			root._appendChild( new Element( 'b', null, new Text( 'btext' ) ) );
 			model.change( writer => {
-				writer.setSelection( Range.createFromParentsAndOffsets( root, 0, root, 1 ) );
+				writer.setSelection( new Range( Position._createAt( root, 0 ), Position._createAt( root, 1 ) ) );
 			} );
 			expect( getData( model ) ).to.equal( '[<b>btext</b>]' );
 			sinon.assert.calledOnce( stringifySpy );
@@ -355,7 +355,7 @@ describe( 'model test utils', () => {
 
 			it( 'writes flat selection containing couple of nodes', () => {
 				model.change( writer => {
-					writer.setSelection( Range.createFromParentsAndOffsets( root, 0, root, 4 ) );
+					writer.setSelection( new Range( Position._createAt( root, 0 ), Position._createAt( root, 4 ) ) );
 				} );
 
 				expect( stringify( root, selection ) ).to.equal(
@@ -365,7 +365,7 @@ describe( 'model test utils', () => {
 
 			it( 'writes flat selection within text', () => {
 				model.change( writer => {
-					writer.setSelection( Range.createFromParentsAndOffsets( root, 2, root, 3 ) );
+					writer.setSelection( new Range( Position._createAt( root, 2 ), Position._createAt( root, 3 ) ) );
 				} );
 
 				expect( stringify( root, selection ) ).to.equal(
@@ -375,7 +375,7 @@ describe( 'model test utils', () => {
 
 			it( 'writes multi-level selection', () => {
 				model.change( writer => {
-					writer.setSelection( Range.createFromParentsAndOffsets( elA, 0, elB, 0 ) );
+					writer.setSelection( new Range( Position._createAt( elA, 0 ), Position._createAt( elB, 0 ) ) );
 				} );
 
 				expect( stringify( root, selection ) ).to.equal(
@@ -385,7 +385,7 @@ describe( 'model test utils', () => {
 
 			it( 'writes selection when is backward', () => {
 				model.change( writer => {
-					writer.setSelection( Range.createFromParentsAndOffsets( elA, 0, elB, 0 ), { backward: true } );
+					writer.setSelection( new Range( Position._createAt( elA, 0 ), Position._createAt( elB, 0 ) ), { backward: true } );
 				} );
 
 				expect( stringify( root, selection ) ).to.equal(
@@ -398,14 +398,14 @@ describe( 'model test utils', () => {
 
 				root._appendChild( new Text( 'நிலைக்கு' ) );
 				model.change( writer => {
-					writer.setSelection( Range.createFromParentsAndOffsets( root, 2, root, 6 ) );
+					writer.setSelection( new Range( Position._createAt( root, 2 ), Position._createAt( root, 6 ) ) );
 				} );
 
 				expect( stringify( root, selection ) ).to.equal( 'நி[லைக்]கு' );
 			} );
 
 			it( 'uses range and coverts it to selection', () => {
-				const range = Range.createFromParentsAndOffsets( elA, 0, elB, 0 );
+				const range = new Range( Position._createAt( elA, 0 ), Position._createAt( elB, 0 ) );
 
 				expect( stringify( root, range ) ).to.equal(
 					'<a>[</a>foo<$text bold="true">bar</$text><b>]</b>'
@@ -441,7 +441,9 @@ describe( 'model test utils', () => {
 				expect( el ).to.be.instanceOf( Element );
 				expect( fragment ).to.be.instanceOf( DocumentFragment );
 				expect( selection.rangeCount ).to.equal( 1 );
-				expect( selection.getFirstRange().isEqual( Range.createFromParentsAndOffsets( fragment, 0, fragment, 1 ) ) ).to.be.true;
+
+				const range = new Range( Position._createAt( fragment, 0 ), Position._createAt( fragment, 1 ) );
+				expect( selection.getFirstRange().isEqual( range ) ).to.be.true;
 			}
 		} );
 

+ 34 - 34
packages/ckeditor5-engine/tests/dev-utils/view.js

@@ -64,7 +64,7 @@ describe( 'view test utils', () => {
 				root._appendChild( new Element( 'p' ) );
 
 				view.change( writer => {
-					writer.setSelection( Range.createFromParentsAndOffsets( root, 0, root, 1 ) );
+					writer.setSelection( Range._createFromParentsAndOffsets( root, 0, root, 1 ) );
 				} );
 
 				expect( getData( view, options ) ).to.equal( '[<p></p>]' );
@@ -166,7 +166,7 @@ describe( 'view test utils', () => {
 			const b1 = new Element( 'b', null, text1 );
 			const b2 = new Element( 'b', null, text2 );
 			const p = new Element( 'p', null, [ b1, b2 ] );
-			const range = Range.createFromParentsAndOffsets( p, 1, p, 2 );
+			const range = Range._createFromParentsAndOffsets( p, 1, p, 2 );
 			const selection = new DocumentSelection( [ range ] );
 			expect( stringify( p, selection ) ).to.equal( '<p><b>foobar</b>[<b>bazqux</b>]</p>' );
 		} );
@@ -175,7 +175,7 @@ describe( 'view test utils', () => {
 			const text = new Text( 'நிலைக்கு' );
 			const b = new Element( 'b', null, text );
 			const p = new Element( 'p', null, b );
-			const range = Range.createFromParentsAndOffsets( p, 0, text, 4 );
+			const range = Range._createFromParentsAndOffsets( p, 0, text, 4 );
 			const selection = new DocumentSelection( [ range ] );
 
 			expect( stringify( p, selection ) ).to.equal( '<p>[<b>நிலை}க்கு</b></p>' );
@@ -184,7 +184,7 @@ describe( 'view test utils', () => {
 		it( 'should write collapsed selection ranges inside elements', () => {
 			const text = new Text( 'foobar' );
 			const p = new Element( 'p', null, text );
-			const range = Range.createFromParentsAndOffsets( p, 0, p, 0 );
+			const range = Range._createFromParentsAndOffsets( p, 0, p, 0 );
 			const selection = new DocumentSelection( [ range ] );
 			expect( stringify( p, selection ) ).to.equal( '<p>[]foobar</p>' );
 		} );
@@ -195,7 +195,7 @@ describe( 'view test utils', () => {
 			const b1 = new Element( 'b', null, text1 );
 			const b2 = new Element( 'b', null, text2 );
 			const p = new Element( 'p', null, [ b1, b2 ] );
-			const range = Range.createFromParentsAndOffsets( text1, 1, text1, 5 );
+			const range = Range._createFromParentsAndOffsets( text1, 1, text1, 5 );
 			const selection = new DocumentSelection( [ range ] );
 			expect( stringify( p, selection ) ).to.equal( '<p><b>f{ooba}r</b><b>bazqux</b></p>' );
 		} );
@@ -206,7 +206,7 @@ describe( 'view test utils', () => {
 			const b1 = new Element( 'b', null, text1 );
 			const b2 = new Element( 'b', null, text2 );
 			const p = new Element( 'p', null, [ b1, b2 ] );
-			const range = Range.createFromParentsAndOffsets( text1, 1, text1, 5 );
+			const range = Range._createFromParentsAndOffsets( text1, 1, text1, 5 );
 			const selection = new DocumentSelection( [ range ] );
 			expect( stringify( p, selection, { sameSelectionCharacters: true } ) )
 				.to.equal( '<p><b>f[ooba]r</b><b>bazqux</b></p>' );
@@ -215,7 +215,7 @@ describe( 'view test utils', () => {
 		it( 'should write collapsed selection ranges inside texts', () => {
 			const text = new Text( 'foobar' );
 			const p = new Element( 'p', null, text );
-			const range = Range.createFromParentsAndOffsets( text, 0, text, 0 );
+			const range = Range._createFromParentsAndOffsets( text, 0, text, 0 );
 			const selection = new DocumentSelection( [ range ] );
 			expect( stringify( p, selection ) ).to.equal( '<p>{}foobar</p>' );
 		} );
@@ -226,7 +226,7 @@ describe( 'view test utils', () => {
 			const b1 = new Element( 'b', null, text1 );
 			const b2 = new Element( 'b', null, text2 );
 			const p = new Element( 'p', null, [ b1, b2 ] );
-			const range = Range.createFromParentsAndOffsets( p, 0, text2, 5 );
+			const range = Range._createFromParentsAndOffsets( p, 0, text2, 5 );
 			const selection = new DocumentSelection( [ range ] );
 			expect( stringify( p, selection ) ).to.equal( '<p>[<b>foobar</b><b>bazqu}x</b></p>' );
 		} );
@@ -277,7 +277,7 @@ describe( 'view test utils', () => {
 			const text = new Text( 'foobar' );
 			const b = new Element( 'b', null, text );
 			const p = new Element( 'p', null, b );
-			const range = Range.createFromParentsAndOffsets( p, 0, p, 5 );
+			const range = Range._createFromParentsAndOffsets( p, 0, p, 5 );
 
 			expect( stringify( p, range ) ).to.equal( '<p>[<b>foobar</b></p>' );
 		} );
@@ -286,7 +286,7 @@ describe( 'view test utils', () => {
 			const text = new Text( 'foobar' );
 			const b = new Element( 'b', null, text );
 			const p = new Element( 'p', null, b );
-			const range = Range.createFromParentsAndOffsets( p, -1, p, 1 );
+			const range = Range._createFromParentsAndOffsets( p, -1, p, 1 );
 
 			expect( stringify( p, range ) ).to.equal( '<p><b>foobar</b>]</p>' );
 		} );
@@ -295,7 +295,7 @@ describe( 'view test utils', () => {
 			const text = new Text( 'foobar' );
 			const b = new Element( 'b', null, text );
 			const p = new Element( 'p', null, b );
-			const range = Range.createFromParentsAndOffsets( text, 0, text, 7 );
+			const range = Range._createFromParentsAndOffsets( text, 0, text, 7 );
 
 			expect( stringify( p, range ) ).to.equal( '<p><b>{foobar</b></p>' );
 		} );
@@ -304,7 +304,7 @@ describe( 'view test utils', () => {
 			const text = new Text( 'foobar' );
 			const b = new Element( 'b', null, text );
 			const p = new Element( 'p', null, b );
-			const range = Range.createFromParentsAndOffsets( text, -1, text, 2 );
+			const range = Range._createFromParentsAndOffsets( text, -1, text, 2 );
 
 			expect( stringify( p, range ) ).to.equal( '<p><b>fo}obar</b></p>' );
 		} );
@@ -315,8 +315,8 @@ describe( 'view test utils', () => {
 			const b1 = new Element( 'b', null, text1 );
 			const b2 = new Element( 'b', null, text2 );
 			const p = new Element( 'p', null, [ b1, b2 ] );
-			const range1 = Range.createFromParentsAndOffsets( p, 0, p, 1 );
-			const range2 = Range.createFromParentsAndOffsets( p, 1, p, 1 );
+			const range1 = Range._createFromParentsAndOffsets( p, 0, p, 1 );
+			const range2 = Range._createFromParentsAndOffsets( p, 1, p, 1 );
 			const selection = new DocumentSelection( [ range2, range1 ] );
 
 			expect( stringify( p, selection ) ).to.equal( '<p>[<b>foobar</b>][]<b>bazqux</b></p>' );
@@ -327,10 +327,10 @@ describe( 'view test utils', () => {
 			const text2 = new Text( 'bazqux' );
 			const b = new Element( 'b', null, text1 );
 			const p = new Element( 'p', null, [ b, text2 ] );
-			const range1 = Range.createFromParentsAndOffsets( p, 0, p, 1 );
-			const range2 = Range.createFromParentsAndOffsets( text2, 0, text2, 3 );
-			const range3 = Range.createFromParentsAndOffsets( text2, 3, text2, 4 );
-			const range4 = Range.createFromParentsAndOffsets( p, 1, p, 1 );
+			const range1 = Range._createFromParentsAndOffsets( p, 0, p, 1 );
+			const range2 = Range._createFromParentsAndOffsets( text2, 0, text2, 3 );
+			const range3 = Range._createFromParentsAndOffsets( text2, 3, text2, 4 );
+			const range4 = Range._createFromParentsAndOffsets( p, 1, p, 1 );
 			const selection = new DocumentSelection( [ range1, range2, range3, range4 ] );
 
 			expect( stringify( p, selection ) ).to.equal( '<p>[<b>foobar</b>][]{baz}{q}ux</p>' );
@@ -345,7 +345,7 @@ describe( 'view test utils', () => {
 
 		it( 'should use Range instance instead of Selection', () => {
 			const text = new Text( 'foobar' );
-			const range = Range.createFromParentsAndOffsets( text, 3, text, 4 );
+			const range = Range._createFromParentsAndOffsets( text, 3, text, 4 );
 			const string = stringify( text, range );
 			expect( string ).to.equal( 'foo{b}ar' );
 		} );
@@ -428,7 +428,7 @@ describe( 'view test utils', () => {
 
 			expect( view ).to.be.instanceOf( DocumentFragment );
 			expect( selection.rangeCount ).to.equal( 1 );
-			expect( selection.getFirstRange().isEqual( Range.createFromParentsAndOffsets( view, 0, view, 0 ) ) ).to.be.true;
+			expect( selection.getFirstRange().isEqual( Range._createFromParentsAndOffsets( view, 0, view, 0 ) ) ).to.be.true;
 		} );
 
 		it( 'should return Element if range is around single element', () => {
@@ -438,7 +438,7 @@ describe( 'view test utils', () => {
 			expect( view ).to.be.instanceOf( Element );
 			expect( parent ).to.be.instanceOf( DocumentFragment );
 			expect( selection.rangeCount ).to.equal( 1 );
-			expect( selection.getFirstRange().isEqual( Range.createFromParentsAndOffsets( parent, 0, parent, 1 ) ) ).to.be.true;
+			expect( selection.getFirstRange().isEqual( Range._createFromParentsAndOffsets( parent, 0, parent, 1 ) ) ).to.be.true;
 		} );
 
 		it( 'should create DocumentFragment when multiple elements on root', () => {
@@ -538,8 +538,8 @@ describe( 'view test utils', () => {
 			expect( selection.rangeCount ).to.equal( 2 );
 			const ranges = [ ...selection.getRanges() ];
 
-			expect( ranges[ 0 ].isEqual( Range.createFromParentsAndOffsets( view, 1, view, 3 ) ) ).to.be.true;
-			expect( ranges[ 1 ].isEqual( Range.createFromParentsAndOffsets( view, 4, view, 4 ) ) ).to.be.true;
+			expect( ranges[ 0 ].isEqual( Range._createFromParentsAndOffsets( view, 1, view, 3 ) ) ).to.be.true;
+			expect( ranges[ 1 ].isEqual( Range._createFromParentsAndOffsets( view, 4, view, 4 ) ) ).to.be.true;
 		} );
 
 		it( 'should parse selection range between elements', () => {
@@ -555,8 +555,8 @@ describe( 'view test utils', () => {
 			expect( text.data ).to.equal( 'foobar' );
 			expect( selection.rangeCount ).to.equal( 2 );
 			const ranges = [ ...selection.getRanges() ];
-			expect( ranges[ 0 ].isEqual( Range.createFromParentsAndOffsets( view, 0, b, 1 ) ) ).to.be.true;
-			expect( ranges[ 1 ].isEqual( Range.createFromParentsAndOffsets( view, 1, view, 1 ) ) ).to.be.true;
+			expect( ranges[ 0 ].isEqual( Range._createFromParentsAndOffsets( view, 0, b, 1 ) ) ).to.be.true;
+			expect( ranges[ 1 ].isEqual( Range._createFromParentsAndOffsets( view, 1, view, 1 ) ) ).to.be.true;
 		} );
 
 		it( 'should support unicode', () => {
@@ -590,7 +590,7 @@ describe( 'view test utils', () => {
 			expect( text ).to.be.instanceof( Text );
 			expect( text.data ).to.equal( 'foobar' );
 			expect( selection.rangeCount ).to.equal( 1 );
-			expect( selection.getFirstRange().isEqual( Range.createFromParentsAndOffsets( text, 3, view, 1 ) ) ).to.be.true;
+			expect( selection.getFirstRange().isEqual( Range._createFromParentsAndOffsets( text, 3, view, 1 ) ) ).to.be.true;
 		} );
 
 		it( 'should parse ranges #2', () => {
@@ -608,17 +608,17 @@ describe( 'view test utils', () => {
 			expect( text2.data ).to.equal( 'baz' );
 			expect( selection.rangeCount ).to.equal( 2 );
 			const ranges = [ ...selection.getRanges() ];
-			expect( ranges[ 0 ].isEqual( Range.createFromParentsAndOffsets( view, 0, text1, 4 ) ) ).to.be.true;
-			expect( ranges[ 1 ].isEqual( Range.createFromParentsAndOffsets( text2, 0, view, 2 ) ) ).to.be.true;
+			expect( ranges[ 0 ].isEqual( Range._createFromParentsAndOffsets( view, 0, text1, 4 ) ) ).to.be.true;
+			expect( ranges[ 1 ].isEqual( Range._createFromParentsAndOffsets( text2, 0, view, 2 ) ) ).to.be.true;
 		} );
 
 		it( 'should use ranges order when provided', () => {
 			const { view, selection } = parse( '{f}oo{b}arb{a}z', { order: [ 3, 1, 2 ] } );
 			expect( selection.rangeCount ).to.equal( 3 );
 			const ranges = [ ...selection.getRanges() ];
-			expect( ranges[ 0 ].isEqual( Range.createFromParentsAndOffsets( view, 3, view, 4 ) ) ).to.be.true;
-			expect( ranges[ 1 ].isEqual( Range.createFromParentsAndOffsets( view, 7, view, 8 ) ) ).to.be.true;
-			expect( ranges[ 2 ].isEqual( Range.createFromParentsAndOffsets( view, 0, view, 1 ) ) ).to.be.true;
+			expect( ranges[ 0 ].isEqual( Range._createFromParentsAndOffsets( view, 3, view, 4 ) ) ).to.be.true;
+			expect( ranges[ 1 ].isEqual( Range._createFromParentsAndOffsets( view, 7, view, 8 ) ) ).to.be.true;
+			expect( ranges[ 2 ].isEqual( Range._createFromParentsAndOffsets( view, 0, view, 1 ) ) ).to.be.true;
 			expect( selection.anchor.isEqual( ranges[ 2 ].start ) ).to.be.true;
 			expect( selection.focus.isEqual( ranges[ 2 ].end ) ).to.be.true;
 		} );
@@ -627,9 +627,9 @@ describe( 'view test utils', () => {
 			const { view, selection } = parse( '{f}oo{b}arb{a}z', { order: [ 3, 1, 2 ], lastRangeBackward: true } );
 			expect( selection.rangeCount ).to.equal( 3 );
 			const ranges = [ ...selection.getRanges() ];
-			expect( ranges[ 0 ].isEqual( Range.createFromParentsAndOffsets( view, 3, view, 4 ) ) ).to.be.true;
-			expect( ranges[ 1 ].isEqual( Range.createFromParentsAndOffsets( view, 7, view, 8 ) ) ).to.be.true;
-			expect( ranges[ 2 ].isEqual( Range.createFromParentsAndOffsets( view, 0, view, 1 ) ) ).to.be.true;
+			expect( ranges[ 0 ].isEqual( Range._createFromParentsAndOffsets( view, 3, view, 4 ) ) ).to.be.true;
+			expect( ranges[ 1 ].isEqual( Range._createFromParentsAndOffsets( view, 7, view, 8 ) ) ).to.be.true;
+			expect( ranges[ 2 ].isEqual( Range._createFromParentsAndOffsets( view, 0, view, 1 ) ) ).to.be.true;
 			expect( selection.anchor.isEqual( ranges[ 2 ].end ) ).to.be.true;
 			expect( selection.focus.isEqual( ranges[ 2 ].start ) ).to.be.true;
 		} );

+ 2 - 5
packages/ckeditor5-engine/tests/manual/highlight.js

@@ -5,9 +5,6 @@
 
 /* global console, window, document */
 
-import ModelRange from '../../src/model/range';
-import ViewPosition from '../../src/view/position';
-
 import {
 	upcastElementToElement,
 } from '../../src/conversion/upcast-converters';
@@ -51,7 +48,7 @@ class FancyWidget extends Plugin {
 			model: 'fancywidget',
 			view: ( modelItem, viewWriter ) => {
 				const widgetElement = viewWriter.createContainerElement( 'figure', { class: 'fancy-widget' } );
-				viewWriter.insert( ViewPosition.createAt( widgetElement ), viewWriter.createText( 'widget' ) );
+				viewWriter.insert( viewWriter.createPositionAt( widgetElement ), viewWriter.createText( 'widget' ) );
 
 				return toWidget( widgetElement, viewWriter );
 			}
@@ -127,7 +124,7 @@ ClassicEditor.create( global.document.querySelector( '#editor' ), {
 
 function addMarker( editor, color ) {
 	editor.model.change( writer => {
-		const range = ModelRange.createFromRange( editor.model.document.selection.getFirstRange() );
+		const range = editor.model.document.selection.getFirstRange();
 		writer.addMarker( 'marker:' + color, { range, usingOperation: false } );
 	} );
 }

+ 1 - 1
packages/ckeditor5-engine/tests/manual/markers.js

@@ -108,7 +108,7 @@ function uid() {
 
 function addHighlight( color ) {
 	model.change( writer => {
-		const range = Range.createFromRange( model.document.selection.getFirstRange() );
+		const range = model.document.selection.getFirstRange();
 		const name = 'highlight:' + color + ':' + uid();
 
 		markerNames.push( name );

+ 2 - 2
packages/ckeditor5-engine/tests/manual/tickets/475/1.js

@@ -70,9 +70,9 @@ class AutoLinker extends Plugin {
 					const length = url.length;
 
 					if ( entry.position.offset + entry.length == index + length ) {
-						const livePos = LivePosition.createFromParentAndOffset( parent, index );
+						const livePos = LivePosition._createAt( parent, index );
 						this.editor.model.enqueueChange( writer => {
-							const urlRange = Range.createFromPositionAndShift( livePos, length );
+							const urlRange = Range._createFromPositionAndShift( livePos, length );
 							writer.setAttribute( 'link', url, urlRange );
 						} );
 						return;

+ 1 - 1
packages/ckeditor5-engine/tests/manual/tickets/ckeditor5-721/1.js

@@ -47,7 +47,7 @@ ClassicEditor
 					const b = writer.createAttributeElement( 'b' );
 					const div = writer.createContainerElement( 'div' );
 
-					writer.insert( ViewPosition.createAt( div ), b );
+					writer.insert( ViewPosition._createAt( div ), b );
 
 					return toWidget( div, writer, { label: 'element label' } );
 				}

+ 2 - 1
packages/ckeditor5-engine/tests/model/_utils/utils.js

@@ -4,6 +4,7 @@
  */
 
 import Range from '../../../src/model/range';
+import Position from '../../../src/model/position';
 import TreeWalker from '../../../src/model/treewalker';
 import Text from '../../../src/model/text';
 import TextProxy from '../../../src/model/textproxy';
@@ -85,5 +86,5 @@ export function getText( element ) {
  * @returns {engine.model.Range}
  */
 export function createRangeOnElementOnly( element ) {
-	return Range.createFromParentsAndOffsets( element.parent, element.startOffset, element, 0 );
+	return new Range( Position._createAt( element.parent, element.startOffset ), Position._createAt( element, 0 ) );
 }

+ 85 - 85
packages/ckeditor5-engine/tests/model/differ.js

@@ -139,9 +139,9 @@ describe( 'Differ', () => {
 				insert( image, position );
 
 				const caption = new Element( 'caption' );
-				insert( caption, Position.createAt( image, 0 ) );
+				insert( caption, Position._createAt( image, 0 ) );
 
-				insert( new Text( 'foo' ), Position.createAt( caption, 0 ) );
+				insert( new Text( 'foo' ), Position._createAt( caption, 0 ) );
 
 				expectChanges( [
 					{ type: 'insert', name: 'image', length: 1, position }
@@ -168,13 +168,13 @@ describe( 'Differ', () => {
 		it( 'node in a element with changed attribute', () => {
 			const text = new Text( 'xyz', { bold: true } );
 			const position = new Position( root, [ 0, 3 ] );
-			const range = Range.createFromParentsAndOffsets( root, 0, root, 1 );
+			const range = new Range( Position._createAt( root, 0 ), Position._createAt( root, 1 ) );
 
 			model.change( () => {
 				insert( text, position );
 				attribute( range, 'align', null, 'center' );
 
-				const diffRange = Range.createFromParentsAndOffsets( root, 0, root.getChild( 0 ), 0 );
+				const diffRange = new Range( Position._createAt( root, 0 ), Position._createAt( root.getChild( 0 ), 0 ) );
 
 				// Compare to scenario above, this time there is only an attribute change on parent element,
 				// so there is also a diff for text.
@@ -198,14 +198,14 @@ describe( 'Differ', () => {
 
 		it( 'nodes before nodes with changed attributes', () => {
 			const p1 = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( p1, 1, p1, 3 );
+			const range = new Range( Position._createAt( p1, 1 ), Position._createAt( p1, 3 ) );
 			const position = new Position( root, [ 0, 0 ] );
 
 			model.change( () => {
 				attribute( range, 'bold', null, true );
 				insert( new Text( 'xx' ), position );
 
-				const rangeAfter = Range.createFromParentsAndOffsets( p1, 3, p1, 5 );
+				const rangeAfter = new Range( Position._createAt( p1, 3 ), Position._createAt( p1, 5 ) );
 
 				expectChanges( [
 					{ type: 'insert', name: '$text', length: 2, position },
@@ -216,15 +216,15 @@ describe( 'Differ', () => {
 
 		it( 'nodes between nodes with changed attributes', () => {
 			const p1 = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( p1, 1, p1, 3 );
+			const range = new Range( Position._createAt( p1, 1 ), Position._createAt( p1, 3 ) );
 			const position = new Position( root, [ 0, 2 ] );
 
 			model.change( () => {
 				attribute( range, 'bold', null, true );
 				insert( new Text( 'xx' ), position );
 
-				const rangeBefore = Range.createFromParentsAndOffsets( p1, 1, p1, 2 );
-				const rangeAfter = Range.createFromParentsAndOffsets( p1, 4, p1, 5 );
+				const rangeBefore = new Range( Position._createAt( p1, 1 ), Position._createAt( p1, 2 ) );
+				const rangeAfter = new Range( Position._createAt( p1, 4 ), Position._createAt( p1, 5 ) );
 
 				expectChanges( [
 					{
@@ -248,7 +248,7 @@ describe( 'Differ', () => {
 
 		it( 'nodes after nodes with changed attributes', () => {
 			const p1 = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( p1, 1, p1, 3 );
+			const range = new Range( Position._createAt( p1, 1 ), Position._createAt( p1, 3 ) );
 			const position = new Position( root, [ 0, 3 ] );
 
 			model.change( () => {
@@ -440,13 +440,13 @@ describe( 'Differ', () => {
 			const position = new Position( root, [ 0, 0 ] );
 
 			const p1 = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( p1, 2, p1, 3 );
+			const range = new Range( Position._createAt( p1, 2 ), Position._createAt( p1, 3 ) );
 
 			model.change( () => {
 				attribute( range, 'bold', null, true );
 				remove( position, 1 );
 
-				const newRange = Range.createFromParentsAndOffsets( p1, 1, p1, 2 );
+				const newRange = new Range( Position._createAt( p1, 1 ), Position._createAt( p1, 2 ) );
 
 				expectChanges( [
 					{ type: 'remove', name: '$text', length: 1, position },
@@ -465,13 +465,13 @@ describe( 'Differ', () => {
 			const position = new Position( root, [ 0, 0 ] );
 
 			const p1 = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( p1, 1, p1, 3 );
+			const range = new Range( Position._createAt( p1, 1 ), Position._createAt( p1, 3 ) );
 
 			model.change( () => {
 				attribute( range, 'bold', null, true );
 				remove( position, 2 );
 
-				const newRange = Range.createFromParentsAndOffsets( p1, 0, p1, 1 );
+				const newRange = new Range( Position._createAt( p1, 0 ), Position._createAt( p1, 1 ) );
 
 				expectChanges( [
 					{ type: 'remove', name: '$text', length: 2, position },
@@ -490,14 +490,14 @@ describe( 'Differ', () => {
 			const position = new Position( root, [ 0, 1 ] );
 
 			const p1 = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( p1, 0, p1, 3 );
+			const range = new Range( Position._createAt( p1, 0 ), Position._createAt( p1, 3 ) );
 
 			model.change( () => {
 				attribute( range, 'bold', null, true );
 				remove( position, 1 );
 
-				const rangeBefore = Range.createFromParentsAndOffsets( p1, 0, p1, 1 );
-				const rangeAfter = Range.createFromParentsAndOffsets( p1, 1, p1, 2 );
+				const rangeBefore = new Range( Position._createAt( p1, 0 ), Position._createAt( p1, 1 ) );
+				const rangeAfter = new Range( Position._createAt( p1, 1 ), Position._createAt( p1, 2 ) );
 
 				expectChanges( [
 					{
@@ -523,13 +523,13 @@ describe( 'Differ', () => {
 			const position = new Position( root, [ 0, 1 ] );
 
 			const p1 = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( p1, 0, p1, 2 );
+			const range = new Range( Position._createAt( p1, 0 ), Position._createAt( p1, 2 ) );
 
 			model.change( () => {
 				attribute( range, 'bold', null, true );
 				remove( position, 2 );
 
-				const newRange = Range.createFromParentsAndOffsets( p1, 0, p1, 1 );
+				const newRange = new Range( Position._createAt( p1, 0 ), Position._createAt( p1, 1 ) );
 
 				expectChanges( [
 					{
@@ -548,7 +548,7 @@ describe( 'Differ', () => {
 			const position = new Position( root, [ 0, 2 ] );
 
 			const p1 = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( p1, 0, p1, 1 );
+			const range = new Range( Position._createAt( p1, 0 ), Position._createAt( p1, 1 ) );
 
 			model.change( () => {
 				attribute( range, 'bold', null, true );
@@ -698,12 +698,12 @@ describe( 'Differ', () => {
 		const attributeNewValue = 'foo';
 
 		it( 'on an element', () => {
-			const range = Range.createFromParentsAndOffsets( root, 0, root, 1 );
+			const range = new Range( Position._createAt( root, 0 ), Position._createAt( root, 1 ) );
 
 			model.change( () => {
 				attribute( range, attributeKey, attributeOldValue, attributeNewValue );
 
-				const diffRange = Range.createFromParentsAndOffsets( root, 0, root.getChild( 0 ), 0 );
+				const diffRange = new Range( Position._createAt( root, 0 ), Position._createAt( root.getChild( 0 ), 0 ) );
 
 				expectChanges( [
 					{ type: 'attribute', range: diffRange, attributeKey, attributeOldValue, attributeNewValue }
@@ -712,7 +712,7 @@ describe( 'Differ', () => {
 		} );
 
 		it( 'on an element - only one of many attributes changes', () => {
-			const range = Range.createFromParentsAndOffsets( root, 0, root, 1 );
+			const range = new Range( Position._createAt( root, 0 ), Position._createAt( root, 1 ) );
 
 			model.change( () => {
 				// Set an attribute on an element. It won't change afterwards.
@@ -722,7 +722,7 @@ describe( 'Differ', () => {
 			model.change( () => {
 				attribute( range, attributeKey, attributeOldValue, attributeNewValue );
 
-				const diffRange = Range.createFromParentsAndOffsets( root, 0, root.getChild( 0 ), 0 );
+				const diffRange = new Range( Position._createAt( root, 0 ), Position._createAt( root.getChild( 0 ), 0 ) );
 
 				expectChanges( [
 					{ type: 'attribute', range: diffRange, attributeKey, attributeOldValue, attributeNewValue }
@@ -732,7 +732,7 @@ describe( 'Differ', () => {
 
 		it( 'on a character', () => {
 			const parent = root.getChild( 1 );
-			const range = Range.createFromParentsAndOffsets( parent, 1, parent, 2 );
+			const range = new Range( Position._createAt( parent, 1 ), Position._createAt( parent, 2 ) );
 
 			model.change( () => {
 				attribute( range, attributeKey, attributeOldValue, attributeNewValue );
@@ -745,7 +745,7 @@ describe( 'Differ', () => {
 
 		it( 'on a character - case with same characters next to each other', () => {
 			const parent = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( parent, 1, parent, 2 );
+			const range = new Range( Position._createAt( parent, 1 ), Position._createAt( parent, 2 ) );
 
 			model.change( () => {
 				attribute( range, attributeKey, attributeOldValue, attributeNewValue );
@@ -758,7 +758,7 @@ describe( 'Differ', () => {
 
 		it( 'on multiple characters', () => {
 			const parent = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( parent, 0, parent, 3 );
+			const range = new Range( Position._createAt( parent, 0 ), Position._createAt( parent, 3 ) );
 
 			model.change( () => {
 				attribute( range, attributeKey, attributeOldValue, attributeNewValue );
@@ -772,14 +772,14 @@ describe( 'Differ', () => {
 		it( 'on multiple consecutive characters in multiple operations', () => {
 			const parent = root.getChild( 0 );
 
-			const range1 = Range.createFromParentsAndOffsets( parent, 1, parent, 2 );
-			const range2 = Range.createFromParentsAndOffsets( parent, 2, parent, 3 );
+			const range1 = new Range( Position._createAt( parent, 1 ), Position._createAt( parent, 2 ) );
+			const range2 = new Range( Position._createAt( parent, 2 ), Position._createAt( parent, 3 ) );
 
 			model.change( () => {
 				attribute( range1, attributeKey, attributeOldValue, attributeNewValue );
 				attribute( range2, attributeKey, attributeOldValue, attributeNewValue );
 
-				const range = Range.createFromParentsAndOffsets( parent, 1, parent, 3 );
+				const range = new Range( Position._createAt( parent, 1 ), Position._createAt( parent, 3 ) );
 
 				expectChanges( [
 					{ type: 'attribute', range, attributeKey, attributeOldValue, attributeNewValue }
@@ -799,7 +799,7 @@ describe( 'Differ', () => {
 
 			model.change( () => {
 				for ( const item of ranges ) {
-					const range = Range.createFromParentsAndOffsets( parent, item[ 0 ], parent, item[ 1 ] );
+					const range = new Range( Position._createAt( parent, item[ 0 ] ), Position._createAt( parent, item[ 1 ] ) );
 
 					attribute( range, item[ 4 ], item[ 2 ], item[ 3 ] );
 				}
@@ -807,14 +807,14 @@ describe( 'Differ', () => {
 				expectChanges( [
 					{
 						type: 'attribute',
-						range: Range.createFromParentsAndOffsets( parent, 0, parent, 2 ),
+						range: new Range( Position._createAt( parent, 0 ), Position._createAt( parent, 2 ) ),
 						attributeKey: 'foo',
 						attributeOldValue: null,
 						attributeNewValue: true
 					},
 					{
 						type: 'attribute',
-						range: Range.createFromParentsAndOffsets( parent, 1, parent, 3 ),
+						range: new Range( Position._createAt( parent, 1 ), Position._createAt( parent, 3 ) ),
 						attributeKey: 'bar',
 						attributeOldValue: null,
 						attributeNewValue: true
@@ -835,7 +835,7 @@ describe( 'Differ', () => {
 
 			model.change( () => {
 				for ( const item of ranges ) {
-					const range = Range.createFromParentsAndOffsets( parent, item[ 0 ], parent, item[ 1 ] );
+					const range = new Range( Position._createAt( parent, item[ 0 ] ), Position._createAt( parent, item[ 1 ] ) );
 
 					attribute( range, item[ 4 ], item[ 2 ], item[ 3 ] );
 				}
@@ -843,28 +843,28 @@ describe( 'Differ', () => {
 				expectChanges( [
 					{
 						type: 'attribute',
-						range: Range.createFromParentsAndOffsets( parent, 0, parent, 1 ),
+						range: new Range( Position._createAt( parent, 0 ), Position._createAt( parent, 1 ) ),
 						attributeKey: 'bar',
 						attributeOldValue: null,
 						attributeNewValue: true
 					},
 					{
 						type: 'attribute',
-						range: Range.createFromParentsAndOffsets( parent, 1, parent, 2 ),
+						range: new Range( Position._createAt( parent, 1 ), Position._createAt( parent, 2 ) ),
 						attributeKey: 'foo',
 						attributeOldValue: null,
 						attributeNewValue: true
 					},
 					{
 						type: 'attribute',
-						range: Range.createFromParentsAndOffsets( parent, 1, parent, 2 ),
+						range: new Range( Position._createAt( parent, 1 ), Position._createAt( parent, 2 ) ),
 						attributeKey: 'bar',
 						attributeOldValue: null,
 						attributeNewValue: true
 					},
 					{
 						type: 'attribute',
-						range: Range.createFromParentsAndOffsets( parent, 2, parent, 3 ),
+						range: new Range( Position._createAt( parent, 2 ), Position._createAt( parent, 3 ) ),
 						attributeKey: 'foo',
 						attributeOldValue: null,
 						attributeNewValue: true
@@ -884,7 +884,7 @@ describe( 'Differ', () => {
 
 			model.change( () => {
 				for ( const item of ranges ) {
-					const range = Range.createFromParentsAndOffsets( parent, item[ 0 ], parent, item[ 1 ] );
+					const range = new Range( Position._createAt( parent, item[ 0 ] ), Position._createAt( parent, item[ 1 ] ) );
 
 					attribute( range, attributeKey, item[ 2 ], item[ 3 ] );
 				}
@@ -906,14 +906,14 @@ describe( 'Differ', () => {
 
 			model.change( () => {
 				for ( const item of ranges ) {
-					const range = Range.createFromParentsAndOffsets( parent, item[ 0 ], parent, item[ 1 ] );
+					const range = new Range( Position._createAt( parent, item[ 0 ] ), Position._createAt( parent, item[ 1 ] ) );
 
 					attribute( range, attributeKey, item[ 2 ], item[ 3 ] );
 				}
 
 				expectChanges( [ {
 					type: 'attribute',
-					range: Range.createFromParentsAndOffsets( parent, 0, parent, 2 ),
+					range: new Range( Position._createAt( parent, 0 ), Position._createAt( parent, 2 ) ),
 					attributeKey,
 					attributeOldValue: null,
 					attributeNewValue: true
@@ -924,8 +924,8 @@ describe( 'Differ', () => {
 		it( 'on multiple non-consecutive characters in multiple operations', () => {
 			const parent = root.getChild( 0 );
 
-			const range1 = Range.createFromParentsAndOffsets( parent, 0, parent, 1 );
-			const range2 = Range.createFromParentsAndOffsets( parent, 2, parent, 3 );
+			const range1 = new Range( Position._createAt( parent, 0 ), Position._createAt( parent, 1 ) );
+			const range2 = new Range( Position._createAt( parent, 2 ), Position._createAt( parent, 3 ) );
 
 			model.change( () => {
 				// Note "reversed" order of ranges. Further range is changed first.
@@ -941,7 +941,7 @@ describe( 'Differ', () => {
 		} );
 
 		it( 'on range containing various nodes', () => {
-			const range = Range.createFromParentsAndOffsets( root, 0, root, 2 );
+			const range = new Range( Position._createAt( root, 0 ), Position._createAt( root, 2 ) );
 
 			model.change( () => {
 				attribute( range, attributeKey, attributeOldValue, attributeNewValue );
@@ -953,14 +953,14 @@ describe( 'Differ', () => {
 				expectChanges( [
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( root, 0, p1, 0 ),
+						range: new Range( Position._createAt( root, 0 ), Position._createAt( p1, 0 ) ),
 						attributeKey,
 						attributeOldValue,
 						attributeNewValue
 					},
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( root, 1, p2, 0 ),
+						range: new Range( Position._createAt( root, 1 ), Position._createAt( p2, 0 ) ),
 						attributeKey,
 						attributeOldValue,
 						attributeNewValue
@@ -974,14 +974,14 @@ describe( 'Differ', () => {
 
 			p.getChild( 0 )._setAttribute( 'bold', true );
 
-			const range = Range.createFromParentsAndOffsets( p, 1, p, 3 );
+			const range = new Range( Position._createAt( p, 1 ), Position._createAt( p, 3 ) );
 
 			model.change( () => {
 				attribute( range, 'bold', true, null );
 				attribute( range, 'italic', null, true );
 
-				const range1 = Range.createFromParentsAndOffsets( p, 1, p, 2 );
-				const range2 = Range.createFromParentsAndOffsets( p, 2, p, 3 );
+				const range1 = new Range( Position._createAt( p, 1 ), Position._createAt( p, 2 ) );
+				const range2 = new Range( Position._createAt( p, 2 ), Position._createAt( p, 3 ) );
 
 				// Attribute change glueing does not work 100% correct.
 				expectChanges( [
@@ -1021,13 +1021,13 @@ describe( 'Differ', () => {
 			const position = new Position( root, [ 0, 1 ] );
 
 			const p1 = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( p1, 0, p1, 2 );
+			const range = new Range( Position._createAt( p1, 0 ), Position._createAt( p1, 2 ) );
 
 			model.change( () => {
 				insert( new Text( 'xx' ), position );
 				attribute( range, attributeKey, attributeOldValue, attributeNewValue );
 
-				const rangeBefore = Range.createFromParentsAndOffsets( p1, 0, p1, 1 );
+				const rangeBefore = new Range( Position._createAt( p1, 0 ), Position._createAt( p1, 1 ) );
 
 				expectChanges( [
 					{ type: 'attribute', range: rangeBefore, attributeKey, attributeOldValue, attributeNewValue },
@@ -1040,7 +1040,7 @@ describe( 'Differ', () => {
 			const position = new Position( root, [ 0, 1 ] );
 
 			const p1 = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( p1, 2, p1, 3 );
+			const range = new Range( Position._createAt( p1, 2 ), Position._createAt( p1, 3 ) );
 
 			model.change( () => {
 				insert( new Text( 'xxx' ), position );
@@ -1056,13 +1056,13 @@ describe( 'Differ', () => {
 			const position = new Position( root, [ 0, 1 ] );
 
 			const p1 = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( p1, 2, p1, 4 );
+			const range = new Range( Position._createAt( p1, 2 ), Position._createAt( p1, 4 ) );
 
 			model.change( () => {
 				insert( new Text( 'xx' ), position );
 				attribute( range, attributeKey, attributeOldValue, attributeNewValue );
 
-				const rangeAfter = Range.createFromParentsAndOffsets( p1, 3, p1, 4 );
+				const rangeAfter = new Range( Position._createAt( p1, 3 ), Position._createAt( p1, 4 ) );
 
 				expectChanges( [
 					{ type: 'insert', name: '$text', length: 2, position },
@@ -1075,14 +1075,14 @@ describe( 'Differ', () => {
 			const position = new Position( root, [ 0, 1 ] );
 
 			const p1 = root.getChild( 0 );
-			const range = Range.createFromParentsAndOffsets( p1, 0, p1, 4 );
+			const range = new Range( Position._createAt( p1, 0 ), Position._createAt( p1, 4 ) );
 
 			model.change( () => {
 				insert( new Text( 'xx' ), position );
 				attribute( range, attributeKey, attributeOldValue, attributeNewValue );
 
-				const rangeBefore = Range.createFromParentsAndOffsets( p1, 0, p1, 1 );
-				const rangeAfter = Range.createFromParentsAndOffsets( p1, 3, p1, 4 );
+				const rangeBefore = new Range( Position._createAt( p1, 0 ), Position._createAt( p1, 1 ) );
+				const rangeAfter = new Range( Position._createAt( p1, 3 ), Position._createAt( p1, 4 ) );
 
 				expectChanges( [
 					{ type: 'attribute', range: rangeBefore, attributeKey, attributeOldValue, attributeNewValue },
@@ -1095,8 +1095,8 @@ describe( 'Differ', () => {
 		it( 'on some not changed and some changed nodes', () => {
 			const p = root.getChild( 0 );
 
-			const rangeA = Range.createFromParentsAndOffsets( p, 1, p, 3 );
-			const rangeB = Range.createFromParentsAndOffsets( p, 0, p, 2 );
+			const rangeA = new Range( Position._createAt( p, 1 ), Position._createAt( p, 3 ) );
+			const rangeB = new Range( Position._createAt( p, 0 ), Position._createAt( p, 2 ) );
 
 			model.change( () => {
 				attribute( rangeA, 'a', null, true );
@@ -1110,28 +1110,28 @@ describe( 'Differ', () => {
 				expectChanges( [
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( p, 0, p, 1 ),
+						range: new Range( Position._createAt( p, 0 ), Position._createAt( p, 1 ) ),
 						attributeKey: 'b',
 						attributeOldValue,
 						attributeNewValue
 					},
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( p, 1, p, 2 ),
+						range: new Range( Position._createAt( p, 1 ), Position._createAt( p, 2 ) ),
 						attributeKey: 'a',
 						attributeOldValue,
 						attributeNewValue
 					},
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( p, 1, p, 2 ),
+						range: new Range( Position._createAt( p, 1 ), Position._createAt( p, 2 ) ),
 						attributeKey: 'b',
 						attributeOldValue,
 						attributeNewValue
 					},
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( p, 2, p, 3 ),
+						range: new Range( Position._createAt( p, 2 ), Position._createAt( p, 3 ) ),
 						attributeKey: 'a',
 						attributeOldValue,
 						attributeNewValue
@@ -1143,8 +1143,8 @@ describe( 'Differ', () => {
 		it( 'on already changed nodes', () => {
 			const p = root.getChild( 1 );
 
-			const rangeA = Range.createFromParentsAndOffsets( p, 0, p, 3 );
-			const rangeB = Range.createFromParentsAndOffsets( p, 1, p, 2 );
+			const rangeA = new Range( Position._createAt( p, 0 ), Position._createAt( p, 3 ) );
+			const rangeB = new Range( Position._createAt( p, 1 ), Position._createAt( p, 2 ) );
 
 			model.change( () => {
 				attribute( rangeA, 'a', null, true );
@@ -1158,21 +1158,21 @@ describe( 'Differ', () => {
 				expectChanges( [
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( p, 0, p, 2 ),
+						range: new Range( Position._createAt( p, 0 ), Position._createAt( p, 2 ) ),
 						attributeKey: 'a',
 						attributeOldValue,
 						attributeNewValue
 					},
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( p, 1, p, 2 ),
+						range: new Range( Position._createAt( p, 1 ), Position._createAt( p, 2 ) ),
 						attributeKey: 'b',
 						attributeOldValue,
 						attributeNewValue
 					},
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( p, 2, p, 3 ),
+						range: new Range( Position._createAt( p, 2 ), Position._createAt( p, 3 ) ),
 						attributeKey: 'a',
 						attributeOldValue,
 						attributeNewValue
@@ -1184,8 +1184,8 @@ describe( 'Differ', () => {
 		it( 'on some changed and some not changed nodes', () => {
 			const p = root.getChild( 1 );
 
-			const rangeA = Range.createFromParentsAndOffsets( p, 0, p, 2 );
-			const rangeB = Range.createFromParentsAndOffsets( p, 1, p, 3 );
+			const rangeA = new Range( Position._createAt( p, 0 ), Position._createAt( p, 2 ) );
+			const rangeB = new Range( Position._createAt( p, 1 ), Position._createAt( p, 3 ) );
 
 			model.change( () => {
 				attribute( rangeA, 'a', null, true );
@@ -1198,14 +1198,14 @@ describe( 'Differ', () => {
 				expectChanges( [
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( p, 0, p, 2 ),
+						range: new Range( Position._createAt( p, 0 ), Position._createAt( p, 2 ) ),
 						attributeKey: 'a',
 						attributeOldValue,
 						attributeNewValue
 					},
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( p, 1, p, 3 ),
+						range: new Range( Position._createAt( p, 1 ), Position._createAt( p, 3 ) ),
 						attributeKey: 'b',
 						attributeOldValue,
 						attributeNewValue
@@ -1217,8 +1217,8 @@ describe( 'Differ', () => {
 		it( 'over all changed nodes and some not changed nodes', () => {
 			const p = root.getChild( 0 );
 
-			const rangeA = Range.createFromParentsAndOffsets( p, 1, p, 2 );
-			const rangeB = Range.createFromParentsAndOffsets( p, 0, p, 3 );
+			const rangeA = new Range( Position._createAt( p, 1 ), Position._createAt( p, 2 ) );
+			const rangeB = new Range( Position._createAt( p, 0 ), Position._createAt( p, 3 ) );
 
 			model.change( () => {
 				attribute( rangeA, 'a', null, true );
@@ -1232,21 +1232,21 @@ describe( 'Differ', () => {
 				expectChanges( [
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( p, 0, p, 1 ),
+						range: new Range( Position._createAt( p, 0 ), Position._createAt( p, 1 ) ),
 						attributeKey: 'b',
 						attributeOldValue,
 						attributeNewValue
 					},
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( p, 1, p, 2 ),
+						range: new Range( Position._createAt( p, 1 ), Position._createAt( p, 2 ) ),
 						attributeKey: 'a',
 						attributeOldValue,
 						attributeNewValue
 					},
 					{
 						type,
-						range: Range.createFromParentsAndOffsets( p, 1, p, 3 ),
+						range: new Range( Position._createAt( p, 1 ), Position._createAt( p, 3 ) ),
 						attributeKey: 'b',
 						attributeOldValue,
 						attributeNewValue
@@ -1391,8 +1391,8 @@ describe( 'Differ', () => {
 		let range, rangeB;
 
 		beforeEach( () => {
-			range = Range.createFromParentsAndOffsets( root, 0, root, 1 );
-			rangeB = Range.createFromParentsAndOffsets( root, 1, root, 2 );
+			range = new Range( Position._createAt( root, 0 ), Position._createAt( root, 1 ) );
+			rangeB = new Range( Position._createAt( root, 1 ), Position._createAt( root, 2 ) );
 		} );
 
 		it( 'add marker', () => {
@@ -1603,10 +1603,10 @@ describe( 'Differ', () => {
 		it( 'remove is correctly transformed by multiple affecting changes', () => {
 			root._appendChild( new Element( 'paragraph', null, new Text( 'xyz' ) ) );
 
-			model.change( () => {
+			model.change( writer => {
 				rename( root.getChild( 1 ), 'heading' );
 				rename( root.getChild( 2 ), 'heading' );
-				remove( Position.createAt( root, 0 ), 3 );
+				remove( writer.createPositionAt( root, 0 ), 3 );
 
 				expectChanges( [
 					{ type: 'remove', name: 'paragraph', length: 1, position: new Position( root, [ 0 ] ) },
@@ -1624,8 +1624,8 @@ describe( 'Differ', () => {
 			position = new Position( root, [ 0, 1 ] );
 			p1 = root.getChild( 0 );
 
-			range = Range.createFromParentsAndOffsets( p1, 2, p1, 4 );
-			rangeAttrChange = Range.createFromParentsAndOffsets( p1, 3, p1, 4 );
+			range = new Range( Position._createAt( p1, 2 ), Position._createAt( p1, 4 ) );
+			rangeAttrChange = new Range( Position._createAt( p1, 3 ), Position._createAt( p1, 4 ) );
 		} );
 
 		it( 'should return changes in graveyard if a flag was set up', () => {
@@ -1762,7 +1762,7 @@ describe( 'Differ', () => {
 	}
 
 	function remove( sourcePosition, howMany ) {
-		const targetPosition = Position.createAt( doc.graveyard, doc.graveyard.maxOffset );
+		const targetPosition = Position._createAt( doc.graveyard, doc.graveyard.maxOffset );
 		const operation = new MoveOperation( sourcePosition, howMany, targetPosition, doc.version );
 
 		model.applyOperation( operation );
@@ -1775,7 +1775,7 @@ describe( 'Differ', () => {
 	}
 
 	function rename( element, newName ) {
-		const operation = new RenameOperation( Position.createBefore( element ), element.name, newName, doc.version );
+		const operation = new RenameOperation( Position._createBefore( element ), element.name, newName, doc.version );
 
 		model.applyOperation( operation );
 	}

+ 8 - 9
packages/ckeditor5-engine/tests/model/document.js

@@ -8,7 +8,6 @@ import Document from '../../src/model/document';
 import RootElement from '../../src/model/rootelement';
 import Text from '../../src/model/text';
 import Batch from '../../src/model/batch';
-import Range from '../../src/model/range';
 import Collection from '@ckeditor/ckeditor5-utils/src/collection';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import count from '@ckeditor/ckeditor5-utils/src/count';
@@ -228,7 +227,7 @@ describe( 'Document', () => {
 			sinon.spy( doc.differ, 'bufferMarkerChange' );
 
 			model.change( writer => {
-				const range = Range.createCollapsedAt( doc.getRoot(), 0 );
+				const range = writer.createRange( writer.createPositionAt( doc.getRoot(), 0 ) );
 				writer.addMarker( 'marker', { range, usingOperation: false } );
 			} );
 
@@ -324,7 +323,7 @@ describe( 'Document', () => {
 			doc.on( 'change', spy );
 
 			model.change( writer => {
-				writer.setSelection( Range.createFromParentsAndOffsets( root, 2, root, 2 ) );
+				writer.setSelection( root, 2 );
 			} );
 
 			sinon.assert.calledOnce( spy );
@@ -373,7 +372,7 @@ describe( 'Document', () => {
 			doc.on( 'change:data', spy );
 
 			model.change( writer => {
-				writer.setSelection( Range.createFromParentsAndOffsets( root, 2, root, 2 ) );
+				writer.setSelection( root, 2 );
 			} );
 
 			sinon.assert.notCalled( spy );
@@ -388,7 +387,7 @@ describe( 'Document', () => {
 			doc.on( 'change:data', spy );
 
 			model.change( writer => {
-				const range = Range.createFromParentsAndOffsets( root, 2, root, 4 );
+				const range = writer.createRange( writer.createPositionAt( root, 2 ), writer.createPositionAt( root, 4 ) );
 				writer.addMarker( 'name', { range, usingOperation: true, affectsData: true } );
 			} );
 
@@ -404,7 +403,7 @@ describe( 'Document', () => {
 			doc.on( 'change:data', spy );
 
 			model.change( writer => {
-				const range = Range.createFromParentsAndOffsets( root, 2, root, 4 );
+				const range = writer.createRange( writer.createPositionAt( root, 2 ), writer.createPositionAt( root, 4 ) );
 				writer.addMarker( 'name', { range, usingOperation: true } );
 			} );
 
@@ -420,7 +419,7 @@ describe( 'Document', () => {
 			doc.on( 'change:data', spy );
 
 			model.change( writer => {
-				const range = Range.createFromParentsAndOffsets( root, 2, root, 4 );
+				const range = writer.createRange( writer.createPositionAt( root, 2 ), writer.createPositionAt( root, 4 ) );
 				writer.addMarker( 'name', { range, usingOperation: false, affectsData: true } );
 			} );
 
@@ -436,7 +435,7 @@ describe( 'Document', () => {
 			doc.on( 'change:data', spy );
 
 			model.change( writer => {
-				const range = Range.createFromParentsAndOffsets( root, 2, root, 4 );
+				const range = writer.createRange( writer.createPositionAt( root, 2 ), writer.createPositionAt( root, 4 ) );
 				writer.addMarker( 'name', { range, usingOperation: false } );
 			} );
 
@@ -471,7 +470,7 @@ describe( 'Document', () => {
 			doc.on( 'change', changeSpy );
 
 			model.change( writer => {
-				const range = Range.createFromParentsAndOffsets( root, 2, root, 4 );
+				const range = writer.createRange( writer.createPositionAt( root, 2 ), writer.createPositionAt( root, 4 ) );
 				writer.addMarker( 'name', { range, usingOperation: false } );
 			} );
 

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

@@ -257,7 +257,7 @@ describe( 'DocumentSelection', () => {
 	describe( '_setFocus()', () => {
 		it( 'modifies default range', () => {
 			const startPos = selection.getFirstPosition();
-			const endPos = Position.createAt( root, 'end' );
+			const endPos = Position._createAt( root, 'end' );
 
 			selection._setFocus( endPos );
 
@@ -266,9 +266,9 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'detaches the range it replaces', () => {
-			const startPos = Position.createAt( root, 1 );
-			const endPos = Position.createAt( root, 2 );
-			const newEndPos = Position.createAt( root, 4 );
+			const startPos = Position._createAt( root, 1 );
+			const endPos = Position._createAt( root, 2 );
+			const newEndPos = Position._createAt( root, 4 );
 			const spy = testUtils.sinon.spy( LiveRange.prototype, 'detach' );
 
 			selection._setTo( new Range( startPos, endPos ) );
@@ -281,7 +281,7 @@ describe( 'DocumentSelection', () => {
 		it( 'refreshes attributes', () => {
 			const spy = sinon.spy( selection._selection, '_updateAttributes' );
 
-			selection._setFocus( Position.createAt( root, 1 ) );
+			selection._setFocus( Position._createAt( root, 1 ) );
 
 			expect( spy.called ).to.be.true;
 		} );
@@ -379,7 +379,7 @@ describe( 'DocumentSelection', () => {
 
 			setData( model, 'f<$text italic="true">[o</$text><$text bold="true">ob]a</$text>r' );
 
-			selection._setTo( [ Range.createFromPositionAndShift( selection.getLastRange().end, 0 ) ] );
+			selection._setTo( [ Range._createFromPositionAndShift( selection.getLastRange().end, 0 ) ] );
 
 			expect( selection.getAttribute( 'bold' ) ).to.equal( true );
 			expect( selection.hasAttribute( 'italic' ) ).to.equal( false );
@@ -447,7 +447,7 @@ describe( 'DocumentSelection', () => {
 
 				// Trigger selecton auto update on document change. It should not get attribute from surrounding text;
 				model.change( writer => {
-					writer.setAttribute( 'foo', 'bar', Range.createIn( fullP ) );
+					writer.setAttribute( 'foo', 'bar', Range._createIn( fullP ) );
 				} );
 
 				expect( selection.getAttribute( 'foo' ) ).to.be.undefined;
@@ -656,7 +656,7 @@ describe( 'DocumentSelection', () => {
 				selection._setAttribute( 'foo', 'bar' );
 
 				model.change( writer => {
-					writer.move( Range.createOn( fullP.getChild( 0 ) ), rangeInEmptyP.start );
+					writer.move( writer.createRangeOn( fullP.getChild( 0 ) ), rangeInEmptyP.start );
 				} );
 
 				expect( emptyP.hasAttribute( fooStoreAttrKey ) ).to.be.false;
@@ -671,7 +671,7 @@ describe( 'DocumentSelection', () => {
 
 				model.change( writer => {
 					// <emptyP>{}<emptyP2>
-					writer.merge( Position.createAfter( emptyP ) );
+					writer.merge( writer.createPositionAfter( emptyP ) );
 				} );
 
 				expect( emptyP.hasAttribute( fooStoreAttrKey ) ).to.be.false;
@@ -717,7 +717,7 @@ describe( 'DocumentSelection', () => {
 
 				model.change( writer => {
 					// <emptyP>{}<emptyP2>
-					writer.merge( Position.createAfter( emptyP ) );
+					writer.merge( writer.createPositionAfter( emptyP ) );
 				} );
 
 				expect( emptyP.getAttribute( fooStoreAttrKey ) ).to.equal( 'bar' );
@@ -1210,8 +1210,8 @@ describe( 'DocumentSelection', () => {
 			] );
 
 			selection._setTo( [
-				Range.createIn( root.getNodeByPath( [ 0 ] ) ),
-				Range.createIn( root.getNodeByPath( [ 1 ] ) )
+				Range._createIn( root.getNodeByPath( [ 0 ] ) ),
+				Range._createIn( root.getNodeByPath( [ 1 ] ) )
 			] );
 
 			spyRange = sinon.spy();
@@ -1234,11 +1234,11 @@ describe( 'DocumentSelection', () => {
 		root._appendChild( '\uD83D\uDCA9' );
 
 		expect( () => {
-			doc.selection._setTo( Range.createFromParentsAndOffsets( root, 0, root, 1 ) );
+			doc.selection._setTo( new Range( Position._createAt( root, 0 ), Position._createAt( root, 1 ) ) );
 		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
 
 		expect( () => {
-			doc.selection._setTo( Range.createFromParentsAndOffsets( root, 1, root, 2 ) );
+			doc.selection._setTo( new Range( Position._createAt( root, 1 ), Position._createAt( root, 2 ) ) );
 		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
 	} );
 
@@ -1247,27 +1247,27 @@ describe( 'DocumentSelection', () => {
 		root._appendChild( 'foo̻̐ͩbar' );
 
 		expect( () => {
-			doc.selection._setTo( Range.createFromParentsAndOffsets( root, 3, root, 9 ) );
+			doc.selection._setTo( new Range( Position._createAt( root, 3 ), Position._createAt( root, 9 ) ) );
 		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
 
 		expect( () => {
-			doc.selection._setTo( Range.createFromParentsAndOffsets( root, 4, root, 9 ) );
+			doc.selection._setTo( new Range( Position._createAt( root, 4 ), Position._createAt( root, 9 ) ) );
 		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
 
 		expect( () => {
-			doc.selection._setTo( Range.createFromParentsAndOffsets( root, 5, root, 9 ) );
+			doc.selection._setTo( new Range( Position._createAt( root, 5 ), Position._createAt( root, 9 ) ) );
 		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
 
 		expect( () => {
-			doc.selection._setTo( Range.createFromParentsAndOffsets( root, 1, root, 3 ) );
+			doc.selection._setTo( new Range( Position._createAt( root, 1 ), Position._createAt( root, 3 ) ) );
 		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
 
 		expect( () => {
-			doc.selection._setTo( Range.createFromParentsAndOffsets( root, 1, root, 4 ) );
+			doc.selection._setTo( new Range( Position._createAt( root, 1 ), Position._createAt( root, 4 ) ) );
 		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
 
 		expect( () => {
-			doc.selection._setTo( Range.createFromParentsAndOffsets( root, 1, root, 5 ) );
+			doc.selection._setTo( new Range( Position._createAt( root, 1 ), Position._createAt( root, 5 ) ) );
 		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
 	} );
 } );

+ 25 - 28
packages/ckeditor5-engine/tests/model/liveposition.js

@@ -12,7 +12,8 @@ import LivePosition from '../../src/model/liveposition';
 import Range from '../../src/model/range';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 
-describe( 'LivePosition', () => {
+describe( 'LivePosition', () =>
+{
 	let model, doc, root, ul, p, li1, li2;
 
 	beforeEach( () => {
@@ -68,26 +69,22 @@ describe( 'LivePosition', () => {
 		LivePosition.prototype.stopListening.restore();
 	} );
 
-	it( 'createFromPosition should return LivePosition', () => {
-		const position = LivePosition.createFromPosition( new Position( root, [ 0 ] ) );
-		expect( position ).to.be.instanceof( LivePosition );
-		position.detach();
-	} );
-
-	it( 'createFromParentAndOffset should return LivePosition', () => {
-		const position = LivePosition.createFromParentAndOffset( ul, 0 );
-		expect( position ).to.be.instanceof( LivePosition );
-		position.detach();
+	describe( 'fromPosition()', () => {
+		it( 'should return LivePosition', () => {
+			const position = LivePosition.fromPosition( new Position( root, [ 0 ] ) );
+			expect( position ).to.be.instanceof( LivePosition );
+			position.detach();
+		} );
 	} );
 
-	it( 'createBefore should return LivePosition', () => {
-		const position = LivePosition.createBefore( ul );
+	it( '_createBefore should return LivePosition', () => {
+		const position = LivePosition._createBefore( ul );
 		expect( position ).to.be.instanceof( LivePosition );
 		position.detach();
 	} );
 
-	it( 'createAfter should return LivePosition', () => {
-		const position = LivePosition.createAfter( ul );
+	it( '_createAfter should return LivePosition', () => {
+		const position = LivePosition._createAfter( ul );
 		expect( position ).to.be.instanceof( LivePosition );
 		position.detach();
 	} );
@@ -140,7 +137,7 @@ describe( 'LivePosition', () => {
 			it( 'is at the same parent and closer offset', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 1, 0, 1 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 3 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 3 );
 					const targetPosition = new Position( root, [ 1, 1, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -154,7 +151,7 @@ describe( 'LivePosition', () => {
 				live.stickiness = 'toNext';
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 1, 0, 1 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 3 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 3 );
 					const targetPosition = new Position( root, [ 1, 1, 3 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -167,7 +164,7 @@ describe( 'LivePosition', () => {
 			it( 'is at a position before a node from the live position path', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 1, 0, 1 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 2 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 2 );
 					const targetPosition = new Position( root, [ 1, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -180,7 +177,7 @@ describe( 'LivePosition', () => {
 			it( 'is from the same parent and closer offset', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 1, 1, 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 2 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 2 );
 					const targetPosition = new Position( root, [ 1, 0, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -193,7 +190,7 @@ describe( 'LivePosition', () => {
 			it( 'is from a position before a node from the live position path', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 1, 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 1 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 1 );
 					const targetPosition = new Position( root, [ 1, 2 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -206,7 +203,7 @@ describe( 'LivePosition', () => {
 			it( 'contains live position (same level)', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 1, 1, 2 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 2 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 2 );
 					const targetPosition = new Position( root, [ 1, 0, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -219,7 +216,7 @@ describe( 'LivePosition', () => {
 			it( 'contains live position (deep)', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 1, 1 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 1 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 1 );
 					const targetPosition = new Position( root, [ 1, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -295,7 +292,7 @@ describe( 'LivePosition', () => {
 			it( 'is at the same parent and further offset', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 1, 0, 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 3 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 3 );
 					const targetPosition = new Position( root, [ 1, 1, 6 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -312,7 +309,7 @@ describe( 'LivePosition', () => {
 
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 1, 0, 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 3 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 3 );
 					const targetPosition = new Position( root, [ 1, 1, 3 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -327,7 +324,7 @@ describe( 'LivePosition', () => {
 			it( 'is at a position after a node from the live position path', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 1, 0, 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 3 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 3 );
 					const targetPosition = new Position( root, [ 2 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -340,7 +337,7 @@ describe( 'LivePosition', () => {
 			it( 'is from the same parent and further offset', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 1, 1, 4 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 2 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 2 );
 					const targetPosition = new Position( otherRoot, [ 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -357,7 +354,7 @@ describe( 'LivePosition', () => {
 
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 1, 1 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 1 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 1 );
 					const targetPosition = new Position( otherRoot, [ 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -374,7 +371,7 @@ describe( 'LivePosition', () => {
 					writer.insertText( 'foo', new Position( otherRoot, [ 0 ] ) );
 
 					const sourcePosition = new Position( otherRoot, [ 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 1 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 1 );
 					const targetPosition = new Position( otherRoot, [ 3 ] );
 
 					writer.move( sourceRange, targetPosition );

+ 34 - 46
packages/ckeditor5-engine/tests/model/liverange.js

@@ -67,33 +67,21 @@ describe( 'LiveRange', () => {
 		LiveRange.prototype.stopListening.restore();
 	} );
 
-	it( 'createIn should return LiveRange', () => {
-		const range = LiveRange.createIn( p );
+	it( '_createIn should return LiveRange', () => {
+		const range = LiveRange._createIn( p );
 		expect( range ).to.be.instanceof( LiveRange );
 		range.detach();
 	} );
 
-	it( 'createFromParentsAndOffsets should return LiveRange', () => {
-		const range = LiveRange.createFromParentsAndOffsets( root, 0, p, 2 );
-		expect( range ).to.be.instanceof( LiveRange );
-		range.detach();
-	} );
-
-	it( 'createFromPositionAndShift should return LiveRange', () => {
-		const range = LiveRange.createFromPositionAndShift( new Position( root, [ 0, 1 ] ), 4 );
-		expect( range ).to.be.instanceof( LiveRange );
-		range.detach();
-	} );
-
-	it( 'createFromRange should return LiveRange', () => {
-		const range = LiveRange.createFromRange( new Range( new Position( root, [ 0 ] ), new Position( root, [ 1 ] ) ) );
+	it( '_createFromPositionAndShift should return LiveRange', () => {
+		const range = LiveRange._createFromPositionAndShift( new Position( root, [ 0, 1 ] ), 4 );
 		expect( range ).to.be.instanceof( LiveRange );
 		range.detach();
 	} );
 
 	it( 'should fire change:range event with when its boundaries are changed', () => {
 		const live = new LiveRange( new Position( root, [ 0, 1, 4 ] ), new Position( root, [ 0, 2, 2 ] ) );
-		const copy = Range.createFromRange( live );
+		const copy = live.toRange();
 
 		const spy = sinon.spy();
 		live.on( 'change:range', spy );
@@ -102,7 +90,7 @@ describe( 'LiveRange', () => {
 		const targetPosition = new Position( root, [ 0 ] );
 
 		model.change( writer => {
-			const sourceRange = Range.createFromPositionAndShift( sourcePosition, 1 );
+			const sourceRange = Range._createFromPositionAndShift( sourcePosition, 1 );
 
 			writer.move( sourceRange, targetPosition );
 		} );
@@ -126,7 +114,7 @@ describe( 'LiveRange', () => {
 		const targetPosition = new Position( root, [ 0, 4, 0 ] );
 
 		model.change( writer => {
-			const sourceRange = Range.createFromPositionAndShift( sourcePosition, 2 );
+			const sourceRange = Range._createFromPositionAndShift( sourcePosition, 2 );
 
 			writer.move( sourceRange, targetPosition );
 		} );
@@ -149,7 +137,7 @@ describe( 'LiveRange', () => {
 		const sourcePosition = new Position( root, [ 0, 0 ] );
 
 		model.change( writer => {
-			writer.remove( Range.createFromPositionAndShift( sourcePosition, 6 ) );
+			writer.remove( Range._createFromPositionAndShift( sourcePosition, 6 ) );
 		} );
 
 		// Second parameter is deletion position.
@@ -267,7 +255,7 @@ describe( 'LiveRange', () => {
 			it( 'is to the same parent as range start and before it', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 4, 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 4 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 4 );
 					const targetPosition = new Position( root, [ 0, 1, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -281,7 +269,7 @@ describe( 'LiveRange', () => {
 			it( 'is to the same parent as range end and before it', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 4, 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 4 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 4 );
 					const targetPosition = new Position( root, [ 0, 2, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -295,7 +283,7 @@ describe( 'LiveRange', () => {
 			it( 'is to a position before a node from range start path', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 4 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 2 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 2 );
 					const targetPosition = new Position( root, [ 0, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -309,7 +297,7 @@ describe( 'LiveRange', () => {
 			it( 'is to a position before a node from range end path', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 4 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 1 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 1 );
 					const targetPosition = new Position( root, [ 0, 2 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -323,7 +311,7 @@ describe( 'LiveRange', () => {
 			it( 'is from the same parent as range start and before it', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 1, 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 3 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 3 );
 					const targetPosition = new Position( root, [ 0, 4, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -337,7 +325,7 @@ describe( 'LiveRange', () => {
 			it( 'is from the same parent as range end and before it - #1', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 2, 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 1 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 1 );
 					const targetPosition = new Position( root, [ 0, 4, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -351,7 +339,7 @@ describe( 'LiveRange', () => {
 			it( 'is from the same parent as range end and before it - #2', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 2, 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 2 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 2 );
 					const targetPosition = new Position( root, [ 0, 4, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -365,7 +353,7 @@ describe( 'LiveRange', () => {
 			it( 'is from a position before a node from range start path', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 1 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 1 );
 					const targetPosition = new Position( root, [ 0, 4 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -379,7 +367,7 @@ describe( 'LiveRange', () => {
 			it( 'intersects on live range left side', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 1, 2 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 4 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 4 );
 					const targetPosition = new Position( root, [ 0, 4, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -393,7 +381,7 @@ describe( 'LiveRange', () => {
 			it( 'intersects on live range right side', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 2, 1 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 4 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 4 );
 					const targetPosition = new Position( root, [ 0, 4, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -409,7 +397,7 @@ describe( 'LiveRange', () => {
 
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 1, 4 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 3 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 3 );
 					const targetPosition = new Position( root, [ 0, 4, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -425,7 +413,7 @@ describe( 'LiveRange', () => {
 
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 1, 3 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 5 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 5 );
 					const targetPosition = new Position( root, [ 0, 4, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -441,7 +429,7 @@ describe( 'LiveRange', () => {
 
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 1, 2 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 3 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 3 );
 					const targetPosition = new Position( root, [ 0, 1, 8 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -455,7 +443,7 @@ describe( 'LiveRange', () => {
 			it( 'is intersecting with live range on right and is moved into live range', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 2, 1 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 5 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 5 );
 					const targetPosition = new Position( root, [ 0, 2, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -663,7 +651,7 @@ describe( 'LiveRange', () => {
 
 		beforeEach( () => {
 			live = new LiveRange( new Position( root, [ 0, 1, 4 ] ), new Position( root, [ 0, 2, 2 ] ) );
-			clone = Range.createFromRange( live );
+			clone = live.toRange();
 
 			spy = sinon.spy();
 			live.on( 'change:content', spy );
@@ -688,7 +676,7 @@ describe( 'LiveRange', () => {
 			it( 'inside the range', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 4, 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 3 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 3 );
 					const targetPosition = new Position( root, [ 0, 1, 5 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -701,7 +689,7 @@ describe( 'LiveRange', () => {
 			it( 'from the range', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 1, 5 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 2 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 2 );
 					const targetPosition = new Position( root, [ 0, 4, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -714,7 +702,7 @@ describe( 'LiveRange', () => {
 			it( 'from the beginning of range', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 1, 4 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 2 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 2 );
 					const targetPosition = new Position( root, [ 0, 4, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -729,7 +717,7 @@ describe( 'LiveRange', () => {
 
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 1, 5 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 1 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 1 );
 					const targetPosition = new Position( root, [ 0, 1, 7 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -748,7 +736,7 @@ describe( 'LiveRange', () => {
 		beforeEach( () => {
 			otherRoot = doc.createRoot( '$root', 'otherRoot' );
 			live = new LiveRange( new Position( root, [ 0, 1, 4 ] ), new Position( root, [ 0, 2, 2 ] ) );
-			clone = Range.createFromRange( live );
+			clone = live.toRange();
 
 			spy = sinon.spy();
 			live.on( 'change', spy );
@@ -791,7 +779,7 @@ describe( 'LiveRange', () => {
 			it( 'is to the same parent as range end and after it', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 4, 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 3 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 3 );
 					const targetPosition = new Position( root, [ 0, 2, 4 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -804,7 +792,7 @@ describe( 'LiveRange', () => {
 			it( 'is to a position after a node from range end path', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 5 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 1 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 1 );
 					const targetPosition = new Position( root, [ 0, 4 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -817,7 +805,7 @@ describe( 'LiveRange', () => {
 			it( 'is from the same parent as range end and after it', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 2, 4 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 3 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 3 );
 					const targetPosition = new Position( root, [ 0, 4, 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -830,7 +818,7 @@ describe( 'LiveRange', () => {
 			it( 'is from a position after a node from range end path', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 4 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 1 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 1 );
 					const targetPosition = new Position( root, [ 0, 5 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -843,7 +831,7 @@ describe( 'LiveRange', () => {
 			it( 'is to different root', () => {
 				model.change( writer => {
 					const sourcePosition = new Position( root, [ 0, 4 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 1 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 1 );
 					const targetPosition = new Position( otherRoot, [ 0 ] );
 
 					writer.move( sourceRange, targetPosition );
@@ -858,7 +846,7 @@ describe( 'LiveRange', () => {
 					writer.insertText( 'foo', new Position( otherRoot, [ 0 ] ) );
 
 					const sourcePosition = new Position( otherRoot, [ 0 ] );
-					const sourceRange = Range.createFromPositionAndShift( sourcePosition, 1 );
+					const sourceRange = Range._createFromPositionAndShift( sourcePosition, 1 );
 					const targetPosition = new Position( root, [ 0, 4 ] );
 
 					writer.move( sourceRange, targetPosition );

+ 12 - 12
packages/ckeditor5-engine/tests/model/markercollection.js

@@ -21,8 +21,8 @@ describe( 'MarkerCollection', () => {
 		markers = new MarkerCollection();
 
 		root = doc.createRoot();
-		range = Range.createFromParentsAndOffsets( root, 0, root, 1 );
-		range2 = Range.createFromParentsAndOffsets( root, 0, root, 2 );
+		range = new Range( Position._createAt( root, 0 ), Position._createAt( root, 1 ) );
+		range2 = new Range( Position._createAt( root, 0 ), Position._createAt( root, 2 ) );
 	} );
 
 	describe( 'iterator', () => {
@@ -212,7 +212,7 @@ describe( 'MarkerCollection', () => {
 			markers._set( 'a', range );
 			const markerB = markers._set( 'b', range2 );
 
-			const result = Array.from( markers.getMarkersAtPosition( Position.createAt( root, 1 ) ) );
+			const result = Array.from( markers.getMarkersAtPosition( Position._createAt( root, 1 ) ) );
 
 			expect( result ).to.deep.equal( [ markerB ] );
 		} );
@@ -250,7 +250,7 @@ describe( 'Marker', () => {
 	it( 'should provide API that returns up-to-date marker range parameters', () => {
 		root._appendChild( new Text( 'foo' ) );
 
-		const range = Range.createFromParentsAndOffsets( root, 1, root, 2 );
+		const range = new Range( Position._createAt( root, 1 ), Position._createAt( root, 2 ) );
 		const marker = model.markers._set( 'name', range );
 
 		expect( marker.getRange().isEqual( range ) ).to.be.true;
@@ -261,7 +261,7 @@ describe( 'Marker', () => {
 			writer.insertText( 'abc', root );
 		} );
 
-		const updatedRange = Range.createFromParentsAndOffsets( root, 4, root, 5 );
+		const updatedRange = new Range( Position._createAt( root, 4 ), Position._createAt( root, 5 ) );
 
 		expect( marker.getRange().isEqual( updatedRange ) ).to.be.true;
 		expect( marker.getStart().isEqual( updatedRange.start ) ).to.be.true;
@@ -269,7 +269,7 @@ describe( 'Marker', () => {
 	} );
 
 	it( 'should throw when using the API if marker was removed from markers collection', () => {
-		const range = Range.createFromParentsAndOffsets( root, 1, root, 2 );
+		const range = new Range( Position._createAt( root, 1 ), Position._createAt( root, 2 ) );
 		const marker = model.markers._set( 'name', range );
 
 		model.markers._remove( 'name' );
@@ -296,7 +296,7 @@ describe( 'Marker', () => {
 	} );
 
 	it( 'should attach live range to marker', () => {
-		const range = Range.createFromParentsAndOffsets( root, 1, root, 2 );
+		const range = new Range( Position._createAt( root, 1 ), Position._createAt( root, 2 ) );
 		const marker = model.markers._set( 'name', range );
 
 		const eventRange = sinon.spy();
@@ -313,7 +313,7 @@ describe( 'Marker', () => {
 	} );
 
 	it( 'should detach live range from marker', () => {
-		const range = Range.createFromParentsAndOffsets( root, 1, root, 2 );
+		const range = new Range( Position._createAt( root, 1 ), Position._createAt( root, 2 ) );
 		const marker = model.markers._set( 'name', range );
 		const liveRange = marker._liveRange;
 
@@ -335,10 +335,10 @@ describe( 'Marker', () => {
 	} );
 
 	it( 'should reattach live range to marker', () => {
-		const range = Range.createFromParentsAndOffsets( root, 1, root, 2 );
+		const range = new Range( Position._createAt( root, 1 ), Position._createAt( root, 2 ) );
 		const marker = model.markers._set( 'name', range );
 		const oldLiveRange = marker._liveRange;
-		const newLiveRange = LiveRange.createFromParentsAndOffsets( root, 0, root, 1 );
+		const newLiveRange = new LiveRange( Position._createAt( root, 0 ), Position._createAt( root, 1 ) );
 
 		const eventRange = sinon.spy();
 		const eventContent = sinon.spy();
@@ -364,7 +364,7 @@ describe( 'Marker', () => {
 	} );
 
 	it( 'should change managedUsingOperations flag', () => {
-		const range = Range.createFromParentsAndOffsets( root, 1, root, 2 );
+		const range = new Range( Position._createAt( root, 1 ), Position._createAt( root, 2 ) );
 		const marker = model.markers._set( 'name', range, false );
 
 		expect( marker.managedUsingOperations ).to.be.false;
@@ -379,7 +379,7 @@ describe( 'Marker', () => {
 	} );
 
 	it( 'should change affectsData flag', () => {
-		const range = Range.createFromParentsAndOffsets( root, 1, root, 2 );
+		const range = new Range( Position._createAt( root, 1 ), Position._createAt( root, 2 ) );
 		const marker = model.markers._set( 'name', range, false, false );
 
 		expect( marker.affectsData ).to.be.false;

+ 76 - 5
packages/ckeditor5-engine/tests/model/model.js

@@ -7,8 +7,10 @@ import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
 import Model from '../../src/model/model';
 import ModelText from '../../src/model/text';
 import ModelRange from '../../src/model/range';
+import ModelPosition from '../../src/model/position';
 import ModelSelection from '../../src/model/selection';
 import ModelDocumentFragment from '../../src/model/documentfragment';
+import Batch from '../../src/model/batch';
 import { getData, setData, stringify } from '../../src/dev-utils/model';
 
 describe( 'Model', () => {
@@ -539,38 +541,107 @@ describe( 'Model', () => {
 		} );
 
 		it( 'should return true if there is a text node in given range', () => {
-			const range = ModelRange.createFromParentsAndOffsets( root, 1, root, 2 );
+			const range = new ModelRange( ModelPosition._createAt( root, 1 ), ModelPosition._createAt( root, 2 ) );
 
 			expect( model.hasContent( range ) ).to.be.true;
 		} );
 
 		it( 'should return true if there is a part of text node in given range', () => {
 			const pFoo = root.getChild( 1 );
-			const range = ModelRange.createFromParentsAndOffsets( pFoo, 1, pFoo, 2 );
+			const range = new ModelRange( ModelPosition._createAt( pFoo, 1 ), ModelPosition._createAt( pFoo, 2 ) );
 
 			expect( model.hasContent( range ) ).to.be.true;
 		} );
 
 		it( 'should return true if there is element that is an object in given range', () => {
 			const divImg = root.getChild( 2 );
-			const range = ModelRange.createFromParentsAndOffsets( divImg, 0, divImg, 1 );
+			const range = new ModelRange( ModelPosition._createAt( divImg, 0 ), ModelPosition._createAt( divImg, 1 ) );
 
 			expect( model.hasContent( range ) ).to.be.true;
 		} );
 
 		it( 'should return false if range is collapsed', () => {
-			const range = ModelRange.createFromParentsAndOffsets( root, 1, root, 1 );
+			const range = new ModelRange( ModelPosition._createAt( root, 1 ), ModelPosition._createAt( root, 1 ) );
 
 			expect( model.hasContent( range ) ).to.be.false;
 		} );
 
 		it( 'should return false if range has only elements that are not objects', () => {
-			const range = ModelRange.createFromParentsAndOffsets( root, 0, root, 1 );
+			const range = new ModelRange( ModelPosition._createAt( root, 0 ), ModelPosition._createAt( root, 1 ) );
 
 			expect( model.hasContent( range ) ).to.be.false;
 		} );
 	} );
 
+	describe( 'createPositionFromPath()', () => {
+		it( 'should return instance of Position', () => {
+			expect( model.createPositionFromPath( model.document.getRoot(), [ 0 ] ) ).to.be.instanceof( ModelPosition );
+		} );
+	} );
+
+	describe( 'createPositionAt()', () => {
+		it( 'should return instance of Position', () => {
+			expect( model.createPositionAt( model.document.getRoot(), 0 ) ).to.be.instanceof( ModelPosition );
+		} );
+	} );
+
+	describe( 'createPositionAfter()', () => {
+		it( 'should return instance of Position', () => {
+			schema.register( 'paragraph', { inheritAllFrom: '$block' } );
+			setData( model, '<paragraph>fo[]ar</paragraph>' );
+
+			expect( model.createPositionAfter( model.document.getRoot().getChild( 0 ) ) ).to.be.instanceof( ModelPosition );
+		} );
+	} );
+
+	describe( 'createPositionBefore()', () => {
+		it( 'should return instance of Position', () => {
+			schema.register( 'paragraph', { inheritAllFrom: '$block' } );
+			setData( model, '<paragraph>fo[]ar</paragraph>' );
+
+			expect( model.createPositionBefore( model.document.getRoot().getChild( 0 ) ) ).to.be.instanceof( ModelPosition );
+		} );
+	} );
+
+	describe( 'createRange()', () => {
+		it( 'should return instance of Range', () => {
+			schema.register( 'paragraph', { inheritAllFrom: '$block' } );
+			setData( model, '<paragraph>fo[]ar</paragraph>' );
+
+			expect( model.createRange( model.createPositionAt( model.document.getRoot(), 0 ) ) ).to.be.instanceof( ModelRange );
+		} );
+	} );
+
+	describe( 'createRangeIn()', () => {
+		it( 'should return instance of Range', () => {
+			schema.register( 'paragraph', { inheritAllFrom: '$block' } );
+			setData( model, '<paragraph>fo[]ar</paragraph>' );
+
+			expect( model.createRangeIn( model.document.getRoot().getChild( 0 ) ) ).to.be.instanceof( ModelRange );
+		} );
+	} );
+
+	describe( 'createRangeOn()', () => {
+		it( 'should return instance of Range', () => {
+			schema.register( 'paragraph', { inheritAllFrom: '$block' } );
+			setData( model, '<paragraph>fo[]ar</paragraph>' );
+
+			expect( model.createRangeOn( model.document.getRoot().getChild( 0 ) ) ).to.be.instanceof( ModelRange );
+		} );
+	} );
+
+	describe( 'createSelection()', () => {
+		it( 'should return instance of Selection', () => {
+			expect( model.createSelection() ).to.be.instanceof( ModelSelection );
+		} );
+	} );
+
+	describe( 'createBatch()', () => {
+		it( 'should return instance of Batch', () => {
+			expect( model.createBatch() ).to.be.instanceof( Batch );
+		} );
+	} );
+
 	describe( 'destroy()', () => {
 		it( 'should destroy document', () => {
 			sinon.spy( model.document, 'destroy' );

+ 5 - 5
packages/ckeditor5-engine/tests/model/operation/detachoperation.js

@@ -21,13 +21,13 @@ describe( 'DetachOperation', () => {
 	} );
 
 	it( 'should have type equal to detach', () => {
-		const op = new DetachOperation( Position.createBefore( element ), 1 );
+		const op = new DetachOperation( Position._createBefore( element ), 1 );
 
 		expect( op.type ).to.equal( 'detach' );
 	} );
 
 	it( 'should remove given element from parent', () => {
-		const op = new DetachOperation( Position.createBefore( element ), 1 );
+		const op = new DetachOperation( Position._createBefore( element ), 1 );
 
 		model.applyOperation( op );
 
@@ -41,7 +41,7 @@ describe( 'DetachOperation', () => {
 
 			root._appendChild( [ element ] );
 
-			const op = new DetachOperation( Position.createBefore( element ), 1 );
+			const op = new DetachOperation( Position._createBefore( element ), 1 );
 
 			expect( () => {
 				op._validate();
@@ -50,14 +50,14 @@ describe( 'DetachOperation', () => {
 	} );
 
 	it( 'should be not a document operation', () => {
-		const op = new DetachOperation( Position.createBefore( element ), 1 );
+		const op = new DetachOperation( Position._createBefore( element ), 1 );
 
 		expect( op.isDocumentOperation ).to.false;
 	} );
 
 	describe( 'toJSON', () => {
 		it( 'should create proper json object', () => {
-			const position = Position.createBefore( element );
+			const position = Position._createBefore( element );
 			const op = new DetachOperation( position, 1 );
 
 			const serialized = op.toJSON();

+ 3 - 4
packages/ckeditor5-engine/tests/model/operation/markeroperation.js

@@ -5,7 +5,6 @@
 
 import Model from '../../../src/model/model';
 import Text from '../../../src/model/text';
-import Range from '../../../src/model/range';
 import MarkerOperation from '../../../src/model/operation/markeroperation';
 
 function matchRange( range ) {
@@ -20,7 +19,7 @@ describe( 'MarkerOperation', () => {
 		doc = model.document;
 		root = doc.createRoot();
 		root._appendChild( new Text( 'foo' ) );
-		range = Range.createFromParentsAndOffsets( root, 0, root, 0 );
+		range = model.createRange( model.createPositionAt( root, 0 ), model.createPositionAt( root, 0 ) );
 	} );
 
 	it( 'should have property type equal to "marker"', () => {
@@ -45,7 +44,7 @@ describe( 'MarkerOperation', () => {
 			new MarkerOperation( 'name', null, range, model.markers, true, doc.version )
 		);
 
-		const range2 = Range.createFromParentsAndOffsets( root, 0, root, 3 );
+		const range2 = model.createRange( model.createPositionAt( root, 0 ), model.createPositionAt( root, 3 ) );
 
 		sinon.spy( model.markers, '_set' );
 
@@ -99,7 +98,7 @@ describe( 'MarkerOperation', () => {
 	} );
 
 	it( 'should return MarkerOperation with swapped ranges as reverse operation', () => {
-		const range2 = Range.createFromParentsAndOffsets( root, 0, root, 3 );
+		const range2 = model.createRange( model.createPositionAt( root, 0 ), model.createPositionAt( root, 3 ) );
 
 		const op1 = new MarkerOperation( 'name', null, range, model.markers, true, doc.version );
 		const reversed1 = op1.getReversed();

+ 5 - 5
packages/ckeditor5-engine/tests/model/operation/renameoperation.js

@@ -23,7 +23,7 @@ describe( 'RenameOperation', () => {
 		element = new Element( oldName );
 		root._appendChild( element );
 
-		position = Position.createBefore( element );
+		position = Position._createBefore( element );
 	} );
 
 	it( 'should have type equal to rename', () => {
@@ -64,7 +64,7 @@ describe( 'RenameOperation', () => {
 
 	describe( '_validate()', () => {
 		it( 'should throw an error if position is not before an element', () => {
-			const op = new RenameOperation( Position.createAt( root, 'end' ), oldName, newName, doc.version );
+			const op = new RenameOperation( Position._createAt( root, 'end' ), oldName, newName, doc.version );
 
 			expect( () => {
 				op._validate();
@@ -89,7 +89,7 @@ describe( 'RenameOperation', () => {
 	} );
 
 	it( 'should create a RenameOperation with the same parameters when cloned', () => {
-		const op = new RenameOperation( Position.createAt( root, 'end' ), oldName, newName, doc.version );
+		const op = new RenameOperation( Position._createAt( root, 'end' ), oldName, newName, doc.version );
 		const clone = op.clone();
 
 		// New instance rather than a pointer to the old instance.
@@ -104,7 +104,7 @@ describe( 'RenameOperation', () => {
 
 	describe( 'toJSON', () => {
 		it( 'should create proper serialized object', () => {
-			const op = new RenameOperation( Position.createAt( root, 'end' ), oldName, newName, doc.version );
+			const op = new RenameOperation( Position._createAt( root, 'end' ), oldName, newName, doc.version );
 			const serialized = op.toJSON();
 
 			expect( serialized ).to.deep.equal( {
@@ -119,7 +119,7 @@ describe( 'RenameOperation', () => {
 
 	describe( 'fromJSON', () => {
 		it( 'should create proper AttributeOperation from json object', () => {
-			const op = new RenameOperation( Position.createAt( root, 'end' ), oldName, newName, doc.version );
+			const op = new RenameOperation( Position._createAt( root, 'end' ), oldName, newName, doc.version );
 
 			const serialized = op.toJSON();
 			const deserialized = RenameOperation.fromJSON( serialized, doc );

+ 18 - 18
packages/ckeditor5-engine/tests/model/operation/transform.js

@@ -100,7 +100,7 @@ describe( 'transform', () => {
 
 			expected = {
 				type: InsertOperation,
-				position: Position.createFromPosition( position )
+				position: position.clone()
 			};
 		} );
 
@@ -217,7 +217,7 @@ describe( 'transform', () => {
 		describe( 'by AttributeOperation', () => {
 			it( 'no position update', () => {
 				const transformBy = new AttributeOperation(
-					Range.createFromPositionAndShift( position, 2 ),
+					Range._createFromPositionAndShift( position, 2 ),
 					'foo',
 					null,
 					'bar',
@@ -914,15 +914,15 @@ describe( 'transform', () => {
 			targetPosition = new Position( root, [ 3, 3, 3 ] );
 			howMany = 2;
 
-			rangeEnd = Position.createFromPosition( sourcePosition );
+			rangeEnd = sourcePosition.clone();
 			rangeEnd.offset += howMany;
 
 			op = new MoveOperation( sourcePosition, howMany, targetPosition, 0 );
 
 			expected = {
 				type: MoveOperation,
-				sourcePosition: Position.createFromPosition( sourcePosition ),
-				targetPosition: Position.createFromPosition( targetPosition ),
+				sourcePosition: sourcePosition.clone(),
+				targetPosition: targetPosition.clone(),
 				howMany
 			};
 		} );
@@ -1957,7 +1957,7 @@ describe( 'transform', () => {
 
 			beforeEach( () => {
 				transformBy = new MoveOperation(
-					Position.createFromPosition( op.sourcePosition ),
+					op.sourcePosition.clone(),
 					op.howMany,
 					new Position( doc.graveyard, [ 0 ] ),
 					0
@@ -2015,11 +2015,11 @@ describe( 'transform', () => {
 			it( 'should force removing content even if was less important', () => {
 				const op = new MoveOperation( new Position( root, [ 8 ] ), 2, new Position( doc.graveyard, [ 0 ] ), 0 );
 
-				const targetPosition = Position.createFromPosition( op.targetPosition );
+				const targetPosition = op.targetPosition.clone();
 
 				const transformBy = new MoveOperation( new Position( root, [ 8 ] ), 2, new Position( root, [ 1 ] ), 0 );
 
-				const sourcePosition = Position.createFromPosition( transformBy.targetPosition );
+				const sourcePosition = transformBy.targetPosition.clone();
 
 				const transOp = transform( op, transformBy );
 
@@ -2426,8 +2426,8 @@ describe( 'transform', () => {
 		let oldRange, newRange;
 
 		beforeEach( () => {
-			oldRange = Range.createFromParentsAndOffsets( root, 1, root, 4 );
-			newRange = Range.createFromParentsAndOffsets( root, 10, root, 12 );
+			oldRange = new Range( Position._createAt( root, 1 ), Position._createAt( root, 4 ) );
+			newRange = new Range( Position._createAt( root, 10 ), Position._createAt( root, 12 ) );
 			op = new MarkerOperation( 'name', oldRange, newRange, model.markers, false, 0 );
 
 			expected = {
@@ -2441,7 +2441,7 @@ describe( 'transform', () => {
 			it( 'insert position affecting oldRange: update oldRange', () => {
 				// Just CC things.
 				op.newRange = null;
-				const transformBy = new InsertOperation( Position.createAt( root, 0 ), [ nodeA, nodeB ], 0 );
+				const transformBy = new InsertOperation( Position._createAt( root, 0 ), [ nodeA, nodeB ], 0 );
 
 				const transOp = transform( op, transformBy );
 
@@ -2456,7 +2456,7 @@ describe( 'transform', () => {
 			it( 'insert position affecting newRange: update newRange', () => {
 				// Just CC things.
 				op.oldRange = null;
-				const transformBy = new InsertOperation( Position.createAt( root, 8 ), [ nodeA, nodeB ], 0 );
+				const transformBy = new InsertOperation( Position._createAt( root, 8 ), [ nodeA, nodeB ], 0 );
 
 				const transOp = transform( op, transformBy );
 
@@ -2494,7 +2494,7 @@ describe( 'transform', () => {
 				// Just CC things.
 				op.newRange = null;
 
-				const transformBy = new MoveOperation( Position.createAt( root, 0 ), 1, Position.createAt( root, 20 ), 0 );
+				const transformBy = new MoveOperation( Position._createAt( root, 0 ), 1, Position._createAt( root, 20 ), 0 );
 				const transOp = transform( op, transformBy );
 
 				expected.newRange = null;
@@ -2506,7 +2506,7 @@ describe( 'transform', () => {
 			} );
 
 			it( 'moved range contains oldRange and is before newRange: update oldRange and newRange', () => {
-				const transformBy = new MoveOperation( Position.createAt( root, 2 ), 2, Position.createAt( root, 20 ), 0 );
+				const transformBy = new MoveOperation( Position._createAt( root, 2 ), 2, Position._createAt( root, 20 ), 0 );
 				const transOp = transform( op, transformBy );
 
 				expected.oldRange.start.offset = 1;
@@ -2522,7 +2522,7 @@ describe( 'transform', () => {
 				// Just CC things.
 				op.oldRange = null;
 
-				const transformBy = new MoveOperation( Position.createAt( root, 20 ), 2, Position.createAt( root, 11 ), 0 );
+				const transformBy = new MoveOperation( Position._createAt( root, 20 ), 2, Position._createAt( root, 11 ), 0 );
 				const transOp = transform( op, transformBy );
 
 				expected.oldRange = null;
@@ -2534,7 +2534,7 @@ describe( 'transform', () => {
 			} );
 
 			it( 'target position is inside oldRange and before newRange: update oldRange and newRange', () => {
-				const transformBy = new MoveOperation( Position.createAt( root, 20 ), 4, Position.createAt( root, 2 ), 0 );
+				const transformBy = new MoveOperation( Position._createAt( root, 20 ), 4, Position._createAt( root, 2 ), 0 );
 				const transOp = transform( op, transformBy );
 
 				expected.oldRange.start.offset = 1;
@@ -2586,7 +2586,7 @@ describe( 'transform', () => {
 			} );
 
 			it( 'same marker name and is important: convert to NoOperation', () => {
-				const anotherRange = Range.createFromParentsAndOffsets( root, 2, root, 2 );
+				const anotherRange = new Range( Position._createAt( root, 2 ), Position._createAt( root, 2 ) );
 				const transformBy = new MarkerOperation( 'name', oldRange, anotherRange, model.markers, false, 0 );
 
 				const transOp = transform( op, transformBy );
@@ -2598,7 +2598,7 @@ describe( 'transform', () => {
 			} );
 
 			it( 'same marker name and is less important: update oldRange parameter', () => {
-				const anotherRange = Range.createFromParentsAndOffsets( root, 2, root, 2 );
+				const anotherRange = new Range( Position._createAt( root, 2 ), Position._createAt( root, 2 ) );
 				const transformBy = new MarkerOperation( 'name', oldRange, anotherRange, model.markers, false, 0 );
 
 				const transOp = transform( op, transformBy, strongContext );

+ 4 - 4
packages/ckeditor5-engine/tests/model/operation/transform/utils.js

@@ -54,7 +54,7 @@ export class Client {
 
 		model.change( writer => {
 			// Replace existing model in document by new one.
-			writer.remove( Range.createIn( modelRoot ) );
+			writer.remove( writer.createRangeIn( modelRoot ) );
 			writer.insert( modelDocumentFragment, modelRoot );
 		} );
 
@@ -220,11 +220,11 @@ export class Client {
 		switch ( type ) {
 			default:
 			case 'start':
-				return Position.createFromPosition( selRange.start );
+				return selRange.start.clone();
 			case 'end':
-				return Position.createFromPosition( selRange.end );
+				return selRange.end.clone();
 			case 'beforeParent':
-				return Position.createBefore( selRange.start.parent );
+				return Position._createBefore( selRange.start.parent );
 		}
 	}
 

+ 13 - 13
packages/ckeditor5-engine/tests/model/operation/utils.js

@@ -39,19 +39,19 @@ describe( 'Operation utils', () => {
 
 	describe( 'insert', () => {
 		it( 'should insert nodes between nodes', () => {
-			utils._insert( Position.createAt( root, 3 ), [ 'xxx', new Element( 'p' ) ] );
+			utils._insert( Position._createAt( root, 3 ), [ 'xxx', new Element( 'p' ) ] );
 
 			expectData( 'fooxxx<p></p><$text bold="true">bar</$text><image src="img.jpg"></image>xyz' );
 		} );
 
 		it( 'should split text node if nodes at inserted at offset inside text node', () => {
-			utils._insert( Position.createAt( root, 5 ), new Element( 'p' ) );
+			utils._insert( Position._createAt( root, 5 ), new Element( 'p' ) );
 
 			expectData( 'foo<$text bold="true">ba</$text><p></p><$text bold="true">r</$text><image src="img.jpg"></image>xyz' );
 		} );
 
 		it( 'should merge text nodes if possible', () => {
-			utils._insert( Position.createAt( root, 3 ), new Text( 'xxx', { bold: true } ) );
+			utils._insert( Position._createAt( root, 3 ), new Text( 'xxx', { bold: true } ) );
 
 			expectData( 'foo<$text bold="true">xxxbar</$text><image src="img.jpg"></image>xyz' );
 		} );
@@ -59,21 +59,21 @@ describe( 'Operation utils', () => {
 
 	describe( 'remove', () => {
 		it( 'should remove nodes in given range', () => {
-			const range = Range.createFromParentsAndOffsets( root, 3, root, 6 );
+			const range = new Range( Position._createAt( root, 3 ), Position._createAt( root, 6 ) );
 			utils._remove( range );
 
 			expectData( 'foo<image src="img.jpg"></image>xyz' );
 		} );
 
 		it( 'should split text node if range starts or ends inside text node', () => {
-			const range = Range.createFromParentsAndOffsets( root, 1, root, 5 );
+			const range = new Range( Position._createAt( root, 1 ), Position._createAt( root, 5 ) );
 			utils._remove( range );
 
 			expectData( 'f<$text bold="true">r</$text><image src="img.jpg"></image>xyz' );
 		} );
 
 		it( 'should merge text nodes if possible', () => {
-			const range = Range.createFromParentsAndOffsets( root, 3, root, 7 );
+			const range = new Range( Position._createAt( root, 3 ), Position._createAt( root, 7 ) );
 			utils._remove( range );
 
 			expectData( 'fooxyz' );
@@ -89,15 +89,15 @@ describe( 'Operation utils', () => {
 
 	describe( 'move', () => {
 		it( 'should move a range of nodes', () => {
-			const range = Range.createFromParentsAndOffsets( root, 3, root, 6 );
-			utils._move( range, Position.createAt( root, 0 ) );
+			const range = new Range( Position._createAt( root, 3 ), Position._createAt( root, 6 ) );
+			utils._move( range, Position._createAt( root, 0 ) );
 
 			expectData( '<$text bold="true">bar</$text>foo<image src="img.jpg"></image>xyz' );
 		} );
 
 		it( 'should correctly move if target position is in same element as moved range, but after range', () => {
-			const range = Range.createFromParentsAndOffsets( root, 3, root, 6 );
-			utils._move( range, Position.createAt( root, 10 ) );
+			const range = new Range( Position._createAt( root, 3 ), Position._createAt( root, 6 ) );
+			utils._move( range, Position._createAt( root, 10 ) );
 
 			expectData( 'foo<image src="img.jpg"></image>xyz<$text bold="true">bar</$text>' );
 		} );
@@ -111,21 +111,21 @@ describe( 'Operation utils', () => {
 
 	describe( 'setAttribute', () => {
 		it( 'should set attribute on given range of nodes', () => {
-			const range = Range.createFromParentsAndOffsets( root, 6, root, 8 );
+			const range = new Range( Position._createAt( root, 6 ), Position._createAt( root, 8 ) );
 			utils._setAttribute( range, 'newAttr', true );
 
 			expectData( 'foo<$text bold="true">bar</$text><image newAttr="true" src="img.jpg"></image><$text newAttr="true">x</$text>yz' );
 		} );
 
 		it( 'should remove attribute if null was passed as a value', () => {
-			const range = Range.createFromParentsAndOffsets( root, 6, root, 7 );
+			const range = new Range( Position._createAt( root, 6 ), Position._createAt( root, 7 ) );
 			utils._setAttribute( range, 'src', null );
 
 			expectData( 'foo<$text bold="true">bar</$text><image></image>xyz' );
 		} );
 
 		it( 'should merge nodes if possible', () => {
-			const range = Range.createFromParentsAndOffsets( root, 0, root, 3 );
+			const range = new Range( Position._createAt( root, 0 ), Position._createAt( root, 3 ) );
 			utils._setAttribute( range, 'bold', true );
 
 			expectData( '<$text bold="true">foobar</$text><image src="img.jpg"></image>xyz' );

+ 105 - 96
packages/ckeditor5-engine/tests/model/position.js

@@ -19,6 +19,7 @@ import MergeOperation from '../../src/model/operation/mergeoperation';
 import SplitOperation from '../../src/model/operation/splitoperation';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
+import LivePosition from '../../src/model/liveposition';
 
 describe( 'Position', () => {
 	let doc, model, root, otherRoot, p, ul, li1, li2, f, o, z, b, a, r, foz, bar;
@@ -93,7 +94,7 @@ describe( 'Position', () => {
 			const pos = new Position( li1, [ 0, 2 ] );
 
 			expect( pos ).to.have.property( 'root', root );
-			expect( pos.isEqual( Position.createAt( li1, 0, 2 ) ) );
+			expect( pos.isEqual( Position._createAt( li1, 0, 2 ) ) );
 		} );
 
 		it( 'should normalize Element from a detached branch as a root', () => {
@@ -102,7 +103,7 @@ describe( 'Position', () => {
 			const pos = new Position( elA, [ 0 ] );
 
 			expect( pos ).to.have.property( 'root', rootEl );
-			expect( pos.isEqual( Position.createAt( elA, 0 ) ) );
+			expect( pos.isEqual( Position._createAt( elA, 0 ) ) );
 		} );
 
 		it( 'should throw error if given path is incorrect', () => {
@@ -126,129 +127,124 @@ describe( 'Position', () => {
 		} );
 	} );
 
-	describe( 'createFromParentAndOffset()', () => {
-		it( 'should create positions form node and offset', () => {
-			expect( Position.createFromParentAndOffset( root, 0 ) ).to.have.property( 'path' ).that.deep.equals( [ 0 ] );
-			expect( Position.createFromParentAndOffset( root, 1 ) ).to.have.property( 'path' ).that.deep.equals( [ 1 ] );
-			expect( Position.createFromParentAndOffset( root, 2 ) ).to.have.property( 'path' ).that.deep.equals( [ 2 ] );
+	describe( 'static creators', () => {
+		describe( '_createAt()', () => {
+			it( 'should throw if no offset is passed', () => {
+				expect( () => Position._createAt( ul ) ).to.throw( CKEditorError, /model-createPositionAt-offset-required/ );
+			} );
 
-			expect( Position.createFromParentAndOffset( p, 0 ) ).to.have.property( 'path' ).that.deep.equals( [ 0, 0 ] );
+			it( 'should create positions from positions', () => {
+				const position = Position._createAt( ul, 0 );
 
-			expect( Position.createFromParentAndOffset( ul, 0 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0 ] );
-			expect( Position.createFromParentAndOffset( ul, 1 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1 ] );
-			expect( Position.createFromParentAndOffset( ul, 2 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 2 ] );
+				const positionCopy = Position._createAt( position );
 
-			expect( Position.createFromParentAndOffset( li1, 0 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 0 ] );
-			expect( Position.createFromParentAndOffset( li1, 1 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 1 ] );
-			expect( Position.createFromParentAndOffset( li1, 2 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 2 ] );
-			expect( Position.createFromParentAndOffset( li1, 3 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 3 ] );
-		} );
+				expect( positionCopy ).to.have.property( 'path' ).that.deep.equals( [ 1, 0 ] );
+				expect( positionCopy ).to.have.property( 'root' ).that.equals( position.root );
+				expect( positionCopy ).to.not.equal( position );
+			} );
 
-		it( 'throws when parent is not an element', () => {
-			expect( () => {
-				Position.createFromParentAndOffset( b, 0 );
-			} ).to.throw( CKEditorError, /^model-position-parent-incorrect/ );
-		} );
+			it( 'should create positions from LivePosition', () => {
+				const position = new LivePosition( root, [ 0, 0 ] );
+				const created = Position._createAt( position );
 
-		it( 'works with a doc frag', () => {
-			const frag = new DocumentFragment();
+				expect( created.isEqual( position ) ).to.be.true;
+				expect( created ).to.not.be.equal( position );
+				expect( created ).to.be.instanceof( Position );
+				expect( created ).to.not.be.instanceof( LivePosition );
+			} );
 
-			expect( Position.createFromParentAndOffset( frag, 0 ) ).to.have.property( 'root', frag );
-		} );
-	} );
+			it( 'should create positions from node and offset', () => {
+				expect( Position._createAt( root, 0 ) ).to.have.property( 'path' ).that.deep.equals( [ 0 ] );
+				expect( Position._createAt( root, 1 ) ).to.have.property( 'path' ).that.deep.equals( [ 1 ] );
+				expect( Position._createAt( root, 2 ) ).to.have.property( 'path' ).that.deep.equals( [ 2 ] );
 
-	describe( 'createAt()', () => {
-		it( 'should throw if no offset is passed', () => {
-			expect( () => Position.createAt( ul ) ).to.throw( CKEditorError, /model-position-createAt-offset-required/ );
-		} );
+				expect( Position._createAt( p, 0 ) ).to.have.property( 'path' ).that.deep.equals( [ 0, 0 ] );
 
-		it( 'should create positions from positions', () => {
-			const spy = testUtils.sinon.spy( Position, 'createFromPosition' );
+				expect( Position._createAt( ul, 0 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0 ] );
+				expect( Position._createAt( ul, 1 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1 ] );
+				expect( Position._createAt( ul, 2 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 2 ] );
 
-			expect( Position.createAt( Position.createAt( ul, 0 ) ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0 ] );
+				expect( Position._createAt( li1, 0 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 0 ] );
+				expect( Position._createAt( li1, 1 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 1 ] );
+				expect( Position._createAt( li1, 2 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 2 ] );
+				expect( Position._createAt( li1, 3 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 3 ] );
+			} );
 
-			expect( spy.calledOnce ).to.be.true;
-		} );
+			it( 'should create positions from node and flag', () => {
+				expect( Position._createAt( root, 'end' ) ).to.have.property( 'path' ).that.deep.equals( [ 2 ] );
 
-		it( 'should create positions from node and offset', () => {
-			expect( Position.createAt( ul, 0 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0 ] );
-			expect( Position.createAt( li1, 0 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 0 ] );
-			expect( Position.createAt( ul, 1 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1 ] );
-		} );
+				expect( Position._createAt( p, 'before' ) ).to.have.property( 'path' ).that.deep.equals( [ 0 ] );
+				expect( Position._createAt( a, 'before' ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 1 ] );
 
-		it( 'should create positions from node and flag', () => {
-			expect( Position.createAt( root, 'end' ) ).to.have.property( 'path' ).that.deep.equals( [ 2 ] );
+				expect( Position._createAt( p, 'after' ) ).to.have.property( 'path' ).that.deep.equals( [ 1 ] );
+				expect( Position._createAt( a, 'after' ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 2 ] );
 
-			expect( Position.createAt( p, 'before' ) ).to.have.property( 'path' ).that.deep.equals( [ 0 ] );
-			expect( Position.createAt( a, 'before' ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 1 ] );
+				expect( Position._createAt( ul, 'end' ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 2 ] );
+			} );
 
-			expect( Position.createAt( p, 'after' ) ).to.have.property( 'path' ).that.deep.equals( [ 1 ] );
-			expect( Position.createAt( a, 'after' ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 2 ] );
+			it( 'throws when parent is not an element', () => {
+				expect( () => {
+					Position._createAt( b, 0 );
+				} ).to.throw( CKEditorError, /^model-position-parent-incorrect/ );
+			} );
+
+			it( 'works with a doc frag', () => {
+				const frag = new DocumentFragment();
 
-			expect( Position.createAt( ul, 'end' ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 2 ] );
+				expect( Position._createAt( frag, 0 ) ).to.have.property( 'root', frag );
+			} );
 		} );
-	} );
 
-	describe( 'createBefore()', () => {
-		it( 'should create positions before elements', () => {
-			expect( Position.createBefore( p ) ).to.have.property( 'path' ).that.deep.equals( [ 0 ] );
+		describe( '_createBefore()', () => {
+			it( 'should create positions before elements', () => {
+				expect( Position._createBefore( p ) ).to.have.property( 'path' ).that.deep.equals( [ 0 ] );
 
-			expect( Position.createBefore( ul ) ).to.have.property( 'path' ).that.deep.equals( [ 1 ] );
+				expect( Position._createBefore( ul ) ).to.have.property( 'path' ).that.deep.equals( [ 1 ] );
 
-			expect( Position.createBefore( li1 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0 ] );
+				expect( Position._createBefore( li1 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0 ] );
 
-			expect( Position.createBefore( f ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 0 ] );
-			expect( Position.createBefore( o ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 1 ] );
-			expect( Position.createBefore( z ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 2 ] );
+				expect( Position._createBefore( f ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 0 ] );
+				expect( Position._createBefore( o ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 1 ] );
+				expect( Position._createBefore( z ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 2 ] );
 
-			expect( Position.createBefore( li2 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1 ] );
+				expect( Position._createBefore( li2 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1 ] );
 
-			expect( Position.createBefore( b ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 0 ] );
-			expect( Position.createBefore( a ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 1 ] );
-			expect( Position.createBefore( r ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 2 ] );
-		} );
+				expect( Position._createBefore( b ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 0 ] );
+				expect( Position._createBefore( a ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 1 ] );
+				expect( Position._createBefore( r ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 2 ] );
+			} );
 
-		it( 'should throw error if one try to create positions before root', () => {
-			expect( () => {
-				Position.createBefore( root );
-			} ).to.throw( CKEditorError, /model-position-before-root/ );
+			it( 'should throw error if one try to create positions before root', () => {
+				expect( () => {
+					Position._createBefore( root );
+				} ).to.throw( CKEditorError, /model-position-before-root/ );
+			} );
 		} );
-	} );
 
-	describe( 'createAfter()', () => {
-		it( 'should create positions after elements', () => {
-			expect( Position.createAfter( p ) ).to.have.property( 'path' ).that.deep.equals( [ 1 ] );
+		describe( '_createAfter()', () => {
+			it( 'should create positions after elements', () => {
+				expect( Position._createAfter( p ) ).to.have.property( 'path' ).that.deep.equals( [ 1 ] );
 
-			expect( Position.createAfter( ul ) ).to.have.property( 'path' ).that.deep.equals( [ 2 ] );
+				expect( Position._createAfter( ul ) ).to.have.property( 'path' ).that.deep.equals( [ 2 ] );
 
-			expect( Position.createAfter( li1 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1 ] );
+				expect( Position._createAfter( li1 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1 ] );
 
-			expect( Position.createAfter( f ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 1 ] );
-			expect( Position.createAfter( o ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 2 ] );
-			expect( Position.createAfter( z ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 3 ] );
+				expect( Position._createAfter( f ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 1 ] );
+				expect( Position._createAfter( o ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 2 ] );
+				expect( Position._createAfter( z ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 3 ] );
 
-			expect( Position.createAfter( li2 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 2 ] );
-
-			expect( Position.createAfter( b ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 1 ] );
-			expect( Position.createAfter( a ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 2 ] );
-			expect( Position.createAfter( r ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 3 ] );
-		} );
-
-		it( 'should throw error if one try to make positions after root', () => {
-			expect( () => {
-				Position.createAfter( root );
-			} ).to.throw( CKEditorError, /model-position-after-root/ );
-		} );
-	} );
+				expect( Position._createAfter( li2 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 2 ] );
 
-	describe( 'createFromPosition()', () => {
-		it( 'should create a copy of given position', () => {
-			const original = new Position( root, [ 1, 2, 3 ] );
-			const position = Position.createFromPosition( original );
+				expect( Position._createAfter( b ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 1 ] );
+				expect( Position._createAfter( a ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 2 ] );
+				expect( Position._createAfter( r ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1, 3 ] );
+			} );
 
-			expect( position ).to.be.instanceof( Position );
-			expect( position.isEqual( original ) ).to.be.true;
-			expect( position ).not.to.be.equal( original );
+			it( 'should throw error if one try to make positions after root', () => {
+				expect( () => {
+					Position._createAfter( root );
+				} ).to.throw( CKEditorError, /model-position-after-root/ );
+			} );
 		} );
 	} );
 
@@ -642,6 +638,18 @@ describe( 'Position', () => {
 		} );
 	} );
 
+	describe( 'clone()', () => {
+		it( 'should return new instance of position', () => {
+			const position = Position._createAt( ul, 0 );
+
+			const positionCopy = position.clone();
+
+			expect( positionCopy ).to.have.property( 'path' ).that.deep.equals( [ 1, 0 ] );
+			expect( positionCopy ).to.have.property( 'root' ).that.equals( position.root );
+			expect( positionCopy ).to.not.equal( position );
+		} );
+	} );
+
 	// Note: We don't create model element structure in these tests because this method
 	// is used by OT so it must not check the structure.
 	describe( 'getTransformedByOperation()', () => {
@@ -653,7 +661,8 @@ describe( 'Position', () => {
 
 		describe( 'by AttributeOperation', () => {
 			it( 'nothing should change', () => {
-				const op = new AttributeOperation( Range.createFromParentsAndOffsets( root, 1, root, 6 ), 'key', true, false, 1 );
+				const range = new Range( Position._createAt( root, 1 ), Position._createAt( root, 6 ) );
+				const op = new AttributeOperation( range, 'key', true, false, 1 );
 				const transformed = pos.getTransformedByOperation( op );
 
 				expect( transformed.path ).to.deep.equal( [ 3, 2 ] );
@@ -674,7 +683,7 @@ describe( 'Position', () => {
 		describe( 'by MarkerOperation', () => {
 			it( 'nothing should change', () => {
 				const op = new MarkerOperation(
-					'marker', null, Range.createFromParentsAndOffsets( root, 1, root, 6 ), model.markers, true, 1
+					'marker', null, new Range( Position._createAt( root, 1 ), Position._createAt( root, 6 ) ), model.markers, true, 1
 				);
 				const transformed = pos.getTransformedByOperation( op );
 

+ 26 - 56
packages/ckeditor5-engine/tests/model/range.js

@@ -68,8 +68,8 @@ describe( 'Range', () => {
 
 	describe( 'isEqual()', () => {
 		it( 'should return true if the ranges are the same', () => {
-			const sameStart = Position.createFromPosition( start );
-			const sameEnd = Position.createFromPosition( end );
+			const sameStart = Position._createAt( start );
+			const sameEnd = Position._createAt( end );
 
 			const sameRange = new Range( sameStart, sameEnd );
 
@@ -80,7 +80,7 @@ describe( 'Range', () => {
 			const range = new Range( start, end );
 
 			const diffStart = new Position( root, [ 0 ] );
-			const sameEnd = Position.createFromPosition( end );
+			const sameEnd = Position._createAt( end );
 
 			const diffRange = new Range( diffStart, sameEnd );
 
@@ -108,7 +108,7 @@ describe( 'Range', () => {
 
 	describe( 'isIntersecting()', () => {
 		it( 'should return true if given range is equal', () => {
-			const otherRange = Range.createFromRange( range );
+			const otherRange = range.clone();
 			expect( range.isIntersecting( otherRange ) ).to.be.true;
 		} );
 
@@ -155,59 +155,28 @@ describe( 'Range', () => {
 			root._insertChild( 0, [ p ] );
 		} );
 
-		describe( 'createIn()', () => {
+		describe( '_createIn()', () => {
 			it( 'should return range', () => {
-				const range = Range.createIn( p );
+				const range = Range._createIn( p );
 
 				expect( range.start.path ).to.deep.equal( [ 0, 0 ] );
 				expect( range.end.path ).to.deep.equal( [ 0, 3 ] );
 			} );
 		} );
 
-		describe( 'createOn()', () => {
+		describe( '_createOn()', () => {
 			it( 'should return range', () => {
-				const range = Range.createOn( p );
+				const range = Range._createOn( p );
 
 				expect( range.start.path ).to.deep.equal( [ 0 ] );
 				expect( range.end.path ).to.deep.equal( [ 1 ] );
 			} );
 		} );
 
-		describe( 'createCollapsedAt()', () => {
-			it( 'should return new collapsed range at the given item position', () => {
-				const item = new Element( 'p', null, new Text( 'foo' ) );
-				const range = Range.createCollapsedAt( item, 0 );
-
-				expect( range.start.parent ).to.equal( item );
-				expect( range.start.offset ).to.equal( 0 );
-
-				expect( range.isCollapsed ).to.be.true;
-			} );
-
-			it( 'should return new collapse range at the given item position and offset', () => {
-				const item = new Element( 'p', null, new Text( 'foo' ) );
-				const range = Range.createCollapsedAt( item, 1 );
-
-				expect( range.start.parent ).to.equal( item );
-				expect( range.start.offset ).to.equal( 1 );
-
-				expect( range.isCollapsed ).to.be.true;
-			} );
-		} );
-
-		describe( 'createFromParentsAndOffsets()', () => {
-			it( 'should return range', () => {
-				const range = Range.createFromParentsAndOffsets( root, 0, p, 2 );
-
-				expect( range.start.path ).to.deep.equal( [ 0 ] );
-				expect( range.end.path ).to.deep.equal( [ 0, 2 ] );
-			} );
-		} );
-
-		describe( 'createFromPositionAndShift()', () => {
+		describe( '_createFromPositionAndShift()', () => {
 			it( 'should make range from start position and offset', () => {
 				const position = new Position( root, [ 1, 2, 3 ] );
-				const range = Range.createFromPositionAndShift( position, 4 );
+				const range = Range._createFromPositionAndShift( position, 4 );
 
 				expect( range ).to.be.instanceof( Range );
 				expect( range.start.isEqual( position ) ).to.be.true;
@@ -216,21 +185,21 @@ describe( 'Range', () => {
 			} );
 		} );
 
-		describe( 'createFromRange()', () => {
+		describe( 'clone()', () => {
 			it( 'should create a new instance of Range that is equal to passed range', () => {
-				const clone = Range.createFromRange( range );
+				const clone = range.clone();
 
 				expect( clone ).not.to.be.equal( range ); // clone is not pointing to the same object as position
 				expect( clone.isEqual( range ) ).to.be.true; // but they are equal in the position-sense
 			} );
 		} );
 
-		describe( 'createFromRanges()', () => {
+		describe( '_createFromRanges()', () => {
 			function makeRanges( root, ...points ) {
 				const ranges = [];
 
 				for ( let i = 0; i < points.length; i += 2 ) {
-					ranges.push( Range.createFromParentsAndOffsets( root, points[ i ], root, points[ i + 1 ] ) );
+					ranges.push( new Range( Position._createAt( root, points[ i ] ), Position._createAt( root, points[ i + 1 ] ) ) );
 				}
 
 				return ranges;
@@ -242,20 +211,20 @@ describe( 'Range', () => {
 
 			it( 'should throw if empty array is passed', () => {
 				expect( () => {
-					Range.createFromRanges( [] );
+					Range._createFromRanges( [] );
 				} ).to.throw( CKEditorError, /^range-create-from-ranges-empty-array/ );
 			} );
 
 			it( 'should return a copy of the range if only one range was passed', () => {
-				const original = Range.createFromParentsAndOffsets( root, 2, root, 3 );
-				const range = Range.createFromRanges( [ original ] );
+				const original = new Range( Position._createAt( root, 2 ), Position._createAt( root, 3 ) );
+				const range = Range._createFromRanges( [ original ] );
 
 				expect( range.isEqual( original ) ).to.be.true;
 				expect( range ).not.to.be.equal( original );
 			} );
 
 			it( 'should combine ranges with reference range', () => {
-				const range = Range.createFromRanges( makeRanges( root, 3, 7, 2, 3, 7, 9, 11, 14, 0, 1 ) );
+				const range = Range._createFromRanges( makeRanges( root, 3, 7, 2, 3, 7, 9, 11, 14, 0, 1 ) );
 
 				expect( range.start.offset ).to.equal( 2 );
 				expect( range.end.offset ).to.equal( 9 );
@@ -417,7 +386,7 @@ describe( 'Range', () => {
 		} );
 
 		it( 'should return true if ranges are equal and check is not strict', () => {
-			const otherRange = Range.createFromRange( range );
+			const otherRange = range.clone();
 
 			expect( range.containsRange( otherRange, true ) ).to.be.true;
 		} );
@@ -460,7 +429,7 @@ describe( 'Range', () => {
 		} );
 
 		it( 'should return true if element is inside range and false when it is not inside range', () => {
-			const range = Range.createFromParentsAndOffsets( root, 1, root, 3 ); // Range over `b` and `c`.
+			const range = new Range( Position._createAt( root, 1 ), Position._createAt( root, 3 ) ); // Range over `b` and `c`.
 
 			expect( range.containsItem( a ) ).to.be.false;
 			expect( range.containsItem( b ) ).to.be.true;
@@ -791,7 +760,7 @@ describe( 'Range', () => {
 		} );
 
 		it( 'should return a range equal to both ranges if both ranges are equal', () => {
-			const otherRange = Range.createFromRange( range );
+			const otherRange = range.clone();
 			const common = range.getIntersection( otherRange );
 
 			expect( common.isEqual( range ) ).to.be.true;
@@ -804,7 +773,7 @@ describe( 'Range', () => {
 		let gyPos;
 
 		beforeEach( () => {
-			range = Range.createFromParentsAndOffsets( root, 2, root, 5 );
+			range = new Range( Position._createAt( root, 2 ), Position._createAt( root, 5 ) );
 			gyPos = new Position( gy, [ 0 ] );
 		} );
 
@@ -815,7 +784,8 @@ describe( 'Range', () => {
 
 		describe( 'by AttributeOperation', () => {
 			it( 'nothing should change', () => {
-				const op = new AttributeOperation( Range.createFromParentsAndOffsets( root, 1, root, 6 ), 'key', true, false, 1 );
+				const opRange = new Range( Position._createAt( root, 1 ), Position._createAt( root, 6 ) );
+				const op = new AttributeOperation( opRange, 'key', true, false, 1 );
 				const transformed = range.getTransformedByOperation( op );
 
 				expectRange( transformed[ 0 ], 2, 5 );
@@ -848,7 +818,7 @@ describe( 'Range', () => {
 		describe( 'by MarkerOperation', () => {
 			it( 'nothing should change', () => {
 				const op = new MarkerOperation(
-					'marker', null, Range.createFromParentsAndOffsets( root, 1, root, 6 ), model.markers, true, 1
+					'marker', null, new Range( Position._createAt( root, 1 ), Position._createAt( root, 6 ) ), model.markers, true, 1
 				);
 
 				const transformed = range.getTransformedByOperation( op );
@@ -1215,7 +1185,7 @@ describe( 'Range', () => {
 	describe( 'getTransformedByOperations()', () => {
 		beforeEach( () => {
 			root._appendChild( new Text( 'foobar' ) );
-			range = Range.createFromParentsAndOffsets( root, 2, root, 5 );
+			range = new Range( Position._createAt( root, 2 ), Position._createAt( root, 5 ) );
 		} );
 
 		function expectRange( range, startOffset, endOffset ) {

+ 28 - 21
packages/ckeditor5-engine/tests/model/schema.js

@@ -15,7 +15,6 @@ import Text from '../../src/model/text';
 import TextProxy from '../../src/model/textproxy';
 import Position from '../../src/model/position';
 import Range from '../../src/model/range';
-import Selection from '../../src/model/selection';
 
 import { getData, setData, stringify, parse } from '../../src/dev-utils/model';
 
@@ -394,8 +393,8 @@ describe( 'Schema', () => {
 		} );
 
 		it( 'accepts a schemaContext instance as a context', () => {
-			const rootContext = new SchemaContext( Position.createAt( root1, 0 ) );
-			const paragraphContext = new SchemaContext( Position.createAt( r1p1, 0 ) );
+			const rootContext = new SchemaContext( Position._createAt( root1, 0 ) );
+			const paragraphContext = new SchemaContext( Position._createAt( r1p1, 0 ) );
 
 			expect( schema.checkChild( rootContext, 'paragraph' ) ).to.be.true;
 			expect( schema.checkChild( rootContext, '$text' ) ).to.be.false;
@@ -405,8 +404,8 @@ describe( 'Schema', () => {
 		} );
 
 		it( 'accepts a position as a context', () => {
-			const posInRoot = Position.createAt( root1, 0 );
-			const posInParagraph = Position.createAt( r1p1, 0 );
+			const posInRoot = Position._createAt( root1, 0 );
+			const posInParagraph = Position._createAt( r1p1, 0 );
 
 			expect( schema.checkChild( posInRoot, 'paragraph' ) ).to.be.true;
 			expect( schema.checkChild( posInRoot, '$text' ) ).to.be.false;
@@ -486,16 +485,16 @@ describe( 'Schema', () => {
 		} );
 
 		it( 'accepts a position as a context', () => {
-			const posInRoot = Position.createAt( root1, 0 );
-			const posInParagraph = Position.createAt( r1p1, 0 );
+			const posInRoot = Position._createAt( root1, 0 );
+			const posInParagraph = Position._createAt( r1p1, 0 );
 
 			expect( schema.checkAttribute( posInRoot, 'align' ) ).to.be.false;
 			expect( schema.checkAttribute( posInParagraph, 'align' ) ).to.be.true;
 		} );
 
 		it( 'accepts a schemaContext instance as a context', () => {
-			const rootContext = new SchemaContext( Position.createAt( root1, 0 ) );
-			const paragraphContext = new SchemaContext( Position.createAt( r1p1, 0 ) );
+			const rootContext = new SchemaContext( Position._createAt( root1, 0 ) );
+			const paragraphContext = new SchemaContext( Position._createAt( r1p1, 0 ) );
 
 			expect( schema.checkAttribute( rootContext, 'align' ) ).to.be.false;
 			expect( schema.checkAttribute( paragraphContext, 'align' ) ).to.be.true;
@@ -743,7 +742,7 @@ describe( 'Schema', () => {
 			new Element( '$root', null, [
 				listItem, listItemToMerge
 			] );
-			const position = Position.createAfter( listItem );
+			const position = Position._createAfter( listItem );
 
 			expect( schema.checkMerge( position ) ).to.be.true;
 		} );
@@ -758,7 +757,7 @@ describe( 'Schema', () => {
 				listItem
 			] );
 
-			const position = Position.createBefore( listItem );
+			const position = Position._createBefore( listItem );
 
 			expect( () => {
 				expect( schema.checkMerge( position ) );
@@ -776,7 +775,7 @@ describe( 'Schema', () => {
 				listItem
 			] );
 
-			const position = Position.createBefore( listItem );
+			const position = Position._createBefore( listItem );
 
 			expect( () => {
 				expect( schema.checkMerge( position ) );
@@ -793,7 +792,7 @@ describe( 'Schema', () => {
 				listItem
 			] );
 
-			const position = Position.createAfter( listItem );
+			const position = Position._createAfter( listItem );
 
 			expect( () => {
 				expect( schema.checkMerge( position ) );
@@ -811,7 +810,7 @@ describe( 'Schema', () => {
 				new Text( 'bar' )
 			] );
 
-			const position = Position.createBefore( listItem );
+			const position = Position._createBefore( listItem );
 
 			expect( () => {
 				expect( schema.checkMerge( position ) );
@@ -1187,7 +1186,7 @@ describe( 'Schema', () => {
 			setData( model, input );
 
 			const validRanges = schema.getValidRanges( doc.selection.getRanges(), attribute );
-			const sel = new Selection( validRanges );
+			const sel = model.createSelection( validRanges );
 
 			expect( stringify( root, sel ) ).to.equal( output );
 		}
@@ -1575,7 +1574,7 @@ describe( 'Schema', () => {
 		it( 'should return position ancestor that allows to insert given node to it', () => {
 			const node = new Element( 'paragraph' );
 
-			const allowedParent = schema.findAllowedParent( node, Position.createAt( r1bQp, 0 ) );
+			const allowedParent = schema.findAllowedParent( node, Position._createAt( r1bQp, 0 ) );
 
 			expect( allowedParent ).to.equal( r1bQ );
 		} );
@@ -1583,7 +1582,7 @@ describe( 'Schema', () => {
 		it( 'should return position ancestor that allows to insert given node to it when position is already i such an element', () => {
 			const node = new Text( 'text' );
 
-			const parent = schema.findAllowedParent( node, Position.createAt( r1bQp, 0 ) );
+			const parent = schema.findAllowedParent( node, Position._createAt( r1bQp, 0 ) );
 
 			expect( parent ).to.equal( r1bQp );
 		} );
@@ -1597,7 +1596,7 @@ describe( 'Schema', () => {
 			} );
 			const node = new Element( 'div' );
 
-			const parent = schema.findAllowedParent( node, Position.createAt( r1bQp, 0 ) );
+			const parent = schema.findAllowedParent( node, Position._createAt( r1bQp, 0 ) );
 
 			expect( parent ).to.null;
 		} );
@@ -1611,7 +1610,7 @@ describe( 'Schema', () => {
 			} );
 			const node = new Element( 'div' );
 
-			const parent = schema.findAllowedParent( node, Position.createAt( r1bQp, 0 ) );
+			const parent = schema.findAllowedParent( node, Position._createAt( r1bQp, 0 ) );
 
 			expect( parent ).to.null;
 		} );
@@ -1619,7 +1618,7 @@ describe( 'Schema', () => {
 		it( 'should return null when there is no allowed ancestor for given position', () => {
 			const node = new Element( 'section' );
 
-			const parent = schema.findAllowedParent( node, Position.createAt( r1bQp, 0 ) );
+			const parent = schema.findAllowedParent( node, Position._createAt( r1bQp, 0 ) );
 
 			expect( parent ).to.null;
 		} );
@@ -2763,6 +2762,14 @@ describe( 'Schema', () => {
 			expect( schema.isObject( 'caption' ) ).to.be.false;
 		} );
 	} );
+
+	describe( 'createContext()', () => {
+		it( 'should return SchemaContext instance', () => {
+			const ctx = schema.createContext( [ 'a', 'b', 'c' ] );
+
+			expect( ctx ).to.be.instanceof( SchemaContext );
+		} );
+	} );
 } );
 
 describe( 'SchemaContext', () => {
@@ -2866,7 +2873,7 @@ describe( 'SchemaContext', () => {
 		} );
 
 		it( 'creates context based on a position', () => {
-			const pos = Position.createAt( root.getChild( 0 ).getChild( 0 ), 0 );
+			const pos = Position._createAt( root.getChild( 0 ).getChild( 0 ), 0 );
 			const ctx = new SchemaContext( pos );
 
 			expect( ctx.length ).to.equal( 3 );

+ 30 - 44
packages/ckeditor5-engine/tests/model/selection.js

@@ -181,7 +181,7 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'is false when last range is collapsed', () => {
-			const pos = Position.createAt( root, 0 );
+			const pos = Position._createAt( root, 0 );
 
 			selection.setTo( pos );
 
@@ -193,9 +193,9 @@ describe( 'Selection', () => {
 		let r1, r2, r3;
 
 		beforeEach( () => {
-			r1 = Range.createFromParentsAndOffsets( root, 2, root, 4 );
-			r2 = Range.createFromParentsAndOffsets( root, 4, root, 6 );
-			r3 = Range.createFromParentsAndOffsets( root, 1, root, 2 );
+			r1 = new Range( Position._createAt( root, 2 ), Position._createAt( root, 4 ) );
+			r2 = new Range( Position._createAt( root, 4 ), Position._createAt( root, 6 ) );
+			r3 = new Range( Position._createAt( root, 1 ), Position._createAt( root, 2 ) );
 			selection.setTo( [ r1, r2 ] );
 		} );
 
@@ -398,7 +398,7 @@ describe( 'Selection', () => {
 			} );
 
 			it( 'should set selection at the specified position', () => {
-				const pos = Position.createFromParentAndOffset( root, 3 );
+				const pos = Position._createAt( root, 3 );
 
 				selection.setTo( pos );
 
@@ -430,13 +430,13 @@ describe( 'Selection', () => {
 			const spy = sinon.spy();
 			selection.on( 'change:range', spy );
 
-			selection.setFocus( Position.createAt( root, 'end' ) );
+			selection.setFocus( Position._createAt( root, 'end' ) );
 
 			expect( spy.calledOnce ).to.be.true;
 		} );
 
 		it( 'throws if there are no ranges in selection', () => {
-			const endPos = Position.createAt( root, 'end' );
+			const endPos = Position._createAt( root, 'end' );
 
 			expect( () => {
 				selection.setFocus( endPos );
@@ -444,8 +444,8 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'modifies existing collapsed selection', () => {
-			const startPos = Position.createAt( root, 1 );
-			const endPos = Position.createAt( root, 2 );
+			const startPos = Position._createAt( root, 1 );
+			const endPos = Position._createAt( root, 2 );
 
 			selection.setTo( startPos );
 
@@ -456,8 +456,8 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'makes existing collapsed selection a backward selection', () => {
-			const startPos = Position.createAt( root, 1 );
-			const endPos = Position.createAt( root, 0 );
+			const startPos = Position._createAt( root, 1 );
+			const endPos = Position._createAt( root, 0 );
 
 			selection.setTo( startPos );
 
@@ -469,9 +469,9 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'modifies existing non-collapsed selection', () => {
-			const startPos = Position.createAt( root, 1 );
-			const endPos = Position.createAt( root, 2 );
-			const newEndPos = Position.createAt( root, 3 );
+			const startPos = Position._createAt( root, 1 );
+			const endPos = Position._createAt( root, 2 );
+			const newEndPos = Position._createAt( root, 3 );
 
 			selection.setTo( new Range( startPos, endPos ) );
 
@@ -482,9 +482,9 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'makes existing non-collapsed selection a backward selection', () => {
-			const startPos = Position.createAt( root, 1 );
-			const endPos = Position.createAt( root, 2 );
-			const newEndPos = Position.createAt( root, 0 );
+			const startPos = Position._createAt( root, 1 );
+			const endPos = Position._createAt( root, 2 );
+			const newEndPos = Position._createAt( root, 0 );
 
 			selection.setTo( new Range( startPos, endPos ) );
 
@@ -496,9 +496,9 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'makes existing backward selection a forward selection', () => {
-			const startPos = Position.createAt( root, 1 );
-			const endPos = Position.createAt( root, 2 );
-			const newEndPos = Position.createAt( root, 3 );
+			const startPos = Position._createAt( root, 1 );
+			const endPos = Position._createAt( root, 2 );
+			const newEndPos = Position._createAt( root, 3 );
 
 			selection.setTo( new Range( startPos, endPos ), { backward: true } );
 
@@ -510,9 +510,9 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'modifies existing backward selection', () => {
-			const startPos = Position.createAt( root, 1 );
-			const endPos = Position.createAt( root, 2 );
-			const newEndPos = Position.createAt( root, 0 );
+			const startPos = Position._createAt( root, 1 );
+			const endPos = Position._createAt( root, 2 );
+			const newEndPos = Position._createAt( root, 0 );
 
 			selection.setTo( new Range( startPos, endPos ), { backward: true } );
 
@@ -525,12 +525,12 @@ describe( 'Selection', () => {
 
 		it( 'modifies only the last range', () => {
 			// Offsets are chosen in this way that the order of adding ranges must count, not their document order.
-			const startPos1 = Position.createAt( root, 4 );
-			const endPos1 = Position.createAt( root, 5 );
-			const startPos2 = Position.createAt( root, 1 );
-			const endPos2 = Position.createAt( root, 2 );
+			const startPos1 = Position._createAt( root, 4 );
+			const endPos1 = Position._createAt( root, 5 );
+			const startPos2 = Position._createAt( root, 1 );
+			const endPos2 = Position._createAt( root, 2 );
 
-			const newEndPos = Position.createAt( root, 0 );
+			const newEndPos = Position._createAt( root, 0 );
 
 			selection.setTo( [
 				new Range( startPos1, endPos1 ),
@@ -557,8 +557,8 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'collapses the selection when extending to the anchor', () => {
-			const startPos = Position.createAt( root, 1 );
-			const endPos = Position.createAt( root, 2 );
+			const startPos = Position._createAt( root, 1 );
+			const endPos = Position._createAt( root, 2 );
 
 			selection.setTo( new Range( startPos, endPos ) );
 
@@ -567,20 +567,6 @@ describe( 'Selection', () => {
 			expect( selection.focus.compareWith( startPos ) ).to.equal( 'same' );
 			expect( selection.isCollapsed ).to.be.true;
 		} );
-
-		it( 'uses Position.createAt', () => {
-			const startPos = Position.createAt( root, 1 );
-			const endPos = Position.createAt( root, 2 );
-			const newEndPos = Position.createAt( root, 4 );
-			const spy = testUtils.sinon.stub( Position, 'createAt' ).returns( newEndPos );
-
-			selection.setTo( new Range( startPos, endPos ) );
-
-			selection.setFocus( root, 'end' );
-
-			expect( spy.calledOnce ).to.be.true;
-			expect( selection.focus.compareWith( newEndPos ) ).to.equal( 'same' );
-		} );
 	} );
 
 	describe( 'setTo - selection set to null', () => {

+ 18 - 18
packages/ckeditor5-engine/tests/model/treewalker.js

@@ -568,7 +568,7 @@ describe( 'TreeWalker', () => {
 		describe( 'forward treewalker', () => {
 			it( 'should jump over all text nodes', () => {
 				const walker = new TreeWalker( {
-					startPosition: Position.createFromParentAndOffset( paragraph, 0 )
+					startPosition: Position._createAt( paragraph, 0 )
 				} );
 
 				walker.skip( value => value.type == 'text' );
@@ -579,7 +579,7 @@ describe( 'TreeWalker', () => {
 
 			it( 'should do not move if the condition is false', () => {
 				const walker = new TreeWalker( {
-					startPosition: Position.createFromParentAndOffset( paragraph, 1 )
+					startPosition: Position._createAt( paragraph, 1 )
 				} );
 
 				walker.skip( () => false );
@@ -590,7 +590,7 @@ describe( 'TreeWalker', () => {
 
 			it( 'should move to the end if the condition is true', () => {
 				const walker = new TreeWalker( {
-					startPosition: Position.createFromParentAndOffset( paragraph, 1 )
+					startPosition: Position._createAt( paragraph, 1 )
 				} );
 
 				walker.skip( () => true );
@@ -603,7 +603,7 @@ describe( 'TreeWalker', () => {
 		describe( 'backward treewalker', () => {
 			it( 'should jump over all text nodes', () => {
 				const walker = new TreeWalker( {
-					startPosition: Position.createFromParentAndOffset( paragraph, 3 ),
+					startPosition: Position._createAt( paragraph, 3 ),
 					direction: 'backward'
 				} );
 
@@ -615,7 +615,7 @@ describe( 'TreeWalker', () => {
 
 			it( 'should do not move if the condition is false', () => {
 				const walker = new TreeWalker( {
-					startPosition: Position.createFromParentAndOffset( paragraph, 1 ),
+					startPosition: Position._createAt( paragraph, 1 ),
 					direction: 'backward'
 				} );
 
@@ -627,7 +627,7 @@ describe( 'TreeWalker', () => {
 
 			it( 'should move to the end if the condition is true', () => {
 				const walker = new TreeWalker( {
-					startPosition: Position.createFromParentAndOffset( paragraph, 1 ),
+					startPosition: Position._createAt( paragraph, 1 ),
 					direction: 'backward'
 				} );
 
@@ -660,11 +660,11 @@ function expectText( value, expected, options = {} ) {
 	expect( value.length ).to.equal( value.item.data.length );
 
 	if ( options.direction == 'backward' ) {
-		previousPosition = Position.createAfter( value.item );
-		nextPosition = Position.createBefore( value.item );
+		previousPosition = Position._createAfter( value.item );
+		nextPosition = Position._createBefore( value.item );
 	} else {
-		previousPosition = Position.createBefore( value.item );
-		nextPosition = Position.createAfter( value.item );
+		previousPosition = Position._createBefore( value.item );
+		nextPosition = Position._createAfter( value.item );
 	}
 
 	expect( value.previousPosition ).to.deep.equal( previousPosition );
@@ -678,11 +678,11 @@ function expectStart( value, expected, options = {} ) {
 	expect( value.length ).to.equal( 1 );
 
 	if ( options.direction == 'backward' ) {
-		previousPosition = Position.createAfter( value.item );
-		nextPosition = Position.createBefore( value.item );
+		previousPosition = Position._createAfter( value.item );
+		nextPosition = Position._createBefore( value.item );
 	} else {
-		previousPosition = Position.createBefore( value.item );
-		nextPosition = Position.createFromParentAndOffset( value.item, 0 );
+		previousPosition = Position._createBefore( value.item );
+		nextPosition = Position._createAt( value.item, 0 );
 	}
 
 	if ( options.shallow ) {
@@ -699,11 +699,11 @@ function expectEnd( value, expected, options = {} ) {
 	expect( value.length ).to.be.undefined;
 
 	if ( options.direction == 'backward' ) {
-		previousPosition = Position.createAfter( value.item );
-		nextPosition = Position.createFromParentAndOffset( value.item, value.item.maxOffset );
+		previousPosition = Position._createAfter( value.item );
+		nextPosition = Position._createAt( value.item, value.item.maxOffset );
 	} else {
-		previousPosition = Position.createFromParentAndOffset( value.item, value.item.maxOffset );
-		nextPosition = Position.createAfter( value.item );
+		previousPosition = Position._createAt( value.item, value.item.maxOffset );
+		nextPosition = Position._createAfter( value.item );
 	}
 
 	expect( value.previousPosition ).to.deep.equal( previousPosition );

+ 1 - 1
packages/ckeditor5-engine/tests/model/utils-tests/utils.js

@@ -32,7 +32,7 @@ describe( 'getNodesAndText', () => {
 	} );
 
 	it( 'reads two elements with text', () => {
-		expect( getNodesAndText( Range.createIn( root ) ) ).to.equal( 'DIVfoobarDIVPabcxyzP' );
+		expect( getNodesAndText( Range._createIn( root ) ) ).to.equal( 'DIVfoobarDIVPabcxyzP' );
 	} );
 } );
 

+ 4 - 5
packages/ckeditor5-engine/tests/model/utils/insertcontent.js

@@ -8,7 +8,6 @@ import insertContent from '../../../src/model/utils/insertcontent';
 import DocumentFragment from '../../../src/model/documentfragment';
 import Text from '../../../src/model/text';
 import Element from '../../../src/model/element';
-import Selection from '../../../src/model/selection';
 import Position from '../../../src/model/position';
 
 import { setData, getData, parse } from '../../../src/dev-utils/model';
@@ -38,7 +37,7 @@ describe( 'DataController utils', () => {
 			model.schema.extend( '$text', { allowIn: '$root' } );
 			setData( model, 'a[]bc' );
 
-			const selection = new Selection( new Position( doc.getRoot(), [ 2 ] ) );
+			const selection = model.createSelection( model.createPositionFromPath( doc.getRoot(), [ 2 ] ) );
 
 			model.change( writer => {
 				insertContent( model, writer.createText( 'x' ), selection );
@@ -50,8 +49,8 @@ describe( 'DataController utils', () => {
 			model.schema.extend( '$text', { allowIn: '$root' } );
 			setData( model, 'a[]bc' );
 
-			const selection = new Selection( new Position( doc.getRoot(), [ 2 ] ) );
-			const selectionCopy = new Selection( new Position( doc.getRoot(), [ 2 ] ) );
+			const selection = model.createSelection( model.createPositionFromPath( doc.getRoot(), [ 2 ] ) );
+			const selectionCopy = model.createSelection( model.createPositionFromPath( doc.getRoot(), [ 2 ] ) );
 
 			expect( selection.isEqual( selectionCopy ) ).to.be.true;
 
@@ -61,7 +60,7 @@ describe( 'DataController utils', () => {
 
 			expect( selection.isEqual( selectionCopy ) ).to.be.false;
 
-			const insertionSelection = new Selection( new Position( doc.getRoot(), [ 3 ] ) );
+			const insertionSelection = model.createSelection( model.createPositionFromPath( doc.getRoot(), [ 3 ] ) );
 			expect( selection.isEqual( insertionSelection ) ).to.be.true;
 		} );
 

+ 2 - 3
packages/ckeditor5-engine/tests/model/utils/modifyselection.js

@@ -4,7 +4,6 @@
  */
 
 import Model from '../../../src/model/model';
-import Selection from '../../../src/model/selection';
 import modifySelection from '../../../src/model/utils/modifyselection';
 import { setData, stringify } from '../../../src/dev-utils/model';
 
@@ -381,7 +380,7 @@ describe( 'DataController utils', () => {
 				// Creating new instance of selection instead of operation on module:engine/model/document~Document#selection.
 				// Document's selection will throw errors in some test cases (which are correct cases, but only for
 				// non-document selections).
-				const testSelection = new Selection( doc.selection );
+				const testSelection = model.createSelection( doc.selection );
 				modifySelection( model, testSelection, { unit: 'codePoint', direction: 'backward' } );
 
 				expect( stringify( doc.getRoot(), testSelection ) ).to.equal( '<p>foob[̂]ar</p>' );
@@ -987,7 +986,7 @@ describe( 'DataController utils', () => {
 			// Creating new instance of selection instead of operation on module:engine/model/document~Document#selection.
 			// Document's selection will throw errors in some test cases (which are correct cases, but only for
 			// non-document selections).
-			const testSelection = new Selection( doc.selection );
+			const testSelection = model.createSelection( doc.selection );
 			modifySelection( model, testSelection, options );
 
 			expect( stringify( doc.getRoot(), testSelection ) ).to.equal( output );

+ 69 - 50
packages/ckeditor5-engine/tests/model/utils/selection-post-fixer.js

@@ -4,8 +4,6 @@
  */
 
 import Model from '../../../src/model/model';
-import ModelPosition from '../../../src/model/position';
-import ModelRange from '../../../src/model/range';
 
 import { injectSelectionPostFixer } from '../../../src/model/utils/selection-post-fixer';
 
@@ -88,7 +86,7 @@ describe( 'Selection post-fixer', () => {
 			// <paragraph>foo</paragraph>[]<image></image>
 			model.change( writer => {
 				writer.setSelection(
-					ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 1 )
+					writer.createRange( writer.createPositionAt( modelRoot, 1 ), writer.createPositionAt( modelRoot, 1 ) )
 				);
 			} );
 
@@ -109,9 +107,9 @@ describe( 'Selection post-fixer', () => {
 			it( 'should fix #1', () => {
 				// <paragraph>f[oo</paragraph><table><tableRow><tableCell></tableCell>]<tableCell>...
 				model.change( writer => {
-					writer.setSelection( ModelRange.createFromParentsAndOffsets(
-						modelRoot.getChild( 0 ), 1,
-						modelRoot.getChild( 1 ).getChild( 0 ), 1
+					writer.setSelection( writer.createRange(
+						writer.createPositionAt( modelRoot.getChild( 0 ), 1 ),
+						writer.createPositionAt( modelRoot.getChild( 1 ).getChild( 0 ), 1 )
 					) );
 				} );
 
@@ -127,9 +125,9 @@ describe( 'Selection post-fixer', () => {
 			it( 'should fix #2', () => {
 				// ...<table><tableRow><tableCell></tableCell>[<tableCell></tableCell></tableRow></table><paragraph>b]ar</paragraph>
 				model.change( writer => {
-					writer.setSelection( ModelRange.createFromParentsAndOffsets(
-						modelRoot.getChild( 1 ).getChild( 0 ), 1,
-						modelRoot.getChild( 2 ), 1
+					writer.setSelection( writer.createRange(
+						writer.createPositionAt( modelRoot.getChild( 1 ).getChild( 0 ), 1 ),
+						writer.createPositionAt( modelRoot.getChild( 2 ), 1 )
 					) );
 				} );
 
@@ -145,9 +143,9 @@ describe( 'Selection post-fixer', () => {
 			it( 'should fix #3', () => {
 				// <paragraph>f[oo</paragraph><table>]<tableRow>...
 				model.change( writer => {
-					writer.setSelection( ModelRange.createFromParentsAndOffsets(
-						modelRoot.getChild( 0 ), 1,
-						modelRoot.getChild( 1 ), 0
+					writer.setSelection( writer.createRange(
+						writer.createPositionAt( modelRoot.getChild( 0 ), 1 ),
+						writer.createPositionAt( modelRoot.getChild( 1 ), 0 )
 					) );
 				} );
 
@@ -163,9 +161,9 @@ describe( 'Selection post-fixer', () => {
 			it( 'should fix #4', () => {
 				// <paragraph>foo</paragraph><table><tableRow><tableCell>a[aa</tableCell><tableCell>b]bb</tableCell>
 				model.change( writer => {
-					writer.setSelection( ModelRange.createFromParentsAndOffsets(
-						modelRoot.getChild( 1 ).getChild( 0 ).getChild( 0 ), 1,
-						modelRoot.getChild( 1 ).getChild( 0 ).getChild( 1 ), 2
+					writer.setSelection( writer.createRange(
+						writer.createPositionAt( modelRoot.getChild( 1 ).getChild( 0 ).getChild( 0 ), 1 ),
+						writer.createPositionAt( modelRoot.getChild( 1 ).getChild( 0 ).getChild( 1 ), 2 )
 					) );
 				} );
 
@@ -295,8 +293,14 @@ describe( 'Selection post-fixer', () => {
 			it( 'should fix multiple ranges #1', () => {
 				model.change( writer => {
 					const ranges = [
-						new ModelRange( new ModelPosition( modelRoot, [ 0, 1 ] ), new ModelPosition( modelRoot, [ 1, 0 ] ) ),
-						new ModelRange( new ModelPosition( modelRoot, [ 1, 0, 0, 0 ] ), new ModelPosition( modelRoot, [ 1, 1 ] ) )
+						writer.createRange(
+							writer.createPositionFromPath( modelRoot, [ 0, 1 ] ),
+							writer.createPositionFromPath( modelRoot, [ 1, 0 ] )
+						),
+						writer.createRange(
+							writer.createPositionFromPath( modelRoot, [ 1, 0, 0, 0 ] ),
+							writer.createPositionFromPath( modelRoot, [ 1, 1 ] )
+						)
 					];
 					writer.setSelection( ranges );
 				} );
@@ -313,8 +317,14 @@ describe( 'Selection post-fixer', () => {
 			it( 'should fix multiple ranges #2', () => {
 				model.change( writer => {
 					const ranges = [
-						new ModelRange( new ModelPosition( modelRoot, [ 0, 1 ] ), new ModelPosition( modelRoot, [ 1, 0 ] ) ),
-						new ModelRange( new ModelPosition( modelRoot, [ 1, 0, 0, 0 ] ), new ModelPosition( modelRoot, [ 2, 2 ] ) )
+						writer.createRange(
+							writer.createPositionFromPath( modelRoot, [ 0, 1 ] ),
+							writer.createPositionFromPath( modelRoot, [ 1, 0 ] )
+						),
+						writer.createRange(
+							writer.createPositionFromPath( modelRoot, [ 1, 0, 0, 0 ] ),
+							writer.createPositionFromPath( modelRoot, [ 2, 2 ] )
+						)
 					];
 
 					writer.setSelection( ranges );
@@ -356,9 +366,18 @@ describe( 'Selection post-fixer', () => {
 			it( 'should fix multiple ranges #4', () => {
 				model.change( writer => {
 					const ranges = [
-						new ModelRange( new ModelPosition( modelRoot, [ 0, 1 ] ), new ModelPosition( modelRoot, [ 1, 0 ] ) ),
-						new ModelRange( new ModelPosition( modelRoot, [ 1, 0, 0, 0 ] ), new ModelPosition( modelRoot, [ 2, 1 ] ) ),
-						new ModelRange( new ModelPosition( modelRoot, [ 2, 2 ] ), new ModelPosition( modelRoot, [ 2, 3 ] ) )
+						writer.createRange(
+							writer.createPositionFromPath( modelRoot, [ 0, 1 ] ),
+							writer.createPositionFromPath( modelRoot, [ 1, 0 ] )
+						),
+						writer.createRange(
+							writer.createPositionFromPath( modelRoot, [ 1, 0, 0, 0 ] ),
+							writer.createPositionFromPath( modelRoot, [ 2, 1 ] )
+						),
+						writer.createRange(
+							writer.createPositionFromPath( modelRoot, [ 2, 2 ] ),
+							writer.createPositionFromPath( modelRoot, [ 2, 3 ] )
+						)
 					];
 
 					writer.setSelection( ranges );
@@ -388,9 +407,9 @@ describe( 'Selection post-fixer', () => {
 			it( 'should fix #1 (crossing object and limit boundaries)', () => {
 				model.change( writer => {
 					// <paragraph>f[oo</paragraph><image><caption>x]xx</caption>...
-					writer.setSelection( ModelRange.createFromParentsAndOffsets(
-						modelRoot.getChild( 0 ), 1,
-						modelRoot.getChild( 1 ).getChild( 0 ), 1
+					writer.setSelection( writer.createRange(
+						writer.createPositionAt( modelRoot.getChild( 0 ), 1 ),
+						writer.createPositionAt( modelRoot.getChild( 1 ).getChild( 0 ), 1 )
 					) );
 				} );
 
@@ -406,9 +425,9 @@ describe( 'Selection post-fixer', () => {
 			it( 'should fix #2 (crossing object boundary)', () => {
 				model.change( writer => {
 					// <paragraph>f[oo</paragraph><image>]<caption>xxx</caption>...
-					writer.setSelection( ModelRange.createFromParentsAndOffsets(
-						modelRoot.getChild( 0 ), 1,
-						modelRoot.getChild( 1 ), 0
+					writer.setSelection( writer.createRange(
+						writer.createPositionAt( modelRoot.getChild( 0 ), 1 ),
+						writer.createPositionAt( modelRoot.getChild( 1 ), 0 )
 					) );
 				} );
 
@@ -424,9 +443,9 @@ describe( 'Selection post-fixer', () => {
 			it( 'should fix #3 (crossing object boundary)', () => {
 				model.change( writer => {
 					// <paragraph>f[oo</paragraph><image><caption>xxx</caption>]</image>...
-					writer.setSelection( ModelRange.createFromParentsAndOffsets(
-						modelRoot.getChild( 0 ), 1,
-						modelRoot.getChild( 1 ), 1
+					writer.setSelection( writer.createRange(
+						writer.createPositionAt( modelRoot.getChild( 0 ), 1 ),
+						writer.createPositionAt( modelRoot.getChild( 1 ), 1 )
 					) );
 				} );
 
@@ -442,9 +461,9 @@ describe( 'Selection post-fixer', () => {
 			it( 'should fix #4 (element selection of not an object)', () => {
 				model.change( writer => {
 					// <paragraph>foo</paragraph><image>[<caption>xxx</caption>]</image>...
-					writer.setSelection( ModelRange.createFromParentsAndOffsets(
-						modelRoot.getChild( 1 ), 0,
-						modelRoot.getChild( 1 ), 1
+					writer.setSelection( writer.createRange(
+						writer.createPositionAt( modelRoot.getChild( 1 ), 0 ),
+						writer.createPositionAt( modelRoot.getChild( 1 ), 1 )
 					) );
 				} );
 
@@ -460,9 +479,9 @@ describe( 'Selection post-fixer', () => {
 			it( 'should not fix #1 (element selection of an object)', () => {
 				model.change( writer => {
 					// <paragraph>foo</paragraph>[<image><caption>xxx</caption></image>]...
-					writer.setSelection( ModelRange.createFromParentsAndOffsets(
-						modelRoot, 1,
-						modelRoot, 2
+					writer.setSelection( writer.createRange(
+						writer.createPositionAt( modelRoot, 1 ),
+						writer.createPositionAt( modelRoot, 2 )
 					) );
 				} );
 
@@ -480,9 +499,9 @@ describe( 'Selection post-fixer', () => {
 					const caption = modelRoot.getChild( 1 ).getChild( 0 );
 
 					// <paragraph>foo</paragraph><image><caption>[xxx]</caption></image>...
-					writer.setSelection( ModelRange.createFromParentsAndOffsets(
-						caption, 0,
-						caption, 3
+					writer.setSelection( writer.createRange(
+						writer.createPositionAt( caption, 0 ),
+						writer.createPositionAt( caption, 3 )
 					) );
 				} );
 
@@ -500,9 +519,9 @@ describe( 'Selection post-fixer', () => {
 					const caption = modelRoot.getChild( 1 ).getChild( 0 );
 
 					// <paragraph>foo</paragraph><image><caption>[xx]x</caption></image>...
-					writer.setSelection( ModelRange.createFromParentsAndOffsets(
-						caption, 0,
-						caption, 2
+					writer.setSelection( writer.createRange(
+						writer.createPositionAt( caption, 0 ),
+						writer.createPositionAt( caption, 2 )
 					) );
 				} );
 
@@ -520,9 +539,9 @@ describe( 'Selection post-fixer', () => {
 					const caption = modelRoot.getChild( 1 ).getChild( 0 );
 
 					// <paragraph>foo</paragraph><image><caption>x[xx]</caption></image>...
-					writer.setSelection( ModelRange.createFromParentsAndOffsets(
-						caption, 1,
-						caption, 3
+					writer.setSelection( writer.createRange(
+						writer.createPositionAt( caption, 1 ),
+						writer.createPositionAt( caption, 3 )
 					) );
 				} );
 
@@ -713,7 +732,7 @@ describe( 'Selection post-fixer', () => {
 				// <table>[]<tableRow>...
 				model.change( writer => {
 					writer.setSelection(
-						ModelRange.createFromParentsAndOffsets( modelRoot.getChild( 1 ), 0, modelRoot.getChild( 1 ), 0 )
+						writer.createRange( writer.createPositionAt( modelRoot.getChild( 1 ), 0 ) )
 					);
 				} );
 
@@ -732,7 +751,7 @@ describe( 'Selection post-fixer', () => {
 					const row = modelRoot.getChild( 1 ).getChild( 0 );
 
 					writer.setSelection(
-						ModelRange.createFromParentsAndOffsets( row, 0, row, 0 )
+						writer.createRange( writer.createPositionAt( row, 0 ) )
 					);
 				} );
 
@@ -750,8 +769,8 @@ describe( 'Selection post-fixer', () => {
 				model.change( writer => {
 					writer.setSelection(
 						[
-							ModelRange.createFromParentsAndOffsets( modelRoot, 0, modelRoot, 0 ),
-							ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 1 )
+							writer.createRange( writer.createPositionAt( modelRoot, 0 ) ),
+							writer.createRange( writer.createPositionAt( modelRoot, 1 ) )
 						]
 					);
 				} );

+ 125 - 29
packages/ckeditor5-engine/tests/model/writer.js

@@ -925,8 +925,8 @@ describe( 'Writer', () => {
 
 			function getRange( startIndex, endIndex ) {
 				return new Range(
-					Position.createFromParentAndOffset( root, startIndex ),
-					Position.createFromParentAndOffset( root, endIndex )
+					Position._createAt( root, startIndex ),
+					Position._createAt( root, endIndex )
 				);
 			}
 
@@ -944,7 +944,7 @@ describe( 'Writer', () => {
 
 			function getCompressedAttrs() {
 				// default: 111---111222---1112------
-				const range = Range.createIn( root );
+				const range = Range._createIn( root );
 
 				return Array.from( range.getItems( { singleCharacters: true } ) )
 					.map( item => item.getAttribute( 'a' ) || '-' )
@@ -1218,7 +1218,7 @@ describe( 'Writer', () => {
 					appendElement( 'e', { a: 1 }, root );
 					appendText( 'xxx', root );
 
-					const range = Range.createIn( root );
+					const range = Range._createIn( root );
 
 					clearAttributes( range );
 
@@ -1286,7 +1286,7 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should set attributes one by one on range', () => {
-			const range = Range.createIn( frag );
+			const range = Range._createIn( frag );
 			let spy;
 
 			model.change( writer => {
@@ -1308,7 +1308,7 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should set attributes one by one on range for map as attributes list', () => {
-			const range = Range.createIn( frag );
+			const range = Range._createIn( frag );
 			let spy;
 
 			model.change( writer => {
@@ -1454,8 +1454,8 @@ describe( 'Writer', () => {
 		it( 'should move flat range of nodes', () => {
 			move( range, new Position( root, [ 1, 3 ] ) );
 
-			expect( getNodesAndText( Range.createIn( root.getChild( 0 ) ) ) ).to.equal( 'PggggPfoPhhhhP' );
-			expect( getNodesAndText( Range.createIn( root.getChild( 1 ) ) ) ).to.equal( 'abcobarxyz' );
+			expect( getNodesAndText( Range._createIn( root.getChild( 0 ) ) ) ).to.equal( 'PggggPfoPhhhhP' );
+			expect( getNodesAndText( Range._createIn( root.getChild( 1 ) ) ) ).to.equal( 'abcobarxyz' );
 		} );
 
 		it( 'should throw if object to move is not a range', () => {
@@ -1525,20 +1525,20 @@ describe( 'Writer', () => {
 
 				expect( root.maxOffset ).to.equal( 1 );
 				expect( root.childCount ).to.equal( 1 );
-				expect( getNodesAndText( Range.createIn( root.getChild( 0 ) ) ) ).to.equal( 'abcxyz' );
+				expect( getNodesAndText( Range._createIn( root.getChild( 0 ) ) ) ).to.equal( 'abcxyz' );
 			} );
 
 			it( 'should remove specified text node', () => {
 				remove( p.getChild( 0 ) );
 
-				expect( getNodesAndText( Range.createOn( p ) ) ).to.equal( 'PP' );
+				expect( getNodesAndText( Range._createOn( p ) ) ).to.equal( 'PP' );
 			} );
 
 			it( 'should remove any range of nodes', () => {
 				remove( range );
 
-				expect( getNodesAndText( Range.createIn( root.getChild( 0 ) ) ) ).to.equal( 'PggParPhhhhP' );
-				expect( getNodesAndText( Range.createIn( root.getChild( 1 ) ) ) ).to.equal( 'abcxyz' );
+				expect( getNodesAndText( Range._createIn( root.getChild( 0 ) ) ) ).to.equal( 'PggParPhhhhP' );
+				expect( getNodesAndText( Range._createIn( root.getChild( 1 ) ) ) ).to.equal( 'abcxyz' );
 			} );
 
 			it( 'should create minimal number of remove operations, each with only one operation', () => {
@@ -1582,20 +1582,20 @@ describe( 'Writer', () => {
 
 				expect( frag.maxOffset ).to.equal( 1 );
 				expect( frag.childCount ).to.equal( 1 );
-				expect( getNodesAndText( Range.createIn( frag.getChild( 0 ) ) ) ).to.equal( 'abcxyz' );
+				expect( getNodesAndText( Range._createIn( frag.getChild( 0 ) ) ) ).to.equal( 'abcxyz' );
 			} );
 
 			it( 'should remove specified text node', () => {
 				remove( p.getChild( 0 ) );
 
-				expect( getNodesAndText( Range.createOn( p ) ) ).to.equal( 'PP' );
+				expect( getNodesAndText( Range._createOn( p ) ) ).to.equal( 'PP' );
 			} );
 
 			it( 'should remove any range of nodes', () => {
 				remove( range );
 
-				expect( getNodesAndText( Range.createIn( frag.getChild( 0 ) ) ) ).to.equal( 'PggParPhhhhP' );
-				expect( getNodesAndText( Range.createIn( frag.getChild( 1 ) ) ) ).to.equal( 'abcxyz' );
+				expect( getNodesAndText( Range._createIn( frag.getChild( 0 ) ) ) ).to.equal( 'PggParPhhhhP' );
+				expect( getNodesAndText( Range._createIn( frag.getChild( 1 ) ) ) ).to.equal( 'abcxyz' );
 			} );
 
 			it( 'should create minimal number of remove operations, each with only one operation', () => {
@@ -1828,7 +1828,7 @@ describe( 'Writer', () => {
 		it( 'should wrap inside document fragment', () => {
 			const docFrag = new DocumentFragment( new Text( 'foo' ) );
 
-			wrap( Range.createIn( docFrag ), 'p' );
+			wrap( Range._createIn( docFrag ), 'p' );
 
 			expect( docFrag.maxOffset ).to.equal( 1 );
 			expect( docFrag.getChild( 0 ).name ).to.equal( 'p' );
@@ -1919,7 +1919,7 @@ describe( 'Writer', () => {
 		beforeEach( () => {
 			root = doc.createRoot();
 			root._appendChild( new Text( 'foo' ) );
-			range = Range.createIn( root );
+			range = Range._createIn( root );
 		} );
 
 		it( 'should throw if options.usingOperations is not defined', () => {
@@ -1979,7 +1979,7 @@ describe( 'Writer', () => {
 		it( 'should throw when trying to update existing marker in the document marker collection', () => {
 			addMarker( 'name', { range, usingOperation: false } );
 
-			const range2 = Range.createFromParentsAndOffsets( root, 0, root, 0 );
+			const range2 = new Range( Position._createAt( root, 0 ), Position._createAt( root, 0 ) );
 
 			expect( () => {
 				addMarker( 'name', { range: range2, usingOperation: false } );
@@ -2028,12 +2028,12 @@ describe( 'Writer', () => {
 		beforeEach( () => {
 			root = doc.createRoot();
 			root._appendChild( new Text( 'foo' ) );
-			range = Range.createIn( root );
+			range = Range._createIn( root );
 		} );
 
 		it( 'should update managed marker\'s range by marker instance using operations', () => {
 			const marker = addMarker( 'name', { range, usingOperation: true } );
-			const range2 = Range.createFromParentsAndOffsets( root, 0, root, 0 );
+			const range2 = new Range( Position._createAt( root, 0 ), Position._createAt( root, 0 ) );
 
 			updateMarker( marker, { range: range2 } );
 
@@ -2048,7 +2048,7 @@ describe( 'Writer', () => {
 
 		it( 'should update managed marker\'s range by marker name using operations', () => {
 			const marker = addMarker( 'name', { range, usingOperation: true } );
-			const range2 = Range.createFromParentsAndOffsets( root, 0, root, 0 );
+			const range2 = new Range( Position._createAt( root, 0 ), Position._createAt( root, 0 ) );
 
 			updateMarker( 'name', { range: range2 } );
 
@@ -2063,7 +2063,7 @@ describe( 'Writer', () => {
 
 		it( 'should update managed marker\'s range by marker instance using operations and usingOperation explicitly passed', () => {
 			const marker = addMarker( 'name', { range, usingOperation: true } );
-			const range2 = Range.createFromParentsAndOffsets( root, 0, root, 0 );
+			const range2 = new Range( Position._createAt( root, 0 ), Position._createAt( root, 0 ) );
 
 			updateMarker( marker, { range: range2, usingOperation: true } );
 
@@ -2078,7 +2078,7 @@ describe( 'Writer', () => {
 
 		it( 'should update managed marker\'s range by marker name using operations and usingOperation explicitly passed', () => {
 			const marker = addMarker( 'name', { range, usingOperation: true } );
-			const range2 = Range.createFromParentsAndOffsets( root, 0, root, 0 );
+			const range2 = new Range( Position._createAt( root, 0 ), Position._createAt( root, 0 ) );
 
 			updateMarker( 'name', { range: range2, usingOperation: true } );
 
@@ -2096,7 +2096,7 @@ describe( 'Writer', () => {
 			model.on( 'applyOperation', spy );
 
 			const marker = addMarker( 'name', { range, usingOperation: false } );
-			const range2 = Range.createFromParentsAndOffsets( root, 0, root, 0 );
+			const range2 = new Range( Position._createAt( root, 0 ), Position._createAt( root, 0 ) );
 
 			updateMarker( marker, { range: range2 } );
 
@@ -2131,7 +2131,7 @@ describe( 'Writer', () => {
 		it( 'should create additional operation when marker type changes to not managed using operation and changing its range', () => {
 			const spy = sinon.spy();
 			model.on( 'applyOperation', spy );
-			const range2 = Range.createFromParentsAndOffsets( root, 0, root, 0 );
+			const range2 = new Range( Position._createAt( root, 0 ), Position._createAt( root, 0 ) );
 
 			addMarker( 'name', { range, usingOperation: true } );
 			updateMarker( 'name', { range: range2, usingOperation: false } );
@@ -2174,7 +2174,7 @@ describe( 'Writer', () => {
 		it( 'should enable changing marker to be managed using operation while changing range', () => {
 			const spy = sinon.spy();
 			model.on( 'applyOperation', spy );
-			const range2 = Range.createFromParentsAndOffsets( root, 0, root, 0 );
+			const range2 = new Range( Position._createAt( root, 0 ), Position._createAt( root, 0 ) );
 
 			addMarker( 'name', { range, usingOperation: false } );
 			updateMarker( 'name', { range: range2, usingOperation: true } );
@@ -2212,7 +2212,7 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should not change affectsData property if not provided', () => {
-			const range2 = Range.createFromParentsAndOffsets( root, 0, root, 0 );
+			const range2 = new Range( Position._createAt( root, 0 ), Position._createAt( root, 0 ) );
 
 			addMarker( 'name', { range, affectsData: false, usingOperation: false } );
 			updateMarker( 'name', { range: range2 } );
@@ -2280,7 +2280,7 @@ describe( 'Writer', () => {
 		beforeEach( () => {
 			root = doc.createRoot();
 			root._appendChild( new Text( 'foo' ) );
-			range = Range.createIn( root );
+			range = Range._createIn( root );
 		} );
 
 		it( 'should remove marker from the document marker collection', () => {
@@ -2570,6 +2570,102 @@ describe( 'Writer', () => {
 		} );
 	} );
 
+	describe( 'createPositionFromPath()', () => {
+		it( 'should call model.createPositionFromPath()', () => {
+			const stub = sinon.stub( model, 'createPositionFromPath' );
+
+			model.change( writer => {
+				writer.createPositionFromPath();
+			} );
+
+			sinon.assert.calledOnce( stub );
+		} );
+	} );
+
+	describe( 'createPositionAt()', () => {
+		it( 'should call model.createPositionAt()', () => {
+			const stub = sinon.stub( model, 'createPositionAt' );
+
+			model.change( writer => {
+				writer.createPositionAt();
+			} );
+
+			sinon.assert.calledOnce( stub );
+		} );
+	} );
+
+	describe( 'createPositionAfter()', () => {
+		it( 'should call model.createPositionAfter()', () => {
+			const stub = sinon.stub( model, 'createPositionAfter' );
+
+			model.change( writer => {
+				writer.createPositionAfter();
+			} );
+
+			sinon.assert.calledOnce( stub );
+		} );
+	} );
+
+	describe( 'createPositionBefore()', () => {
+		it( 'should call model.createPositionBefore()', () => {
+			const stub = sinon.stub( model, 'createPositionBefore' );
+
+			model.change( writer => {
+				writer.createPositionBefore();
+			} );
+
+			sinon.assert.calledOnce( stub );
+		} );
+	} );
+
+	describe( 'createRange()', () => {
+		it( 'should call model.createRange()', () => {
+			const stub = sinon.stub( model, 'createRange' );
+
+			model.change( writer => {
+				writer.createRange();
+			} );
+
+			sinon.assert.calledOnce( stub );
+		} );
+	} );
+
+	describe( 'createRangeIn()', () => {
+		it( 'should call model.createRangeIn()', () => {
+			const stub = sinon.stub( model, 'createRangeIn' );
+
+			model.change( writer => {
+				writer.createRangeIn();
+			} );
+
+			sinon.assert.calledOnce( stub );
+		} );
+	} );
+
+	describe( 'createRangeOn()', () => {
+		it( 'should call model.createRangeOn()', () => {
+			const stub = sinon.stub( model, 'createRangeOn' );
+
+			model.change( writer => {
+				writer.createRangeOn();
+			} );
+
+			sinon.assert.calledOnce( stub );
+		} );
+	} );
+
+	describe( 'createSelection()', () => {
+		it( 'should call model.createSelection()', () => {
+			const stub = sinon.stub( model, 'createSelection' );
+
+			model.change( writer => {
+				writer.createSelection();
+			} );
+
+			sinon.assert.calledOnce( stub );
+		} );
+	} );
+
 	function createText( data, attributes ) {
 		return model.change( writer => {
 			return writer.createText( data, attributes );

+ 2 - 2
packages/ckeditor5-engine/tests/tickets/1267.js

@@ -41,7 +41,7 @@ describe( 'Bug ckeditor5-engine#1267', () => {
 
 		// Remove second paragraph where selection is placed.
 		model.enqueueChange( 'transparent', writer => {
-			writer.remove( Range.createFromPositionAndShift( new Position( model.document.getRoot(), [ 1 ] ), 1 ) );
+			writer.remove( Range._createFromPositionAndShift( new Position( model.document.getRoot(), [ 1 ] ), 1 ) );
 		} );
 
 		expect( getModelData( model ) ).to.equal( '<paragraph>foo bar baz[]</paragraph>' );
@@ -64,7 +64,7 @@ describe( 'Bug ckeditor5-engine#1267', () => {
 
 		// Remove second paragraph.
 		model.enqueueChange( 'transparent', writer => {
-			writer.remove( Range.createFromPositionAndShift( new Position( model.document.getRoot(), [ 1 ] ), 1 ) );
+			writer.remove( Range._createFromPositionAndShift( new Position( model.document.getRoot(), [ 1 ] ), 1 ) );
 		} );
 
 		// Selection attributes set by command should stay as they were.

+ 4 - 4
packages/ckeditor5-engine/tests/tickets/1281.js

@@ -47,11 +47,11 @@ describe( 'Bug ckeditor5-engine#1281', () => {
 
 		expect( selRanges.length ).to.equal( 2 );
 
-		assertPositions( Position.createAt( thirdParagraph, 0 ), selRanges[ 0 ].start );
-		assertPositions( Position.createAt( thirdParagraph, 'end' ), selRanges[ 0 ].end );
+		assertPositions( Position._createAt( thirdParagraph, 0 ), selRanges[ 0 ].start );
+		assertPositions( Position._createAt( thirdParagraph, 'end' ), selRanges[ 0 ].end );
 
-		assertPositions( Position.createAt( fourthParagraph, 0 ), selRanges[ 1 ].start );
-		assertPositions( Position.createAt( fourthParagraph, 'end' ), selRanges[ 1 ].end );
+		assertPositions( Position._createAt( fourthParagraph, 0 ), selRanges[ 1 ].start );
+		assertPositions( Position._createAt( fourthParagraph, 'end' ), selRanges[ 1 ].end );
 	} );
 
 	it( 'does not throw an error when content before the selection is being removed (last element is selected)', () => {

+ 1 - 2
packages/ckeditor5-engine/tests/tickets/1323.js

@@ -7,7 +7,6 @@ import EditingController from '../../src/controller/editingcontroller';
 
 import Model from '../../src/model/model';
 import ModelText from '../../src/model/text';
-import ModelRange from '../../src/model/range';
 
 import MarkerOperation from '../../src/model/operation/markeroperation';
 
@@ -20,7 +19,7 @@ describe( 'Bug ckeditor5-engine@1323', () => {
 			editing = new EditingController( model );
 			root = model.document.createRoot();
 			root._appendChild( new ModelText( 'foo' ) );
-			range = ModelRange.createFromParentsAndOffsets( root, 0, root, 0 );
+			range = model.createRange( model.createPositionAt( root, 0 ), model.createPositionAt( root, 0 ) );
 		} );
 
 		afterEach( () => {

+ 2 - 2
packages/ckeditor5-engine/tests/utils/bindtwostepcarettoattribute.js

@@ -789,7 +789,7 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 									const nextBlock = position.parent.nextSibling;
 
 									if ( nextBlock ) {
-										writer.setSelection( Position.createAt( nextBlock, 0 ) );
+										writer.setSelection( Position._createAt( nextBlock, 0 ) );
 									}
 								} else {
 									writer.setSelection( selection.getFirstPosition().getShiftedBy( 1 ) );
@@ -801,7 +801,7 @@ describe( 'bindTwoStepCaretToAttribute()', () => {
 									const previousBlock = position.parent.previousSibling;
 
 									if ( previousBlock ) {
-										writer.setSelection( Position.createAt( previousBlock, 'end' ) );
+										writer.setSelection( Position._createAt( previousBlock, 'end' ) );
 									}
 								} else {
 									writer.setSelection( selection.getFirstPosition().getShiftedBy( -1 ) );

+ 48 - 61
packages/ckeditor5-engine/tests/view/documentselection.js

@@ -14,19 +14,22 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import count from '@ckeditor/ckeditor5-utils/src/count';
 import createViewRoot from './_utils/createroot';
 import { parse } from '../../src/dev-utils/view';
+import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 
 describe( 'DocumentSelection', () => {
 	let documentSelection, el, range1, range2, range3;
 
+	testUtils.createSinonSandbox();
+
 	beforeEach( () => {
 		const text = new Text( 'xxxxxxxxxxxxxxxxxxxx' );
 		el = new Element( 'p', null, text );
 
 		documentSelection = new DocumentSelection();
 
-		range1 = Range.createFromParentsAndOffsets( text, 5, text, 10 );
-		range2 = Range.createFromParentsAndOffsets( text, 1, text, 2 );
-		range3 = Range.createFromParentsAndOffsets( text, 12, text, 14 );
+		range1 = Range._createFromParentsAndOffsets( text, 5, text, 10 );
+		range2 = Range._createFromParentsAndOffsets( text, 1, text, 2 );
+		range3 = Range._createFromParentsAndOffsets( text, 12, text, 14 );
 	} );
 
 	describe( 'constructor()', () => {
@@ -118,7 +121,7 @@ describe( 'DocumentSelection', () => {
 
 		it( 'should throw an error when ranges intersects', () => {
 			const text = el.getChild( 0 );
-			const range2 = Range.createFromParentsAndOffsets( text, 7, text, 15 );
+			const range2 = Range._createFromParentsAndOffsets( text, 7, text, 15 );
 
 			expect( () => {
 				// eslint-disable-next-line no-new
@@ -198,7 +201,7 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'throws if there are no ranges in selection', () => {
-			const endPos = Position.createAt( el, 'end' );
+			const endPos = Position._createAt( el, 'end' );
 
 			expect( () => {
 				documentSelection._setFocus( endPos );
@@ -206,8 +209,8 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'modifies existing collapsed selection', () => {
-			const startPos = Position.createAt( el, 1 );
-			const endPos = Position.createAt( el, 2 );
+			const startPos = Position._createAt( el, 1 );
+			const endPos = Position._createAt( el, 2 );
 
 			documentSelection._setTo( startPos );
 
@@ -218,8 +221,8 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'makes existing collapsed selection a backward selection', () => {
-			const startPos = Position.createAt( el, 1 );
-			const endPos = Position.createAt( el, 0 );
+			const startPos = Position._createAt( el, 1 );
+			const endPos = Position._createAt( el, 0 );
 
 			documentSelection._setTo( startPos );
 
@@ -231,9 +234,9 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'modifies existing non-collapsed selection', () => {
-			const startPos = Position.createAt( el, 1 );
-			const endPos = Position.createAt( el, 2 );
-			const newEndPos = Position.createAt( el, 3 );
+			const startPos = Position._createAt( el, 1 );
+			const endPos = Position._createAt( el, 2 );
+			const newEndPos = Position._createAt( el, 3 );
 
 			documentSelection._setTo( new Range( startPos, endPos ) );
 
@@ -244,9 +247,9 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'makes existing non-collapsed selection a backward selection', () => {
-			const startPos = Position.createAt( el, 1 );
-			const endPos = Position.createAt( el, 2 );
-			const newEndPos = Position.createAt( el, 0 );
+			const startPos = Position._createAt( el, 1 );
+			const endPos = Position._createAt( el, 2 );
+			const newEndPos = Position._createAt( el, 0 );
 
 			documentSelection._setTo( new Range( startPos, endPos ) );
 
@@ -258,9 +261,9 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'makes existing backward selection a forward selection', () => {
-			const startPos = Position.createAt( el, 1 );
-			const endPos = Position.createAt( el, 2 );
-			const newEndPos = Position.createAt( el, 3 );
+			const startPos = Position._createAt( el, 1 );
+			const endPos = Position._createAt( el, 2 );
+			const newEndPos = Position._createAt( el, 3 );
 
 			documentSelection._setTo( new Range( startPos, endPos ), { backward: true } );
 
@@ -272,9 +275,9 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'modifies existing backward selection', () => {
-			const startPos = Position.createAt( el, 1 );
-			const endPos = Position.createAt( el, 2 );
-			const newEndPos = Position.createAt( el, 0 );
+			const startPos = Position._createAt( el, 1 );
+			const endPos = Position._createAt( el, 2 );
+			const newEndPos = Position._createAt( el, 0 );
 
 			documentSelection._setTo( new Range( startPos, endPos ), { backward: true } );
 
@@ -287,12 +290,12 @@ describe( 'DocumentSelection', () => {
 
 		it( 'modifies only the last range', () => {
 			// Offsets are chosen in this way that the order of adding ranges must count, not their document order.
-			const startPos1 = Position.createAt( el, 4 );
-			const endPos1 = Position.createAt( el, 5 );
-			const startPos2 = Position.createAt( el, 1 );
-			const endPos2 = Position.createAt( el, 2 );
+			const startPos1 = Position._createAt( el, 4 );
+			const endPos1 = Position._createAt( el, 5 );
+			const startPos2 = Position._createAt( el, 1 );
+			const endPos2 = Position._createAt( el, 2 );
 
-			const newEndPos = Position.createAt( el, 0 );
+			const newEndPos = Position._createAt( el, 0 );
 
 			documentSelection._setTo( [
 				new Range( startPos1, endPos1 ),
@@ -313,8 +316,8 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'collapses the selection when extending to the anchor', () => {
-			const startPos = Position.createAt( el, 1 );
-			const endPos = Position.createAt( el, 2 );
+			const startPos = Position._createAt( el, 1 );
+			const endPos = Position._createAt( el, 2 );
 
 			documentSelection._setTo( new Range( startPos, endPos ) );
 
@@ -323,42 +326,26 @@ describe( 'DocumentSelection', () => {
 			expect( documentSelection.focus.compareWith( startPos ) ).to.equal( 'same' );
 			expect( documentSelection.isCollapsed ).to.be.true;
 		} );
-
-		it( 'uses Position.createAt', () => {
-			const startPos = Position.createAt( el, 1 );
-			const endPos = Position.createAt( el, 2 );
-			const newEndPos = Position.createAt( el, 4 );
-
-			const spy = sinon.stub( Position, 'createAt' ).returns( newEndPos );
-
-			documentSelection._setTo( new Range( startPos, endPos ) );
-			documentSelection._setFocus( el, 'end' );
-
-			expect( spy.calledOnce ).to.be.true;
-			expect( documentSelection.focus.compareWith( newEndPos ) ).to.equal( 'same' );
-
-			Position.createAt.restore();
-		} );
 	} );
 
 	describe( 'isCollapsed', () => {
 		it( 'should return true when there is single collapsed range', () => {
-			const range = Range.createFromParentsAndOffsets( el, 5, el, 5 );
+			const range = Range._createFromParentsAndOffsets( el, 5, el, 5 );
 			documentSelection._setTo( range );
 
 			expect( documentSelection.isCollapsed ).to.be.true;
 		} );
 
 		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 );
+			const range1 = Range._createFromParentsAndOffsets( el, 5, el, 5 );
+			const range2 = Range._createFromParentsAndOffsets( el, 15, el, 15 );
 			documentSelection._setTo( [ range1, range2 ] );
 
 			expect( documentSelection.isCollapsed ).to.be.false;
 		} );
 
 		it( 'should return false when there is not collapsed range', () => {
-			const range = Range.createFromParentsAndOffsets( el, 15, el, 16 );
+			const range = Range._createFromParentsAndOffsets( el, 15, el, 16 );
 			documentSelection._setTo( range );
 
 			expect( documentSelection.isCollapsed ).to.be.false;
@@ -381,8 +368,8 @@ describe( 'DocumentSelection', () => {
 
 	describe( 'isBackward', () => {
 		it( 'is defined by the last added range', () => {
-			const range1 = Range.createFromParentsAndOffsets( el, 5, el, 10 );
-			const range2 = Range.createFromParentsAndOffsets( el, 15, el, 16 );
+			const range1 = Range._createFromParentsAndOffsets( el, 5, el, 10 );
+			const range2 = Range._createFromParentsAndOffsets( el, 15, el, 16 );
 
 			documentSelection._setTo( range1, { backward: true } );
 			expect( documentSelection ).to.have.property( 'isBackward', true );
@@ -392,7 +379,7 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'is false when last range is collapsed', () => {
-			const range = Range.createFromParentsAndOffsets( el, 5, el, 5 );
+			const range = Range._createFromParentsAndOffsets( el, 5, el, 5 );
 
 			documentSelection._setTo( range, { backward: true } );
 
@@ -693,10 +680,10 @@ describe( 'DocumentSelection', () => {
 			const span2 = p2.getChild( 0 );
 
 			// <p>[<span>{]</span>}</p><p>[<span>{xx}</span>]</p>
-			const rangeA1 = Range.createFromParentsAndOffsets( p1, 0, span1, 0 );
-			const rangeB1 = Range.createFromParentsAndOffsets( span1, 0, p1, 1 );
-			const rangeA2 = Range.createFromParentsAndOffsets( p2, 0, p2, 1 );
-			const rangeB2 = Range.createFromParentsAndOffsets( span2, 0, span2, 1 );
+			const rangeA1 = Range._createFromParentsAndOffsets( p1, 0, span1, 0 );
+			const rangeB1 = Range._createFromParentsAndOffsets( span1, 0, p1, 1 );
+			const rangeA2 = Range._createFromParentsAndOffsets( p2, 0, p2, 1 );
+			const rangeB2 = Range._createFromParentsAndOffsets( span2, 0, span2, 1 );
 
 			documentSelection._setTo( [ rangeA1, rangeA2 ] );
 
@@ -721,10 +708,10 @@ describe( 'DocumentSelection', () => {
 			const span2 = p2.getChild( 0 );
 
 			// <p>[<span>{]</span>}</p><p>[<span>{xx}</span>]</p>
-			const rangeA1 = Range.createFromParentsAndOffsets( p1, 0, span1, 0 );
-			const rangeB1 = Range.createFromParentsAndOffsets( span1, 0, p1, 1 );
-			const rangeA2 = Range.createFromParentsAndOffsets( p2, 0, p2, 1 );
-			const rangeB2 = Range.createFromParentsAndOffsets( span2, 0, span2, 1 );
+			const rangeA1 = Range._createFromParentsAndOffsets( p1, 0, span1, 0 );
+			const rangeB1 = Range._createFromParentsAndOffsets( span1, 0, p1, 1 );
+			const rangeA2 = Range._createFromParentsAndOffsets( p2, 0, p2, 1 );
+			const rangeB2 = Range._createFromParentsAndOffsets( span2, 0, span2, 1 );
 
 			documentSelection._setTo( [ rangeA1, rangeA2 ] );
 
@@ -1009,7 +996,7 @@ describe( 'DocumentSelection', () => {
 
 			it( 'should throw when range is intersecting with already added range', () => {
 				const text = el.getChild( 0 );
-				const range2 = Range.createFromParentsAndOffsets( text, 7, text, 15 );
+				const range2 = Range._createFromParentsAndOffsets( text, 7, text, 15 );
 
 				expect( () => {
 					documentSelection._setTo( [ range1, range2 ] );
@@ -1079,7 +1066,7 @@ describe( 'DocumentSelection', () => {
 			const element = new Element( 'p' );
 			root._appendChild( element );
 
-			documentSelection._setTo( Range.createFromParentsAndOffsets( element, 0, element, 0 ) );
+			documentSelection._setTo( Range._createFromParentsAndOffsets( element, 0, element, 0 ) );
 
 			expect( documentSelection.editableElement ).to.equal( root );
 		} );

+ 1 - 1
packages/ckeditor5-engine/tests/view/domconverter/dom-to-view.js

@@ -871,7 +871,7 @@ describe( 'DomConverter', () => {
 	} );
 
 	describe( 'domRangeToView()', () => {
-		it( 'should converter DOM range', () => {
+		it( 'should convert DOM range', () => {
 			const domFoo = document.createTextNode( 'foo' );
 			const domBar = document.createTextNode( 'bar' );
 			const domB = createElement( document, 'b', null, domBar );

+ 4 - 4
packages/ckeditor5-engine/tests/view/downcastwriter/breakattributes.js

@@ -154,7 +154,7 @@ describe( 'DowncastWriter', () => {
 				const p2 = new ContainerElement( 'p' );
 
 				expect( () => {
-					writer.breakAttributes( Range.createFromParentsAndOffsets( p1, 0, p2, 0 ) );
+					writer.breakAttributes( Range._createFromParentsAndOffsets( p1, 0, p2, 0 ) );
 				} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
 			} );
 
@@ -162,7 +162,7 @@ describe( 'DowncastWriter', () => {
 				const el = new AttributeElement( 'b' );
 
 				expect( () => {
-					writer.breakAttributes( Range.createFromParentsAndOffsets( el, 0, el, 0 ) );
+					writer.breakAttributes( Range._createFromParentsAndOffsets( el, 0, el, 0 ) );
 				} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
 			} );
 
@@ -252,7 +252,7 @@ describe( 'DowncastWriter', () => {
 				const img = new EmptyElement( 'img' );
 				const b = new AttributeElement( 'b' );
 				new ContainerElement( 'p', null, [ img, b ] ); // eslint-disable-line no-new
-				const range = Range.createFromParentsAndOffsets( img, 0, b, 0 );
+				const range = Range._createFromParentsAndOffsets( img, 0, b, 0 );
 
 				expect( () => {
 					writer.breakAttributes( range );
@@ -273,7 +273,7 @@ describe( 'DowncastWriter', () => {
 				const span = new UIElement( 'span' );
 				const b = new AttributeElement( 'b' );
 				new ContainerElement( 'p', null, [ span, b ] ); // eslint-disable-line no-new
-				const range = Range.createFromParentsAndOffsets( span, 0, b, 0 );
+				const range = Range._createFromParentsAndOffsets( span, 0, b, 0 );
 
 				expect( () => {
 					writer.breakAttributes( range );

+ 1 - 1
packages/ckeditor5-engine/tests/view/downcastwriter/breakcontainer.js

@@ -73,7 +73,7 @@ describe( 'DowncastWriter', () => {
 
 		it( 'should throw if position parent is root', () => {
 			const element = new ContainerElement( 'div' );
-			const position = Position.createAt( element, 0 );
+			const position = Position._createAt( element, 0 );
 
 			expect( () => {
 				writer.breakContainer( position );

+ 2 - 2
packages/ckeditor5-engine/tests/view/downcastwriter/clear.js

@@ -39,7 +39,7 @@ describe( 'DowncastWriter', () => {
 			const p2 = new ContainerElement( 'p' );
 
 			expect( () => {
-				writer.clear( Range.createFromParentsAndOffsets( p1, 0, p2, 0 ) );
+				writer.clear( Range._createFromParentsAndOffsets( p1, 0, p2, 0 ) );
 			} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
 		} );
 
@@ -47,7 +47,7 @@ describe( 'DowncastWriter', () => {
 			const el = new AttributeElement( 'b' );
 
 			expect( () => {
-				writer.clear( Range.createFromParentsAndOffsets( el, 0, el, 0 ) );
+				writer.clear( Range._createFromParentsAndOffsets( el, 0, el, 0 ) );
 			} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
 		} );
 

+ 6 - 6
packages/ckeditor5-engine/tests/view/downcastwriter/move.js

@@ -118,7 +118,7 @@ describe( 'DowncastWriter', () => {
 		it( 'should correctly move text nodes inside same parent', () => {
 			const { view, selection } = parse( '<container:p>[<attribute:b>a</attribute:b>]b<attribute:b>c</attribute:b></container:p>' );
 
-			const newRange = writer.move( selection.getFirstRange(), Position.createAt( view, 2 ) );
+			const newRange = writer.move( selection.getFirstRange(), Position._createAt( view, 2 ) );
 
 			const expectedView = '<container:p>b[<attribute:b>a}c</attribute:b></container:p>';
 			expect( stringify( view, newRange, { showType: true } ) ).to.equal( expectedView );
@@ -130,7 +130,7 @@ describe( 'DowncastWriter', () => {
 			);
 
 			const viewText = view.getChild( 3 );
-			const newRange = writer.move( selection.getFirstRange(), Position.createAt( viewText, 1 ) );
+			const newRange = writer.move( selection.getFirstRange(), Position._createAt( viewText, 1 ) );
 
 			expect( stringify( view, newRange, { showType: true } ) ).to.equal(
 				'<container:p><attribute:b>ad</attribute:b>y[<attribute:b>b</attribute:b>xx<attribute:b>c</attribute:b>]y</container:p>'
@@ -149,7 +149,7 @@ describe( 'DowncastWriter', () => {
 		it( 'should throw if trying to move to EmptyElement', () => {
 			const srcAttribute = new AttributeElement( 'b' );
 			const srcContainer = new ContainerElement( 'p', null, srcAttribute );
-			const srcRange = Range.createFromParentsAndOffsets( srcContainer, 0, srcContainer, 1 );
+			const srcRange = Range._createFromParentsAndOffsets( srcContainer, 0, srcContainer, 1 );
 
 			const dstEmpty = new EmptyElement( 'img' );
 			new ContainerElement( 'p', null, dstEmpty ); // eslint-disable-line no-new
@@ -172,7 +172,7 @@ describe( 'DowncastWriter', () => {
 		it( 'should throw if trying to move to UIElement', () => {
 			const srcAttribute = new AttributeElement( 'b' );
 			const srcContainer = new ContainerElement( 'p', null, srcAttribute );
-			const srcRange = Range.createFromParentsAndOffsets( srcContainer, 0, srcContainer, 1 );
+			const srcRange = Range._createFromParentsAndOffsets( srcContainer, 0, srcContainer, 1 );
 
 			const dstUI = new UIElement( 'span' );
 			new ContainerElement( 'p', null, dstUI ); // eslint-disable-line no-new
@@ -204,11 +204,11 @@ describe( 'DowncastWriter', () => {
 
 			expect( mapper.markerNameToElements( 'foo' ).size ).to.equal( 2 );
 
-			writer.remove( Range.createOn( attrElemA ) );
+			writer.remove( writer.createRangeOn( attrElemA ) );
 
 			expect( mapper.markerNameToElements( 'foo' ).size ).to.equal( 1 );
 
-			writer.move( Range.createOn( attrElemB ), new Position( dstContainer, 0 ) );
+			writer.move( writer.createRangeOn( attrElemB ), new Position( dstContainer, 0 ) );
 
 			expect( mapper.markerNameToElements( 'foo' ).size ).to.equal( 1 );
 		} );

+ 5 - 5
packages/ckeditor5-engine/tests/view/downcastwriter/remove.js

@@ -45,7 +45,7 @@ describe( 'DowncastWriter', () => {
 			const p2 = new ContainerElement( 'p' );
 
 			expect( () => {
-				writer.remove( Range.createFromParentsAndOffsets( p1, 0, p2, 0 ) );
+				writer.remove( Range._createFromParentsAndOffsets( p1, 0, p2, 0 ) );
 			} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
 		} );
 
@@ -53,13 +53,13 @@ describe( 'DowncastWriter', () => {
 			const el = new AttributeElement( 'b' );
 
 			expect( () => {
-				writer.remove( Range.createFromParentsAndOffsets( el, 0, el, 0 ) );
+				writer.remove( Range._createFromParentsAndOffsets( el, 0, el, 0 ) );
 			} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
 		} );
 
 		it( 'should return empty DocumentFragment when range is collapsed', () => {
 			const p = new ContainerElement( 'p' );
-			const range = Range.createFromParentsAndOffsets( p, 0, p, 0 );
+			const range = Range._createFromParentsAndOffsets( p, 0, p, 0 );
 			const fragment = writer.remove( range );
 
 			expect( fragment ).to.be.instanceof( DocumentFragment );
@@ -131,7 +131,7 @@ describe( 'DowncastWriter', () => {
 			const emptyElement = new EmptyElement( 'img' );
 			const attributeElement = new AttributeElement( 'b' );
 			new ContainerElement( 'p', null, [ emptyElement, attributeElement ] ); // eslint-disable-line no-new
-			const range = Range.createFromParentsAndOffsets( emptyElement, 0, attributeElement, 0 );
+			const range = Range._createFromParentsAndOffsets( emptyElement, 0, attributeElement, 0 );
 
 			expect( () => {
 				writer.remove( range );
@@ -150,7 +150,7 @@ describe( 'DowncastWriter', () => {
 			const uiElement = new UIElement( 'span' );
 			const attributeElement = new AttributeElement( 'b' );
 			new ContainerElement( 'p', null, [ uiElement, attributeElement ] ); // eslint-disable-line no-new
-			const range = Range.createFromParentsAndOffsets( uiElement, 0, attributeElement, 0 );
+			const range = Range._createFromParentsAndOffsets( uiElement, 0, attributeElement, 0 );
 
 			expect( () => {
 				writer.remove( range );

+ 13 - 13
packages/ckeditor5-engine/tests/view/downcastwriter/unwrap.js

@@ -84,7 +84,7 @@ describe( 'DowncastWriter', () => {
 			const b = new AttributeElement( 'b' );
 
 			expect( () => {
-				writer.unwrap( Range.createFromParentsAndOffsets( el, 0, el, 0 ), b );
+				writer.unwrap( Range._createFromParentsAndOffsets( el, 0, el, 0 ), b );
 			} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
 		} );
 
@@ -347,7 +347,7 @@ describe( 'DowncastWriter', () => {
 			const empty = new EmptyElement( 'img' );
 			const attribute = new AttributeElement( 'b' );
 			const container = new ContainerElement( 'p', null, [ empty, attribute ] );
-			const range = Range.createFromParentsAndOffsets( empty, 0, container, 2 );
+			const range = Range._createFromParentsAndOffsets( empty, 0, container, 2 );
 
 			expect( () => {
 				writer.unwrap( range, attribute );
@@ -366,7 +366,7 @@ describe( 'DowncastWriter', () => {
 			const uiElement = new UIElement( 'span' );
 			const attribute = new AttributeElement( 'b' );
 			const container = new ContainerElement( 'p', null, [ uiElement, attribute ] );
-			const range = Range.createFromParentsAndOffsets( uiElement, 0, container, 2 );
+			const range = Range._createFromParentsAndOffsets( uiElement, 0, container, 2 );
 
 			expect( () => {
 				writer.unwrap( range, attribute );
@@ -378,8 +378,8 @@ describe( 'DowncastWriter', () => {
 			const attribute = writer.createAttributeElement( 'span', null, { id: 'foo' } );
 			const container = writer.createContainerElement( 'div' );
 
-			writer.insert( Position.createAt( container, 0 ), attribute );
-			writer.unwrap( Range.createOn( attribute ), unwrapper );
+			writer.insert( writer.createPositionAt( container, 0 ), attribute );
+			writer.unwrap( Range._createOn( attribute ), unwrapper );
 
 			expect( stringify( container, null, { showType: false, showPriority: false } ) ).to.equal( '<div></div>' );
 		} );
@@ -389,8 +389,8 @@ describe( 'DowncastWriter', () => {
 			const attribute = writer.createAttributeElement( 'span', { foo: 'foo' }, { id: 'foo' } );
 			const container = writer.createContainerElement( 'div' );
 
-			writer.insert( Position.createAt( container, 0 ), attribute );
-			writer.unwrap( Range.createOn( attribute ), unwrapper );
+			writer.insert( writer.createPositionAt( container, 0 ), attribute );
+			writer.unwrap( writer.createRangeOn( attribute ), unwrapper );
 
 			expect( stringify( container, null, { showType: false, showPriority: false } ) ).to.equal( '<div></div>' );
 		} );
@@ -403,8 +403,8 @@ describe( 'DowncastWriter', () => {
 			const attribute = writer.createAttributeElement( 'span', { foo: 'foo', bar: 'bar' }, { id: 'id' } );
 			const container = writer.createContainerElement( 'div' );
 
-			writer.insert( Position.createAt( container, 0 ), attribute );
-			writer.unwrap( Range.createOn( attribute ), unwrapper );
+			writer.insert( writer.createPositionAt( container, 0 ), attribute );
+			writer.unwrap( writer.createRangeOn( attribute ), unwrapper );
 
 			const view = stringify( container, null, { showType: false, showPriority: false } );
 			expect( view ).to.equal( '<div><span bar="bar" foo="foo"></span></div>' );
@@ -415,8 +415,8 @@ describe( 'DowncastWriter', () => {
 			const attribute = writer.createAttributeElement( 'span', { foo: 'foo', bar: 'bar' } );
 			const container = writer.createContainerElement( 'div' );
 
-			writer.insert( Position.createAt( container, 0 ), attribute );
-			writer.unwrap( Range.createOn( attribute ), unwrapper );
+			writer.insert( writer.createPositionAt( container, 0 ), attribute );
+			writer.unwrap( writer.createRangeOn( attribute ), unwrapper );
 
 			const view = stringify( container, null, { showType: false, showPriority: false } );
 			expect( view ).to.equal( '<div><span bar="bar" foo="foo"></span></div>' );
@@ -427,8 +427,8 @@ describe( 'DowncastWriter', () => {
 			const attribute = writer.createAttributeElement( 'span', { foo: 'foo', bar: 'bar' }, { id: 'b' } );
 			const container = writer.createContainerElement( 'div' );
 
-			writer.insert( Position.createAt( container, 0 ), attribute );
-			writer.unwrap( Range.createOn( attribute ), unwrapper );
+			writer.insert( writer.createPositionAt( container, 0 ), attribute );
+			writer.unwrap( writer.createRangeOn( attribute ), unwrapper );
 
 			const view = stringify( container, null, { showType: false, showPriority: false } );
 			expect( view ).to.equal( '<div><span bar="bar" foo="foo"></span></div>' );

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio