8
0
Pārlūkot izejas kodu

ViewConsumable methods API change, updated tests.

Szymon Kupś 9 gadi atpakaļ
vecāks
revīzija
14f6db49ff

+ 137 - 215
packages/ckeditor5-engine/src/treecontroller/viewconsumable.js

@@ -5,9 +5,7 @@
 
 'use strict';
 
-import isPlainObject from '../../utils/lib/lodash/isPlainObject.js';
 import isArray from '../../utils/lib/lodash/isArray.js';
-import ViewElement from '../treeview/element.js';
 import CKEditorError from '../../utils/ckeditorerror.js';
 
 /**
@@ -23,7 +21,7 @@ class ViewElementConsumables {
 	 * Creates ViewElementConsumables instance.
 	 */
 	constructor()  {
-		this._canConsumeElement = null;
+		this._canConsumeName = null;
 
 		this._consumables = {
 			attribute: new Map(),
@@ -34,31 +32,30 @@ class ViewElementConsumables {
 
 	/**
 	 * Adds consumable parts of the {@link engine.treeView.Element view Element}.
-	 * Element itself can be marked to be consumed (when element is consumed its attributes, classes and styles still
-	 * could be consumed):
+	 * Element's name itself can be marked to be consumed (when element's name is consumed its attributes, classes and
+	 * styles still could be consumed):
 	 *
-	 *		consumables.add( true );
+	 *		consumables.add( { name: true } );
 	 *
 	 * Attributes classes and styles:
 	 *
-	 *		consumables.add( false, { attribute: 'title', class: 'foo', style: 'color' } );
-	 *		consumables.add( false, { attribute: [ 'title', 'name' ], class: [ 'foo', 'bar' ] );
+	 *		consumables.add( { attribute: 'title', class: 'foo', style: 'color' } );
+	 *		consumables.add( { attribute: [ 'title', 'name' ], class: [ 'foo', 'bar' ] );
 	 *
-	 * @param {Boolean} elementOnly Only element itself should be marked for consumption. If set to `true` - `consumables`
-	 * parameter is ignored.
-	 * @param {Object} [consumables] Object describing which parts of the element can be consumed.
+	 * @param {Object} consumables Object describing which parts of the element can be consumed.
+	 * @param {Boolean} consumables.name If set to `true` element's name will be added as consumable.
 	 * @param {String|Array} consumables.attribute Attribute name or array of attribute names to add as consumable.
 	 * @param {String|Array} consumables.class Class name or array of class names to add as consumable.
 	 * @param {String|Array} consumables.style Style name or array of style names to add as consumable.
 	 */
-	add( elementOnly, consumables ) {
-		if ( elementOnly ) {
-			this._canConsumeElement = true;
-		} else {
-			for ( let type in consumables ) {
-				if ( type in this._consumables ) {
-					this._add( type, consumables[ type ] );
-				}
+	add( consumables ) {
+		if ( consumables.name ) {
+			this._canConsumeName = true;
+		}
+
+		for ( let type in this._consumables ) {
+			if ( type in consumables ) {
+				this._add( type, consumables[ type ] );
 			}
 		}
 	}
@@ -68,32 +65,32 @@ class ViewElementConsumables {
 	 * items can be consumed, `null` when even one of the items were never marked for consumption and `false` when even
 	 * one of the items were already consumed.
 	 *
-	 * Element itself can be tested:
+	 * Element's name can be tested:
 	 *
-	 *		consumables.test( true );
+	 *		consumables.test( { name: true } );
 	 *
 	 * Attributes classes and styles:
 	 *
-	 *		consumables.test( false, { attribute: 'title', class: 'foo', style: 'color' } );
-	 *		consumables.test( false, { attribute: [ 'title', 'name' ], class: [ 'foo', 'bar' ] );
+	 *		consumables.test( { attribute: 'title', class: 'foo', style: 'color' } );
+	 *		consumables.test( { attribute: [ 'title', 'name' ], class: [ 'foo', 'bar' ] );
 	 *
-	 * @param {Boolean} elementOnly Only element itself should be tested. If set to `true` - `consumables`
-	 * parameter is ignored.
-	 * @param {Object} [consumables] Object describing which parts of the element should be tested.
+	 * @param {Object} consumables]Object describing which parts of the element should be tested.
+	 * @param {Boolean} consumables.name If set to `true` element's name will be tested.
 	 * @param {String|Array} consumables.attribute Attribute name or array of attribute names to test.
 	 * @param {String|Array} consumables.class Class name or array of class names to test.
 	 * @param {String|Array} consumables.style Style name or array of style names to test.
 	 * @returns {Boolean|null} Returns `true` when all tested items can be consumed, `null` when even one of the items
 	 * were never marked for consumption and `false` when even one of the items were already consumed.
 	 */
-	test( elementOnly, consumables ) {
-		if ( elementOnly ) {
-			return this._canConsumeElement;
+	test( consumables ) {
+		// Check if name can be consumed
+		if ( consumables.name && !this._canConsumeName ) {
+			return this._canConsumeName;
 		}
 
-		for ( let type in consumables ) {
-			if ( type in this._consumables ) {
-				const value =  this._test( type, consumables[ type ] );
+		for ( let type in this._consumables ) {
+			if ( type in consumables ) {
+				const value = this._test( type, consumables[ type ] );
 
 				if ( value !== true ) {
 					return value;
@@ -101,37 +98,35 @@ class ViewElementConsumables {
 			}
 		}
 
+		// Return true only if all can be consumed.
 		return true;
 	}
 
 	/**
 	 * Consumes parts of {@link engine.treeView.Element view Element}. This function does not check if consumable item
 	 * is already consumed - it consumes all consumable items provided.
-	 * Element itself can be consumed:
+	 * Element's name can be consumed:
 	 *
-	 *		consumables.consume( true );
+	 *		consumables.consume( { name: true } );
 	 *
 	 * Attributes classes and styles:
 	 *
-	 *		consumables.consume( false, { attribute: 'title', class: 'foo', style: 'color' } );
-	 *		consumables.consume( false, { attribute: [ 'title', 'name' ], class: [ 'foo', 'bar' ] );
+	 *		consumables.consume( { attribute: 'title', class: 'foo', style: 'color' } );
+	 *		consumables.consume( { attribute: [ 'title', 'name' ], class: [ 'foo', 'bar' ] );
 	 *
-	 * @param {Boolean} elementOnly Only element itself should be consumed. If set to `true` - `consumables`
-	 * parameter is ignored.
-	 * @param {Object} [consumables] Object describing which parts of the element should be consumed.
+	 * @param {Object} consumables Object describing which parts of the element should be consumed.
+	 * @param {Boolean} consumables.name If set to `true` element's name will be consumed.
 	 * @param {String|Array} consumables.attribute Attribute name or array of attribute names to consume.
 	 * @param {String|Array} consumables.class Class name or array of class names to consume.
 	 * @param {String|Array} consumables.style Style name or array of style names to consume.
 	 */
-	consume( elementOnly, consumables ) {
-		if ( elementOnly ) {
-			this._canConsumeElement = false;
-
-			return;
+	consume( consumables ) {
+		if ( consumables.name ) {
+			this._canConsumeName = false;
 		}
 
-		for ( let type in consumables ) {
-			if ( type in this._consumables ) {
+		for ( let type in this._consumables ) {
+			if ( type in consumables ) {
 				this._consume( type, consumables[ type ] );
 			}
 		}
@@ -139,33 +134,28 @@ class ViewElementConsumables {
 
 	/**
 	 * Revert already consumed parts of {@link engine.treeView.Element view Element}, so they can be consumed once again.
-	 * Element itself can be reverted:
+	 * Element's name can be reverted:
 	 *
-	 *		consumables.revert( true );
+	 *		consumables.revert( { name: true } );
 	 *
 	 * Attributes classes and styles:
 	 *
-	 *		consumables.revert( false, { attribute: 'title', class: 'foo', style: 'color' } );
-	 *		consumables.revert( false, { attribute: [ 'title', 'name' ], class: [ 'foo', 'bar' ] );
+	 *		consumables.revert( { attribute: 'title', class: 'foo', style: 'color' } );
+	 *		consumables.revert( { attribute: [ 'title', 'name' ], class: [ 'foo', 'bar' ] );
 	 *
-	 * @param {Boolean} elementOnly Only element itself should be reverted. If set to `true` - `consumables`
-	 * parameter is ignored.
-	 * @param {Object} [consumables] Object describing which parts of the element should be reverted.
+	 * @param {Object} consumables Object describing which parts of the element should be reverted.
+	 * @param {Boolean} consumables.name If set to `true` element's name will be reverted.
 	 * @param {String|Array} consumables.attribute Attribute name or array of attribute names to revert.
 	 * @param {String|Array} consumables.class Class name or array of class names to revert.
 	 * @param {String|Array} consumables.style Style name or array of style names to revert.
 	 */
-	revert( elementOnly, consumables ) {
-		if ( elementOnly ) {
-			if ( this._canConsumeElement === false ) {
-				this._canConsumeElement = true;
-			}
-
-			return;
+	revert( consumables ) {
+		if ( consumables.name ) {
+			this._canConsumeName = true;
 		}
 
-		for ( let type in consumables ) {
-			if ( type in this._consumables ) {
+		for ( let type in this._consumables ) {
+			if ( type in consumables ) {
 				this._revert( type, consumables[ type ] );
 			}
 		}
@@ -175,7 +165,7 @@ class ViewElementConsumables {
 	 * Helper method that adds consumables from one type: attribute, class or style.
 	 *
 	 * @private
-	 * @param {String} type Type of the consumable item: `attribute`, `class` or , `style`.
+	 * @param {String} type Type of the consumable item: `attribute`, `class` or `style`.
 	 * @param {String|Array} item Consumable item or array of items.
 	 */
 	_add( type, item ) {
@@ -200,9 +190,9 @@ class ViewElementConsumables {
 	 * Helper method that tests consumables from one type: attribute, class or style.
 	 *
 	 * @private
-	 * @param {String} type Type of the consumable item: `attribute`, `class` or , `style`.
+	 * @param {String} type Type of the consumable item: `attribute`, `class` or `style`.
 	 * @param {String|Array} item Consumable item or array of items.
-	 * @returns {Boolean|null} Returns `true` if all items con be consumed, `null` when one of the items cannot be
+	 * @returns {Boolean|null} Returns `true` if all items can be consumed, `null` when one of the items cannot be
 	 * consumed and `false` when one of the items is already consumed.
 	 */
 	_test( type, item ) {
@@ -238,7 +228,7 @@ class ViewElementConsumables {
 	 * Helper method that consumes items from one type: attribute, class or style.
 	 *
 	 * @private
-	 * @param {String} type Type of the consumable item: `attribute`, `class` or , `style`.
+	 * @param {String} type Type of the consumable item: `attribute`, `class` or `style`.
 	 * @param {String|Array} item Consumable item or array of items.
 	 */
 	_consume( type, item ) {
@@ -281,17 +271,17 @@ class ViewElementConsumables {
 
 /**
  * Class used for handling consumption of {@link engine.treeView.Element view Elements}.
- * Element and its parts (attributes, classes and styles) can be consumed separately. Consuming an element does not
- * consume its attributes, classes and styles.
- * To add element or its parts use {@link engine.treeController.ViewConsumable#add add method}.
- * To test if element or its parts can be consumed use {@link engine.treeController.ViewConsumable#test test method}.
- * To consume element or its parts use {@link engine.treeController.ViewConsumable#consume consume method}.
- * To revert already consumed element or its parts use {@link engine.treeController.ViewConsumable#revert revert method}.
+ * Element's name and its parts (attributes, classes and styles) can be consumed separately. Consuming an element's name
+ * does not consume its attributes, classes and styles.
+ * To add items for consumption use {@link engine.treeController.ViewConsumable#add add method}.
+ * To test items use {@link engine.treeController.ViewConsumable#test test method}.
+ * To consume items use {@link engine.treeController.ViewConsumable#consume consume method}.
+ * To revert already consumed items use {@link engine.treeController.ViewConsumable#revert revert method}.
  *
- *		viewConsumable.add( element ); // Adds element as ready to be consumed.
- *		viewConsumable.test( element ); // Tests if element can be consumed.
- *		viewConsumable.consume( element ); // Consume element.
- *		vievConsumable.revert( element ); // Revert already consumed element.
+ *		viewConsumable.add( element, { name: true } ); // Adds element's name as ready to be consumed.
+ *		viewConsumable.test( element, { name: true }  ); // Tests if element's name can be consumed.
+ *		viewConsumable.consume( element, { name: true }  ); // Consume element's name.
+ *		viewConsumable.revert( element, { name: true }  ); // Revert already consumed element's name.
  *
  * @memberOf engine.treeController
  */
@@ -305,7 +295,7 @@ export default class ViewConsumable {
 		* Map of consumable elements.
 		*
 		* @protected
-		* @member {Map} core.treeController.ViewConsumable#_consumable
+		* @member {Map.<engine.treeController.ViewElementConsumables>} engine.treeController.ViewConsumable#_consumables
 		*/
 		this._consumables = new Map();
 	}
@@ -313,45 +303,37 @@ export default class ViewConsumable {
 	/**
 	 * Adds {@link engine.treeView.Element view Element} and its parts as ready to be consumed.
 	 *
-	 *		viewConsumable.add( { element: p } ); // Adds element.
-	 *		viewConsumable.add( p ); // Shortcut for adding element.
-	 *		viewConsumable.add( { element: p, attribute: 'name' } ); // Adds attribute but not element itself.
-	 *		viewConsumable.add( { element: p, class: 'foobar' } ); // Adds class but not element itself.
-	 *		viewConsumable.add( { element: p, style: 'color' } ); // Adds style but not element itself.
-	 *		viewConsumable.add( { element: p, attribute: 'name', style: 'color' } ); // Adds attribute and style.
-	 *		viewConsumable.add( p1, { element: p2, class: 'foobar' } ); // Multiple objects can be provided.
-	 *		viewConsumable.consume( { element: p, class: [ 'baz', 'bar' ] } ); // Multiple names can be provided.
-	 *
-	 * Throws {@link utils.CKEditorError CKEditorError} `viewconsumable-element-missing` when no
-	 * {@link engine.treeView.Element view Element} is provided.
+	 *		viewConsumable.add( p, { name: true } ); // Adds element's name to consume.
+	 *		viewConsumable.add( p, { attribute: 'name' } ); // Adds element's attribute.
+	 *		viewConsumable.add( p, { class: 'foobar' } ); // Adds element's class.
+	 *		viewConsumable.add( p, { style: 'color' } ); // Adds element's style
+	 *		viewConsumable.add( p, { attribute: 'name', style: 'color' } ); // Adds attribute and style.
+	 *		viewConsumable.consume( p, { class: [ 'baz', 'bar' ] } ); // Multiple consumables can be provided.
 	 *
 	 * Throws {@link utils.CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`
 	 * attribute is provided - it should be handled separately by providing actual style/class.
 	 *
-	 *		viewConsumable.add( { element: p, attribute: 'style' } ); // This call will throw an exception.
-	 *		viewConsumable.add( { element: p, style: 'color' } ); // This is properly handled style.
+	 *		viewConsumable.add( p, { attribute: 'style' } ); // This call will throw an exception.
+	 *		viewConsumable.add( p, { style: 'color' } ); // This is properly handled style.
 	 *
-	 * @param {...Object} consumables
-	 * @param {engine.treeView.Element} consumables.element
+	 * @param {engine.treeView.Element} element
+	 * @param {Object} consumables
+	 * @param {Boolean} consumables.name If set to true element's name will be included.
 	 * @param {String|Array} consumables.attribute Attribute name or array of attribute names.
 	 * @param {String|Array} consumables.class Class name or array of class names.
 	 * @param {String|Array} consumables.style Style name or array of style names.
 	 */
-	add( ...consumables ) {
-		for ( let item of consumables ) {
-			const { element, elementOnly } = getElement( item );
-			let elementConsumables;
-
-			// Create entry in consumables map for provided element if one is not already present.
-			if ( !this._consumables.has( element ) ) {
-				elementConsumables = new ViewElementConsumables();
-				this._consumables.set( element, elementConsumables );
-			} else {
-				elementConsumables = this._consumables.get( element );
-			}
+	add( element, consumables ) {
+		let elementConsumables;
 
-			elementConsumables.add( elementOnly, item );
+		if ( !this._consumables.has( element ) ) {
+			elementConsumables = new ViewElementConsumables();
+			this._consumables.set( element, elementConsumables );
+		} else {
+			elementConsumables = this._consumables.get( element );
 		}
+
+		elementConsumables.add( consumables );
 	}
 
 	/**
@@ -359,164 +341,104 @@ export default class ViewConsumable {
 	 * It returns `true` when all items included in method's call can be consumed. Returns `false` when
 	 * first already consumed item is found and `null` when first non-consumable item is found.
 	 *
-	 *		viewConsumable.test( { element: p } ); // Tests element.
-	 *		viewConsumable.test( p ); // Shortcut for testing element.
-	 *		viewConsumable.test( { element: p, attribute: 'name' } ); // Tests attribute but not element itself.
-	 *		viewConsumable.test( { element: p, class: 'foobar' } ); // Tests class but not element itself.
-	 *		viewConsumable.test( { element: p, style: 'color' } ); // Tests style but not element itself.
-	 *		viewConsumable.test( { element: p, attribute: 'name', style: 'color' } ); // Tests attribute and style.
-	 *		viewConsumable.test( p1, { element: p2, class: 'foobar' } ); // Multiple objects can be tested.
-	 *		viewConsumable.consume( { element: p, class: [ 'baz', 'bar' ] } ); // Multiple names can be tested.
-	 *
-	 * Throws {@link utils.CKEditorError CKEditorError} `viewconsumable-element-missing` when no
-	 * {@link engine.treeView.Element view Element} is provided.
+	 *		viewConsumable.test( p, { name: true } ); // Tests element's name.
+	 *		viewConsumable.test( p, { attribute: 'name' } ); // Tests attribute.
+	 *		viewConsumable.test( p, { class: 'foobar' } ); // Tests class.
+	 *		viewConsumable.test( p, { style: 'color' } ); // Tests style.
+	 *		viewConsumable.test( p, { attribute: 'name', style: 'color' } ); // Tests attribute and style.
+	 *		viewConsumable.consume( p, { class: [ 'baz', 'bar' ] } ); // Multiple consumables can be tested.
 	 *
 	 * Throws {@link utils.CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`
 	 * attribute is provided - it should be handled separately by providing actual style/class.
 	 *
-	 *		viewConsumable.test( { element: p, attribute: 'style' } ); // This call will throw an exception.
-	 *		viewConsumable.test( { element: p, style: 'color' } ); // This is properly handled style.
+	 *		viewConsumable.test( p, { attribute: 'style' } ); // This call will throw an exception.
+	 *		viewConsumable.test( p, { style: 'color' } ); // This is properly handled style.
 	 *
-	 * @param {...Object} consumables
-	 * @param {engine.treeView.Element} consumables.element
+	 * @param {engine.treeView.Element} element
+	 * @param {Object} consumables
+	 * @param {Boolean} consumables.name If set to true element's name will be included.
 	 * @param {String|Array} consumables.attribute Attribute name or array of attribute names.
 	 * @param {String|Array} consumables.class Class name or array of class names.
 	 * @param {String|Array} consumables.style Style name or array of style names.
 	 * @returns {Boolean|null} Returns `true` when all items included in method's call can be consumed. Returns `false`
 	 * when first already consumed item is found and `null` when first non-consumable item is found.
 	 */
-	test( ...consumables ) {
-		for ( let item of consumables ) {
-			let result;
-			const { element, elementOnly } = getElement( item );
-
-			// Return null if there is no information about provided element.
-			if ( !this._consumables.has( element ) ) {
-				result = null;
-			} else {
-				const elementConsumables = this._consumables.get( element );
-				result =  elementConsumables.test( elementOnly, item );
-			}
+	test( element, consumables ) {
+		const elementConsumables = this._consumables.get( element );
 
-			if ( !result ) {
-				return result;
-			}
+		if ( elementConsumables === undefined ) {
+			return null;
 		}
 
-		return true;
+		return elementConsumables.test( consumables );
 	}
 
 	/**
 	 * Consumes provided {@link engine.treeView.Element view Element} and its parts.
 	 * It returns `true` when all items included in method's call can be consumed, otherwise returns `false`.
 	 *
-	 *		viewConsumable.consume( { element: p } ); // Consumes element.
-	 *		viewConsumable.consume( p ); // Shortcut for consuming element.
-	 *		viewConsumable.consume( { element: p, attribute: 'name' } ); // Consumes attribute but not element itself.
-	 *		viewConsumable.consume( { element: p, class: 'foobar' } ); // Consumes class but not element itself.
-	 *		viewConsumable.consume( { element: p, style: 'color' } ); // Consumes style but not element itself.
-	 *		viewConsumable.consume( { element: p, attribute: 'name', style: 'color' } ); // Consumes attribute and style.
-	 *		viewConsumable.consume( p1, { element: p2, class: 'foobar' } ); // Multiple objects can be consumed.
-	 *		viewConsumable.consume( { element: p, class: [ 'baz', 'bar' ] } ); // Multiple names can be consumed.
-	 *
-	 *
-	 * Throws {@link utils.CKEditorError CKEditorError} `viewconsumable-element-missing` when no
-	 * {@link engine.treeView.Element view Element} is provided.
+	 *		viewConsumable.consume( p, { name: true } ); // Consumes element's name.
+	 *		viewConsumable.consume( p, { attribute: 'name' } ); // Consumes element's attribute.
+	 *		viewConsumable.consume( p, { class: 'foobar' } ); // Consumes element's class.
+	 *		viewConsumable.consume( p, { style: 'color' } ); // Consumes element's style.
+	 *		viewConsumable.consume( p, { attribute: 'name', style: 'color' } ); // Consumes attribute and style.
+	 *		viewConsumable.consume( p, { class: [ 'baz', 'bar' ] } ); // Multiple consumables can be consumed.
 	 *
 	 * Throws {@link utils.CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`
 	 * attribute is provided - it should be handled separately by providing actual style/class.
 	 *
-	 *		viewConsumable.consume( { element: p, attribute: 'style' } ); // This call will throw an exception.
-	 *		viewConsumable.consume( { element: p, style: 'color' } ); // This is properly handled style.
+	 *		viewConsumable.consume( p, { attribute: 'style' } ); // This call will throw an exception.
+	 *		viewConsumable.consume( p, { style: 'color' } ); // This is properly handled style.
 	 *
-	 * @param {...Object} consumables
-	 * @param {engine.treeView.Element} consumables.element
+	 * @param {engine.treeView.Element} element
+	 * @param {Object} consumables
+	 * @param {Boolean} consumables.name If set to true element's name will be included.
 	 * @param {String|Array} consumables.attribute Attribute name or array of attribute names.
 	 * @param {String|Array} consumables.class Class name or array of class names.
 	 * @param {String|Array} consumables.style Style name or array of style names.
 	 * @returns {Boolean|null} Returns `true` when all items included in method's call can be consumed,
 	 * otherwise returns `false`.
 	 */
-	consume( ...description ) {
-		// Consume only if all provided descriptions can be consumed.
-		if ( !this.test( ...description ) ) {
-			return false;
-		}
+	consume( element, consumables ) {
+		if ( this.test( element, consumables ) ) {
+			this._consumables.get( element ).consume( consumables );
 
-		for ( let item of description ) {
-			const { element, elementOnly } = getElement( item );
-			const elementConsumables = this._consumables.get( element );
-
-			elementConsumables.consume( elementOnly, item );
+			return true;
 		}
 
-		return true;
+		return false;
 	}
 
 	/**
 	 * Reverts provided {@link engine.treeView.Element view Element} and its parts so they can be consumed once again.
-	 * Method does not revert items that were never previously added for consumption.
+	 * Method does not revert items that were never previously added for consumption, even if they are included in
+	 * consumables object.
 	 *
-	 *		viewConsumable.revert( { element: p } ); // Reverts element.
-	 *		viewConsumable.revert( p ); // Shortcut for reverting element.
-	 *		viewConsumable.revert( { element: p, attribute: 'name' } ); // Reverts attribute but not element itself.
-	 *		viewConsumable.revert( { element: p, class: 'foobar' } ); // Reverts class but not element itself.
-	 *		viewConsumable.revert( { element: p, style: 'color' } ); // Reverts style but not element itself.
-	 *		viewConsumable.revert( { element: p, attribute: 'name', style: 'color' } ); // Reverts attribute and style.
-	 *		viewConsumable.revert( p1, { element: p2, class: 'foobar' } ); // Multiple objects can be reverted.
-	 *		viewConsumable.revert( { element: p, class: [ 'baz', 'bar' ] } ); // Multiple names can be reverted.
-	 *
-	 *
-	 * Throws {@link utils.CKEditorError CKEditorError} `viewconsumable-element-missing` when no
-	 * {@link engine.treeView.Element view Element} is provided.
+	 *		viewConsumable.revert( p, { name: true } ); // Reverts element's name.
+	 *		viewConsumable.revert( p, { attribute: 'name' } ); // Reverts element's attribute.
+	 *		viewConsumable.revert( p, { class: 'foobar' } ); // Reverts element's class.
+	 *		viewConsumable.revert( p, { style: 'color' } ); // Reverts element's style.
+	 *		viewConsumable.revert( p, { attribute: 'name', style: 'color' } ); // Reverts attribute and style.
+	 *		viewConsumable.revert( p, { class: [ 'baz', 'bar' ] } ); // Multiple names can be reverted.
 	 *
 	 * Throws {@link utils.CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`
 	 * attribute is provided - it should be handled separately by providing actual style/class.
 	 *
-	 *		viewConsumable.revert( { element: p, attribute: 'style' } ); // This call will throw an exception.
-	 *		viewConsumable.revert( { element: p, style: 'color' } ); // This is properly handled style.
+	 *		viewConsumable.revert( p, { attribute: 'style' } ); // This call will throw an exception.
+	 *		viewConsumable.revert( p, { style: 'color' } ); // This is properly handled style.
 	 *
-	 * @param {...Object} consumables
-	 * @param {engine.treeView.Element} consumables.element
+	 * @param {engine.treeView.Element} element
+	 * @param {Object} consumables
+	 * @param {Boolean} consumables.name If set to true element's name will be included.
 	 * @param {String|Array} consumables.attribute Attribute name or array of attribute names.
 	 * @param {String|Array} consumables.class Class name or array of class names.
 	 * @param {String|Array} consumables.style Style name or array of style names.
 	 */
-	revert( ...consumables ) {
-		for ( let item of consumables ) {
-			const { element, elementOnly } = getElement( item );
-
-			// Return null if there is no information about provided element.
-			if ( this._consumables.has( element ) ) {
-				const elementConsumables = this._consumables.get( element );
-				elementConsumables.revert( elementOnly, item );
-			}
-		}
-	}
-}
+	revert( element, consumables ) {
+		const elementConsumables = this._consumables.get( element );
 
-// Helper function that extracts {@link engine.treeView.Element} from consumables object.
-// Element can be provided directly or as `element` key of an object.
-//
-// @private
-// @param {Object|engine.treeView.Element} consumables
-// @returns {Object} info Object with element and information if it is only key in the object.
-// @returns {engine.treeView.Element} info.element Element found in provided object.
-// @returns {Boolean} info.elementOnly Is `true` when element is only item provided in `consumables` object.
-function getElement( consumables ) {
-	// Element can be provided as a stand alone parameter or inside consumables object.
-	if ( consumables instanceof ViewElement ) {
-		return { element: consumables, elementOnly: true };
-	}
-
-	if ( isPlainObject( consumables ) && consumables.element instanceof ViewElement ) {
-		return { element: consumables.element, elementOnly: Object.keys( consumables ).length === 1 };
+		if ( elementConsumables !== undefined ) {
+			elementConsumables.revert( consumables );
+		}
 	}
-
-	/**
-	 * Tree view Element must be provided.
-	 *
-	 * @error viewconsumable-element-missing
-	 */
-	throw new CKEditorError( 'viewconsumable-element-missing: Tree view Element is not provided.' );
 }

+ 147 - 250
packages/ckeditor5-engine/tests/treecontroller/viewconsumable.js

@@ -20,160 +20,126 @@ describe( 'ViewConsumable', () => {
 	} );
 
 	describe( 'add', () => {
-		it( 'should allow to add element', () => {
-			viewConsumable.add( el );
+		it( 'should allow to add element name', () => {
+			viewConsumable.add( el, { name: true } );
 
-			expect( viewConsumable.test( el ) ).to.be.true;
-		} );
-
-		it( 'should allow to add element inside description object', () => {
-			viewConsumable.add( { element: el } );
-
-			expect( viewConsumable.test( el ) ).to.be.true;
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.true;
 		} );
 
 		it( 'should allow to add attributes classes and styles', () => {
-			viewConsumable.add( { element: el, attribute: 'href' } );
-			viewConsumable.add( { element: el, class: 'foobar' } );
-			viewConsumable.add( { element: el, style: 'color' } );
+			viewConsumable.add( el, { attribute: 'href' } );
+			viewConsumable.add( el, { class: 'foobar' } );
+			viewConsumable.add( el, { style: 'color' } );
 
-			expect( viewConsumable.test( { element: el, attribute: 'href' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, class: 'foobar' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, style: 'color' } ) ).to.be.true;
-			expect( viewConsumable.test( el ) ).to.be.null;
+			expect( viewConsumable.test( el, { attribute: 'href' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { class: 'foobar' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { style: 'color' }  ) ).to.be.true;
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.null;
 		} );
 
 		it( 'should allow to add attributes classes and styles in one call', () => {
-			viewConsumable.add( { element: el, attribute: 'href', class: 'foobar', style: 'color' } );
+			viewConsumable.add( el, { attribute: 'href', class: 'foobar', style: 'color' } );
 
-			expect( viewConsumable.test( { element: el, attribute: 'href' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, class: 'foobar' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, style: 'color' } ) ).to.be.true;
-			expect( viewConsumable.test( el ) ).to.be.null;
+			expect( viewConsumable.test( el, { attribute: 'href' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { class: 'foobar' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { style: 'color' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.null;
 		} );
 
 		it( 'should allow to add multiple attributes in one call', () => {
-			viewConsumable.add( { element: el, attribute: [ 'href', 'target', 'title' ] } );
+			viewConsumable.add( el, { attribute: [ 'href', 'target', 'title' ] } );
 
-			expect( viewConsumable.test( { element: el, attribute: 'href' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, attribute: 'target' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, attribute: 'title' } ) ).to.be.true;
-			expect( viewConsumable.test( el ) ).to.be.null;
+			expect( viewConsumable.test( el, { attribute: 'href' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { attribute: 'target' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { attribute: 'title' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.null;
 		} );
 
 		it( 'should allow to add multiple classes in one call', () => {
-			viewConsumable.add( { element: el, class: [ 'foo', 'bar', 'baz' ] } );
+			viewConsumable.add( el, { class: [ 'foo', 'bar', 'baz' ] } );
 
-			expect( viewConsumable.test( { element: el, class: 'foo' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, class: 'bar' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, class: 'baz' } ) ).to.be.true;
-			expect( viewConsumable.test( el ) ).to.be.null;
+			expect( viewConsumable.test( el, { class: 'foo' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { class: 'bar' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { class: 'baz' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.null;
 		} );
 
 		it( 'should allow to add multiple styles in one call', () => {
-			viewConsumable.add( { element: el, style: [ 'color', 'position', 'top' ] } );
-
-			expect( viewConsumable.test( { element: el, style: 'color' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, style: 'position' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, style: 'top' } ) ).to.be.true;
-			expect( viewConsumable.test( el ) ).to.be.null;
-		} );
-
-		it( 'should allow to add multiple consumables in one call', () => {
-			viewConsumable.add( el, { element: el, style: 'color' } );
-
-			expect( viewConsumable.test( el ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, style: 'color' } ) );
-		} );
+			viewConsumable.add( el, { style: [ 'color', 'position', 'top' ] } );
 
-		it( 'should throw an error when element is not provided', () => {
-			expect( () => {
-				viewConsumable.add( { style: 'color' } );
-			} ).to.throw( 'viewconsumable-element-missing' );
+			expect( viewConsumable.test( el, { style: 'color' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { style: 'position' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { style: 'top' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.null;
 		} );
 
 		it( 'should throw if class attribute is added', () => {
 			expect( () => {
-				viewConsumable.add( { element: el, attribute: 'class' } );
+				viewConsumable.add( el, { attribute: 'class' } );
 			} ).to.throw( 'viewconsumable-invalid-attribute' );
 		} );
 
 		it( 'should throw if style attribute is added', () => {
 			expect( () => {
-				viewConsumable.add( { element: el, attribute: 'style' } );
+				viewConsumable.add( el, { attribute: 'style' } );
 			} ).to.throw( 'viewconsumable-invalid-attribute' );
 		} );
 	} );
 
 	describe( 'test', () => {
-		it( 'should test added element', () => {
+		it( 'should test element name', () => {
 			const el2 = new ViewElement( 'p' );
 
-			viewConsumable.add( el );
+			viewConsumable.add( el, { name: true } );
 
-			expect( viewConsumable.test( el ) ).to.be.true;
-			expect( viewConsumable.test( { element: el } ) ).to.be.true;
-			expect( viewConsumable.test( el2 ) ).to.be.null;
-			expect( viewConsumable.test( { element: el2 } ) ).to.be.null;
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.true;
+			expect( viewConsumable.test( el2, { name: true } ) ).to.be.null;
 		} );
 
 		it( 'should test attributes, classes and styles', () => {
 			const el = new ViewElement( 'p' );
 
-			viewConsumable.add( { element: el, attribute: 'href', class: 'foobar', style: 'color' } );
+			viewConsumable.add( el, { attribute: 'href', class: 'foobar', style: 'color' } );
 
-			expect( viewConsumable.test( { element: el, attribute: 'href' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, class: 'foobar' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, style: 'color' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, attribute: 'href', class: 'foobar', style: 'color' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, attribute: 'href', class: 'baz' } ) ).to.be.null;
-			expect( viewConsumable.test( el ) ).to.be.null;
+			expect( viewConsumable.test( el, { attribute: 'href' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { class: 'foobar' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { style: 'color' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { attribute: 'href', class: 'foobar', style: 'color' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { attribute: 'href', class: 'baz' } ) ).to.be.null;
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.null;
 
-			viewConsumable.consume( { element: el, style: 'color' } );
-			expect( viewConsumable.test( { element: el, attribute: 'href', style: 'color' } ) ).to.be.false;
+			viewConsumable.consume( el, { style: 'color' } );
+			expect( viewConsumable.test( el, { attribute: 'href', style: 'color' } ) ).to.be.false;
 		} );
 
 		it( 'should allow to test multiple attributes in one call', () => {
-			viewConsumable.add( { element: el, attribute: [ 'href', 'title', 'target' ] } );
+			viewConsumable.add( el, { attribute: [ 'href', 'title', 'target' ] } );
 
-			expect( viewConsumable.test( { element: el, attribute: [ 'href', 'title', 'target' ] } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, attribute: [ 'href', 'title', 'alt' ] } ) ).to.be.null;
+			expect( viewConsumable.test( el, { attribute: [ 'href', 'title', 'target' ] } ) ).to.be.true;
+			expect( viewConsumable.test( el, { attribute: [ 'href', 'title', 'alt' ] } ) ).to.be.null;
 
-			viewConsumable.consume( { element: el, attribute: 'target' } );
-			expect( viewConsumable.test( { element: el, attribute: [ 'href', 'title', 'target' ] } ) ).to.be.false;
+			viewConsumable.consume( el, { attribute: 'target' } );
+			expect( viewConsumable.test( el, { attribute: [ 'href', 'title', 'target' ] } ) ).to.be.false;
 		} );
 
 		it( 'should allow to test multiple classes in one call', () => {
-			viewConsumable.add( { element: el, class: [ 'foo', 'bar', 'baz' ] } );
+			viewConsumable.add( el, { class: [ 'foo', 'bar', 'baz' ] } );
 
-			expect( viewConsumable.test( { element: el, class: [ 'foo', 'bar', 'baz' ] } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, class: [ 'foo', 'bar', 'qux' ] } ) ).to.be.null;
+			expect( viewConsumable.test( el, { class: [ 'foo', 'bar', 'baz' ] } ) ).to.be.true;
+			expect( viewConsumable.test( el, { class: [ 'foo', 'bar', 'qux' ] } ) ).to.be.null;
 
-			viewConsumable.consume( { element: el, class: 'bar' } );
-			expect( viewConsumable.test( { element: el, class: [ 'foo', 'bar', 'baz' ] } ) ).to.be.false;
+			viewConsumable.consume( el, { class: 'bar' } );
+			expect( viewConsumable.test( el, { class: [ 'foo', 'bar', 'baz' ] } ) ).to.be.false;
 		} );
 
 		it( 'should allow to test multiple styles in one call', () => {
-			viewConsumable.add( { element: el, style: [ 'color', 'position', 'top' ] } );
-
-			expect( viewConsumable.test( { element: el, style: [ 'color', 'position', 'top' ] } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, style: [ 'color', 'position', 'left' ] } ) ).to.be.null;
-
-			viewConsumable.consume( { element: el, style: 'top' } );
-			expect( viewConsumable.test( { element: el, style: [ 'color', 'position', 'top' ] } ) ).to.be.false;
-		} );
+			viewConsumable.add( el, { style: [ 'color', 'position', 'top' ] } );
 
-		it( 'should allow to test with multiple parameters', () => {
-			viewConsumable.add( el, { element: el, class: 'foobar' }, { element: el, 'style': 'red' } );
+			expect( viewConsumable.test( el, { style: [ 'color', 'position', 'top' ] } ) ).to.be.true;
+			expect( viewConsumable.test( el, { style: [ 'color', 'position', 'left' ] } ) ).to.be.null;
 
-			expect( viewConsumable.test( el, { element: el, style: 'red' }, { element: el, class: 'foobar' } ) ).to.be.true;
-			expect( viewConsumable.test( el, { element: el, style: 'red' }, { element: el, class: 'baz' } ) ).to.be.null;
-
-			const el2 = new ViewElement( 'p' );
-			viewConsumable.add( { element: el2, attribute: 'title' } );
-			expect( viewConsumable.test( el, { element: el2, attribute: 'title' } ) ).to.be.true;
-			viewConsumable.consume( { element: el2, attribute: 'title' } );
-			expect( viewConsumable.test( el, { element: el2, attribute: 'title' } ) ).to.be.false;
+			viewConsumable.consume( el, { style: 'top' } );
+			expect( viewConsumable.test( el, { style: [ 'color', 'position', 'top' ] } ) ).to.be.false;
 		} );
 
 		it( 'should return null if not consumable', () => {
@@ -181,288 +147,219 @@ describe( 'ViewConsumable', () => {
 		} );
 
 		it( 'should return false if already consumed', () => {
-			viewConsumable.add( el );
-			viewConsumable.consume( el );
+			viewConsumable.add( el, { name: true } );
+			viewConsumable.consume( el, { name: true } );
 
-			expect( viewConsumable.test( el ) ).to.be.false;
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.false;
 		} );
 
 		it( 'should return null if first non-consumable item is found', () => {
-			viewConsumable.add( { element: el, attribute: 'foo' } );
+			viewConsumable.add( el, { attribute: 'foo' } );
 
-			expect( viewConsumable.test( { element: el, attribute: [ 'foo', 'bar' ] } ) ).to.be.null;
-			expect( viewConsumable.test( { element: el, attribute: 'foo' }, el ) ).to.be.null;
+			expect( viewConsumable.test( el, { attribute: [ 'foo', 'bar' ] } ) ).to.be.null;
 		} );
 
 		it( 'should return false if first already consumed item is found', () => {
-			viewConsumable.add( { element: el, attribute: [ 'foo', 'bar' ] }, el );
-			viewConsumable.consume( { element: el, attribute: 'bar' } );
-			viewConsumable.consume( el );
-
-			expect( viewConsumable.test( { element: el, attribute: [ 'foo', 'bar' ] } ) ).to.be.false;
-			expect( viewConsumable.test( el ) ).to.be.false;
-		} );
+			viewConsumable.add( el, { name: true, attribute: [ 'foo', 'bar' ] } );
+			viewConsumable.consume( el, { attribute: 'bar' } );
+			viewConsumable.consume( el, { name: true } );
 
-		it( 'should throw an error when element is not provided', () => {
-			expect( () => {
-				viewConsumable.test( { style: 'color' } );
-			} ).to.throw( 'viewconsumable-element-missing' );
+			expect( viewConsumable.test( el, { attribute: [ 'foo', 'bar' ] } ) ).to.be.false;
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.false;
 		} );
 
 		it( 'should throw if class attribute is tested', () => {
-			viewConsumable.add( { element: el, class: 'foobar' } );
+			viewConsumable.add( el, { class: 'foobar' } );
 
 			expect( () => {
-				viewConsumable.test( { element: el, attribute: 'class' } );
+				viewConsumable.test( el, { attribute: 'class' } );
 			} ).to.throw( 'viewconsumable-invalid-attribute' );
 		} );
 
 		it( 'should throw if style attribute is tested', () => {
-			viewConsumable.add( { element: el, style: 'color' } );
+			viewConsumable.add( el, { style: 'color' } );
 
 			expect( () => {
-				viewConsumable.test( { element: el, attribute: 'style' } );
+				viewConsumable.test( el, { attribute: 'style' } );
 			} ).to.throw( 'viewconsumable-invalid-attribute' );
 		} );
 	} );
 
 	describe( 'consume', () => {
 		it( 'should consume element', () => {
-			viewConsumable.add( el );
-			const consumed = viewConsumable.consume( el );
+			viewConsumable.add( el, { name: true } );
+			const consumed = viewConsumable.consume( el, { name: true } );
 
-			expect( viewConsumable.test( el ) ).to.be.false;
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.false;
 			expect( consumed ).to.be.true;
 		} );
 
 		it( 'should not consume element not marked for consumption', () => {
-			expect( viewConsumable.consume( el ) ).to.be.false;
+			expect( viewConsumable.consume( el, { name: true } ) ).to.be.false;
 		} );
 
 		it( 'should not consume element already consumed', () => {
-			viewConsumable.add( el );
+			viewConsumable.add( el, { name: true } );
 
-			expect( viewConsumable.consume( el ) ).to.be.true;
-			expect( viewConsumable.consume( el ) ).to.be.false;
+			expect( viewConsumable.consume( el, { name: true } ) ).to.be.true;
+			expect( viewConsumable.consume( el, { name: true } ) ).to.be.false;
 		} );
 
 		it( 'should consume attributes, classes and styles', () => {
-			viewConsumable.add( { element: el, class: 'foobar', attribute: 'href', style: 'color' } );
+			viewConsumable.add( el, { class: 'foobar', attribute: 'href', style: 'color' } );
 
-			const consumed1 = viewConsumable.consume( { element: el, class: 'foobar' } );
-			const consumed2 = viewConsumable.consume( { element: el, attribute: 'href' } );
-			const consumed3 = viewConsumable.consume( { element: el, style: 'color' } );
+			const consumed1 = viewConsumable.consume( el, { class: 'foobar' } );
+			const consumed2 = viewConsumable.consume( el, { attribute: 'href' } );
+			const consumed3 = viewConsumable.consume( el, { style: 'color' } );
 
 			expect( consumed1 ).to.be.true;
 			expect( consumed2 ).to.be.true;
 			expect( consumed3 ).to.be.true;
 
-			expect( viewConsumable.test( { element: el, class: 'foobar' } ) ).to.be.false;
-			expect( viewConsumable.test( { element: el, attribute: 'href' } ) ).to.be.false;
-			expect( viewConsumable.test( { element: el, style: 'color' } ) ).to.be.false;
+			expect( viewConsumable.test( el, { class: 'foobar' } ) ).to.be.false;
+			expect( viewConsumable.test( el, { attribute: 'href' } ) ).to.be.false;
+			expect( viewConsumable.test( el, { style: 'color' } ) ).to.be.false;
 		} );
 
 		it( 'should consume multiple attributes', () => {
-			viewConsumable.add( { element: el, attribute: [ 'href', 'title', 'name' ] } );
+			viewConsumable.add( el, { attribute: [ 'href', 'title', 'name' ] } );
 
-			const consumed = viewConsumable.consume( { element: el, attribute: [ 'href', 'title' ] } );
+			const consumed = viewConsumable.consume( el, { attribute: [ 'href', 'title' ] } );
 
 			expect( consumed ).to.be.true;
-			expect( viewConsumable.test( { element: el, attribute: 'href' } ) ).to.be.false;
-			expect( viewConsumable.test( { element: el, attribute: 'title' } ) ).to.be.false;
-			expect( viewConsumable.test( { element: el, attribute: 'name' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { attribute: 'href' } ) ).to.be.false;
+			expect( viewConsumable.test( el, { attribute: 'title' } ) ).to.be.false;
+			expect( viewConsumable.test( el, { attribute: 'name' } ) ).to.be.true;
 		} );
 
 		it( 'should consume multiple styles', () => {
-			viewConsumable.add( { element: el, style: [ 'color', 'top', 'position' ] } );
+			viewConsumable.add( el, { style: [ 'color', 'top', 'position' ] } );
 
-			const consumed = viewConsumable.consume( { element: el, style: [ 'color', 'position' ] } );
+			const consumed = viewConsumable.consume( el, { style: [ 'color', 'position' ] } );
 
 			expect( consumed ).to.be.true;
-			expect( viewConsumable.test( { element: el, style: 'color' } ) ).to.be.false;
-			expect( viewConsumable.test( { element: el, style: 'position' } ) ).to.be.false;
-			expect( viewConsumable.test( { element: el, style: 'top' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { style: 'color' } ) ).to.be.false;
+			expect( viewConsumable.test( el, { style: 'position' } ) ).to.be.false;
+			expect( viewConsumable.test( el, { style: 'top' } ) ).to.be.true;
 		} );
 
 		it( 'should consume multiple classes', () => {
-			viewConsumable.add( { element: el, class: [ 'foo', 'bar', 'baz' ] } );
-
-			const consumed = viewConsumable.consume( { element: el, class: [ 'bar', 'baz' ] } );
+			viewConsumable.add( el, { class: [ 'foo', 'bar', 'baz' ] } );
 
-			expect( consumed ).to.be.true;
-			expect( viewConsumable.test( { element: el, class: 'bar' } ) ).to.be.false;
-			expect( viewConsumable.test( { element: el, class: 'baz' } ) ).to.be.false;
-			expect( viewConsumable.test( { element: el, class: 'foo' } ) ).to.be.true;
-		} );
-
-		it( 'should consume multiple items', () => {
-			viewConsumable.add( {
-				element: el,
-				attribute: [ 'name', 'href', 'title' ],
-				class: [ 'foo', 'bar', 'baz' ],
-				style: [ 'color', 'position' ]
-			} );
-
-			const consumed = viewConsumable.consume(
-				{ element: el, attribute: 'name', class: 'foo' } ,
-				{ element: el, attribute: 'href', class: [ 'bar', 'baz' ] } ,
-				{ element: el, attribute: 'title', style: 'color' }
-			);
-
-			expect( consumed ).to.be.true;
-			expect( viewConsumable.test( { element: el, attribute: 'name' } ) ).to.be.false;
-			expect( viewConsumable.test( { element: el, attribute: 'href' } ) ).to.be.false;
-			expect( viewConsumable.test( { element: el, attribute: 'title' } ) ).to.be.false;
-
-			expect( viewConsumable.test( { element: el, class: 'foo' } ) ).to.be.false;
-			expect( viewConsumable.test( { element: el, class: 'bar' } ) ).to.be.false;
-			expect( viewConsumable.test( { element: el, class: 'baz' } ) ).to.be.false;
-
-			expect( viewConsumable.test( { element: el, style: 'color' } ) ).to.be.false;
-			expect( viewConsumable.test( { element: el, style: 'position' } ) ).to.be.true;
-		} );
-
-		it( 'should consume element provided as only item in object', () => {
-			viewConsumable.add( el );
-			const consumed = viewConsumable.consume( { element: el } );
+			const consumed = viewConsumable.consume( el, { class: [ 'bar', 'baz' ] } );
 
-			expect( viewConsumable.test( el ) ).to.be.false;
 			expect( consumed ).to.be.true;
+			expect( viewConsumable.test( el, { class: 'bar' } ) ).to.be.false;
+			expect( viewConsumable.test( el, { class: 'baz' } ) ).to.be.false;
+			expect( viewConsumable.test( el, { class: 'foo' } ) ).to.be.true;
 		} );
 
 		it( 'should consume only if all items can be consumed', () => {
-			viewConsumable.add( { element: el, style: [ 'position', 'color' ], attribute: [ 'href', 'title' ] } );
-
-			let consumed = viewConsumable.consume( el, { element: el, style: 'color' } );
-			expect( consumed ).to.be.false;
-			expect( viewConsumable.test( { element: el, style: 'color' } ) ).to.be.true;
+			viewConsumable.add( el, { style: [ 'position', 'color' ], attribute: [ 'href', 'title' ] } );
 
-			consumed = viewConsumable.consume( { element: el, style: [ 'color', 'top' ] } );
+			const consumed = viewConsumable.consume( el, { style: [ 'color', 'top' ] } );
 			expect( consumed ).to.be.false;
-			expect( viewConsumable.test( { element: el, style: 'color' } ) ).to.be.true;
-		} );
-
-		it( 'should throw an error when element is not provided', () => {
-			expect( () => {
-				viewConsumable.consume( { style: 'color' } );
-			} ).to.throw( 'viewconsumable-element-missing' );
+			expect( viewConsumable.test( el, { style: 'color' } ) ).to.be.true;
 		} );
 
 		it( 'should throw if class attribute is provided', () => {
-			viewConsumable.add( { element: el, class: 'foobar' } );
+			viewConsumable.add( el, { class: 'foobar' } );
 
 			expect( () => {
-				viewConsumable.consume( { element: el, attribute: 'class' } );
+				viewConsumable.consume( el, { attribute: 'class' } );
 			} ).to.throw( 'viewconsumable-invalid-attribute' );
 		} );
 
 		it( 'should throw if style attribute is provided', () => {
-			viewConsumable.add( { element: el, style: 'color' } );
+			viewConsumable.add( el, { style: 'color' } );
 
 			expect( () => {
-				viewConsumable.consume( { element: el, attribute: 'style' } );
+				viewConsumable.consume( el, { attribute: 'style' } );
 			} ).to.throw( 'viewconsumable-invalid-attribute' );
 		} );
 	} );
 
 	describe( 'revert', () => {
 		it( 'should revert single element', () => {
-			viewConsumable.add( el );
-			viewConsumable.consume( el );
-			expect( viewConsumable.test( el ) ).to.be.false;
-			viewConsumable.revert( el );
-			expect( viewConsumable.test( el ) ).to.be.true;
+			viewConsumable.add( el, { name: true } );
+			viewConsumable.consume( el, { name: true } );
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.false;
+			viewConsumable.revert( el, { name: true } );
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.true;
 		} );
 
 		it( 'should not revert element that was never added', () => {
-			viewConsumable.revert( el );
-			expect( viewConsumable.test( el ) ).to.be.null;
+			viewConsumable.revert( el, { name: true } );
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.null;
 		} );
 
 		it( 'should do nothing on not consumed element', () => {
-			viewConsumable.add( el );
-			viewConsumable.revert( el );
-			expect( viewConsumable.test( el ) ).to.be.true;
+			viewConsumable.add( el, { name: true } );
+			viewConsumable.revert( el, { name: true } );
+			expect( viewConsumable.test( el, { name: true } ) ).to.be.true;
 		} );
 
 		it( 'should revert classes, attributes and styles', () => {
-			viewConsumable.add( { element: el, class: 'foobar', style: 'color', attribute: 'name' } );
-			viewConsumable.consume( { element: el, class: 'foobar', style: 'color', attribute: 'name' } );
+			viewConsumable.add( el, { class: 'foobar', style: 'color', attribute: 'name' } );
+			viewConsumable.consume( el, { class: 'foobar', style: 'color', attribute: 'name' } );
 
-			viewConsumable.revert( { element: el, class: 'foobar' } );
-			viewConsumable.revert( { element: el, style: 'color' } );
-			viewConsumable.revert( { element: el, attribute: 'name' } );
+			viewConsumable.revert( el, { class: 'foobar' } );
+			viewConsumable.revert( el, { style: 'color' } );
+			viewConsumable.revert( el, { attribute: 'name' } );
 
-			expect( viewConsumable.test( { element: el, class: 'foobar', style: 'color', attribute: 'name' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { class: 'foobar', style: 'color', attribute: 'name' } ) ).to.be.true;
 		} );
 
 		it( 'should revert multiple classes, attributes and styles in one call #1', () => {
-			viewConsumable.add( {
-				element: el,
+			viewConsumable.add( el, {
 				class: 'foobar',
 				style: 'color',
 				attribute: 'name'
 			} );
-			viewConsumable.consume( { element: el, class: 'foobar', style: 'color', attribute: 'name' } );
-			viewConsumable.revert( { element: el, class: 'foobar', style: 'color', attribute: 'name' } );
+			viewConsumable.consume( el, { class: 'foobar', style: 'color', attribute: 'name' } );
+			viewConsumable.revert( el, { class: 'foobar', style: 'color', attribute: 'name' } );
 
-			expect( viewConsumable.test( { element: el, class: 'foobar', style: 'color', attribute: 'name' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { class: 'foobar', style: 'color', attribute: 'name' } ) ).to.be.true;
 		} );
 
 		it( 'should revert multiple classes, attributes and styles in one call #2', () => {
-			const description = {
-				element: el,
+			const consumables = {
 				class: [ 'foobar', 'baz' ],
 				style: [ 'color', 'position' ],
 				attribute: [ 'name', 'href' ]
 			};
 
-			viewConsumable.add( description );
-			viewConsumable.consume( description );
-			viewConsumable.revert( description );
-
-			expect( viewConsumable.test( description ) ).to.be.true;
-		} );
-
-		it( 'should not revert non consumable items', () => {
-			viewConsumable.add( { element: el, class: 'foobar' } );
-			viewConsumable.consume( { element: el, class: 'foobar' }  );
-			viewConsumable.revert( { element: el, class: 'foobar', attribute: 'name' } );
+			viewConsumable.add( el, consumables );
+			viewConsumable.consume( el, consumables );
+			viewConsumable.revert( el, consumables );
 
-			expect( viewConsumable.test( { element: el, class: 'foobar' } ) ).to.be.true;
-			expect( viewConsumable.test( { element: el, attribute: 'name' } ) ).to.be.null;
+			expect( viewConsumable.test( el, consumables ) ).to.be.true;
 		} );
 
-		it( 'should allow to use additional parameters in one call', () => {
-			const el2 = new ViewElement( 'p' );
-			viewConsumable.add( el, el2 );
-			expect( viewConsumable.consume( el, el2 ) ).to.be.true;
-			viewConsumable.revert( el, el2 );
-
-			expect( viewConsumable.test( el, el2 ) ).to.be.true;
-		} );
+		it( 'should revert only items that were prevoiusly added', () => {
+			viewConsumable.add( el, { class: 'foobar' } );
+			viewConsumable.consume( el, { class: 'foobar' } );
+			viewConsumable.revert( el, { class: 'foobar', attribute: 'name' } );
 
-		it( 'should throw an error when element is not provided', () => {
-			expect( () => {
-				viewConsumable.revert( { style: 'color' } );
-			} ).to.throw( 'viewconsumable-element-missing' );
+			expect( viewConsumable.test( el, { class: 'foobar' } ) ).to.be.true;
+			expect( viewConsumable.test( el, { attribute: 'name' } ) ).to.be.null;
 		} );
 
 		it( 'should throw if class attribute is provided', () => {
-			viewConsumable.add( { element: el, class: 'foobar' } );
-			viewConsumable.consume( { element: el, class: 'foobar' } );
+			viewConsumable.add( el, { class: 'foobar' } );
+			viewConsumable.consume( el, { class: 'foobar' } );
 
 			expect( () => {
-				viewConsumable.revert( { element: el, attribute: 'class' } );
+				viewConsumable.revert( el, { attribute: 'class' } );
 			} ).to.throw( 'viewconsumable-invalid-attribute' );
 		} );
 
 		it( 'should throw if style attribute is provided', () => {
-			viewConsumable.add( { element: el, style: 'color' } );
-			viewConsumable.consume( { element: el, style: 'color' } );
+			viewConsumable.add( el, { style: 'color' } );
+			viewConsumable.consume( el, { style: 'color' } );
 
 			expect( () => {
-				viewConsumable.revert( { element: el, attribute: 'style' } );
+				viewConsumable.revert( el, { attribute: 'style' } );
 			} ).to.throw( 'viewconsumable-invalid-attribute' );
 		} );
 	} );