Przeglądaj źródła

Merge branch 'master' into t/404

Maciej Gołaszewski 6 lat temu
rodzic
commit
b821b4116f
65 zmienionych plików z 1169 dodań i 199 usunięć
  1. 30 0
      packages/ckeditor5-engine/CHANGELOG.md
  2. 17 17
      packages/ckeditor5-engine/package.json
  3. 1 1
      packages/ckeditor5-engine/src/controller/editingcontroller.js
  4. 12 4
      packages/ckeditor5-engine/src/conversion/downcastdispatcher.js
  5. 59 5
      packages/ckeditor5-engine/src/conversion/mapper.js
  6. 10 3
      packages/ckeditor5-engine/src/model/documentfragment.js
  7. 14 8
      packages/ckeditor5-engine/src/model/documentselection.js
  8. 19 11
      packages/ckeditor5-engine/src/model/element.js
  9. 20 0
      packages/ckeditor5-engine/src/model/liveposition.js
  10. 20 0
      packages/ckeditor5-engine/src/model/liverange.js
  11. 18 0
      packages/ckeditor5-engine/src/model/markercollection.js
  12. 47 23
      packages/ckeditor5-engine/src/model/node.js
  13. 8 8
      packages/ckeditor5-engine/src/model/operation/transform.js
  14. 18 0
      packages/ckeditor5-engine/src/model/position.js
  15. 18 0
      packages/ckeditor5-engine/src/model/range.js
  16. 28 3
      packages/ckeditor5-engine/src/model/rootelement.js
  17. 8 7
      packages/ckeditor5-engine/src/model/selection.js
  18. 16 2
      packages/ckeditor5-engine/src/model/text.js
  19. 9 3
      packages/ckeditor5-engine/src/model/textproxy.js
  20. 29 3
      packages/ckeditor5-engine/src/view/attributeelement.js
  21. 28 3
      packages/ckeditor5-engine/src/view/containerelement.js
  22. 10 3
      packages/ckeditor5-engine/src/view/documentfragment.js
  23. 14 8
      packages/ckeditor5-engine/src/view/documentselection.js
  24. 1 1
      packages/ckeditor5-engine/src/view/downcastwriter.js
  25. 28 3
      packages/ckeditor5-engine/src/view/editableelement.js
  26. 21 10
      packages/ckeditor5-engine/src/view/element.js
  27. 28 3
      packages/ckeditor5-engine/src/view/emptyelement.js
  28. 40 13
      packages/ckeditor5-engine/src/view/node.js
  29. 19 0
      packages/ckeditor5-engine/src/view/position.js
  30. 19 0
      packages/ckeditor5-engine/src/view/range.js
  31. 30 3
      packages/ckeditor5-engine/src/view/rooteditableelement.js
  32. 9 7
      packages/ckeditor5-engine/src/view/selection.js
  33. 16 2
      packages/ckeditor5-engine/src/view/text.js
  34. 10 3
      packages/ckeditor5-engine/src/view/textproxy.js
  35. 28 3
      packages/ckeditor5-engine/src/view/uielement.js
  36. 34 8
      packages/ckeditor5-engine/tests/conversion/downcastdispatcher.js
  37. 39 0
      packages/ckeditor5-engine/tests/conversion/mapper.js
  38. 4 2
      packages/ckeditor5-engine/tests/model/documentfragment.js
  39. 7 1
      packages/ckeditor5-engine/tests/model/documentselection.js
  40. 12 1
      packages/ckeditor5-engine/tests/model/element.js
  41. 23 0
      packages/ckeditor5-engine/tests/model/liveposition.js
  42. 23 0
      packages/ckeditor5-engine/tests/model/liverange.js
  43. 21 0
      packages/ckeditor5-engine/tests/model/markercollection.js
  44. 8 0
      packages/ckeditor5-engine/tests/model/node.js
  45. 20 0
      packages/ckeditor5-engine/tests/model/position.js
  46. 14 0
      packages/ckeditor5-engine/tests/model/range.js
  47. 11 1
      packages/ckeditor5-engine/tests/model/rootelement.js
  48. 21 1
      packages/ckeditor5-engine/tests/model/selection.js
  49. 4 1
      packages/ckeditor5-engine/tests/model/text.js
  50. 4 1
      packages/ckeditor5-engine/tests/model/textproxy.js
  51. 9 1
      packages/ckeditor5-engine/tests/view/attributeelement.js
  52. 9 1
      packages/ckeditor5-engine/tests/view/containerelement.js
  53. 4 1
      packages/ckeditor5-engine/tests/view/documentfragment.js
  54. 7 1
      packages/ckeditor5-engine/tests/view/documentselection.js
  55. 50 8
      packages/ckeditor5-engine/tests/view/editableelement.js
  56. 10 1
      packages/ckeditor5-engine/tests/view/element.js
  57. 10 1
      packages/ckeditor5-engine/tests/view/emptyelement.js
  58. 20 2
      packages/ckeditor5-engine/tests/view/node.js
  59. 30 3
      packages/ckeditor5-engine/tests/view/position.js
  60. 28 0
      packages/ckeditor5-engine/tests/view/range.js
  61. 16 1
      packages/ckeditor5-engine/tests/view/rooteditableelement.js
  62. 4 1
      packages/ckeditor5-engine/tests/view/selection.js
  63. 7 1
      packages/ckeditor5-engine/tests/view/text.js
  64. 5 1
      packages/ckeditor5-engine/tests/view/textproxy.js
  65. 13 0
      packages/ckeditor5-engine/tests/view/uielement.js

+ 30 - 0
packages/ckeditor5-engine/CHANGELOG.md

@@ -1,6 +1,36 @@
 Changelog
 =========
 
+## [14.0.0](https://github.com/ckeditor/ckeditor5-engine/compare/v13.2.1...v14.0.0) (2019-08-26)
+
+### Features
+
+* `transformSets()` will now return a `Map` instance linking transformed operations to the original operations. ([61da3ec](https://github.com/ckeditor/ckeditor5-engine/commit/61da3ec))
+* Brought support for RTL content in the `bindTwoStepCaretToAttribute()` helper. See [ckeditor/ckeditor5#1151](https://github.com/ckeditor/ckeditor5/issues/1151). ([d57ff5a](https://github.com/ckeditor/ckeditor5-engine/commit/d57ff5a))
+* Introduced `model.Differ#refreshItem()`. ([7dc8710](https://github.com/ckeditor/ckeditor5-engine/commit/7dc8710))
+* Introduced the `is()` method to additional objects from the model and view realms. Closes [#1667](https://github.com/ckeditor/ckeditor5-engine/issues/1667). ([89dbe43](https://github.com/ckeditor/ckeditor5-engine/commit/89dbe43))
+
+### Bug fixes
+
+* Fixed problem with handling very large text nodes. ([a7ae813](https://github.com/ckeditor/ckeditor5-engine/commit/a7ae813))
+* Prevented `Differ` crashing in some scenarios involving attribute changes on elements. Closes [#1764](https://github.com/ckeditor/ckeditor5-engine/issues/1764). ([482e55e](https://github.com/ckeditor/ckeditor5-engine/commit/482e55e))
+
+### Other changes
+
+* Add `unwrapElement()` method to UpcastWriter. ([9e97196](https://github.com/ckeditor/ckeditor5-engine/commit/9e97196))
+* Allowed for unbinding single elements from a marker name in `Mapper`. Closes [#1758](https://github.com/ckeditor/ckeditor5-engine/issues/1758). ([52e701d](https://github.com/ckeditor/ckeditor5-engine/commit/52e701d))
+* The issue tracker for this package was moved to https://github.com/ckeditor/ckeditor5/issues. See [ckeditor/ckeditor5#1988](https://github.com/ckeditor/ckeditor5/issues/1988). ([6ed94c6](https://github.com/ckeditor/ckeditor5-engine/commit/6ed94c6))
+* Introduced automatic marker re-rendering during conversion for markers which view element was unbound. Closes [#1780](https://github.com/ckeditor/ckeditor5-engine/issues/1780). ([5661fb6](https://github.com/ckeditor/ckeditor5-engine/commit/5661fb6))
+* Position getters (such as `#parent` or `#index`) will throw when position points at an incorrect place in its root. Closes [#1776](https://github.com/ckeditor/ckeditor5-engine/issues/1776). ([a359866](https://github.com/ckeditor/ckeditor5-engine/commit/a359866))
+
+### BREAKING CHANGES
+
+* New parameter introduced in `DowncastDispatcher#convertChanges()`. Now it is `convertChanges( differ, markers, writer )`.
+* Although it was rather impossible to use `DowncastDispatcher` without specifying any conversion API in the constructor, now it is a required parameter.
+* The `bindTwoStepCaretToAttribute()` helper arguments syntax has changed (replaced by an object). Please refer to the helper documentation to learn more.
+* `Mapper#unbindElementsFromMarkerName( markerName )` was replaced by `Mapper#unbindElementFromMarkerName( element, markerName )`.
+
+
 ## [13.2.1](https://github.com/ckeditor/ckeditor5-engine/compare/v13.2.0...v13.2.1) (2019-07-10)
 
 Internal changes only (updated dependencies, documentation, etc.).

+ 17 - 17
packages/ckeditor5-engine/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@ckeditor/ckeditor5-engine",
-  "version": "13.2.1",
+  "version": "14.0.0",
   "description": "The editing engine of CKEditor 5 – the best browser-based rich text editor.",
   "keywords": [
     "wysiwyg",
@@ -21,24 +21,24 @@
     "ckeditor 5"
   ],
   "dependencies": {
-    "@ckeditor/ckeditor5-utils": "^13.0.1",
+    "@ckeditor/ckeditor5-utils": "^14.0.0",
     "lodash-es": "^4.17.10"
   },
   "devDependencies": {
-    "@ckeditor/ckeditor5-basic-styles": "^11.1.3",
-    "@ckeditor/ckeditor5-block-quote": "^11.1.2",
-    "@ckeditor/ckeditor5-core": "^12.2.1",
-    "@ckeditor/ckeditor5-editor-classic": "^12.1.3",
-    "@ckeditor/ckeditor5-enter": "^11.0.4",
-    "@ckeditor/ckeditor5-essentials": "^11.0.4",
-    "@ckeditor/ckeditor5-heading": "^11.0.4",
-    "@ckeditor/ckeditor5-link": "^11.1.1",
-    "@ckeditor/ckeditor5-list": "^12.0.4",
-    "@ckeditor/ckeditor5-paragraph": "^11.0.4",
-    "@ckeditor/ckeditor5-theme-lark": "^14.1.1",
-    "@ckeditor/ckeditor5-typing": "^12.1.1",
-    "@ckeditor/ckeditor5-undo": "^11.0.4",
-    "@ckeditor/ckeditor5-widget": "^11.0.4",
+    "@ckeditor/ckeditor5-basic-styles": "^11.1.4",
+    "@ckeditor/ckeditor5-block-quote": "^11.1.3",
+    "@ckeditor/ckeditor5-core": "^12.3.0",
+    "@ckeditor/ckeditor5-editor-classic": "^12.1.4",
+    "@ckeditor/ckeditor5-enter": "^11.1.0",
+    "@ckeditor/ckeditor5-essentials": "^11.0.5",
+    "@ckeditor/ckeditor5-heading": "^11.0.5",
+    "@ckeditor/ckeditor5-link": "^11.1.2",
+    "@ckeditor/ckeditor5-list": "^12.1.0",
+    "@ckeditor/ckeditor5-paragraph": "^11.0.5",
+    "@ckeditor/ckeditor5-theme-lark": "^14.2.0",
+    "@ckeditor/ckeditor5-typing": "^12.2.0",
+    "@ckeditor/ckeditor5-undo": "^11.0.5",
+    "@ckeditor/ckeditor5-widget": "^11.1.0",
     "eslint": "^5.5.0",
     "eslint-config-ckeditor5": "^2.0.0",
     "husky": "^1.3.1",
@@ -51,7 +51,7 @@
   "author": "CKSource (http://cksource.com/)",
   "license": "GPL-2.0-or-later",
   "homepage": "https://ckeditor.com/ckeditor-5",
-  "bugs": "https://github.com/ckeditor/ckeditor5-engine/issues",
+  "bugs": "https://github.com/ckeditor/ckeditor5/issues",
   "repository": {
     "type": "git",
     "url": "https://github.com/ckeditor/ckeditor5-engine.git"

+ 1 - 1
packages/ckeditor5-engine/src/controller/editingcontroller.js

@@ -87,7 +87,7 @@ export default class EditingController {
 		// Also convert model selection.
 		this.listenTo( doc, 'change', () => {
 			this.view.change( writer => {
-				this.downcastDispatcher.convertChanges( doc.differ, writer );
+				this.downcastDispatcher.convertChanges( doc.differ, markers, writer );
 				this.downcastDispatcher.convertSelection( selection, markers, writer );
 			} );
 		}, { priority: 'low' } );

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

@@ -106,10 +106,10 @@ export default class DowncastDispatcher {
 	 * Creates a `DowncastDispatcher` instance.
 	 *
 	 * @see module:engine/conversion/downcastdispatcher~DowncastConversionApi
-	 * @param {Object} [conversionApi] Additional properties for interface that will be passed to events fired
+	 * @param {Object} conversionApi Additional properties for interface that will be passed to events fired
 	 * by `DowncastDispatcher`.
 	 */
-	constructor( conversionApi = {} ) {
+	constructor( conversionApi ) {
 		/**
 		 * Interface passed by dispatcher to the events callbacks.
 		 *
@@ -122,9 +122,10 @@ export default class DowncastDispatcher {
 	 * Takes {@link module:engine/model/differ~Differ model differ} object with buffered changes and fires conversion basing on it.
 	 *
 	 * @param {module:engine/model/differ~Differ} differ Differ object with buffered changes.
+	 * @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with converted model.
 	 * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.
 	 */
-	convertChanges( differ, writer ) {
+	convertChanges( differ, markers, writer ) {
 		// Before the view is updated, remove markers which have changed.
 		for ( const change of differ.getMarkersToRemove() ) {
 			this.convertMarkerRemove( change.name, change.range, writer );
@@ -142,6 +143,13 @@ export default class DowncastDispatcher {
 			}
 		}
 
+		for ( const markerName of this.conversionApi.mapper.flushUnboundMarkerNames() ) {
+			const markerRange = markers.get( markerName ).getRange();
+
+			this.convertMarkerRemove( markerName, markerRange, writer );
+			this.convertMarkerAdd( markerName, markerRange, writer );
+		}
+
 		// After the view is updated, convert markers which have changed.
 		for ( const change of differ.getMarkersToAdd() ) {
 			this.convertMarkerAdd( change.name, change.range, writer );
@@ -252,7 +260,7 @@ export default class DowncastDispatcher {
 	 * @fires addMarker
 	 * @fires attribute
 	 * @param {module:engine/model/selection~Selection} selection Selection to convert.
-	 * @param {Array.<module:engine/model/markercollection~Marker>} markers Array of markers containing model markers.
+	 * @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with converted model.
 	 * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.
 	 */
 	convertSelection( selection, markers, writer ) {

+ 59 - 5
packages/ckeditor5-engine/src/conversion/mapper.js

@@ -77,6 +77,25 @@ export default class Mapper {
 		 */
 		this._markerNameToElements = new Map();
 
+		/**
+		 * View element to model marker names mapping.
+		 *
+		 * This is reverse to {@link ~Mapper#_markerNameToElements} map.
+		 *
+		 * @private
+		 * @member {Map}
+		 */
+		this._elementToMarkerNames = new Map();
+
+		/**
+		 * Stores marker names of markers which has changed due to unbinding a view element (so it is assumed that the view element
+		 * has been removed, moved or renamed).
+		 *
+		 * @private
+		 * @member {Set.<module:engine/model/markercollection~Marker>}
+		 */
+		this._unboundMarkerNames = new Set();
+
 		// Default mapper algorithm for mapping model position to view position.
 		this.on( 'modelToViewPosition', ( evt, data ) => {
 			if ( data.viewPosition ) {
@@ -132,6 +151,12 @@ export default class Mapper {
 
 		this._viewToModelMapping.delete( viewElement );
 
+		if ( this._elementToMarkerNames.has( viewElement ) ) {
+			for ( const markerName of this._elementToMarkerNames.get( viewElement ) ) {
+				this._unboundMarkerNames.add( markerName );
+			}
+		}
+
 		if ( this._modelToViewMapping.get( modelElement ) == viewElement ) {
 			this._modelToViewMapping.delete( modelElement );
 		}
@@ -167,10 +192,13 @@ export default class Mapper {
 	 */
 	bindElementToMarker( element, name ) {
 		const elements = this._markerNameToElements.get( name ) || new Set();
-
 		elements.add( element );
 
+		const names = this._elementToMarkerNames.get( element ) || new Set();
+		names.add( name );
+
 		this._markerNameToElements.set( name, elements );
+		this._elementToMarkerNames.set( element, names );
 	}
 
 	/**
@@ -180,15 +208,39 @@ export default class Mapper {
 	 * @param {String} name Marker name.
 	 */
 	unbindElementFromMarkerName( element, name ) {
-		const elements = this._markerNameToElements.get( name );
+		const nameToElements = this._markerNameToElements.get( name );
 
-		if ( elements ) {
-			elements.delete( element );
+		if ( nameToElements ) {
+			nameToElements.delete( element );
 
-			if ( elements.size == 0 ) {
+			if ( nameToElements.size == 0 ) {
 				this._markerNameToElements.delete( name );
 			}
 		}
+
+		const elementToNames = this._elementToMarkerNames.get( element );
+
+		if ( elementToNames ) {
+			elementToNames.delete( name );
+
+			if ( elementToNames.size == 0 ) {
+				this._elementToMarkerNames.delete( element );
+			}
+		}
+	}
+
+	/**
+	 * Returns all marker names of markers which has changed due to unbinding a view element (so it is assumed that the view element
+	 * has been removed, moved or renamed) since the last flush. After returning, the marker names list is cleared.
+	 *
+	 * @returns {Array.<String>}
+	 */
+	flushUnboundMarkerNames() {
+		const markerNames = Array.from( this._unboundMarkerNames );
+
+		this._unboundMarkerNames.clear();
+
+		return markerNames;
 	}
 
 	/**
@@ -198,6 +250,8 @@ export default class Mapper {
 		this._modelToViewMapping = new WeakMap();
 		this._viewToModelMapping = new WeakMap();
 		this._markerNameToElements = new Map();
+		this._elementToMarkerNames = new Map();
+		this._unboundMarkerNames = new Set();
 	}
 
 	/**

+ 10 - 3
packages/ckeditor5-engine/src/model/documentfragment.js

@@ -116,15 +116,22 @@ export default class DocumentFragment {
 	}
 
 	/**
-	 * Checks whether given model tree object is of given type.
+	 * Checks whether this object is of the given type.
 	 *
-	 * Read more in {@link module:engine/model/node~Node#is}.
+	 *		docFrag.is( 'documentFragment' ); // -> true
+	 *		docFrag.is( 'model:documentFragment' ); // -> true
+	 *
+	 *		docFrag.is( 'view:documentFragment' ); // -> false
+	 *		docFrag.is( 'element' ); // -> false
+	 *		docFrag.is( 'node' ); // -> false
+	 *
+	 * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
 	 *
 	 * @param {String} type
 	 * @returns {Boolean}
 	 */
 	is( type ) {
-		return type == 'documentFragment';
+		return type == 'documentFragment' || type == 'model:documentFragment';
 	}
 
 	/**

+ 14 - 8
packages/ckeditor5-engine/src/model/documentselection.js

@@ -367,21 +367,27 @@ export default class DocumentSelection {
 	}
 
 	/**
-	 * Checks whether object is of given type following the convention set by
-	 * {@link module:engine/model/node~Node#is `Node#is()`}.
+	 * Checks whether this object is of the given type.
 	 *
-	 *		const selection = new DocumentSelection( ... );
+	 *		selection.is( 'selection' ); // -> true
+	 *		selection.is( 'documentSelection' ); // -> true
+	 *		selection.is( 'model:selection' ); // -> true
+	 *		selection.is( 'model:documentSelection' ); // -> true
 	 *
-	 *		selection.is( 'selection' ); // true
-	 *		selection.is( 'documentSelection' ); // true
-	 *		selection.is( 'node' ); // false
-	 *		selection.is( 'element' ); // false
+	 *		selection.is( 'view:selection' ); // -> false
+	 *		selection.is( 'element' ); // -> false
+	 *		selection.is( 'node' ); // -> false
+	 *
+	 * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
 	 *
 	 * @param {String} type
 	 * @returns {Boolean}
 	 */
 	is( type ) {
-		return type == 'selection' || type == 'documentSelection';
+		return type == 'selection' ||
+			type == 'model:selection' ||
+			type == 'documentSelection' ||
+			type == 'model:documentSelection';
 	}
 
 	/**

+ 19 - 11
packages/ckeditor5-engine/src/model/element.js

@@ -89,18 +89,24 @@ export default class Element extends Node {
 	}
 
 	/**
-	 * Checks whether this model object is of the given type.
+	 * Checks whether this object is of the given.
 	 *
-	 *		obj.name; // 'listItem'
-	 *		obj instanceof Element; // true
+	 *		element.is( 'element' ); // -> true
+	 *		element.is( 'node' ); // -> true
+	 *		element.is( 'model:element' ); // -> true
+	 *		element.is( 'model:node' ); // -> true
 	 *
-	 *		obj.is( 'element' ); // true
-	 *		obj.is( 'listItem' ); // true
-	 *		obj.is( 'element', 'listItem' ); // true
-	 *		obj.is( 'text' ); // false
-	 *		obj.is( 'element', 'image' ); // false
+	 *		element.is( 'view:element' ); // -> false
+	 *		element.is( 'documentSelection' ); // -> false
 	 *
-	 * Read more in {@link module:engine/model/node~Node#is `Node#is()`}.
+	 * Assuming that the object being checked is an element, you can also check its
+	 * {@link module:engine/model/element~Element#name name}:
+	 *
+	 *		element.is( 'image' ); // -> true if this is an <image> element
+	 *		element.is( 'element', 'image' ); // -> same as above
+	 *		text.is( 'image' ); -> false
+	 *
+	 * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
 	 *
 	 * @param {String} type Type to check when `name` parameter is present.
 	 * Otherwise, it acts like the `name` parameter.
@@ -108,10 +114,12 @@ export default class Element extends Node {
 	 * @returns {Boolean}
 	 */
 	is( type, name = null ) {
+		const cutType = type.replace( /^model:/, '' );
+
 		if ( !name ) {
-			return type == 'element' || type == this.name || super.is( type );
+			return cutType == 'element' || cutType == this.name || super.is( type );
 		} else {
-			return type == 'element' && name == this.name;
+			return cutType == 'element' && name == this.name;
 		}
 	}
 

+ 20 - 0
packages/ckeditor5-engine/src/model/liveposition.js

@@ -63,6 +63,26 @@ export default class LivePosition extends Position {
 		this.stopListening();
 	}
 
+	/**
+	 * Checks whether this object is of the given.
+	 *
+	 *		livePosition.is( 'position' ); // -> true
+	 *		livePosition.is( 'model:position' ); // -> true
+	 *		livePosition.is( 'liveposition' ); // -> true
+	 *		livePosition.is( 'model:livePosition' ); // -> true
+	 *
+	 *		livePosition.is( 'view:position' ); // -> false
+	 *		livePosition.is( 'documentSelection' ); // -> false
+	 *
+	 * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
+	 *
+	 * @param {String} type
+	 * @returns {Boolean}
+	 */
+	is( type ) {
+		return type == 'livePosition' || type == 'model:livePosition' || super.is( type );
+	}
+
 	/**
 	 * Creates a {@link module:engine/model/position~Position position instance}, which is equal to this live position.
 	 *

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

@@ -40,6 +40,26 @@ export default class LiveRange extends Range {
 		this.stopListening();
 	}
 
+	/**
+	 * Checks whether this object is of the given.
+	 *
+	 *		liveRange.is( 'range' ); // -> true
+	 *		liveRange.is( 'model:range' ); // -> true
+	 *		liveRange.is( 'liveRange' ); // -> true
+	 *		liveRange.is( 'model:liveRange' ); // -> true
+	 *
+	 *		liveRange.is( 'view:range' ); // -> false
+	 *		liveRange.is( 'documentSelection' ); // -> false
+	 *
+	 * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
+	 *
+	 * @param {String} type
+	 * @returns {Boolean}
+	 */
+	is( type ) {
+		return type == 'liveRange' || type == 'model:liveRange' || super.is( type );
+	}
+
 	/**
 	 * Creates a {@link module:engine/model/range~Range range instance} that is equal to this live range.
 	 *

+ 18 - 0
packages/ckeditor5-engine/src/model/markercollection.js

@@ -448,6 +448,24 @@ class Marker {
 		return this._liveRange.toRange();
 	}
 
+	/**
+	 * Checks whether this object is of the given.
+	 *
+	 *		marker.is( 'marker' ); // -> true
+	 *		marker.is( 'model:marker' ); // -> true
+	 *
+	 *		marker.is( 'view:element' ); // -> false
+	 *		marker.is( 'documentSelection' ); // -> false
+	 *
+	 * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
+	 *
+	 * @param {String} type
+	 * @returns {Boolean}
+	 */
+	is( type ) {
+		return type == 'marker' || type == 'model:marker';
+	}
+
 	/**
 	 * Binds new live range to the marker and detach the old one if is attached.
 	 *

+ 47 - 23
packages/ckeditor5-engine/src/model/node.js

@@ -396,6 +396,53 @@ export default class Node {
 		return json;
 	}
 
+	/**
+	 * Checks whether this object is of the given type.
+	 *
+	 * This method is useful when processing model objects that are of unknown type. For example, a function
+	 * may return a {@link module:engine/model/documentfragment~DocumentFragment} or a {@link module:engine/model/node~Node}
+	 * that can be either a text node or an element. This method can be used to check what kind of object is returned.
+	 *
+	 *		someObject.is( 'element' ); // -> true if this is an element
+	 *		someObject.is( 'node' ); // -> true if this is a node (a text node or an element)
+	 *		someObject.is( 'documentFragment' ); // -> true if this is a document fragment
+	 *
+	 * Since this method is also available on a range of view objects, you can prefix the type of the object with
+	 * `model:` or `view:` to check, for example, if this is the model's or view's element:
+	 *
+	 *		modelElement.is( 'model:element' ); // -> true
+	 *		modelElement.is( 'view:element' ); // -> false
+	 *
+	 * By using this method it is also possible to check a name of an element:
+	 *
+	 *		imageElement.is( 'image' ); // -> true
+	 *		imageElement.is( 'element', 'image' ); // -> same as above
+	 *		imageElement.is( 'model:element', 'image' ); // -> same as above, but more precise
+	 *
+	 * The list of model objects which implement the `is()` method:
+	 *
+	 * * {@link module:engine/model/node~Node#is `Node#is()`}
+	 * * {@link module:engine/model/text~Text#is `Text#is()`}
+	 * * {@link module:engine/model/element~Element#is `Element#is()`}
+	 * * {@link module:engine/model/rootelement~RootElement#is `RootElement#is()`}
+	 * * {@link module:engine/model/position~Position#is `Position#is()`}
+	 * * {@link module:engine/model/liveposition~LivePosition#is `LivePosition#is()`}
+	 * * {@link module:engine/model/range~Range#is `Range#is()`}
+	 * * {@link module:engine/model/liverange~LiveRange#is `LiveRange#is()`}
+	 * * {@link module:engine/model/documentfragment~DocumentFragment#is `DocumentFragment#is()`}
+	 * * {@link module:engine/model/selection~Selection#is `Selection#is()`}
+	 * * {@link module:engine/model/documentselection~DocumentSelection#is `DocumentSelection#is()`}
+	 * * {@link module:engine/model/markercollection~Marker#is `Marker#is()`}
+	 * * {@link module:engine/model/textproxy~TextProxy#is `TextProxy#is()`}
+	 *
+	 * @method #is
+	 * @param {String} type
+	 * @returns {Boolean}
+	 */
+	is( type ) {
+		return type == 'node' || type == 'model:node';
+	}
+
 	/**
 	 * Creates a copy of this node, that is a node with exactly same attributes, and returns it.
 	 *
@@ -460,29 +507,6 @@ export default class Node {
 	_clearAttributes() {
 		this._attrs.clear();
 	}
-
-	/**
-	 * Checks whether given model tree object is of given type.
-	 *
-	 * This method is useful when processing model tree objects that are of unknown type. For example, a function
-	 * may return {@link module:engine/model/documentfragment~DocumentFragment} or {@link module:engine/model/node~Node}
-	 * that can be either text node or element. This method can be used to check what kind of object is returned.
-	 *
-	 *		obj.is( 'node' ); // true for any node, false for document fragment and text fragment
-	 *		obj.is( 'documentFragment' ); // true for document fragment, false for any node
-	 *		obj.is( 'element' ); // true for any element, false for text node or document fragment
-	 *		obj.is( 'element', 'paragraph' ); // true only for element which name is 'paragraph'
-	 *		obj.is( 'paragraph' ); // shortcut for obj.is( 'element', 'paragraph' )
-	 *		obj.is( 'text' ); // true for text node, false for element and document fragment
-	 *		obj.is( 'textProxy' ); // true for text proxy object
-	 *
-	 * @method #is
-	 * @param {'element'|'rootElement'|'text'|'textProxy'|'documentFragment'} type
-	 * @returns {Boolean}
-	 */
-	is( type ) {
-		return type == 'node';
-	}
 }
 
 /**

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

@@ -101,14 +101,14 @@ export function transform( a, b, context = {} ) {
 
 		return transformationFunction( a, b, context );
 	} catch ( e ) {
-		// @if CK_DEBUG // console.error( 'Error during operation transformation!', e.message );
-		// @if CK_DEBUG // console.error( 'Transformed operation', a );
-		// @if CK_DEBUG // console.error( 'Operation transformed by', b );
-		// @if CK_DEBUG // console.error( 'context.aIsStrong', context.aIsStrong );
-		// @if CK_DEBUG // console.error( 'context.aWasUndone', context.aWasUndone );
-		// @if CK_DEBUG // console.error( 'context.bWasUndone', context.bWasUndone );
-		// @if CK_DEBUG // console.error( 'context.abRelation', context.abRelation );
-		// @if CK_DEBUG // console.error( 'context.baRelation', context.baRelation );
+		// @if CK_DEBUG // console.warn( 'Error during operation transformation!', e.message );
+		// @if CK_DEBUG // console.warn( 'Transformed operation', a );
+		// @if CK_DEBUG // console.warn( 'Operation transformed by', b );
+		// @if CK_DEBUG // console.warn( 'context.aIsStrong', context.aIsStrong );
+		// @if CK_DEBUG // console.warn( 'context.aWasUndone', context.aWasUndone );
+		// @if CK_DEBUG // console.warn( 'context.bWasUndone', context.bWasUndone );
+		// @if CK_DEBUG // console.warn( 'context.abRelation', context.abRelation );
+		// @if CK_DEBUG // console.warn( 'context.baRelation', context.baRelation );
 
 		throw e;
 	}

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

@@ -525,6 +525,24 @@ export default class Position {
 		}
 	}
 
+	/**
+	 * Checks whether this object is of the given.
+	 *
+	 *		position.is( 'position' ); // -> true
+	 *		position.is( 'model:position' ); // -> true
+	 *
+	 *		position.is( 'view:position' ); // -> false
+	 *		position.is( 'documentSelection' ); // -> false
+	 *
+	 * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
+	 *
+	 * @param {String} type
+	 * @returns {Boolean}
+	 */
+	is( type ) {
+		return type == 'position' || type == 'model:position';
+	}
+
 	/**
 	 * Checks if two positions are in the same parent.
 	 *

+ 18 - 0
packages/ckeditor5-engine/src/model/range.js

@@ -143,6 +143,24 @@ export default class Range {
 		return this.containsPosition( pos ) || this.start.isEqual( pos );
 	}
 
+	/**
+	 * Checks whether this object is of the given.
+	 *
+	 *		range.is( 'range' ); // -> true
+	 *		range.is( 'model:range' ); // -> true
+	 *
+	 *		range.is( 'view:range' ); // -> false
+	 *		range.is( 'documentSelection' ); // -> false
+	 *
+	 * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
+	 *
+	 * @param {String} type
+	 * @returns {Boolean}
+	 */
+	is( type ) {
+		return type == 'range' || type == 'model:range';
+	}
+
 	/**
 	 * Two ranges are equal if their {@link #start} and {@link #end} positions are equal.
 	 *

+ 28 - 3
packages/ckeditor5-engine/src/model/rootelement.js

@@ -55,13 +55,38 @@ export default class RootElement extends Element {
 	}
 
 	/**
-	 * @inheritDoc
+	 * Checks whether this object is of the given.
+	 *
+	 *		rootElement.is( 'rootElement' ); // -> true
+	 *		rootElement.is( 'element' ); // -> true
+	 *		rootElement.is( 'node' ); // -> true
+	 *		rootElement.is( 'model:rootElement' ); // -> true
+	 *		rootElement.is( 'model:element' ); // -> true
+	 *		rootElement.is( 'model:node' ); // -> true
+	 *
+	 *		rootElement.is( 'view:element' ); // -> false
+	 *		rootElement.is( 'documentFragment' ); // -> false
+	 *
+	 * Assuming that the object being checked is an element, you can also check its
+	 * {@link module:engine/model/element~Element#name name}:
+	 *
+	 *		rootElement.is( '$root' ); // -> true if this is a $root element
+	 *		rootElement.is( 'rootElement', '$root' ); // -> same as above
+	 *		text.is( '$root' ); -> false
+	 *
+	 * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
+	 *
+	 * @param {String} type Type to check when `name` parameter is present.
+	 * Otherwise, it acts like the `name` parameter.
+	 * @param {String} [name] Element name.
+	 * @returns {Boolean}
 	 */
 	is( type, name ) {
+		const cutType = type.replace( 'model:', '' );
 		if ( !name ) {
-			return type == 'rootElement' || super.is( type );
+			return cutType == 'rootElement' || super.is( type );
 		} else {
-			return ( type == 'rootElement' && name == this.name ) || super.is( type, name );
+			return ( cutType == 'rootElement' && name == this.name ) || super.is( type, name );
 		}
 	}
 

+ 8 - 7
packages/ckeditor5-engine/src/model/selection.js

@@ -623,20 +623,21 @@ export default class Selection {
 	}
 
 	/**
-	 * Checks whether object is of given type following the convention set by
-	 * {@link module:engine/model/node~Node#is `Node#is()`}.
+	 * Checks whether this object is of the given.
 	 *
-	 *		const selection = new Selection( ... );
+	 *		selection.is( 'selection' ); // -> true
+	 *		selection.is( 'model:selection' ); // -> true
 	 *
-	 *		selection.is( 'selection' ); // true
-	 *		selection.is( 'node' ); // false
-	 *		selection.is( 'element' ); // false
+	 *		selection.is( 'view:selection' ); // -> false
+	 *		selection.is( 'range' ); // -> false
+	 *
+	 * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
 	 *
 	 * @param {String} type
 	 * @returns {Boolean}
 	 */
 	is( type ) {
-		return type == 'selection';
+		return type == 'selection' || type == 'model:selection';
 	}
 
 	/**

+ 16 - 2
packages/ckeditor5-engine/src/model/text.js

@@ -63,10 +63,24 @@ export default class Text extends Node {
 	}
 
 	/**
-	 * @inheritDoc
+	 * Checks whether this object is of the given.
+	 *
+	 *		text.is( 'text' ); // -> true
+	 *		text.is( 'node' ); // -> true
+	 *		text.is( 'model:text' ); // -> true
+	 *		text.is( 'model:node' ); // -> true
+	 *
+	 *		text.is( 'view:text' ); // -> false
+	 *		text.is( 'documentSelection' ); // -> false
+	 *
+	 * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
+	 *
+	 * @param {String} type Type to check when `name` parameter is present.
+	 * Otherwise, it acts like the `name` parameter.
+	 * @returns {Boolean}
 	 */
 	is( type ) {
-		return type == 'text' || super.is( type );
+		return type == 'text' || type == 'model:text' || super.is( type );
 	}
 
 	/**

+ 9 - 3
packages/ckeditor5-engine/src/model/textproxy.js

@@ -173,15 +173,21 @@ export default class TextProxy {
 	}
 
 	/**
-	 * Checks whether given model tree object is of given type.
+	 * Checks whether this object is of the given.
 	 *
-	 * Read more in {@link module:engine/model/node~Node#is}.
+	 *		textProxy.is( 'textProxy' ); // -> true
+	 *		textProxy.is( 'model:textProxy' ); // -> true
+	 *
+	 *		textProxy.is( 'view:textProxy' ); // -> false
+	 *		textProxy.is( 'range' ); // -> false
+	 *
+	 * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
 	 *
 	 * @param {String} type
 	 * @returns {Boolean}
 	 */
 	is( type ) {
-		return type == 'textProxy';
+		return type == 'textProxy' || type == 'model:textProxy';
 	}
 
 	/**

+ 29 - 3
packages/ckeditor5-engine/src/view/attributeelement.js

@@ -125,13 +125,39 @@ export default class AttributeElement extends Element {
 	}
 
 	/**
-	 * @inheritDoc
+	 * Checks whether this object is of the given.
+	 *
+	 *		attributeElement.is( 'attributeElement' ); // -> true
+	 *		attributeElement.is( 'element' ); // -> true
+	 *		attributeElement.is( 'node' ); // -> true
+	 *		attributeElement.is( 'view:attributeElement' ); // -> true
+	 *		attributeElement.is( 'view:element' ); // -> true
+	 *		attributeElement.is( 'view:node' ); // -> true
+	 *
+	 *		attributeElement.is( 'model:element' ); // -> false
+	 *		attributeElement.is( 'documentFragment' ); // -> false
+	 *
+	 * Assuming that the object being checked is an attribute element, you can also check its
+	 * {@link module:engine/view/attributeelement~AttributeElement#name name}:
+	 *
+	 *		attributeElement.is( 'b' ); // -> true if this is a bold element
+	 *		attributeElement.is( 'attributeElement', 'b' ); // -> same as above
+	 *		text.is( 'b' ); -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
+	 *
+	 * @param {String} type Type to check when `name` parameter is present.
+	 * Otherwise, it acts like the `name` parameter.
+	 * @param {String} [name] Element name.
+	 * @returns {Boolean}
 	 */
 	is( type, name = null ) {
+		const cutType = type && type.replace( /^view:/, '' );
+
 		if ( !name ) {
-			return type == 'attributeElement' || super.is( type );
+			return cutType == 'attributeElement' || super.is( type );
 		} else {
-			return ( type == 'attributeElement' && name == this.name ) || super.is( type, name );
+			return ( cutType == 'attributeElement' && name == this.name ) || super.is( type, name );
 		}
 	}
 

+ 28 - 3
packages/ckeditor5-engine/src/view/containerelement.js

@@ -51,13 +51,38 @@ export default class ContainerElement extends Element {
 	}
 
 	/**
-	 * @inheritDoc
+	 * Checks whether this object is of the given.
+	 *
+	 *		containerElement.is( 'containerElement' ); // -> true
+	 *		containerElement.is( 'element' ); // -> true
+	 *		containerElement.is( 'node' ); // -> true
+	 *		containerElement.is( 'view:containerElement' ); // -> true
+	 *		containerElement.is( 'view:element' ); // -> true
+	 *		containerElement.is( 'view:node' ); // -> true
+	 *
+	 *		containerElement.is( 'model:element' ); // -> false
+	 *		containerElement.is( 'documentFragment' ); // -> false
+	 *
+	 * Assuming that the object being checked is a container element, you can also check its
+	 * {@link module:engine/view/containerelement~ContainerElement#name name}:
+	 *
+	 *		containerElement.is( 'div' ); // -> true if this is a div container element
+	 *		containerElement.is( 'contaienrElement', 'div' ); // -> same as above
+	 *		text.is( 'div' ); -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
+	 *
+	 * @param {String} type Type to check when `name` parameter is present.
+	 * Otherwise, it acts like the `name` parameter.
+	 * @param {String} [name] Element name.
+	 * @returns {Boolean}
 	 */
 	is( type, name = null ) {
+		const cutType = type && type.replace( /^view:/, '' );
 		if ( !name ) {
-			return type == 'containerElement' || super.is( type );
+			return cutType == 'containerElement' || super.is( type );
 		} else {
-			return ( type == 'containerElement' && name == this.name ) || super.is( type, name );
+			return ( cutType == 'containerElement' && name == this.name ) || super.is( type, name );
 		}
 	}
 }

+ 10 - 3
packages/ckeditor5-engine/src/view/documentfragment.js

@@ -94,15 +94,22 @@ export default class DocumentFragment {
 	}
 
 	/**
-	 * Checks whether given view tree object is of given type.
+	 * Checks whether this object is of the given type.
 	 *
-	 * Read more in {@link module:engine/view/node~Node#is}.
+	 *		docFrag.is( 'documentFragment' ); // -> true
+	 *		docFrag.is( 'view:documentFragment' ); // -> true
+	 *
+	 *		docFrag.is( 'model:documentFragment' ); // -> false
+	 *		docFrag.is( 'element' ); // -> false
+	 *		docFrag.is( 'node' ); // -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
 	 *
 	 * @param {String} type
 	 * @returns {Boolean}
 	 */
 	is( type ) {
-		return type == 'documentFragment';
+		return type == 'documentFragment' || type == 'view:documentFragment';
 	}
 
 	/**

+ 14 - 8
packages/ckeditor5-engine/src/view/documentselection.js

@@ -275,21 +275,27 @@ export default class DocumentSelection {
 	}
 
 	/**
-	 * Checks whether object is of given type following the convention set by
-	 * {@link module:engine/view/node~Node#is `Node#is()`}.
+	 * Checks whether this object is of the given type.
 	 *
-	 *		const selection = new DocumentSelection( ... );
+	 *		docSelection.is( 'selection' ); // -> true
+	 *		docSelection.is( 'documentSelection' ); // -> true
+	 *		docSelection.is( 'view:selection' ); // -> true
+	 *		docSelection.is( 'view:documentSelection' ); // -> true
 	 *
-	 *		selection.is( 'selection' ); // true
-	 *		selection.is( 'documentSelection' ); // true
-	 *		selection.is( 'node' ); // false
-	 *		selection.is( 'element' ); // false
+	 *		docSelection.is( 'model:documentSelection' ); // -> false
+	 *		docSelection.is( 'element' ); // -> false
+	 *		docSelection.is( 'node' ); // -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
 	 *
 	 * @param {String} type
 	 * @returns {Boolean}
 	 */
 	is( type ) {
-		return type == 'selection' || type == 'documentSelection';
+		return type == 'selection' ||
+			type == 'documentSelection' ||
+			type == 'view:selection' ||
+			type == 'view:documentSelection';
 	}
 
 	/**

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

@@ -69,7 +69,7 @@ export default class DowncastWriter {
 	 *		writer.setSelection( range );
 	 *
 	 *		// Sets selection to given ranges.
-	 * 		const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
+	 * 		const ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];
 	 *		writer.setSelection( range );
 	 *
 	 *		// Sets selection to the other selection.

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

@@ -67,13 +67,38 @@ export default class EditableElement extends ContainerElement {
 	}
 
 	/**
-	 * @inheritDoc
+	 * Checks whether this object is of the given.
+	 *
+	 *		editableElement.is( 'editableElement' ); // -> true
+	 *		editableElement.is( 'element' ); // -> true
+	 *		editableElement.is( 'node' ); // -> true
+	 *		editableElement.is( 'view:editableElement' ); // -> true
+	 *		editableElement.is( 'view:element' ); // -> true
+	 *		editableElement.is( 'view:node' ); // -> true
+	 *
+	 *		editableElement.is( 'model:element' ); // -> false
+	 *		editableElement.is( 'documentFragment' ); // -> false
+	 *
+	 * Assuming that the object being checked is an editbale element, you can also check its
+	 * {@link module:engine/view/editableelement~EditableElement#name name}:
+	 *
+	 *		editableElement.is( 'div' ); // -> true if this is a div element
+	 *		editableElement.is( 'editableElement', 'div' ); // -> same as above
+	 *		text.is( 'div' ); -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
+	 *
+	 * @param {String} type Type to check when `name` parameter is present.
+	 * Otherwise, it acts like the `name` parameter.
+	 * @param {String} [name] Element name.
+	 * @returns {Boolean}
 	 */
 	is( type, name = null ) {
+		const cutType = type && type.replace( /^view:/, '' );
 		if ( !name ) {
-			return type == 'editableElement' || super.is( type );
+			return cutType == 'editableElement' || super.is( type );
 		} else {
-			return ( type == 'editableElement' && name == this.name ) || super.is( type, name );
+			return ( cutType == 'editableElement' && name == this.name ) || super.is( type, name );
 		}
 	}
 

+ 21 - 10
packages/ckeditor5-engine/src/view/element.js

@@ -147,25 +147,36 @@ export default class Element extends Node {
 	}
 
 	/**
-	 * Checks whether this view object is of the given type.
+	 * Checks whether this object is of the given.
 	 *
-	 *		obj.is( 'element' ); // true
-	 *		obj.is( 'li' ); // true
-	 *		obj.is( 'element', 'li' ); // true
-	 *		obj.is( 'text' ); // false
-	 *		obj.is( 'element', 'img' ); // false
+	 *		element.is( 'element' ); // -> true
+	 *		element.is( 'node' ); // -> true
+	 *		element.is( 'view:element' ); // -> true
+	 *		element.is( 'view:node' ); // -> true
 	 *
-	 * Read more in {@link module:engine/view/node~Node#is `Node#is()`}.
+	 *		element.is( 'model:element' ); // -> false
+	 *		element.is( 'documentSelection' ); // -> false
 	 *
-	 * @param {String} type
+	 * Assuming that the object being checked is an element, you can also check its
+	 * {@link module:engine/view/element~Element#name name}:
+	 *
+	 *		element.is( 'img' ); // -> true if this is an <img> element
+	 *		element.is( 'element', 'img' ); // -> same as above
+	 *		text.is( 'img' ); -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
+	 *
+	 * @param {String} type Type to check when `name` parameter is present.
+	 * Otherwise, it acts like the `name` parameter.
 	 * @param {String} [name] Element name.
 	 * @returns {Boolean}
 	 */
 	is( type, name = null ) {
+		const cutType = type.replace( /^view:/, '' );
 		if ( !name ) {
-			return type == 'element' || type == this.name || super.is( type );
+			return cutType == 'element' || cutType == this.name || super.is( type );
 		} else {
-			return type == 'element' && name == this.name;
+			return cutType == 'element' && name == this.name;
 		}
 	}
 

+ 28 - 3
packages/ckeditor5-engine/src/view/emptyelement.js

@@ -44,13 +44,38 @@ export default class EmptyElement extends Element {
 	}
 
 	/**
-	 * @inheritDoc
+	 * Checks whether this object is of the given.
+	 *
+	 *		emptyElement.is( 'emptyElement' ); // -> true
+	 *		emptyElement.is( 'element' ); // -> true
+	 *		emptyElement.is( 'node' ); // -> true
+	 *		emptyElement.is( 'view:emptyElement' ); // -> true
+	 *		emptyElement.is( 'view:element' ); // -> true
+	 *		emptyElement.is( 'view:node' ); // -> true
+	 *
+	 *		emptyElement.is( 'model:element' ); // -> false
+	 *		emptyElement.is( 'documentFragment' ); // -> false
+	 *
+	 * Assuming that the object being checked is an empty element, you can also check its
+	 * {@link module:engine/view/emptyelement~EmptyElement#name name}:
+	 *
+	 *		emptyElement.is( 'img' ); // -> true if this is a img element
+	 *		emptyElement.is( 'emptyElement', 'img' ); // -> same as above
+	 *		text.is( 'img' ); -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
+	 *
+	 * @param {String} type Type to check when `name` parameter is present.
+	 * Otherwise, it acts like the `name` parameter.
+	 * @param {String} [name] Element name.
+	 * @returns {Boolean}
 	 */
 	is( type, name = null ) {
+		const cutType = type.replace( /^view:/, '' );
 		if ( !name ) {
-			return type == 'emptyElement' || super.is( type );
+			return cutType == 'emptyElement' || super.is( type );
 		} else {
-			return ( type == 'emptyElement' && name == this.name ) || super.is( type, name );
+			return ( cutType == 'emptyElement' && name == this.name ) || super.is( type, name );
 		}
 	}
 

+ 40 - 13
packages/ckeditor5-engine/src/view/node.js

@@ -290,25 +290,52 @@ export default class Node {
 	}
 
 	/**
-	 * Checks whether this view object is of the given type.
+	 * Checks whether this object is of the given type.
 	 *
-	 * This method is useful when processing view tree objects that are of unknown type. For example, a function
-	 * may return {@link module:engine/view/documentfragment~DocumentFragment} or {@link module:engine/view/node~Node}
-	 * that can be either text node or element. This method can be used to check what kind of object is returned.
+	 * This method is useful when processing view objects that are of unknown type. For example, a function
+	 * may return a {@link module:engine/view/documentfragment~DocumentFragment} or a {@link module:engine/view/node~Node}
+	 * that can be either a text node or an element. This method can be used to check what kind of object is returned.
 	 *
-	 *		obj.is( 'node' ); // true for any node, false for document fragment and text fragment
-	 *		obj.is( 'documentFragment' ); // true for document fragment, false for any node
-	 *		obj.is( 'element' ); // true for any element, false for text node or document fragment
-	 *		obj.is( 'element', 'p' ); // true only for element which name is 'p'
-	 *		obj.is( 'p' ); // shortcut for obj.is( 'element', 'p' )
-	 *		obj.is( 'text' ); // true for text node, false for element and document fragment
+	 *		someObject.is( 'element' ); // -> true if this is an element
+	 *		someObject.is( 'node' ); // -> true if this is a node (a text node or an element)
+	 *		someObject.is( 'documentFragment' ); // -> true if this is a document fragment
 	 *
-	 * @param {'element'|'containerElement'|'attributeElement'|'emptyElement'|'uiElement'|
-	 * 'rootElement'|'documentFragment'|'text'|'textProxy'} type
+	 * Since this method is also available on a range of model objects, you can prefix the type of the object with
+	 * `model:` or `view:` to check, for example, if this is the model's or view's element:
+	 *
+	 *		viewElement.is( 'view:element' ); // -> true
+	 *		viewElement.is( 'model:element' ); // -> false
+	 *
+	 * By using this method it is also possible to check a name of an element:
+	 *
+	 *		imgElement.is( 'img' ); // -> true
+	 *		imgElement.is( 'element', 'img' ); // -> same as above
+	 *		imgElement.is( 'view:element', 'img' ); // -> same as above, but more precise
+	 *
+	 * The list of view objects which implement the `is()` method:
+	 *
+	 * * {@link module:engine/view/attributeelement~AttributeElement#is `AttributeElement#is()`}
+	 * * {@link module:engine/view/containerelement~ContainerElement#is `ContainerElement#is()`}
+	 * * {@link module:engine/view/documentfragment~DocumentFragment#is `DocumentFragment#is()`}
+	 * * {@link module:engine/view/documentselection~DocumentSelection#is `DocumentSelection#is()`}
+	 * * {@link module:engine/view/editableelement~EditableElement#is `EditableElement#is()`}
+	 * * {@link module:engine/view/element~Element#is `Element#is()`}
+	 * * {@link module:engine/view/emptyelement~EmptyElement#is `EmptyElement#is()`}
+	 * * {@link module:engine/view/node~Node#is `Node#is()`}
+	 * * {@link module:engine/view/position~Position#is `Position#is()`}
+	 * * {@link module:engine/view/range~Range#is `Range#is()`}
+	 * * {@link module:engine/view/rooteditableelement~RootEditableElement#is `RootEditableElement#is()`}
+	 * * {@link module:engine/view/selection~Selection#is `Selection#is()`}
+	 * * {@link module:engine/view/text~Text#is `Text#is()`}
+	 * * {@link module:engine/view/textproxy~TextProxy#is `TextProxy#is()`}
+	 * * {@link module:engine/view/uielement~UIElement#is `UIElement#is()`}
+	 *
+	 * @method #is
+	 * @param {String} type
 	 * @returns {Boolean}
 	 */
 	is( type ) {
-		return type == 'node';
+		return type == 'node' || type == 'view:node';
 	}
 
 	/**

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

@@ -206,6 +206,25 @@ export default class Position {
 		return i === 0 ? null : ancestorsA[ i - 1 ];
 	}
 
+	/**
+	 * Checks whether this object is of the given type.
+	 *
+	 *		position.is( 'position' ); // -> true
+	 *		position.is( 'view:position' ); // -> true
+	 *
+	 *		position.is( 'model:position' ); // -> false
+	 *		position.is( 'element' ); // -> false
+	 *		position.is( 'range' ); // -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
+	 *
+	 * @param {String} type
+	 * @returns {Boolean}
+	 */
+	is( type ) {
+		return type == 'position' || type == 'view:position';
+	}
+
 	/**
 	 * Checks whether this position equals given position.
 	 *

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

@@ -394,6 +394,25 @@ export default class Range {
 		}
 	}
 
+	/**
+	 * Checks whether this object is of the given type.
+	 *
+	 *		range.is( 'range' ); // -> true
+	 *		range.is( 'view:range' ); // -> true
+	 *
+	 *		range.is( 'model:range' ); // -> false
+	 *		range.is( 'element' ); // -> false
+	 *		range.is( 'selection' ); // -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
+	 *
+	 * @param {String} type
+	 * @returns {Boolean}
+	 */
+	is( type ) {
+		return type == 'range' || type == 'view:range';
+	}
+
 	/**
 	 * Checks and returns whether this range intersects with the given range.
 	 *

+ 30 - 3
packages/ckeditor5-engine/src/view/rooteditableelement.js

@@ -38,13 +38,40 @@ export default class RootEditableElement extends EditableElement {
 	}
 
 	/**
-	 * @inheritDoc
+	 * Checks whether this object is of the given.
+	 *
+	 *		rootEditableElement.is( 'rootEditableElement' ); // -> true
+	 *		rootEditableElement.is( 'editableElement' ); // -> true
+	 *		rootEditableElement.is( 'element' ); // -> true
+	 *		rootEditableElement.is( 'node' ); // -> true
+	 *		rootEditableElement.is( 'view:rootEditableElement' ); // -> true
+	 *		rootEditableElement.is( 'view:editableElement' ); // -> true
+	 *		rootEditableElement.is( 'view:element' ); // -> true
+	 *		rootEditableElement.is( 'view:node' ); // -> true
+	 *
+	 *		rootEditableElement.is( 'model:element' ); // -> false
+	 *		rootEditableElement.is( 'documentFragment' ); // -> false
+	 *
+	 * Assuming that the object being checked is a root editbale element, you can also check its
+	 * {@link module:engine/view/rooteditableelement~RootEditableElement#name name}:
+	 *
+	 *		rootEditableElement.is( 'div' ); // -> true if this is a div root editable element
+	 *		rootEditableElement.is( 'rootEditableElement', 'div' ); // -> same as above
+	 *		text.is( 'div' ); -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
+	 *
+	 * @param {String} type Type to check when `name` parameter is present.
+	 * Otherwise, it acts like the `name` parameter.
+	 * @param {String} [name] Element name.
+	 * @returns {Boolean}
 	 */
 	is( type, name = null ) {
+		const cutType = type.replace( /^view:/, '' );
 		if ( !name ) {
-			return type == 'rootElement' || super.is( type );
+			return cutType == 'rootElement' || super.is( type );
 		} else {
-			return ( type == 'rootElement' && name == this.name ) || super.is( type, name );
+			return ( cutType == 'rootElement' && name == this.name ) || super.is( type, name );
 		}
 	}
 

+ 9 - 7
packages/ckeditor5-engine/src/view/selection.js

@@ -598,20 +598,22 @@ export default class Selection {
 	}
 
 	/**
-	 * Checks whether object is of given type following the convention set by
-	 * {@link module:engine/view/node~Node#is `Node#is()`}.
+	 * Checks whether this object is of the given type.
 	 *
-	 *		const selection = new Selection( ... );
+	 *		selection.is( 'selection' ); // -> true
+	 *		selection.is( 'view:selection' ); // -> true
 	 *
-	 *		selection.is( 'selection' ); // true
-	 *		selection.is( 'node' ); // false
-	 *		selection.is( 'element' ); // false
+	 *		selection.is( 'model:selection' ); // -> false
+	 *		selection.is( 'element' ); // -> false
+	 *		selection.is( 'range' ); // -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
 	 *
 	 * @param {String} type
 	 * @returns {Boolean}
 	 */
 	is( type ) {
-		return type == 'selection';
+		return type == 'selection' || type == 'view:selection';
 	}
 
 	/**

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

@@ -42,10 +42,24 @@ export default class Text extends Node {
 	}
 
 	/**
-	 * @inheritDoc
+	 * Checks whether this object is of the given type.
+	 *
+	 *		text.is( 'text' ); // -> true
+	 *		text.is( 'node' ); // -> true
+	 *		text.is( 'view:text' ); // -> true
+	 *		text.is( 'view:node' ); // -> true
+	 *
+	 *		text.is( 'model:text' ); // -> false
+	 *		text.is( 'element' ); // -> false
+	 *		text.is( 'range' ); // -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
+	 *
+	 * @param {String} type
+	 * @returns {Boolean}
 	 */
 	is( type ) {
-		return type == 'text' || super.is( type );
+		return type == 'text' || type == 'view:text' || super.is( type );
 	}
 
 	/**

+ 10 - 3
packages/ckeditor5-engine/src/view/textproxy.js

@@ -141,15 +141,22 @@ export default class TextProxy {
 	}
 
 	/**
-	 * Checks whether given view tree object is of given type.
+	 * Checks whether this object is of the given type.
 	 *
-	 * Read more in {@link module:engine/view/node~Node#is}.
+	 *		textProxy.is( 'textProxy' ); // -> true
+	 *		textProxy.is( 'view:textProxy' ); // -> true
+	 *
+	 *		textProxy.is( 'model:textProxy' ); // -> false
+	 *		textProxy.is( 'element' ); // -> false
+	 *		textProxy.is( 'range' ); // -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
 	 *
 	 * @param {String} type
 	 * @returns {Boolean}
 	 */
 	is( type ) {
-		return type == 'textProxy';
+		return type == 'textProxy' || type == 'view:textProxy';
 	}
 
 	/**

+ 28 - 3
packages/ckeditor5-engine/src/view/uielement.js

@@ -57,13 +57,38 @@ export default class UIElement extends Element {
 	}
 
 	/**
-	 * @inheritDoc
+	 * Checks whether this object is of the given.
+	 *
+	 *		uiElement.is( 'uiElement' ); // -> true
+	 *		uiElement.is( 'element' ); // -> true
+	 *		uiElement.is( 'node' ); // -> true
+	 *		uiElement.is( 'view:uiElement' ); // -> true
+	 *		uiElement.is( 'view:element' ); // -> true
+	 *		uiElement.is( 'view:node' ); // -> true
+	 *
+	 *		uiElement.is( 'model:element' ); // -> false
+	 *		uiElement.is( 'documentFragment' ); // -> false
+	 *
+	 * Assuming that the object being checked is an ui element, you can also check its
+	 * {@link module:engine/view/uielement~UIElement#name name}:
+	 *
+	 *		uiElement.is( 'span' ); // -> true if this is a span ui element
+	 *		uiElement.is( 'uiElement', 'span' ); // -> same as above
+	 *		text.is( 'span' ); -> false
+	 *
+	 * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
+	 *
+	 * @param {String} type Type to check when `name` parameter is present.
+	 * Otherwise, it acts like the `name` parameter.
+	 * @param {String} [name] Element name.
+	 * @returns {Boolean}
 	 */
 	is( type, name = null ) {
+		const cutType = type.replace( /^view:/, '' );
 		if ( !name ) {
-			return type == 'uiElement' || super.is( type );
+			return cutType == 'uiElement' || super.is( type );
 		} else {
-			return ( type == 'uiElement' && name == this.name ) || super.is( type, name );
+			return ( cutType == 'uiElement' && name == this.name ) || super.is( type, name );
 		}
 	}
 

+ 34 - 8
packages/ckeditor5-engine/tests/conversion/downcastdispatcher.js

@@ -4,6 +4,8 @@
  */
 
 import DowncastDispatcher from '../../src/conversion/downcastdispatcher';
+import Mapper from '../../src/conversion/mapper';
+
 import Model from '../../src/model/model';
 import ModelText from '../../src/model/text';
 import ModelElement from '../../src/model/element';
@@ -13,13 +15,14 @@ import View from '../../src/view/view';
 import ViewContainerElement from '../../src/view/containerelement';
 
 describe( 'DowncastDispatcher', () => {
-	let dispatcher, doc, root, differStub, model, view;
+	let dispatcher, doc, root, differStub, model, view, mapper;
 
 	beforeEach( () => {
 		model = new Model();
 		view = new View();
 		doc = model.document;
-		dispatcher = new DowncastDispatcher();
+		mapper = new Mapper();
+		dispatcher = new DowncastDispatcher( { mapper } );
 		root = doc.createRoot();
 
 		differStub = {
@@ -48,7 +51,7 @@ describe( 'DowncastDispatcher', () => {
 			differStub.getChanges = () => [ { type: 'insert', position, length: 1 } ];
 
 			view.change( writer => {
-				dispatcher.convertChanges( differStub, writer );
+				dispatcher.convertChanges( differStub, model.markers, writer );
 			} );
 
 			expect( dispatcher.convertInsert.calledOnce ).to.be.true;
@@ -63,7 +66,7 @@ describe( 'DowncastDispatcher', () => {
 			differStub.getChanges = () => [ { type: 'remove', position, length: 2, name: '$text' } ];
 
 			view.change( writer => {
-				dispatcher.convertChanges( differStub, writer );
+				dispatcher.convertChanges( differStub, model.markers, writer );
 			} );
 
 			expect( dispatcher.convertRemove.calledWith( position, 2, '$text' ) ).to.be.true;
@@ -80,7 +83,7 @@ describe( 'DowncastDispatcher', () => {
 			];
 
 			view.change( writer => {
-				dispatcher.convertChanges( differStub, writer );
+				dispatcher.convertChanges( differStub, model.markers, writer );
 			} );
 
 			expect( dispatcher.convertAttribute.calledWith( range, 'key', null, 'foo' ) ).to.be.true;
@@ -102,7 +105,7 @@ describe( 'DowncastDispatcher', () => {
 			];
 
 			view.change( writer => {
-				dispatcher.convertChanges( differStub, writer );
+				dispatcher.convertChanges( differStub, model.markers, writer );
 			} );
 
 			expect( dispatcher.convertInsert.calledTwice ).to.be.true;
@@ -122,7 +125,7 @@ describe( 'DowncastDispatcher', () => {
 			];
 
 			view.change( writer => {
-				dispatcher.convertChanges( differStub, writer );
+				dispatcher.convertChanges( differStub, model.markers, writer );
 			} );
 
 			expect( dispatcher.convertMarkerAdd.calledWith( 'foo', fooRange ) );
@@ -141,11 +144,34 @@ describe( 'DowncastDispatcher', () => {
 			];
 
 			view.change( writer => {
-				dispatcher.convertChanges( differStub, writer );
+				dispatcher.convertChanges( differStub, model.markers, writer );
+			} );
+
+			expect( dispatcher.convertMarkerRemove.calledWith( 'foo', fooRange ) );
+			expect( dispatcher.convertMarkerRemove.calledWith( 'bar', barRange ) );
+		} );
+
+		it( 'should re-render markers which view elements got unbound during conversion', () => {
+			sinon.stub( dispatcher, 'convertMarkerRemove' );
+			sinon.stub( dispatcher, 'convertMarkerAdd' );
+
+			const fooRange = model.createRange( model.createPositionAt( root, 0 ), model.createPositionAt( root, 1 ) );
+			const barRange = model.createRange( model.createPositionAt( root, 3 ), model.createPositionAt( root, 6 ) );
+
+			model.markers._set( 'foo', fooRange );
+			model.markers._set( 'bar', barRange );
+
+			// Stub `Mapper#flushUnboundMarkerNames`.
+			dispatcher.conversionApi.mapper.flushUnboundMarkerNames = () => [ 'foo', 'bar' ];
+
+			view.change( writer => {
+				dispatcher.convertChanges( differStub, model.markers, writer );
 			} );
 
 			expect( dispatcher.convertMarkerRemove.calledWith( 'foo', fooRange ) );
 			expect( dispatcher.convertMarkerRemove.calledWith( 'bar', barRange ) );
+			expect( dispatcher.convertMarkerAdd.calledWith( 'foo', fooRange ) );
+			expect( dispatcher.convertMarkerAdd.calledWith( 'bar', barRange ) );
 		} );
 	} );
 

+ 39 - 0
packages/ckeditor5-engine/tests/conversion/mapper.js

@@ -23,15 +23,23 @@ describe( 'Mapper', () => {
 			const viewA = new ViewElement( 'a' );
 			const viewB = new ViewElement( 'b' );
 			const viewC = new ViewElement( 'c' );
+			const viewD = new ViewElement( 'd' );
 
 			const modelA = new ModelElement( 'a' );
 			const modelB = new ModelElement( 'b' );
 			const modelC = new ModelElement( 'c' );
+			const modelD = new ModelElement( 'd' );
 
 			const mapper = new Mapper();
+
 			mapper.bindElements( modelA, viewA );
 			mapper.bindElements( modelB, viewB );
 			mapper.bindElements( modelC, viewC );
+			mapper.bindElements( modelD, viewD );
+
+			mapper.bindElementToMarker( viewA, 'foo' );
+			mapper.bindElementToMarker( viewD, 'foo' );
+			mapper.bindElementToMarker( viewD, 'bar' );
 
 			expect( mapper.toModelElement( viewA ) ).to.equal( modelA );
 			expect( mapper.toModelElement( viewB ) ).to.equal( modelB );
@@ -41,6 +49,9 @@ describe( 'Mapper', () => {
 			expect( mapper.toViewElement( modelB ) ).to.equal( viewB );
 			expect( mapper.toViewElement( modelC ) ).to.equal( viewC );
 
+			expect( Array.from( mapper.markerNameToElements( 'foo' ) ) ).to.deep.equal( [ viewA, viewD ] );
+
+			mapper.unbindViewElement( viewD );
 			mapper.clearBindings();
 
 			expect( mapper.toModelElement( viewA ) ).to.be.undefined;
@@ -50,6 +61,9 @@ describe( 'Mapper', () => {
 			expect( mapper.toViewElement( modelA ) ).to.be.undefined;
 			expect( mapper.toViewElement( modelB ) ).to.be.undefined;
 			expect( mapper.toViewElement( modelC ) ).to.be.undefined;
+
+			expect( mapper.markerNameToElements( 'foo' ) ).to.be.null;
+			expect( mapper.flushUnboundMarkerNames() ).to.deep.equal( [] );
 		} );
 	} );
 
@@ -648,11 +662,13 @@ describe( 'Mapper', () => {
 			const viewB = new ViewElement( 'b' );
 
 			mapper.bindElementToMarker( viewA, 'marker' );
+			mapper.bindElementToMarker( viewA, 'markerB' );
 			mapper.bindElementToMarker( viewB, 'marker' );
 
 			mapper.unbindElementFromMarkerName( viewA, 'marker' );
 
 			expect( Array.from( mapper.markerNameToElements( 'marker' ) ) ).to.deep.equal( [ viewB ] );
+			expect( Array.from( mapper.markerNameToElements( 'markerB' ) ) ).to.deep.equal( [ viewA ] );
 
 			mapper.unbindElementFromMarkerName( viewB, 'marker' );
 
@@ -751,4 +767,27 @@ describe( 'Mapper', () => {
 			expect( viewMappedAncestor ).to.equal( viewP );
 		} );
 	} );
+
+	describe( 'flushUnboundMarkerNames()', () => {
+		it( 'should return marker names of markers which elements has been unbound and clear that list', () => {
+			const viewA = new ViewElement( 'a' );
+			const viewB = new ViewElement( 'b' );
+
+			const mapper = new Mapper();
+
+			mapper.bindElementToMarker( viewA, 'foo' );
+			mapper.bindElementToMarker( viewA, 'bar' );
+			mapper.bindElementToMarker( viewB, 'bar' );
+
+			mapper.unbindViewElement( viewA );
+
+			expect( mapper.flushUnboundMarkerNames() ).to.deep.equal( [ 'foo', 'bar' ] );
+			expect( mapper.flushUnboundMarkerNames() ).to.deep.equal( [] );
+
+			mapper.unbindViewElement( viewB );
+
+			expect( mapper.flushUnboundMarkerNames() ).to.deep.equal( [ 'bar' ] );
+			expect( mapper.flushUnboundMarkerNames() ).to.deep.equal( [] );
+		} );
+	} );
 } );

+ 4 - 2
packages/ckeditor5-engine/tests/model/documentfragment.js

@@ -61,7 +61,7 @@ describe( 'DocumentFragment', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		let frag;
 
 		before( () => {
@@ -70,14 +70,16 @@ describe( 'DocumentFragment', () => {
 
 		it( 'should return true for documentFragment', () => {
 			expect( frag.is( 'documentFragment' ) ).to.be.true;
+			expect( frag.is( 'model:documentFragment' ) ).to.be.true;
 		} );
 
-		it( 'should return false for other accept values', () => {
+		it( 'should return false for other values', () => {
 			expect( frag.is( 'node' ) ).to.be.false;
 			expect( frag.is( 'text' ) ).to.be.false;
 			expect( frag.is( 'textProxy' ) ).to.be.false;
 			expect( frag.is( 'element' ) ).to.be.false;
 			expect( frag.is( 'rootElement' ) ).to.be.false;
+			expect( frag.is( 'view:documentFragment' ) ).to.be.false;
 		} );
 	} );
 

+ 7 - 1
packages/ckeditor5-engine/tests/model/documentselection.js

@@ -485,21 +485,27 @@ describe( 'DocumentSelection', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		it( 'should return true for selection', () => {
 			expect( selection.is( 'selection' ) ).to.be.true;
+			expect( selection.is( 'model:selection' ) ).to.be.true;
 		} );
 
 		it( 'should return true for documentSelection', () => {
 			expect( selection.is( 'documentSelection' ) ).to.be.true;
+			expect( selection.is( 'model:documentSelection' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other values', () => {
 			expect( selection.is( 'node' ) ).to.be.false;
+			expect( selection.is( 'model:node' ) ).to.be.false;
 			expect( selection.is( 'text' ) ).to.be.false;
 			expect( selection.is( 'textProxy' ) ).to.be.false;
 			expect( selection.is( 'element' ) ).to.be.false;
+			expect( selection.is( 'element', 'paragraph' ) ).to.be.false;
 			expect( selection.is( 'rootElement' ) ).to.be.false;
+			expect( selection.is( 'view:selection' ) ).to.be.false;
+			expect( selection.is( 'view:documentSelection' ) ).to.be.false;
 		} );
 	} );
 

+ 12 - 1
packages/ckeditor5-engine/tests/model/element.js

@@ -38,7 +38,7 @@ describe( 'Element', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		let element;
 
 		before( () => {
@@ -47,18 +47,29 @@ describe( 'Element', () => {
 
 		it( 'should return true for node, element, element with same name and element name', () => {
 			expect( element.is( 'node' ) ).to.be.true;
+			expect( element.is( 'model:node' ) ).to.be.true;
 			expect( element.is( 'element' ) ).to.be.true;
+			expect( element.is( 'model:element' ) ).to.be.true;
 			expect( element.is( 'element', 'paragraph' ) ).to.be.true;
+			expect( element.is( 'model:element', 'paragraph' ) ).to.be.true;
 			expect( element.is( 'paragraph' ) ).to.be.true;
+			expect( element.is( 'model:paragraph' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other accept values', () => {
 			expect( element.is( 'element', 'image' ) ).to.be.false;
+			expect( element.is( 'model:element', 'image' ) ).to.be.false;
 			expect( element.is( 'image' ) ).to.be.false;
+			expect( element.is( 'model:image' ) ).to.be.false;
 			expect( element.is( 'text' ) ).to.be.false;
+			expect( element.is( 'model:text' ) ).to.be.false;
 			expect( element.is( 'textProxy' ) ).to.be.false;
 			expect( element.is( 'documentFragment' ) ).to.be.false;
 			expect( element.is( 'rootElement' ) ).to.be.false;
+			expect( element.is( 'model:rootElement' ) ).to.be.false;
+			expect( element.is( 'view:node' ) ).to.be.false;
+			expect( element.is( 'view:element' ) ).to.be.false;
+			expect( element.is( 'view:element' ) ).to.be.false;
 		} );
 	} );
 

+ 23 - 0
packages/ckeditor5-engine/tests/model/liveposition.js

@@ -41,6 +41,29 @@ describe( 'LivePosition', () =>
 		expect( live ).to.be.instanceof( Position );
 	} );
 
+	describe( 'is()', () => {
+		let live;
+
+		beforeEach( () => {
+			live = new LivePosition( root, [ 0 ] );
+			live.detach();
+		} );
+
+		it( 'should return true for "livePosition" and "position"', () => {
+			expect( live.is( 'livePosition' ) ).to.be.true;
+			expect( live.is( 'model:livePosition' ) ).to.be.true;
+			expect( live.is( 'position' ) ).to.be.true;
+			expect( live.is( 'model:position' ) ).to.be.true;
+		} );
+
+		it( 'should return false for incorrect values', () => {
+			expect( live.is( 'model' ) ).to.be.false;
+			expect( live.is( 'model:node' ) ).to.be.false;
+			expect( live.is( 'text' ) ).to.be.false;
+			expect( live.is( 'element', 'paragraph' ) ).to.be.false;
+		} );
+	} );
+
 	it( 'should throw if given root is not a RootElement', () => {
 		const docFrag = new DocumentFragment();
 

+ 23 - 0
packages/ckeditor5-engine/tests/model/liverange.js

@@ -183,6 +183,29 @@ describe( 'LiveRange', () => {
 		expect( spy.args[ 1 ][ 2 ].deletionPosition.isEqual( new Position( root, [ 0 ] ) ) ).to.be.true;
 	} );
 
+	describe( 'is()', () => {
+		let live;
+
+		beforeEach( () => {
+			live = new LiveRange( new Position( root, [ 0 ] ), new Position( root, [ 1 ] ) );
+			live.detach();
+		} );
+
+		it( 'should return true for "liveRange" and "range"', () => {
+			expect( live.is( 'liveRange' ) ).to.be.true;
+			expect( live.is( 'model:liveRange' ) ).to.be.true;
+			expect( live.is( 'range' ) ).to.be.true;
+			expect( live.is( 'model:range' ) ).to.be.true;
+		} );
+
+		it( 'should return false for incorrect values', () => {
+			expect( live.is( 'model' ) ).to.be.false;
+			expect( live.is( 'model:node' ) ).to.be.false;
+			expect( live.is( 'text' ) ).to.be.false;
+			expect( live.is( 'element', 'paragraph' ) ).to.be.false;
+		} );
+	} );
+
 	describe( 'should get transformed and fire change:range if', () => {
 		let live, spy;
 

+ 21 - 0
packages/ckeditor5-engine/tests/model/markercollection.js

@@ -410,4 +410,25 @@ describe( 'Marker', () => {
 
 		expect( marker.affectsData ).to.be.false;
 	} );
+
+	describe( 'is()', () => {
+		let marker;
+
+		beforeEach( () => {
+			const range = new Range( Position._createAt( root, 1 ), Position._createAt( root, 2 ) );
+			marker = model.markers._set( 'name', range );
+		} );
+
+		it( 'should return true for "marker"', () => {
+			expect( marker.is( 'marker' ) ).to.be.true;
+			expect( marker.is( 'model:marker' ) ).to.be.true;
+		} );
+
+		it( 'should return false for incorrect values', () => {
+			expect( marker.is( 'model' ) ).to.be.false;
+			expect( marker.is( 'model:node' ) ).to.be.false;
+			expect( marker.is( 'text' ) ).to.be.false;
+			expect( marker.is( 'element', 'paragraph' ) ).to.be.false;
+		} );
+	} );
 } );

+ 8 - 0
packages/ckeditor5-engine/tests/model/node.js

@@ -165,6 +165,14 @@ describe( 'Node', () => {
 	describe( 'is()', () => {
 		it( 'should return true for node', () => {
 			expect( node.is( 'node' ) ).to.be.true;
+			expect( node.is( 'model:node' ) ).to.be.true;
+		} );
+
+		it( 'should return false for incorrect values', () => {
+			expect( node.is( 'model' ) ).to.be.false;
+			expect( node.is( 'model:text' ) ).to.be.false;
+			expect( node.is( 'text' ) ).to.be.false;
+			expect( node.is( 'element', 'paragraph' ) ).to.be.false;
 		} );
 	} );
 

+ 20 - 0
packages/ckeditor5-engine/tests/model/position.js

@@ -128,6 +128,26 @@ describe( 'Position', () => {
 		} );
 	} );
 
+	describe( 'is()', () => {
+		let position;
+
+		beforeEach( () => {
+			position = new Position( root, [ 0 ] );
+		} );
+
+		it( 'should return true for "position"', () => {
+			expect( position.is( 'position' ) ).to.be.true;
+			expect( position.is( 'model:position' ) ).to.be.true;
+		} );
+
+		it( 'should return false for incorrect values', () => {
+			expect( position.is( 'model' ) ).to.be.false;
+			expect( position.is( 'model:node' ) ).to.be.false;
+			expect( position.is( 'text' ) ).to.be.false;
+			expect( position.is( 'element', 'paragraph' ) ).to.be.false;
+		} );
+	} );
+
 	describe( 'static creators', () => {
 		describe( '_createAt()', () => {
 			it( 'should throw if no offset is passed', () => {

+ 14 - 0
packages/ckeditor5-engine/tests/model/range.js

@@ -50,6 +50,20 @@ describe( 'Range', () => {
 		} );
 	} );
 
+	describe( 'is()', () => {
+		it( 'should return true for "range"', () => {
+			expect( range.is( 'range' ) ).to.be.true;
+			expect( range.is( 'model:range' ) ).to.be.true;
+		} );
+
+		it( 'should return false for incorrect values', () => {
+			expect( range.is( 'model' ) ).to.be.false;
+			expect( range.is( 'model:node' ) ).to.be.false;
+			expect( range.is( 'text' ) ).to.be.false;
+			expect( range.is( 'element', 'paragraph' ) ).to.be.false;
+		} );
+	} );
+
 	describe( 'root', () => {
 		it( 'should be equal to start position root', () => {
 			expect( range.root ).to.equal( start.root );

+ 11 - 1
packages/ckeditor5-engine/tests/model/rootelement.js

@@ -22,7 +22,7 @@ describe( 'RootElement', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		let root;
 
 		before( () => {
@@ -34,19 +34,29 @@ describe( 'RootElement', () => {
 
 		it( 'should return true for rootElement, element, element with same name and element name', () => {
 			expect( root.is( 'element', '$root' ) ).to.be.true;
+			expect( root.is( 'model:element', '$root' ) ).to.be.true;
 			expect( root.is( 'element' ) ).to.be.true;
+			expect( root.is( 'model:element' ) ).to.be.true;
 			expect( root.is( '$root' ) ).to.be.true;
+			expect( root.is( 'model:$root' ) ).to.be.true;
 			expect( root.is( 'rootElement', '$root' ) ).to.be.true;
+			expect( root.is( 'model:rootElement', '$root' ) ).to.be.true;
 			expect( root.is( 'rootElement' ) ).to.be.true;
+			expect( root.is( 'model:rootElement' ) ).to.be.true;
+			expect( root.is( 'node' ) ).to.be.true;
+			expect( root.is( 'model:node' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other accept values', () => {
 			expect( root.is( 'element', '$graveyard' ) ).to.be.false;
+			expect( root.is( 'model:element', '$graveyard' ) ).to.be.false;
 			expect( root.is( 'rootElement', '$graveyard' ) ).to.be.false;
+			expect( root.is( 'model:rootElement', '$graveyard' ) ).to.be.false;
 			expect( root.is( '$graveyard' ) ).to.be.false;
 			expect( root.is( 'text' ) ).to.be.false;
 			expect( root.is( 'textProxy' ) ).to.be.false;
 			expect( root.is( 'documentFragment' ) ).to.be.false;
+			expect( root.is( 'view:element' ) ).to.be.false;
 		} );
 	} );
 } );

+ 21 - 1
packages/ckeditor5-engine/tests/model/selection.js

@@ -127,6 +127,26 @@ describe( 'Selection', () => {
 		} );
 	} );
 
+	describe( 'is()', () => {
+		let selection;
+
+		beforeEach( () => {
+			selection = new Selection();
+		} );
+
+		it( 'should return true for "selection"', () => {
+			expect( selection.is( 'selection' ) ).to.be.true;
+			expect( selection.is( 'model:selection' ) ).to.be.true;
+		} );
+
+		it( 'should return false for incorrect values', () => {
+			expect( selection.is( 'model' ) ).to.be.false;
+			expect( selection.is( 'model:node' ) ).to.be.false;
+			expect( selection.is( 'text' ) ).to.be.false;
+			expect( selection.is( 'element', 'paragraph' ) ).to.be.false;
+		} );
+	} );
+
 	describe( 'isCollapsed', () => {
 		it( 'should return false for empty selection', () => {
 			expect( selection.isCollapsed ).to.be.false;
@@ -806,7 +826,7 @@ describe( 'Selection', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		it( 'should return true for selection', () => {
 			expect( selection.is( 'selection' ) ).to.be.true;
 		} );

+ 4 - 1
packages/ckeditor5-engine/tests/model/text.js

@@ -32,7 +32,7 @@ describe( 'Text', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		let text;
 
 		before( () => {
@@ -41,12 +41,15 @@ describe( 'Text', () => {
 
 		it( 'should return true for node, text', () => {
 			expect( text.is( 'node' ) ).to.be.true;
+			expect( text.is( 'model:node' ) ).to.be.true;
 			expect( text.is( 'text' ) ).to.be.true;
+			expect( text.is( 'model:text' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other accept values', () => {
 			expect( text.is( 'textProxy' ) ).to.be.false;
 			expect( text.is( 'element' ) ).to.be.false;
+			expect( text.is( 'model:element' ) ).to.be.false;
 			expect( text.is( 'rootElement' ) ).to.be.false;
 			expect( text.is( 'documentFragment' ) ).to.be.false;
 		} );

+ 4 - 1
packages/ckeditor5-engine/tests/model/textproxy.js

@@ -102,15 +102,18 @@ describe( 'TextProxy', () => {
 		}, /model-textproxy-wrong-length/, model );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		it( 'should return true for textProxy', () => {
 			expect( textProxy.is( 'textProxy' ) ).to.be.true;
+			expect( textProxy.is( 'model:textProxy' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other accept values', () => {
 			expect( textProxy.is( 'node' ) ).to.be.false;
+			expect( textProxy.is( 'model:node' ) ).to.be.false;
 			expect( textProxy.is( 'text' ) ).to.be.false;
 			expect( textProxy.is( 'element' ) ).to.be.false;
+			expect( textProxy.is( 'model:element', 'image' ) ).to.be.false;
 			expect( textProxy.is( 'documentFragment' ) ).to.be.false;
 			expect( textProxy.is( 'rootElement' ) ).to.be.false;
 		} );

+ 9 - 1
packages/ckeditor5-engine/tests/view/attributeelement.js

@@ -21,7 +21,7 @@ describe( 'AttributeElement', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		let el;
 
 		before( () => {
@@ -30,16 +30,24 @@ describe( 'AttributeElement', () => {
 
 		it( 'should return true for attributeElement/element, also with correct name and element name', () => {
 			expect( el.is( 'attributeElement' ) ).to.be.true;
+			expect( el.is( 'view:attributeElement' ) ).to.be.true;
 			expect( el.is( 'attributeElement', 'span' ) ).to.be.true;
+			expect( el.is( 'view:attributeElement', 'span' ) ).to.be.true;
 			expect( el.is( 'element' ) ).to.be.true;
+			expect( el.is( 'view:element' ) ).to.be.true;
 			expect( el.is( 'element', 'span' ) ).to.be.true;
+			expect( el.is( 'view:element', 'span' ) ).to.be.true;
 			expect( el.is( 'span' ) ).to.be.true;
+			expect( el.is( 'view:span' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other accept values', () => {
 			expect( el.is( 'attributeElement', 'p' ) ).to.be.false;
+			expect( el.is( 'view:attributeElement', 'p' ) ).to.be.false;
 			expect( el.is( 'element', 'p' ) ).to.be.false;
+			expect( el.is( 'view:element', 'p' ) ).to.be.false;
 			expect( el.is( 'p' ) ).to.be.false;
+			expect( el.is( 'view:p' ) ).to.be.false;
 			expect( el.is( 'text' ) ).to.be.false;
 			expect( el.is( 'textProxy' ) ).to.be.false;
 			expect( el.is( 'containerElement' ) ).to.be.false;

+ 9 - 1
packages/ckeditor5-engine/tests/view/containerelement.js

@@ -18,7 +18,7 @@ describe( 'ContainerElement', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		let el;
 
 		before( () => {
@@ -27,16 +27,24 @@ describe( 'ContainerElement', () => {
 
 		it( 'should return true for containerElement/element, also with correct name and element name', () => {
 			expect( el.is( 'containerElement' ) ).to.be.true;
+			expect( el.is( 'view:containerElement' ) ).to.be.true;
 			expect( el.is( 'containerElement', 'p' ) ).to.be.true;
+			expect( el.is( 'view:containerElement', 'p' ) ).to.be.true;
 			expect( el.is( 'element' ) ).to.be.true;
+			expect( el.is( 'view:element' ) ).to.be.true;
 			expect( el.is( 'element', 'p' ) ).to.be.true;
+			expect( el.is( 'view:element', 'p' ) ).to.be.true;
 			expect( el.is( 'p' ) ).to.be.true;
+			expect( el.is( 'view:p' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other accept values', () => {
 			expect( el.is( 'containerElement', 'span' ) ).to.be.false;
+			expect( el.is( 'view:containerElement', 'span' ) ).to.be.false;
 			expect( el.is( 'element', 'span' ) ).to.be.false;
+			expect( el.is( 'view:element', 'span' ) ).to.be.false;
 			expect( el.is( 'span' ) ).to.be.false;
+			expect( el.is( 'view:span' ) ).to.be.false;
 			expect( el.is( 'text' ) ).to.be.false;
 			expect( el.is( 'textProxy' ) ).to.be.false;
 			expect( el.is( 'attributeElement' ) ).to.be.false;

+ 4 - 1
packages/ckeditor5-engine/tests/view/documentfragment.js

@@ -71,7 +71,7 @@ describe( 'DocumentFragment', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		let frag;
 
 		before( () => {
@@ -80,13 +80,16 @@ describe( 'DocumentFragment', () => {
 
 		it( 'should return true for documentFragment', () => {
 			expect( frag.is( 'documentFragment' ) ).to.be.true;
+			expect( frag.is( 'view:documentFragment' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other accept values', () => {
 			expect( frag.is( 'node' ) ).to.be.false;
+			expect( frag.is( 'view:node' ) ).to.be.false;
 			expect( frag.is( 'text' ) ).to.be.false;
 			expect( frag.is( 'textProxy' ) ).to.be.false;
 			expect( frag.is( 'element' ) ).to.be.false;
+			expect( frag.is( 'view:element' ) ).to.be.false;
 			expect( frag.is( 'containerElement' ) ).to.be.false;
 			expect( frag.is( 'attributeElement' ) ).to.be.false;
 			expect( frag.is( 'uiElement' ) ).to.be.false;

+ 7 - 1
packages/ckeditor5-engine/tests/view/documentselection.js

@@ -725,21 +725,27 @@ describe( 'DocumentSelection', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		it( 'should return true for selection', () => {
 			expect( documentSelection.is( 'selection' ) ).to.be.true;
+			expect( documentSelection.is( 'view:selection' ) ).to.be.true;
 		} );
 
 		it( 'should return true for documentSelection', () => {
 			expect( documentSelection.is( 'documentSelection' ) ).to.be.true;
+			expect( documentSelection.is( 'view:documentSelection' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other values', () => {
 			expect( documentSelection.is( 'node' ) ).to.be.false;
+			expect( documentSelection.is( 'view:node' ) ).to.be.false;
 			expect( documentSelection.is( 'text' ) ).to.be.false;
+			expect( documentSelection.is( 'view:text' ) ).to.be.false;
 			expect( documentSelection.is( 'textProxy' ) ).to.be.false;
 			expect( documentSelection.is( 'element' ) ).to.be.false;
 			expect( documentSelection.is( 'rootElement' ) ).to.be.false;
+			expect( documentSelection.is( 'model:selection' ) ).to.be.false;
+			expect( documentSelection.is( 'model:documentSelection' ) ).to.be.false;
 		} );
 	} );
 

+ 50 - 8
packages/ckeditor5-engine/tests/view/editableelement.js

@@ -5,16 +5,58 @@
 
 import createDocumentMock from '../../tests/view/_utils/createdocumentmock';
 
-import RootEditableElement from '../../src/view/rooteditableelement';
+import EditableElement from '../../src/view/editableelement';
 import Range from '../../src/view/range';
 import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'EditableElement', () => {
+	describe( 'is', () => {
+		let el;
+
+		before( () => {
+			el = new EditableElement( 'div' );
+		} );
+
+		it( 'should return true for containerElement/editable/element, also with correct name and element name', () => {
+			expect( el.is( 'containerElement' ) ).to.be.true;
+			expect( el.is( 'view:containerElement' ) ).to.be.true;
+			expect( el.is( 'containerElement', 'div' ) ).to.be.true;
+			expect( el.is( 'view:containerElement', 'div' ) ).to.be.true;
+			expect( el.is( 'editableElement' ) ).to.be.true;
+			expect( el.is( 'view:editableElement' ) ).to.be.true;
+			expect( el.is( 'editableElement', 'div' ) ).to.be.true;
+			expect( el.is( 'view:editableElement', 'div' ) ).to.be.true;
+			expect( el.is( 'element' ) ).to.be.true;
+			expect( el.is( 'view:element' ) ).to.be.true;
+			expect( el.is( 'element', 'div' ) ).to.be.true;
+			expect( el.is( 'view:element', 'div' ) ).to.be.true;
+			expect( el.is( 'div' ) ).to.be.true;
+			expect( el.is( 'view:div' ) ).to.be.true;
+		} );
+
+		it( 'should return false for other accept values', () => {
+			expect( el.is( 'rootElement', 'p' ) ).to.be.false;
+			expect( el.is( 'view:rootElement', 'p' ) ).to.be.false;
+			expect( el.is( 'containerElement', 'p' ) ).to.be.false;
+			expect( el.is( 'view:containerElement', 'p' ) ).to.be.false;
+			expect( el.is( 'element', 'p' ) ).to.be.false;
+			expect( el.is( 'view:element', 'p' ) ).to.be.false;
+			expect( el.is( 'p' ) ).to.be.false;
+			expect( el.is( 'view:p' ) ).to.be.false;
+			expect( el.is( 'text' ) ).to.be.false;
+			expect( el.is( 'textProxy' ) ).to.be.false;
+			expect( el.is( 'attributeElement' ) ).to.be.false;
+			expect( el.is( 'uiElement' ) ).to.be.false;
+			expect( el.is( 'emptyElement' ) ).to.be.false;
+			expect( el.is( 'documentFragment' ) ).to.be.false;
+		} );
+	} );
+
 	describe( 'document', () => {
 		let element, docMock;
 
 		beforeEach( () => {
-			element = new RootEditableElement( 'div' );
+			element = new EditableElement( 'div' );
 			docMock = createDocumentMock();
 		} );
 
@@ -51,16 +93,16 @@ describe( 'EditableElement', () => {
 		beforeEach( () => {
 			docMock = createDocumentMock();
 
-			viewMain = new RootEditableElement( 'div' );
+			viewMain = new EditableElement( 'div' );
 			viewMain._document = docMock;
 
-			viewHeader = new RootEditableElement( 'h1' );
+			viewHeader = new EditableElement( 'h1' );
 			viewHeader._document = docMock;
 			viewHeader.rootName = 'header';
 		} );
 
 		it( 'should be observable', () => {
-			const root = new RootEditableElement( 'div' );
+			const root = new EditableElement( 'div' );
 			root._document = createDocumentMock();
 
 			expect( root.isFocused ).to.be.false;
@@ -114,7 +156,7 @@ describe( 'EditableElement', () => {
 
 	describe( 'isReadOnly', () => {
 		it( 'should be observable', () => {
-			const root = new RootEditableElement( 'div' );
+			const root = new EditableElement( 'div' );
 			root._document = createDocumentMock();
 
 			expect( root.isReadOnly ).to.be.false;
@@ -131,7 +173,7 @@ describe( 'EditableElement', () => {
 		} );
 
 		it( 'should be bound to the document#isReadOnly', () => {
-			const root = new RootEditableElement( 'div' );
+			const root = new EditableElement( 'div' );
 			root._document = createDocumentMock();
 
 			root.document.isReadOnly = false;
@@ -147,7 +189,7 @@ describe( 'EditableElement', () => {
 	describe( 'getDocument', () => {
 		it( 'should return document', () => {
 			const docMock = createDocumentMock();
-			const root = new RootEditableElement( 'div' );
+			const root = new EditableElement( 'div' );
 			root._document = docMock;
 
 			expect( root.document ).to.equal( docMock );

+ 10 - 1
packages/ckeditor5-engine/tests/view/element.js

@@ -82,7 +82,7 @@ describe( 'Element', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		let el;
 
 		before( () => {
@@ -91,21 +91,30 @@ describe( 'Element', () => {
 
 		it( 'should return true for node, element, element with correct name and element name', () => {
 			expect( el.is( 'node' ) ).to.be.true;
+			expect( el.is( 'view:node' ) ).to.be.true;
 			expect( el.is( 'element' ) ).to.be.true;
+			expect( el.is( 'view:element' ) ).to.be.true;
 			expect( el.is( 'element', 'p' ) ).to.be.true;
+			expect( el.is( 'view:element', 'p' ) ).to.be.true;
 			expect( el.is( 'p' ) ).to.be.true;
+			expect( el.is( 'view:p' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other accept values', () => {
 			expect( el.is( 'element', 'span' ) ).to.be.false;
+			expect( el.is( 'view:element', 'span' ) ).to.be.false;
 			expect( el.is( 'span' ) ).to.be.false;
+			expect( el.is( 'view:span' ) ).to.be.false;
 			expect( el.is( 'text' ) ).to.be.false;
+			expect( el.is( 'view:text' ) ).to.be.false;
 			expect( el.is( 'textProxy' ) ).to.be.false;
 			expect( el.is( 'containerElement' ) ).to.be.false;
 			expect( el.is( 'attributeElement' ) ).to.be.false;
 			expect( el.is( 'uiElement' ) ).to.be.false;
 			expect( el.is( 'emptyElement' ) ).to.be.false;
+			expect( el.is( 'view:emptyElement' ) ).to.be.false;
 			expect( el.is( 'rootElement' ) ).to.be.false;
+			expect( el.is( 'view:ootElement' ) ).to.be.false;
 			expect( el.is( 'documentFragment' ) ).to.be.false;
 		} );
 	} );

+ 10 - 1
packages/ckeditor5-engine/tests/view/emptyelement.js

@@ -20,7 +20,7 @@ describe( 'EmptyElement', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		let el;
 
 		before( () => {
@@ -29,17 +29,26 @@ describe( 'EmptyElement', () => {
 
 		it( 'should return true for emptyElement/element, also with correct name and element name', () => {
 			expect( el.is( 'emptyElement' ) ).to.be.true;
+			expect( el.is( 'view:emptyElement' ) ).to.be.true;
 			expect( el.is( 'emptyElement', 'p' ) ).to.be.true;
+			expect( el.is( 'view:emptyElement', 'p' ) ).to.be.true;
 			expect( el.is( 'element' ) ).to.be.true;
+			expect( el.is( 'view:element' ) ).to.be.true;
 			expect( el.is( 'element', 'p' ) ).to.be.true;
+			expect( el.is( 'view:element', 'p' ) ).to.be.true;
 			expect( el.is( 'p' ) ).to.be.true;
+			expect( el.is( 'view:p' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other accept values', () => {
 			expect( el.is( 'emptyElement', 'span' ) ).to.be.false;
+			expect( el.is( 'view:emptyElement', 'span' ) ).to.be.false;
 			expect( el.is( 'element', 'span' ) ).to.be.false;
+			expect( el.is( 'view:element', 'span' ) ).to.be.false;
 			expect( el.is( 'span' ) ).to.be.false;
+			expect( el.is( 'view:span' ) ).to.be.false;
 			expect( el.is( 'text' ) ).to.be.false;
+			expect( el.is( 'view:text' ) ).to.be.false;
 			expect( el.is( 'textProxy' ) ).to.be.false;
 			expect( el.is( 'containerElement' ) ).to.be.false;
 			expect( el.is( 'attributeElement' ) ).to.be.false;

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

@@ -31,10 +31,28 @@ describe( 'Node', () => {
 	} );
 
 	describe( 'is()', () => {
-		it( 'should return true for node', () => {
-			const node = new Node();
+		let node;
 
+		beforeEach( () => {
+			node = new Node();
+		} );
+
+		it( 'should return true for node', () => {
 			expect( node.is( 'node' ) ).to.be.true;
+			expect( node.is( 'view:node' ) ).to.be.true;
+		} );
+
+		it( 'should return false for other accept values', () => {
+			expect( node.is( 'rootElement' ) ).to.be.false;
+			expect( node.is( 'containerElement' ) ).to.be.false;
+			expect( node.is( 'element' ) ).to.be.false;
+			expect( node.is( 'p' ) ).to.be.false;
+			expect( node.is( 'text' ) ).to.be.false;
+			expect( node.is( 'textProxy' ) ).to.be.false;
+			expect( node.is( 'attributeElement' ) ).to.be.false;
+			expect( node.is( 'uiElement' ) ).to.be.false;
+			expect( node.is( 'emptyElement' ) ).to.be.false;
+			expect( node.is( 'documentFragment' ) ).to.be.false;
 		} );
 	} );
 

+ 30 - 3
packages/ckeditor5-engine/tests/view/position.js

@@ -24,10 +24,37 @@ describe( 'Position', () => {
 
 	describe( 'constructor()', () => {
 		it( 'should create element without attributes', () => {
-			const elem = new Position( parentMock, 5 );
+			const position = new Position( parentMock, 5 );
 
-			expect( elem ).to.have.property( 'parent' ).that.equals( parentMock );
-			expect( elem ).to.have.property( 'offset' ).that.equals( 5 );
+			expect( position ).to.have.property( 'parent' ).that.equals( parentMock );
+			expect( position ).to.have.property( 'offset' ).that.equals( 5 );
+		} );
+	} );
+
+	describe( 'is()', () => {
+		let position;
+
+		beforeEach( () => {
+			position = new Position( parentMock, 5 );
+		} );
+
+		it( 'should return true for "position"', () => {
+			expect( position.is( 'position' ) ).to.be.true;
+			expect( position.is( 'view:position' ) ).to.be.true;
+		} );
+
+		it( 'should return false for other accept values', () => {
+			expect( position.is( 'rootElement' ) ).to.be.false;
+			expect( position.is( 'containerElement' ) ).to.be.false;
+			expect( position.is( 'element' ) ).to.be.false;
+			expect( position.is( 'p' ) ).to.be.false;
+			expect( position.is( 'text' ) ).to.be.false;
+			expect( position.is( 'textProxy' ) ).to.be.false;
+			expect( position.is( 'attributeElement' ) ).to.be.false;
+			expect( position.is( 'uiElement' ) ).to.be.false;
+			expect( position.is( 'emptyElement' ) ).to.be.false;
+			expect( position.is( 'documentFragment' ) ).to.be.false;
+			expect( position.is( 'model:position' ) ).to.be.false;
 		} );
 	} );
 

+ 28 - 0
packages/ckeditor5-engine/tests/view/range.js

@@ -43,6 +43,34 @@ describe( 'Range', () => {
 		} );
 	} );
 
+	describe( 'is()', () => {
+		let range;
+
+		before( () => {
+			const start = new Position( {}, 1 );
+			range = new Range( start );
+		} );
+
+		it( 'should return true for "range"', () => {
+			expect( range.is( 'range' ) ).to.be.true;
+			expect( range.is( 'view:range' ) ).to.be.true;
+		} );
+
+		it( 'should return false for other accept values', () => {
+			expect( range.is( 'rootElement' ) ).to.be.false;
+			expect( range.is( 'containerElement' ) ).to.be.false;
+			expect( range.is( 'element' ) ).to.be.false;
+			expect( range.is( 'p' ) ).to.be.false;
+			expect( range.is( 'text' ) ).to.be.false;
+			expect( range.is( 'textProxy' ) ).to.be.false;
+			expect( range.is( 'attributeElement' ) ).to.be.false;
+			expect( range.is( 'uiElement' ) ).to.be.false;
+			expect( range.is( 'emptyElement' ) ).to.be.false;
+			expect( range.is( 'documentFragment' ) ).to.be.false;
+			expect( range.is( 'model:range' ) ).to.be.false;
+		} );
+	} );
+
 	describe( 'iterator', () => {
 		it( 'should iterate over the range returning tree walker values', () => {
 			const range = getRange( '<p>fo{o</p><p>bar</p><p>xy}z</p>' );

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

@@ -38,7 +38,7 @@ describe( 'RootEditableElement', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		let el;
 
 		before( () => {
@@ -47,27 +47,42 @@ describe( 'RootEditableElement', () => {
 
 		it( 'should return true for rootElement/containerElement/editable/element, also with correct name and element name', () => {
 			expect( el.is( 'rootElement' ) ).to.be.true;
+			expect( el.is( 'view:rootElement' ) ).to.be.true;
 			expect( el.is( 'rootElement', 'div' ) ).to.be.true;
+			expect( el.is( 'view:rootElement', 'div' ) ).to.be.true;
 			expect( el.is( 'containerElement' ) ).to.be.true;
+			expect( el.is( 'view:containerElement' ) ).to.be.true;
 			expect( el.is( 'containerElement', 'div' ) ).to.be.true;
+			expect( el.is( 'view:containerElement', 'div' ) ).to.be.true;
 			expect( el.is( 'editableElement' ) ).to.be.true;
+			expect( el.is( 'view:editableElement' ) ).to.be.true;
 			expect( el.is( 'editableElement', 'div' ) ).to.be.true;
+			expect( el.is( 'view:editableElement', 'div' ) ).to.be.true;
 			expect( el.is( 'element' ) ).to.be.true;
+			expect( el.is( 'view:element' ) ).to.be.true;
 			expect( el.is( 'element', 'div' ) ).to.be.true;
+			expect( el.is( 'view:element', 'div' ) ).to.be.true;
 			expect( el.is( 'div' ) ).to.be.true;
+			expect( el.is( 'view:div' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other accept values', () => {
 			expect( el.is( 'rootElement', 'p' ) ).to.be.false;
+			expect( el.is( 'view:rootElement', 'p' ) ).to.be.false;
 			expect( el.is( 'containerElement', 'p' ) ).to.be.false;
+			expect( el.is( 'view:containerElement', 'p' ) ).to.be.false;
 			expect( el.is( 'element', 'p' ) ).to.be.false;
+			expect( el.is( 'view:element', 'p' ) ).to.be.false;
 			expect( el.is( 'p' ) ).to.be.false;
+			expect( el.is( 'view:p' ) ).to.be.false;
 			expect( el.is( 'text' ) ).to.be.false;
+			expect( el.is( 'view:text' ) ).to.be.false;
 			expect( el.is( 'textProxy' ) ).to.be.false;
 			expect( el.is( 'attributeElement' ) ).to.be.false;
 			expect( el.is( 'uiElement' ) ).to.be.false;
 			expect( el.is( 'emptyElement' ) ).to.be.false;
 			expect( el.is( 'documentFragment' ) ).to.be.false;
+			expect( el.is( 'model:rootElement' ) ).to.be.false;
 		} );
 	} );
 

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

@@ -600,18 +600,21 @@ describe( 'Selection', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		it( 'should return true for selection', () => {
 			expect( selection.is( 'selection' ) ).to.be.true;
+			expect( selection.is( 'view:selection' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other values', () => {
 			expect( selection.is( 'documentSelection' ) ).to.be.false;
+			expect( selection.is( 'view:documentSelection' ) ).to.be.false;
 			expect( selection.is( 'node' ) ).to.be.false;
 			expect( selection.is( 'text' ) ).to.be.false;
 			expect( selection.is( 'textProxy' ) ).to.be.false;
 			expect( selection.is( 'element' ) ).to.be.false;
 			expect( selection.is( 'rootElement' ) ).to.be.false;
+			expect( selection.is( 'model:selection' ) ).to.be.false;
 		} );
 	} );
 

+ 7 - 1
packages/ckeditor5-engine/tests/view/text.js

@@ -17,7 +17,7 @@ describe( 'Text', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		let text;
 
 		before( () => {
@@ -26,18 +26,24 @@ describe( 'Text', () => {
 
 		it( 'should return true for node, text', () => {
 			expect( text.is( 'node' ) ).to.be.true;
+			expect( text.is( 'view:node' ) ).to.be.true;
 			expect( text.is( 'text' ) ).to.be.true;
+			expect( text.is( 'view:text' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other accept values', () => {
 			expect( text.is( 'textProxy' ) ).to.be.false;
+			expect( text.is( 'view:textProxy' ) ).to.be.false;
 			expect( text.is( 'element' ) ).to.be.false;
+			expect( text.is( 'view:element' ) ).to.be.false;
 			expect( text.is( 'containerElement' ) ).to.be.false;
 			expect( text.is( 'attributeElement' ) ).to.be.false;
 			expect( text.is( 'uiElement' ) ).to.be.false;
 			expect( text.is( 'emptyElement' ) ).to.be.false;
 			expect( text.is( 'rootElement' ) ).to.be.false;
 			expect( text.is( 'documentFragment' ) ).to.be.false;
+			expect( text.is( 'model:text' ) ).to.be.false;
+			expect( text.is( 'model:node' ) ).to.be.false;
 		} );
 	} );
 

+ 5 - 1
packages/ckeditor5-engine/tests/view/textproxy.js

@@ -61,14 +61,17 @@ describe( 'TextProxy', () => {
 		} );
 	} );
 
-	describe( 'is', () => {
+	describe( 'is()', () => {
 		it( 'should return true for textProxy', () => {
 			expect( textProxy.is( 'textProxy' ) ).to.be.true;
+			expect( textProxy.is( 'view:textProxy' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other accept values', () => {
 			expect( textProxy.is( 'node' ) ).to.be.false;
+			expect( textProxy.is( 'view:node' ) ).to.be.false;
 			expect( textProxy.is( 'text' ) ).to.be.false;
+			expect( textProxy.is( 'view:text' ) ).to.be.false;
 			expect( textProxy.is( 'element' ) ).to.be.false;
 			expect( textProxy.is( 'containerElement' ) ).to.be.false;
 			expect( textProxy.is( 'attributeElement' ) ).to.be.false;
@@ -76,6 +79,7 @@ describe( 'TextProxy', () => {
 			expect( textProxy.is( 'emptyElement' ) ).to.be.false;
 			expect( textProxy.is( 'rootElement' ) ).to.be.false;
 			expect( textProxy.is( 'documentFragment' ) ).to.be.false;
+			expect( textProxy.is( 'model:textProxy' ) ).to.be.false;
 		} );
 	} );
 

+ 13 - 0
packages/ckeditor5-engine/tests/view/uielement.js

@@ -46,16 +46,26 @@ describe( 'UIElement', () => {
 
 		it( 'should return true for uiElement/element, also with correct name and element name', () => {
 			expect( el.is( 'uiElement' ) ).to.be.true;
+			expect( el.is( 'view:uiElement' ) ).to.be.true;
 			expect( el.is( 'uiElement', 'span' ) ).to.be.true;
+			expect( el.is( 'view:uiElement', 'span' ) ).to.be.true;
 			expect( el.is( 'element' ) ).to.be.true;
+			expect( el.is( 'view:element' ) ).to.be.true;
+			expect( el.is( 'node' ) ).to.be.true;
+			expect( el.is( 'view:node' ) ).to.be.true;
 			expect( el.is( 'element', 'span' ) ).to.be.true;
+			expect( el.is( 'view:element', 'span' ) ).to.be.true;
 			expect( el.is( 'span' ) ).to.be.true;
+			expect( el.is( 'view:span' ) ).to.be.true;
 		} );
 
 		it( 'should return false for other accept values', () => {
 			expect( el.is( 'uiElement', 'p' ) ).to.be.false;
+			expect( el.is( 'view:uiElement', 'p' ) ).to.be.false;
 			expect( el.is( 'element', 'p' ) ).to.be.false;
+			expect( el.is( 'view:element', 'p' ) ).to.be.false;
 			expect( el.is( 'p' ) ).to.be.false;
+			expect( el.is( 'view:p' ) ).to.be.false;
 			expect( el.is( 'text' ) ).to.be.false;
 			expect( el.is( 'textProxy' ) ).to.be.false;
 			expect( el.is( 'containerElement' ) ).to.be.false;
@@ -63,6 +73,9 @@ describe( 'UIElement', () => {
 			expect( el.is( 'emptyElement' ) ).to.be.false;
 			expect( el.is( 'rootElement' ) ).to.be.false;
 			expect( el.is( 'documentFragment' ) ).to.be.false;
+			expect( el.is( 'model:element' ) ).to.be.false;
+			expect( el.is( 'model:span' ) ).to.be.false;
+			expect( el.is( 'model:node' ) ).to.be.false;
 		} );
 	} );