Sfoglia il codice sorgente

Merge branch 'master' into t/ckeditor5-alignment/16

Piotrek Koszuliński 7 anni fa
parent
commit
eb36b0dfdf
100 ha cambiato i file con 1185 aggiunte e 916 eliminazioni
  1. 1 0
      packages/ckeditor5-engine/src/controller/datacontroller.js
  2. 4 0
      packages/ckeditor5-engine/src/conversion/conversion.js
  3. 1 1
      packages/ckeditor5-engine/src/dataprocessor/htmldataprocessor.js
  4. 7 7
      packages/ckeditor5-engine/src/dev-utils/view.js
  5. 2 2
      packages/ckeditor5-engine/src/model/delta/basic-transformations.js
  6. 56 48
      packages/ckeditor5-engine/src/model/documentfragment.js
  7. 34 45
      packages/ckeditor5-engine/src/model/documentselection.js
  8. 75 63
      packages/ckeditor5-engine/src/model/element.js
  9. 17 15
      packages/ckeditor5-engine/src/model/model.js
  10. 50 37
      packages/ckeditor5-engine/src/model/node.js
  11. 6 3
      packages/ckeditor5-engine/src/model/nodelist.js
  12. 2 2
      packages/ckeditor5-engine/src/model/operation/insertoperation.js
  13. 2 2
      packages/ckeditor5-engine/src/model/operation/rootattributeoperation.js
  14. 10 10
      packages/ckeditor5-engine/src/model/operation/utils.js
  15. 1 0
      packages/ckeditor5-engine/src/model/position.js
  16. 24 7
      packages/ckeditor5-engine/src/model/text.js
  17. 1 1
      packages/ckeditor5-engine/src/model/utils/getselectedcontent.js
  18. 1 1
      packages/ckeditor5-engine/src/model/utils/insertcontent.js
  19. 10 0
      packages/ckeditor5-engine/src/model/writer.js
  20. 17 14
      packages/ckeditor5-engine/src/view/attributeelement.js
  21. 2 0
      packages/ckeditor5-engine/src/view/containerelement.js
  22. 8 7
      packages/ckeditor5-engine/src/view/documentfragment.js
  23. 3 1
      packages/ckeditor5-engine/src/view/domconverter.js
  24. 3 0
      packages/ckeditor5-engine/src/view/editableelement.js
  25. 119 97
      packages/ckeditor5-engine/src/view/element.js
  26. 6 2
      packages/ckeditor5-engine/src/view/emptyelement.js
  27. 4 0
      packages/ckeditor5-engine/src/view/matcher.js
  28. 5 3
      packages/ckeditor5-engine/src/view/node.js
  29. 2 0
      packages/ckeditor5-engine/src/view/position.js
  30. 2 0
      packages/ckeditor5-engine/src/view/range.js
  31. 1 0
      packages/ckeditor5-engine/src/view/renderer.js
  32. 1 0
      packages/ckeditor5-engine/src/view/rooteditableelement.js
  33. 13 13
      packages/ckeditor5-engine/src/view/selection.js
  34. 46 16
      packages/ckeditor5-engine/src/view/text.js
  35. 4 2
      packages/ckeditor5-engine/src/view/uielement.js
  36. 36 22
      packages/ckeditor5-engine/src/view/writer.js
  37. 2 2
      packages/ckeditor5-engine/tests/controller/editingcontroller.js
  38. 6 6
      packages/ckeditor5-engine/tests/conversion/downcast-converters.js
  39. 8 8
      packages/ckeditor5-engine/tests/conversion/downcast-selection-converters.js
  40. 7 7
      packages/ckeditor5-engine/tests/conversion/downcastdispatcher.js
  41. 2 2
      packages/ckeditor5-engine/tests/conversion/mapper.js
  42. 1 1
      packages/ckeditor5-engine/tests/conversion/viewconsumable.js
  43. 1 1
      packages/ckeditor5-engine/tests/dataprocessor/htmldataprocessor.js
  44. 1 1
      packages/ckeditor5-engine/tests/dataprocessor/xmldataprocessor.js
  45. 14 14
      packages/ckeditor5-engine/tests/dev-utils/enableenginedebug.js
  46. 8 8
      packages/ckeditor5-engine/tests/dev-utils/model.js
  47. 2 2
      packages/ckeditor5-engine/tests/dev-utils/view.js
  48. 9 12
      packages/ckeditor5-engine/tests/manual/tickets/475/1.js
  49. 1 1
      packages/ckeditor5-engine/tests/model/delta/renamedelta.js
  50. 1 1
      packages/ckeditor5-engine/tests/model/delta/transform/_utils/utils.js
  51. 1 1
      packages/ckeditor5-engine/tests/model/delta/transform/splitdelta.js
  52. 1 1
      packages/ckeditor5-engine/tests/model/delta/transform/transform.js
  53. 10 10
      packages/ckeditor5-engine/tests/model/differ.js
  54. 1 1
      packages/ckeditor5-engine/tests/model/document.js
  55. 11 11
      packages/ckeditor5-engine/tests/model/documentfragment.js
  56. 45 27
      packages/ckeditor5-engine/tests/model/documentselection.js
  57. 16 16
      packages/ckeditor5-engine/tests/model/element.js
  58. 1 1
      packages/ckeditor5-engine/tests/model/liveposition.js
  59. 1 1
      packages/ckeditor5-engine/tests/model/liverange.js
  60. 1 1
      packages/ckeditor5-engine/tests/model/markercollection.js
  61. 21 21
      packages/ckeditor5-engine/tests/model/node.js
  62. 7 7
      packages/ckeditor5-engine/tests/model/nodelist.js
  63. 17 17
      packages/ckeditor5-engine/tests/model/operation/attributeoperation.js
  64. 1 1
      packages/ckeditor5-engine/tests/model/operation/detachoperation.js
  65. 1 1
      packages/ckeditor5-engine/tests/model/operation/insertoperation.js
  66. 1 1
      packages/ckeditor5-engine/tests/model/operation/markeroperation.js
  67. 13 13
      packages/ckeditor5-engine/tests/model/operation/moveoperation.js
  68. 3 3
      packages/ckeditor5-engine/tests/model/operation/reinsertoperation.js
  69. 4 4
      packages/ckeditor5-engine/tests/model/operation/removeoperation.js
  70. 1 1
      packages/ckeditor5-engine/tests/model/operation/renameoperation.js
  71. 6 6
      packages/ckeditor5-engine/tests/model/operation/rootattributeoperation.js
  72. 1 1
      packages/ckeditor5-engine/tests/model/operation/utils.js
  73. 3 3
      packages/ckeditor5-engine/tests/model/position.js
  74. 9 9
      packages/ckeditor5-engine/tests/model/range.js
  75. 8 8
      packages/ckeditor5-engine/tests/model/schema.js
  76. 2 2
      packages/ckeditor5-engine/tests/model/selection.js
  77. 2 2
      packages/ckeditor5-engine/tests/model/text.js
  78. 2 2
      packages/ckeditor5-engine/tests/model/textproxy.js
  79. 1 1
      packages/ckeditor5-engine/tests/model/treewalker.js
  80. 2 2
      packages/ckeditor5-engine/tests/model/utils-tests/utils.js
  81. 6 6
      packages/ckeditor5-engine/tests/model/utils/deletecontent.js
  82. 41 25
      packages/ckeditor5-engine/tests/model/writer.js
  83. 75 0
      packages/ckeditor5-engine/tests/tickets/1267.js
  84. 1 1
      packages/ckeditor5-engine/tests/tickets/1323.js
  85. 2 2
      packages/ckeditor5-engine/tests/view/attributeelement.js
  86. 32 32
      packages/ckeditor5-engine/tests/view/documentfragment.js
  87. 11 11
      packages/ckeditor5-engine/tests/view/domconverter/view-to-dom.js
  88. 1 1
      packages/ckeditor5-engine/tests/view/editableelement.js
  89. 37 37
      packages/ckeditor5-engine/tests/view/element.js
  90. 6 6
      packages/ckeditor5-engine/tests/view/emptyelement.js
  91. 1 1
      packages/ckeditor5-engine/tests/view/manual/uielement.js
  92. 20 20
      packages/ckeditor5-engine/tests/view/node.js
  93. 1 1
      packages/ckeditor5-engine/tests/view/observer/domeventobserver.js
  94. 19 19
      packages/ckeditor5-engine/tests/view/observer/mutationobserver.js
  95. 1 1
      packages/ckeditor5-engine/tests/view/observer/selectionobserver.js
  96. 83 83
      packages/ckeditor5-engine/tests/view/renderer.js
  97. 1 1
      packages/ckeditor5-engine/tests/view/rooteditableelement.js
  98. 1 1
      packages/ckeditor5-engine/tests/view/selection.js
  99. 13 5
      packages/ckeditor5-engine/tests/view/text.js
  100. 1 1
      packages/ckeditor5-engine/tests/view/treewalker.js

+ 1 - 0
packages/ckeditor5-engine/src/controller/datacontroller.js

@@ -66,6 +66,7 @@ export default class DataController {
 		 * cleared directly after the data are converted. However, the mapper is defined as a class property, because
 		 * it needs to be passed to the `DowncastDispatcher` as a conversion API.
 		 *
+		 * @readonly
 		 * @member {module:engine/conversion/mapper~Mapper}
 		 */
 		this.mapper = new Mapper();

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

@@ -29,6 +29,10 @@ export default class Conversion {
 	 * Creates new Conversion instance.
 	 */
 	constructor() {
+		/**
+		 * @private
+		 * @member {Map}
+		 */
 		this._dispatchersGroups = new Map();
 	}
 

+ 1 - 1
packages/ckeditor5-engine/src/dataprocessor/htmldataprocessor.js

@@ -36,7 +36,7 @@ export default class HtmlDataProcessor {
 		 * A DOM converter used to convert DOM elements to view elements.
 		 *
 		 * @private
-		 * @member
+		 * @member {module:engine/view/domconverter~DomConverter}
 		 */
 		this._domConverter = new DomConverter( { blockFiller: NBSP_FILLER } );
 

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

@@ -322,10 +322,10 @@ export function parse( data, options = {} ) {
 	// If custom root is provided - move all nodes there.
 	if ( options.rootElement ) {
 		const root = options.rootElement;
-		const nodes = view.removeChildren( 0, view.childCount );
+		const nodes = view._removeChildren( 0, view.childCount );
 
-		root.removeChildren( 0, root.childCount );
-		root.appendChildren( nodes );
+		root._removeChildren( 0, root.childCount );
+		root._appendChildren( nodes );
 
 		view = root;
 	}
@@ -350,7 +350,7 @@ export function parse( data, options = {} ) {
 
 	// If single element is returned without selection - remove it from parent and return detached element.
 	if ( view.parent ) {
-		view.remove();
+		view._remove();
 	}
 
 	return view;
@@ -449,13 +449,13 @@ class RangeParser {
 			}
 
 			text = text.replace( regexp, '' );
-			node.data = text;
+			node._data = text;
 			const index = node.index;
 			const parent = node.parent;
 
 			// Remove empty text nodes.
 			if ( !text ) {
-				node.remove();
+				node._remove();
 			}
 
 			for ( const item of brackets ) {
@@ -887,7 +887,7 @@ function _convertViewElements( rootNode ) {
 				throw new Error( 'Parse error - cannot parse inside UIElement.' );
 			}
 
-			convertedElement.appendChildren( _convertViewElements( child ) );
+			convertedElement._appendChildren( _convertViewElements( child ) );
 		}
 
 		return convertedElement;

+ 2 - 2
packages/ckeditor5-engine/src/model/delta/basic-transformations.js

@@ -369,9 +369,9 @@ addTransformationCase( SplitDelta, AttributeDelta, ( a, b, context ) => {
 	for ( const operation of b.operations ) {
 		if ( operation.range.containsPosition( splitPosition ) || operation.range.start.isEqual( splitPosition ) ) {
 			if ( operation.newValue !== null ) {
-				a._cloneOperation.nodes.getNode( 0 ).setAttribute( operation.key, operation.newValue );
+				a._cloneOperation.nodes.getNode( 0 )._setAttribute( operation.key, operation.newValue );
 			} else {
-				a._cloneOperation.nodes.getNode( 0 ).removeAttribute( operation.key );
+				a._cloneOperation.nodes.getNode( 0 )._removeAttribute( operation.key );
 			}
 
 			break;

+ 56 - 48
packages/ckeditor5-engine/src/model/documentfragment.js

@@ -25,6 +25,10 @@ export default class DocumentFragment {
 	/**
 	 * Creates an empty `DocumentFragment`.
 	 *
+	 * **Note:** Constructor of this class shouldn't be used directly in the code.
+	 * Use the {@link module:engine/model/writer~Writer#createDocumentFragment} method instead.
+	 *
+	 * @protected
 	 * @param {module:engine/model/node~Node|Iterable.<module:engine/model/node~Node>} [children]
 	 * Nodes to be contained inside the `DocumentFragment`.
 	 */
@@ -34,6 +38,7 @@ export default class DocumentFragment {
 		 * which will be set as Markers to {@link module:engine/model/model~Model#markers model markers collection}
 		 * when DocumentFragment will be inserted to the document.
 		 *
+		 * @readonly
 		 * @member {Map<String,module:engine/model/range~Range>} module:engine/model/documentfragment~DocumentFragment#markers
 		 */
 		this.markers = new Map();
@@ -47,7 +52,7 @@ export default class DocumentFragment {
 		this._children = new NodeList();
 
 		if ( children ) {
-			this.insertChildren( 0, children );
+			this._insertChildren( 0, children );
 		}
 	}
 
@@ -217,46 +222,88 @@ export default class DocumentFragment {
 	}
 
 	/**
-	 * {@link #insertChildren Inserts} one or more nodes at the end of this document fragment.
+	 * Converts `DocumentFragment` instance to plain object and returns it.
+	 * Takes care of converting all of this document fragment's children.
+	 *
+	 * @returns {Object} `DocumentFragment` instance converted to plain object.
+	 */
+	toJSON() {
+		const json = [];
+
+		for ( const node of this._children ) {
+			json.push( node.toJSON() );
+		}
+
+		return json;
+	}
+
+	/**
+	 * Creates a `DocumentFragment` instance from given plain object (i.e. parsed JSON string).
+	 * Converts `DocumentFragment` children to proper nodes.
+	 *
+	 * @param {Object} json Plain object to be converted to `DocumentFragment`.
+	 * @returns {module:engine/model/documentfragment~DocumentFragment} `DocumentFragment` instance created using given plain object.
+	 */
+	static fromJSON( json ) {
+		const children = [];
+
+		for ( const child of json ) {
+			if ( child.name ) {
+				// If child has name property, it is an Element.
+				children.push( Element.fromJSON( child ) );
+			} else {
+				// Otherwise, it is a Text node.
+				children.push( Text.fromJSON( child ) );
+			}
+		}
+
+		return new DocumentFragment( children );
+	}
+
+	/**
+	 * {@link #_insertChildren Inserts} one or more nodes at the end of this document fragment.
 	 *
+	 * @protected
 	 * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.
 	 */
-	appendChildren( items ) {
-		this.insertChildren( this.childCount, items );
+	_appendChildren( items ) {
+		this._insertChildren( this.childCount, items );
 	}
 
 	/**
 	 * Inserts one or more nodes at the given index and sets {@link module:engine/model/node~Node#parent parent} of these nodes
 	 * to this document fragment.
 	 *
+	 * @protected
 	 * @param {Number} index Index at which nodes should be inserted.
 	 * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.
 	 */
-	insertChildren( index, items ) {
+	_insertChildren( index, items ) {
 		const nodes = normalize( items );
 
 		for ( const node of nodes ) {
 			// If node that is being added to this element is already inside another element, first remove it from the old parent.
 			if ( node.parent !== null ) {
-				node.remove();
+				node._remove();
 			}
 
 			node.parent = this;
 		}
 
-		this._children.insertNodes( index, nodes );
+		this._children._insertNodes( index, nodes );
 	}
 
 	/**
 	 * Removes one or more nodes starting at the given index
 	 * and sets {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.
 	 *
+	 * @protected
 	 * @param {Number} index Index of the first node to remove.
 	 * @param {Number} [howMany=1] Number of nodes to remove.
 	 * @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.
 	 */
-	removeChildren( index, howMany = 1 ) {
-		const nodes = this._children.removeNodes( index, howMany );
+	_removeChildren( index, howMany = 1 ) {
+		const nodes = this._children._removeNodes( index, howMany );
 
 		for ( const node of nodes ) {
 			node.parent = null;
@@ -264,45 +311,6 @@ export default class DocumentFragment {
 
 		return nodes;
 	}
-
-	/**
-	 * Converts `DocumentFragment` instance to plain object and returns it.
-	 * Takes care of converting all of this document fragment's children.
-	 *
-	 * @returns {Object} `DocumentFragment` instance converted to plain object.
-	 */
-	toJSON() {
-		const json = [];
-
-		for ( const node of this._children ) {
-			json.push( node.toJSON() );
-		}
-
-		return json;
-	}
-
-	/**
-	 * Creates a `DocumentFragment` instance from given plain object (i.e. parsed JSON string).
-	 * Converts `DocumentFragment` children to proper nodes.
-	 *
-	 * @param {Object} json Plain object to be converted to `DocumentFragment`.
-	 * @returns {module:engine/model/documentfragment~DocumentFragment} `DocumentFragment` instance created using given plain object.
-	 */
-	static fromJSON( json ) {
-		const children = [];
-
-		for ( const child of json ) {
-			if ( child.name ) {
-				// If child has name property, it is an Element.
-				children.push( Element.fromJSON( child ) );
-			} else {
-				// Otherwise, it is a Text node.
-				children.push( Text.fromJSON( child ) );
-			}
-		}
-
-		return new DocumentFragment( children );
-	}
 }
 
 // Converts strings to Text and non-iterables to arrays.

+ 34 - 45
packages/ckeditor5-engine/src/model/documentselection.js

@@ -19,10 +19,6 @@ import toMap from '@ckeditor/ckeditor5-utils/src/tomap';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import log from '@ckeditor/ckeditor5-utils/src/log';
 
-const attrOpTypes = new Set(
-	[ 'addAttribute', 'removeAttribute', 'changeAttribute', 'addRootAttribute', 'removeRootAttribute', 'changeRootAttribute' ]
-);
-
 const storePrefix = 'selection:';
 
 /**
@@ -533,29 +529,13 @@ class LiveSelection extends Selection {
 			}
 		} );
 
-		this.listenTo( this._model, 'applyOperation', ( evt, args ) => {
-			const operation = args[ 0 ];
-
-			if ( !operation.isDocumentOperation ) {
-				return;
-			}
-
-			// Whenever attribute operation is performed on document, update selection attributes.
-			// This is not the most efficient way to update selection attributes, but should be okay for now.
-			if ( attrOpTypes.has( operation.type ) ) {
-				this._updateAttributes( false );
-			}
-
-			const batch = operation.delta.batch;
+		this.listenTo( this._document, 'change', ( evt, batch ) => {
+			// Update selection's attributes.
+			this._updateAttributes( false );
 
-			// Batch may not be passed to the document#change event in some tests.
-			// See https://github.com/ckeditor/ckeditor5-engine/issues/1001#issuecomment-314202352
-			if ( batch ) {
-				// Whenever element which had selection's attributes stored in it stops being empty,
-				// the attributes need to be removed.
-				clearAttributesStoredInElement( operation, this._model, batch );
-			}
-		}, { priority: 'low' } );
+			// Clear selection attributes from element if no longer empty.
+			clearAttributesStoredInElement( this._model, batch );
+		} );
 
 		this.listenTo( this._model, 'applyOperation', () => {
 			while ( this._fixGraveyardRangesData.length ) {
@@ -823,6 +803,9 @@ class LiveSelection extends Selection {
 	// Internal method for removing `LiveSelection` attribute. Supports attribute priorities (through `directChange`
 	// parameter).
 	//
+	// NOTE: Even if attribute is not present in the selection but is provided to this method, it's priority will
+	// be changed according to `directChange` parameter.
+	//
 	// @private
 	// @param {String} key Attribute key.
 	// @param {Boolean} [directChange=true] `true` if the change is caused by `Selection` API, `false` if change
@@ -837,6 +820,9 @@ class LiveSelection extends Selection {
 			return false;
 		}
 
+		// Update priorities map.
+		this._attributePriority.set( key, priority );
+
 		// Don't do anything if value has not changed.
 		if ( !super.hasAttribute( key ) ) {
 			return false;
@@ -844,9 +830,6 @@ class LiveSelection extends Selection {
 
 		this._attrs.delete( key );
 
-		// Update priorities map.
-		this._attributePriority.set( key, priority );
-
 		return true;
 	}
 
@@ -1021,24 +1004,30 @@ function getAttrsIfCharacter( node ) {
 }
 
 // Removes selection attributes from element which is not empty anymore.
-function clearAttributesStoredInElement( operation, model, batch ) {
-	let changeParent = null;
-
-	if ( operation.type == 'insert' ) {
-		changeParent = operation.position.parent;
-	} else if ( operation.type == 'move' || operation.type == 'reinsert' || operation.type == 'remove' ) {
-		changeParent = operation.getMovedRangeStart().parent;
-	}
+//
+// @private
+// @param {module:engine/model/model~Model} model
+// @param {module:engine/model/batch~Batch} batch
+function clearAttributesStoredInElement( model, batch ) {
+	const differ = model.document.differ;
+
+	for ( const entry of differ.getChanges() ) {
+		if ( entry.type != 'insert' ) {
+			continue;
+		}
 
-	if ( !changeParent || changeParent.isEmpty ) {
-		return;
-	}
+		const changeParent = entry.position.parent;
+		const isNoLongerEmpty = entry.length === changeParent.maxOffset;
 
-	model.enqueueChange( batch, writer => {
-		const storedAttributes = Array.from( changeParent.getAttributeKeys() ).filter( key => key.startsWith( storePrefix ) );
+		if ( isNoLongerEmpty ) {
+			model.enqueueChange( batch, writer => {
+				const storedAttributes = Array.from( changeParent.getAttributeKeys() )
+					.filter( key => key.startsWith( storePrefix ) );
 
-		for ( const key of storedAttributes ) {
-			writer.removeAttribute( key, changeParent );
+				for ( const key of storedAttributes ) {
+					writer.removeAttribute( key, changeParent );
+				}
+			} );
 		}
-	} );
+	}
 }

+ 75 - 63
packages/ckeditor5-engine/src/model/element.js

@@ -25,6 +25,10 @@ export default class Element extends Node {
 	/**
 	 * Creates a model element.
 	 *
+	 * **Note:** Constructor of this class shouldn't be used directly in the code.
+	 * Use the {@link module:engine/model/writer~Writer#createElement} method instead.
+	 *
+	 * @protected
 	 * @param {String} name Element's name.
 	 * @param {Object} [attrs] Element's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.
 	 * @param {module:engine/model/node~Node|Iterable.<module:engine/model/node~Node>} [children]
@@ -36,6 +40,7 @@ export default class Element extends Node {
 		/**
 		 * Element name.
 		 *
+		 * @readonly
 		 * @member {String} module:engine/model/element~Element#name
 		 */
 		this.name = name;
@@ -49,7 +54,7 @@ export default class Element extends Node {
 		this._children = new NodeList();
 
 		if ( children ) {
-			this.insertChildren( 0, children );
+			this._insertChildren( 0, children );
 		}
 	}
 
@@ -151,19 +156,6 @@ export default class Element extends Node {
 		return this._children.getNodeStartOffset( node );
 	}
 
-	/**
-	 * Creates a copy of this element and returns it. Created element has the same name and attributes as the original element.
-	 * If clone is deep, the original element's children are also cloned. If not, then empty element is removed.
-	 *
-	 * @param {Boolean} [deep=false] If set to `true` clones element and all its children recursively. When set to `false`,
-	 * element will be cloned without any child.
-	 */
-	clone( deep = false ) {
-		const children = deep ? Array.from( this._children ).map( node => node.clone( true ) ) : null;
-
-		return new Element( this.name, this.getAttributes(), children );
-	}
-
 	/**
 	 * Returns index of a node that occupies given offset. If given offset is too low, returns `0`. If given offset is
 	 * too high, returns {@link module:engine/model/element~Element#getChildIndex index after last child}.
@@ -185,55 +177,6 @@ export default class Element extends Node {
 		return this._children.offsetToIndex( offset );
 	}
 
-	/**
-	 * {@link module:engine/model/element~Element#insertChildren Inserts} one or more nodes at the end of this element.
-	 *
-	 * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} nodes Nodes to be inserted.
-	 */
-	appendChildren( nodes ) {
-		this.insertChildren( this.childCount, nodes );
-	}
-
-	/**
-	 * Inserts one or more nodes at the given index and sets {@link module:engine/model/node~Node#parent parent} of these nodes
-	 * to this element.
-	 *
-	 * @param {Number} index Index at which nodes should be inserted.
-	 * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.
-	 */
-	insertChildren( index, items ) {
-		const nodes = normalize( items );
-
-		for ( const node of nodes ) {
-			// If node that is being added to this element is already inside another element, first remove it from the old parent.
-			if ( node.parent !== null ) {
-				node.remove();
-			}
-
-			node.parent = this;
-		}
-
-		this._children.insertNodes( index, nodes );
-	}
-
-	/**
-	 * Removes one or more nodes starting at the given index and sets
-	 * {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.
-	 *
-	 * @param {Number} index Index of the first node to remove.
-	 * @param {Number} [howMany=1] Number of nodes to remove.
-	 * @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.
-	 */
-	removeChildren( index, howMany = 1 ) {
-		const nodes = this._children.removeNodes( index, howMany );
-
-		for ( const node of nodes ) {
-			node.parent = null;
-		}
-
-		return nodes;
-	}
-
 	/**
 	 * Returns a descendant node by its path relative to this element.
 	 *
@@ -276,6 +219,75 @@ export default class Element extends Node {
 		return json;
 	}
 
+	/**
+	 * Creates a copy of this element and returns it. Created element has the same name and attributes as the original element.
+	 * If clone is deep, the original element's children are also cloned. If not, then empty element is removed.
+	 *
+	 * @protected
+	 * @param {Boolean} [deep=false] If set to `true` clones element and all its children recursively. When set to `false`,
+	 * element will be cloned without any child.
+	 */
+	_clone( deep = false ) {
+		const children = deep ? Array.from( this._children ).map( node => node._clone( true ) ) : null;
+
+		return new Element( this.name, this.getAttributes(), children );
+	}
+
+	/**
+	 * {@link module:engine/model/element~Element#_insertChildren Inserts} one or more nodes at the end of this element.
+	 *
+	 * @see module:engine/model/writer~Writer#append
+	 * @protected
+	 * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} nodes Nodes to be inserted.
+	 */
+	_appendChildren( nodes ) {
+		this._insertChildren( this.childCount, nodes );
+	}
+
+	/**
+	 * Inserts one or more nodes at the given index and sets {@link module:engine/model/node~Node#parent parent} of these nodes
+	 * to this element.
+	 *
+	 * @see module:engine/model/writer~Writer#insert
+	 * @protected
+	 * @param {Number} index Index at which nodes should be inserted.
+	 * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.
+	 */
+	_insertChildren( index, items ) {
+		const nodes = normalize( items );
+
+		for ( const node of nodes ) {
+			// If node that is being added to this element is already inside another element, first remove it from the old parent.
+			if ( node.parent !== null ) {
+				node._remove();
+			}
+
+			node.parent = this;
+		}
+
+		this._children._insertNodes( index, nodes );
+	}
+
+	/**
+	 * Removes one or more nodes starting at the given index and sets
+	 * {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.
+	 *
+	 * @see module:engine/model/writer~Writer#remove
+	 * @protected
+	 * @param {Number} index Index of the first node to remove.
+	 * @param {Number} [howMany=1] Number of nodes to remove.
+	 * @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.
+	 */
+	_removeChildren( index, howMany = 1 ) {
+		const nodes = this._children._removeNodes( index, howMany );
+
+		for ( const node of nodes ) {
+			node.parent = null;
+		}
+
+		return nodes;
+	}
+
 	/**
 	 * Creates an `Element` instance from given plain object (i.e. parsed JSON string).
 	 * Converts `Element` children to proper nodes.

+ 17 - 15
packages/ckeditor5-engine/src/model/model.js

@@ -39,15 +39,6 @@ import getSelectedContent from './utils/getselectedcontent';
  */
 export default class Model {
 	constructor() {
-		/**
-		 * All callbacks added by {@link module:engine/model/model~Model#change} or
-		 * {@link module:engine/model/model~Model#enqueueChange} methods waiting to be executed.
-		 *
-		 * @private
-		 * @type {Array.<Function>}
-		 */
-		this._pendingChanges = [];
-
 		/**
 		 * Models markers' collection.
 		 *
@@ -59,24 +50,35 @@ export default class Model {
 		/**
 		 * Editors document model.
 		 *
+		 * @readonly
 		 * @member {module:engine/model/document~Document}
 		 */
 		this.document = new Document( this );
 
 		/**
-		 * The last created and currently used writer instance.
+		 * Schema for editors model.
+		 *
+		 * @readonly
+		 * @member {module:engine/model/schema~Schema}
+		 */
+		this.schema = new Schema();
+
+		/**
+		 * All callbacks added by {@link module:engine/model/model~Model#change} or
+		 * {@link module:engine/model/model~Model#enqueueChange} methods waiting to be executed.
 		 *
 		 * @private
-		 * @member {module:engine/model/writer~Writer}
+		 * @type {Array.<Function>}
 		 */
-		this._currentWriter = null;
+		this._pendingChanges = [];
 
 		/**
-		 * Schema for editors model.
+		 * The last created and currently used writer instance.
 		 *
-		 * @member {module:engine/model/schema~Schema}
+		 * @private
+		 * @member {module:engine/model/writer~Writer}
 		 */
-		this.schema = new Schema();
+		this._currentWriter = null;
 
 		[ 'insertContent', 'deleteContent', 'modifySelection', 'getSelectedContent', 'applyOperation' ]
 			.forEach( methodName => this.decorate( methodName ) );

+ 50 - 37
packages/ckeditor5-engine/src/model/node.js

@@ -19,8 +19,8 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
  * However, it is **very important** that nodes already attached to model tree should be only changed through
  * {@link module:engine/model/writer~Writer Writer API}.
  *
- * Changes done by `Node` methods, like {@link module:engine/model/element~Element#insertChildren insertChildren} or
- * {@link module:engine/model/node~Node#setAttribute setAttribute}
+ * Changes done by `Node` methods, like {@link module:engine/model/element~Element#_insertChildren _insertChildren} or
+ * {@link module:engine/model/node~Node#_setAttribute _setAttribute}
  * do not generate {@link module:engine/model/operation/operation~Operation operations}
  * which are essential for correct editor work if you modify nodes in {@link module:engine/model/document~Document document} root.
  *
@@ -201,15 +201,6 @@ export default class Node {
 		return this.root.document || null;
 	}
 
-	/**
-	 * Creates a copy of this node, that is a node with exactly same attributes, and returns it.
-	 *
-	 * @returns {module:engine/model/node~Node} Node with same attributes as this node.
-	 */
-	clone() {
-		return new Node( this._attrs );
-	}
-
 	/**
 	 * Gets path to the node. The path is an array containing starting offsets of consecutive ancestors of this node,
 	 * beginning from {@link module:engine/model/node~Node#root root}, down to this node's starting offset. The path can be used to
@@ -282,13 +273,6 @@ export default class Node {
 		return i === 0 ? null : ancestorsA[ i - 1 ];
 	}
 
-	/**
-	 * Removes this node from it's parent.
-	 */
-	remove() {
-		this.parent.removeChildren( this.index );
-	}
-
 	/**
 	 * Checks if the node has an attribute with given key.
 	 *
@@ -330,55 +314,84 @@ export default class Node {
 		return this._attrs.keys();
 	}
 
+	/**
+	 * Converts `Node` to plain object and returns it.
+	 *
+	 * @returns {Object} `Node` converted to plain object.
+	 */
+	toJSON() {
+		const json = {};
+
+		if ( this._attrs.size ) {
+			json.attributes = [ ...this._attrs ];
+		}
+
+		return json;
+	}
+
+	/**
+	 * Creates a copy of this node, that is a node with exactly same attributes, and returns it.
+	 *
+	 * @protected
+	 * @returns {module:engine/model/node~Node} Node with same attributes as this node.
+	 */
+	_clone() {
+		return new Node( this._attrs );
+	}
+
+	/**
+	 * Removes this node from it's parent.
+	 *
+	 * @see module:engine/model/writer~Writer#remove
+	 * @protected
+	 */
+	_remove() {
+		this.parent._removeChildren( this.index );
+	}
+
 	/**
 	 * Sets attribute on the node. If attribute with the same key already is set, it's value is overwritten.
 	 *
+	 * @see module:engine/model/writer~Writer#setAttribute
+	 * @protected
 	 * @param {String} key Key of attribute to set.
 	 * @param {*} value Attribute value.
 	 */
-	setAttribute( key, value ) {
+	_setAttribute( key, value ) {
 		this._attrs.set( key, value );
 	}
 
 	/**
 	 * Removes all attributes from the node and sets given attributes.
 	 *
+	 * @see module:engine/model/writer~Writer#setAttributes
+	 * @protected
 	 * @param {Object} [attrs] Attributes to set. See {@link module:utils/tomap~toMap} for a list of accepted values.
 	 */
-	setAttributesTo( attrs ) {
+	_setAttributesTo( attrs ) {
 		this._attrs = toMap( attrs );
 	}
 
 	/**
 	 * Removes an attribute with given key from the node.
 	 *
+	 * @see module:engine/model/writer~Writer#removeAttribute
+	 * @protected
 	 * @param {String} key Key of attribute to remove.
 	 * @returns {Boolean} `true` if the attribute was set on the element, `false` otherwise.
 	 */
-	removeAttribute( key ) {
+	_removeAttribute( key ) {
 		return this._attrs.delete( key );
 	}
 
 	/**
 	 * Removes all attributes from the node.
-	 */
-	clearAttributes() {
-		this._attrs.clear();
-	}
-
-	/**
-	 * Converts `Node` to plain object and returns it.
 	 *
-	 * @returns {Object} `Node` converted to plain object.
+	 * @see module:engine/model/writer~Writer#clearAttributes
+	 * @protected
 	 */
-	toJSON() {
-		const json = {};
-
-		if ( this._attrs.size ) {
-			json.attributes = [ ...this._attrs ];
-		}
-
-		return json;
+	_clearAttributes() {
+		this._attrs.clear();
 	}
 
 	/**

+ 6 - 3
packages/ckeditor5-engine/src/model/nodelist.js

@@ -19,6 +19,7 @@ export default class NodeList {
 	/**
 	 * Creates an empty node list.
 	 *
+	 * @protected
 	 * @param {Iterable.<module:engine/model/node~Node>} nodes Nodes contained in this node list.
 	 */
 	constructor( nodes ) {
@@ -31,7 +32,7 @@ export default class NodeList {
 		this._nodes = [];
 
 		if ( nodes ) {
-			this.insertNodes( 0, nodes );
+			this._insertNodes( 0, nodes );
 		}
 	}
 
@@ -164,10 +165,11 @@ export default class NodeList {
 	/**
 	 * Inserts given nodes at given index.
 	 *
+	 * @protected
 	 * @param {Number} index Index at which nodes should be inserted.
 	 * @param {Iterable.<module:engine/model/node~Node>} nodes Nodes to be inserted.
 	 */
-	insertNodes( index, nodes ) {
+	_insertNodes( index, nodes ) {
 		// Validation.
 		for ( const node of nodes ) {
 			if ( !( node instanceof Node ) ) {
@@ -186,11 +188,12 @@ export default class NodeList {
 	/**
 	 * Removes one or more nodes starting at the given index.
 	 *
+	 * @protected
 	 * @param {Number} indexStart Index of the first node to remove.
 	 * @param {Number} [howMany=1] Number of nodes to remove.
 	 * @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.
 	 */
-	removeNodes( indexStart, howMany = 1 ) {
+	_removeNodes( indexStart, howMany = 1 ) {
 		return this._nodes.splice( indexStart, howMany );
 	}
 

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

@@ -63,7 +63,7 @@ export default class InsertOperation extends Operation {
 	 * @returns {module:engine/model/operation/insertoperation~InsertOperation} Clone of this operation.
 	 */
 	clone() {
-		const nodes = new NodeList( [ ...this.nodes ].map( node => node.clone( true ) ) );
+		const nodes = new NodeList( [ ...this.nodes ].map( node => node._clone( true ) ) );
 
 		return new InsertOperation( this.position, nodes, this.baseVersion );
 	}
@@ -107,7 +107,7 @@ export default class InsertOperation extends Operation {
 		// to the operation, not modified. For example, text nodes can get merged or cropped while Elements can
 		// get children. It is important that InsertOperation has the copy of original nodes in intact state.
 		const originalNodes = this.nodes;
-		this.nodes = new NodeList( [ ...originalNodes ].map( node => node.clone( true ) ) );
+		this.nodes = new NodeList( [ ...originalNodes ].map( node => node._clone( true ) ) );
 
 		_insert( this.position, originalNodes );
 	}

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

@@ -156,9 +156,9 @@ export default class RootAttributeOperation extends Operation {
 	 */
 	_execute() {
 		if ( this.newValue !== null ) {
-			this.root.setAttribute( this.key, this.newValue );
+			this.root._setAttribute( this.key, this.newValue );
 		} else {
-			this.root.removeAttribute( this.key );
+			this.root._removeAttribute( this.key );
 		}
 	}
 

+ 10 - 10
packages/ckeditor5-engine/src/model/operation/utils.js

@@ -45,7 +45,7 @@ export function _insert( position, nodes ) {
 
 	// Insert nodes at given index. After splitting we have a proper index and insertion is between nodes,
 	// using basic `Element` API.
-	parent.insertChildren( index, nodes );
+	parent._insertChildren( index, nodes );
 
 	// Merge text nodes, if possible. Merging is needed only at points where inserted nodes "touch" "old" nodes.
 	_mergeNodesAtIndex( parent, index + nodes.length );
@@ -58,7 +58,7 @@ export function _insert( position, nodes ) {
  * Removed nodes in given range. Only {@link module:engine/model/range~Range#isFlat flat} ranges are accepted.
  *
  * @protected
- * @function module:engine/model/operation/utils~utils.remove
+ * @function module:engine/model/operation/utils~utils._remove
  * @param {module:engine/model/range~Range} range Range containing nodes to remove.
  * @returns {Array.<module:engine/model/node~Node>}
  */
@@ -80,7 +80,7 @@ export function _remove( range ) {
 	_splitNodeAtPosition( range.end );
 
 	// Remove the text nodes using basic `Element` API.
-	const removed = parent.removeChildren( range.start.index, range.end.index - range.start.index );
+	const removed = parent._removeChildren( range.start.index, range.end.index - range.start.index );
 
 	// Merge text nodes, if possible. After some nodes were removed, node before and after removed range will be
 	// touching at the position equal to the removed range beginning. We check merging possibility there.
@@ -122,7 +122,7 @@ export function _move( sourceRange, targetPosition ) {
  * Sets given attribute on nodes in given range.
  *
  * @protected
- * @function module:engine/model/operation/utils~utils.setAttribute
+ * @function module:engine/model/operation/utils~utils._setAttribute
  * @param {module:engine/model/range~Range} range Range containing nodes that should have the attribute set.
  * @param {String} key Key of attribute to set.
  * @param {*} value Attribute value.
@@ -140,9 +140,9 @@ export function _setAttribute( range, key, value ) {
 		const node = item.is( 'textProxy' ) ? item.textNode : item;
 
 		if ( value !== null ) {
-			node.setAttribute( key, value );
+			node._setAttribute( key, value );
 		} else {
-			node.removeAttribute( key );
+			node._removeAttribute( key );
 		}
 
 		// After attributes changing it may happen that some text nodes can be merged. Try to merge with previous node.
@@ -221,10 +221,10 @@ function _mergeNodesAtIndex( element, index ) {
 		const mergedNode = new Text( nodeBefore.data + nodeAfter.data, nodeBefore.getAttributes() );
 
 		// Remove separate text nodes.
-		element.removeChildren( index - 1, 2 );
+		element._removeChildren( index - 1, 2 );
 
 		// Insert merged text node.
-		element.insertChildren( index - 1, mergedNode );
+		element._insertChildren( index - 1, mergedNode );
 	}
 }
 
@@ -244,12 +244,12 @@ function _splitNodeAtPosition( position ) {
 		const offsetDiff = position.offset - textNode.startOffset;
 		const index = textNode.index;
 
-		element.removeChildren( index, 1 );
+		element._removeChildren( index, 1 );
 
 		const firstPart = new Text( textNode.data.substr( 0, offsetDiff ), textNode.getAttributes() );
 		const secondPart = new Text( textNode.data.substr( offsetDiff ), textNode.getAttributes() );
 
-		element.insertChildren( index, [ firstPart, secondPart ] );
+		element._insertChildren( index, [ firstPart, secondPart ] );
 	}
 }
 

+ 1 - 0
packages/ckeditor5-engine/src/model/position.js

@@ -104,6 +104,7 @@ export default class Position {
 		 *		     |- LI
 		 *		        |- b^a|r  ^ has path: [ 1, 1, 1 ]   | has path: [ 1, 1, 2 ]
 		 *
+		 * @readonly
 		 * @member {Array.<Number>} module:engine/model/position~Position#path
 		 */
 		this.path = path;

+ 24 - 7
packages/ckeditor5-engine/src/model/text.js

@@ -26,6 +26,10 @@ export default class Text extends Node {
 	/**
 	 * Creates a text node.
 	 *
+	 * **Note:** Constructor of this class shouldn't be used directly in the code.
+	 * Use the {@link module:engine/model/writer~Writer#createText} method instead.
+	 *
+	 * @protected
 	 * @param {String} data Node's text.
 	 * @param {Object} [attrs] Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.
 	 */
@@ -35,9 +39,10 @@ export default class Text extends Node {
 		/**
 		 * Text data contained in this text node.
 		 *
+		 * @protected
 		 * @type {String}
 		 */
-		this.data = data || '';
+		this._data = data || '';
 	}
 
 	/**
@@ -48,17 +53,19 @@ export default class Text extends Node {
 	}
 
 	/**
-	 * @inheritDoc
+	 * Returns a text data contained in the node.
+	 *
+	 * @returns {String}
 	 */
-	is( type ) {
-		return type == 'text';
+	get data() {
+		return this._data;
 	}
 
 	/**
-	 * Creates a copy of this text node and returns it. Created text node has same text data and attributes as original text node.
+	 * @inheritDoc
 	 */
-	clone() {
-		return new Text( this.data, this.getAttributes() );
+	is( type ) {
+		return type == 'text';
 	}
 
 	/**
@@ -74,6 +81,16 @@ export default class Text extends Node {
 		return json;
 	}
 
+	/**
+	 * Creates a copy of this text node and returns it. Created text node has same text data and attributes as original text node.
+	 *
+	 * @protected
+	 * @returns {module:engine/model/text~Text} `Text` instance created using given plain object.
+	 */
+	_clone() {
+		return new Text( this.data, this.getAttributes() );
+	}
+
 	/**
 	 * Creates a `Text` instance from given plain object (i.e. parsed JSON string).
 	 *

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

@@ -71,7 +71,7 @@ export default function getSelectedContent( model, selection ) {
 			if ( item.is( 'textProxy' ) ) {
 				writer.appendText( item.data, item.getAttributes(), frag );
 			} else {
-				writer.append( item.clone( true ), frag );
+				writer.append( item._clone( true ), frag );
 			}
 		}
 

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

@@ -382,7 +382,7 @@ class Insertion {
 		// cause that would lead to an infinite loop. The paragraph would be rejected in
 		// the next _handleNode() call and we'd be here again.
 		if ( this._getAllowedIn( paragraph, this.position.parent ) && this.schema.checkChild( paragraph, node ) ) {
-			paragraph.appendChildren( node );
+			paragraph._appendChildren( node );
 			this._handleNode( paragraph, context );
 		}
 	}

+ 10 - 0
packages/ckeditor5-engine/src/model/writer.js

@@ -322,6 +322,16 @@ export default class Writer {
 		}
 	}
 
+	/**
+	 * Sets the text content for the specified `textNode`.
+	 *
+	 * @param {String} value New value.
+	 * @param {module:engine/model/text~Text} textNode Text node that will be updated.
+	 */
+	setTextData( value, textNode ) {
+		textNode._data = value;
+	}
+
 	/**
 	 * Sets value of the attribute with given key on a {@link module:engine/model/item~Item model item}
 	 * or on a {@link module:engine/model/range~Range range}.

+ 17 - 14
packages/ckeditor5-engine/src/view/attributeelement.js

@@ -26,6 +26,8 @@ export default class AttributeElement extends Element {
 	/**
 	 * Creates a attribute element.
 	 *
+	 * @see module:engine/view/writer~Writer#createAttributeElement
+	 * @protected
 	 * @see module:engine/view/element~Element
 	 */
 	constructor( name, attrs, children ) {
@@ -71,33 +73,34 @@ export default class AttributeElement extends Element {
 		}
 	}
 
+	/**
+	 * Checks if this element is similar to other element.
+	 * Both elements should have the same name, attributes and priority to be considered as similar.
+	 * Two similar elements can contain different set of children nodes.
+	 *
+	 * @param {module:engine/view/element~Element} otherElement
+	 * @returns {Boolean}
+	 */
+	isSimilar( otherElement ) {
+		return super.isSimilar( otherElement ) && this.priority == otherElement.priority;
+	}
+
 	/**
 	 * Clones provided element with priority.
 	 *
+	 * @protected
 	 * @param {Boolean} deep If set to `true` clones element and all its children recursively. When set to `false`,
 	 * element will be cloned without any children.
 	 * @returns {module:engine/view/attributeelement~AttributeElement} Clone of this element.
 	 */
-	clone( deep ) {
-		const cloned = super.clone( deep );
+	_clone( deep ) {
+		const cloned = super._clone( deep );
 
 		// Clone priority too.
 		cloned._priority = this._priority;
 
 		return cloned;
 	}
-
-	/**
-	 * Checks if this element is similar to other element.
-	 * Both elements should have the same name, attributes and priority to be considered as similar.
-	 * Two similar elements can contain different set of children nodes.
-	 *
-	 * @param {module:engine/view/element~Element} otherElement
-	 * @returns {Boolean}
-	 */
-	isSimilar( otherElement ) {
-		return super.isSimilar( otherElement ) && this.priority == otherElement.priority;
-	}
 }
 
 /**

+ 2 - 0
packages/ckeditor5-engine/src/view/containerelement.js

@@ -49,6 +49,8 @@ export default class ContainerElement extends Element {
 	 * Creates a container element.
 	 *
 	 * @see module:engine/view/element~Element
+	 * @see module:engine/view/writer~Writer#createContainerElement
+	 * @protected
 	 */
 	constructor( name, attrs, children ) {
 		super( name, attrs, children );

+ 8 - 7
packages/ckeditor5-engine/src/view/documentfragment.js

@@ -20,6 +20,7 @@ export default class DocumentFragment {
 	/**
 	 * Creates new DocumentFragment instance.
 	 *
+	 * @protected
 	 * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children] List of nodes to be inserted into
 	 * created document fragment.
 	 */
@@ -33,7 +34,7 @@ export default class DocumentFragment {
 		this._children = [];
 
 		if ( children ) {
-			this.insertChildren( 0, children );
+			this._insertChildren( 0, children );
 		}
 	}
 
@@ -101,14 +102,14 @@ export default class DocumentFragment {
 	}
 
 	/**
-	 * {@link module:engine/view/documentfragment~DocumentFragment#insertChildren Insert} a child node or a list of child nodes at the end
+	 * {@link module:engine/view/documentfragment~DocumentFragment#_insertChildren Insert} a child node or a list of child nodes at the end
 	 * and sets the parent of these nodes to this fragment.
 	 *
 	 * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.
 	 * @returns {Number} Number of appended nodes.
 	 */
-	appendChildren( items ) {
-		return this.insertChildren( this.childCount, items );
+	_appendChildren( items ) {
+		return this._insertChildren( this.childCount, items );
 	}
 
 	/**
@@ -148,7 +149,7 @@ export default class DocumentFragment {
 	 * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.
 	 * @returns {Number} Number of inserted nodes.
 	 */
-	insertChildren( index, items ) {
+	_insertChildren( index, items ) {
 		this._fireChange( 'children', this );
 		let count = 0;
 
@@ -157,7 +158,7 @@ export default class DocumentFragment {
 		for ( const node of nodes ) {
 			// If node that is being added to this element is already inside another element, first remove it from the old parent.
 			if ( node.parent !== null ) {
-				node.remove();
+				node._remove();
 			}
 
 			node.parent = this;
@@ -177,7 +178,7 @@ export default class DocumentFragment {
 	 * @param {Number} [howMany=1] Number of nodes to remove.
 	 * @returns {Array.<module:engine/view/node~Node>} The array of removed nodes.
 	 */
-	removeChildren( index, howMany = 1 ) {
+	_removeChildren( index, howMany = 1 ) {
 		this._fireChange( 'children', this );
 
 		for ( let i = index; i < index + howMany; i++ ) {

+ 3 - 1
packages/ckeditor5-engine/src/view/domconverter.js

@@ -64,6 +64,7 @@ export default class DomConverter {
 		/**
 		 * Tag names of DOM `Element`s which are considered pre-formatted elements.
 		 *
+		 * @readonly
 		 * @member {Array.<String>} module:engine/view/domconverter~DomConverter#preElements
 		 */
 		this.preElements = [ 'pre' ];
@@ -71,6 +72,7 @@ export default class DomConverter {
 		/**
 		 * Tag names of DOM `Element`s which are considered block elements.
 		 *
+		 * @readonly
 		 * @member {Array.<String>} module:engine/view/domconverter~DomConverter#blockElements
 		 */
 		this.blockElements = [ 'p', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ];
@@ -419,7 +421,7 @@ export default class DomConverter {
 
 			if ( options.withChildren || options.withChildren === undefined ) {
 				for ( const child of this.domChildrenToView( domNode, options ) ) {
-					viewElement.appendChildren( child );
+					viewElement._appendChildren( child );
 				}
 			}
 

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

@@ -26,6 +26,9 @@ const documentSymbol = Symbol( 'document' );
 export default class EditableElement extends ContainerElement {
 	/**
 	 * Creates an editable element.
+	 *
+	 * @see module:engine/view/writer~Writer#createEditableElement
+	 * @protected
 	 */
 	constructor( name, attrs, children ) {
 		super( name, attrs, children );

+ 119 - 97
packages/ckeditor5-engine/src/view/element.js

@@ -38,6 +38,14 @@ export default class Element extends Node {
 	 *		new Element( 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator
 	 *		new Element( 'div', mapOfAttributes ); // map
 	 *
+	 * **Note:** Constructor of this class shouldn't be used directly in the code. Use the
+	 * {@link module:engine/view/writer~Writer#createAttributeElement} for inline element,
+	 * {@link module:engine/view/writer~Writer#createContainerElement} for block element,
+	 * {@link module:engine/view/writer~Writer#createEditableElement} for editable element,
+	 * {@link module:engine/view/writer~Writer#createEmptyElement} for empty element or
+	 * {@link module:engine/view/writer~Writer#createUIElement} for UI element instead.
+	 *
+	 * @protected
 	 * @param {String} name Node name.
 	 * @param {Object|Iterable} [attrs] Collection of attributes.
 	 * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]
@@ -71,7 +79,7 @@ export default class Element extends Node {
 		this._children = [];
 
 		if ( children ) {
-			this.insertChildren( 0, children );
+			this._insertChildren( 0, children );
 		}
 
 		/**
@@ -150,53 +158,6 @@ export default class Element extends Node {
 		}
 	}
 
-	/**
-	 * Clones provided element.
-	 *
-	 * @param {Boolean} [deep=false] If set to `true` clones element and all its children recursively. When set to `false`,
-	 * element will be cloned without any children.
-	 * @returns {module:engine/view/element~Element} Clone of this element.
-	 */
-	clone( deep = false ) {
-		const childrenClone = [];
-
-		if ( deep ) {
-			for ( const child of this.getChildren() ) {
-				childrenClone.push( child.clone( deep ) );
-			}
-		}
-
-		// ContainerElement and AttributeElement should be also cloned properly.
-		const cloned = new this.constructor( this.name, this._attrs, childrenClone );
-
-		// Classes and styles are cloned separately - this solution is faster than adding them back to attributes and
-		// parse once again in constructor.
-		cloned._classes = new Set( this._classes );
-		cloned._styles = new Map( this._styles );
-
-		// Clone custom properties.
-		cloned._customProperties = new Map( this._customProperties );
-
-		// Clone filler offset method.
-		// We can't define this method in a prototype because it's behavior which
-		// is changed by e.g. toWidget() function from ckeditor5-widget. Perhaps this should be one of custom props.
-		cloned.getFillerOffset = this.getFillerOffset;
-
-		return cloned;
-	}
-
-	/**
-	 * {@link module:engine/view/element~Element#insertChildren Insert} a child node or a list of child nodes at the end of this node
-	 * and sets the parent of these nodes to this element.
-	 *
-	 * @fires module:engine/view/node~Node#change
-	 * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.
-	 * @returns {Number} Number of appended nodes.
-	 */
-	appendChildren( items ) {
-		return this.insertChildren( this.childCount, items );
-	}
-
 	/**
 	 * Gets child at the given index.
 	 *
@@ -317,55 +278,6 @@ export default class Element extends Node {
 		return this._attrs.has( key );
 	}
 
-	/**
-	 * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to
-	 * this element.
-	 *
-	 * @param {Number} index Position where nodes should be inserted.
-	 * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.
-	 * @fires module:engine/view/node~Node#change
-	 * @returns {Number} Number of inserted nodes.
-	 */
-	insertChildren( index, items ) {
-		this._fireChange( 'children', this );
-		let count = 0;
-
-		const nodes = normalize( items );
-
-		for ( const node of nodes ) {
-			// If node that is being added to this element is already inside another element, first remove it from the old parent.
-			if ( node.parent !== null ) {
-				node.remove();
-			}
-
-			node.parent = this;
-
-			this._children.splice( index, 0, node );
-			index++;
-			count++;
-		}
-
-		return count;
-	}
-
-	/**
-	 * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.
-	 *
-	 * @param {Number} index Number of the first node to remove.
-	 * @param {Number} [howMany=1] Number of nodes to remove.
-	 * @returns {Array.<module:engine/view/node~Node>} The array of removed nodes.
-	 * @fires module:engine/view/node~Node#change
-	 */
-	removeChildren( index, howMany = 1 ) {
-		this._fireChange( 'children', this );
-
-		for ( let i = index; i < index + howMany; i++ ) {
-			this._children[ i ].parent = null;
-		}
-
-		return this._children.splice( index, howMany );
-	}
-
 	/**
 	 * Checks if this element is similar to other element.
 	 * Both elements should have the same name and attributes to be considered as similar. Two similar elements
@@ -564,9 +476,112 @@ export default class Element extends Node {
 			( attributes == '' ? '' : ` ${ attributes }` );
 	}
 
+	/**
+	 * Clones provided element.
+	 *
+	 * @protected
+	 * @param {Boolean} [deep=false] If set to `true` clones element and all its children recursively. When set to `false`,
+	 * element will be cloned without any children.
+	 * @returns {module:engine/view/element~Element} Clone of this element.
+	 */
+	_clone( deep = false ) {
+		const childrenClone = [];
+
+		if ( deep ) {
+			for ( const child of this.getChildren() ) {
+				childrenClone.push( child._clone( deep ) );
+			}
+		}
+
+		// ContainerElement and AttributeElement should be also cloned properly.
+		const cloned = new this.constructor( this.name, this._attrs, childrenClone );
+
+		// Classes and styles are cloned separately - this solution is faster than adding them back to attributes and
+		// parse once again in constructor.
+		cloned._classes = new Set( this._classes );
+		cloned._styles = new Map( this._styles );
+
+		// Clone custom properties.
+		cloned._customProperties = new Map( this._customProperties );
+
+		// Clone filler offset method.
+		// We can't define this method in a prototype because it's behavior which
+		// is changed by e.g. toWidget() function from ckeditor5-widget. Perhaps this should be one of custom props.
+		cloned.getFillerOffset = this.getFillerOffset;
+
+		return cloned;
+	}
+
+	/**
+	 * {@link module:engine/view/element~Element#_insertChildren Insert} a child node or a list of child nodes at the end of this node
+	 * and sets the parent of these nodes to this element.
+	 *
+	 * @see module:engine/view/writer~Writer#insert
+	 * @protected
+	 * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.
+	 * @fires module:engine/view/node~Node#change
+	 * @returns {Number} Number of appended nodes.
+	 */
+	_appendChildren( items ) {
+		return this._insertChildren( this.childCount, items );
+	}
+
+	/**
+	 * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to
+	 * this element.
+	 *
+	 * @see module:engine/view/writer~Writer#insert
+	 * @protected
+	 * @param {Number} index Position where nodes should be inserted.
+	 * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.
+	 * @fires module:engine/view/node~Node#change
+	 * @returns {Number} Number of inserted nodes.
+	 */
+	_insertChildren( index, items ) {
+		this._fireChange( 'children', this );
+		let count = 0;
+
+		const nodes = normalize( items );
+
+		for ( const node of nodes ) {
+			// If node that is being added to this element is already inside another element, first remove it from the old parent.
+			if ( node.parent !== null ) {
+				node._remove();
+			}
+
+			node.parent = this;
+
+			this._children.splice( index, 0, node );
+			index++;
+			count++;
+		}
+
+		return count;
+	}
+
+	/**
+	 * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.
+	 *
+	 * @see module:engine/view/writer~Writer#remove
+	 * @param {Number} index Number of the first node to remove.
+	 * @param {Number} [howMany=1] Number of nodes to remove.
+	 * @fires module:engine/view/node~Node#change
+	 * @returns {Array.<module:engine/view/node~Node>} The array of removed nodes.
+	 */
+	_removeChildren( index, howMany = 1 ) {
+		this._fireChange( 'children', this );
+
+		for ( let i = index; i < index + howMany; i++ ) {
+			this._children[ i ].parent = null;
+		}
+
+		return this._children.splice( index, howMany );
+	}
+
 	/**
 	 * Adds or overwrite attribute with a specified key and value.
 	 *
+	 * @see module:engine/view/writer~Writer#setAttribute
 	 * @protected
 	 * @param {String} key Attribute key.
 	 * @param {String} value Attribute value.
@@ -589,6 +604,7 @@ export default class Element extends Node {
 	/**
 	 * Removes attribute from the element.
 	 *
+	 * @see module:engine/view/writer~Writer#removeAttribute
 	 * @protected
 	 * @param {String} key Attribute key.
 	 * @returns {Boolean} Returns true if an attribute existed and has been removed.
@@ -629,6 +645,7 @@ export default class Element extends Node {
 	 *		element._addClass( 'foo' ); // Adds 'foo' class.
 	 *		element._addClass( [ 'foo', 'bar' ] ); // Adds 'foo' and 'bar' classes.
 	 *
+	 * @see module:engine/view/writer~Writer#addClass
 	 * @protected
 	 * @param {Array.<String>|String} className
 	 * @fires module:engine/view/node~Node#change
@@ -646,6 +663,7 @@ export default class Element extends Node {
 	 *		element._removeClass( 'foo' );  // Removes 'foo' class.
 	 *		element._removeClass( [ 'foo', 'bar' ] ); // Removes both 'foo' and 'bar' classes.
 	 *
+	 * @see module:engine/view/writer~Writer#removeClass
 	 * @param {Array.<String>|String} className
 	 * @fires module:engine/view/node~Node#change
 	 */
@@ -665,6 +683,7 @@ export default class Element extends Node {
 	 *			position: 'fixed'
 	 *		} );
 	 *
+	 * @see module:engine/view/writer~Writer#setStyle
 	 * @protected
 	 * @param {String|Object} property Property name or object with key - value pairs.
 	 * @param {String} [value] Value to set. This parameter is ignored if object is provided as the first parameter.
@@ -690,6 +709,7 @@ export default class Element extends Node {
 	 *		element._removeStyle( 'color' );  // Removes 'color' style.
 	 *		element._removeStyle( [ 'color', 'border-top' ] ); // Removes both 'color' and 'border-top' styles.
 	 *
+	 * @see module:engine/view/writer~Writer#removeStyle
 	 * @protected
 	 * @param {Array.<String>|String} property
 	 * @fires module:engine/view/node~Node#change
@@ -705,6 +725,7 @@ export default class Element extends Node {
 	 * Sets a custom property. Unlike attributes, custom properties are not rendered to the DOM,
 	 * so they can be used to add special data to elements.
 	 *
+	 * @see module:engine/view/writer~Writer#setCustomProperty
 	 * @protected
 	 * @param {String|Symbol} key
 	 * @param {*} value
@@ -716,6 +737,7 @@ export default class Element extends Node {
 	/**
 	 * Removes the custom property stored under the given key.
 	 *
+	 * @see module:engine/view/writer~Writer#removeCustomProperty
 	 * @protected
 	 * @param {String|Symbol} key
 	 * @returns {Boolean} Returns true if property was removed.

+ 6 - 2
packages/ckeditor5-engine/src/view/emptyelement.js

@@ -21,6 +21,8 @@ export default class EmptyElement extends Element {
 	 * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-emptyelement-cannot-add` when third parameter is passed,
 	 * to inform that usage of EmptyElement is incorrect (adding child nodes to EmptyElement is forbidden).
 	 *
+	 * @see module:engine/view/writer~Writer#createEmptyElement
+	 * @protected
 	 * @param {String} name Node name.
 	 * @param {Object|Iterable} [attributes] Collection of attributes.
 	 */
@@ -48,11 +50,13 @@ export default class EmptyElement extends Element {
 	}
 
 	/**
-	 * Overrides {@link module:engine/view/element~Element#insertChildren} method.
+	 * Overrides {@link module:engine/view/element~Element#_insertChildren} method.
 	 * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-emptyelement-cannot-add` to prevent
 	 * adding any child nodes to EmptyElement.
+	 *
+	 * @protected
 	 */
-	insertChildren( index, nodes ) {
+	_insertChildren( index, nodes ) {
 		if ( nodes && ( nodes instanceof Node || Array.from( nodes ).length > 0 ) ) {
 			/**
 			 * Cannot add children to {@link module:engine/view/emptyelement~EmptyElement}.

+ 4 - 0
packages/ckeditor5-engine/src/view/matcher.js

@@ -19,6 +19,10 @@ export default class Matcher {
 	 * more information.
 	 */
 	constructor( ...pattern ) {
+		/**
+		 * @private
+		 * @type {Array<String|RegExp|Object>}
+		 */
 		this._patterns = [];
 
 		this.add( ...pattern );

+ 5 - 3
packages/ckeditor5-engine/src/view/node.js

@@ -25,7 +25,7 @@ export default class Node {
 	 */
 	constructor() {
 		/**
-		 * Parent element. Null by default. Set by {@link module:engine/view/element~Element#insertChildren}.
+		 * Parent element. Null by default. Set by {@link module:engine/view/element~Element#_insertChildren}.
 		 *
 		 * @readonly
 		 * @member {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|null}
@@ -164,9 +164,11 @@ export default class Node {
 
 	/**
 	 * Removes node from parent.
+	 *
+	 * @protected
 	 */
-	remove() {
-		this.parent.removeChildren( this.index );
+	_remove() {
+		this.parent._removeChildren( this.index );
 	}
 
 	/**

+ 2 - 0
packages/ckeditor5-engine/src/view/position.js

@@ -27,6 +27,7 @@ export default class Position {
 		/**
 		 * Position parent.
 		 *
+		 * @readonly
 		 * @member {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}
 		 * module:engine/view/position~Position#parent
 		 */
@@ -35,6 +36,7 @@ export default class Position {
 		/**
 		 * Position offset.
 		 *
+		 * @readonly
 		 * @member {Number} module:engine/view/position~Position#offset
 		 */
 		this.offset = offset;

+ 2 - 0
packages/ckeditor5-engine/src/view/range.js

@@ -26,6 +26,7 @@ export default class Range {
 		/**
 		 * Start position.
 		 *
+		 * @readonly
 		 * @member {module:engine/view/position~Position}
 		 */
 		this.start = Position.createFromPosition( start );
@@ -33,6 +34,7 @@ export default class Range {
 		/**
 		 * End position.
 		 *
+		 * @readonly
 		 * @member {module:engine/view/position~Position}
 		 */
 		this.end = end ? Position.createFromPosition( end ) : Position.createFromPosition( start );

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

@@ -43,6 +43,7 @@ export default class Renderer {
 		/**
 		 * Set of DOM Documents instances.
 		 *
+		 * @readonly
 		 * @member {Set.<Document>}
 		 */
 		this.domDocuments = new Set();

+ 1 - 0
packages/ckeditor5-engine/src/view/rooteditableelement.js

@@ -31,6 +31,7 @@ export default class RootEditableElement extends EditableElement {
 		 * Name of this root inside {@link module:engine/view/document~Document} that is an owner of this root. If no
 		 * other name is set, `main` name is used.
 		 *
+		 * @readonly
 		 * @member {String}
 		 */
 		this.rootName = 'main';

+ 13 - 13
packages/ckeditor5-engine/src/view/selection.js

@@ -195,7 +195,7 @@ export default class Selection {
 	 * Returns number of ranges in selection.
 	 *
 	 * @type {Number}
-     */
+	 */
 	get rangeCount() {
 		return this._ranges.length;
 	}
@@ -421,39 +421,39 @@ export default class Selection {
 	 *
 	 *		// Sets selection to the given range.
 	 *		const range = new Range( start, end );
-	 *		selection.setTo( range );
+	 *		selection._setTo( range );
 	 *
 	 *		// Sets selection to given ranges.
 	 * 		const ranges = [ new Range( start1, end2 ), new Range( star2, end2 ) ];
-	 *		selection.setTo( range );
+	 *		selection._setTo( range );
 	 *
 	 *		// Sets selection to the other selection.
 	 *		const otherSelection = new Selection();
-	 *		selection.setTo( otherSelection );
+	 *		selection._setTo( otherSelection );
 	 *
 	 * 		// Sets collapsed selection at the given position.
 	 *		const position = new Position( root, path );
-	 *		selection.setTo( position );
+	 *		selection._setTo( position );
 	 *
 	 * 		// Sets collapsed selection at the position of given item and offset.
-	 *		selection.setTo( paragraph, offset );
+	 *		selection._setTo( 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.
+	 * that element and ends after the last child of that element.
 	 *
-	 *		selection.setTo( paragraph, 'in' );
+	 *		selection._setTo( 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.
 	 *
-	 *		selection.setTo( paragraph, 'on' );
+	 *		selection._setTo( paragraph, 'on' );
 	 *
 	 * 		// Clears selection. Removes all ranges.
-	 *		selection.setTo( null );
+	 *		selection._setTo( null );
 	 *
-	 * `Selection#setTo()` method allow passing additional options (`backward`, `fake` and `label`) as the last argument.
+	 * `Selection#_setTo()` method allow passing additional options (`backward`, `fake` and `label`) as the last argument.
 	 *
 	 *		// Sets selection as backward.
-	 *		selection.setTo( range, { backward: true } );
+	 *		selection._setTo( 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
@@ -463,7 +463,7 @@ export default class Selection {
 	 * (and be  properly handled by screen readers).
 	 *
 	 *		// Creates fake selection with label.
-	 *		selection.setTo( range, { fake: true, label: 'foo' } );
+	 *		selection._setTo( range, { fake: true, label: 'foo' } );
 	 *
 	 * @protected
 	 * @fires change

+ 46 - 16
packages/ckeditor5-engine/src/view/text.js

@@ -18,6 +18,10 @@ export default class Text extends Node {
 	/**
 	 * Creates a tree view text node.
 	 *
+	 * **Note:** Constructor of this class shouldn't be used directly in the code.
+	 * Use the {@link module:engine/view/writer~Writer#createText} method instead.
+	 *
+	 * @protected
 	 * @param {String} data Text.
 	 */
 	constructor( data ) {
@@ -28,19 +32,10 @@ export default class Text extends Node {
 		 *
 		 * Setting the data fires the {@link module:engine/view/node~Node#event:change:text change event}.
 		 *
-		 * @private
-		 * @member {String} module:engine/view/text~Text#_data
+		 * @protected
+		 * @member {String} module:engine/view/text~Text#_textData
 		 */
-		this._data = data;
-	}
-
-	/**
-	 * Clones this node.
-	 *
-	 * @returns {module:engine/view/text~Text} Text node that is a clone of this node.
-	 */
-	clone() {
-		return new Text( this.data );
+		this._textData = data;
 	}
 
 	/**
@@ -53,16 +48,41 @@ export default class Text extends Node {
 	/**
 	 * The text content.
 	 *
-	 * Setting the data fires the {@link module:engine/view/node~Node#event:change:text change event}.
+	 * @returns {String}
 	 */
 	get data() {
-		return this._data;
+		return this._textData;
+	}
+
+	/**
+	 * This getter is required when using the addition assignment operator on protected property:
+	 *
+	 *		const foo = new Text( 'foo' );
+	 *		const bar = new Text( 'bar' );
+	 *
+	 *		foo._data += bar.data;   // executes: `foo._data = foo._data + bar.data`
+	 *		console.log( foo.data ); // prints: 'foobar'
+	 *
+	 * If the protected getter didn't exist, `foo._data` will return `undefined` and result of the merge will be invalid.
+	 *
+	 * @protected
+	 * @returns {String}
+	 */
+	get _data() {
+		return this.data;
 	}
 
-	set data( data ) {
+	/**
+	 * Sets data and fires the {@link module:engine/view/node~Node#event:change:text change event}.
+	 *
+	 * @protected
+	 * @fires change:text
+	 * @param {String} data New data for the text node.
+	 */
+	set _data( data ) {
 		this._fireChange( 'text', this );
 
-		this._data = data;
+		this._textData = data;
 	}
 
 	/**
@@ -79,4 +99,14 @@ export default class Text extends Node {
 
 		return this === otherNode || this.data === otherNode.data;
 	}
+
+	/**
+	 * Clones this node.
+	 *
+	 * @protected
+	 * @returns {module:engine/view/text~Text} Text node that is a clone of this node.
+	 */
+	_clone() {
+		return new Text( this.data );
+	}
 }

+ 4 - 2
packages/ckeditor5-engine/src/view/uielement.js

@@ -23,6 +23,8 @@ export default class UIElement extends Element {
 	 * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-uielement-cannot-add` when third parameter is passed,
 	 * to inform that usage of UIElement is incorrect (adding child nodes to UIElement is forbidden).
 	 *
+	 * @see module:engine/view/writer~Writer#createUIElement
+	 * @protected
 	 * @param {String} name Node name.
 	 * @param {Object|Iterable} [attributes] Collection of attributes.
 	 */
@@ -50,11 +52,11 @@ export default class UIElement extends Element {
 	}
 
 	/**
-	 * Overrides {@link module:engine/view/element~Element#insertChildren} method.
+	 * Overrides {@link module:engine/view/element~Element#_insertChildren} method.
 	 * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-uielement-cannot-add` to prevent adding any child nodes
 	 * to UIElement.
 	 */
-	insertChildren( index, nodes ) {
+	_insertChildren( index, nodes ) {
 		if ( nodes && ( nodes instanceof Node || Array.from( nodes ).length > 0 ) ) {
 			/**
 			 * Cannot add children to {@link module:engine/view/uielement~UIElement}.

+ 36 - 22
packages/ckeditor5-engine/src/view/writer.js

@@ -27,6 +27,10 @@ import EditableElement from './editableelement';
  */
 export default class Writer {
 	constructor( document ) {
+		/**
+		 * @readonly
+		 * @type {module:engine/view/document~Document}
+		 */
 		this.document = document;
 	}
 
@@ -221,6 +225,16 @@ export default class Writer {
 		return uiElement;
 	}
 
+	/**
+	 * Sets the text content for the specified `textNode`.
+	 *
+	 * @param {String} value New value.
+	 * @param {module:engine/view/text~Text} textNode Text node that will be updated.
+	 */
+	setTextData( value, textNode ) {
+		textNode._data = value;
+	}
+
 	/**
 	 * Adds or overwrite element's attribute with a specified key and value.
 	 *
@@ -425,7 +439,7 @@ export default class Writer {
 		if ( position.isAtStart ) {
 			return Position.createBefore( element );
 		} else if ( !position.isAtEnd ) {
-			const newElement = element.clone( false );
+			const newElement = element._clone( false );
 
 			this.insert( Position.createAfter( element ), newElement );
 
@@ -477,7 +491,7 @@ export default class Writer {
 		if ( positionParent.is( 'attributeElement' ) && positionParent.childCount === 0 ) {
 			const parent = positionParent.parent;
 			const offset = positionParent.index;
-			positionParent.remove();
+			positionParent._remove();
 
 			return this.mergeAttributes( new Position( parent, offset ) );
 		}
@@ -498,8 +512,8 @@ export default class Writer {
 		else if ( nodeBefore.is( 'attributeElement' ) && nodeAfter.is( 'attributeElement' ) && nodeBefore.isSimilar( nodeAfter ) ) {
 			// Move all children nodes from node placed after selection and remove that node.
 			const count = nodeBefore.childCount;
-			nodeBefore.appendChildren( nodeAfter.getChildren() );
-			nodeAfter.remove();
+			nodeBefore._appendChildren( nodeAfter.getChildren() );
+			nodeAfter._remove();
 
 			// New position is located inside the first node, before new nodes.
 			// Call this method recursively to merge again if needed.
@@ -588,7 +602,7 @@ export default class Writer {
 
 		const insertionPosition = _breakAttributes( position, true );
 
-		const length = container.insertChildren( insertionPosition.offset, nodes );
+		const length = container._insertChildren( insertionPosition.offset, nodes );
 		const endPosition = insertionPosition.getShiftedBy( length );
 		const start = this.mergeAttributes( insertionPosition );
 
@@ -633,7 +647,7 @@ export default class Writer {
 		const count = breakEnd.offset - breakStart.offset;
 
 		// Remove nodes in range.
-		const removed = parentContainer.removeChildren( breakStart.offset, count );
+		const removed = parentContainer._removeChildren( breakStart.offset, count );
 
 		// Merge after removing.
 		const mergePosition = this.mergeAttributes( breakStart );
@@ -901,12 +915,12 @@ export default class Writer {
 			// Wrap text, empty elements, ui elements or attributes with higher or equal priority.
 			if ( isText || isEmpty || isUI || ( isAttribute && shouldABeOutsideB( attribute, child ) ) ) {
 				// Clone attribute.
-				const newAttribute = attribute.clone();
+				const newAttribute = attribute._clone();
 
 				// Wrap current node with new attribute;
-				child.remove();
-				newAttribute.appendChildren( child );
-				parent.insertChildren( i, newAttribute );
+				child._remove();
+				newAttribute._appendChildren( child );
+				parent._insertChildren( i, newAttribute );
 
 				wrapPositions.push(	new Position( parent, i ) );
 			}
@@ -965,8 +979,8 @@ export default class Writer {
 				const count = child.childCount;
 
 				// Replace wrapper element with its children
-				child.remove();
-				parent.insertChildren( i, unwrapped );
+				child._remove();
+				parent._insertChildren( i, unwrapped );
 
 				// Save start and end position of moved items.
 				unwrapPositions.push(
@@ -1103,7 +1117,7 @@ export default class Writer {
 		fakePosition.isSimilar = () => false;
 
 		// Insert fake element in position location.
-		position.parent.insertChildren( position.offset, fakePosition );
+		position.parent._insertChildren( position.offset, fakePosition );
 
 		// Range around inserted fake attribute element.
 		const wrapRange = new Range( position, position.getShiftedBy( 1 ) );
@@ -1113,7 +1127,7 @@ export default class Writer {
 
 		// Remove fake element and place new position there.
 		const newPosition = new Position( fakePosition.parent, fakePosition.index );
-		fakePosition.remove();
+		fakePosition._remove();
 
 		// If position is placed between text nodes - merge them and return position inside.
 		const nodeBefore = newPosition.nodeBefore;
@@ -1394,17 +1408,17 @@ function _breakAttributes( position, forceSplitText = false ) {
 		const offsetAfter = positionParent.index + 1;
 
 		// Break element.
-		const clonedNode = positionParent.clone();
+		const clonedNode = positionParent._clone();
 
 		// Insert cloned node to position's parent node.
-		positionParent.parent.insertChildren( offsetAfter, clonedNode );
+		positionParent.parent._insertChildren( offsetAfter, clonedNode );
 
 		// Get nodes to move.
 		const count = positionParent.childCount - positionOffset;
-		const nodesToMove = positionParent.removeChildren( positionOffset, count );
+		const nodesToMove = positionParent._removeChildren( positionOffset, count );
 
 		// Move nodes to cloned node.
-		clonedNode.appendChildren( nodesToMove );
+		clonedNode._appendChildren( nodesToMove );
 
 		// Create new position to work on.
 		const newPosition = new Position( positionParent.parent, offsetAfter );
@@ -1478,10 +1492,10 @@ function breakTextNode( position ) {
 	const textToMove = position.parent.data.slice( position.offset );
 
 	// Leave rest of the text in position's parent.
-	position.parent.data = position.parent.data.slice( 0, position.offset );
+	position.parent._data = position.parent.data.slice( 0, position.offset );
 
 	// Insert new text node after position's parent text node.
-	position.parent.parent.insertChildren( position.parent.index + 1, new Text( textToMove ) );
+	position.parent.parent._insertChildren( position.parent.index + 1, new Text( textToMove ) );
 
 	// Return new position between two newly created text nodes.
 	return new Position( position.parent.parent, position.parent.index + 1 );
@@ -1496,8 +1510,8 @@ function breakTextNode( position ) {
 function mergeTextNodes( t1, t2 ) {
 	// Merge text data into first text node and remove second one.
 	const nodeBeforeLength = t1.data.length;
-	t1.data += t2.data;
-	t2.remove();
+	t1._data += t2.data;
+	t2._remove();
 
 	return new Position( t1, nodeBeforeLength );
 }

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

@@ -100,9 +100,9 @@ describe( 'EditingController', () => {
 				writer.setSelection( null );
 			} );
 
-			modelRoot.removeChildren( 0, modelRoot.childCount );
+			modelRoot._removeChildren( 0, modelRoot.childCount );
 
-			viewRoot.removeChildren( 0, viewRoot.childCount );
+			viewRoot._removeChildren( 0, viewRoot.childCount );
 
 			const modelData = new ModelDocumentFragment( parse(
 				'<paragraph>foo</paragraph>' +

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

@@ -1030,8 +1030,8 @@ describe( 'downcast-converters', () => {
 		} );
 
 		it( 'should not remove view ui elements that are placed next to removed content', () => {
-			modelRoot.appendChildren( new ModelText( 'fozbar' ) );
-			viewRoot.appendChildren( [
+			modelRoot._appendChildren( new ModelText( 'fozbar' ) );
+			viewRoot._appendChildren( [
 				new ViewText( 'foz' ),
 				new ViewUIElement( 'span' ),
 				new ViewText( 'bar' )
@@ -1053,8 +1053,8 @@ describe( 'downcast-converters', () => {
 		} );
 
 		it( 'should remove correct amount of text when it is split by view ui element', () => {
-			modelRoot.appendChildren( new ModelText( 'fozbar' ) );
-			viewRoot.appendChildren( [
+			modelRoot._appendChildren( new ModelText( 'fozbar' ) );
+			viewRoot._appendChildren( [
 				new ViewText( 'foz' ),
 				new ViewUIElement( 'span' ),
 				new ViewText( 'bar' )
@@ -1129,8 +1129,8 @@ describe( 'downcast-converters', () => {
 			const viewUi2 = new ViewUIElement( 'span' );
 			const viewP2 = new ViewContainerElement( 'p' );
 
-			modelRoot.appendChildren( [ modelP1, modelP2 ] );
-			viewRoot.appendChildren( [ viewP1, viewUi1, viewUi2, viewP2 ] );
+			modelRoot._appendChildren( [ modelP1, modelP2 ] );
+			viewRoot._appendChildren( [ viewP1, viewUi1, viewUi2, viewP2 ] );
 
 			controller.mapper.bindElements( modelP1, viewP1 );
 			controller.mapper.bindElements( modelP2, viewP2 );

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

@@ -202,7 +202,7 @@ describe( 'downcast-selection-converters', () => {
 				} );
 
 				// Remove view children manually (without firing additional conversion).
-				viewRoot.removeChildren( 0, viewRoot.childCount );
+				viewRoot._removeChildren( 0, viewRoot.childCount );
 
 				// Convert model to view.
 				view.change( writer => {
@@ -227,7 +227,7 @@ describe( 'downcast-selection-converters', () => {
 				} );
 
 				// Remove view children manually (without firing additional conversion).
-				viewRoot.removeChildren( 0, viewRoot.childCount );
+				viewRoot._removeChildren( 0, viewRoot.childCount );
 
 				// Convert model to view.
 				view.change( writer => {
@@ -254,7 +254,7 @@ describe( 'downcast-selection-converters', () => {
 				} );
 
 				// Remove view children manually (without firing additional conversion).
-				viewRoot.removeChildren( 0, viewRoot.childCount );
+				viewRoot._removeChildren( 0, viewRoot.childCount );
 
 				// Convert model to view.
 				view.change( writer => {
@@ -279,7 +279,7 @@ describe( 'downcast-selection-converters', () => {
 				} );
 
 				// Remove view children manually (without firing additional conversion).
-				viewRoot.removeChildren( 0, viewRoot.childCount );
+				viewRoot._removeChildren( 0, viewRoot.childCount );
 
 				// Convert model to view.
 				view.change( writer => {
@@ -298,7 +298,7 @@ describe( 'downcast-selection-converters', () => {
 				setModelData( model, '' );
 
 				// Add two ui elements to view.
-				viewRoot.appendChildren( [
+				viewRoot._appendChildren( [
 					new ViewUIElement( 'span' ),
 					new ViewUIElement( 'span' )
 				] );
@@ -333,7 +333,7 @@ describe( 'downcast-selection-converters', () => {
 
 					// Add ui element to view.
 					const uiElement = new ViewUIElement( 'span' );
-					viewRoot.insertChildren( 1, uiElement );
+					viewRoot._insertChildren( 1, uiElement );
 
 					dispatcher.convertSelection( docSelection, model.markers, writer );
 				} );
@@ -358,7 +358,7 @@ describe( 'downcast-selection-converters', () => {
 
 					// Add ui element to view.
 					const uiElement = new ViewUIElement( 'span' );
-					viewRoot.insertChildren( 1, uiElement, writer );
+					viewRoot._insertChildren( 1, uiElement, writer );
 					dispatcher.convertSelection( docSelection, model.markers, writer );
 				} );
 
@@ -587,7 +587,7 @@ describe( 'downcast-selection-converters', () => {
 		} );
 
 		// Remove view children manually (without firing additional conversion).
-		viewRoot.removeChildren( 0, viewRoot.childCount );
+		viewRoot._removeChildren( 0, viewRoot.childCount );
 
 		// Convert model to view.
 		view.change( writer => {

+ 7 - 7
packages/ckeditor5-engine/tests/conversion/downcastdispatcher.js

@@ -152,7 +152,7 @@ describe( 'DowncastDispatcher', () => {
 
 	describe( 'convertInsert', () => {
 		it( 'should fire event with correct parameters for every item in passed range', () => {
-			root.appendChildren( [
+			root._appendChildren( [
 				new ModelText( 'foo', { bold: true } ),
 				new ModelElement( 'image' ),
 				new ModelText( 'bar' ),
@@ -206,7 +206,7 @@ describe( 'DowncastDispatcher', () => {
 		} );
 
 		it( 'should not fire events for already consumed parts of model', () => {
-			root.appendChildren( [
+			root._appendChildren( [
 				new ModelElement( 'image', { src: 'foo.jpg', title: 'bar', bold: true }, [
 					new ModelElement( 'caption', {}, new ModelText( 'title' ) )
 				] )
@@ -252,7 +252,7 @@ describe( 'DowncastDispatcher', () => {
 		beforeEach( () => {
 			dispatcher.off( 'selection' );
 
-			root.appendChildren( new ModelText( 'foobar' ) );
+			root._appendChildren( new ModelText( 'foobar' ) );
 			model.change( writer => {
 				writer.setSelection( [
 					new ModelRange( new ModelPosition( root, [ 1 ] ), new ModelPosition( root, [ 3 ] ) ),
@@ -373,12 +373,12 @@ describe( 'DowncastDispatcher', () => {
 
 		it( 'should not fire event for marker if selection is in a element with custom highlight handling', () => {
 			// Clear after `beforeEach`.
-			root.removeChildren( 0, root.childCount );
+			root._removeChildren( 0, root.childCount );
 
 			const text = new ModelText( 'abc' );
 			const caption = new ModelElement( 'caption', null, text );
 			const image = new ModelElement( 'image', null, caption );
-			root.appendChildren( [ image ] );
+			root._appendChildren( [ image ] );
 
 			// Create view elements that will be "mapped" to model elements.
 			const viewCaption = new ViewContainerElement( 'caption' );
@@ -441,7 +441,7 @@ describe( 'DowncastDispatcher', () => {
 		beforeEach( () => {
 			text = new ModelText( 'foo bar baz' );
 			element = new ModelElement( 'paragraph', null, [ text ] );
-			root.appendChildren( [ element ] );
+			root._appendChildren( [ element ] );
 
 			range = ModelRange.createFromParentsAndOffsets( element, 0, element, 4 );
 		} );
@@ -521,7 +521,7 @@ describe( 'DowncastDispatcher', () => {
 		beforeEach( () => {
 			text = new ModelText( 'foo bar baz' );
 			element = new ModelElement( 'paragraph', null, [ text ] );
-			root.appendChildren( [ element ] );
+			root._appendChildren( [ element ] );
 
 			range = ModelRange.createFromParentsAndOffsets( element, 0, element, 4 );
 		} );

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

@@ -181,7 +181,7 @@ describe( 'Mapper', () => {
 			] );
 
 			modelDiv = new ModelRootElement();
-			modelDiv.appendChildren( [
+			modelDiv._appendChildren( [
 				new ModelText( 'x' ),
 				modelP,
 				new ModelText( 'zz' )
@@ -451,7 +451,7 @@ describe( 'Mapper', () => {
 			modelCaption = new ModelElement( 'caption', {}, new ModelText( 'foo' ) );
 			modelWidget = new ModelElement( 'widget', {}, [ modelImg, modelCaption ] );
 			modelDiv = new ModelRootElement();
-			modelDiv.appendChildren( [ new ModelText( 'x' ), modelWidget, new ModelText( 'zz' ) ] );
+			modelDiv._appendChildren( [ new ModelText( 'x' ), modelWidget, new ModelText( 'zz' ) ] );
 
 			viewTextX = new ViewText( 'y' );
 			viewTextZZ = new ViewText( 'zz' );

+ 1 - 1
packages/ckeditor5-engine/tests/conversion/viewconsumable.js

@@ -537,7 +537,7 @@ describe( 'ViewConsumable', () => {
 			const child1 = new ViewElement( 'p', { 'title': 'baz' }, [ text1 ] );
 			const child2 = new ViewElement( 'p' );
 			const child3 = new ViewElement( 'p', { 'style': 'top:10px;', 'class': 'qux bar' }, [ text2, child2 ] );
-			el.appendChildren( [ child1, child3 ] );
+			el._appendChildren( [ child1, child3 ] );
 
 			const newConsumable = ViewConsumable.createFrom( el );
 

+ 1 - 1
packages/ckeditor5-engine/tests/dataprocessor/htmldataprocessor.js

@@ -97,7 +97,7 @@ describe( 'HtmlDataProcessor', () => {
 
 		it( 'should return text if document fragment with single text node is passed', () => {
 			const fragment = new ViewDocumentFragment();
-			fragment.appendChildren( parse( 'foo bar' ) );
+			fragment._appendChildren( parse( 'foo bar' ) );
 
 			expect( dataProcessor.toData( fragment ) ).to.equal( 'foo bar' );
 		} );

+ 1 - 1
packages/ckeditor5-engine/tests/dataprocessor/xmldataprocessor.js

@@ -89,7 +89,7 @@ describe( 'XmlDataProcessor', () => {
 
 		it( 'should return text if document fragment with single text node is passed', () => {
 			const fragment = new ViewDocumentFragment();
-			fragment.appendChildren( parse( 'foo bar' ) );
+			fragment._appendChildren( parse( 'foo bar' ) );
 
 			expect( dataProcessor.toData( fragment ) ).to.equal( 'foo bar' );
 		} );

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

@@ -233,7 +233,7 @@ describe( 'debug tools', () => {
 
 		describe( 'for operations', () => {
 			beforeEach( () => {
-				modelRoot.appendChildren( [ new ModelText( 'foobar' ) ] );
+				modelRoot._appendChildren( [ new ModelText( 'foobar' ) ] );
 			} );
 
 			it( 'AttributeOperation', () => {
@@ -256,7 +256,7 @@ describe( 'debug tools', () => {
 
 			it( 'DetachOperation (element)', () => {
 				const element = new ModelElement( 'element' );
-				modelRoot.insertChildren( 0, element );
+				modelRoot._insertChildren( 0, element );
 
 				const op = new DetachOperation( ModelPosition.createBefore( element ), 1 );
 
@@ -268,7 +268,7 @@ describe( 'debug tools', () => {
 
 			it( 'DetachOperation (multiple nodes)', () => {
 				const element = new ModelElement( 'element' );
-				modelRoot.insertChildren( 0, element );
+				modelRoot._insertChildren( 0, element );
 
 				const op = new DetachOperation( ModelPosition.createBefore( element ), 2 );
 
@@ -376,7 +376,7 @@ describe( 'debug tools', () => {
 			} );
 
 			it( 'AttributeDelta', () => {
-				modelRoot.appendChildren( new ModelText( 'foobar' ) );
+				modelRoot._appendChildren( new ModelText( 'foobar' ) );
 
 				const delta = new AttributeDelta();
 				const op = new AttributeOperation( ModelRange.createIn( modelRoot ), 'key', null, { foo: 'bar' }, 0 );
@@ -427,7 +427,7 @@ describe( 'debug tools', () => {
 			} );
 
 			it( 'MarkerDelta', () => {
-				modelRoot.appendChildren( new ModelText( 'foobar' ) );
+				modelRoot._appendChildren( new ModelText( 'foobar' ) );
 
 				const delta = new MarkerDelta();
 				const op = new MarkerOperation( 'marker', null, ModelRange.createIn( modelRoot ), modelDoc.markers, 0 );
@@ -445,7 +445,7 @@ describe( 'debug tools', () => {
 				const firstEle = new ModelElement( 'paragraph' );
 				const removedEle = new ModelElement( 'paragraph', null, [ new ModelText( 'foo' ) ] );
 
-				otherRoot.appendChildren( [ firstEle, removedEle ] );
+				otherRoot._appendChildren( [ firstEle, removedEle ] );
 
 				const graveyard = modelDoc.graveyard;
 				const delta = new MergeDelta();
@@ -471,7 +471,7 @@ describe( 'debug tools', () => {
 				const firstEle = new ModelElement( 'paragraph' );
 				const removedEle = new ModelElement( 'paragraph', null, [ new ModelText( 'foo' ) ] );
 
-				otherRoot.appendChildren( [ firstEle, removedEle ] );
+				otherRoot._appendChildren( [ firstEle, removedEle ] );
 
 				const delta = new MergeDelta();
 				const move = new MoveOperation( ModelPosition.createAt( removedEle, 0 ), 3, ModelPosition.createAt( firstEle, 0 ), 0 );
@@ -527,7 +527,7 @@ describe( 'debug tools', () => {
 				const otherRoot = modelDoc.createRoot( 'main', 'otherRoot' );
 				const splitEle = new ModelElement( 'paragraph', null, [ new ModelText( 'foo' ) ] );
 
-				otherRoot.appendChildren( [ splitEle ] );
+				otherRoot._appendChildren( [ splitEle ] );
 
 				const delta = new SplitDelta();
 				const insert = new InsertOperation( ModelPosition.createAt( otherRoot, 1 ), [ new ModelElement( 'paragraph' ) ], 0 );
@@ -546,7 +546,7 @@ describe( 'debug tools', () => {
 				const otherRoot = modelDoc.createRoot( 'main', 'otherRoot' );
 				const splitEle = new ModelElement( 'paragraph', null, [ new ModelText( 'foo' ) ] );
 
-				otherRoot.appendChildren( [ splitEle ] );
+				otherRoot._appendChildren( [ splitEle ] );
 
 				const delta = new SplitDelta();
 				const insert = new InsertOperation( ModelPosition.createAt( otherRoot, 1 ), [ new ModelElement( 'paragraph' ) ], 0 );
@@ -581,7 +581,7 @@ describe( 'debug tools', () => {
 				const otherRoot = modelDoc.createRoot( 'main', 'otherRoot' );
 				const unwrapEle = new ModelElement( 'paragraph', null, [ new ModelText( 'foo' ) ] );
 
-				otherRoot.appendChildren( [ unwrapEle ] );
+				otherRoot._appendChildren( [ unwrapEle ] );
 
 				const graveyard = modelDoc.graveyard;
 				const delta = new UnwrapDelta();
@@ -630,7 +630,7 @@ describe( 'debug tools', () => {
 			const modelDoc = model.document;
 			const modelRoot = modelDoc.createRoot();
 
-			modelRoot.appendChildren( [
+			modelRoot._appendChildren( [
 				new ModelElement( 'paragraph', { foo: 'bar' }, [
 					new ModelText( 'This is ' ), new ModelText( 'bold', { bold: true } ), new ModelText( '.' )
 				] ),
@@ -699,7 +699,7 @@ describe( 'debug tools', () => {
 			const viewDoc = new ViewDocument();
 			const viewRoot = createViewRoot( viewDoc );
 
-			viewRoot.appendChildren( [
+			viewRoot._appendChildren( [
 				new ViewContainerElement( 'p', { foo: 'bar' }, [
 					new ViewText( 'This is ' ), new ViewAttributeElement( 'b', null, new ViewText( 'bold' ) ), new ViewText( '.' )
 				] ),
@@ -904,7 +904,7 @@ describe( 'debug tools', () => {
 			const firstEle = new ModelElement( 'paragraph' );
 			const removedEle = new ModelElement( 'paragraph', null, [ new ModelText( 'foo' ) ] );
 
-			otherRoot.appendChildren( [ firstEle, removedEle ] );
+			otherRoot._appendChildren( [ firstEle, removedEle ] );
 
 			const delta = new MergeDelta();
 			const graveyard = modelDoc.graveyard;
@@ -930,7 +930,7 @@ describe( 'debug tools', () => {
 			const firstEle = new ModelElement( 'paragraph' );
 			const removedEle = new ModelElement( 'paragraph', null, [ new ModelText( 'foo' ) ] );
 
-			otherRoot.appendChildren( [ firstEle, removedEle ] );
+			otherRoot._appendChildren( [ firstEle, removedEle ] );
 
 			const delta = new MergeDelta();
 			const graveyard = modelDoc.graveyard;

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

@@ -57,7 +57,7 @@ describe( 'model test utils', () => {
 	describe( 'getData', () => {
 		it( 'should use stringify method', () => {
 			const stringifySpy = sandbox.spy( getData, '_stringify' );
-			root.appendChildren( new Element( 'b', null, new Text( 'btext' ) ) );
+			root._appendChildren( new Element( 'b', null, new Text( 'btext' ) ) );
 
 			expect( getData( model, { withoutSelection: true } ) ).to.equal( '<b>btext</b>' );
 			sinon.assert.calledOnce( stringifySpy );
@@ -66,7 +66,7 @@ describe( 'model test utils', () => {
 
 		it( 'should use stringify method with selection', () => {
 			const stringifySpy = sandbox.spy( getData, '_stringify' );
-			root.appendChildren( new Element( 'b', null, new Text( 'btext' ) ) );
+			root._appendChildren( new Element( 'b', null, new Text( 'btext' ) ) );
 			model.change( writer => {
 				writer.setSelection( Range.createFromParentsAndOffsets( root, 0, root, 1 ) );
 			} );
@@ -214,7 +214,7 @@ describe( 'model test utils', () => {
 		} );
 
 		it( 'writes elements and texts', () => {
-			root.appendChildren( [
+			root._appendChildren( [
 				new Element( 'a', null, new Text( 'atext' ) ),
 				new Element( 'b', null, [
 					new Element( 'c1' ),
@@ -230,7 +230,7 @@ describe( 'model test utils', () => {
 		} );
 
 		it( 'writes element attributes', () => {
-			root.appendChildren(
+			root._appendChildren(
 				new Element( 'a', { foo: true, bar: 1, car: false }, [
 					new Element( 'b', { fooBar: 'x y', barFoo: { x: 1, y: 2 } } )
 				] )
@@ -244,7 +244,7 @@ describe( 'model test utils', () => {
 		} );
 
 		it( 'writes text attributes', () => {
-			root.appendChildren( [
+			root._appendChildren( [
 				new Text( 'foo', { bold: true } ),
 				new Text( 'bar' ),
 				new Text( 'bom', { bold: true, italic: true } ),
@@ -260,7 +260,7 @@ describe( 'model test utils', () => {
 		} );
 
 		it( 'writes unicode text', () => {
-			root.appendChildren( new Text( 'நிலைக்கு' ) );
+			root._appendChildren( new Text( 'நிலைக்கு' ) );
 
 			expect( stringify( root ) ).to.equal( 'நிலைக்கு' );
 		} );
@@ -272,7 +272,7 @@ describe( 'model test utils', () => {
 				elA = new Element( 'a' );
 				elB = new Element( 'b' );
 
-				root.appendChildren( [
+				root._appendChildren( [
 					elA,
 					new Text( 'foo' ),
 					new Text( 'bar', { bold: true } ),
@@ -397,7 +397,7 @@ describe( 'model test utils', () => {
 			it( 'writes selection in unicode text', () => {
 				const root = document.createRoot( '$root', 'empty' );
 
-				root.appendChildren( new Text( 'நிலைக்கு' ) );
+				root._appendChildren( new Text( 'நிலைக்கு' ) );
 				model.change( writer => {
 					writer.setSelection( Range.createFromParentsAndOffsets( root, 2, root, 6 ) );
 				} );

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

@@ -40,7 +40,7 @@ describe( 'view test utils', () => {
 				const viewDocument = view.document;
 				const options = { showType: false, showPriority: false, withoutSelection: true };
 				const root = createAttachedRoot( viewDocument, element );
-				root.appendChildren( new Element( 'p' ) );
+				root._appendChildren( new Element( 'p' ) );
 
 				expect( getData( view, options ) ).to.equal( '<p></p>' );
 				sinon.assert.calledOnce( stringifySpy );
@@ -61,7 +61,7 @@ describe( 'view test utils', () => {
 				const viewDocument = view.document;
 				const options = { showType: false, showPriority: false };
 				const root = createAttachedRoot( viewDocument, element );
-				root.appendChildren( new Element( 'p' ) );
+				root._appendChildren( new Element( 'p' ) );
 
 				view.change( writer => {
 					writer.setSelection( Range.createFromParentsAndOffsets( root, 0, root, 1 ) );

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

@@ -19,8 +19,6 @@ import {
 	downcastAttributeToElement,
 } from '../../../../src/conversion/downcast-converters';
 
-import AttributeElement from '../../../../src/view/attributeelement';
-
 import Enter from '@ckeditor/ckeditor5-enter/src/enter';
 import Typing from '@ckeditor/ckeditor5-typing/src/typing';
 import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
@@ -33,8 +31,11 @@ class Link extends Plugin {
 		// Allow bold attribute on all inline nodes.
 		editor.model.schema.extend( '$text', { allowAttributes: 'link' } );
 
-		editor.conversion.for( 'downcast' ).add( downcastAttributeToElement( 'link', {
-			view: attributeValue => new AttributeElement( 'a', { href: attributeValue } )
+		editor.conversion.for( 'downcast' ).add( downcastAttributeToElement( {
+			model: 'link',
+			view: ( modelAttributeValue, viewWriter ) => {
+				return viewWriter.createAttributeElement( 'a', { href: modelAttributeValue } );
+			}
 		} ) );
 
 		editor.conversion.for( 'upcast' ).add( upcastElementToAttribute( {
@@ -53,16 +54,12 @@ class AutoLinker extends Plugin {
 			const changes = this.editor.model.document.differ.getChanges();
 
 			for ( const entry of changes ) {
-				if ( entry.type != 'insert' || entry.name != '$text' || !entry.position.textNode ) {
+				if ( entry.type != 'insert' || entry.name != '$text' || !entry.position.parent ) {
 					continue;
 				}
 
-				const textNode = entry.position.textNode;
-				const text = textNode.data;
-
-				if ( !text ) {
-					return;
-				}
+				const parent = entry.position.parent;
+				const text = Array.from( parent.getChildren() ).map( item => item.data ).join( '' );
 
 				const regexp = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g;
 				let match;
@@ -73,7 +70,7 @@ class AutoLinker extends Plugin {
 					const length = url.length;
 
 					if ( entry.position.offset + entry.length == index + length ) {
-						const livePos = LivePosition.createFromParentAndOffset( textNode.parent, index );
+						const livePos = LivePosition.createFromParentAndOffset( parent, index );
 						this.editor.model.enqueueChange( writer => {
 							const urlRange = Range.createFromPositionAndShift( livePos, length );
 							writer.setAttribute( 'link', url, urlRange );

+ 1 - 1
packages/ckeditor5-engine/tests/model/delta/renamedelta.js

@@ -39,7 +39,7 @@ describe( 'RenameDelta', () => {
 		} );
 
 		it( 'should return correct RenameDelta', () => {
-			root.appendChildren( new Element( 'p', null, new Text( 'abc' ) ) );
+			root._appendChildren( new Element( 'p', null, new Text( 'abc' ) ) );
 
 			model.change( writer => {
 				writer.rename( root.getChild( 0 ), 'h' );

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

@@ -225,7 +225,7 @@ export function getFilledDocument() {
 	const doc = model.document;
 	const root = doc.createRoot();
 
-	root.insertChildren( 0, [
+	root._insertChildren( 0, [
 		new Element( 'x' ),
 		new Element( 'x' ),
 		new Element( 'x', [], new Text( 'a' ) ),

+ 1 - 1
packages/ckeditor5-engine/tests/model/delta/transform/splitdelta.js

@@ -690,7 +690,7 @@ describe( 'transform', () => {
 			} );
 
 			it( 'attribute removed from split element', () => {
-				splitDelta.operations[ 0 ].nodes.getNode( 0 ).setAttribute( 'key', 'oldValue' );
+				splitDelta.operations[ 0 ].nodes.getNode( 0 )._setAttribute( 'key', 'oldValue' );
 				const attributeDelta = new AttributeDelta();
 
 				attributeDelta.addOperation( new AttributeOperation(

+ 1 - 1
packages/ckeditor5-engine/tests/model/delta/transform/transform.js

@@ -44,7 +44,7 @@ describe( 'transform', () => {
 		doc = model.document;
 		root = doc.createRoot();
 
-		root.appendChildren( new Element( 'p', null, new Text( 'foobar' ) ) );
+		root._appendChildren( new Element( 'p', null, new Text( 'foobar' ) ) );
 
 		baseVersion = doc.version;
 	} );

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

@@ -27,7 +27,7 @@ describe( 'Differ', () => {
 
 		root = doc.createRoot();
 
-		root.appendChildren( [
+		root._appendChildren( [
 			new Element( 'paragraph', null, [
 				new Text( 'foo' )
 			] ),
@@ -615,7 +615,7 @@ describe( 'Differ', () => {
 		} );
 
 		it( 'reinsert removed element', () => {
-			doc.graveyard.appendChildren( new Element( 'listItem' ) );
+			doc.graveyard._appendChildren( new Element( 'listItem' ) );
 
 			const sourcePosition = new Position( doc.graveyard, [ 0 ] );
 			const targetPosition = new Position( root, [ 2 ] );
@@ -811,7 +811,7 @@ describe( 'Differ', () => {
 		it( 'remove and add attribute on text', () => {
 			const p = root.getChild( 1 );
 
-			p.getChild( 0 ).setAttribute( 'bold', true );
+			p.getChild( 0 )._setAttribute( 'bold', true );
 
 			const range = Range.createFromParentsAndOffsets( p, 1, p, 3 );
 
@@ -1215,8 +1215,8 @@ describe( 'Differ', () => {
 			// it appeared that `blockQuote` looks like it is removed because it had the same path as the already removed `<image>`.
 			// In a result, removing `paragraph` was discarded.
 			// The mistake was that the checking for removing was done at incorrect moment.
-			root.removeChildren( 0, root.childCount );
-			root.appendChildren( [
+			root._removeChildren( 0, root.childCount );
+			root._appendChildren( [
 				new Element( 'paragraph', null, new Text( 'foo' ) ),
 				new Element( 'image' ),
 				new Element( 'blockQuote', null, [
@@ -1245,9 +1245,9 @@ describe( 'Differ', () => {
 		// In this scenario we create a new element, then remove something from before it to mess up with offsets,
 		// finally we insert some content into a new element. Since we are inserting into a new element, the
 		// inserted children should not be shown on changes list.
-		it( 'proper filtering of changes in inserted elements #1', () => {
-			root.removeChildren( 0, root.childCount );
-			root.appendChildren( new Element( 'image' ) );
+		it( 'proper filtering of changes in inserted elements', () => {
+			root._removeChildren( 0, root.childCount );
+			root._appendChildren( new Element( 'image' ) );
 
 			const blockQuote = new Element( 'blockQuote', null, new Element( 'paragraph' ) );
 
@@ -1270,8 +1270,8 @@ describe( 'Differ', () => {
 		// the new element. This way we mess up with offsets and insert content into a new element in one operation.
 		// Since we are inserting into a new element, the insertion of moved element should not be shown on changes list.
 		it( 'proper filtering of changes in inserted elements #2', () => {
-			root.removeChildren( 0, root.childCount );
-			root.appendChildren( new Element( 'image' ) );
+			root._removeChildren( 0, root.childCount );
+			root._appendChildren( new Element( 'image' ) );
 
 			model.change( () => {
 				// Insert `div` after `image`.

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

@@ -343,7 +343,7 @@ describe( 'Document', () => {
 			const spy = sinon.spy();
 
 			const root = doc.getRoot();
-			root.appendChildren( new Text( 'foo' ) );
+			root._appendChildren( new Text( 'foo' ) );
 
 			doc.on( 'change', spy );
 

+ 11 - 11
packages/ckeditor5-engine/tests/model/documentfragment.js

@@ -125,10 +125,10 @@ describe( 'DocumentFragment', () => {
 		} );
 	} );
 
-	describe( 'insertChildren', () => {
+	describe( '_insertChildren', () => {
 		it( 'should add children to the document fragment', () => {
 			const frag = new DocumentFragment( new Text( 'xy' ) );
-			frag.insertChildren( 1, new Text( 'foo' ) );
+			frag._insertChildren( 1, new Text( 'foo' ) );
 
 			expect( frag.childCount ).to.equal( 2 );
 			expect( frag.maxOffset ).to.equal( 5 );
@@ -139,13 +139,13 @@ describe( 'DocumentFragment', () => {
 		it( 'should accept strings and arrays', () => {
 			const frag = new DocumentFragment();
 
-			frag.insertChildren( 0, 'abc' );
+			frag._insertChildren( 0, 'abc' );
 			expect( frag.childCount ).to.equal( 1 );
 			expect( frag.maxOffset ).to.equal( 3 );
 			expect( frag.getChild( 0 ) ).to.have.property( 'data' ).that.equals( 'abc' );
 
-			frag.removeChildren( 0, 1 );
-			frag.insertChildren( 0, [ new Element( 'p' ), 'abc' ] );
+			frag._removeChildren( 0, 1 );
+			frag._insertChildren( 0, [ new Element( 'p' ), 'abc' ] );
 
 			expect( frag.childCount ).to.equal( 2 );
 			expect( frag.maxOffset ).to.equal( 4 );
@@ -158,7 +158,7 @@ describe( 'DocumentFragment', () => {
 			const text = new Text( 'abcxyz', { bold: true } );
 			const textProxy = new TextProxy( text, 2, 3 );
 
-			frag.insertChildren( 0, textProxy );
+			frag._insertChildren( 0, textProxy );
 
 			expect( frag.childCount ).to.equal( 1 );
 			expect( frag.maxOffset ).to.equal( 3 );
@@ -168,10 +168,10 @@ describe( 'DocumentFragment', () => {
 		} );
 	} );
 
-	describe( 'appendChildren', () => {
+	describe( '_appendChildren', () => {
 		it( 'should add children to the end of the element', () => {
 			const frag = new DocumentFragment( new Text( 'xy' ) );
-			frag.appendChildren( new Text( 'foo' ) );
+			frag._appendChildren( new Text( 'foo' ) );
 
 			expect( frag.childCount ).to.equal( 2 );
 			expect( frag.maxOffset ).to.equal( 5 );
@@ -180,10 +180,10 @@ describe( 'DocumentFragment', () => {
 		} );
 	} );
 
-	describe( 'removeChildren', () => {
+	describe( '_removeChildren', () => {
 		it( 'should remove children from the element and return them as an array', () => {
 			const frag = new DocumentFragment( [ new Text( 'foobar' ), new Element( 'image' ) ] );
-			const removed = frag.removeChildren( 1, 1 );
+			const removed = frag._removeChildren( 1, 1 );
 
 			expect( frag.childCount ).to.equal( 1 );
 			expect( frag.maxOffset ).to.equal( 6 );
@@ -196,7 +196,7 @@ describe( 'DocumentFragment', () => {
 
 		it( 'should remove one child when second parameter is not specified', () => {
 			const frag = new DocumentFragment( [ new Text( 'foo' ), new Element( 'image' ) ] );
-			const removed = frag.removeChildren( 0 );
+			const removed = frag._removeChildren( 0 );
 
 			expect( frag.childCount ).to.equal( 1 );
 			expect( frag.maxOffset ).to.equal( 1 );

+ 45 - 27
packages/ckeditor5-engine/tests/model/documentselection.js

@@ -34,7 +34,7 @@ describe( 'DocumentSelection', () => {
 		model = new Model();
 		doc = model.document;
 		root = doc.createRoot();
-		root.appendChildren( [
+		root._appendChildren( [
 			new Element( 'p' ),
 			new Element( 'p' ),
 			new Element( 'p', [], new Text( 'foobar' ) ),
@@ -73,7 +73,7 @@ describe( 'DocumentSelection', () => {
 			model = new Model();
 			doc = model.document;
 			root = doc.createRoot();
-			root.insertChildren( 0, new Text( 'foobar' ) );
+			root._insertChildren( 0, new Text( 'foobar' ) );
 			selection = doc.selection;
 
 			const ranges = Array.from( selection.getRanges() );
@@ -89,7 +89,7 @@ describe( 'DocumentSelection', () => {
 			model = new Model();
 			doc = model.document;
 			root = doc.createRoot();
-			root.insertChildren( 0, [
+			root._insertChildren( 0, [
 				new Element( 'img' ),
 				new Element( 'p', [], new Text( 'foobar' ) )
 			] );
@@ -113,7 +113,7 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'should be false for the default range (object selection) ', () => {
-			root.insertChildren( 0, new Element( 'widget' ) );
+			root._insertChildren( 0, new Element( 'widget' ) );
 
 			expect( selection.isCollapsed ).to.be.false;
 		} );
@@ -133,7 +133,7 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'should equal the default range\'s start (object selection)', () => {
-			root.insertChildren( 0, new Element( 'widget' ) );
+			root._insertChildren( 0, new Element( 'widget' ) );
 
 			const expectedPos = new Position( root, [ 0 ] );
 
@@ -155,7 +155,7 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'should equal the default range\'s end (object selection)', () => {
-			root.insertChildren( 0, new Element( 'widget' ) );
+			root._insertChildren( 0, new Element( 'widget' ) );
 
 			const expectedPos = new Position( root, [ 1 ] );
 
@@ -405,8 +405,8 @@ describe( 'DocumentSelection', () => {
 		let fullP, emptyP, rangeInFullP, rangeInEmptyP;
 
 		beforeEach( () => {
-			root.removeChildren( 0, root.childCount );
-			root.appendChildren( [
+			root._removeChildren( 0, root.childCount );
+			root._appendChildren( [
 				new Element( 'p', [], new Text( 'foobar' ) ),
 				new Element( 'p', [], [] )
 			] );
@@ -439,6 +439,21 @@ describe( 'DocumentSelection', () => {
 
 				expect( selection.getAttribute( 'foo' ) ).to.be.undefined;
 			} );
+
+			it( 'should prevent auto update of the attribute even if attribute is not preset yet', () => {
+				selection._setTo( new Position( root, [ 0, 1 ] ) );
+
+				// Remove "foo" attribute that is not present in selection yet.
+				expect( selection.hasAttribute( 'foo' ) ).to.be.false;
+				selection._removeAttribute( 'foo' );
+
+				// 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 ) );
+				} );
+
+				expect( selection.getAttribute( 'foo' ) ).to.be.undefined;
+			} );
 		} );
 
 		describe( '_getStoredAttributes()', () => {
@@ -451,7 +466,7 @@ describe( 'DocumentSelection', () => {
 
 		describe( 'are updated on a direct range change', () => {
 			beforeEach( () => {
-				root.insertChildren( 0, [
+				root._insertChildren( 0, [
 					new Element( 'p', { p: true } ),
 					new Text( 'a', { a: true } ),
 					new Element( 'p', { p: true } ),
@@ -651,10 +666,10 @@ describe( 'DocumentSelection', () => {
 
 			it( 'are removed when containing element is merged with a non-empty element', () => {
 				const emptyP2 = new Element( 'p', null, 'x' );
-				root.appendChildren( emptyP2 );
+				root._appendChildren( emptyP2 );
 
-				emptyP.setAttribute( fooStoreAttrKey, 'bar' );
-				emptyP2.setAttribute( fooStoreAttrKey, 'bar' );
+				emptyP._setAttribute( fooStoreAttrKey, 'bar' );
+				emptyP2._setAttribute( fooStoreAttrKey, 'bar' );
 
 				model.change( writer => {
 					// <emptyP>{}<emptyP2>
@@ -666,7 +681,7 @@ describe( 'DocumentSelection', () => {
 			} );
 
 			it( 'are removed even when there is no selection in it', () => {
-				emptyP.setAttribute( fooStoreAttrKey, 'bar' );
+				emptyP._setAttribute( fooStoreAttrKey, 'bar' );
 
 				selection._setTo( [ rangeInFullP ] );
 
@@ -680,10 +695,10 @@ describe( 'DocumentSelection', () => {
 			it( 'are removed only once in case of multi-op deltas', () => {
 				let batch;
 				const emptyP2 = new Element( 'p', null, 'x' );
-				root.appendChildren( emptyP2 );
+				root._appendChildren( emptyP2 );
 
-				emptyP.setAttribute( fooStoreAttrKey, 'bar' );
-				emptyP2.setAttribute( fooStoreAttrKey, 'bar' );
+				emptyP._setAttribute( fooStoreAttrKey, 'bar' );
+				emptyP2._setAttribute( fooStoreAttrKey, 'bar' );
 
 				model.change( writer => {
 					batch = writer.batch;
@@ -713,10 +728,10 @@ describe( 'DocumentSelection', () => {
 
 			it( 'are not removed or merged when containing element is merged with another empty element', () => {
 				const emptyP2 = new Element( 'p', null );
-				root.appendChildren( emptyP2 );
+				root._appendChildren( emptyP2 );
 
-				emptyP.setAttribute( fooStoreAttrKey, 'bar' );
-				emptyP2.setAttribute( abcStoreAttrKey, 'bar' );
+				emptyP._setAttribute( fooStoreAttrKey, 'bar' );
+				emptyP2._setAttribute( abcStoreAttrKey, 'bar' );
 
 				expect( emptyP.hasAttribute( fooStoreAttrKey ) ).to.be.true;
 				expect( emptyP.hasAttribute( abcStoreAttrKey ) ).to.be.false;
@@ -869,8 +884,8 @@ describe( 'DocumentSelection', () => {
 		let spyRange;
 
 		beforeEach( () => {
-			root.removeChildren( 0, root.childCount );
-			root.insertChildren( 0, [
+			root._removeChildren( 0, root.childCount );
+			root._insertChildren( 0, [
 				new Element( 'p', [], new Text( 'abcdef' ) ),
 				new Element( 'p', [], new Text( 'foobar' ) ),
 				new Text( 'xyz' )
@@ -1066,6 +1081,9 @@ describe( 'DocumentSelection', () => {
 					)
 				) );
 
+				// Attributes are auto updated on document change.
+				model.change( () => {} );
+
 				expect( selection.getAttribute( 'foo' ) ).to.equal( 'bar' );
 				expect( spyAttribute.calledOnce ).to.be.true;
 			} );
@@ -1204,8 +1222,8 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( '`DocumentSelection#change:range` event should be fire once even if selection contains multi-ranges', () => {
-			root.removeChildren( 0, root.childCount );
-			root.insertChildren( 0, [
+			root._removeChildren( 0, root.childCount );
+			root._insertChildren( 0, [
 				new Element( 'p', [], new Text( 'abcdef' ) ),
 				new Element( 'p', [], new Text( 'foobar' ) ),
 				new Text( 'xyz #2' )
@@ -1232,8 +1250,8 @@ describe( 'DocumentSelection', () => {
 	} );
 
 	it( 'should throw if one of ranges starts or ends inside surrogate pair', () => {
-		root.removeChildren( 0, root.childCount );
-		root.appendChildren( '\uD83D\uDCA9' );
+		root._removeChildren( 0, root.childCount );
+		root._appendChildren( '\uD83D\uDCA9' );
 
 		expect( () => {
 			doc.selection._setTo( Range.createFromParentsAndOffsets( root, 0, root, 1 ) );
@@ -1245,8 +1263,8 @@ describe( 'DocumentSelection', () => {
 	} );
 
 	it( 'should throw if one of ranges starts or ends between base character and combining mark', () => {
-		root.removeChildren( 0, root.childCount );
-		root.appendChildren( 'foo̻̐ͩbar' );
+		root._removeChildren( 0, root.childCount );
+		root._appendChildren( 'foo̻̐ͩbar' );
 
 		expect( () => {
 			doc.selection._setTo( Range.createFromParentsAndOffsets( root, 3, root, 9 ) );

+ 16 - 16
packages/ckeditor5-engine/tests/model/element.js

@@ -62,13 +62,13 @@ describe( 'Element', () => {
 		} );
 	} );
 
-	describe( 'clone', () => {
+	describe( '_clone()', () => {
 		it( 'should return an element with same name, attributes and same instances of children if clone was not deep', () => {
 			const p = new Element( 'p' );
 			const foo = new Text( 'foo' );
 
 			const element = new Element( 'elem', { bold: true, italic: true }, [ p, foo ] );
-			const copy = element.clone();
+			const copy = element._clone();
 
 			expect( copy.name ).to.equal( 'elem' );
 			expect( Array.from( copy.getAttributes() ) ).to.deep.equal( [ [ 'bold', true ], [ 'italic', true ] ] );
@@ -81,7 +81,7 @@ describe( 'Element', () => {
 			const p = new Element( 'p', null, bar );
 
 			const element = new Element( 'elem', { bold: true, italic: true }, [ p, foo ] );
-			const copy = element.clone( true );
+			const copy = element._clone( true );
 
 			expect( copy.name ).to.equal( 'elem' );
 			expect( Array.from( copy.getAttributes() ) ).to.deep.equal( [ [ 'bold', true ], [ 'italic', true ] ] );
@@ -97,10 +97,10 @@ describe( 'Element', () => {
 		} );
 	} );
 
-	describe( 'insertChildren', () => {
+	describe( '_insertChildren', () => {
 		it( 'should add a child to the element', () => {
 			const element = new Element( 'elem', [], new Text( 'xy' ) );
-			element.insertChildren( 1, new Text( 'foo' ) );
+			element._insertChildren( 1, new Text( 'foo' ) );
 
 			expect( element.childCount ).to.equal( 2 );
 			expect( element.maxOffset ).to.equal( 5 );
@@ -110,7 +110,7 @@ describe( 'Element', () => {
 
 		it( 'should accept arrays and strings', () => {
 			const element = new Element( 'elem' );
-			element.insertChildren( 0, [ new Element( 'image' ), 'xy', new Element( 'list' ) ] );
+			element._insertChildren( 0, [ new Element( 'image' ), 'xy', new Element( 'list' ) ] );
 
 			expect( element.childCount ).to.equal( 3 );
 			expect( element.maxOffset ).to.equal( 4 );
@@ -121,7 +121,7 @@ describe( 'Element', () => {
 
 		it( 'should accept strings', () => {
 			const element = new Element( 'div' );
-			element.insertChildren( 0, 'abc' );
+			element._insertChildren( 0, 'abc' );
 
 			expect( element.childCount ).to.equal( 1 );
 			expect( element.maxOffset ).to.equal( 3 );
@@ -133,7 +133,7 @@ describe( 'Element', () => {
 			const text = new Text( 'abcxyz', { bold: true } );
 			const textProxy = new TextProxy( text, 2, 3 );
 
-			element.insertChildren( 0, textProxy );
+			element._insertChildren( 0, textProxy );
 
 			expect( element.childCount ).to.equal( 1 );
 			expect( element.maxOffset ).to.equal( 3 );
@@ -143,23 +143,23 @@ describe( 'Element', () => {
 		} );
 	} );
 
-	describe( 'appendChildren', () => {
-		it( 'should use insertChildren to add children at the end of the element', () => {
+	describe( '_appendChildren', () => {
+		it( 'should use _insertChildren to add children at the end of the element', () => {
 			const element = new Element( 'elem', [], new Text( 'xy' ) );
 
-			sinon.spy( element, 'insertChildren' );
+			sinon.spy( element, '_insertChildren' );
 
 			const text = new Text( 'foo' );
-			element.appendChildren( text );
+			element._appendChildren( text );
 
-			expect( element.insertChildren.calledWithExactly( 0, text ) );
+			expect( element._insertChildren.calledWithExactly( 0, text ) );
 		} );
 	} );
 
-	describe( 'removeChildren', () => {
+	describe( '_removeChildren', () => {
 		it( 'should remove children from the element and return them as an array', () => {
 			const element = new Element( 'elem', [], [ new Text( 'foobar' ), new Element( 'image' ) ] );
-			const removed = element.removeChildren( 1, 1 );
+			const removed = element._removeChildren( 1, 1 );
 
 			expect( element.childCount ).to.equal( 1 );
 			expect( element.maxOffset ).to.equal( 6 );
@@ -172,7 +172,7 @@ describe( 'Element', () => {
 
 		it( 'should remove one child when second parameter is not specified', () => {
 			const element = new Element( 'element', [], [ new Text( 'foo' ), new Element( 'image' ) ] );
-			const removed = element.removeChildren( 0 );
+			const removed = element._removeChildren( 0 );
 
 			expect( element.childCount ).to.equal( 1 );
 			expect( element.maxOffset ).to.equal( 1 );

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

@@ -26,7 +26,7 @@ describe( 'LivePosition', () => {
 		ul = new Element( 'ul', [], [ li1, li2 ] );
 		p = new Element( 'p', [], new Text( 'qwerty' ) );
 
-		root.insertChildren( 0, [ p, ul ] );
+		root._insertChildren( 0, [ p, ul ] );
 	} );
 
 	afterEach( () => {

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

@@ -34,7 +34,7 @@ describe( 'LiveRange', () => {
 		ul = new Element( 'ul', [], lis );
 		p = new Element( 'p', [], new Text( 'qwertyuiop' ) );
 
-		root.insertChildren( 0, [ ul, p, new Text( 'xyzxyz' ) ] );
+		root._insertChildren( 0, [ ul, p, new Text( 'xyzxyz' ) ] );
 	} );
 
 	it( 'should be an instance of Range', () => {

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

@@ -241,7 +241,7 @@ describe( 'Marker', () => {
 	} );
 
 	it( 'should provide API that returns up-to-date marker range parameters', () => {
-		root.appendChildren( new Text( 'foo' ) );
+		root._appendChildren( new Text( 'foo' ) );
 
 		const range = Range.createFromParentsAndOffsets( root, 1, root, 2 );
 		const marker = model.markers._set( 'name', range );

+ 21 - 21
packages/ckeditor5-engine/tests/model/node.js

@@ -30,7 +30,7 @@ describe( 'Node', () => {
 
 		doc = model.document;
 		root = doc.createRoot();
-		root.appendChildren( [ one, two, three ] );
+		root._appendChildren( [ one, two, three ] );
 	} );
 
 	describe( 'should have a correct property', () => {
@@ -91,7 +91,7 @@ describe( 'Node', () => {
 
 			// DocumentFragment does not have document property, so node's document property should be null.
 			const docFrag = new DocumentFragment();
-			docFrag.appendChildren( node );
+			docFrag._appendChildren( node );
 			expect( node ).to.have.property( 'document' ).that.is.null;
 		} );
 	} );
@@ -136,22 +136,22 @@ describe( 'Node', () => {
 		} );
 	} );
 
-	describe( 'clone()', () => {
+	describe( '_clone()', () => {
 		it( 'should return a copy of cloned node', () => {
 			const node = new Node( { foo: 'bar' } );
-			const copy = node.clone();
+			const copy = node._clone();
 
 			expect( copy ).not.to.equal( node );
 			expect( Array.from( copy.getAttributes() ) ).to.deep.equal( Array.from( node.getAttributes() ) );
 		} );
 	} );
 
-	describe( 'remove()', () => {
+	describe( '_remove()', () => {
 		it( 'should remove node from it\'s parent', () => {
 			const element = new Element( 'p' );
-			element.appendChildren( node );
+			element._appendChildren( node );
 
-			node.remove();
+			node._remove();
 
 			expect( element.childCount ).to.equal( 0 );
 			expect( node.parent ).to.be.null;
@@ -159,7 +159,7 @@ describe( 'Node', () => {
 
 		it( 'should throw if node does not have a parent', () => {
 			expect( () => {
-				node.remove();
+				node._remove();
 			} ).to.throw;
 		} );
 	} );
@@ -348,46 +348,46 @@ describe( 'Node', () => {
 			} );
 		} );
 
-		describe( 'setAttribute', () => {
+		describe( '_setAttribute', () => {
 			it( 'should set given attribute on the element', () => {
-				node.setAttribute( 'foo', 'bar' );
+				node._setAttribute( 'foo', 'bar' );
 
 				expect( node.getAttribute( 'foo' ) ).to.equal( 'bar' );
 			} );
 		} );
 
-		describe( 'setAttributesTo', () => {
+		describe( '_setAttributesTo', () => {
 			it( 'should remove all attributes set on element and set the given ones', () => {
-				node.setAttribute( 'abc', 'xyz' );
-				node.setAttributesTo( { foo: 'bar' } );
+				node._setAttribute( 'abc', 'xyz' );
+				node._setAttributesTo( { foo: 'bar' } );
 
 				expect( node.getAttribute( 'foo' ) ).to.equal( 'bar' );
 				expect( node.getAttribute( 'abc' ) ).to.be.undefined;
 			} );
 		} );
 
-		describe( 'removeAttribute', () => {
+		describe( '_removeAttribute', () => {
 			it( 'should remove attribute set on the element and return true', () => {
-				node.setAttribute( 'foo', 'bar' );
-				const result = node.removeAttribute( 'foo' );
+				node._setAttribute( 'foo', 'bar' );
+				const result = node._removeAttribute( 'foo' );
 
 				expect( node.getAttribute( 'foo' ) ).to.be.undefined;
 				expect( result ).to.be.true;
 			} );
 
 			it( 'should return false if element does not contain given attribute', () => {
-				const result = node.removeAttribute( 'foo' );
+				const result = node._removeAttribute( 'foo' );
 
 				expect( result ).to.be.false;
 			} );
 		} );
 
-		describe( 'clearAttributes', () => {
+		describe( '_clearAttributes', () => {
 			it( 'should remove all attributes from the element', () => {
-				node.setAttribute( 'foo', 'bar' );
-				node.setAttribute( 'abc', 'xyz' );
+				node._setAttribute( 'foo', 'bar' );
+				node._setAttribute( 'abc', 'xyz' );
 
-				node.clearAttributes();
+				node._clearAttributes();
 
 				expect( node.getAttribute( 'foo' ) ).to.be.undefined;
 				expect( node.getAttribute( 'abc' ) ).to.be.undefined;

+ 7 - 7
packages/ckeditor5-engine/tests/model/nodelist.js

@@ -121,14 +121,14 @@ describe( 'NodeList', () => {
 		} );
 	} );
 
-	describe( 'insertNodes', () => {
+	describe( '_insertNodes', () => {
 		it( 'should insert nodes at given index', () => {
 			const newImg = new Element( 'image' );
-			nodes.insertNodes( 1, [ newImg ] );
+			nodes._insertNodes( 1, [ newImg ] );
 
 			const bar = new Text( 'bar', { bold: true } );
 			const xyz = new Text( 'xyz' );
-			nodes.insertNodes( 4, [ bar, xyz ] );
+			nodes._insertNodes( 4, [ bar, xyz ] );
 
 			expect( nodes.length ).to.equal( 6 );
 			expect( nodes.maxOffset ).to.equal( 12 );
@@ -159,14 +159,14 @@ describe( 'NodeList', () => {
 
 		it( 'should throw if not a Node is inserted', () => {
 			expect( () => {
-				nodes.insertNodes( 0, [ 'foo' ] );
+				nodes._insertNodes( 0, [ 'foo' ] );
 			} ).to.throw( CKEditorError, /nodelist-insertNodes-not-node/ );
 		} );
 	} );
 
-	describe( 'removeNodes', () => {
+	describe( '_removeNodes', () => {
 		it( 'should remove one or more nodes from given index', () => {
-			nodes.removeNodes( 0, 2 );
+			nodes._removeNodes( 0, 2 );
 
 			expect( nodes.length ).to.equal( 1 );
 			expect( nodes.maxOffset ).to.equal( 1 );
@@ -177,7 +177,7 @@ describe( 'NodeList', () => {
 		} );
 
 		it( 'should remove one node if howMany parameter was not specified', () => {
-			nodes.removeNodes( 1 );
+			nodes._removeNodes( 1 );
 
 			expect( nodes.length ).to.equal( 2 );
 			expect( nodes.maxOffset ).to.equal( 2 );

+ 17 - 17
packages/ckeditor5-engine/tests/model/operation/attributeoperation.js

@@ -61,7 +61,7 @@ describe( 'AttributeOperation', () => {
 	} );
 
 	it( 'should insert attribute to the set of nodes', () => {
-		root.insertChildren( 0, new Text( 'bar' ) );
+		root._insertChildren( 0, new Text( 'bar' ) );
 
 		model.applyOperation( wrapInDelta(
 			new AttributeOperation(
@@ -82,7 +82,7 @@ describe( 'AttributeOperation', () => {
 	} );
 
 	it( 'should add attribute to the existing attributes', () => {
-		root.insertChildren( 0, new Text( 'x', { foo: true, bar: true } ) );
+		root._insertChildren( 0, new Text( 'x', { foo: true, bar: true } ) );
 
 		model.applyOperation( wrapInDelta(
 			new AttributeOperation(
@@ -103,7 +103,7 @@ describe( 'AttributeOperation', () => {
 	} );
 
 	it( 'should change attribute to the set of nodes', () => {
-		root.insertChildren( 0, new Text( 'bar', { isNew: false } ) );
+		root._insertChildren( 0, new Text( 'bar', { isNew: false } ) );
 
 		model.applyOperation( wrapInDelta(
 			new AttributeOperation(
@@ -124,7 +124,7 @@ describe( 'AttributeOperation', () => {
 	} );
 
 	it( 'should change attribute in the middle of existing attributes', () => {
-		root.insertChildren( 0, new Text( 'x', { foo: true, x: 1, bar: true } ) );
+		root._insertChildren( 0, new Text( 'x', { foo: true, x: 1, bar: true } ) );
 
 		model.applyOperation( wrapInDelta(
 			new AttributeOperation(
@@ -145,7 +145,7 @@ describe( 'AttributeOperation', () => {
 	} );
 
 	it( 'should work correctly if old and new value are same', () => {
-		root.insertChildren( 0, new Text( 'bar', { foo: 'bar' } ) );
+		root._insertChildren( 0, new Text( 'bar', { foo: 'bar' } ) );
 
 		model.applyOperation( wrapInDelta(
 			new AttributeOperation(
@@ -164,7 +164,7 @@ describe( 'AttributeOperation', () => {
 	} );
 
 	it( 'should remove attribute', () => {
-		root.insertChildren( 0, new Text( 'x', { foo: true, x: true, bar: true } ) );
+		root._insertChildren( 0, new Text( 'x', { foo: true, x: true, bar: true } ) );
 
 		model.applyOperation( wrapInDelta(
 			new AttributeOperation(
@@ -185,7 +185,7 @@ describe( 'AttributeOperation', () => {
 
 	describe( '_validate()', () => {
 		it( 'should not throw for non-primitive attribute values', () => {
-			root.insertChildren( 0, new Text( 'x', { foo: [ 'bar', 'xyz' ] } ) );
+			root._insertChildren( 0, new Text( 'x', { foo: [ 'bar', 'xyz' ] } ) );
 
 			expect( () => {
 				const operation = new AttributeOperation(
@@ -201,7 +201,7 @@ describe( 'AttributeOperation', () => {
 		} );
 
 		it( 'should throw an error when one try to remove and the attribute does not exists', () => {
-			root.insertChildren( 0, new Text( 'x' ) );
+			root._insertChildren( 0, new Text( 'x' ) );
 
 			expect( () => {
 				const operation = new AttributeOperation(
@@ -217,7 +217,7 @@ describe( 'AttributeOperation', () => {
 		} );
 
 		it( 'should throw an error when one try to insert and the attribute already exists', () => {
-			root.insertChildren( 0, new Text( 'x', { x: 1 } ) );
+			root._insertChildren( 0, new Text( 'x', { x: 1 } ) );
 
 			expect( () => {
 				const operation = new AttributeOperation(
@@ -233,7 +233,7 @@ describe( 'AttributeOperation', () => {
 		} );
 
 		it( 'should not throw when attribute value is the same', () => {
-			root.insertChildren( 0, new Text( 'x', { foo: true } ) );
+			root._insertChildren( 0, new Text( 'x', { foo: true } ) );
 
 			expect( () => {
 				const operation = new AttributeOperation(
@@ -263,7 +263,7 @@ describe( 'AttributeOperation', () => {
 	} );
 
 	it( 'should undo adding attribute by applying reverse operation', () => {
-		root.insertChildren( 0, new Text( 'bar' ) );
+		root._insertChildren( 0, new Text( 'bar' ) );
 
 		const operation = new AttributeOperation(
 			new Range( new Position( root, [ 0 ] ), new Position( root, [ 3 ] ) ),
@@ -287,7 +287,7 @@ describe( 'AttributeOperation', () => {
 		const eleA = new Element( 'a', [], new Text( 'abc' ) );
 		const eleB = new Element( 'b', [], new Text( 'xyz' ) );
 
-		root.insertChildren( 0, [ eleA, eleB ] );
+		root._insertChildren( 0, [ eleA, eleB ] );
 
 		model.applyOperation( wrapInDelta(
 			new AttributeOperation(
@@ -308,7 +308,7 @@ describe( 'AttributeOperation', () => {
 		const eleA = new Element( 'a', fooAttr, new Text( 'abc' ) );
 		const eleB = new Element( 'b', fooAttr, new Text( 'xyz' ) );
 
-		root.insertChildren( 0, [ eleA, eleB ] );
+		root._insertChildren( 0, [ eleA, eleB ] );
 
 		model.applyOperation( wrapInDelta(
 			new AttributeOperation(
@@ -324,7 +324,7 @@ describe( 'AttributeOperation', () => {
 	} );
 
 	it( 'should undo changing attribute by applying reverse operation', () => {
-		root.insertChildren( 0, new Text( 'bar', { isNew: false } ) );
+		root._insertChildren( 0, new Text( 'bar', { isNew: false } ) );
 
 		const operation = new AttributeOperation(
 			new Range( new Position( root, [ 0 ] ), new Position( root, [ 3 ] ) ),
@@ -346,7 +346,7 @@ describe( 'AttributeOperation', () => {
 	} );
 
 	it( 'should undo remove attribute by applying reverse operation', () => {
-		root.insertChildren( 0, new Text( 'bar', { foo: true } ) );
+		root._insertChildren( 0, new Text( 'bar', { foo: true } ) );
 
 		const operation = new AttributeOperation(
 			new Range( new Position( root, [ 0 ] ), new Position( root, [ 3 ] ) ),
@@ -390,8 +390,8 @@ describe( 'AttributeOperation', () => {
 		const attrA = { foo: 'a' };
 		const attrB = { foo: 'b' };
 
-		root.insertChildren( 0, new Text( 'abc', attrA ) );
-		root.insertChildren( 1, new Text( 'xyz', attrB ) );
+		root._insertChildren( 0, new Text( 'abc', attrA ) );
+		root._insertChildren( 1, new Text( 'xyz', attrB ) );
 
 		model.applyOperation( wrapInDelta(
 			new AttributeOperation(

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

@@ -40,7 +40,7 @@ describe( 'DetachOperation', () => {
 			const root = doc.createRoot();
 			const element = new Element( 'element' );
 
-			root.appendChildren( [ element ] );
+			root._appendChildren( [ element ] );
 
 			const op = new DetachOperation( Position.createBefore( element ), 1 );
 

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

@@ -78,7 +78,7 @@ describe( 'InsertOperation', () => {
 	} );
 
 	it( 'should insert between existing nodes', () => {
-		root.insertChildren( 0, new Text( 'xy' ) );
+		root._insertChildren( 0, new Text( 'xy' ) );
 
 		model.applyOperation( wrapInDelta(
 			new InsertOperation(

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

@@ -20,7 +20,7 @@ describe( 'MarkerOperation', () => {
 		model = new Model();
 		doc = model.document;
 		root = doc.createRoot();
-		root.appendChildren( new Text( 'foo' ) );
+		root._appendChildren( new Text( 'foo' ) );
 		range = Range.createFromParentsAndOffsets( root, 0, root, 0 );
 	} );
 

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

@@ -46,7 +46,7 @@ describe( 'MoveOperation', () => {
 		const p1 = new Element( 'p1', [], new Element( 'x' ) );
 		const p2 = new Element( 'p2' );
 
-		root.insertChildren( 0, [ p1, p2 ] );
+		root._insertChildren( 0, [ p1, p2 ] );
 
 		model.applyOperation( wrapInDelta(
 			new MoveOperation(
@@ -67,7 +67,7 @@ describe( 'MoveOperation', () => {
 	} );
 
 	it( 'should move position of children in one node backward', () => {
-		root.insertChildren( 0, new Text( 'xbarx' ) );
+		root._insertChildren( 0, new Text( 'xbarx' ) );
 
 		model.applyOperation( wrapInDelta(
 			new MoveOperation(
@@ -84,7 +84,7 @@ describe( 'MoveOperation', () => {
 	} );
 
 	it( 'should move position of children in one node forward', () => {
-		root.insertChildren( 0, new Text( 'xbarx' ) );
+		root._insertChildren( 0, new Text( 'xbarx' ) );
 
 		model.applyOperation( wrapInDelta(
 			new MoveOperation(
@@ -124,7 +124,7 @@ describe( 'MoveOperation', () => {
 		const p1 = new Element( 'p1', [], new Element( 'x' ) );
 		const p2 = new Element( 'p2' );
 
-		root.insertChildren( 0, [ p1, p2 ] );
+		root._insertChildren( 0, [ p1, p2 ] );
 
 		const operation = new MoveOperation(
 			new Position( root, [ 0, 0 ] ),
@@ -152,7 +152,7 @@ describe( 'MoveOperation', () => {
 
 	describe( '_validate()', () => {
 		it( 'should throw an error if number of nodes to move exceeds the number of existing nodes in given element', () => {
-			root.insertChildren( 0, new Text( 'xbarx' ) );
+			root._insertChildren( 0, new Text( 'xbarx' ) );
 
 			const operation = new MoveOperation(
 				new Position( root, [ 3 ] ),
@@ -166,8 +166,8 @@ describe( 'MoveOperation', () => {
 
 		it( 'should throw an error if target or source parent-element specified by position does not exist', () => {
 			const p = new Element( 'p' );
-			p.insertChildren( 0, new Text( 'foo' ) );
-			root.insertChildren( 0, [ new Text( 'ab' ), p ] );
+			p._insertChildren( 0, new Text( 'foo' ) );
+			root._insertChildren( 0, [ new Text( 'ab' ), p ] );
 
 			const operation = new MoveOperation(
 				new Position( root, [ 2, 0 ] ),
@@ -176,13 +176,13 @@ describe( 'MoveOperation', () => {
 				doc.version
 			);
 
-			root.removeChildren( 1 );
+			root._removeChildren( 1 );
 
 			expect( () => operation._validate() ).to.throw( CKEditorError, /move-operation-position-invalid/ );
 		} );
 
 		it( 'should throw an error if operation tries to move a range between the beginning and the end of that range', () => {
-			root.insertChildren( 0, new Text( 'xbarx' ) );
+			root._insertChildren( 0, new Text( 'xbarx' ) );
 
 			const operation = new MoveOperation(
 				new Position( root, [ 1 ] ),
@@ -196,7 +196,7 @@ describe( 'MoveOperation', () => {
 
 		it( 'should throw an error if operation tries to move a range into a sub-tree of a node that is in that range', () => {
 			const p = new Element( 'p', [], [ new Element( 'p' ) ] );
-			root.insertChildren( 0, [ new Text( 'ab' ), p, new Text( 'xy' ) ] );
+			root._insertChildren( 0, [ new Text( 'ab' ), p, new Text( 'xy' ) ] );
 
 			const operation = new MoveOperation(
 				new Position( root, [ 1 ] ),
@@ -210,7 +210,7 @@ describe( 'MoveOperation', () => {
 
 		it( 'should not throw an error if operation move a range into a sibling', () => {
 			const p = new Element( 'p' );
-			root.insertChildren( 0, [ new Text( 'ab' ), p, new Text( 'xy' ) ] );
+			root._insertChildren( 0, [ new Text( 'ab' ), p, new Text( 'xy' ) ] );
 
 			const operation = new MoveOperation(
 				new Position( root, [ 1 ] ),
@@ -224,8 +224,8 @@ describe( 'MoveOperation', () => {
 
 		it( 'should not throw when operation paths looks like incorrect but move is between different roots', () => {
 			const p = new Element( 'p' );
-			root.insertChildren( 0, [ new Text( 'a' ), p, new Text( 'b' ) ] );
-			doc.graveyard.insertChildren( 0, new Text( 'abc' ) );
+			root._insertChildren( 0, [ new Text( 'a' ), p, new Text( 'b' ) ] );
+			doc.graveyard._insertChildren( 0, new Text( 'abc' ) );
 
 			const operation = new MoveOperation(
 				new Position( doc.graveyard, [ 0 ] ),

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

@@ -65,7 +65,7 @@ describe( 'ReinsertOperation', () => {
 	} );
 
 	it( 'should create RemoveOperation as a reverse', () => {
-		graveyard.appendChildren( new Element( 'x' ) );
+		graveyard._appendChildren( new Element( 'x' ) );
 
 		const reverse = operation.getReversed();
 
@@ -87,7 +87,7 @@ describe( 'ReinsertOperation', () => {
 	it( 'should undo reinsert set of nodes by applying reverse operation', () => {
 		const reverse = operation.getReversed();
 
-		graveyard.insertChildren( 0, new Text( 'xx' ) );
+		graveyard._insertChildren( 0, new Text( 'xx' ) );
 
 		model.applyOperation( wrapInDelta( operation ) );
 
@@ -106,7 +106,7 @@ describe( 'ReinsertOperation', () => {
 		it( 'should throw when target position is not in the document', () => {
 			const docFrag = new DocumentFragment();
 
-			graveyard.insertChildren( 0, new Text( 'xx' ) );
+			graveyard._insertChildren( 0, new Text( 'xx' ) );
 
 			operation = new ReinsertOperation(
 				graveyardPosition,

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

@@ -58,7 +58,7 @@ describe( 'RemoveOperation', () => {
 	} );
 
 	it( 'should be able to remove set of nodes and append them to graveyard root', () => {
-		root.insertChildren( 0, new Text( 'fozbar' ) );
+		root._insertChildren( 0, new Text( 'fozbar' ) );
 
 		model.applyOperation( wrapInDelta(
 			new RemoveOperation(
@@ -115,7 +115,7 @@ describe( 'RemoveOperation', () => {
 		const operation = new RemoveOperation( position, 3, new Position( doc.graveyard, [ 0 ] ), 0 );
 		const reverse = operation.getReversed();
 
-		root.insertChildren( 0, new Text( 'bar' ) );
+		root._insertChildren( 0, new Text( 'bar' ) );
 
 		model.applyOperation( wrapInDelta( operation ) );
 
@@ -130,7 +130,7 @@ describe( 'RemoveOperation', () => {
 	} );
 
 	it( 'should properly remove a node that is already in a graveyard', () => {
-		doc.graveyard.appendChildren( [ new Element( 'x' ), new Element( 'y' ), new Element( 'z' ) ] );
+		doc.graveyard._appendChildren( [ new Element( 'x' ), new Element( 'y' ), new Element( 'z' ) ] );
 
 		const position = new Position( doc.graveyard, [ 2 ] );
 		const operation = new RemoveOperation( position, 1, new Position( doc.graveyard, [ 0 ] ), 0 );
@@ -148,7 +148,7 @@ describe( 'RemoveOperation', () => {
 			const docFrag = new DocumentFragment();
 			const item = new Element( 'foo' );
 
-			docFrag.appendChildren( [ item ] );
+			docFrag._appendChildren( [ item ] );
 
 			const op = new RemoveOperation(
 				new Position( docFrag, [ 0 ] ),

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

@@ -22,7 +22,7 @@ describe( 'RenameOperation', () => {
 		root = doc.createRoot();
 
 		element = new Element( oldName );
-		root.appendChildren( element );
+		root._appendChildren( element );
 
 		position = Position.createBefore( element );
 	} );

+ 6 - 6
packages/ckeditor5-engine/tests/model/operation/rootattributeoperation.js

@@ -73,7 +73,7 @@ describe( 'RootAttributeOperation', () => {
 	} );
 
 	it( 'should change attribute on the root element', () => {
-		root.setAttribute( 'isNew', false );
+		root._setAttribute( 'isNew', false );
 
 		model.applyOperation( wrapInDelta(
 			new RootAttributeOperation(
@@ -90,7 +90,7 @@ describe( 'RootAttributeOperation', () => {
 	} );
 
 	it( 'should remove attribute from the root element', () => {
-		root.setAttribute( 'x', true );
+		root._setAttribute( 'x', true );
 
 		model.applyOperation( wrapInDelta(
 			new RootAttributeOperation(
@@ -137,7 +137,7 @@ describe( 'RootAttributeOperation', () => {
 	} );
 
 	it( 'should undo changing attribute by applying reverse operation', () => {
-		root.setAttribute( 'isNew', false );
+		root._setAttribute( 'isNew', false );
 
 		const operation = new RootAttributeOperation(
 			root,
@@ -157,7 +157,7 @@ describe( 'RootAttributeOperation', () => {
 	} );
 
 	it( 'should undo remove attribute by applying reverse operation', () => {
-		root.setAttribute( 'foo', true );
+		root._setAttribute( 'foo', true );
 
 		const operation = new RootAttributeOperation(
 			root,
@@ -180,7 +180,7 @@ describe( 'RootAttributeOperation', () => {
 		it( 'should throw an error when trying to change non-root element', () => {
 			const child = new Element( 'p' );
 			const parent = new Element( 'p' );
-			parent.appendChildren( child );
+			parent._appendChildren( child );
 
 			expect( () => {
 				const op = new RootAttributeOperation(
@@ -224,7 +224,7 @@ describe( 'RootAttributeOperation', () => {
 		} );
 
 		it( 'should throw an error when trying to add an attribute that already exists', () => {
-			root.setAttribute( 'x', 1 );
+			root._setAttribute( 'x', 1 );
 
 			expect( () => {
 				const op = new RootAttributeOperation(

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

@@ -29,7 +29,7 @@ describe( 'Operation utils', () => {
 		// offset:	0123456789
 		// data:	foobarIxyz
 		// bold:	___BBBB___
-		root.appendChildren( [
+		root._appendChildren( [
 			new Text( 'foo' ),
 			new Text( 'bar', { bold: true } ),
 			new Element( 'image', { src: 'img.jpg' } ),

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

@@ -56,7 +56,7 @@ describe( 'Position', () => {
 
 		p = new Element( 'p' );
 
-		root.insertChildren( 0, [ p, ul ] );
+		root._insertChildren( 0, [ p, ul ] );
 	} );
 
 	describe( 'constructor()', () => {
@@ -868,7 +868,7 @@ describe( 'Position', () => {
 
 			const p = new Element( 'p', null, 'foobar' );
 
-			root.appendChildren( p );
+			root._appendChildren( p );
 
 			const postion = new Position( root, [ 0, 3 ] ); // <p>foo^bar</p>
 
@@ -897,7 +897,7 @@ describe( 'Position', () => {
 
 			const p = new Element( 'p', null, new Element( 'a' ) );
 
-			root.appendChildren( p );
+			root._appendChildren( p );
 
 			const postion = new Position( root, [ 0, 0 ] ); // <p>^<a></a></p>
 

+ 9 - 9
packages/ckeditor5-engine/tests/model/range.js

@@ -160,7 +160,7 @@ describe( 'Range', () => {
 		beforeEach( () => {
 			p = new Element( 'p', [], new Text( 'foz' ) );
 
-			root.insertChildren( 0, [ p ] );
+			root._insertChildren( 0, [ p ] );
 		} );
 
 		describe( 'createIn()', () => {
@@ -245,7 +245,7 @@ describe( 'Range', () => {
 			}
 
 			beforeEach( () => {
-				root.appendChildren( new Text( 'abcdefghijklmnopqrtuvwxyz' ) );
+				root._appendChildren( new Text( 'abcdefghijklmnopqrtuvwxyz' ) );
 			} );
 
 			it( 'should throw if empty array is passed', () => {
@@ -337,9 +337,9 @@ describe( 'Range', () => {
 			const e1 = new Element( 'e1' );
 			const e2 = new Element( 'e2' );
 
-			e1.insertChildren( 0, [ a, b ] );
-			e2.insertChildren( 0, [ x, y ] );
-			root.insertChildren( 0, [ e1, e2 ] );
+			e1._insertChildren( 0, [ a, b ] );
+			e2._insertChildren( 0, [ x, y ] );
+			root._insertChildren( 0, [ e1, e2 ] );
 
 			const range = new Range(
 				new Position( root, [ 0, 1 ] ),
@@ -462,9 +462,9 @@ describe( 'Range', () => {
 			d = new Element( 'd' );
 
 			xxx = new Text( 'xxx' );
-			b.appendChildren( xxx );
+			b._appendChildren( xxx );
 
-			root.appendChildren( [ a, b, c, d ] );
+			root._appendChildren( [ a, b, c, d ] );
 		} );
 
 		it( 'should return true if element is inside range and false when it is not inside range', () => {
@@ -1214,7 +1214,7 @@ describe( 'Range', () => {
 
 	describe( 'getTransformedByDeltas()', () => {
 		beforeEach( () => {
-			root.appendChildren( new Text( 'foobar' ) );
+			root._appendChildren( new Text( 'foobar' ) );
 			range = Range.createFromParentsAndOffsets( root, 2, root, 5 );
 		} );
 
@@ -1338,7 +1338,7 @@ describe( 'Range', () => {
 	}
 
 	function prepareRichRoot() {
-		root.insertChildren( 0, [
+		root._insertChildren( 0, [
 			new Element( 'div', [], [
 				new Element( 'h', [], new Text( 'first' ) ),
 				new Element( 'p', [], new Text( 'lorem ipsum' ) )

+ 8 - 8
packages/ckeditor5-engine/tests/model/schema.js

@@ -1501,7 +1501,7 @@ describe( 'Schema', () => {
 			const text = new Text( 'foo', { a: 1, b: 1 } );
 			const image = new Element( 'image', { a: 1, b: 1 } );
 
-			root.appendChildren( [ text, image ] );
+			root._appendChildren( [ text, image ] );
 
 			model.change( writer => {
 				schema.removeDisallowedAttributes( root.getChildren(), writer );
@@ -1548,7 +1548,7 @@ describe( 'Schema', () => {
 			const paragraph = new Element( 'paragraph', [], [ foo, imageInParagraph ] );
 			const div = new Element( 'div', [], [ paragraph, bar, imageInDiv ] );
 
-			root.appendChildren( [ div ] );
+			root._appendChildren( [ div ] );
 
 			model.change( writer => {
 				schema.removeDisallowedAttributes( root.getChildren(), writer );
@@ -1612,7 +1612,7 @@ describe( 'Schema', () => {
 				} );
 
 				const div = new Element( 'div' );
-				root1.appendChildren( div );
+				root1._appendChildren( div );
 
 				const div2 = new Element( 'div' );
 
@@ -1626,7 +1626,7 @@ describe( 'Schema', () => {
 				} );
 
 				const div = new Element( 'div' );
-				root1.appendChildren( div );
+				root1._appendChildren( div );
 
 				expect( schema.checkChild( div, div ) ).to.be.true;
 			} );
@@ -2063,7 +2063,7 @@ describe( 'Schema', () => {
 			it( 'does not break when trying to check registered child in a context which contains non-registered elements', () => {
 				const foo404 = new Element( 'foo404' );
 
-				root1.appendChildren( foo404 );
+				root1._appendChildren( foo404 );
 
 				schema.register( '$root' );
 				schema.register( '$text', {
@@ -2452,7 +2452,7 @@ describe( 'Schema', () => {
 			// Edge case because p>p should not exist in the first place.
 			// But it's good to know that it blocks also this.
 			const p = new Element( 'p' );
-			r1p1.appendChildren( p );
+			r1p1._appendChildren( p );
 
 			expect( schema.checkChild( p, '$text' ) ).to.be.false;
 		} );
@@ -2746,7 +2746,7 @@ describe( 'SchemaContext', () => {
 		it( 'filters out DocumentFragment when it is a first item of context - element', () => {
 			const p = new Element( 'paragraph' );
 			const docFrag = new DocumentFragment();
-			docFrag.appendChildren( p );
+			docFrag._appendChildren( p );
 
 			const ctx = new SchemaContext( p );
 
@@ -2757,7 +2757,7 @@ describe( 'SchemaContext', () => {
 		it( 'filters out DocumentFragment when it is a first item of context - position', () => {
 			const p = new Element( 'paragraph' );
 			const docFrag = new DocumentFragment();
-			docFrag.appendChildren( p );
+			docFrag._appendChildren( p );
 
 			const ctx = new SchemaContext( new Position( docFrag, [ 0, 0 ] ) );
 

+ 2 - 2
packages/ckeditor5-engine/tests/model/selection.js

@@ -25,7 +25,7 @@ describe( 'Selection', () => {
 		model = new Model();
 		doc = model.document;
 		root = doc.createRoot();
-		root.appendChildren( [
+		root._appendChildren( [
 			new Element( 'p' ),
 			new Element( 'p' ),
 			new Element( 'p', [], new Text( 'foobar' ) ),
@@ -1128,7 +1128,7 @@ describe( 'Selection', () => {
 		let rangeInFullP;
 
 		beforeEach( () => {
-			root.insertChildren( 0, [
+			root._insertChildren( 0, [
 				new Element( 'p', [], new Text( 'foobar' ) ),
 				new Element( 'p', [], [] )
 			] );

+ 2 - 2
packages/ckeditor5-engine/tests/model/text.js

@@ -52,10 +52,10 @@ describe( 'Text', () => {
 		} );
 	} );
 
-	describe( 'clone', () => {
+	describe( '_clone()', () => {
 		it( 'should return a new Text instance, with data and attributes equal to cloned text node', () => {
 			const text = new Text( 'foo', { bold: true } );
-			const copy = text.clone();
+			const copy = text._clone();
 
 			expect( copy.data ).to.equal( 'foo' );
 			expect( Array.from( copy.getAttributes() ) ).to.deep.equal( [ [ 'bold', true ] ] );

+ 2 - 2
packages/ckeditor5-engine/tests/model/textproxy.js

@@ -17,10 +17,10 @@ describe( 'TextProxy', () => {
 		doc = model.document;
 		root = doc.createRoot();
 		element = new Element( 'div' );
-		root.insertChildren( 0, element );
+		root._insertChildren( 0, element );
 
 		text = new Text( 'foobar', { foo: 'bar' } );
-		element.insertChildren( 0, [ new Text( 'abc' ), text ] );
+		element._insertChildren( 0, [ new Text( 'abc' ), text ] );
 		textProxy = new TextProxy( text, 2, 3 );
 
 		textNoParent = new Text( 'abcxyz' );

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

@@ -40,7 +40,7 @@ describe( 'TreeWalker', () => {
 		paragraph = new Element( 'p', [], [ ba, r, img2, x ] );
 		img1 = new Element( 'img1' );
 
-		root.insertChildren( 0, [ img1, paragraph ] );
+		root._insertChildren( 0, [ img1, paragraph ] );
 
 		rootBeginning = new Position( root, [ 0 ] );
 		rootEnding = new Position( root, [ 2 ] );

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

@@ -32,7 +32,7 @@ describe( 'getNodesAndText', () => {
 		div = new Element( 'div', [], new Text( 'foobar' ) );
 		p = new Element( 'p', [], new Text( 'abcxyz' ) );
 
-		root.insertChildren( 0, [ div, p ] );
+		root._insertChildren( 0, [ div, p ] );
 	} );
 
 	it( 'reads two elements with text', () => {
@@ -120,7 +120,7 @@ describe( 'createRangeOnElementOnly', () => {
 	it( 'should create a range that contains only the given element', () => {
 		const parent = new Element( 'parent' );
 		const element = new Element( 'elem' );
-		parent.appendChildren( element );
+		parent._appendChildren( element );
 
 		const range = createRangeOnElementOnly( element );
 

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

@@ -327,7 +327,7 @@ describe( 'DataController utils', () => {
 					// <pparent>x<paragraph>x<pchild>fo[o</pchild></paragraph></pparent>
 					// <pparent><paragraph><pchild>b]ar</pchild>y</paragraph>y</pparent>
 
-					root.appendChildren(
+					root._appendChildren(
 						new Element( 'pparent', null, [
 							'x',
 							new Element( 'paragraph', null, [
@@ -337,7 +337,7 @@ describe( 'DataController utils', () => {
 						] )
 					);
 
-					root.appendChildren(
+					root._appendChildren(
 						new Element( 'pparent', null, [
 							new Element( 'paragraph', null, [
 								new Element( 'pchild', null, 'bar' ),
@@ -380,7 +380,7 @@ describe( 'DataController utils', () => {
 					// We need to use the raw API due to https://github.com/ckeditor/ckeditor5-engine/issues/905.
 					// <pparent>x<paragraph>foo<pchild>ba[r</pchild></paragraph></pparent><paragraph>b]om</paragraph>
 
-					root.appendChildren(
+					root._appendChildren(
 						new Element( 'pparent', null, [
 							'x',
 							new Element( 'paragraph', null, [
@@ -390,7 +390,7 @@ describe( 'DataController utils', () => {
 						] )
 					);
 
-					root.appendChildren(
+					root._appendChildren(
 						new Element( 'paragraph', null, 'bom' )
 					);
 
@@ -427,11 +427,11 @@ describe( 'DataController utils', () => {
 					// We need to use the raw API due to https://github.com/ckeditor/ckeditor5-engine/issues/905.
 					// <paragraph>fo[o</paragraph><pparent><paragraph><pchild>bar]</pchild></paragraph></pparent>
 
-					root.appendChildren(
+					root._appendChildren(
 						new Element( 'paragraph', null, 'foo' )
 					);
 
-					root.appendChildren(
+					root._appendChildren(
 						new Element( 'pparent', null, [
 							new Element( 'paragraph', null, [
 								new Element( 'pchild', null, 'bar' )

+ 41 - 25
packages/ckeditor5-engine/tests/model/writer.js

@@ -811,6 +811,16 @@ describe( 'Writer', () => {
 		} );
 	} );
 
+	describe( 'setTextData()', () => {
+		it( 'should update the content for text node', () => {
+			const textNode = createText( 'foo' );
+
+			setTextData( 'bar', textNode );
+
+			expect( textNode.data ).to.equal( 'bar' );
+		} );
+	} );
+
 	describe( 'setAttribute() / removeAttribute()', () => {
 		let root, spy;
 
@@ -1278,7 +1288,7 @@ describe( 'Writer', () => {
 		it( 'should not add empty delta to the batch', () => {
 			const nodeA = new Element( 'p', { a: 1 } );
 			const nodeB = new Element( 'p', { b: 2 } );
-			root.insertChildren( 0, [ nodeA, nodeB ] );
+			root._insertChildren( 0, [ nodeA, nodeB ] );
 
 			setAttribute( 'a', 1, nodeA );
 
@@ -1403,7 +1413,7 @@ describe( 'Writer', () => {
 			p1 = new Element( 'p', { key1: 'value1' }, new Text( 'foo' ) );
 			p2 = new Element( 'p', { key2: 'value2' }, new Text( 'bar' ) );
 
-			root.insertChildren( 0, [ p1, p2 ] );
+			root._insertChildren( 0, [ p1, p2 ] );
 		} );
 
 		it( 'should merge foo and bar into foobar', () => {
@@ -1459,10 +1469,10 @@ describe( 'Writer', () => {
 			div = new Element( 'div', [], new Text( 'foobar' ) );
 			p = new Element( 'p', [], new Text( 'abcxyz' ) );
 
-			div.insertChildren( 0, [ new Element( 'p', [], new Text( 'gggg' ) ) ] );
-			div.insertChildren( 2, [ new Element( 'p', [], new Text( 'hhhh' ) ) ] );
+			div._insertChildren( 0, [ new Element( 'p', [], new Text( 'gggg' ) ) ] );
+			div._insertChildren( 2, [ new Element( 'p', [], new Text( 'hhhh' ) ) ] );
 
-			root.insertChildren( 0, [ div, p ] );
+			root._insertChildren( 0, [ div, p ] );
 
 			range = new Range( new Position( root, [ 0, 3 ] ), new Position( root, [ 0, 7 ] ) );
 		} );
@@ -1647,7 +1657,7 @@ describe( 'Writer', () => {
 			const root = doc.createRoot();
 			const p = new Element( 'p', null, new Text( 'abc' ) );
 
-			root.appendChildren( p );
+			root._appendChildren( p );
 
 			rename( p, 'h' );
 
@@ -1659,7 +1669,7 @@ describe( 'Writer', () => {
 			const docFrag = new DocumentFragment();
 			const p = new Element( 'p' );
 
-			docFrag.appendChildren( p );
+			docFrag._appendChildren( p );
 
 			rename( p, 'h' );
 
@@ -1691,7 +1701,7 @@ describe( 'Writer', () => {
 
 			p = new Element( 'p', { key: 'value' }, new Text( 'foobar' ) );
 
-			root.insertChildren( 0, p );
+			root._insertChildren( 0, p );
 		} );
 
 		it( 'should split foobar to foo and bar', () => {
@@ -1714,7 +1724,7 @@ describe( 'Writer', () => {
 
 		it( 'should split inside document fragment', () => {
 			const docFrag = new DocumentFragment();
-			docFrag.appendChildren( new Element( 'p', null, new Text( 'foobar' ) ) );
+			docFrag._appendChildren( new Element( 'p', null, new Text( 'foobar' ) ) );
 
 			split( new Position( docFrag, [ 0, 3 ] ) );
 
@@ -1772,7 +1782,7 @@ describe( 'Writer', () => {
 			const div = new Element( 'div', null, p );
 			const section = new Element( 'section', null, div );
 
-			root.insertChildren( 0, section );
+			root._insertChildren( 0, section );
 
 			split( new Position( p, [ 3 ] ), section );
 
@@ -1796,8 +1806,8 @@ describe( 'Writer', () => {
 			const div = new Element( 'div', null, p );
 			const section = new Element( 'section', null, div );
 
-			root.insertChildren( 0, div );
-			root.insertChildren( 1, section );
+			root._insertChildren( 0, div );
+			root._insertChildren( 1, section );
 
 			expect( () => {
 				split( new Position( p, [ 3 ] ), section );
@@ -1819,7 +1829,7 @@ describe( 'Writer', () => {
 		beforeEach( () => {
 			root = doc.createRoot();
 
-			root.insertChildren( 0, new Text( 'foobar' ) );
+			root._insertChildren( 0, new Text( 'foobar' ) );
 
 			range = new Range( new Position( root, [ 2 ] ), new Position( root, [ 4 ] ) );
 		} );
@@ -1856,7 +1866,7 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should throw if range to wrap is not flat', () => {
-			root.insertChildren( 1, [ new Element( 'p', [], new Text( 'xyz' ) ) ] );
+			root._insertChildren( 1, [ new Element( 'p', [], new Text( 'xyz' ) ) ] );
 			const notFlatRange = new Range( new Position( root, [ 3 ] ), new Position( root, [ 6, 2 ] ) );
 
 			expect( () => {
@@ -1874,7 +1884,7 @@ describe( 'Writer', () => {
 
 		it( 'should throw if element to wrap with has children #2', () => {
 			const p = new Element( 'p' );
-			root.insertChildren( 0, p );
+			root._insertChildren( 0, p );
 
 			expect( () => {
 				wrap( range, p );
@@ -1897,7 +1907,7 @@ describe( 'Writer', () => {
 			root = doc.createRoot();
 
 			p = new Element( 'p', [], new Text( 'xyz' ) );
-			root.insertChildren( 0, [ new Text( 'a' ), p, new Text( 'b' ) ] );
+			root._insertChildren( 0, [ new Text( 'a' ), p, new Text( 'b' ) ] );
 		} );
 
 		it( 'should unwrap given element', () => {
@@ -1938,7 +1948,7 @@ describe( 'Writer', () => {
 
 		beforeEach( () => {
 			root = doc.createRoot();
-			root.appendChildren( new Text( 'foo' ) );
+			root._appendChildren( new Text( 'foo' ) );
 			range = Range.createIn( root );
 		} );
 
@@ -2104,7 +2114,7 @@ describe( 'Writer', () => {
 
 		beforeEach( () => {
 			root = doc.createRoot();
-			root.appendChildren( new Text( 'foo' ) );
+			root._appendChildren( new Text( 'foo' ) );
 			range = Range.createIn( root );
 		} );
 
@@ -2162,7 +2172,7 @@ describe( 'Writer', () => {
 			model.schema.extend( 'p', { allowIn: '$root' } );
 
 			root = doc.createRoot();
-			root.appendChildren( [
+			root._appendChildren( [
 				new Element( 'p' ),
 				new Element( 'p' ),
 				new Element( 'p', [], new Text( 'foo' ) )
@@ -2199,7 +2209,7 @@ describe( 'Writer', () => {
 			model.schema.extend( 'p', { allowIn: '$root' } );
 
 			root = doc.createRoot();
-			root.appendChildren( [
+			root._appendChildren( [
 				new Element( 'p' ),
 				new Element( 'p' ),
 				new Element( 'p', [], new Text( 'foo' ) )
@@ -2235,7 +2245,7 @@ describe( 'Writer', () => {
 			model.schema.extend( 'p', { allowIn: '$root' } );
 
 			root = doc.createRoot();
-			root.appendChildren( [
+			root._appendChildren( [
 				new Element( 'p', [], [] ),
 				new Element( 'p' ),
 				new Element( 'p', [], new Text( 'foo' ) )
@@ -2280,7 +2290,7 @@ describe( 'Writer', () => {
 			model.schema.extend( 'p', { allowIn: '$root' } );
 
 			root = doc.createRoot();
-			root.appendChildren( [
+			root._appendChildren( [
 				new Element( 'p', [], [] ),
 				new Element( 'p' ),
 				new Element( 'p', [], new Text( 'foo' ) )
@@ -2337,7 +2347,7 @@ describe( 'Writer', () => {
 
 		it( 'should not get attributes from the node before the caret when gravity is overridden', () => {
 			const root = doc.createRoot();
-			root.appendChildren( [
+			root._appendChildren( [
 				new Text( 'foo', { foo: true } ),
 				new Text( 'bar', { foo: true, bar: true } ),
 				new Text( 'biz', { foo: true } )
@@ -2361,7 +2371,7 @@ describe( 'Writer', () => {
 
 		it( 'should allow to restorer gravity in a custom way', () => {
 			const root = doc.createRoot();
-			root.appendChildren( [ new Text( 'foobar', { foo: true } ) ] );
+			root._appendChildren( [ new Text( 'foobar', { foo: true } ) ] );
 
 			setSelection( new Position( root, [ 1 ] ) );
 
@@ -2390,7 +2400,7 @@ describe( 'Writer', () => {
 
 		it( 'should restore overridden gravity to default', () => {
 			const root = doc.createRoot();
-			root.appendChildren( [
+			root._appendChildren( [
 				new Text( 'foo', { foo: true } ),
 				new Text( 'bar', { foo: true, bar: true } ),
 				new Text( 'biz', { foo: true } )
@@ -2462,6 +2472,12 @@ describe( 'Writer', () => {
 		} );
 	}
 
+	function setTextData( value, textNode ) {
+		model.enqueueChange( batch, writer => {
+			writer.setTextData( value, textNode );
+		} );
+	}
+
 	function setAttribute( key, value, itemOrRange ) {
 		model.enqueueChange( batch, writer => {
 			writer.setAttribute( key, value, itemOrRange );

+ 75 - 0
packages/ckeditor5-engine/tests/tickets/1267.js

@@ -0,0 +1,75 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* globals document */
+
+import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
+import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
+import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
+import Position from '../../src/model/position';
+import Range from '../../src/model/range';
+import { setData as setModelData, getData as getModelData } from '../../src/dev-utils/model';
+
+describe( 'Bug ckeditor5-engine#1267', () => {
+	let element, editor, model;
+
+	beforeEach( () => {
+		element = document.createElement( 'div' );
+		document.body.appendChild( element );
+
+		return ClassicTestEditor
+			.create( element, { plugins: [ Paragraph, Bold ] } )
+			.then( newEditor => {
+				editor = newEditor;
+				model = editor.model;
+			} );
+	} );
+
+	afterEach( () => {
+		element.remove();
+
+		return editor.destroy();
+	} );
+
+	it( 'selection should not retain attributes after external change removal', () => {
+		setModelData( model,
+			'<paragraph>foo bar baz</paragraph>' +
+			'<paragraph>foo <$text bold="true">bar{}</$text> baz</paragraph>'
+		);
+
+		// Remove second paragraph where selection is placed.
+		model.enqueueChange( 'transparent', writer => {
+			writer.remove( Range.createFromPositionAndShift( new Position( model.document.getRoot(), [ 1 ] ), 1 ) );
+		} );
+
+		expect( getModelData( model ) ).to.equal( '<paragraph>foo bar baz[]</paragraph>' );
+	} );
+
+	it( 'selection should retain attributes set manually', () => {
+		setModelData( model,
+			'<paragraph>foo bar baz</paragraph>' +
+			'<paragraph>foo bar baz</paragraph>' +
+			'<paragraph>[]</paragraph>'
+		);
+
+		// Execute bold command when selection is inside empty paragraph.
+		editor.execute( 'bold' );
+		expect( getModelData( model ) ).to.equal(
+			'<paragraph>foo bar baz</paragraph>' +
+			'<paragraph>foo bar baz</paragraph>' +
+			'<paragraph selection:bold="true"><$text bold="true">[]</$text></paragraph>'
+		);
+
+		// Remove second paragraph.
+		model.enqueueChange( 'transparent', writer => {
+			writer.remove( Range.createFromPositionAndShift( new Position( model.document.getRoot(), [ 1 ] ), 1 ) );
+		} );
+
+		// Selection attributes set by command should stay as they were.
+		expect( getModelData( model ) ).to.equal(
+			'<paragraph>foo bar baz</paragraph>' +
+			'<paragraph selection:bold="true"><$text bold="true">[]</$text></paragraph>' );
+	} );
+} );

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

@@ -20,7 +20,7 @@ describe( 'Bug ckeditor5-engine@1323', () => {
 			model = new Model();
 			editing = new EditingController( model );
 			root = model.document.createRoot();
-			root.appendChildren( new ModelText( 'foo' ) );
+			root._appendChildren( new ModelText( 'foo' ) );
 			range = ModelRange.createFromParentsAndOffsets( root, 0, root, 0 );
 		} );
 

+ 2 - 2
packages/ckeditor5-engine/tests/view/attributeelement.js

@@ -48,12 +48,12 @@ describe( 'AttributeElement', () => {
 		} );
 	} );
 
-	describe( 'clone', () => {
+	describe( '_clone()', () => {
 		it( 'should clone element with priority', () => {
 			const el = new AttributeElement( 'b' );
 			el._priority = 7;
 
-			const clone = el.clone();
+			const clone = el._clone();
 
 			expect( clone ).to.not.equal( el );
 			expect( clone.name ).to.equal( el.name );

+ 32 - 32
packages/ckeditor5-engine/tests/view/documentfragment.js

@@ -107,8 +107,8 @@ describe( 'DocumentFragment', () => {
 
 		describe( 'insertion', () => {
 			it( 'should insert children', () => {
-				const count1 = fragment.insertChildren( 0, [ el1, el3 ] );
-				const count2 = fragment.insertChildren( 1, el2 );
+				const count1 = fragment._insertChildren( 0, [ el1, el3 ] );
+				const count2 = fragment._insertChildren( 1, el2 );
 
 				expect( fragment.childCount ).to.equal( 3 );
 				expect( fragment.getChild( 0 ) ).to.have.property( 'name' ).that.equals( 'el1' );
@@ -119,22 +119,22 @@ describe( 'DocumentFragment', () => {
 			} );
 
 			it( 'should accept strings', () => {
-				fragment.insertChildren( 0, 'abc' );
+				fragment._insertChildren( 0, 'abc' );
 
 				expect( fragment.childCount ).to.equal( 1 );
 				expect( fragment.getChild( 0 ) ).to.have.property( 'data' ).that.equals( 'abc' );
 
-				fragment.removeChildren( 0, 1 );
-				fragment.insertChildren( 0, [ new Element( 'p' ), 'abc' ] );
+				fragment._removeChildren( 0, 1 );
+				fragment._insertChildren( 0, [ new Element( 'p' ), 'abc' ] );
 
 				expect( fragment.childCount ).to.equal( 2 );
 				expect( fragment.getChild( 1 ) ).to.have.property( 'data' ).that.equals( 'abc' );
 			} );
 
 			it( 'should append children', () => {
-				const count1 = fragment.insertChildren( 0, el1 );
-				const count2 = fragment.appendChildren( el2 );
-				const count3 = fragment.appendChildren( el3 );
+				const count1 = fragment._insertChildren( 0, el1 );
+				const count2 = fragment._appendChildren( el2 );
+				const count3 = fragment._appendChildren( el3 );
 
 				expect( fragment.childCount ).to.equal( 3 );
 				expect( fragment.getChild( 0 ) ).to.have.property( 'name' ).that.equals( 'el1' );
@@ -151,7 +151,7 @@ describe( 'DocumentFragment', () => {
 					done();
 				} );
 
-				fragment.insertChildren( 0, el1 );
+				fragment._insertChildren( 0, el1 );
 			} );
 
 			it( 'should fire change event when appending', done => {
@@ -160,7 +160,7 @@ describe( 'DocumentFragment', () => {
 					done();
 				} );
 
-				fragment.appendChildren( el1 );
+				fragment._appendChildren( el1 );
 			} );
 
 			it( 'should accept and correctly handle text proxies', () => {
@@ -168,7 +168,7 @@ describe( 'DocumentFragment', () => {
 				const text = new Text( 'abcxyz' );
 				const textProxy = new TextProxy( text, 2, 3 );
 
-				frag.insertChildren( 0, textProxy );
+				frag._insertChildren( 0, textProxy );
 
 				expect( frag.childCount ).to.equal( 1 );
 				expect( frag.getChild( 0 ) ).to.be.instanceof( Text );
@@ -178,9 +178,9 @@ describe( 'DocumentFragment', () => {
 
 		describe( 'getChildIndex', () => {
 			it( 'should return child index', () => {
-				fragment.appendChildren( el1 );
-				fragment.appendChildren( el2 );
-				fragment.appendChildren( el3 );
+				fragment._appendChildren( el1 );
+				fragment._appendChildren( el2 );
+				fragment._appendChildren( el3 );
 
 				expect( fragment.childCount ).to.equal( 3 );
 				expect( fragment.getChildIndex( el1 ) ).to.equal( 0 );
@@ -191,9 +191,9 @@ describe( 'DocumentFragment', () => {
 
 		describe( 'getChildren', () => {
 			it( 'should renturn children iterator', () => {
-				fragment.appendChildren( el1 );
-				fragment.appendChildren( el2 );
-				fragment.appendChildren( el3 );
+				fragment._appendChildren( el1 );
+				fragment._appendChildren( el2 );
+				fragment._appendChildren( el3 );
 
 				const expected = [ el1, el2, el3 ];
 				let i = 0;
@@ -207,14 +207,14 @@ describe( 'DocumentFragment', () => {
 			} );
 		} );
 
-		describe( 'removeChildren', () => {
+		describe( '_removeChildren', () => {
 			it( 'should remove children', () => {
-				fragment.appendChildren( el1 );
-				fragment.appendChildren( el2 );
-				fragment.appendChildren( el3 );
-				fragment.appendChildren( el4 );
+				fragment._appendChildren( el1 );
+				fragment._appendChildren( el2 );
+				fragment._appendChildren( el3 );
+				fragment._appendChildren( el4 );
 
-				fragment.removeChildren( 1, 2 );
+				fragment._removeChildren( 1, 2 );
 
 				expect( fragment.childCount ).to.equal( 2 );
 				expect( fragment.getChild( 0 ) ).to.have.property( 'name' ).that.equals( 'el1' );
@@ -227,11 +227,11 @@ describe( 'DocumentFragment', () => {
 			} );
 
 			it( 'should remove one child when second parameter is not specified', () => {
-				fragment.appendChildren( el1 );
-				fragment.appendChildren( el2 );
-				fragment.appendChildren( el3 );
+				fragment._appendChildren( el1 );
+				fragment._appendChildren( el2 );
+				fragment._appendChildren( el3 );
 
-				const removed = fragment.removeChildren( 1 );
+				const removed = fragment._removeChildren( 1 );
 
 				expect( fragment.childCount ).to.equal( 2 );
 				expect( fragment.getChild( 0 ) ).to.have.property( 'name' ).that.equals( 'el1' );
@@ -242,14 +242,14 @@ describe( 'DocumentFragment', () => {
 			} );
 
 			it( 'should fire change event', done => {
-				fragment.appendChildren( el1 );
+				fragment._appendChildren( el1 );
 
 				fragment.once( 'change:children', ( event, node ) => {
 					expect( node ).to.equal( fragment );
 					done();
 				} );
 
-				fragment.removeChildren( 0 );
+				fragment._removeChildren( 0 );
 			} );
 		} );
 	} );
@@ -291,14 +291,14 @@ describe( 'DocumentFragment', () => {
 			expect( node3.previousSibling ).to.equal( node2 );
 		} );
 
-		it( 'remove() should remove node from fragment', () => {
+		it( '_remove() should remove node from fragment', () => {
 			const node1 = new Node();
 			const node2 = new Node();
 			const node3 = new Node();
 			const fragment = new DocumentFragment( [ node1, node2, node3 ] );
 
-			node1.remove();
-			node3.remove();
+			node1._remove();
+			node3._remove();
 
 			expect( fragment.childCount ).to.equal( 1 );
 			expect( node1.parent ).to.be.null;

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

@@ -31,8 +31,8 @@ describe( 'DomConverter', () => {
 			const viewText = new ViewText( 'foo' );
 			const viewP = new ViewElement( 'p', { class: 'foo' } );
 
-			viewP.appendChildren( viewImg );
-			viewP.appendChildren( viewText );
+			viewP._appendChildren( viewImg );
+			viewP._appendChildren( viewText );
 
 			const domImg = document.createElement( 'img' );
 
@@ -59,8 +59,8 @@ describe( 'DomConverter', () => {
 			const viewText = new ViewText( 'foo' );
 			const viewP = new ViewElement( 'p', { class: 'foo' } );
 
-			viewP.appendChildren( viewImg );
-			viewP.appendChildren( viewText );
+			viewP._appendChildren( viewImg );
+			viewP._appendChildren( viewText );
 
 			const domP = converter.viewToDom( viewP, document, { bind: true } );
 
@@ -96,8 +96,8 @@ describe( 'DomConverter', () => {
 			const viewText = new ViewText( 'foo' );
 			const viewP = new ViewElement( 'p', { class: 'foo' } );
 
-			viewP.appendChildren( viewImg );
-			viewP.appendChildren( viewText );
+			viewP._appendChildren( viewImg );
+			viewP._appendChildren( viewText );
 
 			const domImg = document.createElement( 'img' );
 
@@ -120,8 +120,8 @@ describe( 'DomConverter', () => {
 			const viewText = new ViewText( 'foo' );
 			const viewFragment = new ViewDocumentFragment();
 
-			viewFragment.appendChildren( viewImg );
-			viewFragment.appendChildren( viewText );
+			viewFragment._appendChildren( viewImg );
+			viewFragment._appendChildren( viewText );
 
 			const domFragment = converter.viewToDom( viewFragment, document, { bind: true } );
 
@@ -139,8 +139,8 @@ describe( 'DomConverter', () => {
 			const viewText = new ViewText( 'foo' );
 			const viewFragment = new ViewDocumentFragment();
 
-			viewFragment.appendChildren( viewImg );
-			viewFragment.appendChildren( viewText );
+			viewFragment._appendChildren( viewImg );
+			viewFragment._appendChildren( viewText );
 
 			const domImg = document.createElement( 'img' );
 
@@ -244,7 +244,7 @@ describe( 'DomConverter', () => {
 					const viewElement = new ViewContainerElement( 'p' );
 
 					for ( const text of inputTexts ) {
-						viewElement.appendChildren( new ViewText( text.replace( /_/g, '\u00A0' ) ) );
+						viewElement._appendChildren( new ViewText( text.replace( /_/g, '\u00A0' ) ) );
 					}
 
 					const domElement = converter.viewToDom( viewElement, document );

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

@@ -38,7 +38,7 @@ describe( 'EditableElement', () => {
 
 		it( 'should be cloned properly', () => {
 			element._document = docMock;
-			const newElement = element.clone();
+			const newElement = element._clone();
 
 			expect( newElement.document ).to.equal( docMock );
 		} );

+ 37 - 37
packages/ckeditor5-engine/tests/view/element.js

@@ -123,10 +123,10 @@ describe( 'Element', () => {
 		} );
 	} );
 
-	describe( 'clone', () => {
+	describe( '_clone()', () => {
 		it( 'should clone element', () => {
 			const el = new Element( 'p', { attr1: 'foo', attr2: 'bar' } );
-			const clone = el.clone();
+			const clone = el._clone();
 
 			expect( clone ).to.not.equal( el );
 			expect( clone.name ).to.equal( el.name );
@@ -140,7 +140,7 @@ describe( 'Element', () => {
 				new Element( 'span', { attr: 'qux' } )
 			] );
 			const count = el.childCount;
-			const clone = el.clone( true );
+			const clone = el._clone( true );
 
 			expect( clone ).to.not.equal( el );
 			expect( clone.name ).to.equal( el.name );
@@ -163,7 +163,7 @@ describe( 'Element', () => {
 				new Element( 'b', { attr: 'baz' } ),
 				new Element( 'span', { attr: 'qux' } )
 			] );
-			const clone = el.clone( false );
+			const clone = el._clone( false );
 
 			expect( clone ).to.not.equal( el );
 			expect( clone.name ).to.equal( el.name );
@@ -175,7 +175,7 @@ describe( 'Element', () => {
 		it( 'should clone class attribute', () => {
 			const el = new Element( 'p', { foo: 'bar' } );
 			el._addClass( [ 'baz', 'qux' ] );
-			const clone = el.clone( false );
+			const clone = el._clone( false );
 
 			expect( clone ).to.not.equal( el );
 			expect( clone.name ).to.equal( el.name );
@@ -185,7 +185,7 @@ describe( 'Element', () => {
 
 		it( 'should clone style attribute', () => {
 			const el = new Element( 'p', { style: 'color: red; font-size: 12px;' } );
-			const clone = el.clone( false );
+			const clone = el._clone( false );
 
 			expect( clone ).to.not.equal( el );
 			expect( clone.name ).to.equal( el.name );
@@ -201,7 +201,7 @@ describe( 'Element', () => {
 			el._setCustomProperty( 'foo', 'bar' );
 			el._setCustomProperty( symbol, 'baz' );
 
-			const cloned = el.clone();
+			const cloned = el._clone();
 
 			expect( cloned.getCustomProperty( 'foo' ) ).to.equal( 'bar' );
 			expect( cloned.getCustomProperty( symbol ) ).to.equal( 'baz' );
@@ -214,7 +214,7 @@ describe( 'Element', () => {
 			expect( el.getFillerOffset ).to.be.undefined;
 			el.getFillerOffset = fm;
 
-			const cloned = el.clone();
+			const cloned = el._clone();
 
 			expect( cloned.getFillerOffset ).to.equal( fm );
 		} );
@@ -237,16 +237,16 @@ describe( 'Element', () => {
 		} );
 
 		it( 'sould return false when name is not the same', () => {
-			const other = el.clone();
+			const other = el._clone();
 			other.name = 'div';
 
 			expect( el.isSimilar( other ) ).to.be.false;
 		} );
 
 		it( 'should return false when attributes are not the same', () => {
-			const other1 = el.clone();
-			const other2 = el.clone();
-			const other3 = el.clone();
+			const other1 = el._clone();
+			const other2 = el._clone();
+			const other3 = el._clone();
 			other1._setAttribute( 'baz', 'qux' );
 			other2._setAttribute( 'foo', 'not-bar' );
 			other3._removeAttribute( 'foo' );
@@ -305,8 +305,8 @@ describe( 'Element', () => {
 
 		describe( 'insertion', () => {
 			it( 'should insert children', () => {
-				const count1 = parent.insertChildren( 0, [ el1, el3 ] );
-				const count2 = parent.insertChildren( 1, el2 );
+				const count1 = parent._insertChildren( 0, [ el1, el3 ] );
+				const count2 = parent._insertChildren( 1, el2 );
 
 				expect( parent.childCount ).to.equal( 3 );
 				expect( parent.getChild( 0 ) ).to.have.property( 'name' ).that.equals( 'el1' );
@@ -317,22 +317,22 @@ describe( 'Element', () => {
 			} );
 
 			it( 'should accept strings', () => {
-				parent.insertChildren( 0, 'abc' );
+				parent._insertChildren( 0, 'abc' );
 
 				expect( parent.childCount ).to.equal( 1 );
 				expect( parent.getChild( 0 ) ).to.have.property( 'data' ).that.equals( 'abc' );
 
-				parent.removeChildren( 0, 1 );
-				parent.insertChildren( 0, [ new Element( 'p' ), 'abc' ] );
+				parent._removeChildren( 0, 1 );
+				parent._insertChildren( 0, [ new Element( 'p' ), 'abc' ] );
 
 				expect( parent.childCount ).to.equal( 2 );
 				expect( parent.getChild( 1 ) ).to.have.property( 'data' ).that.equals( 'abc' );
 			} );
 
 			it( 'should append children', () => {
-				const count1 = parent.insertChildren( 0, el1 );
-				const count2 = parent.appendChildren( el2 );
-				const count3 = parent.appendChildren( el3 );
+				const count1 = parent._insertChildren( 0, el1 );
+				const count2 = parent._appendChildren( el2 );
+				const count3 = parent._appendChildren( el3 );
 
 				expect( parent.childCount ).to.equal( 3 );
 				expect( parent.getChild( 0 ) ).to.have.property( 'name' ).that.equals( 'el1' );
@@ -348,7 +348,7 @@ describe( 'Element', () => {
 				const text = new Text( 'abcxyz' );
 				const textProxy = new TextProxy( text, 2, 3 );
 
-				element.insertChildren( 0, textProxy );
+				element._insertChildren( 0, textProxy );
 
 				expect( element.childCount ).to.equal( 1 );
 				expect( element.getChild( 0 ) ).to.be.instanceof( Text );
@@ -358,9 +358,9 @@ describe( 'Element', () => {
 
 		describe( 'getChildIndex', () => {
 			it( 'should return child index', () => {
-				parent.appendChildren( el1 );
-				parent.appendChildren( el2 );
-				parent.appendChildren( el3 );
+				parent._appendChildren( el1 );
+				parent._appendChildren( el2 );
+				parent._appendChildren( el3 );
 
 				expect( parent.childCount ).to.equal( 3 );
 				expect( parent.getChildIndex( el1 ) ).to.equal( 0 );
@@ -371,9 +371,9 @@ describe( 'Element', () => {
 
 		describe( 'getChildren', () => {
 			it( 'should renturn children iterator', () => {
-				parent.appendChildren( el1 );
-				parent.appendChildren( el2 );
-				parent.appendChildren( el3 );
+				parent._appendChildren( el1 );
+				parent._appendChildren( el2 );
+				parent._appendChildren( el3 );
 
 				const expected = [ el1, el2, el3 ];
 				let i = 0;
@@ -387,14 +387,14 @@ describe( 'Element', () => {
 			} );
 		} );
 
-		describe( 'removeChildren', () => {
+		describe( '_removeChildren', () => {
 			it( 'should remove children', () => {
-				parent.appendChildren( el1 );
-				parent.appendChildren( el2 );
-				parent.appendChildren( el3 );
-				parent.appendChildren( el4 );
+				parent._appendChildren( el1 );
+				parent._appendChildren( el2 );
+				parent._appendChildren( el3 );
+				parent._appendChildren( el4 );
 
-				parent.removeChildren( 1, 2 );
+				parent._removeChildren( 1, 2 );
 
 				expect( parent.childCount ).to.equal( 2 );
 				expect( parent.getChild( 0 ) ).to.have.property( 'name' ).that.equals( 'el1' );
@@ -407,11 +407,11 @@ describe( 'Element', () => {
 			} );
 
 			it( 'should remove one child when second parameter is not specified', () => {
-				parent.appendChildren( el1 );
-				parent.appendChildren( el2 );
-				parent.appendChildren( el3 );
+				parent._appendChildren( el1 );
+				parent._appendChildren( el2 );
+				parent._appendChildren( el3 );
 
-				const removed = parent.removeChildren( 1 );
+				const removed = parent._removeChildren( 1 );
 
 				expect( parent.childCount ).to.equal( 2 );
 				expect( parent.getChild( 0 ) ).to.have.property( 'name' ).that.equals( 'el1' );

+ 6 - 6
packages/ckeditor5-engine/tests/view/emptyelement.js

@@ -54,25 +54,25 @@ describe( 'EmptyElement', () => {
 		} ).to.throw( CKEditorError, 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.' );
 	} );
 
-	describe( 'appendChildren', () => {
+	describe( '_appendChildren', () => {
 		it( 'should throw when try to append new child element', () => {
 			expect( () => {
-				emptyElement.appendChildren( element );
+				emptyElement._appendChildren( element );
 			} ).to.throw( CKEditorError, 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.' );
 		} );
 	} );
 
-	describe( 'insertChildren', () => {
+	describe( '_insertChildren', () => {
 		it( 'should throw when try to insert new child element', () => {
 			expect( () => {
-				emptyElement.insertChildren( 0, element );
+				emptyElement._insertChildren( 0, element );
 			} ).to.throw( CKEditorError, 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.' );
 		} );
 	} );
 
-	describe( 'clone', () => {
+	describe( '_clone()', () => {
 		it( 'should be cloned properly', () => {
-			const newEmptyElement = emptyElement.clone();
+			const newEmptyElement = emptyElement._clone();
 
 			expect( newEmptyElement.name ).to.equal( 'img' );
 			expect( newEmptyElement.getAttribute( 'alt' ) ).to.equal( 'alternative text' );

+ 1 - 1
packages/ckeditor5-engine/tests/view/manual/uielement.js

@@ -47,7 +47,7 @@ class UIElementTestPlugin extends Plugin {
 		// Add some UIElement to each paragraph.
 		editing.downcastDispatcher.on( 'insert:paragraph', ( evt, data, conversionApi ) => {
 			const viewP = conversionApi.mapper.toViewElement( data.item );
-			viewP.appendChildren( createEndingUIElement( conversionApi.writer ) );
+			viewP._appendChildren( createEndingUIElement( conversionApi.writer ) );
 		}, { priority: 'lowest' } );
 	}
 }

+ 20 - 20
packages/ckeditor5-engine/tests/view/node.js

@@ -100,7 +100,7 @@ describe( 'Node', () => {
 		it( 'should return ancestors including DocumentFragment', () => {
 			const fragment = new DocumentFragment( root );
 			const result = img.getAncestors();
-			root.remove();
+			root._remove();
 
 			expect( result.length ).to.equal( 3 );
 			expect( result[ 0 ] ).to.equal( fragment );
@@ -258,24 +258,24 @@ describe( 'Node', () => {
 		} );
 	} );
 
-	describe( 'remove()', () => {
+	describe( '_remove()', () => {
 		it( 'should remove node from its parent', () => {
 			const char = new Text( 'a' );
 			const parent = new Element( 'p', null, [ char ] );
-			char.remove();
+			char._remove();
 
 			expect( parent.getChildIndex( char ) ).to.equal( -1 );
 		} );
 
-		it( 'uses parent.removeChildren method', () => {
+		it( 'uses parent._removeChildren method', () => {
 			const char = new Text( 'a' );
 			const parent = new Element( 'p', null, [ char ] );
-			const removeChildrenSpy = sinon.spy( parent, 'removeChildren' );
+			const _removeChildrenSpy = sinon.spy( parent, '_removeChildren' );
 			const index = char.index;
-			char.remove();
-			removeChildrenSpy.restore();
-			sinon.assert.calledOnce( removeChildrenSpy );
-			sinon.assert.calledWithExactly( removeChildrenSpy, index );
+			char._remove();
+			_removeChildrenSpy.restore();
+			sinon.assert.calledOnce( _removeChildrenSpy );
+			sinon.assert.calledWithExactly( _removeChildrenSpy, index );
 		} );
 	} );
 
@@ -283,13 +283,13 @@ describe( 'Node', () => {
 		it( 'should prevent circular reference when stringifying a node', () => {
 			const char = new Text( 'a' );
 			const parent = new Element( 'p', null );
-			parent.appendChildren( char );
+			parent._appendChildren( char );
 
 			const json = JSON.stringify( char );
 			const parsed = JSON.parse( json );
 
 			expect( parsed ).to.deep.equal( {
-				_data: 'a'
+				_textData: 'a'
 			} );
 		} );
 	} );
@@ -306,7 +306,7 @@ describe( 'Node', () => {
 			img = new Element( 'img', { 'src': 'img.png' } );
 
 			root = new Element( 'p', { renderer: { markToSync: rootChangeSpy } } );
-			root.appendChildren( [ text, img ] );
+			root._appendChildren( [ text, img ] );
 
 			root.on( 'change:children', ( evt, node ) => rootChangeSpy( 'children', node ) );
 			root.on( 'change:attributes', ( evt, node ) => rootChangeSpy( 'attributes', node ) );
@@ -353,36 +353,36 @@ describe( 'Node', () => {
 			} );
 		} );
 
-		describe( 'insertChildren()', () => {
+		describe( '_insertChildren()', () => {
 			it( 'should fire change event', () => {
-				root.insertChildren( 1, new Element( 'img' ) );
+				root._insertChildren( 1, new Element( 'img' ) );
 
 				sinon.assert.calledOnce( rootChangeSpy );
 				sinon.assert.calledWith( rootChangeSpy, 'children', root );
 			} );
 		} );
 
-		describe( 'appendChildren()', () => {
+		describe( '_appendChildren()', () => {
 			it( 'should fire change event', () => {
-				root.appendChildren( new Element( 'img' ) );
+				root._appendChildren( new Element( 'img' ) );
 
 				sinon.assert.calledOnce( rootChangeSpy );
 				sinon.assert.calledWith( rootChangeSpy, 'children', root );
 			} );
 		} );
 
-		describe( 'removeChildren()', () => {
+		describe( '_removeChildren()', () => {
 			it( 'should fire change event', () => {
-				root.removeChildren( 1, 1 );
+				root._removeChildren( 1, 1 );
 
 				sinon.assert.calledOnce( rootChangeSpy );
 				sinon.assert.calledWith( rootChangeSpy, 'children', root );
 			} );
 		} );
 
-		describe( 'removeChildren()', () => {
+		describe( 'setText', () => {
 			it( 'should fire change event', () => {
-				text.data = 'bar';
+				text._data = 'bar';
 
 				sinon.assert.calledOnce( rootChangeSpy );
 				sinon.assert.calledWith( rootChangeSpy, 'text', text );

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

@@ -182,7 +182,7 @@ describe( 'DomEventObserver', () => {
 			const viewRoot = createViewRoot( viewDocument );
 			view.attachDomRoot( domRoot );
 			uiElement = createUIElement( 'p' );
-			viewRoot.appendChildren( uiElement );
+			viewRoot._appendChildren( uiElement );
 			view.render();
 
 			domEvent = new MouseEvent( 'click', { bubbles: true } );

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

@@ -37,7 +37,7 @@ describe( 'MutationObserver', () => {
 
 		viewRoot = viewDocument.getRoot();
 
-		viewRoot.appendChildren( parse( '<container:p>foo</container:p><container:p>bar</container:p>' ) );
+		viewRoot._appendChildren( parse( '<container:p>foo</container:p><container:p>bar</container:p>' ) );
 
 		view.render();
 	} );
@@ -96,8 +96,8 @@ describe( 'MutationObserver', () => {
 	} );
 
 	it( 'should handle unbold', () => {
-		viewRoot.removeChildren( 0, viewRoot.childCount );
-		viewRoot.appendChildren( parse( '<container:p><attribute:b>foo</attribute:b></container:p>' ) );
+		viewRoot._removeChildren( 0, viewRoot.childCount );
+		viewRoot._appendChildren( parse( '<container:p><attribute:b>foo</attribute:b></container:p>' ) );
 		view.render();
 
 		const domP = domEditor.childNodes[ 0 ];
@@ -203,7 +203,7 @@ describe( 'MutationObserver', () => {
 		createViewRoot( viewDocument, 'div', 'additional' );
 		view.attachDomRoot( domAdditionalEditor, 'additional' );
 
-		viewDocument.getRoot( 'additional' ).appendChildren(
+		viewDocument.getRoot( 'additional' )._appendChildren(
 			parse( '<container:p>foo</container:p><container:p>bar</container:p>' ) );
 
 		// Render AdditionalEditor (first editor has been rendered in the beforeEach function)
@@ -228,7 +228,7 @@ describe( 'MutationObserver', () => {
 		const { view: viewContainer, selection } = parse( '<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
 
 		view.change( writer => {
-			viewRoot.appendChildren( viewContainer );
+			viewRoot._appendChildren( viewContainer );
 			writer.setSelection( selection );
 		} );
 
@@ -246,7 +246,7 @@ describe( 'MutationObserver', () => {
 		const { view: viewContainer, selection } = parse( '<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
 
 		view.change( writer => {
-			viewRoot.appendChildren( viewContainer );
+			viewRoot._appendChildren( viewContainer );
 			writer.setSelection( selection );
 		} );
 
@@ -254,7 +254,7 @@ describe( 'MutationObserver', () => {
 		inlineFiller.data += 'x';
 
 		view.change( () => {
-			viewContainer.getChild( 1 ).appendChildren( parse( 'x' ) );
+			viewContainer.getChild( 1 )._appendChildren( parse( 'x' ) );
 			mutationObserver.flush();
 		} );
 
@@ -279,7 +279,7 @@ describe( 'MutationObserver', () => {
 		);
 
 		view.change( writer => {
-			viewRoot.appendChildren( viewContainer );
+			viewRoot._appendChildren( viewContainer );
 			writer.setSelection( selection );
 		} );
 
@@ -311,7 +311,7 @@ describe( 'MutationObserver', () => {
 		);
 
 		view.change( writer => {
-			viewRoot.appendChildren( viewContainer );
+			viewRoot._appendChildren( viewContainer );
 			writer.setSelection( selection );
 		} );
 
@@ -354,7 +354,7 @@ describe( 'MutationObserver', () => {
 		);
 
 		view.change( writer => {
-			viewRoot.appendChildren( viewContainer );
+			viewRoot._appendChildren( viewContainer );
 			writer.setSelection( selection );
 		} );
 
@@ -376,7 +376,7 @@ describe( 'MutationObserver', () => {
 	} );
 
 	it( 'should have no block filler in mutation', () => {
-		viewRoot.appendChildren( parse( '<container:p></container:p>' ) );
+		viewRoot._appendChildren( parse( '<container:p></container:p>' ) );
 
 		view.render();
 
@@ -395,7 +395,7 @@ describe( 'MutationObserver', () => {
 	} );
 
 	it( 'should ignore mutation with bogus br inserted on the end of the empty paragraph', () => {
-		viewRoot.appendChildren( parse( '<container:p></container:p>' ) );
+		viewRoot._appendChildren( parse( '<container:p></container:p>' ) );
 
 		view.render();
 
@@ -408,7 +408,7 @@ describe( 'MutationObserver', () => {
 	} );
 
 	it( 'should ignore mutation with bogus br inserted on the end of the paragraph with text', () => {
-		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
+		viewRoot._appendChildren( parse( '<container:p>foo</container:p>' ) );
 
 		view.render();
 
@@ -421,7 +421,7 @@ describe( 'MutationObserver', () => {
 	} );
 
 	it( 'should ignore mutation with bogus br inserted on the end of the paragraph while processing text mutations', () => {
-		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
+		viewRoot._appendChildren( parse( '<container:p>foo</container:p>' ) );
 
 		view.render();
 
@@ -438,7 +438,7 @@ describe( 'MutationObserver', () => {
 	} );
 
 	it( 'should ignore child mutations which resulted in no changes – when element contains elements', () => {
-		viewRoot.appendChildren( parse( '<container:p><container:x></container:x></container:p>' ) );
+		viewRoot._appendChildren( parse( '<container:p><container:x></container:x></container:p>' ) );
 
 		view.render();
 
@@ -472,7 +472,7 @@ describe( 'MutationObserver', () => {
 	} );
 
 	it( 'should not ignore mutation with br inserted not on the end of the paragraph', () => {
-		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
+		viewRoot._appendChildren( parse( '<container:p>foo</container:p>' ) );
 
 		view.render();
 
@@ -491,7 +491,7 @@ describe( 'MutationObserver', () => {
 	} );
 
 	it( 'should not ignore mutation inserting element different than br on the end of the empty paragraph', () => {
-		viewRoot.appendChildren( parse( '<container:p></container:p>' ) );
+		viewRoot._appendChildren( parse( '<container:p></container:p>' ) );
 
 		view.render();
 
@@ -509,7 +509,7 @@ describe( 'MutationObserver', () => {
 	} );
 
 	it( 'should not ignore mutation inserting element different than br on the end of the paragraph with text', () => {
-		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
+		viewRoot._appendChildren( parse( '<container:p>foo</container:p>' ) );
 
 		view.render();
 
@@ -543,7 +543,7 @@ describe( 'MutationObserver', () => {
 
 		beforeEach( () => {
 			const uiElement = createUIElement( 'div' );
-			viewRoot.appendChildren( uiElement );
+			viewRoot._appendChildren( uiElement );
 
 			view.render();
 		} );

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

@@ -37,7 +37,7 @@ describe( 'SelectionObserver', () => {
 		viewRoot = viewDocument.getRoot();
 
 		view.change( writer => {
-			viewRoot.appendChildren( parse(
+			viewRoot._appendChildren( parse(
 				'<container:p>xxx<ui:span></ui:span></container:p>' +
 				'<container:p>yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy</container:p>' ) );
 

+ 83 - 83
packages/ckeditor5-engine/tests/view/renderer.js

@@ -43,7 +43,7 @@ describe( 'Renderer', () => {
 
 			const domRoot = document.createElement( 'p' );
 			domConverter.bindElements( domRoot, viewRoot );
-			viewRoot.appendChildren( new ViewText( 'foo' ) );
+			viewRoot._appendChildren( new ViewText( 'foo' ) );
 
 			renderer.markedTexts.clear();
 			renderer.markedAttributes.clear();
@@ -59,7 +59,7 @@ describe( 'Renderer', () => {
 		} );
 
 		it( 'should mark children which need update', () => {
-			viewRoot.appendChildren( new ViewText( 'foo' ) );
+			viewRoot._appendChildren( new ViewText( 'foo' ) );
 
 			renderer.markToSync( 'children', viewRoot );
 
@@ -70,7 +70,7 @@ describe( 'Renderer', () => {
 			// Overwrite viewRoot with node without coresponding DOM node.
 			viewRoot = new ViewElement( 'p' );
 
-			viewRoot.appendChildren( new ViewText( 'foo' ) );
+			viewRoot._appendChildren( new ViewText( 'foo' ) );
 
 			renderer.markToSync( 'children', viewRoot );
 
@@ -79,8 +79,8 @@ describe( 'Renderer', () => {
 
 		it( 'should mark text which need update', () => {
 			const viewText = new ViewText( 'foo' );
-			viewRoot.appendChildren( viewText );
-			viewText.data = 'bar';
+			viewRoot._appendChildren( viewText );
+			viewText._data = 'bar';
 
 			renderer.markToSync( 'text', viewText );
 
@@ -92,8 +92,8 @@ describe( 'Renderer', () => {
 			// Overwrite viewRoot with node without coresponding DOM node.
 			viewRoot = new ViewElement( 'p' );
 
-			viewRoot.appendChildren( viewText );
-			viewText.data = 'bar';
+			viewRoot._appendChildren( viewText );
+			viewText._data = 'bar';
 
 			renderer.markToSync( 'text', viewText );
 
@@ -165,7 +165,7 @@ describe( 'Renderer', () => {
 		} );
 
 		it( 'should add children', () => {
-			viewRoot.appendChildren( new ViewText( 'foo' ) );
+			viewRoot._appendChildren( new ViewText( 'foo' ) );
 
 			renderer.markToSync( 'children', viewRoot );
 			renderer.render();
@@ -177,7 +177,7 @@ describe( 'Renderer', () => {
 		} );
 
 		it( 'should remove children', () => {
-			viewRoot.appendChildren( new ViewText( 'foo' ) );
+			viewRoot._appendChildren( new ViewText( 'foo' ) );
 
 			renderer.markToSync( 'children', viewRoot );
 			renderer.render();
@@ -185,7 +185,7 @@ describe( 'Renderer', () => {
 			expect( domRoot.childNodes.length ).to.equal( 1 );
 			expect( domRoot.childNodes[ 0 ].data ).to.equal( 'foo' );
 
-			viewRoot.removeChildren( 0, 1 );
+			viewRoot._removeChildren( 0, 1 );
 
 			renderer.markToSync( 'children', viewRoot );
 			renderer.render();
@@ -197,7 +197,7 @@ describe( 'Renderer', () => {
 
 		it( 'should update text', () => {
 			const viewText = new ViewText( 'foo' );
-			viewRoot.appendChildren( viewText );
+			viewRoot._appendChildren( viewText );
 
 			renderer.markToSync( 'children', viewRoot );
 			renderer.render();
@@ -205,7 +205,7 @@ describe( 'Renderer', () => {
 			expect( domRoot.childNodes.length ).to.equal( 1 );
 			expect( domRoot.childNodes[ 0 ].data ).to.equal( 'foo' );
 
-			viewText.data = 'bar';
+			viewText._data = 'bar';
 
 			renderer.markToSync( 'text', viewText );
 			renderer.render();
@@ -219,7 +219,7 @@ describe( 'Renderer', () => {
 		it( 'should not update text parent child list changed', () => {
 			const viewImg = new ViewElement( 'img' );
 			const viewText = new ViewText( 'foo' );
-			viewRoot.appendChildren( [ viewImg, viewText ] );
+			viewRoot._appendChildren( [ viewImg, viewText ] );
 
 			renderer.markToSync( 'children', viewRoot );
 			renderer.markToSync( 'text', viewText );
@@ -232,7 +232,7 @@ describe( 'Renderer', () => {
 
 		it( 'should not change text if it is the same during text rendering', () => {
 			const viewText = new ViewText( 'foo' );
-			viewRoot.appendChildren( viewText );
+			viewRoot._appendChildren( viewText );
 
 			renderer.markToSync( 'children', viewRoot );
 			renderer.render();
@@ -249,7 +249,7 @@ describe( 'Renderer', () => {
 
 		it( 'should not change text if it is the same during children rendering', () => {
 			const viewText = new ViewText( 'foo' );
-			viewRoot.appendChildren( viewText );
+			viewRoot._appendChildren( viewText );
 
 			renderer.markToSync( 'children', viewRoot );
 			renderer.render();
@@ -266,7 +266,7 @@ describe( 'Renderer', () => {
 
 		it( 'should not change element if it is the same', () => {
 			const viewImg = new ViewElement( 'img' );
-			viewRoot.appendChildren( viewImg );
+			viewRoot._appendChildren( viewImg );
 
 			// This should not be changed during the render.
 			const domImg = document.createElement( 'img' );
@@ -283,14 +283,14 @@ describe( 'Renderer', () => {
 
 		it( 'should change element if it is different', () => {
 			const viewImg = new ViewElement( 'img' );
-			viewRoot.appendChildren( viewImg );
+			viewRoot._appendChildren( viewImg );
 
 			renderer.markToSync( 'children', viewRoot );
 			renderer.render();
 
 			const viewP = new ViewElement( 'p' );
-			viewRoot.removeChildren( 0, 1 );
-			viewRoot.appendChildren( viewP );
+			viewRoot._removeChildren( 0, 1 );
+			viewRoot._appendChildren( viewP );
 
 			renderer.markToSync( 'children', viewRoot );
 			renderer.render();
@@ -304,18 +304,18 @@ describe( 'Renderer', () => {
 			const viewP = new ViewElement( 'p', null, viewFoo );
 			const viewDiv = new ViewElement( 'div', null, viewP );
 
-			viewRoot.appendChildren( viewDiv );
+			viewRoot._appendChildren( viewDiv );
 
 			renderer.markToSync( 'children', viewRoot );
 			renderer.render();
 
-			viewDiv.removeChildren( 0, 1 );
+			viewDiv._removeChildren( 0, 1 );
 			renderer.markToSync( 'children', viewDiv );
 			renderer.render();
 
-			viewP.removeChildren( 0, 1 );
+			viewP._removeChildren( 0, 1 );
 
-			viewDiv.appendChildren( viewP );
+			viewDiv._appendChildren( viewP );
 			renderer.markToSync( 'children', viewDiv );
 			renderer.render();
 
@@ -337,21 +337,21 @@ describe( 'Renderer', () => {
 			const viewP = new ViewElement( 'p' );
 			const viewDivInner = new ViewElement( 'div', null, viewP );
 			const viewDivOuter = new ViewElement( 'div', null, viewDivInner );
-			viewRoot.appendChildren( viewDivOuter );
+			viewRoot._appendChildren( viewDivOuter );
 
 			// Render view tree to DOM.
 			renderer.markToSync( 'children', viewRoot );
 			renderer.render();
 
 			// Remove div "outer" from root and render it.
-			viewDivOuter.remove();
+			viewDivOuter._remove();
 			renderer.markToSync( 'children', viewRoot );
 			renderer.render();
 
 			// Remove p from div "child" -- div "inner" won't be marked because it is in document fragment not view root.
-			viewP.remove();
+			viewP._remove();
 			// Add div "outer" back to root.
-			viewRoot.appendChildren( viewDivOuter );
+			viewRoot._appendChildren( viewDivOuter );
 			renderer.markToSync( 'children', viewRoot );
 
 			// Render changes, view is: root -> div "outer" -> div "inner".
@@ -376,18 +376,18 @@ describe( 'Renderer', () => {
 			const viewP = new ViewElement( 'p', null, viewFoo );
 			const viewDiv = new ViewElement( 'div', null, viewP );
 
-			viewRoot.appendChildren( viewDiv );
+			viewRoot._appendChildren( viewDiv );
 
 			renderer.markToSync( 'children', viewRoot );
 			renderer.render();
 
-			viewRoot.removeChildren( 0, 1 );
+			viewRoot._removeChildren( 0, 1 );
 			renderer.markToSync( 'children', viewRoot );
 
-			viewDiv.removeChildren( 0, 1 );
+			viewDiv._removeChildren( 0, 1 );
 			renderer.markToSync( 'children', viewDiv );
 
-			viewP.removeChildren( 0, 1 );
+			viewP._removeChildren( 0, 1 );
 			renderer.markToSync( 'children', viewP );
 
 			renderer.render();
@@ -402,7 +402,7 @@ describe( 'Renderer', () => {
 				'<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
 
 			const viewRoot = new ViewElement( 'p' );
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -416,7 +416,7 @@ describe( 'Renderer', () => {
 			const { view: viewP, selection: newSelection } = parse(
 				'<container:p>foo<attribute:b contenteditable="false">[]</attribute:b>bar</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -438,7 +438,7 @@ describe( 'Renderer', () => {
 			const { view: viewP, selection: newSelection } = parse(
 				'<container:p contenteditable="false">foo<attribute:b>[]</attribute:b>bar</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -463,7 +463,7 @@ describe( 'Renderer', () => {
 			const { view: viewP, selection: newSelection } = parse(
 				'<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -522,7 +522,7 @@ describe( 'Renderer', () => {
 			const { view: viewP, selection: newSelection } = parse(
 				'<container:p>[]<attribute:b>foo</attribute:b></container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -573,7 +573,7 @@ describe( 'Renderer', () => {
 			const { view: viewP, selection: newSelection } = parse(
 				'<container:p><attribute:b>foo</attribute:b>[]</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -623,7 +623,7 @@ describe( 'Renderer', () => {
 			const { view: viewP, selection: newSelection } = parse(
 				'<container:p><attribute:b>foo</attribute:b>[]<attribute:b>bar</attribute:b></container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -651,7 +651,7 @@ describe( 'Renderer', () => {
 			const { view: viewP, selection: newSelection } = parse(
 				'<container:p>foo<attribute:b>[]</attribute:b><attribute:i></attribute:i></container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -687,7 +687,7 @@ describe( 'Renderer', () => {
 			// Step 1: <p>foo<b>"FILLER{}"</b></p>
 			const { view: viewP, selection: newSelection } = parse( '<container:p>foo<attribute:b>[]</attribute:b></container:p>' );
 			const viewB = viewP.getChild( 1 );
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -702,7 +702,7 @@ describe( 'Renderer', () => {
 
 			// Step 2: Add text node.
 			const viewText = new ViewText( 'x' );
-			viewB.appendChildren( viewText );
+			viewB._appendChildren( viewText );
 			selection._setTo( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
 
 			renderer.markToSync( 'children', viewB );
@@ -726,7 +726,7 @@ describe( 'Renderer', () => {
 		it( 'should remove filler from a modified DOM in case <p>bar<b>foo</b>[]</p>', () => {
 			// Step 1: <p>bar<b>foo</b>"FILLER{}"</p>
 			const { view: viewP, selection: newSelection } = parse( '<container:p>bar<attribute:b>foo</attribute:b>[]</container:p>' );
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -737,7 +737,7 @@ describe( 'Renderer', () => {
 			expect( domP.childNodes[ 2 ].data ).to.equal( INLINE_FILLER );
 
 			// Step 2: Remove the <b> and update the selection (<p>bar[]</p>).
-			viewP.removeChildren( 1 );
+			viewP._removeChildren( 1 );
 
 			selection._setTo( ViewRange.createFromParentsAndOffsets( viewP, 1, viewP, 1 ) );
 
@@ -755,7 +755,7 @@ describe( 'Renderer', () => {
 			const { view: viewFragment, selection: newSelection } = parse(
 				'<container:p><attribute:b>foo</attribute:b>[]<attribute:b>bar</attribute:b></container:p><container:p></container:p>'
 			);
-			viewRoot.appendChildren( viewFragment );
+			viewRoot._appendChildren( viewFragment );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -772,9 +772,9 @@ describe( 'Renderer', () => {
 			// <p>[]</p><p><b>foo</b><b>bar</b></p>
 			const viewP = viewRoot.getChild( 0 );
 			const viewP2 = viewRoot.getChild( 1 );
-			const removedChildren = viewP.removeChildren( 0, 2 );
+			const removedChildren = viewP._removeChildren( 0, 2 );
 
-			viewP2.appendChildren( removedChildren );
+			viewP2._appendChildren( removedChildren );
 
 			selection._setTo( ViewRange.createFromParentsAndOffsets( viewP, 0, viewP, 0 ) );
 
@@ -797,7 +797,7 @@ describe( 'Renderer', () => {
 		it( 'should not break when selection is moved to a new element, when filler exists', () => {
 			// Step 1: <p>bar<b>"FILLER{}"</b></p>
 			const { view: viewP, selection: newSelection } = parse( '<container:p>bar<attribute:b>[]</attribute:b></container:p>' );
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -808,10 +808,10 @@ describe( 'Renderer', () => {
 			expect( domP.childNodes[ 1 ].childNodes[ 0 ].data ).to.equal( INLINE_FILLER );
 
 			// Step 2: Move selection to a new attribute element and remove the previous one
-			viewP.removeChildren( 1 ); // Remove <b>.
+			viewP._removeChildren( 1 ); // Remove <b>.
 
 			const viewI = parse( '<attribute:i></attribute:i>' );
-			viewP.appendChildren( viewI );
+			viewP._appendChildren( viewI );
 
 			selection._setTo( ViewRange.createFromParentsAndOffsets( viewI, 0, viewI, 0 ) );
 
@@ -829,7 +829,7 @@ describe( 'Renderer', () => {
 		it( 'should remove inline filler if selection is before a view element not bound to dom', () => {
 			// Step 1: <p>bar<b>abc</b>"FILLER"{}</p>
 			const { view: viewP, selection: newSelection } = parse( '<container:p>bar<attribute:b>abc</attribute:b>[]</container:p>' );
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -841,7 +841,7 @@ describe( 'Renderer', () => {
 
 			// Step 2: Move selection to a new attribute element.
 			const viewAbc = parse( 'abc' );
-			viewP.appendChildren( viewAbc );
+			viewP._appendChildren( viewAbc );
 
 			selection._setTo( ViewRange.createFromParentsAndOffsets( viewP, 3, viewP, 3 ) );
 
@@ -858,7 +858,7 @@ describe( 'Renderer', () => {
 
 			const { view: viewP, selection: newSelection } = parse( '<container:p>[]</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -885,7 +885,7 @@ describe( 'Renderer', () => {
 			domSelection.addRange( domRange );
 
 			const viewText = new ViewText( 'x' );
-			viewP.appendChildren( viewText );
+			viewP._appendChildren( viewText );
 			selection._setTo( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
 
 			renderer.markToSync( 'children', viewP );
@@ -897,7 +897,7 @@ describe( 'Renderer', () => {
 
 			const { view: viewP, selection: newSelection } = parse( '<container:p>[]</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -915,7 +915,7 @@ describe( 'Renderer', () => {
 
 			// Add text node only in View <p>x{}</p>
 			const viewText = new ViewText( 'x' );
-			viewP.appendChildren( viewText );
+			viewP._appendChildren( viewText );
 			selection._setTo( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
 
 			renderer.markToSync( 'children', viewP );
@@ -935,7 +935,7 @@ describe( 'Renderer', () => {
 
 			const { view: viewP, selection: newSelection } = parse( '<container:p>x{}</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -961,7 +961,7 @@ describe( 'Renderer', () => {
 			domRange.collapse( true );
 			domSelection.addRange( domRange );
 
-			viewP.removeChildren( 0 );
+			viewP._removeChildren( 0 );
 
 			selection._setTo( ViewRange.createFromParentsAndOffsets( viewP, 0, viewP, 0 ) );
 
@@ -977,7 +977,7 @@ describe( 'Renderer', () => {
 			const { view: viewP, selection: newSelection } = parse(
 				'<container:p><attribute:b>[]</attribute:b>foo</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -1013,7 +1013,7 @@ describe( 'Renderer', () => {
 			domSelection.addRange( domRange );
 
 			const viewText = new ViewText( 'x' );
-			viewB.appendChildren( viewText );
+			viewB._appendChildren( viewText );
 			selection._setTo( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
 
 			renderer.markToSync( 'children', viewP );
@@ -1028,7 +1028,7 @@ describe( 'Renderer', () => {
 			const { view: viewP, selection: newSelection } = parse(
 				'<container:p><attribute:b>[]</attribute:b>foo</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -1056,7 +1056,7 @@ describe( 'Renderer', () => {
 			// 3. Add text node only to the view: <p><b>x{}</b>foo</p>.
 
 			const viewText = new ViewText( 'x' );
-			viewB.appendChildren( viewText );
+			viewB._appendChildren( viewText );
 			selection._setTo( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
 
 			renderer.markToSync( 'children', viewB );
@@ -1091,7 +1091,7 @@ describe( 'Renderer', () => {
 			const { view: viewP, selection: newSelection } = parse(
 				'<container:p><attribute:b>[]</attribute:b>foo</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -1119,7 +1119,7 @@ describe( 'Renderer', () => {
 			// 3. Add text node only to the view: <p><b>x{}</b>foo</p>.
 
 			const viewText = new ViewText( 'x' );
-			viewB.appendChildren( viewText );
+			viewB._appendChildren( viewText );
 			selection._setTo( ViewRange.createFromParentsAndOffsets( viewText, 1, viewText, 1 ) );
 
 			renderer.markToSync( 'text', viewText );
@@ -1142,7 +1142,7 @@ describe( 'Renderer', () => {
 			const { view: viewP, selection: newSelection } = parse(
 				'<container:p>fo{o<attribute:b>b}ar</attribute:b></container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -1180,7 +1180,7 @@ describe( 'Renderer', () => {
 
 			const { view: viewP, selection: newSelection } = parse( '<container:p>fo{o}</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.render();
@@ -1222,7 +1222,7 @@ describe( 'Renderer', () => {
 
 			const { view: viewP, selection: newSelection } = parse( '<container:p>fo{o}</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.render();
@@ -1251,7 +1251,7 @@ describe( 'Renderer', () => {
 		it( 'should not add inline filler after text node', () => {
 			const { view: viewP, selection: newSelection } = parse( '<container:p>foo[]</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -1266,7 +1266,7 @@ describe( 'Renderer', () => {
 			const { view: viewP, selection: newSelection } = parse(
 				'<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
 
-			viewRoot.appendChildren( viewP );
+			viewRoot._appendChildren( viewP );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -1299,7 +1299,7 @@ describe( 'Renderer', () => {
 
 			const { view: view, selection: newSelection } = parse( inputView );
 
-			viewRoot.appendChildren( view );
+			viewRoot._appendChildren( view );
 			selection._setTo( newSelection );
 
 			renderer.markToSync( 'children', viewRoot );
@@ -1310,9 +1310,9 @@ describe( 'Renderer', () => {
 
 			// 3. Move the inline filler parent to a newly created element.
 			const viewLi = view.getChild( 0 );
-			const viewLiIndented = view.removeChildren( 1, 1 ); // Array with one element.
+			const viewLiIndented = view._removeChildren( 1, 1 ); // Array with one element.
 			const viewUl = new ViewContainerElement( 'ul', null, viewLiIndented );
-			viewLi.appendChildren( viewUl );
+			viewLi._appendChildren( viewUl );
 
 			// 4. Mark changed items and render the view.
 			renderer.markToSync( 'children', view );
@@ -1360,7 +1360,7 @@ describe( 'Renderer', () => {
 				const { view: viewP, selection: newSelection } = parse(
 					'<container:p>[foo bar]</container:p>'
 				);
-				viewRoot.appendChildren( viewP );
+				viewRoot._appendChildren( viewP );
 				selection._setTo( newSelection );
 				renderer.markToSync( 'children', viewRoot );
 				renderer.render();
@@ -1550,7 +1550,7 @@ describe( 'Renderer', () => {
 				const { view: viewP, selection: newSelection } = parse(
 					'<container:p>foo{}<attribute:b>bar</attribute:b></container:p>' );
 
-				viewRoot.appendChildren( viewP );
+				viewRoot._appendChildren( viewP );
 				selection._setTo( newSelection );
 
 				renderer.markToSync( 'children', viewRoot );
@@ -1590,7 +1590,7 @@ describe( 'Renderer', () => {
 				const { view: viewP, selection: newSelection } = parse(
 					'<container:p>foo<attribute:b>[]</attribute:b></container:p>' );
 
-				viewRoot.appendChildren( viewP );
+				viewRoot._appendChildren( viewP );
 				selection._setTo( newSelection );
 
 				renderer.markToSync( 'children', viewRoot );
@@ -1629,7 +1629,7 @@ describe( 'Renderer', () => {
 				const { view: viewP, selection: newSelection } = parse(
 					'<container:p>fo{o}<attribute:b>bar</attribute:b></container:p>' );
 
-				viewRoot.appendChildren( viewP );
+				viewRoot._appendChildren( viewP );
 				selection._setTo( newSelection );
 
 				renderer.markToSync( 'children', viewRoot );
@@ -1668,7 +1668,7 @@ describe( 'Renderer', () => {
 
 				const { view: viewP, selection: newSelection } = parse( '<container:p>foo[]<ui:span></ui:span></container:p>' );
 
-				viewRoot.appendChildren( viewP );
+				viewRoot._appendChildren( viewP );
 				selection._setTo( newSelection );
 
 				renderer.markToSync( 'children', viewRoot );
@@ -1710,7 +1710,7 @@ describe( 'Renderer', () => {
 				const { view: viewP, selection: newSelection } = parse(
 					'<container:p>foo<attribute:b>{ba}r</attribute:b></container:p>' );
 
-				viewRoot.appendChildren( viewP );
+				viewRoot._appendChildren( viewP );
 				selection._setTo( newSelection );
 
 				renderer.markToSync( 'children', viewRoot );
@@ -1748,7 +1748,7 @@ describe( 'Renderer', () => {
 				const { view: viewP, selection: newSelection } = parse(
 					'<container:p>foo<attribute:b>b{ar}</attribute:b>baz</container:p>' );
 
-				viewRoot.appendChildren( viewP );
+				viewRoot._appendChildren( viewP );
 				selection._setTo( newSelection );
 
 				renderer.markToSync( 'children', viewRoot );
@@ -1786,7 +1786,7 @@ describe( 'Renderer', () => {
 				const { view: viewP, selection: newSelection } = parse(
 					'<container:p>foo<attribute:b><attribute:i>{ba}r</attribute:i></attribute:b></container:p>' );
 
-				viewRoot.appendChildren( viewP );
+				viewRoot._appendChildren( viewP );
 				selection._setTo( newSelection );
 
 				renderer.markToSync( 'children', viewRoot );
@@ -1824,7 +1824,7 @@ describe( 'Renderer', () => {
 				const { view: viewP, selection: newSelection } = parse(
 					'<container:p>f{oo<attribute:b><attribute:i>bar}</attribute:i></attribute:b>baz</container:p>' );
 
-				viewRoot.appendChildren( viewP );
+				viewRoot._appendChildren( viewP );
 				selection._setTo( newSelection );
 
 				renderer.markToSync( 'children', viewRoot );
@@ -1914,7 +1914,7 @@ describe( 'Renderer', () => {
 				writer.unwrap( viewDoc.selection.getFirstRange(), new ViewAttributeElement( 'italic' ) );
 			} );
 
-			viewRoot.getChild( 0 ).getChild( 0 ).getChild( 0 ).data = 'bar';
+			viewRoot.getChild( 0 ).getChild( 0 ).getChild( 0 )._data = 'bar';
 			expect( getViewData( view ) ).to.equal( '<p>[<strong>bar</strong>]</p>' );
 
 			// Re-render changes in view to DOM.
@@ -1935,7 +1935,7 @@ describe( 'Renderer', () => {
 
 			// Change text and insert new element into paragraph.
 			const textNode = viewRoot.getChild( 0 ).getChild( 0 );
-			textNode.data = 'foobar';
+			textNode._data = 'foobar';
 
 			view.change( writer => {
 				writer.insert( ViewPosition.createAfter( textNode ), new ViewAttributeElement( 'img' ) );
@@ -1961,7 +1961,7 @@ describe( 'Renderer', () => {
 
 			// Change text and insert new element into paragraph.
 			const textNode = viewRoot.getChild( 0 ).getChild( 0 );
-			textNode.data = 'foobar';
+			textNode._data = 'foobar';
 
 			view.change( writer => {
 				writer.insert( ViewPosition.createBefore( textNode ), new ViewAttributeElement( 'img' ) );

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

@@ -86,7 +86,7 @@ describe( 'RootEditableElement', () => {
 		root._document = createDocumentMock();
 		root.rootName = 'header';
 
-		const newRoot = root.clone();
+		const newRoot = root._clone();
 
 		expect( newRoot._document ).to.equal( root._document );
 		expect( newRoot.rootName ).to.equal( root.rootName );

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

@@ -942,7 +942,7 @@ describe( 'Selection', () => {
 			const selection = viewDocument.selection;
 			const root = createViewRoot( viewDocument, 'div', 'main' );
 			const element = new Element( 'p' );
-			root.appendChildren( element );
+			root._appendChildren( element );
 
 			selection._setTo( Range.createFromParentsAndOffsets( element, 0, element, 0 ) );
 

+ 13 - 5
packages/ckeditor5-engine/tests/view/text.js

@@ -40,10 +40,10 @@ describe( 'Text', () => {
 		} );
 	} );
 
-	describe( 'clone', () => {
+	describe( '_clone()', () => {
 		it( 'should return new text with same data', () => {
 			const text = new Text( 'foo bar' );
-			const clone = text.clone();
+			const clone = text._clone();
 
 			expect( clone ).to.not.equal( text );
 			expect( clone.data ).to.equal( text.data );
@@ -69,8 +69,8 @@ describe( 'Text', () => {
 		} );
 
 		it( 'should return false when data is not the same', () => {
-			const other = text.clone();
-			other.data = 'not-foo';
+			const other = text._clone();
+			other._data = 'not-foo';
 
 			expect( text.isSimilar( other ) ).to.be.false;
 		} );
@@ -79,9 +79,17 @@ describe( 'Text', () => {
 	describe( 'setText', () => {
 		it( 'should change the text', () => {
 			const text = new Text( 'foo' );
-			text.data = 'bar';
+			text._data = 'bar';
 
 			expect( text.data ).to.equal( 'bar' );
 		} );
+
+		it( 'works when using addition assignment operator (+=)', () => {
+			const foo = new Text( 'foo' );
+			const bar = new Text( 'bar' );
+
+			foo._data += bar.data;
+			expect( foo.data ).to.equal( 'foobar' );
+		} );
 	} );
 } );

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

@@ -42,7 +42,7 @@ describe( 'TreeWalker', () => {
 		paragraph = new ContainerElement( 'p', null, [ bold, charY, img2, charX ] );
 		img1 = new ContainerElement( 'img1' );
 
-		root.insertChildren( 0, [ img1, paragraph ] );
+		root._insertChildren( 0, [ img1, paragraph ] );
 
 		rootBeginning = new Position( root, 0 );
 		rootEnding = new Position( root, 2 );

Some files were not shown because too many files changed in this diff