瀏覽代碼

Introduce AttributeElement and ContainerElement.

Piotr Jasiun 9 年之前
父節點
當前提交
7d616f2e5f

+ 41 - 0
packages/ckeditor5-engine/src/treeview/attributeelement.js

@@ -0,0 +1,41 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Element from './element.js';
+
+export const DEFAULT_PRIORITY = 10;
+
+/**
+ * Attributes are elements which define document presentation. They are mostly elements like `<b>` or `<span>`.
+ * Attributes can be broken and merged by the {@link engine.treeView.Writer}. Merging requires that attribute nodes are
+ * {@link engine.treeView.Element#isSimilar similar} and have same priority. Setting different priorities on similar
+ * nodes may prevent merging, eg. two `<abbr>` nodes next each other shouldn't be merged.
+ *
+ * Editing engine does not define fixed HTML DTD. This is why the type of the {@link engine.treeView.Element} need to
+ * be defined by the feature developer. Creating an element you should use {@link engine.treeView.ContainerElement}
+ * class or `AttributeElement`.
+ *
+ * @memberOf engine.treeView
+ * @extends engine.treeView.Element
+ */
+export default class AttributeElement extends Element {
+	/**
+	 * Creates a attribute element.
+	 *
+	 * @see engine.treeView.Element
+	 */
+	constructor( name, attrs, children ) {
+		super( name, attrs, children );
+
+		/**
+		 * Element priority.
+		 *
+		 * @member {Number} engine.treeView.AttributeElement#priority
+		 */
+		this.priority = DEFAULT_PRIORITY;
+	}
+}

+ 54 - 0
packages/ckeditor5-engine/src/treeview/containerelement.js

@@ -0,0 +1,54 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Element from './element.js';
+
+/**
+ * Containers are elements which define document structure. They define boundaries for
+ * {@link engine.treeView.AttributeElement attributes}. They are mostly use for block elements like `<p>` or `<div>`.
+ *
+ * Editing engine does not define fixed HTML DTD. This is why the type of the {@link engine.treeView.Element} need to
+ * be defined by the feature developer.
+ *
+ * Creating an element you should use `ContainerElement` class or {@link engine.treeView.AttributeElement}. This is
+ * important to define the type of the element because of two reasons:
+ *
+ * Firstly, {@link engine.treeView.DomConverter} needs the information what is an editable block to convert elements to
+ * DOM properly. {@link engine.treeView.DomConverter} will ensure that `ContainerElement` is editable and it is possible
+ * to put caret inside it, even if the container is empty.
+ *
+ * Secondly, {@link engine.treeView.Writer} use this information.
+ * {@link engine.treeView.Writer#breakAttributes Break} and {@link engine.treeView.Writer#mergeAttributes Merge}
+ * operations are performed only in a bounds of a container nodes.
+ *
+ * For instance if `<p>` is an container and `<b>` is attribute:
+ *
+ *		<p><b>fo^o</b></p>
+ *
+ * {@link engine.treeView.Writer#breakAttributes breakAttributes} will create:
+ *
+ *		<p><b>fo</b><b>o</b></p>
+ *
+ * There might be a need to mark `<span>` element as a container node, for example in situation when it will be a
+ * container of an inline widget:
+ *
+ * 		<span color="red">foobar</span>  // attribute
+ * 		<span data-widget>foobar</span>  // container
+ *
+ * @memberOf engine.treeView
+ * @extends engine.treeView.Element
+ */
+export default class ContainerElement extends Element {
+	/**
+	 * Creates a container element.
+	 *
+	 * @see engine.treeView.Element
+	 */
+	constructor( name, attrs, children ) {
+		super( name, attrs, children );
+	}
+}

+ 10 - 1
packages/ckeditor5-engine/src/treeview/element.js

@@ -12,6 +12,14 @@ import isPlainObject from '../../utils/lib/lodash/isPlainObject.js';
 /**
  * Tree view element.
  *
+ * Editing engine does not define fixed HTML DTD. This is why the type of the {@link engine.treeView.Element} need to
+ * be defined by the feature developer. Creating an element you should use {@link engine.treeView.ContainerElement}
+ * class or {@link engine.treeView.AttributeElement}.
+ *
+ * Note that for view elements which are not created from model, like elements from mutations, paste or
+ * {@link engine.treeController.DataController#set data.set} it is not possible to define the type of the element, so
+ * these will be instances of the {@link engine.treeView.Element}.
+ *
  * @memberOf engine.treeView
  * @extends engine.treeView.Node
  */
@@ -110,7 +118,8 @@ export default class Element extends Node {
 			}
 		}
 
-		const cloned = new Element( this.name, this._attrs, childrenClone );
+		// 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.

+ 18 - 90
packages/ckeditor5-engine/src/treeview/writer.js

@@ -6,7 +6,8 @@
 'use strict';
 
 import Position from './position.js';
-import Element from './element.js';
+import ContainerElement from './containerelement.js';
+import AttributeElement from './attributeelement.js';
 import Text from './text.js';
 import Range from './range.js';
 import CKEditorError from '../../utils/ckeditorerror.js';
@@ -19,79 +20,6 @@ import DocumentFragment from './documentfragment.js';
  * @memberOf engine.treeView
  */
  export default class Writer {
-	constructor() {
-		/**
-		 * Priorities map. Maps node to priority.
-		 * Nodes with priorities are considered as attributes.
-		 *
-		 * @member {WeakMap} engine.treeView.Writer#_priorities
-		 * @protected
-		 */
-		this._priorities = new WeakMap();
-	}
-
-	/**
-	 * Returns `true` if provided node is a `container` node.
-	 *
-	 * `Container` nodes are mostly elements like `<p>` or `<div>`. Break and merge operations are performed only in a
-	 * bounds of a container nodes. Containers will not be broken or merged by
-	 * {@link engine.treeView.Writer#breakAttributes breakAttributes} and
-	 * {@link engine.treeView.Writer#mergeAttributes mergeAttributes}.
-	 *
-	 * `Attribute` nodes are mostly elements like `<b>` or `<span>`. Attributes can be broken and merged. Merging requires
-	 * that attribute nodes are {@link engine.treeView.Element#isSimilar similar} and have same priority. Setting different
-	 * priorities on similar nodes may prevent merging, eg. two `<abbr>` nodes next ot each other shouldn't be merged.
-	 * There might be a need to mark `<span>` element as a container node, for example in situation when it will be a
-	 * container of an inline widget:
-	 *
-	 * 		<span color="red">foobar</span>  // attribute
-	 * 		<span data-widget>foobar</span>  // container
-	 *
-	 * @param {engine.treeView.Element} node Node to check.
-	 * @returns {Boolean} `True` if provided node is a container.
-     */
-	isContainer( node ) {
-		const isElement = node instanceof Element;
-
-		return isElement && !this._priorities.has( node );
-	}
-
-	/**
-	 * Returns `true` if provided node is an `attribute` node.
-	 * For more information about attribute and container nodes see {@link engine.treeView.Writer#isContainer isContainer}
-	 * method description.
-	 *
-	 * @see engine.treeView.Writer#isContainer
-	 * @param {engine.treeView.Element} node Node to check.
-	 * @returns {Boolean} `True` if provided node is an attribute.
-	 */
-	isAttribute( node ) {
-		const isElement = node instanceof Element;
-
-		return isElement && this._priorities.has( node );
-	}
-
-	/**
-	 * Sets node priority. When priority is defined, node is considered as `attribute`.
-	 *
-	 * @see engine.treeView.Writer#isContainer
-	 * @param {engine.treeView.Node} node
-	 * @param {Number} priority
-     */
-	setPriority( node, priority ) {
-		this._priorities.set( node, priority );
-	}
-
-	/**
-	 * Returns node's priority.
-	 *
-	 * @param {engine.treeView.Node} node Node to check its priority.
-	 * @returns {Number|undefined} Priority or `undefined` if there is no priority defined.
-     */
-	getPriority( node ) {
-		return this._priorities.get( node );
-	}
-
 	/**
 	 * Returns first parent container of specified {@link engine.treeView.Position Position}.
 	 * Position's parent node is checked as first, then next parents are checked.
@@ -102,7 +30,7 @@ import DocumentFragment from './documentfragment.js';
 	getParentContainer( position ) {
 		let parent = position.parent;
 
-		while ( !this.isContainer( parent ) ) {
+		while ( !( parent instanceof ContainerElement ) ) {
 			if ( !parent ) {
 				return undefined;
 			}
@@ -132,7 +60,7 @@ import DocumentFragment from './documentfragment.js';
 		const positionParent = position.parent;
 
 		// Position's parent is container, so no attributes to break.
-		if ( this.isContainer( positionParent ) ) {
+		if ( positionParent instanceof ContainerElement ) {
 			return Position.createFromPosition( position );
 		}
 
@@ -182,7 +110,7 @@ import DocumentFragment from './documentfragment.js';
 				const clonedNode = positionParent.clone();
 
 				// Clone priority.
-				this.setPriority( clonedNode, this.getPriority( positionParent ) );
+				clonedNode.priority = positionParent.priority;
 
 				// Insert cloned node to position's parent node.
 				positionParent.parent.insertChildren( offsetAfter, clonedNode );
@@ -279,7 +207,7 @@ import DocumentFragment from './documentfragment.js';
 		}
 
 		// When one or both nodes are containers - no attributes to merge.
-		if ( this.isContainer( nodeBefore ) || this.isContainer( nodeAfter ) ) {
+		if ( ( nodeBefore instanceof ContainerElement ) || ( nodeAfter instanceof ContainerElement ) ) {
 			return position;
 		}
 
@@ -293,8 +221,8 @@ import DocumentFragment from './documentfragment.js';
 			return new Position( nodeBefore, nodeBeforeLength );
 		} else if ( nodeBefore.isSimilar( nodeAfter ) ) {
 			// When selection is between same nodes.
-			const nodeBeforePriority = this._priorities.get( nodeBefore );
-			const nodeAfterPriority = this._priorities.get( nodeAfter );
+			const nodeBeforePriority = nodeBefore.priority;
+			const nodeAfterPriority = nodeAfter.priority;
 
 			// Do not merge same nodes with different priorities.
 			if ( nodeBeforePriority === undefined || nodeBeforePriority !== nodeAfterPriority ) {
@@ -414,7 +342,7 @@ import DocumentFragment from './documentfragment.js';
 	 * and {@link engine.treeView.Range#end} positions are not placed inside same parent container.
 	 *
 	 * @param {engine.treeView.Range} range Range to wrap.
-	 * @param {engine.treeView.Element} attribute Attribute element to use as wrapper.
+	 * @param {engine.treeView.AttributeElement} attribute Attribute element to use as wrapper.
 	 * @param {Number} priority Priority to set.
 	 */
 	wrap( range, attribute, priority ) {
@@ -434,7 +362,7 @@ import DocumentFragment from './documentfragment.js';
 		}
 
 		// Sets wrapper element priority.
-		this.setPriority( attribute, priority );
+		attribute.priority = priority;
 
 		// Break attributes at range start and end.
 		const { start: breakStart, end: breakEnd } = this.breakRange( range );
@@ -466,7 +394,7 @@ import DocumentFragment from './documentfragment.js';
 	 * same parent container.
 	 *
 	 * @param {engine.treeView.Range} range
-	 * @param {engine.treeView.Element} element
+	 * @param {engine.treeView.AttributeElement} element
 	 */
 	unwrap( range, attribute ) {
 		// Range should be placed inside one container.
@@ -522,7 +450,7 @@ function unwrapChildren( writer, parent, startOffset, endOffset, attribute ) {
 		const child = parent.getChild( i );
 
 		// If attributes are the similar and have same priority, then unwrap.
-		if (  child.isSimilar( attribute ) && writer.getPriority( child ) == writer.getPriority( attribute ) ) {
+		if (  child.isSimilar( attribute ) && child.priority == attribute.priority ) {
 			const unwrapped = child.getChildren();
 			const count = child.getChildCount();
 
@@ -542,7 +470,7 @@ function unwrapChildren( writer, parent, startOffset, endOffset, attribute ) {
 			endOffset += count - 1;
 		} else {
 			// If other nested attribute is found start unwrapping there.
-			if ( writer.isAttribute( child ) ) {
+			if ( child instanceof AttributeElement ) {
 				unwrapChildren( writer, child, 0, child.getChildCount(), attribute );
 			}
 
@@ -589,14 +517,14 @@ function wrapChildren( writer, parent, startOffset, endOffset, attribute ) {
 	while ( i < endOffset ) {
 		const child = parent.getChild( i );
 		const isText = child instanceof Text;
-		const isAttribute = writer.isAttribute( child );
-		const priority = writer.getPriority( attribute );
+		const isAttribute = child instanceof AttributeElement;
+		const priority = attribute.priority;
 
 		// Wrap text or attributes with higher or equal priority.
-		if ( isText || ( isAttribute && priority <= writer.getPriority( child ) ) ) {
+		if ( isText || ( isAttribute && priority <= child.priority ) ) {
 			// Clone attribute.
 			const newAttribute = attribute.clone();
-			writer.setPriority( newAttribute, priority );
+			newAttribute.priority = priority;
 
 			// Wrap current node with new attribute;
 			child.remove();
@@ -606,7 +534,7 @@ function wrapChildren( writer, parent, startOffset, endOffset, attribute ) {
 			wrapPositions.push(	new Position( parent, i ) );
 		} else {
 			// If other nested attribute is found start wrapping there.
-			if ( writer.isAttribute( child ) ) {
+			if ( child instanceof AttributeElement ) {
 				wrapChildren( writer, child, 0, child.getChildCount(), attribute );
 			}
 		}

+ 2 - 2
packages/ckeditor5-engine/tests/treeview/writer/_utils/utils.js

@@ -44,7 +44,7 @@ const utils = {
 		}
 
 		if ( description.priority !== undefined ) {
-			writer.setPriority( node, description.priority );
+			node.priority = description.priority;
 		}
 
 		if ( description.rangeStart !== undefined ) {
@@ -125,7 +125,7 @@ const utils = {
 		}
 
 		if ( description.priority !== undefined ) {
-			expect( description.priority ).to.equal( writer.getPriority( node ) );
+			expect( description.priority ).to.equal( node.priority );
 		}
 
 		if ( description.rangeStart !== undefined ) {

+ 33 - 32
packages/ckeditor5-engine/tests/treeview/writer/breakattributes.js

@@ -8,7 +8,8 @@
 'use strict';
 
 import Writer from '/ckeditor5/engine/treeview/writer.js';
-import Element from '/ckeditor5/engine/treeview/element.js';
+import ContainerElement from '/ckeditor5/engine/treeview/containerelement.js';
+import AttributeElement from '/ckeditor5/engine/treeview/attributeelement.js';
 import Text from '/ckeditor5/engine/treeview/text.js';
 import utils from '/tests/engine/treeview/writer/_utils/utils.js';
 
@@ -25,7 +26,7 @@ describe( 'Writer', () => {
 		// <p>{|foobar}</p> -> <p>|{foobar}</p>
 		it( '<p>{|foobar}</p>', () => {
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', position: 0 }
@@ -35,7 +36,7 @@ describe( 'Writer', () => {
 			const newPosition = writer.breakAttributes( created.position );
 
 			test( writer, newPosition, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 0,
 				children: [
@@ -47,7 +48,7 @@ describe( 'Writer', () => {
 		it( '<p>foo|bar</p>', () => {
 			// <p>{foo|bar}</p> -> <p>{foo}|{bar}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', position: 3 }
@@ -57,7 +58,7 @@ describe( 'Writer', () => {
 			const newPosition = writer.breakAttributes( created.position );
 
 			test( writer, newPosition, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 1,
 				children: [
@@ -70,7 +71,7 @@ describe( 'Writer', () => {
 		it( '<p>{foobar|}</p>', () => {
 			// <p>{foobar|}</p> -> <p>{foobar}|</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', position: 6 }
@@ -80,7 +81,7 @@ describe( 'Writer', () => {
 			const newPosition = writer.breakAttributes( created.position );
 
 			test( writer, newPosition, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 1,
 				children: [
@@ -92,11 +93,11 @@ describe( 'Writer', () => {
 		it( '<p><b>{foo|bar}</b></p>', () => {
 			// <p><b>{foo|bar}</b></p> -> <p><b>{foo}</b>|<b>{bar}</b></p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -109,12 +110,12 @@ describe( 'Writer', () => {
 			const newPosition = writer.breakAttributes( created.position );
 
 			test( writer, newPosition, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -122,7 +123,7 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -136,16 +137,16 @@ describe( 'Writer', () => {
 		it( '<p><b><u>{|foobar}</u></b></p>', () => {
 			// <p><b><u>{|foobar}</u></b></p> -> <p>|<b><u>{foobar}</u></b></p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [
@@ -160,17 +161,17 @@ describe( 'Writer', () => {
 			const newPosition = writer.breakAttributes( created.position );
 
 			test( writer, newPosition, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 0,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [
@@ -186,16 +187,16 @@ describe( 'Writer', () => {
 		// <p><b><u>{foo|ba}r</u></b></p> -> <p><b><u>{foo}</u></b>|<b></u>{bar}</u></b></p>
 		it( '<p><b><u>{foo|bar}</u></b></p>', () => {
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [
@@ -210,17 +211,17 @@ describe( 'Writer', () => {
 			const newPosition = writer.breakAttributes( created.position );
 
 			test( writer, newPosition, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [
@@ -230,12 +231,12 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [
@@ -251,16 +252,16 @@ describe( 'Writer', () => {
 		it( '<p><b><u>{foobar|}</u></b></p>', () => {
 			// <p><b><u>{foobar|}</u></b></p> -> <p><b><u>{foobar}</u></b>|</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [
@@ -275,17 +276,17 @@ describe( 'Writer', () => {
 			const newPosition = writer.breakAttributes( created.position );
 
 			test( writer, newPosition, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [

+ 21 - 20
packages/ckeditor5-engine/tests/treeview/writer/breakrange.js

@@ -8,7 +8,8 @@
 'use strict';
 
 import Writer from '/ckeditor5/engine/treeview/writer.js';
-import Element from '/ckeditor5/engine/treeview/element.js';
+import ContainerElement from '/ckeditor5/engine/treeview/containerelement.js';
+import AttributeElement from '/ckeditor5/engine/treeview/attributeelement.js';
 import Range from '/ckeditor5/engine/treeview/range.js';
 import Text from '/ckeditor5/engine/treeview/text.js';
 import utils from '/tests/engine/treeview/writer/_utils/utils.js';
@@ -24,8 +25,8 @@ describe( 'Writer', () => {
 
 	describe( 'breakRange', () => {
 		it( 'should throw when range placed in two containers', () => {
-			const p1 = new Element( 'p' );
-			const p2 = new Element( 'p' );
+			const p1 = new ContainerElement( 'p' );
+			const p2 = new ContainerElement( 'p' );
 
 			expect( () => {
 				writer.breakRange( Range.createFromParentsAndOffsets( p1, 0, p2, 0 ) );
@@ -35,7 +36,7 @@ describe( 'Writer', () => {
 		it( 'should break at collapsed range and return collapsed one', () => {
 			// <p>{foo[]bar}</p> -> <p>{foo}[]{bar}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', rangeStart: 3, rangeEnd: 3 }
@@ -45,7 +46,7 @@ describe( 'Writer', () => {
 			const newRange = writer.breakRange( created.range );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 1,
 				rangeEnd: 1,
@@ -59,7 +60,7 @@ describe( 'Writer', () => {
 		it( 'should break inside text node #1', () => {
 			// <p>{foo[bar]baz}</p> -> <p>{foo}[{bar}]{baz}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobarbaz', rangeStart: 3, rangeEnd: 6 }
@@ -69,7 +70,7 @@ describe( 'Writer', () => {
 			const newRange = writer.breakRange( created.range );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 1,
 				rangeEnd: 2,
@@ -84,7 +85,7 @@ describe( 'Writer', () => {
 		it( 'should break inside text node #2', () => {
 			// <p>{foo[barbaz]}</p> -> <p>{foo}[{barbaz}]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobarbaz', rangeStart: 3, rangeEnd: 9 }
@@ -94,7 +95,7 @@ describe( 'Writer', () => {
 			const newRange = writer.breakRange( created.range );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 1,
 				rangeEnd: 2,
@@ -108,7 +109,7 @@ describe( 'Writer', () => {
 		it( 'should break inside text node #3', () => {
 			// <p>{foo[barbaz}]</p> -> <p>{foo}[{barbaz}]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeEnd: 1,
 				children: [
@@ -119,7 +120,7 @@ describe( 'Writer', () => {
 			const newRange = writer.breakRange( created.range );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 1,
 				rangeEnd: 2,
@@ -133,7 +134,7 @@ describe( 'Writer', () => {
 		it( 'should break inside text node #4', () => {
 			// <p>{[foo]barbaz}</p> -> <p>[{foo}]{barbaz]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobarbaz', rangeStart: 0, rangeEnd: 3 }
@@ -143,7 +144,7 @@ describe( 'Writer', () => {
 			const newRange = writer.breakRange( created.range );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
@@ -157,7 +158,7 @@ describe( 'Writer', () => {
 		it( 'should break inside text node #5', () => {
 			// <p>[{foo]barbaz}</p> -> <p>[{foo}]{barbaz]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				children: [
@@ -168,7 +169,7 @@ describe( 'Writer', () => {
 			const newRange = writer.breakRange( created.range );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
@@ -183,12 +184,12 @@ describe( 'Writer', () => {
 			// <p>{foo[bar}<b>{baz]qux}</b></p>
 			// <p>{foo}[{bar}<b>{baz}</b>]<b>qux</b></p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', rangeStart: 3 },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -200,7 +201,7 @@ describe( 'Writer', () => {
 
 			const newRange = writer.breakRange( created.range );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 1,
 				rangeEnd: 3,
@@ -208,7 +209,7 @@ describe( 'Writer', () => {
 					{ instanceOf: Text, data: 'foo' },
 					{ instanceOf: Text, data: 'bar' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -216,7 +217,7 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [

+ 39 - 38
packages/ckeditor5-engine/tests/treeview/writer/insert.js

@@ -8,7 +8,8 @@
 'use strict';
 
 import Writer from '/ckeditor5/engine/treeview/writer.js';
-import Element from '/ckeditor5/engine/treeview/element.js';
+import ContainerElement from '/ckeditor5/engine/treeview/containerelement.js';
+import AttributeElement from '/ckeditor5/engine/treeview/attributeelement.js';
 import Position from '/ckeditor5/engine/treeview/position.js';
 import Text from '/ckeditor5/engine/treeview/text.js';
 import utils from '/tests/engine/treeview/writer/_utils/utils.js';
@@ -26,7 +27,7 @@ describe( 'Writer', () => {
 		it( 'should return collapsed range in insertion position when using empty array', () => {
 			// <p>{foo|bar}</p> -> <p>{foo[]bar}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', position: 3 }
@@ -35,7 +36,7 @@ describe( 'Writer', () => {
 
 			const newRange = writer.insert( created.position, [] );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', rangeStart: 3, rangeEnd: 3 }
@@ -47,7 +48,7 @@ describe( 'Writer', () => {
 			// <p>{foo|bar}</p> insert {baz}
 			// <p>{foo[baz]bar}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', position: 3 }
@@ -56,7 +57,7 @@ describe( 'Writer', () => {
 
 			const newRange = writer.insert( created.position, new Text( 'baz' ) );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobazbar', rangeStart: 3, rangeEnd: 6 }
@@ -68,7 +69,7 @@ describe( 'Writer', () => {
 			// <p>{foobar|}</p> insert {baz}
 			// <p>{foobar[baz}]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', position: 6 }
@@ -77,7 +78,7 @@ describe( 'Writer', () => {
 
 			const newRange = writer.insert( created.position, new Text( 'baz' ) );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeEnd: 1,
 				children: [
@@ -90,7 +91,7 @@ describe( 'Writer', () => {
 			// <p>{|foobar}</p> insert {baz}
 			// <p>[{baz]foobar}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', position: 0 }
@@ -99,7 +100,7 @@ describe( 'Writer', () => {
 
 			const newRange = writer.insert( created.position, new Text( 'baz' ) );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				children: [
@@ -112,14 +113,14 @@ describe( 'Writer', () => {
 			// <p>{foo|bar}</p> insert <b>{baz}</b>
 			// <p>{foo}[<b>baz</b>]{bar}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', position: 3 }
 				]
 			} );
 			const toInsert = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'b',
 				priority: 1,
 				children: [
@@ -129,14 +130,14 @@ describe( 'Writer', () => {
 
 			const newRange = writer.insert( created.position, toInsert.node );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 1,
 				rangeEnd: 2,
 				children: [
 					{ instanceOf: Text, data: 'foo' },
 					{
-						instanceOf: Element,
+						instanceOf: ContainerElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -152,7 +153,7 @@ describe( 'Writer', () => {
 			// <p>|{foobar}</p> insert {baz}
 			// <p>[{baz]foobar}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 0,
 				children: [
@@ -162,7 +163,7 @@ describe( 'Writer', () => {
 
 			const newRange = writer.insert( created.position, new Text( 'baz' ) );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				children: [
@@ -175,11 +176,11 @@ describe( 'Writer', () => {
 			// <p><b>{foo|bar}</b></p> insert <b>{baz}</b>
 			// <p><b>{foo[baz]bar}</b></p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -189,7 +190,7 @@ describe( 'Writer', () => {
 				]
 			} );
 			const toInsert = create( writer, {
-				instanceOf: Element,
+				instanceOf: AttributeElement,
 				name: 'b',
 				priority: 1,
 				children: [
@@ -199,11 +200,11 @@ describe( 'Writer', () => {
 
 			const newRange = writer.insert( created.position, toInsert.node );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -218,11 +219,11 @@ describe( 'Writer', () => {
 			// <p><b>{foo|bar}</b></p> insert <b>{baz}</b> ( different priority )
 			// <p><b>{foo}</b>[<b>{baz}</b>]<b>{bar}</b></p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -232,7 +233,7 @@ describe( 'Writer', () => {
 				]
 			} );
 			const toInsert = create( writer, {
-				instanceOf: Element,
+				instanceOf: AttributeElement,
 				name: 'b',
 				priority: 2,
 				children: [
@@ -242,13 +243,13 @@ describe( 'Writer', () => {
 
 			const newRange = writer.insert( created.position, toInsert.node );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 1,
 				rangeEnd: 2,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -256,7 +257,7 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 2,
 						children: [
@@ -264,7 +265,7 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -278,13 +279,13 @@ describe( 'Writer', () => {
 		it( 'should allow to insert multiple nodes', () => {
 			// <p>|</p> insert <b>{foo}</b>{bar}
 			// <p>[<b>{foo}</b>{bar}]</p>
-			const root = new Element( 'p' );
+			const root = new ContainerElement( 'p' );
 			const toInsert = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'fake',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -298,13 +299,13 @@ describe( 'Writer', () => {
 
 			const newRange = writer.insert( position, toInsert );
 			test( writer, newRange, root, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 2,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -320,12 +321,12 @@ describe( 'Writer', () => {
 			// <p><b>{qux}</b>|{baz}</p> insert <b>{foo}</b>{bar}
 			// <p><b>{qux[foo}</b>{bar]baz}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -336,11 +337,11 @@ describe( 'Writer', () => {
 				]
 			} );
 			const toInsert = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'fake',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -353,11 +354,11 @@ describe( 'Writer', () => {
 
 			const newRange = writer.insert( created.position, toInsert );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [

+ 30 - 29
packages/ckeditor5-engine/tests/treeview/writer/mergeattributes.js

@@ -8,7 +8,8 @@
 'use strict';
 
 import Writer from '/ckeditor5/engine/treeview/writer.js';
-import Element from '/ckeditor5/engine/treeview/element.js';
+import ContainerElement from '/ckeditor5/engine/treeview/containerelement.js';
+import AttributeElement from '/ckeditor5/engine/treeview/attributeelement.js';
 import Text from '/ckeditor5/engine/treeview/text.js';
 import utils from '/tests/engine/treeview/writer/_utils/utils.js';
 
@@ -25,7 +26,7 @@ describe( 'Writer', () => {
 		it( 'should not merge if inside text node', () => {
 			// <p>{fo|obar}</p>
 			const description = {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', position: 2 }
@@ -39,19 +40,19 @@ describe( 'Writer', () => {
 		it( 'should not merge if between containers', () => {
 			// <div><p>{foo}</p>|<p>{bar}</p></div>
 			const description = {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'div',
 				position: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: ContainerElement,
 						name: 'p',
 						children: [
 							{ instanceOf: Text, data: 'foo' }
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: ContainerElement,
 						name: 'p',
 						children: [
 							{ instanceOf: Text, data: 'bar' }
@@ -66,7 +67,7 @@ describe( 'Writer', () => {
 
 		it( 'should return same position when inside empty container', () => {
 			// <p>|</p>
-			const description = { instanceOf: Element, name: 'p', position: 0 };
+			const description = { instanceOf: ContainerElement, name: 'p', position: 0 };
 			const created = create( writer, description );
 			const newPosition = writer.mergeAttributes( created.position );
 			test( writer, newPosition, created.node, description );
@@ -75,12 +76,12 @@ describe( 'Writer', () => {
 		it( 'should not merge when position is placed at the beginning of the container', () => {
 			// <p>|<b></b></p>
 			const description = {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 0,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1
 					}
@@ -94,12 +95,12 @@ describe( 'Writer', () => {
 		it( 'should not merge when position is placed at the end of the container', () => {
 			// <p><b></b>|</p>
 			const description = {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1
 					}
@@ -113,7 +114,7 @@ describe( 'Writer', () => {
 		it( 'should merge when placed between two text nodes', () => {
 			// <p>{foo}|{bar}</p> -> <p>{foo|bar}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 1,
 				children: [
@@ -125,7 +126,7 @@ describe( 'Writer', () => {
 			const newPosition = writer.mergeAttributes( created.position );
 
 			test( writer, newPosition, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', position: 3 }
@@ -136,18 +137,18 @@ describe( 'Writer', () => {
 		it( 'should merge when placed between similar attribute nodes', () => {
 			// <p><b foo="bar"></b>|<b foo="bar"></b></p> -> <p><b foo="bar">|</b></p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						attributes: { foo: 'bar' }
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						attributes: { foo: 'bar' }
@@ -158,11 +159,11 @@ describe( 'Writer', () => {
 			const newPosition = writer.mergeAttributes( created.position );
 
 			test( writer, newPosition, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						position: 0,
@@ -176,18 +177,18 @@ describe( 'Writer', () => {
 			// <p><b foo="bar"></b>|<b foo="baz"></b></p> ->
 			// <p><b foo="bar"></b>|<b foo="baz"></b></p>
 			const description = {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						attributes: { foo: 'bar' }
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						attributes: { foo: 'baz' }
@@ -202,25 +203,25 @@ describe( 'Writer', () => {
 		it( 'should not merge when placed between similar attribute nodes with different priority', () => {
 			// <p><b foo="bar"></b>|<b foo="bar"></b></p> -> <p><b foo="bar"></b>|<b foo="bar"></b></p>
 			const description =  {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						attributes: { foo: 'bar' }
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 2,
 						attributes: { foo: 'bar' }
 					}
 				]
 			};
-			const created = create( writer,description );
+			const created = create( writer, description );
 			const newPosition = writer.mergeAttributes( created.position );
 			test( writer, newPosition, created.node, description );
 		} );
@@ -230,12 +231,12 @@ describe( 'Writer', () => {
 			// <p><b foo="bar">{foo}|{bar}</b></p>
 			// <p><b foo="bar">{foo|bar}</b></p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						attributes: { foo: 'bar' },
@@ -244,7 +245,7 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						attributes: { foo: 'bar' },
@@ -258,11 +259,11 @@ describe( 'Writer', () => {
 			const newPosition = writer.mergeAttributes( created.position );
 
 			test( writer, newPosition, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						attributes: { foo: 'bar' },

+ 31 - 30
packages/ckeditor5-engine/tests/treeview/writer/remove.js

@@ -8,7 +8,8 @@
 'use strict';
 
 import Writer from '/ckeditor5/engine/treeview/writer.js';
-import Element from '/ckeditor5/engine/treeview/element.js';
+import ContainerElement from '/ckeditor5/engine/treeview/containerelement.js';
+import AttributeElement from '/ckeditor5/engine/treeview/attributeelement.js';
 import Range from '/ckeditor5/engine/treeview/range.js';
 import Text from '/ckeditor5/engine/treeview/text.js';
 import DocumentFragment from '/ckeditor5/engine/treeview/documentfragment.js';
@@ -25,8 +26,8 @@ describe( 'Writer', () => {
 
 	describe( 'remove', () => {
 		it( 'should throw when range placed in two containers', () => {
-			const p1 = new Element( 'p' );
-			const p2 = new Element( 'p' );
+			const p1 = new ContainerElement( 'p' );
+			const p2 = new ContainerElement( 'p' );
 
 			expect( () => {
 				writer.remove( Range.createFromParentsAndOffsets( p1, 0, p2, 0 ) );
@@ -34,7 +35,7 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should return empty DocumentFragment when range is collapsed', () => {
-			const p = new Element( 'p' );
+			const p = new ContainerElement( 'p' );
 			const range = Range.createFromParentsAndOffsets( p, 0, p, 0 );
 			const fragment = writer.remove( range );
 
@@ -46,7 +47,7 @@ describe( 'Writer', () => {
 		it( 'should remove single text node', () => {
 			// <p>[{foobar}]</p> -> <p>|</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
@@ -57,7 +58,7 @@ describe( 'Writer', () => {
 
 			const removed = writer.remove( created.range );
 			test( writer, created.range.start, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 0,
 				children: []
@@ -72,7 +73,7 @@ describe( 'Writer', () => {
 		it( 'should not leave empty text nodes', () => {
 			// <p>{[foobar]}</p> -> <p>|</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', rangeStart: 0, rangeEnd: 6 }
@@ -81,7 +82,7 @@ describe( 'Writer', () => {
 
 			const removed = writer.remove( created.range );
 			test( writer, created.range.start, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 0,
 				children: []
@@ -96,7 +97,7 @@ describe( 'Writer', () => {
 		it( 'should remove part of the text node', () => {
 			// <p>{f[oob]ar}</p> -> <p>{f|ar}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', rangeStart: 1, rangeEnd: 4 }
@@ -105,7 +106,7 @@ describe( 'Writer', () => {
 
 			const removed = writer.remove( created.range );
 			test( writer, created.range.start, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'far', position: 1 }
@@ -121,12 +122,12 @@ describe( 'Writer', () => {
 		it( 'should remove parts of nodes', () => {
 			// <p>{f[oo}<b>{ba]r}</b></p> -> <p>{f}|<b>r</b></p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foo', rangeStart: 1 },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -138,13 +139,13 @@ describe( 'Writer', () => {
 
 			const removed = writer.remove( created.range );
 			test( writer, created.range.start, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				position: 1,
 				children: [
 					{ instanceOf: Text, data: 'f' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -158,9 +159,9 @@ describe( 'Writer', () => {
 			test( writer, null, removed, [
 				{ instanceOf: Text, data: 'oo' },
 				{
-					instanceOf: Element,
-					priority: 1,
+					instanceOf: AttributeElement,
 					name: 'b',
+					priority: 1,
 					children: [
 						{ instanceOf: Text, data: 'ba' }
 					]
@@ -171,13 +172,13 @@ describe( 'Writer', () => {
 		it( 'should merge after removing #1', () => {
 			// <p><b>foo</b>[{bar}]<b>bazqux</b></p> -> <p><b>foo|bazqux</b></p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 1,
 				rangeEnd: 2,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -186,7 +187,7 @@ describe( 'Writer', () => {
 					},
 					{ instanceOf: Text, data: 'bar' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -198,11 +199,11 @@ describe( 'Writer', () => {
 
 			const removed = writer.remove( created.range );
 			test( writer, created.range.start, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -221,11 +222,11 @@ describe( 'Writer', () => {
 		it( 'should merge after removing #2', () => {
 			// <p><b>fo[o</b>{bar}<b>ba]zqux</b></p> -> <p><b>fo|zqux</b></p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -234,7 +235,7 @@ describe( 'Writer', () => {
 					},
 					{ instanceOf: Text, data: 'bar' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -246,11 +247,11 @@ describe( 'Writer', () => {
 
 			const removed = writer.remove( created.range );
 			test( writer, created.range.start, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -263,18 +264,18 @@ describe( 'Writer', () => {
 			// Test removed nodes.
 			test( writer, null, removed, [
 				{
-					instanceOf: Element,
-					priority: 1,
+					instanceOf: AttributeElement,
 					name: 'b',
+					priority: 1,
 					children: [
 						{ instanceOf: Text, data: 'o' }
 					]
 				},
 				{ instanceOf: Text, data: 'bar' },
 				{
-					instanceOf: Element,
-					priority: 1,
+					instanceOf: AttributeElement,
 					name: 'b',
+					priority: 1,
 					children: [
 						{ instanceOf: Text, data: 'ba' }
 					]

+ 103 - 102
packages/ckeditor5-engine/tests/treeview/writer/unwrap.js

@@ -8,7 +8,8 @@
 'use strict';
 
 import Writer from '/ckeditor5/engine/treeview/writer.js';
-import Element from '/ckeditor5/engine/treeview/element.js';
+import ContainerElement from '/ckeditor5/engine/treeview/containerelement.js';
+import AttributeElement from '/ckeditor5/engine/treeview/attributeelement.js';
 import Position from '/ckeditor5/engine/treeview/position.js';
 import Range from '/ckeditor5/engine/treeview/range.js';
 import Text from '/ckeditor5/engine/treeview/text.js';
@@ -27,21 +28,21 @@ describe( 'Writer', () => {
 	describe( 'unwrap', () => {
 		it( 'should do nothing on collapsed ranges', () => {
 			const description = {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foo', rangeStart: 1, rangeEnd: 1 }
 				]
 			};
 			const created = create( writer, description );
-			const newRange = writer.unwrap( created.range, new Element( 'b' ), 1 );
+			const newRange = writer.unwrap( created.range, new ContainerElement( 'b' ), 1 );
 			test( writer, newRange, created.node, description );
 		} );
 
 		it( 'should do nothing on single text node', () => {
 			// <p>[{foobar}]</p>
 			const description = {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
@@ -51,21 +52,21 @@ describe( 'Writer', () => {
 			};
 
 			const created = create( writer, description );
-			const b = new Element( 'b' );
-			writer.setPriority( b, 1 );
+			const b = new ContainerElement( 'b' );
+			b.priority = 1;
 			const newRange = writer.unwrap( created.range, b );
 
 			test( writer, newRange, created.node, description );
 		} );
 
 		it( 'should throw error when range placed in two containers', () => {
-			const container1 = new Element( 'p' );
-			const container2 = new Element( 'p' );
+			const container1 = new ContainerElement( 'p' );
+			const container2 = new ContainerElement( 'p' );
 			const range = new Range(
 				new Position( container1, 0 ),
 				new Position( container2, 1 )
 			);
-			const b = new Element( 'b' );
+			const b = new ContainerElement( 'b' );
 
 			expect( () => {
 				writer.unwrap( range, b, 1 );
@@ -75,15 +76,15 @@ describe( 'Writer', () => {
 		it( 'should unwrap single node', () => {
 			// <p>[<b>{foobar}</b>]<p> -> <p>[{foobar}]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
-						priority: 1,
+						instanceOf: AttributeElement,
 						name: 'b',
+						priority: 1,
 						children: [
 							{ instanceOf: Text, data: 'foobar' }
 						]
@@ -91,12 +92,12 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const b = new Element( 'b' );
-			writer.setPriority( b, 1 );
+			const b = new ContainerElement( 'b' );
+			b.priority = 1;
 			const newRange = writer.unwrap( created.range, b );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
@@ -110,15 +111,15 @@ describe( 'Writer', () => {
 			// <p>[<b>{foobar}</b>]<p> -> <p>[<b>{foobar}</b>]</p>
 			// Unwrapped with <b> but using different priority.
 			const description =  {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
-						priority: 1,
+						instanceOf: AttributeElement,
 						name: 'b',
+						priority: 1,
 						children: [
 							{ instanceOf: Text, data: 'foobar' }
 						]
@@ -127,8 +128,8 @@ describe( 'Writer', () => {
 			};
 			const created = create( writer, description );
 
-			const b = new Element( 'b' );
-			writer.setPriority( b, 2 );
+			const b = new ContainerElement( 'b' );
+			b.priority = 2;
 			const newRange = writer.unwrap( created.range, b );
 
 			test( writer, newRange, created.node, description );
@@ -138,31 +139,31 @@ describe( 'Writer', () => {
 			// <p>[<b>{foo}</b><b>{bar}</b><b>{baz}</b>]<p> -> <p>[{foo}<b>bar</b>{baz}]</p>
 			// <b> around `bar` has different priority than others.
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 3,
 				children: [
 					{
-						instanceOf: Element,
-						priority: 2,
+						instanceOf: AttributeElement,
 						name: 'b',
+						priority: 2,
 						children: [
 							{ instanceOf: Text, data: 'foo' }
 						]
 					},
 					{
-						instanceOf: Element,
-						priority: 1,
+						instanceOf: AttributeElement,
 						name: 'b',
+						priority: 1,
 						children: [
 							{ instanceOf: Text, data: 'bar' }
 						]
 					},
 					{
-						instanceOf: Element,
-						priority: 2,
+						instanceOf: AttributeElement,
 						name: 'b',
+						priority: 2,
 						children: [
 							{ instanceOf: Text, data: 'baz' }
 						]
@@ -170,21 +171,21 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const b = new Element( 'b' );
-			writer.setPriority( b, 2 );
+			const b = new ContainerElement( 'b' );
+			b.priority = 2;
 			const newRange = writer.unwrap( created.range, b );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 3,
 				children: [
 					{ instanceOf: Text, data: 'foo' },
 					{
-						instanceOf: Element,
-						priority: 1,
+						instanceOf: AttributeElement,
 						name: 'b',
+						priority: 1,
 						children: [
 							{ instanceOf: Text, data: 'bar' }
 						]
@@ -197,13 +198,13 @@ describe( 'Writer', () => {
 		it( 'should unwrap part of the node', () => {
 			// <p>[{baz}<b>{foo]bar}</b><p> -> <p>[{bazfoo}]<b>{bar}</b></p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				children: [
 					{ instanceOf: Text, data: 'baz' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -214,20 +215,20 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const b = new Element( 'b' );
-			writer.setPriority( b, 1 );
+			const b = new ContainerElement( 'b' );
+			b.priority = 1;
 
 			const newRange = writer.unwrap( created.range, b );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{ instanceOf: Text, data: 'bazfoo' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -242,18 +243,18 @@ describe( 'Writer', () => {
 		it( 'should unwrap nested attributes', () => {
 			// <p>[<u><b>{foobar}</b></u>]</p> -> <p>[<u>{foobar}</u>]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'b',
 								priority: 1,
 								children: [
@@ -264,18 +265,18 @@ describe( 'Writer', () => {
 					}
 				]
 			} );
-			const b = new Element( 'b' );
-			writer.setPriority( b, 1 );
+			const b = new ContainerElement( 'b' );
+			b.priority = 1;
 
 			const newRange = writer.unwrap( created.range, b );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
@@ -289,14 +290,14 @@ describe( 'Writer', () => {
 		it( 'should merge unwrapped nodes #1', () => {
 			// <p>{foo}[<b>{bar}</b>]{bom}</p> -> <p>{foo[bar]bom}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 1,
 				rangeEnd: 2,
 				children: [
 					{ instanceOf: Text, data: 'foo' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -307,11 +308,11 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const b =  new Element( 'b' );
-			writer.setPriority( b, 1 );
+			const b =  new ContainerElement( 'b' );
+			b.priority = 1;
 			const newRange = writer.unwrap( created.range, b );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
@@ -327,14 +328,14 @@ describe( 'Writer', () => {
 		it( 'should merge unwrapped nodes #2', () => {
 			// <p>{foo}<u>{bar}</u>[<b><u>{bazqux}</u></b>]</p> -> <p>{foo}<u>{bar[bazqux}</u>]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 2,
 				rangeEnd: 3,
 				children: [
 					{ instanceOf: Text, data: 'foo' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
@@ -342,12 +343,12 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [
@@ -359,12 +360,12 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const b = new Element( 'b' );
-			writer.setPriority( b, 1 );
+			const b = new ContainerElement( 'b' );
+			b.priority = 1;
 			const newRange = writer.unwrap( created.range, b );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeEnd: 2,
 				children: [
@@ -373,7 +374,7 @@ describe( 'Writer', () => {
 						data: 'foo'
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
@@ -387,13 +388,13 @@ describe( 'Writer', () => {
 		it( 'should merge unwrapped nodes #3', () => {
 			// <p>{foo}<u>{bar}</u>[<b><u>{baz]qux}</u></b></p> -> <p>{foo}<u>{bar[baz}</u>]<b><u>{qux}</u></b></p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 2,
 				children: [
 					{ instanceOf: Text, data: 'foo' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
@@ -401,12 +402,12 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [
@@ -418,12 +419,12 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const b = new Element( 'b' );
-			writer.setPriority( b, 1 );
+			const b = new ContainerElement( 'b' );
+			b.priority = 1;
 			const newRange = writer.unwrap( created.range, b );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeEnd: 2,
 				children: [
@@ -432,7 +433,7 @@ describe( 'Writer', () => {
 						data: 'foo'
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
@@ -440,12 +441,12 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [
@@ -461,14 +462,14 @@ describe( 'Writer', () => {
 		it( 'should merge unwrapped nodes #4', () => {
 			// <p>{foo}<u>{bar}</u>[<b><u>{baz}</u></b>]<u>qux</u></p> -> <p>{foo}<u>{bar[baz]qux}</u></p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 2,
 				rangeEnd: 3,
 				children: [
 					{ instanceOf: Text, data: 'foo' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
@@ -476,12 +477,12 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [
@@ -491,7 +492,7 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
@@ -501,12 +502,12 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const b = new Element( 'b' );
-			writer.setPriority( b, 1 );
+			const b = new ContainerElement( 'b' );
+			b.priority = 1;
 			const newRange = writer.unwrap( created.range, b );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{
@@ -514,7 +515,7 @@ describe( 'Writer', () => {
 						data: 'foo'
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
@@ -528,18 +529,18 @@ describe( 'Writer', () => {
 		it( 'should merge unwrapped nodes #5', () => {
 			// <p>[<b><u>{foo}</u></b><b><u>{bar}</u></b><b><u>{baz}</u></b>]</p> -> <p>[<u>{foobarbaz}</u>]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 3,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [
@@ -549,12 +550,12 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [
@@ -564,12 +565,12 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'u',
 								priority: 1,
 								children: [
@@ -581,17 +582,17 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const b = new Element( 'b' );
-			writer.setPriority( b, 1 );
+			const b = new ContainerElement( 'b' );
+			b.priority = 1;
 			const newRange = writer.unwrap( created.range, b );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
@@ -605,17 +606,17 @@ describe( 'Writer', () => {
 		it( 'should unwrap mixed ranges #1', () => {
 			// <p>[<u><b>{foo}]</b></u></p> -> <p>[<u>{foo}</u>]</p
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'b',
 								priority: 1,
 								rangeEnd: 1,
@@ -627,17 +628,17 @@ describe( 'Writer', () => {
 					}
 				]
 			} );
-			const b = new Element( 'b' );
-			writer.setPriority( b, 1 );
+			const b = new ContainerElement( 'b' );
+			b.priority = 1;
 			const newRange = writer.unwrap( created.range, b );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
@@ -651,17 +652,17 @@ describe( 'Writer', () => {
 		it( 'should unwrap mixed ranges #2', () => {
 			// <p>[<u><b>{foo]}</b></u></p> -> <p>[<u>{foo}</u>]</p
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'b',
 								priority: 1,
 								children: [
@@ -672,17 +673,17 @@ describe( 'Writer', () => {
 					}
 				]
 			} );
-			const b = new Element( 'b' );
-			writer.setPriority( b, 1 );
+			const b = new ContainerElement( 'b' );
+			b.priority = 1;
 			const newRange = writer.unwrap( created.range, b );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [

+ 65 - 64
packages/ckeditor5-engine/tests/treeview/writer/wrap.js

@@ -8,7 +8,8 @@
 'use strict';
 
 import Writer from '/ckeditor5/engine/treeview/writer.js';
-import Element from '/ckeditor5/engine/treeview/element.js';
+import ContainerElement from '/ckeditor5/engine/treeview/containerelement.js';
+import AttributeElement from '/ckeditor5/engine/treeview/attributeelement.js';
 import Position from '/ckeditor5/engine/treeview/position.js';
 import Range from '/ckeditor5/engine/treeview/range.js';
 import Text from '/ckeditor5/engine/treeview/text.js';
@@ -27,14 +28,14 @@ describe( 'Writer', () => {
 	describe( 'wrap', () => {
 		it( 'should do nothing on collapsed ranges', () => {
 			const description = {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foo', rangeStart: 1, rangeEnd: 1 }
 				]
 			};
 			const created = create( writer, description );
-			const newRange = writer.wrap( created.range, new Element( 'b' ), 1 );
+			const newRange = writer.wrap( created.range, new AttributeElement( 'b' ), 1 );
 			test( writer, newRange, created.node, description );
 		} );
 
@@ -43,7 +44,7 @@ describe( 'Writer', () => {
 			// wrap <b>
 			// <p>[<b>{foobar}<b>]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
@@ -52,17 +53,17 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const b = new Element( 'b' );
+			const b = new AttributeElement( 'b' );
 			const newRange = writer.wrap( created.range, b, 1 );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -74,13 +75,13 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should throw error when range placed in two containers', () => {
-			const container1 = new Element( 'p' );
-			const container2 = new Element( 'p' );
+			const container1 = new ContainerElement( 'p' );
+			const container2 = new ContainerElement( 'p' );
 			const range = new Range(
 				new Position( container1, 0 ),
 				new Position( container2, 1 )
 			);
-			const b = new Element( 'b' );
+			const b = new AttributeElement( 'b' );
 
 			expect( () => {
 				writer.wrap( range, b, 1 );
@@ -92,7 +93,7 @@ describe( 'Writer', () => {
 			// wrap with <b>
 			// <p>[<b>{foo}</b>]{bar}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				children: [
@@ -100,17 +101,17 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const b = new Element( 'b' );
+			const b = new AttributeElement( 'b' );
 			const newRange = writer.wrap( created.range, b, 2 );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 2,
 						children: [
@@ -127,24 +128,24 @@ describe( 'Writer', () => {
 			// wrap with <b>
 			// <p>[<b>{foo}</b>]{bar}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', rangeStart: 0, rangeEnd: 3 }
 				]
 			} );
 
-			const b = new Element( 'b' );
+			const b = new AttributeElement( 'b' );
 			const newRange = writer.wrap( created.range, b, 2 );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 2,
 						children: [
@@ -161,25 +162,25 @@ describe( 'Writer', () => {
 			// wrap with <b>
 			// <p>{foo}[<b>{bar}</b>]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				children: [
 					{ instanceOf: Text, data: 'foobar', rangeStart: 3, rangeEnd: 6 }
 				]
 			} );
 
-			const b = new Element( 'b' );
+			const b = new AttributeElement( 'b' );
 			const newRange = writer.wrap( created.range, b, 2 );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 1,
 				rangeEnd: 2,
 				children: [
 					{ instanceOf: Text, data: 'foo' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 2,
 						children: [
@@ -195,14 +196,14 @@ describe( 'Writer', () => {
 			// wrap with <b>
 			// <div>[<b>{foobar}</b><p>{baz}</p>]</div>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'div',
 				rangeStart: 0,
 				rangeEnd: 2,
 				children: [
 					{ instanceOf: Text, data: 'foobar' },
 					{
-						instanceOf: Element,
+						instanceOf: ContainerElement,
 						name: 'p',
 						children: [
 							{ instanceOf: Text, data: 'baz' }
@@ -211,15 +212,15 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const newRange = writer.wrap( created.range, new Element( 'b' ), 1 );
+			const newRange = writer.wrap( created.range, new AttributeElement( 'b' ), 1 );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'div',
 				rangeStart: 0,
 				rangeEnd: 2,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -227,7 +228,7 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: ContainerElement,
 						name: 'p',
 						children: [
 							{ instanceOf: Text, data: 'baz' }
@@ -242,13 +243,13 @@ describe( 'Writer', () => {
 			// wrap with <b> that has higher priority than <u>
 			// <p>[<u><b>{foobar}</b></u>]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
@@ -258,22 +259,22 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const b = new Element( 'b' );
+			const b = new AttributeElement( 'b' );
 			const newRange = writer.wrap( created.range, b, 2 );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'u',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'b',
 								priority: 2,
 								children: [
@@ -291,13 +292,13 @@ describe( 'Writer', () => {
 			// wrap with <b>
 			// <p>[<b>{foobarbaz}</b>]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 3,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -306,7 +307,7 @@ describe( 'Writer', () => {
 					},
 					{ instanceOf: Text, data: 'bar' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -316,17 +317,17 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const b = new Element( 'b' );
+			const b = new AttributeElement( 'b' );
 			const newRange = writer.wrap( created.range, b, 1 );
 
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -342,12 +343,12 @@ describe( 'Writer', () => {
 			// wrap with <b>
 			// <p><b>{foo[bar}</b>]{baz}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -358,14 +359,14 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const newRange = writer.wrap( created.range, new Element( 'b' ), 1 );
+			const newRange = writer.wrap( created.range, new AttributeElement( 'b' ), 1 );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -382,13 +383,13 @@ describe( 'Writer', () => {
 			// wrap with <b>
 			// <p><b>{foobar[baz}</b>]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 1,
 				rangeEnd: 2,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -399,14 +400,14 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const newRange = writer.wrap( created.range, new Element( 'b' ), 1 );
+			const newRange = writer.wrap( created.range, new AttributeElement( 'b' ), 1 );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
@@ -422,14 +423,14 @@ describe( 'Writer', () => {
 			// wrap with <b>
 			// <p>[<b>{foo}<i>{bar}</i></b>]{baz}</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 2,
 				children: [
 					{ instanceOf: Text, data: 'foo' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'i',
 						priority: 1,
 						children: [
@@ -440,21 +441,21 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const newRange = writer.wrap( created.range, new Element( 'b' ), 1 );
+			const newRange = writer.wrap( created.range, new AttributeElement( 'b' ), 1 );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 1,
 						children: [
 							{ instanceOf: Text, data: 'foo' },
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'i',
 								priority: 1,
 								children: [
@@ -473,14 +474,14 @@ describe( 'Writer', () => {
 			// wrap with <b>, that has higher priority than <i>
 			// <p>[<b>{foo}</b><i><b>{bar}</b></i><b>{baz}</b>]</p>
 			const created = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 3,
 				children: [
 					{ instanceOf: Text, data: 'foo' },
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'i',
 						priority: 1,
 						children: [
@@ -491,15 +492,15 @@ describe( 'Writer', () => {
 				]
 			} );
 
-			const newRange = writer.wrap( created.range, new Element( 'b' ), 2 );
+			const newRange = writer.wrap( created.range, new AttributeElement( 'b' ), 2 );
 			test( writer, newRange, created.node, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 3,
 				children: [
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 2,
 						children: [
@@ -507,12 +508,12 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'i',
 						priority: 1,
 						children: [
 							{
-								instanceOf: Element,
+								instanceOf: AttributeElement,
 								name: 'b',
 								priority: 2,
 								children: [
@@ -522,7 +523,7 @@ describe( 'Writer', () => {
 						]
 					},
 					{
-						instanceOf: Element,
+						instanceOf: AttributeElement,
 						name: 'b',
 						priority: 2,
 						children: [

+ 9 - 50
packages/ckeditor5-engine/tests/treeview/writer/writer.js

@@ -8,7 +8,8 @@
 'use strict';
 
 import Writer from '/ckeditor5/engine/treeview/writer.js';
-import Element from '/ckeditor5/engine/treeview/element.js';
+import ContainerElement from '/ckeditor5/engine/treeview/containerelement.js';
+import AttributeElement from '/ckeditor5/engine/treeview/attributeelement.js';
 import Text from '/ckeditor5/engine/treeview/text.js';
 import Position from '/ckeditor5/engine/treeview/position.js';
 import utils from '/tests/engine/treeview/writer/_utils/utils.js';
@@ -21,55 +22,13 @@ describe( 'Writer', () => {
 		writer = new Writer();
 	} );
 
-	describe( 'isContainer', () => {
-		it( 'should return true for container elements', () => {
-			const containerElement = new Element( 'p' );
-			const attributeElement = new Element( 'b' );
-
-			writer._priorities.set( attributeElement, 1 );
-
-			expect( writer.isContainer( containerElement ) ).to.be.true;
-			expect( writer.isContainer( attributeElement ) ).to.be.false;
-		} );
-	} );
-
-	describe( 'isAttribute', () => {
-		it( 'should return true for attribute elements', () => {
-			const containerElement = new Element( 'p' );
-			const attributeElement = new Element( 'b' );
-
-			writer._priorities.set( attributeElement, 1 );
-
-			expect( writer.isAttribute( containerElement ) ).to.be.false;
-			expect( writer.isAttribute( attributeElement ) ).to.be.true;
-		} );
-	} );
-
-	describe( 'setPriority', () => {
-		it( 'sets node priority', () => {
-			const nodeMock = {};
-			writer.setPriority( nodeMock, 10 );
-
-			expect( writer._priorities.get( nodeMock ) ).to.equal( 10 );
-		} );
-	} );
-
-	describe( 'getPriority', () => {
-		it( 'gets node priority', () => {
-			const nodeMock = {};
-			writer._priorities.set( nodeMock, 12 );
-
-			expect( writer.getPriority( nodeMock ) ).to.equal( 12 );
-		} );
-	} );
-
 	describe( 'getParentContainer', () => {
 		it( 'should return parent container of the node', () => {
 			const text = new Text( 'foobar' );
-			const b = new Element( 'b', null, [ text ] );
-			const parent = new Element( 'p', null, [ b ] );
+			const b = new AttributeElement( 'b', null, [ text ] );
+			const parent = new ContainerElement( 'p', null, [ b ] );
 
-			writer.setPriority( b, 1 );
+			b.priority = 1;
 			const container = writer.getParentContainer( new Position( text, 0 ) );
 
 			expect( container ).to.equal( parent );
@@ -77,9 +36,9 @@ describe( 'Writer', () => {
 
 		it( 'should return undefined if no parent container', () => {
 			const text = new Text( 'foobar' );
-			const b = new Element( 'b', null, [ text ] );
+			const b = new AttributeElement( 'b', null, [ text ] );
 
-			writer.setPriority( b, 1 );
+			b.priority = 1;
 			const container = writer.getParentContainer( new Position( text, 0 ) );
 
 			expect( container ).to.be.undefined;
@@ -92,7 +51,7 @@ describe( 'Writer', () => {
 			// Move to <div>|</div>
 			// <div>[{foobar}]</div>
 			const source = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'p',
 				rangeStart: 0,
 				rangeEnd: 1,
@@ -101,7 +60,7 @@ describe( 'Writer', () => {
 				]
 			} );
 			const target = create( writer, {
-				instanceOf: Element,
+				instanceOf: ContainerElement,
 				name: 'div',
 				position: 0
 			} );