ソースを参照

Merge branch 'master' into t/190

Piotrek Koszuliński 9 年 前
コミット
6ec31d6c88
91 ファイル変更2053 行追加1181 行削除
  1. 5 8
      packages/ckeditor5-engine/CHANGES.md
  2. 2 3
      packages/ckeditor5-engine/CONTRIBUTING.md
  3. 10 18
      packages/ckeditor5-engine/LICENSE.md
  4. 2 3
      packages/ckeditor5-engine/README.md
  5. 5 5
      packages/ckeditor5-engine/src/ckeditor.js
  6. 5 4
      packages/ckeditor5-engine/src/ckeditorerror.js
  7. 10 10
      packages/ckeditor5-engine/src/collection.js
  8. 4 7
      packages/ckeditor5-engine/src/config.js
  9. 8 0
      packages/ckeditor5-engine/src/core.jsdoc
  10. 7 6
      packages/ckeditor5-engine/src/creator.js
  11. 8 0
      packages/ckeditor5-engine/src/dataprocessor.jsdoc
  12. 2 2
      packages/ckeditor5-engine/src/dataprocessor/basichtmlwriter.js
  13. 3 3
      packages/ckeditor5-engine/src/dataprocessor/dataprocessor.js
  14. 4 6
      packages/ckeditor5-engine/src/dataprocessor/htmldataprocessor.js
  15. 2 2
      packages/ckeditor5-engine/src/dataprocessor/htmlwriter.js
  16. 8 0
      packages/ckeditor5-engine/src/editable.jsdoc
  17. 6 10
      packages/ckeditor5-engine/src/editable/editable.js
  18. 11 2
      packages/ckeditor5-engine/src/editable/editableview.js
  19. 8 9
      packages/ckeditor5-engine/src/editor.js
  20. 5 6
      packages/ckeditor5-engine/src/editorconfig.js
  21. 3 3
      packages/ckeditor5-engine/src/editorui.js
  22. 8 4
      packages/ckeditor5-engine/src/emittermixin.js
  23. 7 4
      packages/ckeditor5-engine/src/eventinfo.js
  24. 4 4
      packages/ckeditor5-engine/src/log.js
  25. 25 21
      packages/ckeditor5-engine/src/observablemixin.js
  26. 5 6
      packages/ckeditor5-engine/src/plugin.js
  27. 5 7
      packages/ckeditor5-engine/src/plugincollection.js
  28. 8 0
      packages/ckeditor5-engine/src/treecontroller.jsdoc
  29. 22 24
      packages/ckeditor5-engine/src/treecontroller/mapper.js
  30. 8 0
      packages/ckeditor5-engine/src/treemodel.jsdoc
  31. 10 8
      packages/ckeditor5-engine/src/treemodel/batch-base.js
  32. 9 9
      packages/ckeditor5-engine/src/treemodel/characterproxy.js
  33. 8 0
      packages/ckeditor5-engine/src/treemodel/delta.jsdoc
  34. 8 9
      packages/ckeditor5-engine/src/treemodel/delta/attributedelta.js
  35. 8 10
      packages/ckeditor5-engine/src/treemodel/delta/delta.js
  36. 7 7
      packages/ckeditor5-engine/src/treemodel/delta/insertdelta.js
  37. 5 5
      packages/ckeditor5-engine/src/treemodel/delta/mergedelta.js
  38. 6 6
      packages/ckeditor5-engine/src/treemodel/delta/movedelta.js
  39. 5 5
      packages/ckeditor5-engine/src/treemodel/delta/removedelta.js
  40. 5 5
      packages/ckeditor5-engine/src/treemodel/delta/splitdelta.js
  41. 5 5
      packages/ckeditor5-engine/src/treemodel/delta/unwrapdelta.js
  42. 13 13
      packages/ckeditor5-engine/src/treemodel/delta/weakinsertdelta.js
  43. 7 7
      packages/ckeditor5-engine/src/treemodel/delta/wrapdelta.js
  44. 40 41
      packages/ckeditor5-engine/src/treemodel/document.js
  45. 27 17
      packages/ckeditor5-engine/src/treemodel/element.js
  46. 45 39
      packages/ckeditor5-engine/src/treemodel/liveposition.js
  47. 28 27
      packages/ckeditor5-engine/src/treemodel/liverange.js
  48. 25 20
      packages/ckeditor5-engine/src/treemodel/node.js
  49. 31 31
      packages/ckeditor5-engine/src/treemodel/nodelist.js
  50. 9 0
      packages/ckeditor5-engine/src/treemodel/operation.jsdoc
  51. 17 11
      packages/ckeditor5-engine/src/treemodel/operation/attributeoperation.js
  52. 14 8
      packages/ckeditor5-engine/src/treemodel/operation/insertoperation.js
  53. 14 8
      packages/ckeditor5-engine/src/treemodel/operation/moveoperation.js
  54. 9 2
      packages/ckeditor5-engine/src/treemodel/operation/nooperation.js
  55. 17 19
      packages/ckeditor5-engine/src/treemodel/operation/operation.js
  56. 8 4
      packages/ckeditor5-engine/src/treemodel/operation/reinsertoperation.js
  57. 11 4
      packages/ckeditor5-engine/src/treemodel/operation/removeoperation.js
  58. 13 11
      packages/ckeditor5-engine/src/treemodel/operation/transform.js
  59. 42 43
      packages/ckeditor5-engine/src/treemodel/position.js
  60. 54 53
      packages/ckeditor5-engine/src/treemodel/range.js
  61. 6 6
      packages/ckeditor5-engine/src/treemodel/rootelement.js
  62. 21 22
      packages/ckeditor5-engine/src/treemodel/selection.js
  63. 4 5
      packages/ckeditor5-engine/src/treemodel/text.js
  64. 17 17
      packages/ckeditor5-engine/src/treemodel/textfragment.js
  65. 31 31
      packages/ckeditor5-engine/src/treemodel/treewalker.js
  66. 8 0
      packages/ckeditor5-engine/src/treeview.jsdoc
  67. 30 30
      packages/ckeditor5-engine/src/treeview/converter.js
  68. 23 25
      packages/ckeditor5-engine/src/treeview/element.js
  69. 21 24
      packages/ckeditor5-engine/src/treeview/node.js
  70. 8 0
      packages/ckeditor5-engine/src/treeview/observer.jsdoc
  71. 42 36
      packages/ckeditor5-engine/src/treeview/observer/mutationobserver.js
  72. 12 13
      packages/ckeditor5-engine/src/treeview/observer/observer.js
  73. 8 8
      packages/ckeditor5-engine/src/treeview/position.js
  74. 18 19
      packages/ckeditor5-engine/src/treeview/renderer.js
  75. 5 10
      packages/ckeditor5-engine/src/treeview/text.js
  76. 22 20
      packages/ckeditor5-engine/src/treeview/treeview.js
  77. 8 0
      packages/ckeditor5-engine/src/ui.jsdoc
  78. 9 10
      packages/ckeditor5-engine/src/ui/controller.js
  79. 3 5
      packages/ckeditor5-engine/src/ui/controllercollection.js
  80. 40 32
      packages/ckeditor5-engine/src/ui/domemittermixin.js
  81. 2 4
      packages/ckeditor5-engine/src/ui/model.js
  82. 4 7
      packages/ckeditor5-engine/src/ui/region.js
  83. 122 54
      packages/ckeditor5-engine/src/ui/template.js
  84. 326 73
      packages/ckeditor5-engine/src/ui/view.js
  85. 1 0
      packages/ckeditor5-engine/src/utils-diff.js
  86. 19 5
      packages/ckeditor5-engine/src/utils.js
  87. 4 2
      packages/ckeditor5-engine/tests/_utils/ui/editable/framed/framededitableview.js
  88. 3 3
      packages/ckeditor5-engine/tests/treemodel/document/change-event.js
  89. 1 1
      packages/ckeditor5-engine/tests/treemodel/operation/attributeoperation.js
  90. 119 24
      packages/ckeditor5-engine/tests/ui/template.js
  91. 406 91
      packages/ckeditor5-engine/tests/ui/view.js

+ 5 - 8
packages/ckeditor5-engine/CHANGES.md

@@ -1,9 +1,9 @@
-{App Name} Changelog
-====================
+CKEditor 5 Core Framework Changelog
+========================================
 
-## App 1.2.3
+## CKEditor 5 Core Framework 0.0.2
 
-**Major|Minor|Patch Release** - Build Date: yyyy-mm-dd
+**Major|Minor|Patch Release**  Build Date: yyyy-mm-dd
 
 New Features:
 
@@ -15,14 +15,11 @@ Fixed Issues:
 * [#Issue Number](http://issue/url): Item 1.
 * Item 2
 
-
 Other Changes:
 
 * Item 1
 * Item 2
 
----
-
-## App 1.2.2
+## CKEditor 5 Core Framework 0.0.1
 
 ...

+ 2 - 3
packages/ckeditor5-engine/CONTRIBUTING.md

@@ -1,5 +1,4 @@
 Contributing
-============
+========================================
 
-Information about contributing can be found at the following page:
-https://github.com/ckeditor/ckeditor5/blob/master/CONTRIBUTING.md
+Information about contributing can be found at the following page: <https://github.com/ckeditor/ckeditor5/blob/master/CONTRIBUTING.md>.

+ 10 - 18
packages/ckeditor5-engine/LICENSE.md

@@ -1,37 +1,29 @@
 Software License Agreement
 ==========================
 
-**CKEditor 5 Core Framework** - https://github.com/ckeditor/ckeditor5-core <br>
+**CKEditor 5 Core Framework**  https://github.com/ckeditor/ckeditor5-core <br>
 Copyright (c) 2003-2016, [CKSource](http://cksource.com) Frederico Knabben. All rights reserved.
 
 Licensed under the terms of any of the following licenses at your choice:
 
- * [GNU General Public License Version 2 or later (the "GPL")](http://www.gnu.org/licenses/gpl.html)
+* [GNU General Public License Version 2 or later (the "GPL")](http://www.gnu.org/licenses/gpl.html)
+* [GNU Lesser General Public License Version 2.1 or later (the "LGPL")](http://www.gnu.org/licenses/lgpl.html)
+* [Mozilla Public License Version 1.1 or later (the "MPL")](http://www.mozilla.org/MPL/MPL-1.1.html)
 
- * [GNU Lesser General Public License Version 2.1 or later (the "LGPL")](http://www.gnu.org/licenses/lgpl.html)
-
- * [Mozilla Public License Version 1.1 or later (the "MPL")](http://www.mozilla.org/MPL/MPL-1.1.html)
-
-You are not required to, but if you want to explicitly declare the license you have chosen to be bound to when using,
-reproducing, modifying and distributing this software, just include a text file titled "legal.txt" in your version of
-this software, indicating your license choice. In any case, your choice will not restrict any recipient of your version
-of this software to use, reproduce, modify and distribute this software under any of the above licenses.
+You are not required to, but if you want to explicitly declare the license you have chosen to be bound to when using, reproducing, modifying and distributing this software, just include a text file titled "legal.txt" in your version of this software, indicating your license choice. In any case, your choice will not restrict any recipient of your version of this software to use, reproduce, modify and distribute this software under any of the above licenses.
 
 Sources of Intellectual Property Included in CKEditor
 -----------------------------------------------------
 
-Where not otherwise indicated, all CKEditor content is authored by CKSource engineers and consists of CKSource-owned
-intellectual property. In some specific instances, CKEditor will incorporate work done by developers outside of CKSource
-with their express permission.
+Where not otherwise indicated, all CKEditor content is authored by CKSource engineers and consists of CKSource-owned intellectual property. In some specific instances, CKEditor will incorporate work done by developers outside of CKSource with their express permission.
 
 Third parties' software included:
 
- * Lo-Dash (src/lib/lodash) <br>
-   Copyright 2012-2015 [The Dojo Foundation](http://dojofoundation.org/) <br>
-   Available under [MIT license](http://lodash.com/license)
+* Lo-Dash (src/lib/lodash) <br>
+  Copyright 2012-2015 [The Dojo Foundation](http://dojofoundation.org/) <br>
+  Available under [MIT license](http://lodash.com/license)
 
 Trademarks
 ----------
 
-**CKEditor** is a trademark of [CKSource](http://cksource.com) Frederico Knabben. All other brand and product names are
-trademarks, registered trademarks or service marks of their respective holders.
+**CKEditor** is a trademark of [CKSource](http://cksource.com) Frederico Knabben. All other brand and product names are trademarks, registered trademarks or service marks of their respective holders.

+ 2 - 3
packages/ckeditor5-engine/README.md

@@ -1,10 +1,9 @@
 CKEditor 5 Core Framework
-================================
+========================================
 
 [![devDependency Status](https://david-dm.org/ckeditor/ckeditor5-core/dev-status.svg)](https://david-dm.org/ckeditor/ckeditor5-core#info=devDependencies)
 
-The core framework of CKEditor 5 project. More information about the project can be found at the following url: <br>
-https://github.com/ckeditor/ckeditor5
+The core framework of CKEditor 5 project. More information about the project can be found at the following url: <https://github.com/ckeditor/ckeditor5>.
 
 ## License
 

+ 5 - 5
packages/ckeditor5-engine/src/ckeditor.js

@@ -12,16 +12,14 @@ import Config from './config.js';
 /**
  * This is the API entry point. The entire CKEditor code runs under this object.
  *
- * @class CKEDITOR
- * @singleton
+ * @namespace CKEDITOR
  */
-
 const CKEDITOR = {
 	/**
 	 * A collection containing all editor instances created.
 	 *
 	 * @readonly
-	 * @property {Collection}
+	 * @member {core.Collection} CKEDITOR.instances
 	 */
 	instances: new Collection(),
 
@@ -37,6 +35,7 @@ const CKEDITOR = {
 	 *			// Manipulate "editor" here.
 	 *		} );
 	 *
+	 * @method CKEDITOR.create
 	 * @param {String|HTMLElement} element An element selector or a DOM element, which will be the source for the
 	 * created instance.
 	 * @returns {Promise} A promise, which will be fulfilled with the created editor.
@@ -75,8 +74,9 @@ const CKEDITOR = {
 	/**
 	 * Holds global configuration defaults, which will be used by editor instances when such configurations are not
 	 * available on them directly.
+	 * @member {core.Config} CKEDITOR.config
 	 */
 	config: new Config()
 };
 
-export default CKEDITOR;
+export default CKEDITOR;

+ 5 - 4
packages/ckeditor5-engine/src/ckeditorerror.js

@@ -13,17 +13,15 @@
  *
  * Read more in the {@link core.log} module.
  *
- * @class CKEditorError
+ * @memberOf core
  * @extends Error
  */
-
 export default class CKEditorError extends Error {
 	/**
 	 * Creates an instance of the CKEditorError class.
 	 *
 	 * Read more about error logging in the {@link core.log} module.
 	 *
-	 * @constructor
 	 * @param {String} message The error message in an `error-name: Error message.` format.
 	 * During the minification process the "Error message" part will be removed to limit the code size
 	 * and a link to this error documentation will be added to the `message`.
@@ -38,12 +36,15 @@ export default class CKEditorError extends Error {
 
 		super( message );
 
+		/**
+		 * @member {String} core.CKEditorError#name
+		 */
 		this.name = 'CKEditorError';
 
 		/**
 		 * The additional error data passed to the constructor.
 		 *
-		 * @property {Object} data
+		 * @member {Object} core.CKEditorError#data
 		 */
 		this.data = data;
 	}

+ 10 - 10
packages/ckeditor5-engine/src/collection.js

@@ -19,16 +19,14 @@ import utils from './utils.js';
  * By default an item in the collection is identified by its `id` property. The name of the identifier can be
  * configured through the constructor of the collection.
  *
- * @class Collection
- * @mixins EventEmitter
+ * @memberOf core
+ * @mixes EventEmitter
  */
-
 export default class Collection {
 	/**
 	 * Creates a new Collection instance.
 	 *
-	 * @constructor
-	 * @param {Iterale} [items] Items to be added to the collection.
+	 * @param {Iterable} [items] Items to be added to the collection.
 	 * @param {Object} options The options object.
 	 * @param {String} [options.idProperty='id'] The name of the property which is considered to identify an item.
 	 */
@@ -37,7 +35,7 @@ export default class Collection {
 		 * The internal list of items in the collection.
 		 *
 		 * @private
-		 * @property {Object[]}
+		 * @type {Object[]}
 		 */
 		this._items = [];
 
@@ -45,7 +43,7 @@ export default class Collection {
 		 * The internal map of items in the collection.
 		 *
 		 * @private
-		 * @property {Map}
+		 * @type {Map}
 		 */
 		this._itemMap = new Map();
 
@@ -53,7 +51,7 @@ export default class Collection {
 		 * The name of the property which is considered to identify an item.
 		 *
 		 * @private
-		 * @property {String}
+		 * @type {String}
 		 */
 		this._idProperty = options && options.idProperty || 'id';
 	}
@@ -76,6 +74,7 @@ export default class Collection {
 	 * @param {Object} item
 	 * @param {Number} [index] The position of the item in the collection. The item
 	 * is pushed to the collection when `index` not specified.
+	 * @fires {@link core.Collection.add add}
 	 */
 	add( item, index ) {
 		let itemId;
@@ -157,6 +156,7 @@ export default class Collection {
 	 *
 	 * @param {Object|Number|String} subject The item to remove, its id or index in the collection.
 	 * @returns {Object} The removed item.
+	 * @fires {@link core.Collection.remove remove}
 	 */
 	remove( subject ) {
 		let index, id, item;
@@ -270,13 +270,13 @@ utils.mix( Collection, EmitterMixin );
 /**
  * Fired when an item is added to the collection.
  *
- * @event add
+ * @event core.Collection.add
  * @param {Object} item The added item.
  */
 
 /**
  * Fired when an item is removed from the collection.
  *
- * @event remove
+ * @event core.Collection.remove
  * @param {Object} item The removed item.
  */

+ 4 - 7
packages/ckeditor5-engine/src/config.js

@@ -13,16 +13,14 @@ import utils from './utils.js';
 /**
  * Handles a configuration dictionary.
  *
- * @class core.Config
- * @mixins core.ObservableMixin
+ * @memberOf core
+ * @mixes core.ObservableMixin
  */
-
 export default class Config {
 	/**
 	 * Creates an instance of the {@link Config} class.
 	 *
 	 * @param {Object} [configurations] The initial configurations to be set.
-	 * @constructor
 	 */
 	constructor( configurations ) {
 		if ( configurations ) {
@@ -63,7 +61,7 @@ export default class Config {
 	 *     config.toolbar.collapsed; // true
 	 *     config.toolbar.color; // 'red'
 	 *
-	 * @param {String|Object} nameOrConfigurations The configuration name or an object from which take properties as
+	 * @param {String|Object} name The configuration name or an object from which take properties as
 	 * configuration entries. Configuration names are case-insensitive.
 	 * @param {*} [value=null] The configuration value. Used if a name is passed to nameOrConfigurations.
 	 */
@@ -171,7 +169,7 @@ export default class Config {
 	 * This method is supposed to be called by plugin developers to setup plugin's configurations. It would be
 	 * rarely used for other needs.
 	 *
-	 * @param {String|Object} nameOrConfigurations The configuration name or an object from which take properties as
+	 * @param {String|Object} name The configuration name or an object from which take properties as
 	 * configuration entries.
 	 * @param {*} [value] The configuration value. Used if a name is passed to nameOrConfigurations. If undefined,
 	 * the configuration is set to `null`.
@@ -181,7 +179,6 @@ export default class Config {
 			/**
 			 * TODO
 			 *
-			 * @property
 			 * @type {Config}
 			 */
 			this.definition = new Config();

+ 8 - 0
packages/ckeditor5-engine/src/core.jsdoc

@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @namespace core
+ */

+ 7 - 6
packages/ckeditor5-engine/src/creator.js

@@ -10,16 +10,15 @@ import Plugin from './plugin.js';
 /**
  * Basic creator class.
  *
- * @class core.Creator
+ * @memberOf core
  * @extends core.Plugin
  */
-
 export default class Creator extends Plugin {
 	/**
-	 * The element used to {@link #_replaceElement replace} the editor element.
+	 * The element used to {@link core.Creator#_replaceElement _replaceElement} the editor element.
 	 *
 	 * @private
-	 * @property {HTMLElement} _elementReplacemenet
+	 * @member {HTMLElement} core.Creator#_elementReplacement
 	 */
 
 	/**
@@ -64,6 +63,7 @@ export default class Creator extends Plugin {
 
 	/**
 	 * Updates the {@link core.Editor#element editor element}'s content with the data.
+	 *
 	 */
 	updateEditorElement() {
 		Creator.setDataInElement( this.editor.element, this.editor.getData() );
@@ -71,6 +71,7 @@ export default class Creator extends Plugin {
 
 	/**
 	 * Loads the data from the {@link core.Editor#element editor element} to the editable.
+	 *
 	 */
 	loadDataFromEditorElement() {
 		this.editor.setData( Creator.getDataFromElement( this.editor.element ) );
@@ -108,7 +109,7 @@ export default class Creator extends Plugin {
 	 * Hides the {@link core.Editor#element editor element} and inserts the the given element
 	 * (usually, editor's UI main element) next to it.
 	 *
-	 * The effect of this method will be automatically reverted by {@link #destroy}.
+	 * The effect of this method will be automatically reverted by {@link core.Creator#destroy destroy}.
 	 *
 	 * @protected
 	 * @param {HTMLElement} [newElement] The replacement element. If not passed, then the main editor's UI view element
@@ -128,7 +129,7 @@ export default class Creator extends Plugin {
 	}
 
 	/**
-	 * Restores what the {@link #_replaceElement} did.
+	 * Restores what the {@link core.Creator#_replaceElement _replaceElement} did.
 	 *
 	 * @protected
 	 */

+ 8 - 0
packages/ckeditor5-engine/src/dataprocessor.jsdoc

@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @namespace core.dataProcessor
+ */

+ 2 - 2
packages/ckeditor5-engine/src/dataprocessor/basichtmlwriter.js

@@ -9,8 +9,8 @@
  * Basic HTML writer, it uses the native `innerHTML` property for basic conversion
  * from DocumentFragment to an HTML string.
  *
- * @class dataProcessor.BasicHtmlWriter
- * @implements dataProcessor.HtmlWriter
+ * @memberOf core.dataProcessor
+ * @implements core.dataProcessor.HtmlWriter
  */
 export default class BasicHtmlWriter {
 	/**

+ 3 - 3
packages/ckeditor5-engine/src/dataprocessor/dataprocessor.js

@@ -8,13 +8,13 @@
  * Each data processor implements a certain format of the data. E.g. `MarkdownDataProcessor` will convert the data
  * (Markdown string) to a DocumentFragment and back.
  *
- * @interface dataProcessor.DataProcessor
+ * @interface core.dataProcessor.DataProcessor
  */
 
 /**
  * Converts a DocumentFragment to data.
  *
- * @method toData
+ * @method core.dataProcessor.DataProcessor#toData
  * @param {DocumentFragment} fragment DocumentFragment to be processed.
  * @returns {*}
  */
@@ -22,7 +22,7 @@
 /**
  * Converts data to a DocumentFragment.
  *
- * @method toDom
+ * @method core.dataProcessor.DataProcessor#toDom
  * @param {*} data Data to be processed.
  * @returns {DocumentFragment}
  */

+ 4 - 6
packages/ckeditor5-engine/src/dataprocessor/htmldataprocessor.js

@@ -11,21 +11,19 @@ import BasicHtmlWriter from './basichtmlwriter.js';
  * HtmlDataProcessor class.
  * This data processor implementation uses HTML as input/output data.
  *
- * @class dataProcessor.HtmlDataProcessor
- * @implements dataProcessor.DataProcessor
+ * @memberOf core.dataProcessor
+ * @implements core.dataProcessor.DataProcessor
  */
 export default class HtmlDataProcessor {
 	/**
 	 * Creates a new instance of the HtmlDataProcessor class.
-	 *
-	 * @constructor
 	 */
 	constructor() {
 		/**
 		 * DOMParser instance used to parse HTML string to HTMLDocument.
 		 *
 		 * @private
-		 * @property {DOMParser}
+		 * @member {DOMParser} core.dataProcessor.HtmlDataProcessor#_domParser
 		 */
 		this._domParser = new DOMParser();
 
@@ -33,7 +31,7 @@ export default class HtmlDataProcessor {
 		 * BasicHtmlWriter instance used to convert DOM elements to HTML string.
 		 *
 		 * @private
-		 * @type {dataProcessor.BasicHtmlWriter}
+		 * @member {core.dataProcessor.BasicHtmlWriter} core.dataProcessor.HtmlDataProcessor#_htmlWriter
 		 */
 		this._htmlWriter = new BasicHtmlWriter();
 	}

+ 2 - 2
packages/ckeditor5-engine/src/dataprocessor/htmlwriter.js

@@ -6,13 +6,13 @@
 /**
  * HTML writer interface.
  *
- * @interface dataProcessor.HtmlWriter
+ * @interface core.dataProcessor.HtmlWriter
  */
 
 /**
  * Returns HTML string created from DocumentFragment.
  *
- * @method getHtml
+ * @method core.dataProcessor.HtmlWriter#getHtml
  * @param {DocumentFragment} fragment
  * @returns {String}
  */

+ 8 - 0
packages/ckeditor5-engine/src/editable.jsdoc

@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @namespace core.editable
+ */

+ 6 - 10
packages/ckeditor5-engine/src/editable/editable.js

@@ -11,15 +11,15 @@ import utils from '../utils.js';
 import ObservableMixin from '../observablemixin.js';
 
 /**
- * @class core.editable.Editable
+ * @memberOf core.editable
  * @extends core.ui.Controller
- * @mixins core.ObservableMixin
+ * @mixes core.ObservableMixin
  */
 export default class Editable extends Controller {
 	/**
 	 * Creates a new instance of the Editable class.
 	 *
-	 * @constructor
+	 * @param editor
 	 */
 	constructor( editor ) {
 		super();
@@ -29,7 +29,7 @@ export default class Editable extends Controller {
 		/**
 		 * Whether the editable is in read-write or read-only mode.
 		 *
-		 * @property {Boolean} isEditable
+		 * @member {Boolean} core.editable.Editable#isEditable
 		 */
 		this.set( 'isEditable', true );
 
@@ -37,20 +37,16 @@ export default class Editable extends Controller {
 		 * Whether the editable is focused.
 		 *
 		 * @readonly
-		 * @property {Boolean} isFocused
+		 * @member {Boolean} core.editable.Editable#isFocused
 		 */
 		this.set( 'isFocused', false );
-
-		/**
-		 * @private {Model} _viewModel
-		 */
 	}
 
 	/**
 	 * The model for the editable view.
 	 *
 	 * @readonly
-	 * @property {core.ui.Model} viewModel
+	 * @type {core.ui.Model}
 	 */
 	get viewModel() {
 		if ( this._viewModel ) {

+ 11 - 2
packages/ckeditor5-engine/src/editable/editableview.js

@@ -8,15 +8,24 @@
 import View from '../ui/view.js';
 import CKEditorError from '../ckeditorerror.js';
 
+/**
+ * @memberOf core.editable
+ * @extends core.ui.View
+ */
 export default class EditableView extends View {
 	/**
 	 * The element which is the main editable element (usually the one with `contentEditable="true"`).
 	 *
 	 * @readonly
-	 * @property {HTMLElement} editableElement
+	 * @member {HTMLElement} core.editable.EditableView#editableElement
 	 */
 
+	/**
+	 * @param {HTMLElement} editableElement
+	 */
 	setEditableElement( editableElement ) {
+		const bind = this.attributeBinder;
+
 		if ( this.editableElement ) {
 			throw new CKEditorError(
 				'editableview-cannot-override-editableelement: The editableElement cannot be overriden.'
@@ -36,7 +45,7 @@ export default class EditableView extends View {
 			},
 
 			attributes: {
-				contentEditable: this.bindToAttribute( 'isEditable' )
+				contentEditable: bind.to( 'isEditable' )
 			}
 		} );
 	}

+ 8 - 9
packages/ckeditor5-engine/src/editor.js

@@ -15,10 +15,9 @@ import utils from './utils.js';
 /**
  * Represents a single editor instance.
  *
- * @class core.Editor
- * @mixins core.ObservableMixin
+ * @memberOf core
+ * @mixes core.ObservableMixin
  */
-
 export default class Editor {
 	/**
 	 * Creates a new instance of the Editor class.
@@ -27,7 +26,6 @@ export default class Editor {
 	 * {@link CKEDITOR#create CKEDITOR.create() method}.
 	 *
 	 * @param {HTMLElement} element The DOM element that will be the source for the created editor.
-	 * @constructor
 	 */
 	constructor( element, config ) {
 		/**
@@ -35,7 +33,7 @@ export default class Editor {
 		 * editor creation and is not subject to be modified.
 		 *
 		 * @readonly
-		 * @property {HTMLElement}
+		 * @type {HTMLElement}
 		 */
 		this.element = element;
 
@@ -47,7 +45,7 @@ export default class Editor {
 		 * instance itself.
 		 *
 		 * @readonly
-		 * @property {Config}
+		 * @type {Config}
 		 */
 		this.config = new EditorConfig( config );
 
@@ -55,7 +53,7 @@ export default class Editor {
 		 * The plugins loaded and in use by this editor instance.
 		 *
 		 * @readonly
-		 * @property {PluginCollection}
+		 * @type {PluginCollection}
 		 */
 		this.plugins = new PluginCollection( this );
 
@@ -63,7 +61,7 @@ export default class Editor {
 		 * The chosen creator.
 		 *
 		 * @protected
-		 * @property {Creator} _creator
+		 * @type {Creator}
 		 */
 	}
 
@@ -133,7 +131,7 @@ export default class Editor {
 	 * Destroys the editor instance, releasing all resources used by it. If the editor replaced an element, the
 	 * element will be recovered.
 	 *
-	 * @fires destroy
+	 * @fires {@link core.Editor.destroy destroy}
 	 * @returns {Promise} A promise that resolves once the editor instance is fully destroyed.
 	 */
 	destroy() {
@@ -166,6 +164,7 @@ utils.mix( Editor, ObservableMixin );
  * Fired when this editor instance is destroyed. The editor at this point is not usable and this event should be used to
  * perform the clean-up in any plugin.
  *
+ * @memberOf core.Editor
  * @event destroy
  */
 

+ 5 - 6
packages/ckeditor5-engine/src/editorconfig.js

@@ -11,16 +11,15 @@ import Config from './config.js';
 /**
  * Handles a configuration dictionary for an editor instance.
  *
- * The basic difference between {@link EditorConfig} and {@link Config} is that {@link EditorConfig#get} retrieves
+ * The basic difference between {@link core.EditorConfig} and {@link core.Config} is that {@link core.EditorConfig#get} retrieves
  * configurations from {@link CKEDITOR#config} if they are not found.
  *
- * @class EditorConfig
- * @extends Config
+ * @memberOf core
+ * @extends core.Config
  */
-
 export default class EditorConfig extends Config {
 	/**
-	 * @inheritdoc core.Config#get
+	 * @inheritDoc
 	 */
 	get() {
 		// Try to take it from this editor instance.
@@ -33,4 +32,4 @@ export default class EditorConfig extends Config {
 
 		return value;
 	}
-}
+}

+ 3 - 3
packages/ckeditor5-engine/src/editorui.js

@@ -12,9 +12,9 @@ import ObservableMixin from './observablemixin.js';
 /**
  * Base class for the editor main view controllers.
  *
- * @class core.EditorUI
+ * @memberOf core
  * @extends core.ui.Controller
- * @mixins core.ObservableMixin
+ * @mixes core.ObservableMixin
  */
 
 export default class EditorUI extends Controller {
@@ -23,7 +23,7 @@ export default class EditorUI extends Controller {
 
 		/**
 		 * @readonly
-		 * @property {core.Editor}
+		 * @member {core.Editor} core.EditorUI.editor
 		 */
 		this.editor = editor;
 	}

+ 8 - 4
packages/ckeditor5-engine/src/emittermixin.js

@@ -15,11 +15,9 @@ let eventsCounter = 0;
 /**
  * Mixin that injects the events API into its host.
  *
- * @singleton
- * @class core.EmitterMixin
- * @implementes core.Emitter
+ * @mixin core.EmitterMixin
+ * @implements core.Emitter
  */
-
 const EmitterMixin = {
 	/**
 	 * Registers a callback function to be executed when an event is fired.
@@ -30,6 +28,7 @@ const EmitterMixin = {
 	 * event.
 	 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
 	 * Lower values are called first.
+	 * @method core.EmitterMixin#on
 	 */
 	on( event, callback, ctx, priority ) {
 		const callbacks = getCallbacks( this, event );
@@ -69,6 +68,7 @@ const EmitterMixin = {
 	 * event.
 	 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
 	 * Lower values are called first.
+	 * @method core.EmitterMixin#once
 	 */
 	once( event, callback, ctx, priority ) {
 		const onceCallback = function( event ) {
@@ -90,6 +90,7 @@ const EmitterMixin = {
 	 * @param {Function} callback The function to stop being called.
 	 * @param {Object} [ctx] The context object to be removed, pared with the given callback. To handle cases where
 	 * the same callback is used several times with different contexts.
+	 * @method core.EmitterMixin#off
 	 */
 	off( event, callback, ctx ) {
 		const callbacks = getCallbacksIfAny( this, event );
@@ -118,6 +119,7 @@ const EmitterMixin = {
 	 * @param {Object} [ctx] The object that represents `this` in the callback. Defaults to `emitter`.
 	 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
 	 * Lower values are called first.
+	 * @method core.EmitterMixin#listenTo
 	 */
 	listenTo( emitter, event, callback, ctx, priority ) {
 		let emitters, emitterId, emitterInfo, eventCallbacks;
@@ -174,6 +176,7 @@ const EmitterMixin = {
 	 * for all events from `emitter`.
 	 * @param {Function} [callback] (Requires the `event`) The function to be removed from the call list for the given
 	 * `event`.
+	 * @method core.EmitterMixin#stopListening
 	 */
 	stopListening( emitter, event, callback ) {
 		let emitters = this._listeningTo;
@@ -221,6 +224,7 @@ const EmitterMixin = {
 	 *
 	 * @param {String} event The name of the event.
 	 * @param {...*} [args] Additional arguments to be passed to the callbacks.
+	 * @method core.EmitterMixin#fire
 	 */
 	fire( event, args ) {
 		const callbacks = getCallbacksIfAny( this, event );

+ 7 - 4
packages/ckeditor5-engine/src/eventinfo.js

@@ -11,18 +11,21 @@ import utils from './utils.js';
  * The event object passed to event callbacks. It is used to provide information about the event as well as a tool to
  * manipulate it.
  *
- * @class EventInfo
+ * @memberOf core
  */
-
 export default class EventInfo {
 	constructor( source, name ) {
 		/**
 		 * The object that fired the event.
+		 *
+		 * @member core.EventInfo#source
 		 */
 		this.source = source;
 
 		/**
 		 * The event name.
+		 *
+		 * @member core.EventInfo#name
 		 */
 		this.name = name;
 
@@ -31,14 +34,14 @@ export default class EventInfo {
 		/**
 		 * Stops the event emitter to call further callbacks for this event interaction.
 		 *
-		 * @method
+		 * @method core.EventInfo#stop
 		 */
 		this.stop = utils.spy();
 
 		/**
 		 * Removes the current callback from future interactions of this event.
 		 *
-		 * @method
+		 * @method core.EventInfo#off
 		 */
 		this.off = utils.spy();
 	}

+ 4 - 4
packages/ckeditor5-engine/src/log.js

@@ -35,10 +35,8 @@
  * log an error.
  * * Whenever it's really bad and it does not make sense to continue working, throw a {@link core.CKEditorError}.
  *
- * @class log
- * @singleton
+ * @namespace core.log
  */
-
 const log = {
 	/**
 	 * Logs an error to the console.
@@ -49,6 +47,7 @@ const log = {
 	 * During the minification process the "Error message" part will be removed to limit the code size
 	 * and a link to this error documentation will be logged to the console.
 	 * @param {Object} [data] Additional data describing the error.
+	 * @method core.log.error
 	 */
 	error( message, data ) {
 		console.error( message, data );
@@ -63,10 +62,11 @@ const log = {
 	 * During the minification process the "Warning message" part will be removed to limit the code size
 	 * and a link to this error documentation will be logged to the console.
 	 * @param {Object} [data] Additional data describing the warning.
+	 * @method core.log.warn
 	 */
 	warn( message, data ) {
 		console.warn( message, data );
 	}
 };
 
-export default log;
+export default log;

+ 25 - 21
packages/ckeditor5-engine/src/observablemixin.js

@@ -18,12 +18,10 @@ const boundAttributesSymbol = Symbol( 'boundAttributes' );
  * Mixin that injects the "observable attributes" and data binding functionality.
  * Used mainly in the {@link core.ui.Model} class.
  *
- * @singleton
- * @class core.ObservableMixin
- * @mixins EmitterMixin
+ * @mixin core.ObservableMixin
+ * @mixes core.EmitterMixin
  * @implements core.Observable
  */
-
 const ObservableMixin = {
 	/**
 	 * Creates and sets the value of an observable attribute of this object. Such an attribute becomes a part
@@ -35,6 +33,7 @@ const ObservableMixin = {
 	 * have a property with a given attribute name. This prevents from mistakenly overriding existing
 	 * properties and methods, but means that `foo.set( 'bar', 1 )` may be slightly slower than `foo.bar = 1`.
 	 *
+	 * @method core.ObservableMixin#set
 	 * @param {String} name The attributes name.
 	 * @param {*} value The attributes value.
 	 */
@@ -103,15 +102,16 @@ const ObservableMixin = {
 	 * of the observable it is bound to and react to the changes to these attributes
 	 * in the future.
 	 *
-	 * **Note**: To release the binding use {@link #unbind}.
+	 * **Note**: To release the binding use {@link core.ObservableMixin#unbind}.
 	 *
 	 *		A.bind( 'a' ).to( B );
 	 *		A.bind( 'a' ).to( B, 'b' );
 	 *		A.bind( 'a', 'b' ).to( B, 'c', 'd' );
 	 *		A.bind( 'a' ).to( B, 'b', C, 'd', ( b, d ) => b + d );
 	 *
+	 * @method core.ObservableMixin#bind
 	 * @param {String...} bindAttrs Observable attributes that will be bound to another observable(s).
-	 * @returns {BindChain}
+	 * @returns {core.BindChain}
 	 */
 	bind( ...bindAttrs ) {
 		if ( !bindAttrs.length || !isStringArray( bindAttrs ) ) {
@@ -150,7 +150,7 @@ const ObservableMixin = {
 		const bindings = new Map();
 
 		/**
-		 * @typedef Binding
+		 * @typedef core.Binding
 		 * @type Object
 		 * @property {Array} attr Attribute which is bound.
 		 * @property {Array} to Array of observable–attribute components of the binding (`{ observable: ..., attr: .. }`).
@@ -164,13 +164,14 @@ const ObservableMixin = {
 		} );
 
 		/**
-		 * @typedef BindChain
+		 * @typedef core.BindChain
 		 * @type Object
-		 * @property {Function} to See {@link #_bindTo}.
+		 * @property {Function} to See {@link core.ObservableMixin#_bindTo}.
 		 * @property {Observable} _observable The observable which initializes the binding.
 		 * @property {Array} _bindAttrs Array of `_observable` attributes to be bound.
 		 * @property {Array} _to Array of `to()` observable–attributes (`{ observable: toObservable, attrs: ...toAttrs }`).
-		 * @property {Map} _bindings Stores bindings to be kept in {@link #_boundAttributes}/{@link #_boundObservables}
+		 * @property {Map} _bindings Stores bindings to be kept in
+		 *  {@link core.ObservableMixin#_boundAttributes}/{@link core.ObservableMixin#_boundObservables}
 		 * initiated in this binding chain.
 		 */
 		return {
@@ -184,12 +185,13 @@ const ObservableMixin = {
 	},
 
 	/**
-	 * Removes the binding created with {@link #bind}.
+	 * Removes the binding created with {@link core.ObservableMixin#bind}.
 	 *
 	 *		A.unbind( 'a' );
 	 *		A.unbind();
 	 *
-	 * @param {String...} [bindAttrs] Observable attributes to be unbound. All the bindings will
+	 * @method core.ObservableMixin#unbind
+	 * @param {String} [unbindAttrs] Observable attributes to be unbound. All the bindings will
 	 * be released if no attributes provided.
 	 */
 	unbind( ...unbindAttrs ) {
@@ -262,15 +264,15 @@ function initObservable( observable ) {
 	// The internal hash containing the observable's state.
 	//
 	// @private
-	// @property {Map} _attributes
+	// @type {Map}
 	Object.defineProperty( observable, attributesSymbol, {
 		value: new Map()
 	} );
 
 	// Map containing bindings to external observables. It shares the binding objects
-	// (`{ observable: A, attr: 'a', to: ... }`) with {@link #_boundAttributes} and
+	// (`{ observable: A, attr: 'a', to: ... }`) with {@link core.ObservableMixin#_boundAttributes} and
 	// it is used to observe external observables to update own attributes accordingly.
-	// See {@link #bind}.
+	// See {@link core.ObservableMixin#bind}.
 	//
 	//		A.bind( 'a', 'b', 'c' ).to( B, 'x', 'y', 'x' );
 	//		console.log( A._boundObservables );
@@ -311,15 +313,17 @@ function initObservable( observable ) {
 	//			} )
 	//
 	// @private
-	// @property {Map} _boundObservables
+	// @type {Map}
 	Object.defineProperty( observable, boundObservablesSymbol, {
 		value: new Map()
 	} );
 
 	// Object that stores which attributes of this observable are bound and how. It shares
-	// the binding objects (`{ observable: A, attr: 'a', to: ... }`) with {@link #_boundObservables}.
-	// This data structure is a reverse of {@link #_boundObservables} and it is helpful for {@link #unbind}.
-	// See {@link #bind}.
+	// the binding objects (`{ observable: A, attr: 'a', to: ... }`) with {@link core.ObservableMixin#_boundObservables}.
+	// This data structure is a reverse of {@link core.ObservableMixin#_boundObservables} and it is helpful for
+	// {@link core.ObservableMixin#unbind}.
+	//
+	// See {@link core.ObservableMixin#bind}.
 	//
 	//		A.bind( 'a', 'b', 'c' ).to( B, 'x', 'y', 'x' );
 	//		console.log( A._boundAttributes );
@@ -341,13 +345,13 @@ function initObservable( observable ) {
 	//			} )
 	//
 	// @private
-	// @property {Map} _boundAttributes
+	// @type {Map}
 	Object.defineProperty( observable, boundAttributesSymbol, {
 		value: new Map()
 	} );
 }
 
-// A chaining for {@link #bind} providing `.to()` interface.
+// A chaining for {@link core.ObservableMixin#bind} providing `.to()` interface.
 //
 // @private
 // @param {...[Observable|String|Function]} args Arguments of the `.to( args )` binding.

+ 5 - 6
packages/ckeditor5-engine/src/plugin.js

@@ -11,10 +11,9 @@ import utils from './utils.js';
 /**
  * The base class for CKEditor plugin classes.
  *
- * @class core.Plugin
- * @mixins core.ObservableMixin
+ * @memberOf core
+ * @mixes core.ObservableMixin
  */
-
 export default class Plugin {
 	/**
 	 * Creates a new Plugin instance.
@@ -24,7 +23,7 @@ export default class Plugin {
 	constructor( editor ) {
 		/**
 		 * @readonly
-		 * @property {core.Editor}
+		 * @member {core.Editor} core.Plugin#editor
 		 */
 		this.editor = editor;
 	}
@@ -43,11 +42,11 @@ export default class Plugin {
 	 *		}
 	 *
 	 * @static
-	 * @property {Function[]} requires
+	 * @member {Function[]} core.Plugin.requires
 	 */
 
 	/**
-	 * @returns {null/Promise}
+	 * @returns {null|Promise}
 	 */
 	init() {}
 

+ 5 - 7
packages/ckeditor5-engine/src/plugincollection.js

@@ -13,26 +13,24 @@ import load from '../load.js';
 /**
  * Manages a list of CKEditor plugins, including loading, resolving dependencies and initialization.
  *
- * @class PluginCollection
+ * @memberOf core
  */
-
 export default class PluginCollection {
 	/**
 	 * Creates an instance of the PluginCollection class, initializing it with a set of plugins.
 	 *
-	 * @constructor
 	 * @param {core.Editor} editor
 	 */
 	constructor( editor ) {
 		/**
 		 * @protected
-		 * @property {core.Editor}
+		 * @member {core.Editor} core.PluginCollection#_editor
 		 */
 		this._editor = editor;
 
 		/**
 		 * @protected
-		 * @property {Map}
+		 * @member {Map} core.PluginCollection#_plugins
 		 */
 		this._plugins = new Map();
 	}
@@ -49,7 +47,7 @@ export default class PluginCollection {
 	 * Gets the plugin instance by its name or class.
 	 *
 	 * @param {String/Function} key The name of the plugin or the class.
-	 * @returns {Plugin}
+	 * @returns {core.Plugin}
 	 */
 	get( key ) {
 		return this._plugins.get( key );
@@ -169,7 +167,7 @@ export default class PluginCollection {
 	 *
 	 * @protected
 	 * @param {String/Function} key The name or the plugin class.
-	 * @param {Plugin} plugin The instance of the plugin.
+	 * @param {core.Plugin} plugin The instance of the plugin.
 	 */
 	_add( key, plugin ) {
 		this._plugins.set( key, plugin );

+ 8 - 0
packages/ckeditor5-engine/src/treecontroller.jsdoc

@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @namespace core.treeController
+ */

+ 22 - 24
packages/ckeditor5-engine/src/treecontroller/mapper.js

@@ -10,25 +10,23 @@ import ViewPosition from '../treeview/position.js';
 import ViewText from '../treeview/text.js';
 
 /**
- * Maps elements and positions between {@link treeView TreeView} and {@link treeModel TreeModel}.
+ * Maps elements and positions between {@link core.treeView.TreeView TreeView} and {@link core.treeModel TreeModel}.
  *
  * Mapper use binded elements to find corresponding elements and positions, so, to get proper results,
- * all Tree Model elements should be {@link treeController.Mapper#bindElements binded}.
+ * all Tree Model elements should be {@link core.treeController.Mapper#bindElements binded}.
  *
- * @class treeController.Mapper
+ * @memberOf core.treeController
  */
 export default class Mapper {
 	/**
 	 * Creates an instance of the mapper.
-	 *
-	 * @constructor
 	 */
 	constructor() {
 		/**
 		 * Model element to View element mapping.
 		 *
 		 * @private
-		 * @type {WeakMap}
+		 * @member {WeakMap} core.treeController.Mapper#_modelToViewMapping
 		 */
 		this._modelToViewMapping = new WeakMap();
 
@@ -36,18 +34,18 @@ export default class Mapper {
 		 * View element to Model element mapping.
 		 *
 		 * @private
-		 * @type {WeakMap}
+		 * @member {WeakMap} core.treeController.Mapper#_viewToModelMapping
 		 */
 		this._viewToModelMapping = new WeakMap();
 	}
 
 	/**
 	 * Marks model and view elements as corresponding. Corresponding elements can be retrieved by using
-	 * the {@link #toModelElement} and {@link #toViewElement} methods.
-	 * The information that elements are bound is also used to translate positions.
+	 * the {@link core.treeController.Mapper#toModelElement toModelElement} and {@link core.treeController.Mapper#toViewElement toViewElement}
+	 * methods. The information that elements are bound is also used to translate positions.
 	 *
-	 * @param {treeModel.Element} modelElement Model element.
-	 * @param {treeView.Element} viewElement View element.
+	 * @param {core.treeModel.Element} modelElement Model element.
+	 * @param {core.treeView.Element} viewElement View element.
 	 */
 	bindElements( modelElement, viewElement ) {
 		this._modelToViewMapping.set( modelElement, viewElement );
@@ -57,8 +55,8 @@ export default class Mapper {
 	/**
 	 * Gets the corresponding model element.
 	 *
-	 * @param {treeView.Element} viewElement View element.
-	 * @returns {treeModel.Element|null} Corresponding model element or `null` if not found.
+	 * @param {core.treeView.Element} viewElement View element.
+	 * @returns {core.treeModel.Element|null} Corresponding model element or `null` if not found.
 	 */
 	toModelElement( viewElement ) {
 		return this._viewToModelMapping.get( viewElement );
@@ -67,8 +65,8 @@ export default class Mapper {
 	/**
 	 * Gets the corresponding view element.
 	 *
-	 * @param {treeModel.Element} modelElement Model element.
-	 * @returns {treeView.Element|null} Corresponding view element or `null` if not found.
+	 * @param {core.treeModel.Element} modelElement Model element.
+	 * @returns {core.treeView.Element|null} Corresponding view element or `null` if not found.
 	 */
 	toViewElement( modelElement ) {
 		return this._modelToViewMapping.get( modelElement );
@@ -77,8 +75,8 @@ export default class Mapper {
 	/**
 	 * Gets the corresponding model position.
 	 *
-	 * @param {treeView.Position} viewPosition View position.
-	 * @returns {treeModel.Position} Corresponding model position.
+	 * @param {core.treeView.Position} viewPosition View position.
+	 * @returns {core.treeModel.Position} Corresponding model position.
 	 */
 	toModelPosition( viewPosition ) {
 		let viewBlock = viewPosition.parent;
@@ -97,8 +95,8 @@ export default class Mapper {
 	/**
 	 * Gets the corresponding view position.
 	 *
-	 * @param {treeModel.Position} modelPosition Model position.
-	 * @returns {treeView.Position} Corresponding view position.
+	 * @param {core.treeModel.Position} modelPosition Model position.
+	 * @returns {core.treeView.Position} Corresponding view position.
 	 */
 	toViewPosition( modelPosition ) {
 		let viewContainer = this._modelToViewMapping.get( modelPosition.parent );
@@ -119,9 +117,9 @@ export default class Mapper {
 	 *		<p>foo<b>ba|r</b></p> // _toModelOffset( b, 2, b ) -> 2
 	 *
 	 * @private
-	 * @param {treeView.Element} viewParent Position parent.
+	 * @param {core.treeView.Element} viewParent Position parent.
 	 * @param {Number} viewOffset Position offset.
-	 * @param {treeView.Element} viewBlock Block used as a base to calculate offset.
+	 * @param {core.treeView.Element} viewBlock Block used as a base to calculate offset.
 	 * @returns {Number} Offset in the model.
 	 */
 	_toModelOffset( viewParent, viewOffset, viewBlock ) {
@@ -160,7 +158,7 @@ export default class Mapper {
 	 *		<p>foo</p>   -> 1 // Length the element which has corresponding model element is always 1.
 	 *
 	 * @private
-	 * @param {treeView.Element} viewNode View node.
+	 * @param {core.treeView.Element} viewNode View node.
 	 * @returns {Number} Length of the node in the tree model.
 	 */
 	_getModelLength( viewNode ) {
@@ -203,9 +201,9 @@ export default class Mapper {
 	 *		<p>fo<b>ba|r</b>bom</p> -> expected offset: 2, actual offset: 2 -> position found
 	 *
 	 * @private
-	 * @param {treeView.Element} viewParent Tree view element in which we are looking for the position.
+	 * @param {core.treeView.Element} viewParent Tree view element in which we are looking for the position.
 	 * @param {Number} expectedOffset Expected offset.
-	 * @returns {treeVew.Position} Found position.
+	 * @returns {core.treeView.Position} Found position.
 	 */
 	_findPositionIn( viewParent, expectedOffset ) {
 		// Last scanned view node.

+ 8 - 0
packages/ckeditor5-engine/src/treemodel.jsdoc

@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @namespace core.treeModel
+ */

+ 10 - 8
packages/ckeditor5-engine/src/treemodel/batch-base.js

@@ -28,29 +28,30 @@ import CKEditorError from '../ckeditorerror.js';
  *
  *		doc.batch().insert( firstPosition, 'foo' ).insert( secondPosition, 'bar' );
  *
- * @class treeModel.Batch
+ * @memberOf core.treeModel
  */
 export default class Batch {
 	/**
-	 * Creates Batch instance. Not recommended to use directly, use {@link treeModel.Document#batch} instead.
+	 * Creates Batch instance. Not recommended to use directly, use {@link core.treeModel.Document#batch} instead.
 	 *
-	 * @constructor
-	 * @param {treeModel.Document} doc Document which this Batch changes.
+	 * @param {core.treeModel.Document} doc Document which this Batch changes.
 	 */
 	constructor( doc ) {
 		/**
 		 * Document which this Batch changes.
 		 *
+		 * @member core.treeModel.Batch#doc
 		 * @readonly
-		 * @type {treeModel.Document}
+		 * @type {core.treeModel.Document}
 		 */
 		this.doc = doc;
 
 		/**
 		 * Array of deltas which compose Batch.
 		 *
+		 * @member core.treeModel.Batch#deltas
 		 * @readonly
-		 * @type {Array.<treeModel.delta.Delta>}
+		 * @type {Array.<core.treeModel.delta.Delta>}
 		 */
 		this.deltas = [];
 	}
@@ -59,8 +60,8 @@ export default class Batch {
 	 * Adds delta to the Batch instance. All modification methods (insert, remove, split, etc.) use this method
 	 * to add created deltas.
 	 *
-	 * @param {treeModel.delta.Delta} delta Delta to add.
-	 * @return {treeModel.delta.Delta} Added delta.
+	 * @param {core.treeModel.delta.Delta} delta Delta to add.
+	 * @return {core.treeModel.delta.Delta} Added delta.
 	 */
 	addDelta( delta ) {
 		delta.batch = this;
@@ -101,6 +102,7 @@ export default class Batch {
  *			return this;
  *		} );
  *
+ * @method core.treeModel.Batch.register
  * @param {String} name Method name.
  * @param {Function} creator Method body.
  */

+ 9 - 9
packages/ckeditor5-engine/src/treemodel/characterproxy.js

@@ -18,21 +18,21 @@ import Node from './node.js';
  *
  * CharacterProxy is created on the fly basing on tree model. It is not an explicit node in a tree model but
  * rather represents it. Because of this, it is not advised to store or compare instances of CharacterProxy class.
- * If you want to keep live reference to a point in a text, you should use {@link treeModel.LivePosition}.
+ * If you want to keep live reference to a point in a text, you should use {@link core.treeModel.LivePosition}.
  *
  * You should never create an instance of this class by your own. When passing parameters to constructors,
- * use string literals or {@link treeModel.Text} instead.
+ * use string literals or {@link core.treeModel.Text} instead.
  *
- * @class treeModel.CharacterProxy
+ * @memberOf core.treeModel
+ * @extends core.treeModel.Node
  */
 export default class CharacterProxy extends Node {
 	/**
 	 * Creates character node proxy.
 	 *
-	 * @param {treeModel.NodeListText} nodeListText Reference to a text object in a node list containing this character.
+	 * @param {core.treeModel.NodeListText} nodeListText Reference to a text object in a node list containing this character.
 	 * @param {Number} index Index of the character in `nodeListText`.
 	 * @protected
-	 * @constructor
 	 */
 	constructor( nodeListText, index ) {
 		super( nodeListText._attrs );
@@ -42,7 +42,7 @@ export default class CharacterProxy extends Node {
 		 *
 		 * @protected
 		 * @readonly
-		 * @property {treeModel.NodeListText} nodeListText
+		 * @member {core.treeModel.NodeListText} core.treeModel.CharacterProxy#_nodeListText
 		 */
 		this._nodeListText = nodeListText;
 
@@ -51,7 +51,7 @@ export default class CharacterProxy extends Node {
 		 *
 		 * @protected
 		 * @readonly
-		 * @property {Number} index
+		 * @member {Number} core.treeModel.CharacterProxy#_index
 		 */
 		this._index = index;
 
@@ -60,12 +60,12 @@ export default class CharacterProxy extends Node {
 		 *
 		 * @protected
 		 * @readonly
-		 * @property {String} character
+		 * @member {String} core.treeModel.CharacterProxy#character
 		 */
 		this.character = nodeListText.text.substr( index, 1 );
 
 		/**
-		 * @see {@link treeModel.Node#parent}
+		 * @inheritdoc
 		 */
 		this.parent = this._nodeListText.parent;
 	}

+ 8 - 0
packages/ckeditor5-engine/src/treemodel/delta.jsdoc

@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @namespace core.treeModel.delta
+ */

+ 8 - 9
packages/ckeditor5-engine/src/treemodel/delta/attributedelta.js

@@ -12,11 +12,12 @@ import Range from '../range.js';
 import Element from '../element.js';
 
 /**
- * To provide specific OT behavior and better collisions solving, change methods ({@link treeModel.Batch#setAttr}
- * and {@link treeModel.Batch#removeAttr}) use `AttributeDelta` class which inherits from the `Delta` class and may
+ * To provide specific OT behavior and better collisions solving, change methods ({@link core.treeModel.Batch#setAttr}
+ * and {@link core.treeModel.Batch#removeAttr}) use `AttributeDelta` class which inherits from the `Delta` class and may
  * overwrite some methods.
  *
- * @class treeModel.delta.AttributeDelta
+ * @memberOf core.treeModel.delta
+ * @extends core.treeModel.delta.Delta
  */
 export default class AttributeDelta extends Delta {}
 
@@ -24,11 +25,10 @@ export default class AttributeDelta extends Delta {}
  * Sets the value of the attribute of the node or on the range.
  *
  * @chainable
- * @method setAttr
- * @memberOf treeModel.Batch
+ * @method core.treeModel.Batch#setAttr
  * @param {String} key Attribute key.
  * @param {*} value Attribute new value.
- * @param {treeModel.Node|treeModel.Range} nodeOrRange Node or range on which the attribute will be set.
+ * @param {core.treeModel.Node|core.treeModel.Range} nodeOrRange Node or range on which the attribute will be set.
  */
 register( 'setAttr', function( key, value, nodeOrRange ) {
 	attribute( this, key, value, nodeOrRange );
@@ -40,10 +40,9 @@ register( 'setAttr', function( key, value, nodeOrRange ) {
  * Removes an attribute from the range.
  *
  * @chainable
- * @method removeAttr
- * @memberOf treeModel.Batch
+ * @method core.treeModel.Batch#removeAttr
  * @param {String} key Attribute key.
- * @param {treeModel.Node|treeModel.Range} nodeOrRange Node or range on which the attribute will be removed.
+ * @param {core.treeModel.Node|core.treeModel.Range} nodeOrRange Node or range on which the attribute will be removed.
  */
 register( 'removeAttr', function( key, nodeOrRange ) {
 	attribute( this, key, null, nodeOrRange );

+ 8 - 10
packages/ckeditor5-engine/src/treemodel/delta/delta.js

@@ -11,23 +11,21 @@
  * Delta is a single, from the user action point of view, change in the editable document, like insert, split or
  * rename element. Delta is composed of operations, which are unit changes needed to be done to execute user action.
  *
- * Multiple deltas are grouped into a single {@link treeModel.Batch}.
+ * Multiple deltas are grouped into a single {@link core.treeModel.Batch}.
  *
- * @class treeModel.delta.Delta
+ * @memberOf core.treeModel.delta
  */
 export default class Delta {
 	/**
 	 * Creates a delta instance.
-	 *
-	 * @constructor
 	 */
 	constructor() {
 		/**
-		 * {@link treeModel.Batch} which delta is a part of. This property is null by default and set by the
-		 * {@link treeModel.Batch#addDelta} method.
+		 * {@link core.treeModel.Batch} which delta is a part of. This property is null by default and set by the
+		 * {@link core.treeModel.Batch#addDelta} method.
 		 *
 		 * @readonly
-		 * @type {treeModel.Batch}
+		 * @member {core.treeModel.Batch} core.treeModel.delta.Delta#batch
 		 */
 		this.batch = null;
 
@@ -35,7 +33,7 @@ export default class Delta {
 		 * Array of operations which compose delta.
 		 *
 		 * @readonly
-		 * @type {treeModel.operation.Operation[]}
+		 * @member {core.treeModel.operation.Operation[]} core.treeModel.delta.Delta#operations
 		 */
 		this.operations = [];
 	}
@@ -43,7 +41,7 @@ export default class Delta {
 	/**
 	 * Add operation to the delta.
 	 *
-	 * @param {treeModel.operation.Operation} operation Operation instance.
+	 * @param {core.treeModel.operation.Operation} operation Operation instance.
 	 */
 	addOperation( operation ) {
 		operation.delta = this;
@@ -51,4 +49,4 @@ export default class Delta {
 
 		return operation;
 	}
-}
+}

+ 7 - 7
packages/ckeditor5-engine/src/treemodel/delta/insertdelta.js

@@ -10,10 +10,11 @@ import { register } from '../batch-base.js';
 import InsertOperation from '../operation/insertoperation.js';
 
 /**
- * To provide specific OT behavior and better collisions solving, the {@link treeModel.Batch#insert} method
+ * @classdesc
+ * To provide specific OT behavior and better collisions solving, the {@link core.treeModel.Batch#insert Batch#insert} method
  * uses the `InsertDelta` class which inherits from the `Delta` class and may overwrite some methods.
  *
- * @class treeModel.delta.InsertDelta
+ * @memberOf core.treeModel.delta
  */
 export default class InsertDelta extends Delta {}
 
@@ -21,11 +22,10 @@ export default class InsertDelta extends Delta {}
  * Inserts a node or nodes at the given position.
  *
  * @chainable
- * @memberOf treeModel.Batch
- * @method insert
- * @param {treeModel.Position} position Position of insertion.
- * @param {treeModel.NodeSet} nodes The list of nodes to be inserted.
- * List of nodes can be of any type accepted by the {@link treeModel.NodeList} constructor.
+ * @method core.treeModel.Batch#insert
+ * @param {core.treeModel.Position} position Position of insertion.
+ * @param {core.treeModel.NodeSet} nodes The list of nodes to be inserted.
+ * List of nodes can be of any type accepted by the {@link core.treeModel.NodeList} constructor.
  */
 register( 'insert', function( position, nodes ) {
 	const delta = new InsertDelta();

+ 5 - 5
packages/ckeditor5-engine/src/treemodel/delta/mergedelta.js

@@ -14,10 +14,11 @@ import MoveOperation from '../operation/moveoperation.js';
 import CKEditorError from '../../ckeditorerror.js';
 
 /**
- * To provide specific OT behavior and better collisions solving, {@link treeModel.Batch#merge} method
+ * @classdesc
+ * To provide specific OT behavior and better collisions solving, {@link core.treeModel.Batch#merge} method
  * uses the `MergeDelta` class which inherits from the `Delta` class and may overwrite some methods.
  *
- * @class treeModel.delta.MergeDelta
+ * @memberOf core.treeModel.delta
  */
 export default class MergeDelta extends Delta {}
 
@@ -28,9 +29,8 @@ export default class MergeDelta extends Delta {}
  * `batch-merge-no-element-after` error will be thrown.
  *
  * @chainable
- * @method merge
- * @memberOf treeModel.Batch
- * @param {treeModel.Position} position Position of merge.
+ * @method core.treeModel.Batch#merge
+ * @param {core.treeModel.Position} position Position of merge.
  */
 register( 'merge', function( position ) {
 	const delta = new MergeDelta();

+ 6 - 6
packages/ckeditor5-engine/src/treemodel/delta/movedelta.js

@@ -13,10 +13,11 @@ import Range from '../range.js';
 import CKEditorError from '../../ckeditorerror.js';
 
 /**
- * To provide specific OT behavior and better collisions solving, {@link treeModel.Batch#move} method
+ * @classdesc
+ * To provide specific OT behavior and better collisions solving, {@link core.treeModel.Batch#move} method
  * uses the `MoveDelta` class which inherits from the `Delta` class and may overwrite some methods.
  *
- * @class treeModel.delta.MoveDelta
+ * @memberOf core.treeModel.delta
  */
 export default class MoveDelta extends Delta {}
 
@@ -30,10 +31,9 @@ function addMoveOperation( batch, delta, sourcePosition, howMany, targetPosition
  * Moves given node or given range of nodes to target position.
  *
  * @chainable
- * @method move
- * @memberOf treeModel.Batch
- * @param {treeModel.Node|treeModel.Range} nodeOrRange Node or range of nodes to move.
- * @param {treeModel.Position} targetPosition Position where moved nodes will be inserted.
+ * @method core.treeModel.Batch#move
+ * @param {core.treeModel.Node|core.treeModel.Range} nodeOrRange Node or range of nodes to move.
+ * @param {core.treeModel.Position} targetPosition Position where moved nodes will be inserted.
  */
 register( 'move', function( nodeOrRange, targetPosition ) {
 	const delta = new MoveDelta();

+ 5 - 5
packages/ckeditor5-engine/src/treemodel/delta/removedelta.js

@@ -12,10 +12,11 @@ import Position from '../position.js';
 import Range from '../range.js';
 
 /**
- * To provide specific OT behavior and better collisions solving, {@link treeModel.Batch#remove} method
+ * @classdesc
+ * To provide specific OT behavior and better collisions solving, {@link core.treeModel.Batch#remove} method
  * uses the `RemoveDelta` class which inherits from the `Delta` class and may overwrite some methods.
  *
- * @class treeModel.delta.RemoveDelta
+ * @memberOf core.treeModel.delta
  */
 export default class RemoveDelta extends Delta {}
 
@@ -29,9 +30,8 @@ function addRemoveOperation( batch, delta, position, howMany ) {
  * Removes given node or range of nodes.
  *
  * @chainable
- * @method remove
- * @memberOf treeModel.Batch
- * @param {treeModel.Node|treeModel.Range} nodeOrRange Node or range of nodes to remove.
+ * @method core.treeModel.Batch#remove
+ * @param {core.treeModel.Node|core.treeModel.Range} nodeOrRange Node or range of nodes to remove.
  */
 register( 'remove', function( nodeOrRange ) {
 	const delta = new RemoveDelta();

+ 5 - 5
packages/ckeditor5-engine/src/treemodel/delta/splitdelta.js

@@ -14,10 +14,11 @@ import MoveOperation from '../operation/moveoperation.js';
 import CKEditorError from '../../ckeditorerror.js';
 
 /**
- * To provide specific OT behavior and better collisions solving, the {@link treeModel.Batch#split} method
+ * @classdesc
+ * To provide specific OT behavior and better collisions solving, the {@link core.treeModel.Batch#split} method
  * uses `SplitDelta` class which inherits from the `Delta` class and may overwrite some methods.
  *
- * @class treeModel.delta.SplitDelta
+ * @memberOf core.treeModel.delta
  */
 export default class SplitDelta extends Delta {}
 
@@ -28,9 +29,8 @@ export default class SplitDelta extends Delta {}
  * you try to split the root element.
  *
  * @chainable
- * @method split
- * @memberOf treeModel.Batch
- * @param {treeModel.Position} position Position of split.
+ * @method core.treeModel.Batch#split
+ * @param {core.treeModel.Position} position Position of split.
  */
 register( 'split', function( position ) {
 	const delta = new SplitDelta();

+ 5 - 5
packages/ckeditor5-engine/src/treemodel/delta/unwrapdelta.js

@@ -13,10 +13,11 @@ import MoveOperation from '../operation/moveoperation.js';
 import CKEditorError from '../../ckeditorerror.js';
 
 /**
- * To provide specific OT behavior and better collisions solving, {@link treeModel.Batch#merge} method
+ * @classdesc
+ * To provide specific OT behavior and better collisions solving, {@link core.treeModel.Batch#merge} method
  * uses the `UnwrapDelta` class which inherits from the `Delta` class and may overwrite some methods.
  *
- * @class treeModel.delta.UnwrapDelta
+ * @memberOf core.treeModel.delta
  */
 export default class UnwrapDelta extends Delta {}
 
@@ -25,9 +26,8 @@ export default class UnwrapDelta extends Delta {}
  * error if you try to unwrap an element that does not have a parent.
  *
  * @chainable
- * @method unwrap
- * @memberOf treeModel.Batch
- * @param {treeModel.Element} position Element to unwrap.
+ * @method core.treeModel.Batch#unwrap
+ * @param {core.treeModel.Element} position Element to unwrap.
  */
 register( 'unwrap', function( element ) {
 	if ( element.parent === null ) {

+ 13 - 13
packages/ckeditor5-engine/src/treemodel/delta/weakinsertdelta.js

@@ -11,29 +11,29 @@ import InsertOperation from '../operation/insertoperation.js';
 import NodeList from '../nodelist.js';
 
 /**
- * To provide specific OT behavior and better collisions solving, the {@link treeModel.Batch#insert} method
+ * @classdesc
+ * To provide specific OT behavior and better collisions solving, the {@link core.treeModel.Batch#insert} method
  * uses the `WeakInsertDelta` class which inherits from the `Delta` class and may overwrite some methods.
  *
- * @class treeModel.delta.WeakInsertDelta
+ * @memberOf core.treeModel.delta
  */
 export default class WeakInsertDelta extends Delta {}
 
 /**
- * Inserts a node or nodes at the given position. {@link treeModel.Batch#weakInsert} is commonly used for actions
+ * Inserts a node or nodes at the given position. {@link core.treeModel.Batch#weakInsert weakInsert} is commonly used for actions
  * like typing or plain-text paste (without formatting). There are two differences between
- * {@link treeModel.Batch#insert} and {@link treeModel.Batch#weakInsert}:
+ * {@link core.treeModel.Batch#insert insert} and {@link core.treeModel.Batch#weakInsert weakInsert}:
  * * When using `weakInsert`, inserted nodes will have same attributes as the current attributes of
- * {@link treeModel.Document#selection document selection}.
- * * The above has to be reflected during {@link treeModel.operation.transform operational transformation}. Normal
- * behavior is that inserting inside range changed by {@link treeModel.operation.AttributeOperation} splits the operation
- * into two operations, which "omit" the inserted nodes. The correct behavior for `WeakInsertDelta` is that
- * {@link treeModel.operation.AttributeOperation} does not "break" and also applies attributes for inserted nodes.
+ * {@link core.treeModel.Document#selection document selection}.
+ * * The above has to be reflected during {@link core.treeModel.operation.transform operational transformation}. Normal
+ * behavior is that inserting inside range changed by {@link core.treeModel.operation.AttributeOperation AttributeOperation} splits
+ * the operation into two operations, which "omit" the inserted nodes. The correct behavior for `WeakInsertDelta` is that
+ * {@link core.treeModel.operation.AttributeOperation AttributeOperation} does not "break" and also applies attributes for inserted nodes.
  *
  * @chainable
- * @memberOf treeModel.Batch
- * @method weakInsert
- * @param {treeModel.Position} position Position of insertion.
- * @param {treeModel.NodeSet} nodes The list of nodes to be inserted.
+ * @method core.treeModel.Batch#weakInsert
+ * @param {core.treeModel.Position} position Position of insertion.
+ * @param {core.treeModel.NodeSet} nodes The list of nodes to be inserted.
  */
 register( 'weakInsert', function( position, nodes ) {
 	const delta = new WeakInsertDelta();

+ 7 - 7
packages/ckeditor5-engine/src/treemodel/delta/wrapdelta.js

@@ -14,22 +14,22 @@ import MoveOperation from '../operation/moveoperation.js';
 import CKEditorError from '../../ckeditorerror.js';
 
 /**
- * To provide specific OT behavior and better collisions solving, {@link treeModel.Batch#merge} method
+ * @classdesc
+ * To provide specific OT behavior and better collisions solving, {@link core.treeModel.Batch#merge} method
  * uses the `WrapDelta` class which inherits from the `Delta` class and may overwrite some methods.
  *
- * @class treeModel.delta.WrapDelta
+ * @memberOf core.treeModel.delta
  */
 export default class WrapDelta extends Delta {}
 
 /**
  * Wraps given range with given element or with a new element of specified name if string has been passed.
- * **Note:** given range should be a "flat range" (see {@link treeModel.Range#isFlat}). If not, error will be thrown.
+ * **Note:** given range should be a "flat range" (see {@link core.treeModel.Range#isFlat}). If not, error will be thrown.
  *
  * @chainable
- * @method wrap
- * @memberOf treeModel.Batch
- * @param {treeModel.Range} range Range to wrap.
- * @param {treeModel.Element|String} elementOrString Element or name of element to wrap the range with.
+ * @method core.treeModel.Batch#wrap
+ * @param {core.treeModel.Range} range Range to wrap.
+ * @param {core.treeModel.Element|String} elementOrString Element or name of element to wrap the range with.
  */
 register( 'wrap', function( range, elementOrString ) {
 	if ( !range.isFlat ) {

+ 40 - 41
packages/ckeditor5-engine/src/treemodel/document.js

@@ -15,40 +15,39 @@ import utils from '../utils.js';
 const graveyardSymbol = Symbol( 'graveyard' );
 
 /**
- * Document tree model describes all editable data in the editor. It may contain multiple {@link #roots root elements},
- * for example if the editor have multiple editable areas, each area will be represented by the separate root.
+ * Document tree model describes all editable data in the editor. It may contain multiple
+ * {@link core.treeModel.Document#roots root elements}, for example if the editor have multiple editable areas, each area will be
+ * represented by the separate root.
  *
- * All changes in the document are done by {@link treeModel.operation.Operation operations}. To create operations in
- * the simple way use use the {@link treeModel.Batch} API, for example:
+ * All changes in the document are done by {@link core.treeModel.operation.Operation operations}. To create operations in
+ * the simple way use use the {@link core.treeModel.Batch} API, for example:
  *
  *		doc.batch().insert( position, nodes ).split( otherPosition );
  *
- * @see #batch
+ * @see core.treeModel.Document#batch
  *
- * @class treeModel.Document
+ * @memberOf core.treeModel
  */
 export default class Document {
 	/**
-	 * Creates an empty document instance with no {@link #roots} (other than graveyard).
-	 *
-	 * @constructor
+	 * Creates an empty document instance with no {@link core.treeModel.Document#roots} (other than graveyard).
 	 */
 	constructor() {
 		/**
 		 * List of roots that are owned and managed by this document.
 		 *
 		 * @readonly
-		 * @property {Map} roots
+		 * @member {Map} core.treeModel.Document#roots
 		 */
 		this.roots = new Map();
 
 		/**
 		 * Document version. It starts from `0` and every operation increases the version number. It is used to ensure that
-		 * operations are applied on the proper document version. If the {@link treeModel.operation.Operation#baseVersion} will
+		 * operations are applied on the proper document version. If the {@link core.treeModel.operation.Operation#baseVersion} will
 		 * not match document version the {@link document-applyOperation-wrong-version} error is thrown.
 		 *
 		 * @readonly
-		 * @property {Number} version
+		 * @member {Number} core.treeModel.Document#version
 		 */
 		this.version = 0;
 
@@ -56,10 +55,10 @@ export default class Document {
 		this.createRoot( graveyardSymbol );
 
 		/**
-		 * Array of pending changes. See: {@link #enqueueChanges}.
+		 * Array of pending changes. See: {@link core.treeModel.Document#enqueueChanges}.
 		 *
 		 * @private
-		 * @property {Array.<Function>}
+		 * @member {Array.<Function>} core.treeModel.Document#_pendingChanges
 		 */
 		this._pendingChanges = [];
 
@@ -67,7 +66,7 @@ export default class Document {
 		 * Selection done on this document.
 		 *
 		 * @readonly
-		 * @property {treeModel.Selection}
+		 * @member {core.treeModel.Selection} core.treeModel.Document#selection
 		 */
 		this.selection = new Selection();
 	}
@@ -76,7 +75,7 @@ export default class Document {
 	 * Graveyard tree root. Document always have a graveyard root, which stores removed nodes.
 	 *
 	 * @readonly
-	 * @property {treeModel.RootElement} graveyard
+	 * @type {core.treeModel.RootElement}
 	 */
 	get graveyard() {
 		return this.getRoot( graveyardSymbol );
@@ -84,12 +83,12 @@ export default class Document {
 
 	/**
 	 * This is the entry point for all document changes. All changes on the document are done using
-	 * {@link treeModel.operation.Operation operations}. To create operations in the simple way use the
-	 * {@link treeModel.Batch} API available via {@link #batch} method.
+	 * {@link core.treeModel.operation.Operation operations}. To create operations in the simple way use the
+	 * {@link core.treeModel.Batch} API available via {@link core.treeModel.Document#batch} method.
 	 *
-	 * This method calls {@link #change} event.
+	 * This method calls {@link core.treeModel.Document#change} event.
 	 *
-	 * @param {treeModel.operation.Operation} operation Operation to be applied.
+	 * @param {core.treeModel.operation.Operation} operation Operation to be applied.
 	 */
 	applyOperation( operation ) {
 		if ( operation.baseVersion !== this.version ) {
@@ -97,7 +96,7 @@ export default class Document {
 			 * Only operations with matching versions can be applied.
 			 *
 			 * @error document-applyOperation-wrong-version
-			 * @param {treeModel.operation.Operation} operation
+			 * @param {core.treeModel.operation.Operation} operation
 			 */
 			throw new CKEditorError(
 				'document-applyOperation-wrong-version: Only operations with matching versions can be applied.',
@@ -113,9 +112,9 @@ export default class Document {
 	}
 
 	/**
-	 * Creates a {@link treeModel.Batch} instance which allows to change the document.
+	 * Creates a {@link core.treeModel.Batch} instance which allows to change the document.
 	 *
-	 * @returns {treeModel.Batch} Batch instance.
+	 * @returns {core.treeModel.Batch} Batch instance.
 	 */
 	batch() {
 		return new Batch( this );
@@ -125,7 +124,7 @@ export default class Document {
 	 * Creates a new top-level root.
 	 *
 	 * @param {String|Symbol} name Unique root name.
-	 * @returns {treeModel.RootElement} Created root.
+	 * @returns {core.treeModel.RootElement} Created root.
 	 */
 	createRoot( name ) {
 		if ( this.roots.has( name ) ) {
@@ -133,7 +132,7 @@ export default class Document {
 			 * Root with specified name already exists.
 			 *
 			 * @error document-createRoot-name-exists
-			 * @param {treeModel.Document} doc
+			 * @param {core.treeModel.Document} doc
 			 * @param {String} name
 			 */
 			throw new CKEditorError(
@@ -149,12 +148,12 @@ export default class Document {
 	}
 
 	/**
-	 * Enqueue a callback with document changes. Any changes to be done on document (mostly using {@link #batch} should
+	 * Enqueue a callback with document changes. Any changes to be done on document (mostly using {@link core.treeModel.Document#batch} should
 	 * be placed in the queued callback. If no other plugin is changing document at the moment, the callback will be
 	 * called immediately. Otherwise it will wait for all previously queued changes to finish happening. This way
 	 * queued callback will not interrupt other callbacks.
 	 *
-	 * When all queued changes are done {@link #changesDone} event is fired.
+	 * When all queued changes are done {@link core.treeModel.Document#changesDone} event is fired.
 	 *
 	 * @param {Function} callback Callback to enqueue.
 	 */
@@ -175,7 +174,7 @@ export default class Document {
 	 * Returns top-level root by it's name.
 	 *
 	 * @param {String|Symbol} name Name of the root to get.
-	 * @returns {treeModel.RootElement} Root registered under given name.
+	 * @returns {core.treeModel.RootElement} Root registered under given name.
 	 */
 	getRoot( name ) {
 		if ( !this.roots.has( name ) ) {
@@ -203,30 +202,30 @@ export default class Document {
 	 * * 'remove' when nodes are removed,
 	 * * 'reinsert' when remove is undone,
 	 * * 'move' when nodes are moved,
-	 * * 'attr' when attributes change.
+	 * * 'attribute' when attributes change. TODO attribute
 	 *
 	 * Change event is fired after the change is done. This means that any ranges or positions passed in
 	 * `changeInfo` are referencing nodes and paths in updated tree model.
 	 *
-	 * @event change
-	 * @param {String} type Change type, possible option: 'insert', 'remove', 'reinsert', 'move', 'attr'.
+	 * @event core.treeModel.Document.change
+	 * @param {String} type Change type, possible option: 'insert', 'remove', 'reinsert', 'move', 'attribute'.
 	 * @param {Object} changeInfo Additional information about the change.
-	 * @param {treeModel.Range} changeInfo.range Range containing changed nodes. Note that for 'remove' the range will be in the
-	 * {@link #graveyard graveyard root}.
-	 * @param {treeModel.Position} [changeInfo.sourcePosition] Change source position. Exists for 'remove', 'reinsert' and 'move'.
-	 * Note that for 'reinsert' the source position will be in the {@link #graveyard graveyard root}.
-	 * @param {String} [changeInfo.key] Only for 'attr' type. Key of changed / inserted / removed attribute.
-	 * @param {*} [changeInfo.oldValue] Only for 'attr' type. If the type is 'attr' and `oldValue`
+	 * @param {core.treeModel.Range} changeInfo.range Range containing changed nodes. Note that for 'remove' the range will be in the
+	 * {@link core.treeModel.Document#graveyard graveyard root}.
+	 * @param {core.treeModel.Position} [changeInfo.sourcePosition] Change source position. Exists for 'remove', 'reinsert' and 'move'.
+	 * Note that for 'reinsert' the source position will be in the {@link core.treeModel.Document#graveyard graveyard root}.
+	 * @param {String} [changeInfo.key] Only for 'attribute' type. Key of changed / inserted / removed attribute.
+	 * @param {*} [changeInfo.oldValue] Only for 'attribute' type. If the type is 'attribute' and `oldValue`
 	 * is `undefined` it means that new attribute was inserted. Otherwise it contains changed or removed attribute value.
-	 * @param {*} [changeInfo.newValue] Only for 'attr' type. If the type is 'attr' and `newValue`
+	 * @param {*} [changeInfo.newValue] Only for 'attribute' type. If the type is 'attribute' and `newValue`
 	 * is `undefined` it means that attribute was removed. Otherwise it contains changed or inserted attribute value.
-	 * @param {treeModel.Batch} {@link treeModel.Batch} of changes which this change is a part of.
+	 * @param {core.treeModel.Batch} batch A {@link core.treeModel.Batch batch} of changes which this change is a part of.
 	 */
 
 	/**
-	 * Fired when all queued document changes are done. See {@link #enqueueChanges}.
+	 * Fired when all queued document changes are done. See {@link core.treeModel.Document#enqueueChanges}.
 	 *
-	 * @event changesDone
+	 * @event core.treeModel.Document.changesDone
 	 */
 }
 

+ 27 - 17
packages/ckeditor5-engine/src/treemodel/element.js

@@ -12,7 +12,7 @@ import utils from '../utils.js';
 /**
  * Tree data model element.
  *
- * @class treeModel.Element
+ * @memberOf core.treeModel
  */
 export default class Element extends Node {
 	/**
@@ -20,9 +20,8 @@ export default class Element extends Node {
 	 *
 	 * @param {String} name Node name.
 	 * @param {Iterable} attrs Iterable collection of attributes.
-	 * @param {treeModel.NodeSet} children List of nodes to be inserted
-	 * into created element. List of nodes can be of any type accepted by the {@link treeModel.NodeList} constructor.
-	 * @constructor
+	 * @param {core.treeModel.NodeSet} children List of nodes to be inserted
+	 * into created element. List of nodes can be of any type accepted by the {@link core.treeModel.NodeList} constructor.
 	 */
 	constructor( name, attrs, children ) {
 		super( attrs );
@@ -31,7 +30,7 @@ export default class Element extends Node {
 		 * Element name.
 		 *
 		 * @readonly
-		 * @property {String} name
+		 * @type {String}
 		 */
 		this.name = name;
 
@@ -39,7 +38,7 @@ export default class Element extends Node {
 		 * List of children nodes.
 		 *
 		 * @protected
-		 * @property {treeModel.NodeList} _children
+		 * @type {core.treeModel.NodeList}
 		 */
 		this._children = new NodeList();
 
@@ -51,8 +50,9 @@ export default class Element extends Node {
 	/**
 	 * Gets child at the given index.
 	 *
+	 * @method core.treeModel.Element#getChild
 	 * @param {Number} index Index of child.
-	 * @returns {treeModel.Node} Child node.
+	 * @returns {core.treeModel.Node} Child node.
 	 */
 	getChild( index ) {
 		return this._children.get( index );
@@ -61,6 +61,7 @@ export default class Element extends Node {
 	/**
 	 * Gets the number of element's children.
 	 *
+	 * @method core.treeModel.Element#getChildCount
 	 * @returns {Number} The number of element's children.
 	 */
 	getChildCount() {
@@ -70,7 +71,8 @@ export default class Element extends Node {
 	/**
 	 * Gets index of the given child node.
 	 *
-	 * @param {treeModel.Node} node Child node.
+	 * @method core.treeModel.Element#getChildIndex
+	 * @param {core.treeModel.Node} node Child node.
 	 * @returns {Number} Index of the child node.
 	 */
 	getChildIndex( node ) {
@@ -78,13 +80,14 @@ export default class Element extends Node {
 	}
 
 	/**
-	 * {@link treeModel.Element#insert Inserts} a child node or a list of child nodes at the end of this node and sets
+	 * {@link core.treeModel.Element#insert Inserts} a child node or a list of child nodes at the end of this node and sets
 	 * the parent of these nodes to this element.
 	 *
 	 * Note that the list of children can be modified only in elements not yet attached to the document.
-	 * All attached nodes should be modified using the {@link treeModel.operation.InsertOperation}.
+	 * All attached nodes should be modified using the {@link core.treeModel.operation.InsertOperation}.
 	 *
-	 * @param {treeModel.NodeSet} nodes The list of nodes to be inserted.
+	 * @method core.treeModel.Element#appendChildren
+	 * @param {core.treeModel.NodeSet} nodes The list of nodes to be inserted.
 	 */
 	appendChildren( nodes ) {
 		this.insertChildren( this.getChildCount(), nodes );
@@ -94,11 +97,12 @@ export default class Element extends Node {
 	 * Inserts a list of child nodes on the given index and sets the parent of these nodes to this element.
 	 *
 	 * Note that the list of children can be modified only in elements not yet attached to the document.
-	 * All attached nodes should be modified using the {@link treeModel.operation.InsertOperation}.
+	 * All attached nodes should be modified using the {@link core.treeModel.operation.InsertOperation}.
 	 *
+	 * @method core.treeModel.Element#insertChildren
 	 * @param {Number} index Position where nodes should be inserted.
-	 * @param {treeModel.NodeSet} nodes The list of nodes to be inserted.
-	 * The list of nodes can be of any type accepted by the {@link treeModel.NodeList} constructor.
+	 * @param {core.treeModel.NodeSet} nodes The list of nodes to be inserted.
+	 * The list of nodes can be of any type accepted by the {@link core.treeModel.NodeList} constructor.
 	 */
 	insertChildren( index, nodes ) {
 		let nodeList = new NodeList( nodes );
@@ -114,11 +118,12 @@ export default class Element extends Node {
 	 * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.
 	 *
 	 * Note that the list of children can be modified only in elements not yet attached to the document.
-	 * All attached nodes should be modified using the {@link treeModel.operation.RemoveOperation}.
+	 * All attached nodes should be modified using the {@link core.treeModel.operation.RemoveOperation}.
 	 *
+	 * @method core.treeModel.Element#removeChildren
 	 * @param {Number} index Position of the first node to remove.
 	 * @param {Number} number Number of nodes to remove.
-	 * @returns {treeModel.NodeList} The list of removed nodes.
+	 * @returns {core.treeModel.NodeList} The list of removed nodes.
 	 */
 	removeChildren( index, number ) {
 		let nodeList = this._children.remove( index, number );
@@ -133,6 +138,7 @@ export default class Element extends Node {
 	/**
 	 * Sets attribute on the element. If attribute with the same key already is set, it overwrites its values.
 	 *
+	 * @method core.treeModel.Element#setAttribute
 	 * @param {String} key Key of attribute to set.
 	 * @param {*} value Attribute value.
 	 */
@@ -143,7 +149,8 @@ export default class Element extends Node {
 	/**
 	 * Removes all attributes from the element and sets given attributes.
 	 *
-	 * @param {Iterable|Object} attrs Iterable object containing attributes to be set. See {@link treeModel.Node#getAttributes}.
+	 * @method core.treeModel.Element#setAttributesTo
+	 * @param {Iterable|Object} attrs Iterable object containing attributes to be set. See {@link core.treeModel.Node#getAttributes}.
 	 */
 	setAttributesTo( attrs ) {
 		this._attrs = utils.toMap( attrs );
@@ -152,6 +159,7 @@ export default class Element extends Node {
 	/**
 	 * Removes an attribute with given key from the element.
 	 *
+	 * @method core.treeModel.Element#removeAttribute
 	 * @param {String} key Key of attribute to remove.
 	 * @returns {Boolean} `true` if the attribute was set on the element, `false` otherwise.
 	 */
@@ -161,6 +169,8 @@ export default class Element extends Node {
 
 	/**
 	 * Removes all attributes from the element.
+	 *
+	 * @method core.treeModel.Element#clearAttributes
 	 */
 	clearAttributes() {
 		this._attrs.clear();

+ 45 - 39
packages/ckeditor5-engine/src/treemodel/liveposition.js

@@ -10,29 +10,23 @@ import Range from './range.js';
 import EmitterMixin from '../emittermixin.js';
 import utils from '../utils.js';
 
-/**
- * Enum representing how position is "sticking" with their neighbour nodes.
- * Possible values: `'STICKS_TO_NEXT'`, `'STICKS_TO_PREVIOUS'`.
- * @typedef {String} treeModel.PositionStickiness
- */
-
 /**
  * LivePosition is a position in the Tree Model that updates itself as the tree changes. It may be used as a bookmark.
  * **Note:** Be very careful when dealing with LivePosition. Each LivePosition instance bind events that might
- * have to be unbound. Use {@link #detach} whenever you don't need LivePosition anymore.
+ * have to be unbound. Use {@link core.treeModel.LivePosition#detach} whenever you don't need LivePosition anymore.
  *
- * @class treeModel.LivePosition
+ * @memberOf core.treeModel
+ * @extends core.treeModel.Position
  */
-
 export default class LivePosition extends Position {
 	/**
 	 * Creates a live position.
 	 *
-	 * @see {@link treeModel.Position}
-	 * @param root
-	 * @param path
-	 * @param {treeModel.PositionStickiness} [stickiness] Defaults to `'STICKS_TO_NEXT'`. See {@link #stickiness}.
-	 * @constructor
+	 * @see @link core.treeModel.Position
+	 * @param {core.treeModel.RootElement} root
+	 * @param {Array.<Number>} path
+	 * @param {core.treeModel.PositionStickiness} [stickiness] Defaults to `'STICKS_TO_NEXT'`. See
+	 *  {@link core.treeModel.LivePosition#stickiness}.
 	 */
 	constructor( root, path, stickiness ) {
 		super( root, path );
@@ -46,15 +40,15 @@ export default class LivePosition extends Position {
 		 * Examples:
 		 * Insert:
 		 * Position is at | and we insert at the same position, marked as ^:
-		 * | sticks to previous node: `<p>f|^oo</p>` => `<p>f|baroo</p>`
-		 * | sticks to next node: `<p>f^|oo</p>` => `<p>fbar|oo</p>`
+		 * - | sticks to previous node: `<p>f|^oo</p>` => `<p>f|baroo</p>`
+		 * - | sticks to next node: `<p>f^|oo</p>` => `<p>fbar|oo</p>`
 		 *
 		 * Move:
 		 * Position is at | and range [ ] is moved to position ^:
-		 * | sticks to previous node: `<p>f|[oo]</p><p>b^ar</p>` => `<p>f|</p><p>booar</p>`
-		 * | sticks to next node: `<p>f|[oo]</p><p>b^ar</p>` => `<p>f</p><p>b|ooar</p>`
+		 * - | sticks to previous node: `<p>f|[oo]</p><p>b^ar</p>` => `<p>f|</p><p>booar</p>`
+		 * - | sticks to next node: `<p>f|[oo]</p><p>b^ar</p>` => `<p>f</p><p>b|ooar</p>`
 		 *
-		 * @type {treeModel.PositionStickiness}
+		 * @member {treeModel.PositionStickiness} core.treeModel.LivePosition#stickiness
 		 */
 		this.stickiness = stickiness || 'STICKS_TO_NEXT';
 
@@ -65,6 +59,8 @@ export default class LivePosition extends Position {
 	 * Unbinds all events previously bound by LivePosition. Use it whenever you don't need LivePosition instance
 	 * anymore (i.e. when leaving scope in which it was declared or before re-assigning variable that was
 	 * referring to it).
+	 *
+	 * @method core.treeModel.LivePosition#detach
 	 */
 	detach() {
 		this.stopListening();
@@ -72,43 +68,44 @@ export default class LivePosition extends Position {
 
 	/**
 	 * @static
-	 * @method createAfter
-	 * @see {@link treeModel.Position#createAfter}
-	 * @param {treeModel.Node} node
-	 * @returns {treeModel.LivePosition}
+	 * @method core.treeModel.LivePosition.createAfter
+	 * @see {@link core.treeModel.Position#createAfter}
+	 * @param {core.treeModel.Node} node
+	 * @returns {core.treeModel.LivePosition}
 	 */
 
 	/**
 	 * @static
-	 * @method createBefore
-	 * @see {@link treeModel.Position#createBefore}
-	 * @param {treeModel.Node} node
-	 * @returns {treeModel.LivePosition}
+	 * @method core.treeModel.LivePosition.createBefore
+	 * @see {@link core.treeModel.Position#createBefore}
+	 * @param {core.treeModel.Node} node
+	 * @returns {core.treeModel.LivePosition}
 	 */
 
 	/**
 	 * @static
-	 * @method createFromParentAndOffset
-	 * @see {@link treeModel.Position#createFromParentAndOffset}
-	 * @param {treeModel.Element} parent
+	 * @method core.treeModel.LivePosition.createFromParentAndOffset
+	 * @see {@link core.treeModel.Position#createFromParentAndOffset}
+	 * @param {core.treeModel.Element} parent
 	 * @param {Number} offset
-	 * @returns {treeModel.LivePosition}
+	 * @returns {core.treeModel.LivePosition}
 	 */
 
 	/**
 	 * @static
-	 * @method createFromPosition
-	 * @see {@link treeModel.Position#createFromPosition}
-	 * @param {treeModel.Position} position
-	 * @returns {treeModel.LivePosition}
+	 * @method core.treeModel.LivePosition.createFromPosition
+	 * @see {@link core.treeModel.Position#createFromPosition}
+	 * @param {core.treeModel.Position} position
+	 * @returns {core.treeModel.LivePosition}
 	 */
 }
 
 /**
- * Binds this LivePosition to the {@link treeModel.Document} that owns this position {@link treeModel.RootElement root}.
+ * Binds this LivePosition to the {@link core.treeModel.Document} that owns this position {@link core.treeModel.RootElement root}.
  *
+ * @ignore
  * @private
- * @method bindWithDocument
+ * @method core.treeModel.LivePosition.bindWithDocument
  */
 function bindWithDocument() {
 	/*jshint validthis: true */
@@ -126,11 +123,12 @@ function bindWithDocument() {
 /**
  * Updates this position accordingly to the updates applied to the Tree Model. Bases on change events.
  *
+ * @ignore
  * @private
  * @method transform
  * @param {String} type Type of changes applied to the Tree Model.
- * @param {treeModel.Range} range Range containing the result of applied change.
- * @param {treeModel.Position} [position] Additional position parameter provided by some change events.
+ * @param {core.treeModel.Range} range Range containing the result of applied change.
+ * @param {core.treeModel.Position} [position] Additional position parameter provided by some change events.
  */
 function transform( type, range, position ) {
 	/*jshint validthis: true */
@@ -168,3 +166,11 @@ function transform( type, range, position ) {
 }
 
 utils.mix( LivePosition, EmitterMixin );
+
+/**
+ * Enum representing how position is "sticking" with their neighbour nodes.
+ * Possible values: `'STICKS_TO_NEXT'`, `'STICKS_TO_PREVIOUS'`.
+ *
+ * @typedef {String} core.treeModel.PositionStickiness
+ */
+

+ 28 - 27
packages/ckeditor5-engine/src/treemodel/liverange.js

@@ -12,18 +12,17 @@ import utils from '../utils.js';
 
 /**
  * LiveRange is a Range in the Tree Model that updates itself as the tree changes. It may be used as a bookmark.
- * **Note:** Constructor creates it's own {@link treeModel.LivePosition} instances basing on passed values.
+ * **Note:** Constructor creates it's own {@link core.treeModel.LivePosition} instances basing on passed values.
  * **Note:** Be very careful when dealing with LiveRange. Each LiveRange instance bind events that might
- * have to be unbound. Use {@link #detach} whenever you don't need LiveRange anymore.
+ * have to be unbound. Use {@link core.treeModel.LiveRange#detach detach} whenever you don't need LiveRange anymore.
  *
- * @class treeModel.LiveRange
+ * @memberOf core.treeModel
  */
 export default class LiveRange extends Range {
 	/**
 	 * Creates a live range.
 	 *
-	 * @see {treeModel.Range}
-	 * @constructor
+	 * @see core.treeModel.Range
 	 */
 	constructor( start, end ) {
 		super( start, end );
@@ -46,47 +45,48 @@ export default class LiveRange extends Range {
 	}
 
 	/**
-	 * @see {@link treeModel.Range#createFromElement}
+	 * @see {@link core.treeModel.Range#createFromElement}
 	 * @static
-	 * @method createFromElement
-	 * @param {treeModel.Element} element
-	 * @returns {treeModel.LiveRange}
+	 * @method core.treeModel.LiveRange.createFromElement
+	 * @param {core.treeModel.Element} element
+	 * @returns {core.treeModel.LiveRange}
 	 */
 
 	/**
-	 * @see {@link treeModel.Range#createFromPositionAndShift}
+	 * @see {@link core.treeModel.Range#createFromPositionAndShift}
 	 * @static
-	 * @method createFromPositionAndShift
-	 * @param {treeModel.Position} position
+	 * @method core.treeModel.LiveRange.createFromPositionAndShift
+	 * @param {core.treeModel.Position} position
 	 * @param {Number} shift
-	 * @returns {treeModel.LiveRange}
+	 * @returns {core.treeModel.LiveRange}
 	 */
 
 	/**
-	 * @see {@link treeModel.Range#createFromParentsAndOffsets}
+	 * @see {@link core.treeModel.Range#createFromParentsAndOffsets}
 	 * @static
-	 * @method createFromParentsAndOffsets
-	 * @param {treeModel.Element} startElement
+	 * @method core.treeModel.LiveRange.createFromParentsAndOffsets
+	 * @param {core.treeModel.Element} startElement
 	 * @param {Number} startOffset
-	 * @param {treeModel.Element} endElement
+	 * @param {core.treeModel.Element} endElement
 	 * @param {Number} endOffset
-	 * @returns {treeModel.LiveRange}
+	 * @returns {core.treeModel.LiveRange}
 	 */
 
 	/**
-	 * @see {@link treeModel.Range#createFromRange}
+	 * @see {@link core.treeModel.Range#createFromRange}
 	 * @static
-	 * @method createFromRange
-	 * @param {treeModel.Range} range
-	 * @returns {treeModel.LiveRange}
+	 * @method core.treeModel.LiveRange.createFromRange
+	 * @param {core.treeModel.Range} range
+	 * @returns {core.treeModel.LiveRange}
 	 */
 }
 
 /**
- * Binds this LiveRange to the {@link treeModel.Document} that owns this range.
+ * Binds this LiveRange to the {@link core.treeModel.Document} that owns this range.
  *
+ * @ignore
  * @private
- * @method bindWithDocument
+ * @method core.treeModel.LiveRange#bindWithDocument
  */
 function bindWithDocument() {
 	/*jshint validthis: true */
@@ -102,15 +102,16 @@ function bindWithDocument() {
 }
 
 /**
- * LiveRange boundaries are instances of {@link treeModel.LivePosition}, so it is updated thanks to them. This method
+ * LiveRange boundaries are instances of {@link core.treeModel.LivePosition}, so it is updated thanks to them. This method
  * additionally fixes the results of updating live positions taking into account that those live positions
  * are boundaries of a range. An example case for fixing live positions is end boundary is moved before start boundary.
  *
+ * @ignore
  * @private
  * @method fixBoundaries
  * @param {String} type Type of changes applied to the Tree Model.
- * @param {treeModel.Range} range Range containing the result of applied change.
- * @param {treeModel.Position} [position] Additional position parameter provided by some change events.
+ * @param {core.treeModel.Range} range Range containing the result of applied change.
+ * @param {core.treeModel.Position} [position] Additional position parameter provided by some change events.
  */
 function fixBoundaries( type, range, position ) {
 	/* jshint validthis: true */

+ 25 - 20
packages/ckeditor5-engine/src/treemodel/node.js

@@ -10,37 +10,36 @@ import utils from '../utils.js';
 import CKEditorError from '../ckeditorerror.js';
 
 /**
- * Abstract document tree node class.
+ * Creates a tree node.
+ *
+ * This is an abstract class, so this constructor should not be used directly.
+ *
+ * @param {Iterable|Object} attrs Iterable collection of attributes.
  *
  * @abstract
- * @class treeModel.Node
+ * @class core.treeModel.Node
+ * @classdesc Abstract document tree node class.
  */
 export default class Node {
-	/**
-	 * Creates a tree node.
-	 *
-	 * This is an abstract class, so this constructor should not be used directly.
-	 *
-	 * @param {Iterable|Object} attrs Iterable collection of attributes.
-	 * @constructor
-	 */
 	constructor( attrs ) {
 		/**
-		 * Parent element. Null by default. Set by {@link treeModel.Element#insertChildren}.
+		 * Parent element. Null by default. Set by {@link core.treeModel.Element#insertChildren}.
 		 *
+		 * @member core.treeModel.Node#parent
 		 * @readonly
-		 * @property {treeModel.Element|null} parent
+		 * @member {core.treeModel.Element|null} core.treeModel.Node#parent
 		 */
 		this.parent = null;
 
 		/**
 		 * List of attributes set on this node.
+		 *
 		 * **Note:** It is **important** that attributes of nodes already attached to the document must be changed
-		 * only by an {@link treeModel.operation.AttributeOperation}. Do not set attributes of such nodes
-		 * using {@link treeModel.Node} methods.
+		 * only by an {@link core.treeModel.operation.AttributeOperation}. Do not set attributes of such nodes
+		 * using {@link core.treeModel.Node} methods.
 		 *
 		 * @protected
-		 * @property {Map} _attrs
+		 * @member {Map} core.treeModel.Node#_attrs
 		 */
 		this._attrs = utils.toMap( attrs );
 	}
@@ -49,7 +48,7 @@ export default class Node {
 	 * Depth of the node, which equals to total number of its parents.
 	 *
 	 * @readonly
-	 * @property {Number} depth
+	 * @member {Number} core.treeModel.Node#depth
 	 */
 	get depth() {
 		let depth = 0;
@@ -68,7 +67,7 @@ export default class Node {
 	 * Nodes next sibling or `null` if it is the last child.
 	 *
 	 * @readonly
-	 * @property {treeModel.Node|null} nextSibling
+	 * @member {core.treeModel.Node|null} core.treeModel.Node#nextSibling
 	 */
 	get nextSibling() {
 		const index = this.getIndex();
@@ -80,7 +79,7 @@ export default class Node {
 	 * Nodes previous sibling or null if it is the last child.
 	 *
 	 * @readonly
-	 * @property {treeModel.Node|null} previousSibling
+	 * @member {core.treeModel.Node|null} core.treeModel.Node#previousSibling
 	 */
 	get previousSibling() {
 		const index = this.getIndex();
@@ -92,7 +91,7 @@ export default class Node {
 	 * The top parent for the node. If node has no parent it is the root itself.
 	 *
 	 * @readonly
-	 * @property {Number} depth
+	 * @member {Number} core.treeModel.Node#root
 	 */
 	get root() {
 		let root = this;
@@ -109,6 +108,7 @@ export default class Node {
 	 *
 	 * Throws error if the parent element does not contain this node.
 	 *
+	 * @method core.treeModel.Node#getIndes
 	 * @returns {Number|Null} Index of the node in the parent element or null if the node has not parent.
 	 */
 	getIndex() {
@@ -132,8 +132,9 @@ export default class Node {
 
 	/**
 	 * Gets path to the node. For example if the node is the second child of the first child of the root then the path
-	 * will be `[ 1, 2 ]`. This path can be used as a parameter of {@link treeModel.Position}.
+	 * will be `[ 1, 2 ]`. This path can be used as a parameter of {@link core.treeModel.Position}.
 	 *
+	 * @method core.treeModel.Node#getPath
 	 * @returns {Number[]} The path.
 	 */
 	getPath() {
@@ -151,6 +152,7 @@ export default class Node {
 	/**
 	 * Custom toJSON method to solve child-parent circular dependencies.
 	 *
+	 * @method core.treeModel.Node#toJSON
 	 * @returns {Object} Clone of this object with the parent property replaced with its name.
 	 */
 	toJSON() {
@@ -165,6 +167,7 @@ export default class Node {
 	/**
 	 * Checks if the node has an attribute for given key.
 	 *
+	 * @method core.treeModel.Node#hasAttribute
 	 * @param {String} key Key of attribute to check.
 	 * @returns {Boolean} `true` if attribute with given key is set on node, `false` otherwise.
 	 */
@@ -175,6 +178,7 @@ export default class Node {
 	/**
 	 * Gets an attribute value for given key or undefined if that attribute is not set on node.
 	 *
+	 * @method core.treeModel.Node#getAttribute
 	 * @param {String} key Key of attribute to look for.
 	 * @returns {*} Attribute value or null.
 	 */
@@ -185,6 +189,7 @@ export default class Node {
 	/**
 	 * Returns iterator that iterates over this node attributes.
 	 *
+	 * @method core.treeModel.Node#getAttributes
 	 * @returns {Iterable.<*>}
 	 */
 	getAttributes() {

+ 31 - 31
packages/ckeditor5-engine/src/treemodel/nodelist.js

@@ -12,27 +12,14 @@ import clone from '../lib/lodash/clone.js';
 import CKEditorError from '../ckeditorerror.js';
 
 /**
- * Value that is convertible to an item kept in {@link treeModel.NodeList} or an iterable collection of such items.
- * In other words, this is anything that {@link treeModel.NodeList#constructor} is able to take and convert to node:
- * * {@link treeModel.Element} will be left as is
- * * {@link treeModel.CharacterProxy} will be left as is
- * * {@link treeModel.Text} and {String} will be converted to a set of {@link treeModel.CharacterProxy}
- * * {@link treeModel.NodeList} will clone a node list (but not the nodes inside, so the new and passed list will
- * point to the same nodes.
- * * Iterable collection of above items will be iterated over and all items will be added to the node list.
- *
- * @typedef {treeModel.Element|treeModel.CharacterProxy|treeModel.Text|String|treeModel.NodeList|Iterable} treeModel.NodeSet
- */
-
-/**
- * This is a private helper-class for {@link treeModel.NodeList} text compression utility.
+ * This is a private helper-class for {@link core.treeModel.NodeList} text compression utility.
  *
  * @protected
- * @class treeModel.NodeListText
+ * @memberOf core.treeModel
  */
 class NodeListText extends Text {
 	/**
-	 * @see {@link treeModel.Text#constructor}
+	 * @see {@link core.treeModel.Text#constructor}
 	 * @protected
 	 * @constructor
 	 */
@@ -43,10 +30,10 @@ class NodeListText extends Text {
 	}
 
 	/**
-	 * Gets a character at given index and creates a {@link treeModel.CharacterProxy} out of it.
+	 * Gets a character at given index and creates a {@link core.treeModel.CharacterProxy} out of it.
 	 *
 	 * @param {Number} index Character index.
-	 * @returns {treeModel.CharacterProxy}
+	 * @returns {core.treeModel.CharacterProxy}
 	 */
 	getCharAt( index ) {
 		index = index && index >= 0 ? index : 0;
@@ -70,14 +57,14 @@ class NodeListText extends Text {
 
 /**
  * List of nodes. It is used to represent multiple nodes with a given order, for example children of
- * {@link treeModel.Element} object or nodes inserted using {@link treeModel.operation.InsertOperation}.
+ * {@link core.treeModel.Element} object or nodes inserted using {@link core.treeModel.operation.InsertOperation}.
  *
  * Thanks to the constructor, which accepts various arguments, this class lets you easily create desired list of nodes.
  *
- * Parameters passed to constructor are converted and internally kept as an array of {@link treeModel.Node}
- * and {@link treeModel.Text} instances.
+ * Parameters passed to constructor are converted and internally kept as an array of {@link core.treeModel.Node}
+ * and {@link core.treeModel.Text} instances.
  *
- * @class treeModel.NodeList
+ * @memberOf core.treeModel
  */
 export default class NodeList {
 	/**
@@ -106,9 +93,9 @@ export default class NodeList {
 	 *		nodeListA === nodeListB // true
 	 *		nodeListB.length // 3
 	 *
-	 * @see {@link treeModel.NodeSet} for more explanation.
+	 * @see {@link core.treeModel.NodeSet} for more explanation.
 	 *
-	 * @param {treeModel.NodeSet} nodes List of nodes.
+	 * @param {core.treeModel.NodeSet} nodes List of nodes.
 	 * @constructor
 	 */
 	constructor( nodes ) {
@@ -121,7 +108,7 @@ export default class NodeList {
 		 * Internal array to store nodes.
 		 *
 		 * @protected
-		 * @property {Array}
+		 * @type {Array}
 		 */
 		this._nodes = [];
 
@@ -131,7 +118,7 @@ export default class NodeList {
 		 * which occupy multiple slots in `_indexMap`.
 		 *
 		 * @private
-		 * @property {Array}
+		 * @type {Array}
 		 */
 		this._indexMap = [];
 
@@ -184,7 +171,7 @@ export default class NodeList {
 	 * Number of nodes in the node list.
 	 *
 	 * @readonly
-	 * @property {Number} length
+	 * @type {Number}
 	 */
 	get length() {
 		return this._indexMap.length;
@@ -208,7 +195,7 @@ export default class NodeList {
 	 * Returns node at the given index.
 	 *
 	 * @param {Number} index Node index.
-	 * @returns {treeModel.Node} Node at given index.
+	 * @returns {core.treeModel.Node} Node at given index.
 	 */
 	get( index ) {
 		let realIndex = this._indexMap[ index ];
@@ -224,7 +211,7 @@ export default class NodeList {
 	/**
 	 * Search for the element in the node list.
 	 *
-	 * @param {treeModel.Node} node Node to find.
+	 * @param {core.treeModel.Node} node Node to find.
 	 * @returns {Number} Position of the element in the list or -1 if not found.
 	 */
 	indexOf( node ) {
@@ -243,7 +230,7 @@ export default class NodeList {
 	 * Inserts nodes from the given node list into this node list at the given index.
 	 *
 	 * @param {Number} index Position where nodes should be inserted.
-	 * @param {treeModel.NodeList} nodeList List of nodes to insert.
+	 * @param {core.treeModel.NodeList} nodeList List of nodes to insert.
 	 */
 	insert( index, nodeList ) {
 		if ( this._nodes.length === 0 ) {
@@ -283,7 +270,7 @@ export default class NodeList {
 	 *
 	 * @param {Number} index Position of the first node to remove.
 	 * @param {Number} number Number of nodes to remove.
-	 * @returns {treeModel.NodeList} List of removed nodes.
+	 * @returns {core.treeModel.NodeList} List of removed nodes.
 	 */
 	remove( index, number ) {
 		if ( this._nodes.length === 0 ) {
@@ -451,3 +438,16 @@ export default class NodeList {
 		return index - this._indexMap.indexOf( this._indexMap[ index ] );
 	}
 }
+
+/**
+ * Value that is convertible to an item kept in {@link core.treeModel.NodeList} or an iterable collection of such items.
+ * In other words, this is anything that {@link core.treeModel.NodeList#constructor} is able to take and convert to node:
+ * * {@link core.treeModel.Element} will be left as is
+ * * {@link core.treeModel.CharacterProxy} will be left as is
+ * * {@link core.treeModel.Text} and {String} will be converted to a set of {@link core.treeModel.CharacterProxy}
+ * * {@link core.treeModel.NodeList} will clone a node list (but not the nodes inside, so the new and passed list will
+ * point to the same nodes.
+ * * Iterable collection of above items will be iterated over and all items will be added to the node list.
+ *
+ * @typedef {treeModel.Element|treeModel.CharacterProxy|treeModel.Text|String|treeModel.NodeList|Iterable} core.treeModel.NodeSet
+ */

+ 9 - 0
packages/ckeditor5-engine/src/treemodel/operation.jsdoc

@@ -0,0 +1,9 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * Core &rarr; TreeModel &rarr; Operation namespace (`core.treeModel.operation`).
+ * @namespace core.treeModel.operation
+ */

+ 17 - 11
packages/ckeditor5-engine/src/treemodel/operation/attributeoperation.js

@@ -13,7 +13,8 @@ import TextFragment from '../textfragment.js';
 /**
  * Operation to change nodes' attribute. Using this class you can add, remove or change value of the attribute.
  *
- * @class treeModel.operation.AttributeOperation
+ * @memberOf core.treeModel.operation
+ * @extends core.treeModel.operation.Operation
  */
 export default class AttributeOperation extends Operation {
 	/**
@@ -28,12 +29,11 @@ export default class AttributeOperation extends Operation {
 	 * If both new and old attributes are set, then the operation will change the attribute value. Note that both new and
 	 * old attributes have to have the same key and the old attribute must be present in all nodes in ranges.
 	 *
-	 * @param {treeModel.Range} range Range on which the operation should be applied.
+	 * @param {core.treeModel.Range} range Range on which the operation should be applied.
 	 * @param {String} key Key of an attribute to change or remove.
 	 * @param {*} oldValue Old value of the attribute with given key or `null` if adding a new attribute.
 	 * @param {*} newValue New value to set for the attribute. If `null`, then the operation just removes the attribute.
-	 * @param {Number} baseVersion {@link treeModel.Document#version} on which the operation can be applied.
-	 * @constructor
+	 * @param {Number} baseVersion {@link core.treeModel.Document#version} on which the operation can be applied.
 	 */
 	constructor( range, key, oldValue, newValue, baseVersion ) {
 		super( baseVersion );
@@ -42,7 +42,7 @@ export default class AttributeOperation extends Operation {
 		 * Range on which operation should be applied.
 		 *
 		 * @readonly
-		 * @type {treeModel.Range}
+		 * @member {core.treeModel.Range} core.treeModel.operation.AttributeOperation#range
 		 */
 		this.range = Range.createFromRange( range );
 
@@ -50,7 +50,7 @@ export default class AttributeOperation extends Operation {
 		 * Key of an attribute to change or remove.
 		 *
 		 * @readonly
-		 * @property {String} key
+		 * @member {String} core.treeModel.operation.AttributeOperation#key
 		 */
 		this.key = key;
 
@@ -58,7 +58,7 @@ export default class AttributeOperation extends Operation {
 		 * Old value of the attribute with given key or `null` if adding a new attribute.
 		 *
 		 * @readonly
-		 * @property {*} oldValue
+		 * @member {*} core.treeModel.operation.AttributeOperation#oldValue
 		 */
 		this.oldValue = oldValue;
 
@@ -66,19 +66,25 @@ export default class AttributeOperation extends Operation {
 		 * New value to set for the attribute. If `null`, then the operation just removes the attribute.
 		 *
 		 * @readonly
-		 * @property {*} newValue
+		 * @member {*} core.treeModel.operation.AttributeOperation#newValue
 		 */
 		this.newValue = newValue;
 	}
 
 	get type() {
-		return 'attr';
+		return 'attribute';
 	}
 
+	/**
+	 * @returns {core.treeModel.operation.AttributeOperation}
+	 */
 	clone() {
 		return new AttributeOperation( this.range, this.key, this.oldValue, this.newValue, this.baseVersion );
 	}
 
+	/**
+	 * @returns {core.treeModel.operation.AttributeOperation}
+	 */
 	getReversed() {
 		return new AttributeOperation( this.range, this.key, this.newValue, this.oldValue, this.baseVersion + 1 );
 	}
@@ -90,7 +96,7 @@ export default class AttributeOperation extends Operation {
 				 * The attribute which should be removed does not exists for the given node.
 				 *
 				 * @error operation-attribute-no-attr-to-remove
-				 * @param {treeModel.Node} node
+				 * @param {core.treeModel.Node} node
 				 * @param {String} key
 				 * @param {*} value
 				 */
@@ -105,7 +111,7 @@ export default class AttributeOperation extends Operation {
 				 * The attribute with given key already exists for the given node.
 				 *
 				 * @error operation-attribute-attr-exists
-				 * @param {treeModel.Node} node
+				 * @param {core.treeModel.Node} node
 				 * @param {String} key
 				 */
 				throw new CKEditorError(

+ 14 - 8
packages/ckeditor5-engine/src/treemodel/operation/insertoperation.js

@@ -14,17 +14,17 @@ import RemoveOperation from './removeoperation.js';
 /**
  * Operation to insert list of nodes on the given position in the tree data model.
  *
- * @class treeModel.operation.InsertOperation
+ * @memberOf core.treeModel.operation
+ * @extends core.treeModel.operation.Operation
  */
 export default class InsertOperation extends Operation {
 	/**
 	 * Creates an insert operation.
 	 *
-	 * @param {treeModel.Position} position Position of insertion.
-	 * @param {treeModel.NodeSet} nodes The list of nodes to be inserted.
-	 * List of nodes can be any type accepted by the {@link treeModel.NodeList} constructor.
-	 * @param {Number} baseVersion {@link treeModel.Document#version} on which operation can be applied.
-	 * @constructor
+	 * @param {core.treeModel.Position} position Position of insertion.
+	 * @param {core.treeModel.NodeSet} nodes The list of nodes to be inserted.
+	 * List of nodes can be any type accepted by the {@link core.treeModel.NodeList} constructor.
+	 * @param {Number} baseVersion {@link core.treeModel.Document#version} on which operation can be applied.
 	 */
 	constructor( position, nodes, baseVersion ) {
 		super( baseVersion );
@@ -33,7 +33,7 @@ export default class InsertOperation extends Operation {
 		 * Position of insertion.
 		 *
 		 * @readonly
-		 * @type {treeModel.Position}
+		 * @member {core.treeModel.Position} core.treeModel.operation.InsertOperation#position
 		 */
 		this.position = Position.createFromPosition( position );
 
@@ -41,7 +41,7 @@ export default class InsertOperation extends Operation {
 		 * List of nodes to insert.
 		 *
 		 * @readonly
-		 * @type {treeModel.NodeList}
+		 * @member {core.treeModel.NodeList} core.treeModel.operation.InsertOperation#nodeList
 		 */
 		this.nodeList = new NodeList( nodes );
 	}
@@ -50,10 +50,16 @@ export default class InsertOperation extends Operation {
 		return 'insert';
 	}
 
+	/**
+	 * @returns {core.treeModel.operation.InsertOperation}
+	 */
 	clone() {
 		return new InsertOperation( this.position, this.nodeList, this.baseVersion );
 	}
 
+	/**
+	 * @returns {core.treeModel.operation.RemoveOperation}
+	 */
 	getReversed() {
 		return new RemoveOperation( this.position, this.nodeList.length, this.baseVersion + 1 );
 	}

+ 14 - 8
packages/ckeditor5-engine/src/treemodel/operation/moveoperation.js

@@ -14,17 +14,17 @@ import utils from '../../utils.js';
 /**
  * Operation to move list of subsequent nodes from one position in the document to another.
  *
- * @class treeModel.operation.MoveOperation
+ * @memberOf core.treeModel.operation
+ * @extends core.treeModel.operation.Operation
  */
 export default class MoveOperation extends Operation {
 	/**
 	 * Creates a move operation.
 	 *
-	 * @param {treeModel.Position} sourcePosition Position before the first node to move.
+	 * @param {core.treeModel.Position} sourcePosition Position before the first node to move.
 	 * @param {Number} howMany How many consecutive nodes to move, starting from `sourcePosition`.
-	 * @param {treeModel.Position} targetPosition Position where moved nodes will be inserted.
-	 * @param {Number} baseVersion {@link treeModel.Document#version} on which operation can be applied.
-	 * @constructor
+	 * @param {core.treeModel.Position} targetPosition Position where moved nodes will be inserted.
+	 * @param {Number} baseVersion {@link core.treeModel.Document#version} on which operation can be applied.
 	 */
 	constructor( sourcePosition, howMany, targetPosition, baseVersion ) {
 		super( baseVersion );
@@ -32,21 +32,21 @@ export default class MoveOperation extends Operation {
 		/**
 		 * Source move position.
 		 *
-		 * @type {treeModel.Position}
+		 * @member {core.treeModel.Position} core.treeModel.operation.MoveOperation#sourcePosition
 		 */
 		this.sourcePosition = Position.createFromPosition( sourcePosition );
 
 		/**
 		 * How many nodes to move.
 		 *
-		 * @type {Number}
+		 * @member {Number} core.treeModel.operation.MoveOperation#howMany
 		 */
 		this.howMany = howMany;
 
 		/**
 		 * Target move position.
 		 *
-		 * @type {treeModel.Position}
+		 * @member {core.treeModel.Position} core.treeModel.operation.MoveOperation#targetPosition
 		 */
 		this.targetPosition = Position.createFromPosition( targetPosition );
 	}
@@ -55,10 +55,16 @@ export default class MoveOperation extends Operation {
 		return 'move';
 	}
 
+	/**
+	 * @returns {core.treeModel.operation.MoveOperation}
+	 */
 	clone() {
 		return new this.constructor( this.sourcePosition, this.howMany, this.targetPosition, this.baseVersion );
 	}
 
+	/**
+	 * @returns {core.treeModel.operation.MoveOperation}
+	 */
 	getReversed() {
 		return new this.constructor( this.targetPosition, this.howMany, this.sourcePosition, this.baseVersion + 1 );
 	}

+ 9 - 2
packages/ckeditor5-engine/src/treemodel/operation/nooperation.js

@@ -13,16 +13,23 @@ import Operation from './operation.js';
  * It still has some parameters defined for transformation purposes.
  *
  * In most cases this operation is a result of transforming operations. When transformation returns
- * {@link treeModel.operation.NoOperation} it means that changes done by the transformed operation
+ * {@link core.treeModel.operation.NoOperation} it means that changes done by the transformed operation
  * have already been applied.
  *
- * @class treeModel.operation.NoOperation
+ * @memberOf core.treeModel.operation
+ * @extends core.treeModel.operation.Operation
  */
 export default class NoOperation extends Operation {
+	/**
+	 * @returns {core.treeModel.operation.NoOperation}
+	 */
 	clone() {
 		return new NoOperation( this.baseVersion );
 	}
 
+	/**
+	 * @returns {core.treeModel.operation.NoOperation}
+	 */
 	getReversed() {
 		return new NoOperation( this.baseVersion + 1 );
 	}

+ 17 - 19
packages/ckeditor5-engine/src/treemodel/operation/operation.js

@@ -9,45 +9,43 @@
  * Abstract base operation class.
  *
  * @abstract
- * @class treeModel.operation.Operation
+ * @memberOf core.treeModel.operation
  */
 export default class Operation {
 	/**
 	 * Base operation constructor.
-	 *
-	 * @param {Number} baseVersion {@link treeModel.Document#version} on which the operation can be applied.
-	 * @constructor
+	 * @param {Number} baseVersion {@link core.treeModel.Document#version} on which the operation can be applied.
 	 */
 	constructor( baseVersion ) {
 		/**
-		 * {@link treeModel.Document#version} on which operation can be applied. If you try to
-		 * {@link treeModel.Document#applyOperation apply} operation with different base version than the
-		 * {@link treeModel.Document#version document version} the {@link document-applyOperation-wrong-version}
+		 * {@link core.treeModel.Document#version} on which operation can be applied. If you try to
+		 * {@link core.treeModel.Document#applyOperation apply} operation with different base version than the
+		 * {@link core.treeModel.Document#version document version} the {@link document-applyOperation-wrong-version}
 		 * error is thrown.
 		 *
-		 * @property {Number}
+		 * @member {Number} core.treeModel.operation.Operation#baseVersion
 		 */
 		this.baseVersion = baseVersion;
 
 		/**
 		 * Operation type.
 		 *
-		 * @property {String} type
+		 * @member {String} core.treeModel.operation.Operation#type
 		 */
 
 		/**
-		 * {@link treeModel.Delta Delta} which the operation is a part of. This property is set by the
-		 * {@link treeModel.Delta delta} when the operations is added to it by the
-		 * {@link treeModel.Delta#addOperation} method.
+		 * {@link core.treeModel.Delta Delta} which the operation is a part of. This property is set by the
+		 * {@link core.treeModel.Delta delta} when the operations is added to it by the
+		 * {@link core.treeModel.Delta#addOperation} method.
 		 *
-		 * @property {treeModel.Delta} delta
+		 * @member {core.treeModel.Delta} core.treeModel.operation.Operation#delta
 		 */
 
 		/**
 		 * Creates and returns an operation that has the same parameters as this operation.
 		 *
-		 * @method clone
-		 * @returns {treeModel.operation.Operation} Clone of this operation.
+		 * @method core.treeModel.operation.Operation#clone
+		 * @returns {core.treeModel.operation.Operation} Clone of this operation.
 		 */
 
 		/**
@@ -57,10 +55,10 @@ export default class Operation {
 		 *
 		 * Keep in mind that tree model state may change since executing the original operation,
 		 * so reverse operation will be "outdated". In that case you will need to
-		 * {@link treeModel.operation.transform} it by all operations that were executed after the original operation.
+		 * {@link core.treeModel.operation.transform} it by all operations that were executed after the original operation.
 		 *
-		 * @method getReversed
-		 * @returns {treeModel.operation.Operation} Reversed operation.
+		 * @method core.treeModel.operation.Operation#getReversed
+		 * @returns {core.treeModel.operation.Operation} Reversed operation.
 		 */
 
 		/**
@@ -68,7 +66,7 @@ export default class Operation {
 		 * will be applied to the tree model.
 		 *
 		 * @protected
-		 * @method _execute
+		 * @method core.treeModel.operation.Operation#_execute
 		 * @returns {Object} Object with additional information about the applied changes. Always has `range`
 		 * property containing changed nodes. May have additional properties depending on the operation type.
 		 */

+ 8 - 4
packages/ckeditor5-engine/src/treemodel/operation/reinsertoperation.js

@@ -10,16 +10,20 @@ import RemoveOperation from './removeoperation.js';
 
 /**
  * Operation to reinsert previously removed nodes back to the non-graveyard root.
- * This is basically {@link treeModel.operation.MoveOperation} but it returns
- * {@link treeModel.operation.RemoveOperation} when reversed.
+ * This is basically {@link core.treeModel.operation.MoveOperation} but it returns
+ * {@link core.treeModel.operation.RemoveOperation} when reversed.
  *
  * With this class, we achieve two goals: by having separate classes it's easier to distinguish whether move
  * operation is actually a remove/reinsert operation and fire proper events. Also it
  * will be easier to expand if we need to change operation's behavior if it is remove/reinsert.
  *
- * @class treeModel.operation.ReinsertOperation
+ * @memberOf core.treeModel.operation
+ * @extends core.treeModel.operation.Operation
  */
 export default class ReinsertOperation extends MoveOperation {
+	/**
+	 * @returns {core.treeModel.operation.RemoveOperation}
+	 */
 	getReversed() {
 		return new RemoveOperation( this.targetPosition, this.howMany, this.baseVersion + 1 );
 	}
@@ -27,4 +31,4 @@ export default class ReinsertOperation extends MoveOperation {
 	get type() {
 		return 'reinsert';
 	}
-}
+}

+ 11 - 4
packages/ckeditor5-engine/src/treemodel/operation/removeoperation.js

@@ -12,16 +12,17 @@ import ReinsertOperation from './reinsertoperation.js';
 /**
  * Operation to remove a range of nodes.
  *
- * @class treeModel.operation.RemoveOperation
+ * @memberOf core.treeModel.operation
+ * @extends core.treeModel.operation.Operation
  */
 export default class RemoveOperation extends MoveOperation {
 	/**
+	 *
 	 * Creates a remove operation.
 	 *
-	 * @param {treeModel.Position} position Position before the first node to remove.
+	 * @param {core.treeModel.Position} position Position before the first node to remove.
 	 * @param {Number} howMany How many nodes to remove.
-	 * @param {Number} baseVersion {@link treeModel.Document#version} on which operation can be applied.
-	 * @constructor
+	 * @param {Number} baseVersion {@link core.treeModel.Document#version} on which operation can be applied.
 	 */
 	constructor( position, howMany, baseVersion ) {
 		// Position in a graveyard where nodes were moved.
@@ -34,10 +35,16 @@ export default class RemoveOperation extends MoveOperation {
 		return 'remove';
 	}
 
+	/**
+	 * @returns {core.treeModel.operation.ReinsertOperation}
+	 */
 	getReversed() {
 		return new ReinsertOperation( this.targetPosition, this.howMany, this.sourcePosition, this.baseVersion + 1 );
 	}
 
+	/**
+	 * @returns {core.treeModel.operation.RemoveOperation}
+	 */
 	clone() {
 		return new RemoveOperation( this.sourcePosition, this.howMany, this.baseVersion );
 	}

+ 13 - 11
packages/ckeditor5-engine/src/treemodel/operation/transform.js

@@ -15,19 +15,20 @@ import isEqual from '../../lib/lodash/isEqual.js';
 import utils from '../../utils.js';
 
 /**
- * Transforms given {treeModel.operation.Operation} by another {treeModel.operation.Operation} and returns the result of
- * that transformation as an array containing one or more {treeModel.operation.Operation} elements.
+ * Transforms given {@link core.treeModel.operation.Operation operation} by another {@link core.treeModel.operation.Operation operation} and
+ * returns the result of that transformation as an array containing one or more {@link core.treeModel.operation.Operation operation}
+ * elements.
  *
- * Operations work on specified positions, passed to them when they are created. Whenever {@link treeModel.Document document}
+ * Operations work on specified positions, passed to them when they are created. Whenever {@link core.treeModel.Document document}
  * changes, we have to reflect those modifications by updating or "transforming" operations which are not yet applied.
  * When an operation is transformed, its parameters may change based on the operation by which it is transformed.
  * If the transform-by operation applied any modifications to the Tree Data Model which affect positions or nodes
  * connected with transformed operation, those changes will be reflected in the parameters of the returned operation(s).
  *
- * Whenever the {@link treeModel.Document document} has different {@link treeModel.Document#baseVersion}
- * than the operation you want to {@link treeModel.Document#applyOperation apply}, you need to transform that
- * operation by all operations which were already applied to the {@link treeModel.Document document} and have greater
- * {@link treeModel.Document#baseVersion} than the operation being applied. Transform them in the same order as those
+ * Whenever the {@link core.treeModel.Document document} has different {@link core.treeModel.Document#baseVersion}
+ * than the operation you want to {@link core.treeModel.Document#applyOperation apply}, you need to transform that
+ * operation by all operations which were already applied to the {@link core.treeModel.Document document} and have greater
+ * {@link core.treeModel.Document#baseVersion} than the operation being applied. Transform them in the same order as those
  * operations which were applied. This way all modifications done to the Tree Data Model will be reflected
  * in the operation parameters and the operation will "operate" on "up-to-date" version of the Tree Data Model.
  * This is mostly the case with Operational Transformations but it might be needed in particular features as well.
@@ -44,12 +45,13 @@ import utils from '../../utils.js';
  * `a` by `b` and also `b` by `a`. In both transformations the same operation has to be the important one. If we assume
  * that first or the second passed operation is always more important we won't be able to solve this case.
  *
- * @function treeModel.operation.transform
- * @param {treeModel.operation.Operation} a Operation that will be transformed.
- * @param {treeModel.operation.Operation} b Operation to transform by.
+ * @external core.treeModel.operation
+ * @function core.treeModel.operation.transform
+ * @param {core.treeModel.operation.Operation} a Operation that will be transformed.
+ * @param {core.treeModel.operation.Operation} b Operation to transform by.
  * @param {Boolean} isAMoreImportantThanB Flag indicating whether the operation which will be transformed (`a`) should be treated
  * as more important when resolving conflicts.
- * @returns {Array.<treeModel.operation.Operation>} Result of the transformation.
+ * @returns {Array.<core.treeModel.operation.Operation>} Result of the transformation.
  */
 
 export default transform;

+ 42 - 43
packages/ckeditor5-engine/src/treemodel/position.js

@@ -10,26 +10,18 @@ import CKEditorError from '../ckeditorerror.js';
 import last from '../lib/lodash/last.js';
 import utils from '../utils.js';
 
-/**
- * A flag indicating whether this position is `'BEFORE'` or `'AFTER'` or `'SAME'` as given position.
- * If positions are in different roots `'DIFFERENT'` flag is returned.
- *
- * @typedef {String} treeModel.PositionRelation
- */
-
 /**
  * Position in the tree. Position is always located before or after a node.
  * See {@link #path} property for more information.
  *
- * @class treeModel.Position
+ * @memberOf core.treeModel
  */
 export default class Position {
 	/**
 	 * Creates a position.
 	 *
-	 * @param {treeModel.RootElement} root Root element for the path. Note that this element can not have a parent.
+	 * @param {core.treeModel.RootElement} root Root element for the path. Note that this element can not have a parent.
 	 * @param {Array.<Number>} path Position path. Must contain at least one item. See {@link #path} property for more information.
-	 * @constructor
 	 */
 	constructor( root, path ) {
 		if ( !( root instanceof RootElement ) ) {
@@ -45,7 +37,7 @@ export default class Position {
 		/**
 		 * Root element for the path. Note that this element can not have a parent.
 		 *
-		 * @type {treeModel.RootElement}
+		 * @type {core.treeModel.RootElement}
 		 */
 		this.root = root;
 
@@ -83,7 +75,7 @@ export default class Position {
 	 * Node directly after the position.
 	 *
 	 * @readonly
-	 * @property {treeModel.Node}
+	 * @type {core.treeModel.Node}
 	 */
 	get nodeAfter() {
 		return this.parent.getChild( this.offset ) || null;
@@ -93,7 +85,7 @@ export default class Position {
 	 * Node directly before the position.
 	 *
 	 * @readonly
-	 * @type {treeModel.Node}
+	 * @type {Node}
 	 */
 	get nodeBefore() {
 		return this.parent.getChild( this.offset - 1 ) || null;
@@ -103,7 +95,7 @@ export default class Position {
 	 * Offset at which the position is located in the {@link #parent}.
 	 *
 	 * @readonly
-	 * @property {Number} offset
+	 * @type {Number}
 	 */
 	get offset() {
 		return last( this.path );
@@ -120,7 +112,7 @@ export default class Position {
 	 * Parent element of the position. The position is located at {@link #offset} in this element.
 	 *
 	 * @readonly
-	 * @property {treeModel.Element} parent
+	 * @type {core.treeModel.Element}
 	 */
 	get parent() {
 		let parent = this.root;
@@ -137,8 +129,8 @@ export default class Position {
 	/**
 	 * Checks whether this position is before or after given position.
 	 *
-	 * @param {treeModel.Position} otherPosition Position to compare with.
-	 * @returns {treeModel.PositionRelation}
+	 * @param {core.treeModel.Position} otherPosition Position to compare with.
+	 * @returns {core.treeModel.PositionRelation}
 	 */
 	compareWith( otherPosition ) {
 		if ( this.root != otherPosition.root ) {
@@ -167,7 +159,7 @@ export default class Position {
 	}
 
 	/**
-	 * Returns the path to the parent, which is the {@link treeModel.Position#path} without the last element.
+	 * Returns the path to the parent, which is the {@link core.treeModel.Position#path} without the last element.
 	 *
 	 * This method returns the parent path even if the parent does not exists.
 	 *
@@ -181,7 +173,7 @@ export default class Position {
 	 * Returns a new instance of Position with offset incremented by `shift` value.
 	 *
 	 * @param {Number} shift How position offset should get changed. Accepts negative values.
-	 * @returns {treeModel.Position} Shifted position.
+	 * @returns {core.treeModel.Position} Shifted position.
 	 */
 	getShiftedBy( shift ) {
 		let shifted = Position.createFromPosition( this );
@@ -196,9 +188,9 @@ export default class Position {
 	 * Returns this position after being updated by removing `howMany` nodes starting from `deletePosition`.
 	 * It may happen that this position is in a removed node. If that is the case, `null` is returned instead.
 	 *
-	 * @param {treeModel.Position} deletePosition Position before the first removed node.
+	 * @param {core.treeModel.Position} deletePosition Position before the first removed node.
 	 * @param {Number} howMany How many nodes are removed.
-	 * @returns {treeModel.Position|null} Transformed position or `null`.
+	 * @returns {core.treeModel.Position|null} Transformed position or `null`.
 	 */
 	getTransformedByDeletion( deletePosition, howMany ) {
 		let transformed = Position.createFromPosition( this );
@@ -242,12 +234,12 @@ export default class Position {
 	/**
 	 * Returns this position after being updated by inserting `howMany` nodes at `insertPosition`.
 	 *
-	 * @param {treeModel.Position} insertPosition Position where nodes are inserted.
+	 * @param {core.treeModel.Position} insertPosition Position where nodes are inserted.
 	 * @param {Number} howMany How many nodes are inserted.
 	 * @param {Boolean} insertBefore Flag indicating whether nodes are inserted before or after `insertPosition`.
 	 * This is important only when `insertPosition` and this position are same. If that is the case and the flag is
 	 * set to `true`, this position will get transformed. If the flag is set to `false`, it won't.
-	 * @returns {treeModel.Position} Transformed position.
+	 * @returns {core.treeModel.Position} Transformed position.
 	 */
 	getTransformedByInsertion( insertPosition, howMany, insertBefore ) {
 		let transformed = Position.createFromPosition( this );
@@ -281,13 +273,13 @@ export default class Position {
 	/**
 	 * Returns this position after being updated by moving `howMany` attributes from `sourcePosition` to `targetPosition`.
 	 *
-	 * @param {treeModel.Position} sourcePosition Position before the first element to move.
-	 * @param {treeModel.Position} targetPosition Position where moved elements will be inserted.
+	 * @param {core.treeModel.Position} sourcePosition Position before the first element to move.
+	 * @param {core.treeModel.Position} targetPosition Position where moved elements will be inserted.
 	 * @param {Number} howMany How many consecutive nodes to move, starting from `sourcePosition`.
 	 * @param {Boolean} insertBefore Flag indicating whether moved nodes are pasted before or after `insertPosition`.
 	 * This is important only when `targetPosition` and this position are same. If that is the case and the flag is
 	 * set to `true`, this position will get transformed by range insertion. If the flag is set to `false`, it won't.
-	 * @returns {treeModel.Position} Transformed position.
+	 * @returns {core.treeModel.Position} Transformed position.
 	 */
 	getTransformedByMove( sourcePosition, targetPosition, howMany, insertBefore ) {
 		// Moving a range removes nodes from their original position. We acknowledge this by proper transformation.
@@ -311,7 +303,7 @@ export default class Position {
 	 *
 	 * **Note:** see {treeModel.Position#isBefore}.
 	 *
-	 * @param {treeModel.Position} otherPosition Position to compare with.
+	 * @param {core.treeModel.Position} otherPosition Position to compare with.
 	 * @returns {Boolean} True if this position is after given position.
 	 */
 	isAfter( otherPosition ) {
@@ -346,7 +338,7 @@ export default class Position {
 	 *    // do A.
 	 *  }
 	 *
-	 * @param {treeModel.Position} otherPosition Position to compare with.
+	 * @param {core.treeModel.Position} otherPosition Position to compare with.
 	 * @returns {Boolean} True if this position is before given position.
 	 */
 	isBefore( otherPosition ) {
@@ -356,7 +348,7 @@ export default class Position {
 	/**
 	 * Checks whether this position equals given position.
 	 *
-	 * @param {treeModel.Position} otherPosition Position to compare with.
+	 * @param {core.treeModel.Position} otherPosition Position to compare with.
 	 * @returns {Boolean} True if positions are same.
 	 */
 	isEqual( otherPosition ) {
@@ -368,7 +360,7 @@ export default class Position {
 	 * or empty nodes in a range between them. Technically, those positions are not equal but in many cases
 	 * they are very similar or even indistinguishable when they touch.
 	 *
-	 * @param {treeModel.Position} otherPosition Position to compare with.
+	 * @param {core.treeModel.Position} otherPosition Position to compare with.
 	 * @returns {Boolean} True if positions touch.
 	 */
 	isTouching( otherPosition ) {
@@ -419,8 +411,8 @@ export default class Position {
 	/**
 	 * Creates a new position after given node.
 	 *
-	 * @param {treeModel.Node} node Node the position should be directly after.
-	 * @returns {treeModel.Position}
+	 * @param {core.treeModel.Node} node Node the position should be directly after.
+	 * @returns {core.treeModel.Position}
 	 */
 	static createAfter( node ) {
 		if ( !node.parent ) {
@@ -428,7 +420,7 @@ export default class Position {
 			 * You can not make position after root.
 			 *
 			 * @error position-after-root
-			 * @param {treeModel.Node} root
+			 * @param {core.treeModel.Node} root
 			 */
 			throw new CKEditorError( 'position-after-root: You can not make position after root.', { root: node } );
 		}
@@ -439,8 +431,8 @@ export default class Position {
 	/**
 	 * Creates a new position before the given node.
 	 *
-	 * @param {treeModel.node} node Node the position should be directly before.
-	 * @returns {treeModel.Position}
+	 * @param {core.treeModel.node} node Node the position should be directly before.
+	 * @returns {core.treeModel.Position}
 	 */
 	static createBefore( node ) {
 		if ( !node.parent ) {
@@ -448,7 +440,7 @@ export default class Position {
 			 * You can not make position before root.
 			 *
 			 * @error position-before-root
-			 * @param {treeModel.Node} root
+			 * @param {core.treeModel.Node} root
 			 */
 			throw new CKEditorError( 'position-before-root: You can not make position before root.', { root: node } );
 		}
@@ -459,9 +451,9 @@ export default class Position {
 	/**
 	 * Creates a new position from the parent element and the offset in that element.
 	 *
-	 * @param {treeModel.Element} parent Position parent element.
+	 * @param {core.treeModel.Element} parent Position parent element.
 	 * @param {Number} offset Position offset.
-	 * @returns {treeModel.Position}
+	 * @returns {core.treeModel.Position}
 	 */
 	static createFromParentAndOffset( parent, offset ) {
 		const path = parent.getPath();
@@ -474,8 +466,8 @@ export default class Position {
 	/**
 	 * Creates and returns a new instance of Position, which is equal to passed position.
 	 *
-	 * @param {treeModel.Position} position Position to be cloned.
-	 * @returns {treeModel.Position}
+	 * @param {core.treeModel.Position} position Position to be cloned.
+	 * @returns {core.treeModel.Position}
 	 */
 	static createFromPosition( position ) {
 		return new this( position.root, position.path.slice() );
@@ -507,9 +499,9 @@ export default class Position {
 	 * Finally, the transformed position will point to `[ 1, 1, 4, 1 ]`.
 	 *
 	 * @protected
-	 * @param {treeModel.Position} source Beginning of the moved range.
-	 * @param {treeModel.Position} target Position where the range is moved.
-	 * @returns {treeModel.Position} Combined position.
+	 * @param {core.treeModel.Position} source Beginning of the moved range.
+	 * @param {core.treeModel.Position} target Position where the range is moved.
+	 * @returns {core.treeModel.Position} Combined position.
 	 */
 	_getCombined( source, target ) {
 		const i = source.path.length - 1;
@@ -529,3 +521,10 @@ export default class Position {
 		return combined;
 	}
 }
+
+/**
+ * A flag indicating whether this position is `'BEFORE'` or `'AFTER'` or `'SAME'` as given position.
+ * If positions are in different roots `'DIFFERENT'` flag is returned.
+ *
+ * @typedef {String} core.treeModel.PositionRelation
+ */

+ 54 - 53
packages/ckeditor5-engine/src/treemodel/range.js

@@ -12,29 +12,30 @@ import utils from '../utils.js';
 /**
  * Range class. Range is iterable.
  *
- * @class treeModel.Range
+ * @memberOf core.treeModel
  */
 export default class Range {
 	/**
 	 * Creates a range spanning from `start` position to `end` position.
-	 * **Note:** Constructor creates it's own {@link treeModel.Position} instances basing on passed values.
+	 * **Note:** Constructor creates it's own {@link core.treeModel.Position} instances basing on passed values.
 	 *
-	 * @param {treeModel.Position} start Start position.
-	 * @param {treeModel.Position} end End position.
-	 * @constructor
+	 * @param {core.treeModel.Position} start Start position.
+	 * @param {core.treeModel.Position} end End position.
 	 */
 	constructor( start, end ) {
 		/**
 		 * Start position.
 		 *
-		 * @property {treeModel.Position}
+		 * @private
+		 * @member {core.treeModel.Position}  core.treeModel.Range#start
 		 */
 		this.start = Position.createFromPosition( start );
 
 		/**
 		 * End position.
 		 *
-		 * @property {treeModel.Position}
+		 * @private
+		 * @member {core.treeModel.Position} core.treeModel.Range#end
 		 */
 		this.end = Position.createFromPosition( end );
 	}
@@ -42,7 +43,7 @@ export default class Range {
 	/**
 	 * Returns whether the range is collapsed, that is it start and end positions are equal.
 	 *
-	 * @property {Boolean}
+	 * @type {Boolean}
 	 */
 	get isCollapsed() {
 		return this.start.isEqual( this.end );
@@ -60,7 +61,7 @@ export default class Range {
 	/**
 	 * Range root element. Equals to the root of start position (which should be same as root of end position).
 	 *
-	 * @property {treeModel.RootElement}
+	 * @type {core.treeModel.RootElement}
 	 */
 	get root() {
 		return this.start.root;
@@ -69,35 +70,35 @@ export default class Range {
 	/**
 	 * Range iterator.
 	 *
-	 * @see treeModel.TreeWalker
+	 * @see core.treeModel.TreeWalker
 	 */
 	[ Symbol.iterator ]() {
 		return new TreeWalker( { boundaries: this } );
 	}
 
 	/**
-	 * Checks whether this contains given {@link treeModel.Position position}.
+	 * Checks whether this contains given {@link core.treeModel.Position position}.
 	 *
-	 * @param {treeModel.Position} position Position to check.
-	 * @returns {Boolean} True if given {@link treeModel.Position position} is contained.
+	 * @param {core.treeModel.Position} position Position to check.
+	 * @returns {Boolean} True if given {@link core.treeModel.Position position} is contained.
 	 */
 	containsPosition( position ) {
 		return position.isAfter( this.start ) && position.isBefore( this.end );
 	}
 
 	/**
-	 * Checks whether this range contains given {@link treeModel.Range range}.
+	 * Checks whether this range contains given {@link core.treeModel.Range range}.
 	 *
-	 * @param {treeModel.Range} otherRange Range to check.
-	 * @returns {Boolean} True if given {@link treeModel.Range range} boundaries are contained by this range.
+	 * @param {core.treeModel.Range} otherRange Range to check.
+	 * @returns {Boolean} True if given {@link core.treeModel.Range range} boundaries are contained by this range.
 	 */
 	containsRange( otherRange ) {
 		return this.containsPosition( otherRange.start ) && this.containsPosition( otherRange.end );
 	}
 
 	/**
-	 * Gets a part of this {@link treeModel.Range range} which is not a part of given {@link treeModel.Range range}. Returned
-	 * array contains zero, one or two {@link treeModel.Range ranges}.
+	 * Gets a part of this {@link core.treeModel.Range range} which is not a part of given {@link core.treeModel.Range range}. Returned
+	 * array contains zero, one or two {@link core.treeModel.Range ranges}.
 	 *
 	 * Examples:
 	 *
@@ -114,8 +115,8 @@ export default class Range {
 	 *		transformed = range.getDifference( otherRange );
 	 *		// transformed array has two ranges: from [ 2, 7 ] to [ 3 ] and from [ 4 ] to [ 4, 0, 1 ]
 	 *
-	 * @param {treeModel.Range} otherRange Range to differentiate against.
-	 * @returns {Array.<treeModel.Range>} The difference between ranges.
+	 * @param {core.treeModel.Range} otherRange Range to differentiate against.
+	 * @returns {Array.<core.treeModel.Range>} The difference between ranges.
 	 */
 	getDifference( otherRange ) {
 		const ranges = [];
@@ -143,7 +144,7 @@ export default class Range {
 	}
 
 	/**
-	 * Returns an intersection of this {@link treeModel.Range range} and given {@link treeModel.Range range}. Intersection
+	 * Returns an intersection of this {@link core.treeModel.Range range} and given {@link core.treeModel.Range range}. Intersection
 	 * is a common part of both of those ranges. If ranges has no common part, returns `null`.
 	 *
 	 * Examples:
@@ -155,8 +156,8 @@ export default class Range {
 	 *		otherRange = new Range( new Position( root, [ 3 ] ), new Position( root, [ 5 ] ) );
 	 *		transformed = range.getIntersection( otherRange ); // range from [ 3 ] to [ 4, 0, 1 ]
 	 *
-	 * @param {treeModel.Range} otherRange Range to check for intersection.
-	 * @returns {treeModel.Range|null} A common part of given ranges or null if ranges have no common part.
+	 * @param {core.treeModel.Range} otherRange Range to check for intersection.
+	 * @returns {core.treeModel.Range|null} A common part of given ranges or null if ranges have no common part.
 	 */
 	getIntersection( otherRange ) {
 		if ( this.isIntersecting( otherRange ) ) {
@@ -217,7 +218,7 @@ export default class Range {
 	 * **Note:** this method is not returning flat ranges that contain no nodes. It may also happen that not-collapsed
 	 * range will return an empty array of flat ranges.
 	 *
-	 * @returns {Array.<treeModel.Range>} Array of flat ranges.
+	 * @returns {Array.<core.treeModel.Range>} Array of flat ranges.
 	 */
 	getMinimalFlatRanges() {
 		let ranges = [];
@@ -260,20 +261,20 @@ export default class Range {
 	}
 
 	/**
-	 * Returns an iterator that iterates over all {@link treeModel.Node nodes} that are in this range and returns them.
-	 * A node is in the range when it is after a {@link treeModel.Position position} contained in this range.
-	 * In other words, this iterates over all text characters that are inside the range and all the {@link treeModel.Element}s
+	 * Returns an iterator that iterates over all {@link core.treeModel.Node nodes} that are in this range and returns them.
+	 * A node is in the range when it is after a {@link core.treeModel.Position position} contained in this range.
+	 * In other words, this iterates over all text characters that are inside the range and all the {@link core.treeModel.Element}s
 	 * we enter into when iterating over this range.
 	 *
-	 * **Note:** this method will not return a parent node of start position. This is in contrary to {@link treeModel.TreeWalker}
-	 * which will return that node with `'ELEMENT_END'` type. This method also returns each {@link treeModel.Element} once,
-	 * while simply used {@link treeModel.TreeWalker} might return it twice: for `'ELEMENT_START'` and `'ELEMENT_END'`.
+	 * **Note:** this method will not return a parent node of start position. This is in contrary to {@link core.treeModel.TreeWalker}
+	 * which will return that node with `'ELEMENT_END'` type. This method also returns each {@link core.treeModel.Element} once,
+	 * while simply used {@link core.treeModel.TreeWalker} might return it twice: for `'ELEMENT_START'` and `'ELEMENT_END'`.
 	 *
 	 * @see {treeModel.TreeWalker}
 	 * @param {Boolean} [mergeCharacters] Flag indicating whether all consecutive characters with the same attributes
-	 * should be returned as one {@link treeModel.TextFragment} (`true`) or one by one as multiple {@link treeModel.CharacterProxy}
+	 * should be returned as one {@link core.treeModel.TextFragment} (`true`) or one by one as multiple {@link core.treeModel.CharacterProxy}
 	 * (`false`) objects. Defaults to `false`.
-	 * @returns {Iterable.<treeModel.Node|treeModel.TextFragment>}
+	 * @returns {Iterable.<core.treeModel.Node|treeModel.TextFragment>}
 	 */
 	*getAllNodes( mergeCharacters ) {
 		let it = new TreeWalker( { boundaries: this, mergeCharacters: mergeCharacters } );
@@ -289,13 +290,13 @@ export default class Range {
 	}
 
 	/**
-	 * Returns an iterator that iterates over all {@link treeModel.Position positions} that are boundaries or
+	 * Returns an iterator that iterates over all {@link core.treeModel.Position positions} that are boundaries or
 	 * contained in this range.
 	 *
 	 * @param {Boolean} [mergeCharacters] Flag indicating whether all consecutive characters with the same attributes
-	 * should be returned as one {@link treeModel.TextFragment} (`true`) or one by one as multiple {@link treeModel.CharacterProxy}
+	 * should be returned as one {@link core.treeModel.TextFragment} (`true`) or one by one as multiple {@link core.treeModel.CharacterProxy}
 	 * (`false`) objects. Defaults to `false`.
-	 * @returns {Iterable.<treeModel.Position>}
+	 * @returns {Iterable.<core.treeModel.Position>}
 	 */
 	*getPositions( mergeCharacters ) {
 		let it = new TreeWalker( { boundaries: this, mergeCharacters: mergeCharacters } );
@@ -306,14 +307,14 @@ export default class Range {
 	}
 
 	/**
-	 * Returns an iterator that iterates over all {@link treeModel.Node nodes} that are top-level nodes in this range
+	 * Returns an iterator that iterates over all {@link core.treeModel.Node nodes} that are top-level nodes in this range
 	 * and returns them. A node is a top-level node when it is in the range but it's parent is not. In other words,
 	 * this function splits the range into separate sub-trees and iterates over their roots.
 	 *
 	 * @param {Boolean} [mergeCharacters] Flag indicating whether all consecutive characters with the same attributes
-	 * should be returned as one {@link treeModel.TextFragment} (`true`) or one by one as multiple {@link treeModel.CharacterProxy}
+	 * should be returned as one {@link core.treeModel.TextFragment} (`true`) or one by one as multiple {@link core.treeModel.CharacterProxy}
 	 * (`false`) objects. Defaults to `false`.
-	 * @returns {Iterable.<treeModel.Node|treeModel.TextFragment>}
+	 * @returns {Iterable.<core.treeModel.Node|treeModel.TextFragment>}
 	 */
 	*getTopLevelNodes( mergeCharacters ) {
 		let flatRanges = this.getMinimalFlatRanges();
@@ -348,8 +349,8 @@ export default class Range {
 
 	/**
 	 * Returns an array containing one or two {treeModel.Range ranges} that are a result of transforming this
-	 * {@link treeModel.Range range} by inserting `howMany` nodes at `insertPosition`. Two {@link treeModel.Range ranges} are
-	 * returned if the insertion was inside this {@link treeModel.Range range}.
+	 * {@link core.treeModel.Range range} by inserting `howMany` nodes at `insertPosition`. Two {@link core.treeModel.Range ranges} are
+	 * returned if the insertion was inside this {@link core.treeModel.Range range}.
 	 *
 	 * Examples:
 	 *
@@ -363,11 +364,11 @@ export default class Range {
 	 *		transformed = range.getTransformedByInsertion( new Position( root, [ 3, 2 ] ), 4, true );
 	 *		// transformed array has one range which is equal to `range`. This is because of spreadOnlyOnSameLevel flag.
 	 *
-	 * @param {treeModel.Position} insertPosition Position where nodes are inserted.
+	 * @param {core.treeModel.Position} insertPosition Position where nodes are inserted.
 	 * @param {Number} howMany How many nodes are inserted.
 	 * @param {Boolean} spreadOnlyOnSameLevel Flag indicating whether this {treeModel.Range range} should be spread
 	 * if insertion was inside a node from this {treeModel.Range range} but not in the range itself.
-	 * @returns {Array.<treeModel.Range>} Result of the transformation.
+	 * @returns {Array.<core.treeModel.Range>} Result of the transformation.
 	 */
 	getTransformedByInsertion( insertPosition, howMany, spreadOnlyOnSameLevel ) {
 		// Flag indicating whether this whole range and given insertPosition is on the same tree level.
@@ -402,7 +403,7 @@ export default class Range {
 	/**
 	 * Two ranges equal if their start and end positions equal.
 	 *
-	 * @param {treeModel.Range} otherRange Range to compare with.
+	 * @param {core.treeModel.Range} otherRange Range to compare with.
 	 * @returns {Boolean} True if ranges equal.
 	 */
 	isEqual( otherRange ) {
@@ -412,7 +413,7 @@ export default class Range {
 	/**
 	 * Checks and returns whether this range intersects with given range.
 	 *
-	 * @param {treeModel.Range} otherRange Range to compare with.
+	 * @param {core.treeModel.Range} otherRange Range to compare with.
 	 * @returns {Boolean} True if ranges intersect.
 	 */
 	isIntersecting( otherRange ) {
@@ -422,8 +423,8 @@ export default class Range {
 	/**
 	 * Creates a range inside an element which starts before the first child and ends after the last child.
 	 *
-	 * @param {treeModel.Element} element Element which is a parent for the range.
-	 * @returns {treeModel.Range} Created range.
+	 * @param {core.treeModel.Element} element Element which is a parent for the range.
+	 * @returns {core.treeModel.Range} Created range.
 	 */
 	static createFromElement( element ) {
 		return this.createFromParentsAndOffsets( element, 0, element, element.getChildCount() );
@@ -432,9 +433,9 @@ export default class Range {
 	/**
 	 * Creates a new range spreading from specified position to the same position moved by given shift.
 	 *
-	 * @param {treeModel.Position} position Beginning of the range.
+	 * @param {core.treeModel.Position} position Beginning of the range.
 	 * @param {Number} shift How long the range should be.
-	 * @returns {treeModel.Range}
+	 * @returns {core.treeModel.Range}
 	 */
 	static createFromPositionAndShift( position, shift ) {
 		return new this( position, position.getShiftedBy( shift ) );
@@ -443,11 +444,11 @@ export default class Range {
 	/**
 	 * Creates a range from given parents and offsets.
 	 *
-	 * @param {treeModel.Element} startElement Start position parent element.
+	 * @param {core.treeModel.Element} startElement Start position parent element.
 	 * @param {Number} startOffset Start position offset.
-	 * @param {treeModel.Element} endElement End position parent element.
+	 * @param {core.treeModel.Element} endElement End position parent element.
 	 * @param {Number} endOffset End position offset.
-	 * @returns {treeModel.Range} Created range.
+	 * @returns {core.treeModel.Range} Created range.
 	 */
 	static createFromParentsAndOffsets( startElement, startOffset, endElement, endOffset ) {
 		return new this(
@@ -459,8 +460,8 @@ export default class Range {
 	/**
 	 * Creates and returns a new instance of Range which is equal to passed range.
 	 *
-	 * @param {treeModel.Range} range Range to clone.
-	 * @returns {treeModel.Range}
+	 * @param {core.treeModel.Range} range Range to clone.
+	 * @returns {core.treeModel.Range}
 	 */
 	static createFromRange( range ) {
 		return new this( range.start, range.end );

+ 6 - 6
packages/ckeditor5-engine/src/treemodel/rootelement.js

@@ -10,24 +10,24 @@ import Element from './element.js';
 /**
  * Class for nodes that are roots of trees in tree data model.
  *
- * @class treeModel.RootElement
+ * @memberOf core.treeModel
+ * @extends core.treeModel.Element
  */
 export default class RootElement extends Element {
 	/**
 	 * Creates tree root node.
 	 *
-	 * @param {treeModel.Document} doc {@link treeModel.Document} that is an owner of the root.
-	 * @constructor
+	 * @param {Document} doc {@link Document} that is an owner of the root.
 	 */
 	constructor( doc ) {
 		super( 'root' );
 
 		/**
-		 * {@link treeModel.Document} that is an owner of this root.
+		 * {@link core.treeModel.Document} that is an owner of this root.
 		 *
 		 * @readonly
-		 * @property {treeModel.Document}
+		 * @member {core.treeModel.Document} core.treeModel.RootElement#doc
 		 */
 		this.document = doc;
 	}
-}
+}

+ 21 - 22
packages/ckeditor5-engine/src/treemodel/selection.js

@@ -11,23 +11,21 @@ import CKEditorError from '../ckeditorerror.js';
 import utils from '../utils.js';
 
 /**
- * Represents a selection that is made on nodes in {@link treeModel.Document}. Selection instance is
- * created by {@link treeModel.Document}. In most scenarios you should not need to create an instance of Selection.
+ * Represents a selection that is made on nodes in {@link core.treeModel.Document}. Selection instance is
+ * created by {@link core.treeModel.Document}. In most scenarios you should not need to create an instance of Selection.
  *
- * @class treeModel.Selection
+ * @memberOf core.treeModel
  */
 export default class Selection {
 	/**
 	 * Creates an empty selection.
-	 *
-	 * @constructor
 	 */
 	constructor() {
 		/**
 		 * List of attributes set on current selection.
 		 *
 		 * @protected
-		 * @property {Map}
+		 * @member {Map} core.treeModel.Selection#_attrs
 		 */
 		this._attrs = new Map();
 
@@ -35,7 +33,7 @@ export default class Selection {
 		 * Stores all ranges that are selected.
 		 *
 		 * @private
-		 * @property {Array.<LiveRange>}
+		 * @member {Array.<core.treeModel.LiveRange>} core.treeModel.Selection#_ranges
 		 */
 		this._ranges = [];
 
@@ -43,7 +41,7 @@ export default class Selection {
 		 * Specifies whether the last added range was added as a backward or forward range.
 		 *
 		 * @private
-		 * @property {Boolean}
+		 * @member {Boolean} core.treeModel.Selection#_lastRangeBackward
 		 */
 		this._lastRangeBackward = false;
 	}
@@ -55,7 +53,7 @@ export default class Selection {
 	 * Anchor is always a start or end of the most recent added range. It may be a bit unintuitive when
 	 * there are multiple ranges in selection.
 	 *
-	 * @property {treeModel.LivePosition|null}
+	 * @type {core.treeModel.LivePosition|null}
 	 */
 	get anchor() {
 		if ( this._ranges.length > 0 ) {
@@ -71,8 +69,8 @@ export default class Selection {
 	 * Selection focus. Focus is a position where the selection ends. When there are no ranges in selection,
 	 * focus is null.
 	 *
-	 * @see {#anchor}
-	 * @property {treeModel.LivePosition|null}
+	 * @link {#anchor}
+	 * @type {core.treeModel.LivePosition|null}
 	 */
 	get focus() {
 		if ( this._ranges.length > 0 ) {
@@ -87,7 +85,7 @@ export default class Selection {
 	/**
 	 * Returns whether the selection is collapsed. Selection is collapsed when all it's ranges are collapsed.
 	 *
-	 * @property {Boolean}
+	 * @type {Boolean}
 	 */
 	get isCollapsed() {
 		for ( let i = 0; i < this._ranges.length; i++ ) {
@@ -100,13 +98,13 @@ export default class Selection {
 	}
 
 	/**
-	 * Adds a range to the selection. Added range is copied and converted to {@link treeModel.LiveRange}. This means
+	 * Adds a range to the selection. Added range is copied and converted to {@link core.treeModel.LiveRange}. This means
 	 * that passed range is not saved in the Selection instance and you can safely operate on it. Accepts a flag
-	 * describing in which way the selection is made - passed range might be selected from {@link treeModel.Range#start}
-	 * to {@link treeModel.Range#end} or from {@link treeModel.Range#start} to {@link treeModel.Range#end}. The flag
+	 * describing in which way the selection is made - passed range might be selected from {@link core.treeModel.Range#start}
+	 * to {@link core.treeModel.Range#end} or from {@link core.treeModel.Range#start} to {@link core.treeModel.Range#end}. The flag
 	 * is used to set {@link #anchor} and {@link #focus} properties.
 	 *
-	 * @param {treeModel.Range} range Range to add.
+	 * @param {core.treeModel.Range} range Range to add.
 	 * @param {Boolean} [isBackward] Flag describing if added range was selected forward - from start to end (`false`)
 	 * or backward - from end to start (`true`). Defaults to `false`.
 	 */
@@ -138,6 +136,7 @@ export default class Selection {
 
 	/**
 	 * Removes all ranges that were added to the selection. Fires update event.
+	 *
 	 */
 	removeAllRanges() {
 		this.detach();
@@ -151,7 +150,7 @@ export default class Selection {
 	 * is treated like the last added range and is used to set {@link #anchor} and {@link #focus}. Accepts a flag
 	 * describing in which way the selection is made (see {@link #addRange}).
 	 *
-	 * @param {Array.<treeModel.Range>} newRanges Array of ranges to set.
+	 * @param {Array.<core.treeModel.Range>} newRanges Array of ranges to set.
 	 * @param {Boolean} [isLastBackward] Flag describing if last added range was selected forward - from start to end (`false`)
 	 * or backward - from end to start (`true`). Defaults to `false`.
 	 */
@@ -234,13 +233,13 @@ export default class Selection {
 }
 
 /**
- * Converts given range to {@link treeModel.LiveRange} and adds it to internal ranges array. Throws an error
+ * Converts given range to {@link core.treeModel.LiveRange} and adds it to internal ranges array. Throws an error
  * if given range is intersecting with any range that is already stored in this selection.
  *
  * @private
  * @method pushRange
- * @memberOf {treeModel.Selection}
- * @param {treeModel.Range} range Range to add.
+ * @memberOf {core.treeModel.Selection}
+ * @param {core.treeModel.Range} range Range to add.
  */
 function pushRange( range ) {
 	/* jshint validthis: true */
@@ -250,8 +249,8 @@ function pushRange( range ) {
 			 * Trying to add a range that intersects with another range from selection.
 			 *
 			 * @error selection-range-intersects
-			 * @param {treeModel.Range} addedRange Range that was added to the selection.
-			 * @param {treeModel.Range} intersectingRange Range from selection that intersects with `addedRange`.
+			 * @param {core.treeModel.Range} addedRange Range that was added to the selection.
+			 * @param {core.treeModel.Range} intersectingRange Range from selection that intersects with `addedRange`.
 			 */
 			throw new CKEditorError(
 				'selection-range-intersects: Trying to add a range that intersects with another range from selection.',

+ 4 - 5
packages/ckeditor5-engine/src/treemodel/text.js

@@ -8,12 +8,12 @@
 import utils from '../utils.js';
 
 /**
- * Data structure for text with attributes. Note that `Text` is not a {@link treeModel.Node}. This class is used
+ * Data structure for text with attributes. Note that `Text` is not a {@link core.treeModel.Node}. This class is used
  * as an aggregator for multiple characters that have same attributes. Example usage:
  *
  *		let myElem = new Element( 'li', [], new Text( 'text with attributes', { foo: true, bar: true } ) );
  *
- * @class treeModel.Text
+ * @memberOf core.treeModel
  */
 export default class Text {
 	/**
@@ -21,14 +21,13 @@ export default class Text {
 	 *
 	 * @param {String} text Described text.
 	 * @param {Iterable|Object} attrs Iterable collection of attributes.
-	 * @constructor
 	 */
 	constructor( text, attrs ) {
 		/**
 		 * Text.
 		 *
 		 * @readonly
-		 * @property {String}
+		 * @member {String} core.treeModel.Text#text
 		 */
 		this.text = text || '';
 
@@ -36,7 +35,7 @@ export default class Text {
 		 * List of attributes bound with the text.
 		 *
 		 * @protected
-		 * @property {Map}
+		 * @member {Map} core.treeModel.Text#_attrs
 		 */
 		this._attrs = utils.toMap( attrs );
 	}

+ 17 - 17
packages/ckeditor5-engine/src/treemodel/textfragment.js

@@ -10,64 +10,64 @@ import CharacterProxy from './characterproxy.js';
 /**
  * TextFragment is an aggregator for multiple CharacterProxy instances that are placed next to each other in
  * tree model, in the same parent, and all have same attributes set. Instances of this class are created and returned
- * in various algorithms that "merge characters" (see {@link treeModel.TreeWalker}, {@link treeModel.Range}).
+ * in various algorithms that "merge characters" (see {@link core.treeModel.TreeWalker}, {@link core.treeModel.Range}).
  *
- * Difference between {@link treeModel.TextFragment} and {@link treeModel.Text} is that the former is a set of
- * nodes taken from tree model, while {@link treeModel.Text} is simply a string with attributes set.
+ * Difference between {@link core.treeModel.TextFragment} and {@link core.treeModel.Text} is that the former is a set of
+ * nodes taken from tree model, while {@link core.treeModel.Text} is simply a string with attributes set.
  *
- * You should never create an instance of this class by your own. Instead, use string literals or {@link treeModel.Text}.
+ * You should never create an instance of this class by your own. Instead, use string literals or {@link core.treeModel.Text}.
  *
- * @class treeModel.TextFragment
+ * @memberOf core.treeModel
  */
 export default class TextFragment {
 	/**
 	 * Creates a text fragment.
 	 *
-	 * @param {treeModel.CharacterProxy} firstCharacter First character node contained in {@link treeModel.TextFragment}.
-	 * @param {Number} length Whole text contained in {@link treeModel.TextFragment}.
+	 * @param {core.treeModel.CharacterProxy} firstCharacter First character node contained in {@link core.treeModel.TextFragment}.
+	 * @param {Number} length Whole text contained in {@link core.treeModel.TextFragment}.
 	 * @protected
 	 * @constructor
 	 */
 	constructor( firstCharacter, length ) {
 		/**
-		 * First character node contained in {@link treeModel.TextFragment}.
+		 * First character node contained in {@link core.treeModel.TextFragment}.
 		 *
 		 * @readonly
-		 * @property {treeModel.CharacterProxy} first
+		 * @type {core.treeModel.CharacterProxy}
 		 */
 		this.first = firstCharacter;
 
 		/**
-		 * Characters contained in {@link treeModel.TextFragment}.
+		 * Characters contained in {@link core.treeModel.TextFragment}.
 		 *
 		 * @readonly
-		 * @property {String} text
+		 * @type {String}
 		 */
 		this.text = firstCharacter._nodeListText.text.substr( this.first._index, length );
 
 		/**
-		 * Last {@link treeModel.CharacterProxy character node} contained in {@link treeModel.TextFragment}.
+		 * Last {@link core.treeModel.CharacterProxy character node} contained in {@link core.treeModel.TextFragment}.
 		 *
 		 * @readonly
-		 * @property {treeModel.CharacterProxy} last
+		 * @type {core.treeModel.CharacterProxy}
 		 */
 		this.last = this.getCharAt( this.text.length - 1 );
 	}
 
 	/**
-	 * A common parent of all character nodes contained in {@link treeModel.TextFragment}.
+	 * A common parent of all character nodes contained in {@link core.treeModel.TextFragment}.
 	 *
-	 * @property {treeModel.Element} commonParent
+	 * @type {core.treeModel.Element}
 	 */
 	get commonParent() {
 		return this.first.parent;
 	}
 
 	/**
-	 * Gets a character at given index and creates a {@link treeModel.CharacterProxy} out of it.
+	 * Gets a character at given index and creates a {@link core.treeModel.CharacterProxy} out of it.
 	 *
 	 * @param {Number} index Character index.
-	 * @returns {treeModel.CharacterProxy}
+	 * @returns {core.treeModel.CharacterProxy}
 	 */
 	getCharAt( index ) {
 		if ( index < 0 || index >= this.text.length ) {

+ 31 - 31
packages/ckeditor5-engine/src/treemodel/treewalker.js

@@ -11,37 +11,20 @@ import Element from './element.js';
 import Position from './position.js';
 import CKEditorError from '../ckeditorerror.js';
 
-/**
- * Type of the step made by {@link treeModel.TreeWalker}.
- * Possible values: `'ELEMENT_START'` if walker is at the beginning of a node, `'ELEMENT_END'` if walker is at the end of node,
- * `'CHARACTER'` if walker traversed over a character, or `'TEXT'` if walker traversed over multiple characters (available in
- * character merging mode, see {@link treeModel.TreeWalker#constructor}).
- *
- * @typedef {String} treeModel.TreeWalkerItemType
- */
-
-/**
- * Object returned by {@link treeModel.TreeWalker} when traversing tree model.
- *
- * @typedef {Object} treeModel.TreeWalkerItem
- * @property {treeModel.TreeWalkerItemType} type
- * @property {treeModel.Node|treeModel.TextFragment} item Value between old and new position of {@link treeModel.TreeWalker}.
- */
-
 /**
  * Position iterator class. It allows to iterate forward and backward over the tree document.
  *
- * @class treeModel.TreeWalker
+ * @memberOf core.treeModel
  */
 export default class TreeWalker {
 	/**
 	 * Creates a range iterator. All parameters are optional, but you have to specify either `boundaries` or `position`.
 	 *
 	 * @param {Object} options Object with configuration.
-	 * @param {treeModel.Range} [options.boundaries] Range to define boundaries of the iterator.
-	 * @param {treeModel.Position} [options.position] Starting position.
+	 * @param {core.treeModel.Range} [options.boundaries] Range to define boundaries of the iterator.
+	 * @param {core.treeModel.Position} [options.position] Starting position.
 	 * @param {Boolean} [options.mergeCharacters=false] Flag indicating whether all consecutive characters with the same attributes
-	 * should be returned as one {@link treeModel.TextFragment} (`true`) or one by one as multiple {@link treeModel.CharacterProxy}
+	 * should be returned as one {@link core.treeModel.TextFragment} (`true`) or one by one as multiple {@link core.treeModel.CharacterProxy}
 	 * (`false`) objects.
 	 * @constructor
 	 */
@@ -63,7 +46,7 @@ export default class TreeWalker {
 		 *
 		 * If boundaries are not defined they are set before first and after last child of the root node.
 		 *
-		 * @property {treeModel.Range} boundaries
+		 * @type {core.treeModel.Range}
 		 */
 		this.boundaries = options.boundaries || null;
 
@@ -71,7 +54,7 @@ export default class TreeWalker {
 		 * Start boundary cached for optimization purposes.
 		 *
 		 * @private
-		 * @property {treeModel.Element} boundaryStartParent
+		 * @type {core.treeModel.Element}
 		 */
 		this._boundaryStartParent = this.boundaries ? this.boundaries.start.parent : null;
 
@@ -79,15 +62,15 @@ export default class TreeWalker {
 		 * End boundary cached for optimization purposes.
 		 *
 		 * @private
-		 * @property {treeModel.Element} boundaryEndParent
+		 * @type {core.treeModel.Element}
 		 */
 		this._boundaryEndParent = this.boundaries ? this.boundaries.end.parent : null;
 
 		/**
 		 * Iterator position. This is alway static position, even if the initial position was a
-		 * {@link treeModel.LivePosition live position}.
+		 * {@link core.treeModel.LivePosition live position}.
 		 *
-		 * @property {treeModel.Position} position
+		 * @type {core.treeModel.Position}
 		 */
 		this.position = options.position ?
 			Position.createFromPosition( options.position ) :
@@ -95,9 +78,9 @@ export default class TreeWalker {
 
 		/**
 		 * Flag indicating whether all consecutive characters with the same attributes should be
-		 * returned as one {@link treeModel.CharacterProxy} (`true`) or one by one (`false`).
+		 * returned as one {@link core.treeModel.CharacterProxy} (`true`) or one by one (`false`).
 		 *
-		 * @property {Boolean} mergeCharacters
+		 * @type {Boolean}
 		 */
 		this.mergeCharacters = !!options.mergeCharacters;
 
@@ -105,7 +88,7 @@ export default class TreeWalker {
 		 * Parent of the most recently visited node. Cached for optimization purposes.
 		 *
 		 * @private
-		 * @property {treeModel.Element} visitedParent
+		 * @type {core.treeModel.Element}
 		 */
 		this._visitedParent = this.position.parent;
 	}
@@ -115,7 +98,7 @@ export default class TreeWalker {
 	 *
 	 * @returns {Object} Object implementing iterator interface, returning information about taken step.
 	 * @returns {Boolean} return.done True if iterator is done.
-	 * @returns {treeModel.TreeWalkerItem} return.value Information about taken step.
+	 * @returns {core.treeModel.TreeWalkerItem} return.value Information about taken step.
 	 */
 	next() {
 		const position = Position.createFromPosition( this.position );
@@ -179,7 +162,7 @@ export default class TreeWalker {
 	 *
 	 * @returns {Object} Object implementing iterator interface, returning information about taken step.
 	 * @returns {Boolean} return.done True if iterator is done.
-	 * @returns {treeModel.TreeWalkerItem} return.value Information about taken step.
+	 * @returns {core.treeModel.TreeWalkerItem} return.value Information about taken step.
 	 */
 	previous() {
 		const position = Position.createFromPosition( this.position );
@@ -248,3 +231,20 @@ function formatReturnValue( type, item ) {
 		}
 	};
 }
+
+/**
+ * Type of the step made by {@link core.treeModel.TreeWalker}.
+ * Possible values: `'ELEMENT_START'` if walker is at the beginning of a node, `'ELEMENT_END'` if walker is at the end of node,
+ * `'CHARACTER'` if walker traversed over a character, or `'TEXT'` if walker traversed over multiple characters (available in
+ * character merging mode, see {@link core.treeModel.TreeWalker#constructor}).
+ *
+ * @typedef {String} core.treeModel.TreeWalkerItemType
+ */
+
+/**
+ * Object returned by {@link core.treeModel.TreeWalker} when traversing tree model.
+ *
+ * @typedef {Object} core.treeModel.TreeWalkerItem
+ * @property {treeModel.TreeWalkerItemType} type
+ * @property {treeModel.Node|treeModel.TextFragment} item Value between old and new position of {@link core.treeModel.TreeWalker}.
+ */

+ 8 - 0
packages/ckeditor5-engine/src/treeview.jsdoc

@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @namespace core.treeView
+ */

+ 30 - 30
packages/ckeditor5-engine/src/treeview/converter.js

@@ -10,21 +10,19 @@ import ViewElement from './element.js';
 
 /**
  * Converter is a set of tools to do transformations between DOM nodes and view nodes. It also handles
- * {@link #bindElements binding} these nodes.
+ * {@link core.treeView.Converter#bindElements binding} these nodes.
  *
- * Converter does not check which nodes should be rendered (use {@link treeView.Renderer}), does not keep a state of
- * a tree nor keeps synchronization between tree view and DOM tree (use {@treeView.TreeView}).
+ * Converter does not check which nodes should be rendered (use {@link core.treeView.Renderer}), does not keep a state of
+ * a tree nor keeps synchronization between tree view and DOM tree (use {@link @core.treeView.TreeView}).
  *
  * Converter keeps DOM elements to View element bindings, so when the converter will be destroyed, the binding will be
  * lost. Two converters will keep separate binding maps, so one tree view can be bound with two DOM trees.
  *
- * @class treeView.Converter
+ * @memberOf core.treeView
  */
 export default class Converter {
 	/**
 	 * Creates converter.
-	 *
-	 * @constructor
 	 */
 	constructor() {
 		// Using WeakMap prevent memory leaks: when the converter will be destroyed all referenced between View and DOM
@@ -32,12 +30,14 @@ export default class Converter {
 		// will be also removed, isn't it brilliant?
 		//
 		// Yes, PJ. It is.
+		//
+		// You guys so smart.
 
 		/**
 		 * DOM to View mapping.
 		 *
 		 * @private
-		 * @type {WeakMap}
+		 * @member {WeakMap} core.treeView.Converter#_domToViewMapping
 		 */
 		this._domToViewMapping = new WeakMap();
 
@@ -45,17 +45,17 @@ export default class Converter {
 		 * View to DOM mapping.
 		 *
 		 * @private
-		 * @type {WeakMap}
+		 * @member {WeakMap} core.treeView.Converter#_viewToDomMapping
 		 */
 		this._viewToDomMapping = new WeakMap();
 	}
 
 	/**
 	 * Binds DOM and View elements, so it will be possible to get corresponding elements using
-	 * {@link treeView.Converter#getCorrespondingViewElement} and {@link treeView.Converter#getCorespondingDOMElement}.
+	 * {@link core.treeView.Converter#getCorrespondingViewElement} and {@link core.treeView.Converter#getCorespondingDOMElement}.
 	 *
 	 * @param {HTMLElement} domElement DOM element to bind.
-	 * @param {treeView.Element} viewElement View element to bind.
+	 * @param {core.treeView.Element} viewElement View element to bind.
 	 */
 	bindElements( domElement, viewElement ) {
 		this._domToViewMapping.set( domElement, viewElement );
@@ -67,7 +67,7 @@ export default class Converter {
 	 * text data. Nodes need to have corresponding types. In all other cases nodes are different.
 	 *
 	 * @param {Node} domNode DOM node to compare.
-	 * @param {treeView.Node} viewNode View node to compare.
+	 * @param {core.treeView.Node} viewNode View node to compare.
 	 * @returns {Boolean} True if nodes are same.
 	 */
 	compareNodes( domNode, viewNode ) {
@@ -88,7 +88,7 @@ export default class Converter {
 	 * Converts view to DOM. For all text nodes and not bound elements new elements will be created. For bound
 	 * elements function will return corresponding elements.
 	 *
-	 * @param {treeView.Node} viewNode View node to transform.
+	 * @param {core.treeView.Node} viewNode View node to transform.
 	 * @param {document} domDocument Document which will be used to create DOM nodes.
 	 * @param {Object} [options] Conversion options.
 	 * @param {Boolean} [options.bind=false] Determines whether new elements will be bound.
@@ -135,7 +135,7 @@ export default class Converter {
 	 * @param {Object} [options] Conversion options.
 	 * @param {Boolean} [options.bind=false] Determines whether new elements will be bound.
 	 * @param {Boolean} [options.withChildren=true] It true node's children will be converter too.
-	 * @returns {treeView.Node} Converted node.
+	 * @returns {core.treeView.Node} Converted node.
 	 */
 	domToView( domNode, options ) {
 		if ( !options ) {
@@ -174,11 +174,11 @@ export default class Converter {
 	}
 
 	/**
-	 * Gets corresponding view node. This function use {@link #getCorrespondingViewElement} for elements and
+	 * Gets corresponding view node. This function use {@link core.treeView.Converter#getCorrespondingViewElement} for elements and
 	 * {@link getCorrespondingViewText} for text nodes.
 	 *
 	 * @param {Node} domNode DOM node.
-	 * @returns {treeView.Node|null} Corresponding node.
+	 * @returns {core.treeView.Node|null} Corresponding node.
 	 */
 	getCorrespondingView( domNode ) {
 		if ( domNode instanceof HTMLElement ) {
@@ -189,30 +189,30 @@ export default class Converter {
 	}
 
 	/**
-	 * Gets corresponding view element. Returns element if an view element was {@link #bindElements bound} to the given
+	 * Gets corresponding view element. Returns element if an view element was {@link core.treeView.Converter#bindElements bound} to the given
 	 * DOM element or null otherwise.
 	 *
 	 * @param {HTMLElement} domElement DOM element.
-	 * @returns {treeView.Element|null} Corresponding element or null if none element was bound.
+	 * @returns {core.treeView.Element|null} Corresponding element or null if none element was bound.
 	 */
 	getCorrespondingViewElement( domElement ) {
 		return this._domToViewMapping.get( domElement );
 	}
 
 	/**
-	 * Gets corresponding text node. Text nodes are not {@link #bindElements bound}, corresponding text node is
+	 * Gets corresponding text node. Text nodes are not {@link core.treeView.Converter#bindElements bound}, corresponding text node is
 	 * returned based on the sibling or parent.
 	 *
-	 * If the directly previous sibling is a {@link #bindElements bound} element, it is used to find the corresponding
+	 * If the directly previous sibling is a {@link core.treeView.Converter#bindElements bound} element, it is used to find the corresponding
 	 * text node.
 	 *
-	 * If this is a first child in the parent and the parent is a {@link #bindElements bound} element, it is used to
+	 * If this is a first child in the parent and the parent is a {@link core.treeView.Converter#bindElements bound} element, it is used to
 	 * find the corresponding text node.
 	 *
 	 * Otherwise `null` is returned.
 	 *
 	 * @param {Text} domText DOM text node.
-	 * @returns {treeView.Text|null} Corresponding view text node or null, if it was not possible to find a
+	 * @returns {core.treeView.Text|null} Corresponding view text node or null, if it was not possible to find a
 	 * corresponding node.
 	 */
 	getCorrespondingViewText( domText ) {
@@ -244,10 +244,10 @@ export default class Converter {
 	}
 
 	/**
-	 * Gets corresponding DOM node. This function uses {@link #getCorrespondingDomElement} for elements and
-	 * {@link #getCorrespondingDomText} for text nodes.
+	 * Gets corresponding DOM node. This function uses {@link core.treeView.Converter#getCorrespondingDomElement} for elements and
+	 * {@link core.treeView.Converter#getCorrespondingDomText} for text nodes.
 	 *
-	 * @param {treeView.Node} viewNode View node.
+	 * @param {core.treeView.Node} viewNode View node.
 	 * @returns {Node|null} Corresponding DOM node.
 	 */
 	getCorrespondingDom( viewNode ) {
@@ -259,10 +259,10 @@ export default class Converter {
 	}
 
 	/**
-	 * Gets corresponding DOM element. Returns element if an DOM element was {@link #bindElements bound} to the given
+	 * Gets corresponding DOM element. Returns element if an DOM element was {@link core.treeView.Converter#bindElements bound} to the given
 	 * view element or null otherwise.
 	 *
-	 * @param {treeView.Element} viewElement View element.
+	 * @param {core.treeView.Element} viewElement View element.
 	 * @returns {HTMLElement|null} Corresponding element or null if none element was bound.
 	 */
 	getCorrespondingDomElement( viewElement ) {
@@ -270,18 +270,18 @@ export default class Converter {
 	}
 
 	/**
-	 * Gets corresponding text node. Text nodes are not {@link #bindElements bound}, corresponding text node is
+	 * Gets corresponding text node. Text nodes are not {@link core.treeView.Converter#bindElements bound}, corresponding text node is
 	 * returned based on the sibling or parent.
 	 *
-	 * If the directly previous sibling is a {@link #bindElements bound} element, it is used to find the corresponding
+	 * If the directly previous sibling is a {@link core.treeView.Converter#bindElements bound} element, it is used to find the corresponding
 	 * text node.
 	 *
-	 * If this is a first child in the parent and the parent is a {@link #bindElements bound} element, it is used to
+	 * If this is a first child in the parent and the parent is a {@link core.treeView.Converter#bindElements bound} element, it is used to
 	 * find the corresponding text node.
 	 *
 	 * Otherwise null is returned.
 	 *
-	 * @param {treeView.Text} viewText View text node.
+	 * @param {core.treeView.Text} viewText View text node.
 	 * @returns {Text|null} Corresponding DOM text node or null, if it was not possible to find a corresponding node.
 	 */
 	getCorrespondingDomText( viewText ) {

+ 23 - 25
packages/ckeditor5-engine/src/treeview/element.js

@@ -12,7 +12,8 @@ import isPlainObject from '../lib/lodash/isPlainObject.js';
 /**
  * Tree view element.
  *
- * @class treeView.Element
+ * @memberOf core.treeView
+ * @extends core.treeView.Node
  */
 export default class Element extends Node {
 	/**
@@ -20,14 +21,13 @@ export default class Element extends Node {
 	 *
 	 * Attributes can be passes in various formats:
 	 *
-	 *		new Element( 'div', { 'class': 'editor', 'contentEditable': 'true' } ); // object
-	 *		new Element( 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator
-	 *		new Element( 'div', mapOfAttributes ); // map
+	 *        new Element( 'div', { 'class': 'editor', 'contentEditable': 'true' } ); // object
+	 *        new Element( 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator
+	 *        new Element( 'div', mapOfAttributes ); // map
 	 *
 	 * @param {String} name Node name.
-	 * @param {Object|Interable} [attrs] Collection of attributes.
-	 * @param {treeView.Node|Iterable.<treeView.Node>} [children] List of nodes to be inserted into created element.
-	 * @constructor
+	 * @param {Object|Iterable} [attrs] Collection of attributes.
+	 * @param {core.treeView.Node|Iterable.<core.treeView.Node>} [children] List of nodes to be inserted into created element.
 	 */
 	constructor( name, attrs, children ) {
 		super();
@@ -36,7 +36,7 @@ export default class Element extends Node {
 		 * Name of the element.
 		 *
 		 * @readonly
-		 * @property {String}
+		 * @member {String} core.treeView.Element#name
 		 */
 		this.name = name;
 
@@ -44,7 +44,7 @@ export default class Element extends Node {
 		 * Map of attributes, where attributes names are keys and attributes values are values.
 		 *
 		 * @protected
-		 * @property {Map} _attrs
+		 * @member {Map} core.treeView.Element#_attrs
 		 */
 		if ( isPlainObject( attrs ) ) {
 			this._attrs = utils.objectToMap( attrs );
@@ -56,7 +56,7 @@ export default class Element extends Node {
 		 * Array of child nodes.
 		 *
 		 * @protected
-		 * @property {Array.<treeView.Node>}
+		 * @member {Array.<core.treeView.Node>} core.treeView.Element#_children
 		 */
 		this._children = [];
 
@@ -66,12 +66,11 @@ export default class Element extends Node {
 	}
 
 	/**
-	 * {@link treeView.Element#insert Insert} a child node or a list of child nodes at the end of this node and sets
+	 * {@link core.treeView.Element#insert Insert} a child node or a list of child nodes at the end of this node and sets
 	 * the parent of these nodes to this element.
 	 *
-	 * Fires the {@link treeView.Node#change change event}.
-	 *
-	 * @param {treeView.Node|Iterable.<treeView.Node>} nodes Node or the list of nodes to be inserted.
+	 * @param {core.treeView.Node|Iterable.<core.treeView.Node>} nodes Node or the list of nodes to be inserted.
+	 * @fires {@link core.treeView.Node#change change event}
 	 */
 	appendChildren( nodes ) {
 		this.insertChildren( this.getChildCount(), nodes );
@@ -81,7 +80,7 @@ export default class Element extends Node {
 	 * Gets child at the given index.
 	 *
 	 * @param {Number} index Index of child.
-	 * @returns {treeView.Node} Child node.
+	 * @returns {core.treeView.Node} Child node.
 	 */
 	getChild( index ) {
 		return this._children[ index ];
@@ -99,7 +98,7 @@ export default class Element extends Node {
 	/**
 	 * Gets index of the given child node.
 	 *
-	 * @param {treeView.Node} node Child node.
+	 * @param {core.treeView.Node} node Child node.
 	 * @returns {Number} Index of the child node.
 	 */
 	getChildIndex( node ) {
@@ -109,7 +108,7 @@ export default class Element extends Node {
 	/**
 	 * Gets child nodes iterator.
 	 *
-	 * @returns {Iterable.<treeView.Node>} Child nodes iterator.
+	 * @returns {Iterable.<core.treeView.Node>} Child nodes iterator.
 	 */
 	getChildren() {
 		return this._children[ Symbol.iterator ]();
@@ -147,10 +146,10 @@ export default class Element extends Node {
 	/**
 	 * Adds or overwrite attribute with a specified key and value.
 	 *
-	 * Fires the {@link treeView.Node#change change event}.
 	 *
 	 * @param {String} key Attribute key.
 	 * @param {String} value Attribute value.
+	 * @fires {@link core.treeView.Node#change change event}
 	 */
 	setAttribute( key, value ) {
 		this._fireChange( 'ATTRIBUTES', this );
@@ -162,10 +161,10 @@ export default class Element extends Node {
 	 * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to
 	 * this element.
 	 *
-	 * Fires the {@link treeView.Node#change change event}.
 	 *
 	 * @param {Number} index Position where nodes should be inserted.
-	 * @param {treeView.Node|Iterable.<treeView.Node>} nodes Node or the list of nodes to be inserted.
+	 * @param {core.treeView.Node|Iterable.<core.treeView.Node>} nodes Node or the list of nodes to be inserted.
+	 * @fires {@link core.treeView.Node#change change event}.
 	 */
 	insertChildren( index, nodes ) {
 		this._fireChange( 'CHILDREN', this );
@@ -185,10 +184,9 @@ export default class Element extends Node {
 	/**
 	 * Removes attribute from the element.
 	 *
-	 * Fires the {@link treeView.Node#change change event}.
-	 *
 	 * @param {String} key Attribute key.
-	 * @returns {Boolead} Returns true if an attribute existed and has been removed.
+	 * @returns {Boolean} Returns true if an attribute existed and has been removed.
+	 * @fires {@link core.treeView.Node#change change event}
 	 */
 	removeAttribute( key ) {
 		this._fireChange( 'ATTRIBUTES', this );
@@ -199,11 +197,11 @@ export default class Element extends Node {
 	/**
 	 * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.
 	 *
-	 * Fires the {@link treeView.Node#change change event}.
 	 *
 	 * @param {Number} index Number of the first node to remove.
 	 * @param {Number} number Number of nodes to remove.
-	 * @returns {Array.<treeView.Node>} The array of removed nodes.
+	 * @returns {Array.<core.treeView.Node>} The array of removed nodes.
+	 * @fires {@link core.treeView.Node#change change event}
 	 */
 	removeChildren( index, number ) {
 		this._fireChange( 'CHILDREN', this );

+ 21 - 24
packages/ckeditor5-engine/src/treeview/node.js

@@ -13,30 +13,28 @@ import utils from '../utils.js';
  * Abstract tree view node class.
  *
  * @abstract
- * @class treeView.Node
+ * @memberOf core.treeView
  */
 export default class Node {
 	/**
 	 * Creates a tree view node.
 	 *
 	 * This is an abstract class, so this constructor should not be used directly.
-	 *
-	 * @constructor
 	 */
 	constructor() {
 		/**
-		 * Parent element. Null by default. Set by {@link treeView.Element#insertChildren}.
+		 * Parent element. Null by default. Set by {@link core.treeView.Element#insertChildren}.
 		 *
 		 * @readonly
-		 * @property {treeView.Element|null} parent
+		 * @member {core.treeView.Element|null} core.treeView.Node#parent
 		 */
 		this.parent = null;
 
 		/**
-		 * {@link treeView.TreeView} reference.
+		 * {@link core.treeView.TreeView} reference.
 		 *
 		 * @protected
-		 * @type {treeView.TreeView}
+		 * @member {core.treeView.TreeView} core.treeView.Node#_treeView
 		 */
 		this._treeView = null;
 	}
@@ -71,7 +69,7 @@ export default class Node {
 	/**
 	 * Returns nodes next sibling or `null` if it is the last child.
 	 *
-	 * @returns {treeView.Node|null} Nodes next sibling or `null` if it is the last child.
+	 * @returns {core.treeView.Node|null} Nodes next sibling or `null` if it is the last child.
 	 */
 	getNextSibling() {
 		const index = this.getIndex();
@@ -82,7 +80,7 @@ export default class Node {
 	/**
 	 * Returns nodes previous sibling or `null` if it is the first child.
 	 *
-	 * @returns {treeView.Node|null} Nodes previous sibling or `null` if it is the first child.
+	 * @returns {core.treeView.Node|null} Nodes previous sibling or `null` if it is the first child.
 	 */
 	getPreviousSibling() {
 		const index = this.getIndex();
@@ -91,11 +89,11 @@ export default class Node {
 	}
 
 	/**
-	 * Gets {@link treeView.TreeView} reference. If the node has {@link treeView.TreeView}, assign by
-	 * {@link treeView.Node#setTreeView} it will be returned. Otherwise {@link treeView.TreeView} of the parents node
+	 * Gets {@link core.treeView.TreeView} reference. If the node has {@link core.treeView.TreeView}, assign by
+	 * {@link core.treeView.Node#setTreeView} it will be returned. Otherwise {@link core.treeView.TreeView} of the parents node
 	 * will be returned. If node has no parent, `null` will be returned.
 	 *
-	 * @returns {treeView.TreeView|null} Tree view of the node, tree view of the parent or null.
+	 * @returns {core.treeView.TreeView|null} Tree view of the node, tree view of the parent or null.
 	 */
 	getTreeView() {
 		if ( this._treeView ) {
@@ -108,20 +106,19 @@ export default class Node {
 	}
 
 	/**
-	 * Sets the {@link treeView.TreeView} of the node. Note that not all of nodes need to have {@link treeView.TreeView}
-	 * assigned, see {@link treeView.Node#getTreeView}.
+	 * Sets the {@link core.treeView.TreeView} of the node. Note that not all of nodes need to have {@link core.treeView.TreeView}
+	 * assigned, see {@link core.treeView.Node#getTreeView}.
 	 *
-	 * @param {treeView.TreeView} treeView Tree view.
+	 * @param {core.treeView.TreeView} treeView Tree view.
 	 */
 	setTreeView( treeView ) {
 		this._treeView = treeView;
 	}
 
 	/**
-	 * Fires the {@link treeView.Node#change change event}.
-	 *
-	 * @param {treeView.ChangeType} type Type of the change.
-	 * @param {treeView.Node} node Changed node.
+	 * @param {core.treeView.ChangeType} type Type of the change.
+	 * @param {core.treeView.Node} node Changed node.
+	 * @fires {@link core.treeView.Node#change change event}.
 	 */
 	_fireChange( type, node ) {
 		this.fire( 'change', type, node );
@@ -134,14 +131,14 @@ export default class Node {
 	/**
 	 * Fired when a node changes.
 	 *
-	 * * In case of {@link treeView.Text text nodes} it will be a change of the text data.
-	 * * In case of {@link treeView.Element elements} it will be a change of child nodes or attributes.
+	 * * In case of {@link core.treeView.Text text nodes} it will be a change of the text data.
+	 * * In case of {@link core.treeView.Element elements} it will be a change of child nodes or attributes.
 	 *
 	 * Change event is bubbling, it is fired on the ancestors chain.
 	 *
-	 * @event change
-	 * @param {treeView.ChangeType} Type of the change.
-	 * @param {treeView.Node} Changed node.
+	 * @event core.treeView.Node#change
+	 * @param {core.treeView.ChangeType} Type of the change.
+	 * @param {core.treeView.Node} Changed node.
 	 */
 }
 

+ 8 - 0
packages/ckeditor5-engine/src/treeview/observer.jsdoc

@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @namespace core.treeView.observer
+ */

+ 42 - 36
packages/ckeditor5-engine/src/treeview/observer/mutationobserver.js

@@ -8,24 +8,23 @@
 import Observer from './observer.js';
 
 /**
- * Mutation observer class observes changes in the DOM, fires {@link treeView.TreeView#mutations} event, mark view elements
- * as changed and call {@link treeView.render}. Because all mutated nodes are marked as "to be rendered" and the
- * {@link treeView.render} is called, all changes will be reverted, unless the mutation will be handled by the
- * {@link treeView.TreeView#mutations} event listener. It means user will see only handled changes, and the editor will
+ * Mutation observer class observes changes in the DOM, fires {@link core.treeView.TreeView#mutations} event, mark view elements
+ * as changed and call {@link core.treeView.render}. Because all mutated nodes are marked as "to be rendered" and the
+ * {@link core.treeView.render} is called, all changes will be reverted, unless the mutation will be handled by the
+ * {@link core.treeView.TreeView#mutations} event listener. It means user will see only handled changes, and the editor will
  * block all changes which are not handled.
  *
  * Mutation Observer also take care of reducing number of mutations which are fired. It removes duplicates and
  * mutations on elements which do not have corresponding view elements. Also
- * {@link treeView.TreeView.MutatatedText text mutation} is fired only if parent element do not change child list.
+ * {@link core.treeView.TreeView.MutatatedText text mutation} is fired only if parent element do not change child list.
  *
- * @class treeView.observer.MutationObserver
+ * @memberOf core.treeView.observer
+ * @extends core.treeView.observer.Observer
  */
 export default class MutationObserver extends Observer {
 	/**
 	 * Mutation observer constructor. Note that most of the initialization is done in
-	 * {@link treeView.observer.MutationObserver#init} method.
-	 *
-	 * @constructor
+	 * {@link core.treeView.observer.MutationObserver#init} method.
 	 */
 	constructor() {
 		super();
@@ -34,7 +33,7 @@ export default class MutationObserver extends Observer {
 		 * Native mutation observer config.
 		 *
 		 * @private
-		 * @property {Object}
+		 * @member {Object} core.treeView.observer.MutationObserver#_config
 		 */
 		this._config = {
 			childList: true,
@@ -44,33 +43,35 @@ export default class MutationObserver extends Observer {
 		};
 	}
 
-	// Docs in the base class.
+	/**
+	 * @inheritDoc
+	 */
 	init( treeView ) {
 		/**
-		 * Reference to the {@link treeView.TreeView} object.
+		 * Reference to the {@link core.treeView.TreeView} object.
 		 *
-		 * @property {treeView.TreeView}
+		 * @member {core.treeView.TreeView} core.treeView.observer.MutationObserver#treeView
 		 */
 		this.treeView = treeView;
 
 		/**
-		 * Reference to the {@link treeView.TreeView#domRoot}.
+		 * Reference to the {@link core.treeView.TreeView#domRoot}.
 		 *
-		 * @property {HTMLElement}
+		 * @member {HTMLElement} core.treeView.observer.MutationObserver#domRoot
 		 */
 		this.domRoot = treeView.domRoot;
 
 		/**
-		 * Reference to the {@link treeView.TreeView#converter}.
+		 * Reference to the {@link core.treeView.TreeView#converter}.
 		 *
-		 * @property {treeView.Converter}
+		 * @member {core.treeView.Converter} core.treeView.observer.MutationObserver#converter
 		 */
 		this.converter = treeView.converter;
 
 		/**
-		 * Reference to the {@link treeView.TreeView#renderer}.
+		 * Reference to the {@link core.treeView.TreeView#renderer}.
 		 *
-		 * @property {treeView.Renderer}
+		 * @member {core.treeView.Renderer} core.treeView.observer.MutationObserver#renderer
 		 */
 		this.renderer = treeView.renderer;
 
@@ -78,17 +79,21 @@ export default class MutationObserver extends Observer {
 		 * Native mutation observer.
 		 *
 		 * @private
-		 * @property {window.MutationObserver}
+		 * @member {window.MutationObserver} core.treeView.observer.MutationObserver#_mutationObserver
 		 */
 		this._mutationObserver = new window.MutationObserver( this._onMutations.bind( this ) );
 	}
 
-	// Docs in the base class.
+	/**
+	 * @inheritDoc
+	 */
 	attach() {
 		this._mutationObserver.observe( this.domRoot, this._config );
 	}
 
-	// Docs in the base class.
+	/**
+	 * @inheritDoc
+	 */
 	detach() {
 		this._mutationObserver.disconnect();
 	}
@@ -96,6 +101,7 @@ export default class MutationObserver extends Observer {
 	/**
 	 * Handles mutations. Deduplicates, mark view elements to sync, fire event and call render.
 	 *
+	 * @method core.treeView.observer.MutationObserver#_onMutations
 	 * @protected
 	 * @param {Array.<Object>} domMutations Array of native mutations.
 	 */
@@ -178,24 +184,24 @@ export default class MutationObserver extends Observer {
  * mutation, so all changes which should be applied, should be handled on this event.
  *
  * @event mutations
- * @memberOf treeView.TreeView
+ * @memberOf core.treeView.TreeView
  *
- * @param {Array.<treeView.MutatatedText|treeView.MutatatedChildren>} viewMutations
+ * @param {Array.<core.treeView.TreeView~MutatatedText|core.treeView.TreeView~MutatatedChildren>} viewMutations
  * Array of mutations.
- * For mutated texts it will be {@link treeView.MutatatedText} and for mutated elements it will be
- * {@link treeView.MutatatedElement}. You can recognize the type based on the `type` property.
+ * For mutated texts it will be {@link core.treeView.TreeView~MutatatedText} and for mutated elements it will be
+ * {@link core.treeView.TreeView~MutatatedElement}. You can recognize the type based on the `type` property.
  */
 
 /**
  * Mutation item for text.
  *
- * @see treeView.TreeView#mutations
- * @see treeView.MutatatedChildren
+ * @see core.treeView.TreeView#mutations
+ * @see core.treeView.MutatatedChildren
  *
- * @typedef {Object} treeView.MutatatedText
+ * @typedef {Object} core.treeView.MutatatedText
  *
  * @property {String} type For text mutations it is always 'text'.
- * @property {treeView.Text} node Mutated text node.
+ * @property {core.treeView.Text} node Mutated text node.
  * @property {String} oldText Old text.
  * @property {String} newText New text.
  */
@@ -203,13 +209,13 @@ export default class MutationObserver extends Observer {
 /**
  * Mutation item for child nodes.
  *
- * @see treeView.TreeView#mutations
- * @see treeView.MutatatedText
+ * @see core.treeView.TreeView#mutations
+ * @see core.treeView.MutatatedText
  *
- * @typedef {Object} treeView.MutatatedChildren
+ * @typedef {Object} core.treeView.MutatatedChildren
  *
  * @property {String} type For child nodes mutations it is always 'children'.
- * @property {treeView.Element} node Parent of the mutated children.
- * @property {Array.<treeView.Node>} oldChildren Old child nodes.
- * @property {Array.<treeView.Node>} newChildren New child nodes.
+ * @property {core.treeView.Element} node Parent of the mutated children.
+ * @property {Array.<core.treeView.Node>} oldChildren Old child nodes.
+ * @property {Array.<core.treeView.Node>} newChildren New child nodes.
  */

+ 12 - 13
packages/ckeditor5-engine/src/treeview/observer/observer.js

@@ -7,36 +7,35 @@
 
 /**
  * Abstract base observer class. Observers are classes which observe changes on DOM elements, do the preliminary
- * processing and fire events on the {@link treeView.TreeView} objects.
- *
+ * processing and fire events on the {@link core.treeView.TreeView} objects.
  * @abstract
- * @class treeView.observer.Observer
+ * @memberOf core.treeView.observer
  */
 export default class Observer {
 	/**
-	 * Inits the observer class, caches all needed {@link treeView.TreeView} properties, create objects.
-	 * This method do not {@link treeView.observer.Observer#attach attach} listeners to the DOM.
+	 * Inits the observer class, caches all needed {@link core.treeView.TreeView} properties, create objects.
+	 * This method do not {@link core.treeView.observer.Observer#attach attach} listeners to the DOM.
 	 *
-	 * @method init
-	 * @param {treeView.TreeView}
+	 * @method core.treeView.observer.Observer#init
+	 * @param {core.treeView.TreeView}
 	 */
 
 	/**
 	 * Attaches observers and listeners to DOM elements. This method is called when then observer is added to the
-	 * {@link treeView.TreeView} and after {@link treeView.TreeView#render rendering} to reattach observers and listeners.
+	 * {@link core.treeView.TreeView} and after {@link core.treeView.TreeView#render rendering} to reattach observers and listeners.
 	 *
-	 * @see treeView.observer.Observer#detach
+	 * @see core.treeView.observer.Observer#detach
 	 *
-	 * @method attach
+	 * @method core.treeView.observer.Observer#attach
 	 */
 
 	/**
 	 * Detaches observers and listeners from the DOM elements. This method is called before
-	 * {@link treeView.TreeView#render rendering} to prevent firing events during rendering and when the editor is
+	 * {@link core.treeView.TreeView#render rendering} to prevent firing events during rendering and when the editor is
 	 * destroyed.
 	 *
-	 * @see treeView.observer.Observer#attach
+	 * @see core.treeView.observer.Observer#attach
 	 *
-	 * @method detach
+	 * @method core.treeView.observer.Observer#detach
 	 */
 }

+ 8 - 8
packages/ckeditor5-engine/src/treeview/position.js

@@ -5,31 +5,31 @@
 
 'use strict';
 
-/**
- * Position in the tree. Position is always located before or after a node.
+/**Position in the tree. Position is always located before or after a node.
  *
- * @class treeView.Position
+ * @memberOf core.treeView
  */
- export default class Position {
+export default class Position {
 	/**
 	 * Creates a position.
 	 *
-	 * @param {treeView.Element} parent Position parent element.
+	 * @param {core.treeView.Element} parent Position parent element.
 	 * @param {Number} offset Position offset.
-	 * @constructor
 	 */
 	constructor( parent, offset ) {
 		/**
 		 * Position parent element.
 		 *
-		 * @property {treeView.Element}
+		 * @member core.treeView.Position#parent
+		 * @type {core.treeView.Element}
 		 */
 		this.parent = parent;
 
 		/**
 		 * Position offset.
 		 *
-		 * @property {Number}
+		 * @member core.treeView.Position#offset
+		 * @type {Number}
 		 */
 		this.offset = offset;
 	}

+ 18 - 19
packages/ckeditor5-engine/src/treeview/renderer.js

@@ -10,26 +10,25 @@ import CKEditorError from '../ckeditorerror.js';
 
 /**
  * Renderer updates DOM tree, to make it a reflection of the view tree. Changed nodes need to be
- * {@link treeView.Renderer#markToSync marked} to be rendered. Then, on {@link treeView.Renderer#render}, renderer
+ * {@link core.treeView.Renderer#markToSync marked} to be rendered. Then, on {@link core.treeView.Renderer#render render}, renderer
  * ensure they need to be refreshed and creates DOM nodes from view nodes,
- * {@link treeView.Converter#bindElements bind} them and insert into DOM tree. Renderer use {@link treeView.Converter}
+ * {@link core.treeView.Converter#bindElements bind} them and insert into DOM tree. Renderer use {@link core.treeView.Converter}
  * to transform and bind nodes.
  *
- * @class treeView.Renderer
+ * @memberOf core.treeView
  */
 export default class Renderer {
 	/**
 	 * Creates a renderer instance.
 	 *
-	 * @param {treeView.Converter} converter Converter instance.
-	 * @constructor
+	 * @param {core.treeView.Converter} converter Converter instance.
 	 */
 	constructor( converter ) {
 		/**
 		 * Converter instance.
 		 *
 		 * @readonly
-		 * @property {treeView.Converter}
+		 * @member {core.treeView.Converter} core.treeView.Renderer#converter
 		 */
 		this.converter = converter;
 
@@ -37,7 +36,7 @@ export default class Renderer {
 		 * Set of nodes which attributes changed and may need to be rendered.
 		 *
 		 * @readonly
-		 * @property {Set.<treeView.Node>}
+		 * @member {Set.<core.treeView.Node>} core.treeView.Renderer#markedAttributes
 		 */
 		this.markedAttributes = new Set();
 
@@ -45,7 +44,7 @@ export default class Renderer {
 		 * Set of elements which child lists changed and may need to be rendered.
 		 *
 		 * @readonly
-		 * @property {Set.<treeView.Node>}
+		 * @member {Set.<core.treeView.Node>} core.treeView.Renderer#markedChildren
 		 */
 		this.markedChildren = new Set();
 
@@ -53,7 +52,7 @@ export default class Renderer {
 		 * Set of text nodes which text data changed and may need to be rendered.
 		 *
 		 * @readonly
-		 * @property {Set.<treeView.Node>}
+		 * @member {Set.<core.treeView.Node>} core.treeView.Renderer#markedTexts
 		 */
 		this.markedTexts = new Set();
 	}
@@ -63,12 +62,12 @@ export default class Renderer {
 	 *
 	 * Note that only view nodes which parents have corresponding DOM elements need to be marked to be synchronized.
 	 *
-	 * @see treeView.Renderer#markedAttributes
-	 * @see treeView.Renderer#markedChildren
-	 * @see treeView.Renderer#markedTexts
+	 * @see core.treeView.Renderer#markedAttributes
+	 * @see core.treeView.Renderer#markedChildren
+	 * @see core.treeView.Renderer#markedTexts
 	 *
-	 * @param {treeView.ChangeType} type Type of the change.
-	 * @param {treeView.Node} node Node to be marked.
+	 * @param {core.treeView.ChangeType} type Type of the change.
+	 * @param {core.treeView.Node} node Node to be marked.
 	 */
 	markToSync( type, node ) {
 		if ( type === 'TEXT' ) {
@@ -98,8 +97,8 @@ export default class Renderer {
 	}
 
 	/**
-	 * Render method check {@link treeView.Renderer#markedAttributes}, {@link treeView.Renderer#markedChildren} and
-	 * {@link treeView.Renderer#markedTexts} and updated all nodes which needs to be updated. Then it clear all three
+	 * Render method check {@link core.treeView.Renderer#markedAttributes}, {@link core.treeView.Renderer#markedChildren} and
+	 * {@link core.treeView.Renderer#markedTexts} and updated all nodes which needs to be updated. Then it clear all three
 	 * sets.
 	 *
 	 * Renderer try not to bread IME, so it do as little as it is possible to update DOM.
@@ -109,10 +108,10 @@ export default class Renderer {
 	 *
 	 * For text nodes it update the text string if it is different. Note that if parent element is marked as an element
 	 * which changed child list, text node update will not be done, because it may not be possible do find a
-	 * {@link @treeView.Converter#getCorrespondingDomText corresponding DOM text}. The change will be handled in the
+	 * {@link core.treeView.Converter#getCorrespondingDomText corresponding DOM text}. The change will be handled in the
 	 * parent element.
 	 *
-	 * For nodes which changed child list it calculates a {@link diff} using {@link @treeView.Converter#compareNodes}
+	 * For nodes which changed child list it calculates a {@link diff} using {@link core.treeView.Converter#compareNodes}
 	 * and add or removed nodes which changed.
 	 */
 	render() {
@@ -176,7 +175,7 @@ export default class Renderer {
 			for ( let action of actions ) {
 				if ( action === 'INSERT' ) {
 					let domChildToInsert = converter.viewToDom( viewChildren[ i ], domDocument, { bind: true } );
-					domElement.insertBefore( domChildToInsert, domChildren[ i ] || null  );
+					domElement.insertBefore( domChildToInsert, domChildren[ i ] || null );
 					i++;
 				} else if ( action === 'DELETE' ) {
 					domElement.removeChild( domChildren[ i ] );

+ 5 - 10
packages/ckeditor5-engine/src/treeview/text.js

@@ -10,14 +10,14 @@ import Node from './node.js';
 /**
  * Tree view text node.
  *
- * @class treeView.Text
+ * @memberOf core.treeView
+ * @extends core.treeView.Node
  */
 export default class Text extends Node {
 	/**
 	 * Creates a tree view text node.
 	 *
 	 * @param {String} data Text.
-	 * @constructor
 	 */
 	constructor( data ) {
 		super();
@@ -25,19 +25,14 @@ export default class Text extends Node {
 		/**
 		 * The text content.
 		 *
+		 * Setting the data fires the {@link core.treeView.Node#event:change change event}.
+		 *
 		 * @private
-		 * @property {String}
+		 * @member {String} core.treeView.Text#_data
 		 */
 		this._data = data;
 	}
 
-	/**
-	 * The text content.
-	 *
-	 * Setting the data fires the {@link treeView.Node#change change event}.
-	 *
-	 * @property {String} Text data.
-	 */
 	get data() {
 		return this._data;
 	}

+ 22 - 20
packages/ckeditor5-engine/src/treeview/treeview.js

@@ -12,14 +12,14 @@ import Converter from './converter.js';
 import utils from '../utils.js';
 
 /**
- * TreeView class combines the actual tree of view elements, tree of DOM elements, {@link treeView.Converter converter},
- * {@link treeView.Renderer renderer} and all {@link treeView.Observer observers}. It creates an abstract layer over the
+ * TreeView class combines the actual tree of view elements, tree of DOM elements, {@link core.treeView.Converter converter},
+ * {@link core.treeView.Renderer renderer} and all {@link core.treeView.Observer observers}. It creates an abstract layer over the
  * content editable area.
  *
- * If you want to only transform the tree of view elements to the DOM elements you can use the {@link treeView.Converter}.
+ * If you want to only transform the tree of view elements to the DOM elements you can use the {@link core.treeView.Converter Converter}.
  *
- * @mixins EmitterMixin
- * @class treeView.TreeView
+ * @memberOf core.treeView
+ * @mixes core.EmitterMixin
  */
 export default class TreeView {
 	/**
@@ -27,47 +27,46 @@ export default class TreeView {
 	 *
 	 * The constructor copies the element name and attributes to create the
 	 * root of the view, but does not copy its children. This means that the while rendering, the whole content of this
-	 * root element will be removed when you call {@link treeView.TreeView#render} but the root name and attributes will
+	 * root element will be removed when you call {@link core.treeView.TreeView#render render} but the root name and attributes will
 	 * be preserved.
 	 *
 	 * @param {HTMLElement} domRoot DOM element in which the tree view should do change.
-	 * @constructor
 	 */
 	constructor( domRoot ) {
 		/**
 		 * Root of the DOM tree.
 		 *
-		 * @property {HTMLElement}
+		 * @member {HTMLElement} core.treeView.TreeView#domRoot
 		 */
 		this.domRoot = domRoot;
 
 		/**
-		 * Set of {@link treeView.Observer observers}.
+		 * Set of {@link core.treeView.Observer observers}.
 		 *
-		 * @property {Set.<treeView.Observer>}
+		 * @member {Set.<core.treeView.Observer>} core.treeView.TreeView#observers
 		 */
 		this.observers = new Set();
 
 		/**
-		 * Instance of the {@link treeView.Converter converter} use by {@link treeView.TreeView#renderer renderer} and
-		 * {@link treeView.TreeView#observers observers}.
+		 * Instance of the {@link core.treeView.Converter converter} use by {@link core.treeView.TreeView#renderer renderer} and
+		 * {@link core.treeView.TreeView#observers observers}.
 		 *
-		 * @property {treeView.Converter}
+		 * @member {core.treeView.Converter} core.treeView.TreeView#converter
 		 */
 		this.converter = new Converter();
 
 		/**
 		 * Root of the view tree.
 		 *
-		 * @property {treeView.Element}
+		 * @member {core.treeView.Element} core.treeView.TreeView#viewRoot
 		 */
 		this.viewRoot = this.converter.domToView( domRoot, { bind: true, withChildren: false } );
 		this.viewRoot.setTreeView( this );
 
 		/**
-		 * Instance of the {@link treeView.TreeView#renderer renderer}.
+		 * Instance of the {@link core.treeView.TreeView#renderer renderer}.
 		 *
-		 * @property {treeView.Renderer}
+		 * @member {core.treeView.Renderer} core.treeView.TreeView#renderer
 		 */
 		this.renderer = new Renderer( this.converter );
 		this.renderer.markToSync( 'CHILDREN', this.viewRoot );
@@ -79,10 +78,11 @@ export default class TreeView {
 	}
 
 	/**
-	 * Adds an observer to the set of observers. This method also {@link treeView.Observer#init initializes} and
-	 * {@link treeView.Observer#attach attaches} the observer.
+	 * Adds an observer to the set of observers. This method also {@link core.treeView.Observer#init initializes} and
+	 * {@link core.treeView.Observer#attach attaches} the observer.
 	 *
-	 * @param {treeView.Observer} observer Observer to add.
+	 * @method core.treeView.TreeView#addObserver
+	 * @param {core.treeView.Observer} observer Observer to add.
 	 */
 	addObserver( observer ) {
 		this.observers.add( observer );
@@ -93,6 +93,8 @@ export default class TreeView {
 	/**
 	 * Renders all changes. In order to avoid triggering the observers (e.g. mutations) all observers all detached
 	 * before rendering and reattached after that.
+	 *
+	 * @method core.treeView.TreeView#render
 	 */
 	render() {
 		for ( let observer of this.observers ) {
@@ -118,5 +120,5 @@ utils.mix( TreeView, EmitterMixin );
  * * `ATTRIBUTES` - for element attributes changes,
  * * `TEXT` - for text nodes changes.
  *
- * @typedef {String} treeView.ChangeType
+ * @typedef {String} core.treeView.ChangeType
  */

+ 8 - 0
packages/ckeditor5-engine/src/ui.jsdoc

@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @namespace core.ui
+ */

+ 9 - 10
packages/ckeditor5-engine/src/ui/controller.js

@@ -13,37 +13,36 @@ import utils from '../utils.js';
 /**
  * Basic Controller class.
  *
- * @class Controller
- * @mixins EmitterMixin
+ * @memberOf core.ui
+ * @mixes core.EmitterMixin
  */
 
 export default class Controller {
 	/**
-	 * Creates an instance of the {@link Controller} class.
+	 * Creates an instance of the {@link core.ui.Controller} class.
 	 *
-	 * @param {Model} [model] Model of this Controller.
-	 * @param {View} [view] View instance of this Controller.
-	 * @constructor
+	 * @param {core.ui.Model} [model] Model of this Controller.
+	 * @param {core.ui.View} [view] View instance of this Controller.
 	 */
 	constructor( model, view ) {
 		/**
 		 * Model of this controller.
 		 *
-		 * @property {Model}
+		 * @member {core.ui.Model} core.ui.Controller#model
 		 */
 		this.model = model || null;
 
 		/**
 		 * Set `true` after {@link #init}.
 		 *
-		 * @property {Boolean}
+		 * @member {Boolean} core.ui.Controller#ready
 		 */
 		this.ready = false;
 
 		/**
 		 * View of this controller.
 		 *
-		 * @property {View}
+		 * @member {core.ui.View} core.ui.Controller#view
 		 */
 		this.view = view || null;
 
@@ -51,7 +50,7 @@ export default class Controller {
 		 * A collection of {@link ControllerCollection} instances containing
 		 * child controllers.
 		 *
-		 * @property {Collection}
+		 * @member {core.Collection} core.ui.Controller#collections
 		 */
 		this.collections = new Collection( {
 			idProperty: 'name'

+ 3 - 5
packages/ckeditor5-engine/src/ui/controllercollection.js

@@ -17,8 +17,6 @@ import CKEditorError from '../ckeditorerror.js';
 export default class ControllerCollection extends Collection {
 	/**
 	 * Creates an instance of the ControllerCollection class, initializing it with a name.
-	 *
-	 * @constructor
 	 */
 	constructor( name ) {
 		super();
@@ -35,14 +33,14 @@ export default class ControllerCollection extends Collection {
 		/**
 		 * Name of this collection.
 		 *
-		 * @property {String}
+		 * @type {String}
 		 */
 		this.name = name;
 
 		/**
 		 * Parent controller of this collection.
 		 *
-		 * @property {Controller}
+		 * @type {core.ui.Controller}
 		 */
 		this.parent = null;
 	}
@@ -51,7 +49,7 @@ export default class ControllerCollection extends Collection {
 	 * Adds a child controller to the collection. If {@link #parent} {@link Controller}
 	 * instance is ready, the child view is initialized when added.
 	 *
-	 * @param {Controller} controller A child controller.
+	 * @param {core.ui.Controller} controller A child controller.
 	 * @param {Number} [index] Index at which the child will be added to the collection.
 	 * @returns {Promise} A Promise resolved when the child {@link Controller#init} is done.
 	 */

+ 40 - 32
packages/ckeditor5-engine/src/ui/domemittermixin.js

@@ -14,11 +14,10 @@ import log from '../log.js';
  * Creates a ProxyEmitter instance. Such an instance is a bridge between a DOM Node firing events
  * and any Host listening to them. It is backwards compatible with {@link EmitterMixin#on}.
  *
- * @class DOMEmitterMixin
- * @mixins EmitterMixin
- * @implements DOMEmitter
+ * @memberOf core.ui
+ * @mixes core.EmitterMixin
+ * @implements core.ui.DOMEmitter
  */
-
 class ProxyEmitter {
 	/**
 	 * @param {Node} node DOM Node that fires events.
@@ -38,7 +37,7 @@ extend( ProxyEmitter.prototype, EmitterMixin, {
 	 * Collection of native DOM listeners.
 	 *
 	 * @private
-	 * @property {Object} _domListeners
+	 * @member {Object} core.ui.ProxyEmitter#_domListeners
 	 */
 
 	/**
@@ -53,6 +52,8 @@ extend( ProxyEmitter.prototype, EmitterMixin, {
 	 * event.
 	 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
 	 * Lower values are called first.
+	 *
+	 * @method core.ui.ProxyEmitter#on
 	 */
 	on( event ) {
 		// Execute parent class method first.
@@ -85,6 +86,8 @@ extend( ProxyEmitter.prototype, EmitterMixin, {
 	 * @param {Function} callback The function to stop being called.
 	 * @param {Object} [ctx] The context object to be removed, pared with the given callback. To handle cases where
 	 * the same callback is used several times with different contexts.
+	 *
+	 * @method core.ui.ProxyEmitter#off
 	 */
 	off( event ) {
 		// Execute parent class method first.
@@ -106,6 +109,8 @@ extend( ProxyEmitter.prototype, EmitterMixin, {
 	 * Note: A native DOM Event is passed as an argument.
 	 *
 	 * @param {String} event
+	 *
+	 * @method core.ui.ProxyEmitter#_createDomListener
 	 * @returns {Function} The DOM listener callback.
 	 */
 	_createDomListener( event ) {
@@ -129,38 +134,36 @@ extend( ProxyEmitter.prototype, EmitterMixin, {
  * Mixin that injects the DOM events API into its host. It provides the API
  * compatible with {@link EmitterMixin}.
  *
- *                               listenTo( click, ... )
- *                 +-----------------------------------------+
- *                 |              stopListening( ... )       |
- *  +----------------------------+                           |             addEventListener( click, ... )
- *  | Host                       |                           |   +---------------------------------------------+
- *  +----------------------------+                           |   |       removeEventListener( click, ... )     |
- *  | _listeningTo: {            |                +----------v-------------+                                   |
- *  |   UID: {                   |                | ProxyEmitter           |                                   |
- *  |     emitter: ProxyEmitter, |                +------------------------+                      +------------v----------+
- *  |     callbacks: {           |                | events: {              |                      | Node (HTMLElement)    |
- *  |       click: [ callbacks ] |                |   click: [ callbacks ] |                      +-----------------------+
- *  |     }                      |                | },                     |                      | data-cke-expando: UID |
- *  |   }                        |                | _domNode: Node,        |                      +-----------------------+
- *  | }                          |                | _domListeners: {},     |                                   |
- *  | +------------------------+ |                | _emitterId: UID        |                                   |
- *  | | DOMEmitterMixin        | |                +--------------^---------+                                   |
- *  | +------------------------+ |                           |   |                                             |
- *  +--------------^-------------+                           |   +---------------------------------------------+
- *                 |                                         |                  click (DOM Event)
- *                 +-----------------------------------------+
- *                             fire( click, DOM Event )
+ *                                  listenTo( click, ... )
+ *                    +-----------------------------------------+
+ *                    |              stopListening( ... )       |
+ *     +----------------------------+                           |             addEventListener( click, ... )
+ *     | Host                       |                           |   +---------------------------------------------+
+ *     +----------------------------+                           |   |       removeEventListener( click, ... )     |
+ *     | _listeningTo: {            |                +----------v-------------+                                   |
+ *     |   UID: {                   |                | ProxyEmitter           |                                   |
+ *     |     emitter: ProxyEmitter, |                +------------------------+                      +------------v----------+
+ *     |     callbacks: {           |                | events: {              |                      | Node (HTMLElement)    |
+ *     |       click: [ callbacks ] |                |   click: [ callbacks ] |                      +-----------------------+
+ *     |     }                      |                | },                     |                      | data-cke-expando: UID |
+ *     |   }                        |                | _domNode: Node,        |                      +-----------------------+
+ *     | }                          |                | _domListeners: {},     |                                   |
+ *     | +------------------------+ |                | _emitterId: UID        |                                   |
+ *     | | DOMEmitterMixin        | |                +--------------^---------+                                   |
+ *     | +------------------------+ |                           |   |                                             |
+ *     +--------------^-------------+                           |   +---------------------------------------------+
+ *                    |                                         |                  click (DOM Event)
+ *                    +-----------------------------------------+
+ *                                fire( click, DOM Event )
  *
- * @singleton
- * @class DOMEmitterMixin
- * @mixins EmitterMixin
- * @implements DOMEmitter
+ * @mixin core.ui.DOMEmitterMixin
+ * @mixes core.EmitterMixin
+ * @implements core.ui.DOMEmitter
  */
-
 const DOMEmitterMixin = extend( {}, EmitterMixin, {
 	/**
 	 * Registers a callback function to be executed when an event is fired in a specific Emitter or DOM Node.
-	 * It is backwards compatible with {@link EmitterMixin#listenTo}.
+	 * It is backwards compatible with {@link core.EmitterMixin#listenTo}.
 	 *
 	 * @param {Emitter|Node} emitter The object that fires the event.
 	 * @param {String} event The name of the event.
@@ -168,6 +171,8 @@ const DOMEmitterMixin = extend( {}, EmitterMixin, {
 	 * @param {Object} [ctx] The object that represents `this` in the callback. Defaults to `emitter`.
 	 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
 	 * Lower values are called first.
+	 *
+	 * @method core.ui.DOMEmitterMixin#listenTo
 	 */
 	listenTo() {
 		const args = Array.prototype.slice.call( arguments );
@@ -197,6 +202,8 @@ const DOMEmitterMixin = extend( {}, EmitterMixin, {
 	 * for all events from `emitter`.
 	 * @param {Function} [callback] (Requires the `event`) The function to be removed from the call list for the given
 	 * `event`.
+	 *
+	 * @method core.ui.DOMEmitterMixin#stopListening
 	 */
 	stopListening() {
 		const args = Array.prototype.slice.call( arguments );
@@ -224,6 +231,7 @@ const DOMEmitterMixin = extend( {}, EmitterMixin, {
 	 * Retrieves ProxyEmitter instance for given DOM Node residing in this Host.
 	 *
 	 * @param {Node} node DOM Node of the ProxyEmitter.
+	 * @method core.ui.DOMEmitterMixin#_getProxyEmitter
 	 * @return {ProxyEmitter} ProxyEmitter instance or null.
 	 */
 	_getProxyEmitter( node ) {

+ 2 - 4
packages/ckeditor5-engine/src/ui/model.js

@@ -12,17 +12,15 @@ import ObservableMixin from '../observablemixin.js';
 /**
  * The base MVC model class.
  *
- * @class core.ui.Model
- * @mixins core.ObservableMixin
+ * @memberOf core.ui
+ * @mixes core.ObservableMixin
  */
-
 export default class Model {
 	/**
 	 * Creates a new Model instance.
 	 *
 	 * @param {Object} [attributes] The model state attributes to be defined during the instance creation.
 	 * @param {Object} [properties] The (out of state) properties to be appended to the instance during creation.
-	 * @method constructor
 	 */
 	constructor( attributes, properties ) {
 		// Extend this instance with the additional (out of state) properties.

+ 4 - 7
packages/ckeditor5-engine/src/ui/region.js

@@ -10,36 +10,33 @@ import Collection from '../collection.js';
 /**
  * Basic Region class.
  *
- * @class Region
- * @extends Model
+ * @memberOf core.ui
  */
-
 export default class Region {
 	/**
 	 * Creates an instance of the {@link Region} class.
 	 *
 	 * @param {String} name The name of the Region.
-	 * @constructor
 	 */
 	constructor( name ) {
 		/**
 		 * The name of the region.
 		 *
-		 * @property {String}
+		 * @member {String} core.ui.Region#name
 		 */
 		this.name = name;
 
 		/**
 		 * Views which belong to the region.
 		 *
-		 * @property {Collection}
+		 * @member {Collection} core.ui.Region#views
 		 */
 		this.views = new Collection();
 
 		/**
 		 * Element of this region (see {@link #init}).
 		 *
-		 * @property {HTMLElement}
+		 * @member {HTMLElement} core.ui.Region#element
 		 */
 		this.element = null;
 	}

+ 122 - 54
packages/ckeditor5-engine/src/ui/template.js

@@ -12,29 +12,27 @@ import CKEditorError from '../ckeditorerror.js';
 /**
  * Basic Template class.
  *
- * @class Template
+ * @memberOf core.ui
  */
-
 export default class Template {
 	/**
 	 * Creates an instance of the {@link Template} class.
 	 *
-	 * @param {TemplateDefinition} definition The definition of the template.
-	 * @constructor
+	 * @param {core.ui.TemplateDefinition} def The definition of the template.
 	 */
 	constructor( def ) {
 		/**
 		 * Definition of this template.
 		 *
-		 * @property {TemplateDefinition}
+		 * @type {core.ui.TemplateDefinition}
 		 */
 		this.definition = def;
 	}
 
 	/**
-	 * Renders DOM Node using {@link #definition}.
+	 * Renders DOM Node using {@link core.ui.Template#definition}.
 	 *
-	 * See: {@link #apply}.
+	 * @see core.ui.Template#apply
 	 *
 	 * @returns {HTMLElement}
 	 */
@@ -43,11 +41,12 @@ export default class Template {
 	}
 
 	/**
-	 * Applies template {@link #def} to existing DOM tree.
+	 * Applies template {@link core.ui.Template#def} to existing DOM tree.
 	 *
 	 * **Note:** No new DOM nodes (elements, text nodes) will be created.
 	 *
-	 * See: {@link #render}, {@link View#applyTemplateToElement}.
+	 * @see core.ui.Template#render
+	 * @see View#applyTemplateToElement.
 	 *
 	 * @param {Node} element Root element for template to apply.
 	 */
@@ -68,7 +67,7 @@ export default class Template {
 	 * Renders a DOM Node from definition.
 	 *
 	 * @protected
-	 * @param {TemplateDefinition} def Definition of a Node.
+	 * @param {core.ui.TemplateDefinition} def Definition of a Node.
 	 * @param {Node} applyNode If specified, template `def` will be applied to existing DOM Node.
 	 * @param {Boolean} intoFragment If set, children are rendered into DocumentFragment.
 	 * @returns {HTMLElement} A rendered Node.
@@ -103,7 +102,7 @@ export default class Template {
 	 * Renders an HTMLElement from TemplateDefinition.
 	 *
 	 * @protected
-	 * @param {TemplateDefinition} def Definition of an element.
+	 * @param {core.ui.TemplateDefinition} def Definition of an element.
 	 * @param {HTMLElement} applyElement If specified, template `def` will be applied to existing HTMLElement.
 	 * @param {Boolean} intoFragment If set, children are rendered into DocumentFragment.
 	 * @returns {HTMLElement} A rendered element.
@@ -139,57 +138,80 @@ export default class Template {
 	 * @returns {Text} A rendered Text.
 	 */
 	_renderText( defOrText, applyText ) {
-		const text = applyText || document.createTextNode( '' );
+		const textNode = applyText || document.createTextNode( '' );
+
+		// Check if there's a binder available for this Text Node.
+		const binder = defOrText._modelBinders && defOrText._modelBinders.text;
 
-		// Case: { text: func }, like binding
-		if ( typeof defOrText.text == 'function' ) {
-			defOrText.text( text, getTextUpdater() );
+		// Activate binder if one. Cases:
+		//		{ text: bind.to( ... ) }
+		//		{ text: [ 'foo', bind.to( ... ), ... ] }
+		if ( binder ) {
+			binder( textNode, getTextNodeUpdater( textNode ) );
 		}
-		// Case: { text: 'foo' }
-		// Case: 'foo'
+
+		// Simply set text. Cases:
+		// 		{ text: [ 'all', 'are', 'static' ] }
+		// 		{ text: 'foo' }
+		// 		'foo'
 		else {
-			text.textContent = defOrText.text || defOrText;
+			textNode.textContent = defOrText.text || defOrText;
 		}
 
-		return text;
+		return textNode;
 	}
 
 	/**
 	 * Renders element attributes from definition.
 	 *
 	 * @protected
-	 * @param {TemplateDefinition} def Definition of an element.
+	 * @param {core.ui.TemplateDefinition} def Definition of an element.
 	 * @param {HTMLElement} el Element which is rendered.
 	 */
 	_renderElementAttributes( def, el ) {
-		let attr, value;
+		const attributes = def.attributes;
+		const binders = def._modelBinders && def._modelBinders.attributes;
+		let binder, attrName, attrValue;
+
+		if ( !attributes ) {
+			return;
+		}
 
-		for ( attr in def.attributes ) {
-			value = def.attributes[ attr ];
+		for ( attrName in attributes ) {
+			// Check if there's a binder available for this attribute.
+			binder = binders && binders[ attrName ];
 
-			// Attribute bound directly to the model.
-			if ( typeof value == 'function' ) {
-				value( el, getAttributeUpdater( attr ) );
+			// Activate binder if one. Cases:
+			// 		{ class: [ 'bar', bind.to( ... ), 'baz' ] }
+			// 		{ class: bind.to( ... ) }
+			if ( binder ) {
+				binder( el, getElementAttributeUpdater( el, attrName ) );
 			}
 
-			// Explicit attribute definition (string).
+			// Otherwise simply set the attribute.
+			// 		{ class: [ 'all', 'are', 'static' ] }
+			// 		{ class: 'foo' }
 			else {
-				// Attribute can be an array, i.e. classes.
-				if ( Array.isArray( value ) ) {
-					value = value.join( ' ' );
+				attrValue = attributes[ attrName ];
+
+				// Attribute can be an array. Merge array elements:
+				if ( Array.isArray( attrValue ) ) {
+					attrValue = attrValue.reduce( function binderValueReducer( prev, cur ) {
+						return prev === '' ? `${cur}` : `${prev} ${cur}`;
+					} );
 				}
 
-				el.setAttribute( attr, value );
+				el.setAttribute( attrName, attrValue );
 			}
 		}
 	}
 
 	/**
 	 * Recursively renders element children from definition by
-	 * calling {@link #_renderElement}.
+	 * calling {@link core.ui.Template#_renderElement}.
 	 *
 	 * @protected
-	 * @param {TemplateDefinition} def Definition of an element.
+	 * @param {core.ui.TemplateDefinition} def Definition of an element.
 	 * @param {HTMLElement} el Element which is rendered.
 	 * @param {Boolean} isApply Traverse existing DOM structure only, don't modify DOM.
 	 */
@@ -209,7 +231,7 @@ export default class Template {
 	 * Activates element `on` listeners passed in element definition.
 	 *
 	 * @protected
-	 * @param {TemplateDefinition} def Definition of an element.
+	 * @param {core.ui.TemplateDefinition} def Definition of an element.
 	 * @param {HTMLElement} el Element which is rendered.
 	 */
 	_activateElementListenerAttachers( def, el ) {
@@ -237,30 +259,53 @@ export default class Template {
 }
 
 /**
- * Returns a function which, when called in the context of HTMLElement,
- * it replaces element children with a text node of given value.
+ * Returns an object consisting of `set` and `remove` functions, which
+ * can be used in the context of DOM Node to set or reset `textContent`.
+ * @see core.ui.View#_getModelBinder
  *
+ * @ignore
  * @private
- * @param {Function}
+ * @param {Node} node DOM Node to be modified.
+ * @returns {Object}
  */
-function getTextUpdater() {
-	return ( el, value ) => el.textContent = value;
+function getTextNodeUpdater( node ) {
+	return {
+		set( value ) {
+			node.textContent = value;
+		},
+
+		remove() {
+			node.textContent = '';
+		}
+	};
 }
 
 /**
- * Returns a function which, when called in the context of HTMLElement,
- * it updates element's attribute with given value.
+ * Returns an object consisting of `set` and `remove` functions, which
+ * can be used in the context of DOM Node to set or reset an attribute.
+ * @see core.ui.View#_getModelBinder
  *
+ * @ignore
  * @private
- * @param {String} attr A name of the attribute to be updated.
- * @param {Function}
+ * @param {Node} node DOM Node to be modified.
+ * @param {String} attrName Name of the attribute to be modified.
+ * @returns {Object}
  */
-function getAttributeUpdater( attr ) {
-	return ( el, value ) => el.setAttribute( attr, value );
+function getElementAttributeUpdater( el, attrName ) {
+	return {
+		set( value ) {
+			el.setAttribute( attrName, value );
+		},
+
+		remove() {
+			el.removeAttribute( attrName );
+		}
+	};
 }
 
 /**
  * Definition of {@link Template}.
+ * See: {@link core.ui.TemplateValueSchema}.
  *
  *		{
  *			tag: 'p',
@@ -272,31 +317,54 @@ function getAttributeUpdater( attr ) {
  *					...
  *				},
  *				{
- *					text: 'abc'
+ *					text: 'static–text'
  *				},
- *				'def',
+ *				'also-static–text',
  *				...
  *			],
  *			attributes: {
- *				'class': [ 'a', 'b' ],
- *				id: 'c',
+ *				'class': [ 'class-a', 'class-b' ],
+ *				id: 'element-id',
  *				style: callback,
  *				...
  *			},
  *			on: {
- *				event1: 'a'
- *				event2: [ 'b', 'c', callback ],
- *				'event3@selector': 'd',
- *				'event4@selector': [ 'e', 'f', callback ],
+ *				'click': 'clicked'
+ *				'mouseup': [ 'view-event-a', 'view-event-b', callback ],
+ *				'keyup@selector': 'view-event',
+ *				'focus@selector': [ 'view-event-a', 'view-event-b', callback ],
  *				...
  *			}
  *		}
  *
- * @typedef TemplateDefinition
+ * @typedef core.ui.TemplateDefinition
  * @type Object
  * @property {String} tag
  * @property {Array} [children]
  * @property {Object} [attributes]
  * @property {String} [text]
  * @property {Object} [on]
+ * @property {Object} _modelBinders
+ */
+
+/**
+ * Describes a value of HTMLElement attribute or `textContent`.
+ * See: {@link core.ui.TemplateDefinition}.
+ *
+ *		{
+ *			tag: 'p',
+ *			attributes: {
+ *				// Plain String schema.
+ *				class: 'class-foo'
+ *
+ *				// Object schema, a Model binding.
+ *				class: { model: m, attribute: 'foo', callback... }
+ *
+ *				// Array schema, combines the above.
+ *				class: [ 'foo', { model: m, attribute: 'bar' }, 'baz' ]
+ *			}
+ *		}
+ *
+ * @typedef core.ui.TemplateValueSchema
+ * @type {Object|String|Array}
  */

+ 326 - 73
packages/ckeditor5-engine/src/ui/view.js

@@ -11,33 +11,35 @@ import Template from './template.js';
 import CKEditorError from '../ckeditorerror.js';
 import DOMEmitterMixin from './domemittermixin.js';
 import utils from '../utils.js';
+import isPlainObject from '../lib/lodash/isPlainObject.js';
+
+const bindToSymbol = Symbol( 'bind-to' );
+const bindIfSymbol = Symbol( 'bind-if' );
 
 /**
  * Basic View class.
  *
- * @class View
- * @mixins DOMEmitterMixin
+ * @memberOf core.ui
+ * @mixes DOMEmitterMixin
  */
-
 export default class View {
 	/**
 	 * Creates an instance of the {@link View} class.
 	 *
-	 * @param {Model} model (View)Model of this View.
-	 * @constructor
+	 * @param {core.ui.Model} model (View)Model of this View.
 	 */
 	constructor( model ) {
 		/**
 		 * Model of this view.
 		 *
-		 * @property {Model}
+		 * @type {core.ui.Model}
 		 */
 		this.model = model || null;
 
 		/**
-		 * Regions of this view. See {@link #register}.
+		 * Regions of this view. See {@link core.ui.View#register}.
 		 *
-		 * @property {Collection}
+		 * @type {Collection}
 		 */
 		this.regions = new Collection( {
 			idProperty: 'name'
@@ -46,15 +48,15 @@ export default class View {
 		/**
 		 * Template of this view.
 		 *
-		 * @property {Object}
+		 * @type {Object}
 		 */
 		this.template = null;
 
 		/**
-		 * Region selectors of this view. See {@link #register}.
+		 * Region selectors of this view. See {@link core.ui.View#register}.
 		 *
 		 * @private
-		 * @property {Object}
+		 * @type {Object}
 		 */
 		this._regionsSelectors = {};
 
@@ -62,24 +64,22 @@ export default class View {
 		 * Element of this view.
 		 *
 		 * @private
-		 * @property {HTMLElement}
+		 * @type {HTMLElement}
 		 */
 		this._element = null;
 
 		/**
-		 * An instance of Template to generate {@link #_el}.
+		 * An instance of Template to generate {@link core.ui.View#_el}.
 		 *
 		 * @private
-		 * @property {Template}
+		 * @type {Template}
 		 */
 		this._template = null;
 	}
 
 	/**
 	 * Element of this view. The element is rendered on first reference
-	 * using {@link #template} definition and {@link #_template} object.
-	 *
-	 * @property element
+	 * using {@link core.ui.View#template} definition and {@link core.ui.View#_template} object.
 	 */
 	get element() {
 		if ( this._element ) {
@@ -97,7 +97,10 @@ export default class View {
 		}
 
 		// Prepare pre–defined listeners.
-		this._createTemplateListenerAttachers( this.template );
+		this._extendTemplateWithListenerAttachers( this.template );
+
+		// Prepare pre–defined attribute bindings.
+		this._extendTemplateWithModelBinders( this.template );
 
 		this._template = new Template( this.template );
 
@@ -108,6 +111,92 @@ export default class View {
 		this._element = el;
 	}
 
+	/**
+	 * And entry point to the interface which allows binding attributes of {@link View#model}
+	 * to the DOM items like HTMLElement attributes or Text Node `textContent`, so their state
+	 * is synchronized with {@link View#model}.
+	 *
+	 * @readonly
+	 */
+	get attributeBinder() {
+		if ( this._attributeBinder ) {
+			return this._attributeBinder;
+		}
+
+		const model = this.model;
+		const binder = {
+			/**
+			 * Binds {@link View#model} to HTMLElement attribute or Text Node `textContent`
+			 * so remains in sync with the Model when it changes.
+			 *
+			 *		this.template = {
+			 *			tag: 'p',
+			 *			attributes: {
+			 *				// class="..." attribute gets bound to this.model.a
+			 *				'class': bind.to( 'a' )
+			 *			},
+			 *			children: [
+			 *				// <p>...</p> gets bound to this.model.b; always `toUpperCase()`.
+			 *				{ text: bind.to( 'b', ( value, node ) => value.toUpperCase() ) }
+			 *			]
+			 *		}
+			 *
+			 * @property {attributeBinder.to}
+			 * @param {String} attribute Name of {@link View#model} used in the binding.
+			 * @param {Function} [callback] Allows processing of the value. Accepts `Node` and `value` as arguments.
+			 * @return {core.ui.ViewModelBinding}
+			 */
+			to( attribute, callback ) {
+				return {
+					type: bindToSymbol,
+					model: model,
+					attribute,
+					callback
+				};
+			},
+
+			/**
+			 * Binds {@link View#model} to HTMLElement attribute or Text Node `textContent`
+			 * so remains in sync with the Model when it changes. Unlike {@link View#attributeBinder.to},
+			 * it controls the presence of the attribute/`textContent` depending on the "falseness" of
+			 * {@link View#model} attribute.
+			 *
+			 *		this.template = {
+			 *			tag: 'input',
+			 *			attributes: {
+			 *				// <input checked> this.model.a is not undefined/null/false/''
+			 *				// <input> this.model.a is undefined/null/false
+			 *				checked: bind.if( 'a' )
+			 *			},
+			 *			children: [
+			 *				{
+			 *					// <input>"b-is-not-set"</input> when this.model.b is undefined/null/false/''
+			 *					// <input></input> when this.model.b is not "falsy"
+			 *					text: bind.if( 'b', 'b-is-not-set', ( value, node ) => !value )
+			 *				}
+			 *			]
+			 *		}
+			 *
+			 * @property {attributeBinder.if}
+			 * @param {String} attribute Name of {@link View#model} used in the binding.
+			 * @param {String} [valueIfTrue] Value set when {@link View#model} attribute is not undefined/null/false/''.
+			 * @param {Function} [callback] Allows processing of the value. Accepts `Node` and `value` as arguments.
+			 * @return {core.ui.ViewModelBinding}
+			 */
+			if( attribute, valueIfTrue, callback ) {
+				return {
+					type: bindIfSymbol,
+					model: model,
+					attribute,
+					valueIfTrue,
+					callback
+				};
+			}
+		};
+
+		return ( this._attributeBinder = binder );
+	}
+
 	/**
 	 * Initializes the view.
 	 */
@@ -116,7 +205,7 @@ export default class View {
 	}
 
 	/**
-	 * Registers a region in {@link #regions}.
+	 * Registers a region in {@link core.ui.View#regions}.
 	 *
 	 *		let view = new View();
 	 *
@@ -135,7 +224,7 @@ export default class View {
 	 * @param {String|Region} stringOrRegion The name or an instance of the Region
 	 * to be registered. If `String`, the region will be created on the fly.
 	 * @param {String|Function|true} regionSelector The selector to retrieve region's element
-	 * in DOM when the region instance is initialized (see {@link Region#init}, {@link #init}).
+	 * in DOM when the region instance is initialized (see {@link Region#init}, {@link core.ui.View#init}).
 	 * @param {Boolean} [override] When set `true` it will allow overriding of registered regions.
 	 */
 	register( ...args ) {
@@ -190,50 +279,6 @@ export default class View {
 		this._regionsSelectors[ regionName ] = regionSelector;
 	}
 
-	/**
-	 * Binds an `attribute` of View's model so the DOM of the View is updated when the `attribute`
-	 * changes. It returns a function which, once called in the context of a DOM element,
-	 * attaches a listener to the model which, in turn, brings changes to DOM.
-	 *
-	 * @param {String} attribute Attribute name in the model to be observed.
-	 * @param {Function} [callback] Callback function executed on attribute change in model.
-	 * If not specified, a default DOM `domUpdater` supplied by the template is used.
-	 */
-	bindToAttribute( attribute, callback ) {
-		/**
-		 * Attaches a listener to View's model, which updates DOM when the model's attribute
-		 * changes. DOM is either updated by the `domUpdater` function supplied by the template
-		 * (like attribute changer or `innerHTML` setter) or custom `callback` passed to {@link #bind}.
-		 *
-		 * This function is called by {@link Template#render}.
-		 *
-		 * @param {HTMLElement} el DOM element to be updated when `attribute` in model changes.
-		 * @param {Function} domUpdater A function provided by the template which updates corresponding
-		 * DOM.
-		 */
-		return ( el, domUpdater ) => {
-			let onModelChange;
-
-			if ( callback ) {
-				onModelChange = ( evt, value ) => {
-					let processedValue = callback( el, value );
-
-					if ( typeof processedValue != 'undefined' ) {
-						domUpdater( el, processedValue );
-					}
-				};
-			} else {
-				onModelChange = ( evt, value ) => domUpdater( el, value );
-			}
-
-			// Execute callback when the attribute changes.
-			this.listenTo( this.model, 'change:' + attribute, onModelChange );
-
-			// Set the initial state of the view.
-			onModelChange( null, this.model[ attribute ] );
-		};
-	}
-
 	/**
 	 * Applies template to existing DOM element in the context of a View.
 	 *
@@ -258,10 +303,14 @@ export default class View {
 	 * See: {@link Template#apply}.
 	 *
 	 * @param {DOMElement} element DOM Element to initialize.
-	 * @param {TemplateDefinition} def Template definition to be applied.
+	 * @param {core.ui.TemplateDefinition} def Template definition to be applied.
 	 */
 	applyTemplateToElement( element, def ) {
-		this._createTemplateListenerAttachers( def );
+		// Prepare pre–defined listeners.
+		this._extendTemplateWithListenerAttachers( def );
+
+		// Prepare pre–defined attribute bindings.
+		this._extendTemplateWithModelBinders( def );
 
 		new Template( def ).apply( element );
 	}
@@ -269,8 +318,8 @@ export default class View {
 	/**
 	 * Destroys the view instance. The process includes:
 	 *
-	 * 1. Removal of child views from {@link #regions}.
-	 * 2. Destruction of the {@link #regions}.
+	 * 1. Removal of child views from {@link core.ui.View#regions}.
+	 * 2. Destruction of the {@link core.ui.View#regions}.
 	 * 3. Removal of {#link #_el} from DOM.
 	 */
 	destroy() {
@@ -294,8 +343,8 @@ export default class View {
 	}
 
 	/**
-	 * Initializes {@link #regions} of this view by passing a DOM element
-	 * generated from {@link #_regionsSelectors} into {@link Region#init}.
+	 * Initializes {@link core.ui.View#regions} of this view by passing a DOM element
+	 * generated from {@link core.ui.View#_regionsSelectors} into {@link Region#init}.
 	 *
 	 * @protected
 	 */
@@ -368,15 +417,153 @@ export default class View {
 		};
 	}
 
+	/**
+	 * For given {@link core.ui.TemplateValueSchema} found by (@link _extendTemplateWithModelBinders} containing
+	 * {@link core.ui.ViewModelBinding} it returns a function, which when called by {@link Template#render}
+	 * or {@link Template#apply} activates the binding and sets its initial value.
+	 *
+	 * Note: {@link core.ui.TemplateValueSchema} can be for HTMLElement attributes or Text Node `textContent`.
+	 *
+	 * @protected
+	 * @param {core.ui.TemplateValueSchema}
+	 * @return {Function}
+	 */
+	_getModelBinder( valueSchema ) {
+		valueSchema = normalizeBinderValueSchema( valueSchema );
+
+		/**
+		 * Assembles the value using {@link core.ui.TemplateValueSchema} and stores it in a form of
+		 * an Array. Each entry of an Array corresponds to one of {@link core.ui.TemplateValueSchema}
+		 * items.
+		 *
+		 * @private
+		 * @param {Node} node
+		 * @return {Array}
+		 */
+		const getBoundValue = ( node ) => {
+			let model, modelValue;
+
+			return valueSchema.map( schemaItem => {
+				model = schemaItem.model;
+
+				if ( model ) {
+					modelValue = model[ schemaItem.attribute ];
+
+					if ( schemaItem.callback ) {
+						modelValue = schemaItem.callback( modelValue, node );
+					}
+
+					return modelValue;
+				} else {
+					return schemaItem;
+				}
+			} );
+		};
+
+		/**
+		 * Attaches a listener to {@link View#model}, which updates DOM with a value constructed from
+		 * {@link core.ui.TemplateValueSchema} when {@link View#model} attribute value changes.
+		 *
+		 * This function is called by {@link Template#render} or {@link Template#apply}.
+		 *
+		 * @param {Node} node DOM Node to be updated when {@link View#model} changes.
+		 * @param {Function} domUpdater A function provided by {@link Template} which updates corresponding
+		 * DOM attribute or `textContent`.
+		 */
+		return ( node, domUpdater ) => {
+			// Check if valueSchema is a single bind.if, like:
+			//		{ class: bind.if( 'foo' ) }
+			const isPlainBindIf = valueSchema.length == 1 && valueSchema[ 0 ].type == bindIfSymbol;
+
+			// A function executed each time bound model attribute changes.
+			const onModelChange = () => {
+				let value = getBoundValue( node );
+
+				if ( isPlainBindIf ) {
+					value = value[ 0 ];
+				} else {
+					value = value.reduce( binderValueReducer, '' );
+				}
+
+				const isSet = isPlainBindIf ? !!value : value;
+
+				const valueToSet = isPlainBindIf ?
+					( valueSchema[ 0 ].valueIfTrue || '' ) : value;
+
+				if ( isSet ) {
+					domUpdater.set( valueToSet );
+				} else {
+					domUpdater.remove();
+				}
+			};
+
+			valueSchema
+				.filter( schemaItem => schemaItem.model )
+				.forEach( schemaItem => {
+					this.listenTo( schemaItem.model, 'change:' + schemaItem.attribute, onModelChange );
+				} );
+
+			// Set initial values.
+			onModelChange();
+		};
+	}
+
+	/**
+	 * Iterates over "attributes" and "text" properties in {@link TemplateDefinition} and
+	 * locates existing {@link core.ui.ViewModelBinding} created by {@link core.ui.View#attributeBinder}.
+	 * Then, for each such a binding, it creates corresponding entry in {@link Template#_modelBinders},
+	 * which can be then activated by {@link Template#render} or {@link Template#apply}.
+	 *
+	 * @protected
+	 * @param {core.ui.TemplateDefinition} def
+	 */
+	_extendTemplateWithModelBinders( def ) {
+		const attributes = def.attributes;
+		const text = def.text;
+		let binders = def._modelBinders;
+		let attrName, attrValue;
+
+		if ( !binders && isPlainObject( def ) ) {
+			Object.defineProperty( def, '_modelBinders', {
+				enumerable: false,
+				writable: true,
+				value: {
+					attributes: {}
+				}
+			} );
+
+			binders = def._modelBinders;
+		}
+
+		if ( attributes ) {
+			for ( attrName in attributes ) {
+				attrValue = attributes[ attrName ];
+
+				if ( hasModelBinding( attrValue ) ) {
+					binders.attributes[ attrName ] = this._getModelBinder( attrValue );
+				}
+			}
+		}
+
+		if ( text && hasModelBinding( text ) ) {
+			binders.text = this._getModelBinder( text );
+		}
+
+		// Repeat recursively for the children.
+		if ( def.children ) {
+			def.children.forEach( this._extendTemplateWithModelBinders, this );
+		}
+	}
+
 	/**
 	 * Iterates over "on" property in {@link TemplateDefinition} to recursively
 	 * replace each listener declaration with a function which, once executed in a context
 	 * of an element, attaches native DOM listener to that element.
 	 *
 	 * @protected
-	 * @param {TemplateDefinition} def Template definition.
+	 * @param {core.ui.TemplateDefinition} def Template definition.
 	 */
-	_createTemplateListenerAttachers( def ) {
+	_extendTemplateWithListenerAttachers( def ) {
 		const on = def.on;
 
 		// Don't create attachers if they're already here or in the context of the same (this) View instance.
@@ -425,7 +612,7 @@ export default class View {
 
 		// Repeat recursively for the children.
 		if ( def.children ) {
-			def.children.forEach( this._createTemplateListenerAttachers, this );
+			def.children.forEach( this._extendTemplateWithListenerAttachers, this );
 		}
 	}
 }
@@ -437,6 +624,7 @@ const validSelectorTypes = new Set( [ 'string', 'boolean', 'function' ] );
 /**
  * Check whether region selector is valid.
  *
+ * @ignore
  * @private
  * @param {*} selector Selector to be checked.
  * @returns {Boolean}
@@ -444,3 +632,68 @@ const validSelectorTypes = new Set( [ 'string', 'boolean', 'function' ] );
 function isValidRegionSelector( selector ) {
 	return validSelectorTypes.has( typeof selector ) && selector !== false;
 }
+
+/**
+ * Normalizes given {@link core.ui.TemplateValueSchema} it's always in an Array–like format:
+ *
+ * 		{ attributeName/text: 'bar' } ->
+ * 			{ attributeName/text: [ 'bar' ] }
+ *
+ * 		{ attributeName/text: { model: ..., modelAttributeName: ..., callback: ... } } ->
+ * 			{ attributeName/text: [ { model: ..., modelAttributeName: ..., callback: ... } ] }
+ *
+ * 		{ attributeName/text: [ 'bar', { model: ..., modelAttributeName: ... }, 'baz' ] }
+ *
+ * @ignore
+ * @private
+ * @param {core.ui.TemplateValueSchema} valueSchema
+ * @returns {Array}
+ */
+function normalizeBinderValueSchema( valueSchema ) {
+	return Array.isArray( valueSchema ) ? valueSchema : [ valueSchema ];
+}
+
+/**
+ * Checks whether given {@link core.ui.TemplateValueSchema} contains a
+ * {@link core.ui.ViewModelBinding}.
+ *
+ * @ignore
+ * @private
+ * @param {core.ui.TemplateValueSchema} valueSchema
+ * @returns {Boolean}
+ */
+function hasModelBinding( valueSchema ) {
+	if ( Array.isArray( valueSchema ) ) {
+		return valueSchema.some( hasModelBinding );
+	} else if ( valueSchema.model ) {
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * A helper which concatenates the value avoiding unwanted
+ * leading white spaces.
+ *
+ * @ignore
+ * @private
+ * @param {String} prev
+ * @param {String} cur
+ * @returns {String}
+ */
+function binderValueReducer( prev, cur ) {
+	return prev === '' ? `${cur}` : `${prev} ${cur}`;
+}
+
+/**
+ * Describes Model binding created by {@link View#attributeBinder}.
+ *
+ * @typedef core.ui.ViewModelBinding
+ * @type Object
+ * @property {Symbol} type
+ * @property {core.ui.Model} model
+ * @property {String} attribute
+ * @property {String} [valueIfTrue]
+ * @property {Function} [callback]
+ */

+ 1 - 0
packages/ckeditor5-engine/src/utils-diff.js

@@ -14,6 +14,7 @@
  *
  *		diff( 'aba', 'acca' ); // [ EQUAL, INSERT, INSERT, DELETE, EQUAL ]
  *
+ * @method core.diff
  * @param {Array} a Input array.
  * @param {Array} b Output array.
  * @param {Function} [cmp] Optional function used to compare array values, by default === is used.

+ 19 - 5
packages/ckeditor5-engine/src/utils.js

@@ -8,12 +8,8 @@
 import isPlainObject from './lib/lodash/isPlainObject.js';
 
 /**
- * An index at which arrays differ. If arrays are same at all indexes, it represents how arrays are related.
- * In this case, possible values are: 'SAME', 'PREFIX' or 'EXTENSION'.
- *
- * @typedef {String|Number} utils.ArrayRelation
+ * @namespace core.utils
  */
-
 const utils = {
 	/**
 	 * Creates a spy function (ala Sinon.js) that can be used to inspect call to it.
@@ -22,6 +18,7 @@ const utils = {
 	 *
 	 *  * spy.called: property set to `true` if the function has been called at least once.
 	 *
+	 * @memberOf core.utils
 	 * @returns {Function} The spy function.
 	 */
 	spy() {
@@ -34,6 +31,8 @@ const utils = {
 	 * Returns a unique id. This id is a number (starting from 1) which will never get repeated on successive calls
 	 * to this method.
 	 *
+	 * @function
+	 * @memberOf core.utils
 	 * @returns {Number} A number representing the id.
 	 */
 	uid: ( () => {
@@ -47,6 +46,7 @@ const utils = {
 	/**
 	 * Checks if value implements iterator interface.
 	 *
+	 * @memberOf core.utils
 	 * @param {*} value The value to check.
 	 * @returns {Boolean} True if value implements iterator interface.
 	 */
@@ -66,6 +66,7 @@ const utils = {
 	 *   compareArrays( [ 0, 2 ], [ 1, 2 ] ); // 0
 	 *   compareArrays( [ 0, 2 ], [ 0, 1 ] ); // 1
 	 *
+	 * @memberOf core.utils
 	 * @param {Array} a Array that is compared.
 	 * @param {Array} b Array to compare with.
 	 * @returns {utils.ArrayRelation} How array `a` is related to `b`.
@@ -99,6 +100,7 @@ const utils = {
 	 *		const map = utils.objectToMap( { 'foo': 1, 'bar': 2 } );
 	 *		map.get( 'foo' ); // 1
 	 *
+	 * @memberOf core.utils
 	 * @param {Object} obj Object to transform.
 	 * @returns {Map} Map created from object.
 	 */
@@ -119,6 +121,7 @@ const utils = {
 	 *		map = utils.toMap( [ [ 'foo', 1 ], [ 'bar', 2 ] ] );
 	 *		map = utils.toMap( anotherMap );
 	 *
+	 * @memberOf core.utils
 	 * @param {Object|Iterable} data Object or iterable to transform.
 	 * @returns {Map} Map created from data.
 	 */
@@ -133,6 +136,7 @@ const utils = {
 	/**
 	 * Checks whether given {Map}s are equal, that is has same size and same key-value pairs.
 	 *
+	 * @memberOf core.utils
 	 * @returns {Boolean} `true` if given maps are equal, `false` otherwise.
 	 */
 	mapsEqual( mapA, mapB ) {
@@ -155,6 +159,7 @@ const utils = {
 	/**
 	 * Returns `nth` (starts from `0` of course) item of an `iterable`.
 	 *
+	 * @memberOf core.utils
 	 * @param {Number} index
 	 * @param {Iterable.<*>} iterable
 	 * @returns {*}
@@ -190,6 +195,7 @@ const utils = {
 	 *
 	 * Note: Properties which already exist in the base class will not be overriden.
 	 *
+	 * @memberOf core.utils
 	 * @param {Function} [baseClass] Class which prototype will be extended.
 	 * @param {Object} [...mixins] Objects from which to get properties.
 	 */
@@ -210,4 +216,12 @@ const utils = {
 	}
 };
 
+/**
+ * An index at which arrays differ. If arrays are same at all indexes, it represents how arrays are related.
+ * In this case, possible values are: 'SAME', 'PREFIX' or 'EXTENSION'.
+ *
+ * @memberOf core.utils
+ * @typedef {String|Number} ArrayRelation
+ */
+
 export default utils;

+ 4 - 2
packages/ckeditor5-engine/tests/_utils/ui/editable/framed/framededitableview.js

@@ -11,6 +11,8 @@ export default class FramedEditableView extends EditableView {
 	constructor( model ) {
 		super( model );
 
+		const bind = this.attributeBinder;
+
 		// Here's the tricky part - we must return the promise from init()
 		// because iframe loading may be asynchronous. However, we can't start
 		// listening to 'load' in init(), because at this point the element is already in the DOM
@@ -28,8 +30,8 @@ export default class FramedEditableView extends EditableView {
 				// It seems that we need to allow scripts in order to be able to listen to events.
 				// TODO: Research that. Perhaps the src must be set?
 				sandbox: 'allow-same-origin allow-scripts',
-				width: this.bindToAttribute( 'width' ),
-				height: this.bindToAttribute( 'height' )
+				width: bind.to( 'width' ),
+				height: bind.to( 'height' )
 			},
 			on: {
 				load: 'loaded'

+ 3 - 3
packages/ckeditor5-engine/tests/treemodel/document/change-event.js

@@ -116,7 +116,7 @@ describe( 'Document change event', () => {
 		);
 
 		expect( changes ).to.have.length( 1 );
-		expect( types[ 0 ] ).to.equal( 'attr' );
+		expect( types[ 0 ] ).to.equal( 'attribute' );
 		expect( changes[ 0 ].range ).to.deep.equal( Range.createFromParentsAndOffsets( root, 0, root, 3 ) );
 		expect( changes[ 0 ].key ).to.equal( 'key' );
 		expect( changes[ 0 ].oldValue ).to.be.null;
@@ -138,7 +138,7 @@ describe( 'Document change event', () => {
 		);
 
 		expect( changes ).to.have.length( 1 );
-		expect( types[ 0 ] ).to.equal( 'attr' );
+		expect( types[ 0 ] ).to.equal( 'attribute' );
 		expect( changes[ 0 ].range ).to.deep.equal( Range.createFromParentsAndOffsets( root, 0, elem, 0 ) );
 		expect( changes[ 0 ].key ).to.equal( 'key' );
 		expect( changes[ 0 ].oldValue ).to.equal( 'old' );
@@ -160,7 +160,7 @@ describe( 'Document change event', () => {
 		);
 
 		expect( changes ).to.have.length( 1 );
-		expect( types[ 0 ] ).to.equal( 'attr' );
+		expect( types[ 0 ] ).to.equal( 'attribute' );
 		expect( changes[ 0 ].range ).to.deep.equal( Range.createFromParentsAndOffsets( root, 0, elem, 0 ) );
 		expect( changes[ 0 ].key ).to.equal( 'key' );
 		expect( changes[ 0 ].oldValue ).to.equal( 'old' );

+ 1 - 1
packages/ckeditor5-engine/tests/treemodel/operation/attributeoperation.js

@@ -32,7 +32,7 @@ describe( 'AttributeOperation', () => {
 			doc.version
 		);
 
-		expect( op.type ).to.equal( 'attr' );
+		expect( op.type ).to.equal( 'attribute' );
 	} );
 
 	it( 'should insert attribute to the set of nodes', () => {

+ 119 - 24
packages/ckeditor5-engine/tests/ui/template.js

@@ -41,7 +41,17 @@ describe( 'Template', () => {
 			} ).to.throw( CKEditorError, /ui-template-wrong-syntax/ );
 		} );
 
-		it( 'creates a HTMLElement with attributes', () => {
+		it( 'creates a HTMLElement', () => {
+			const el = new Template( {
+				tag: 'p',
+			} ).render();
+
+			expect( el ).to.be.instanceof( HTMLElement );
+			expect( el.parentNode ).to.be.null;
+			expect( el.outerHTML ).to.be.equal( '<p></p>' );
+		} );
+
+		it( 'renders HTMLElement attributes', () => {
 			const el = new Template( {
 				tag: 'p',
 				attributes: {
@@ -56,7 +66,33 @@ describe( 'Template', () => {
 			expect( el.outerHTML ).to.be.equal( '<p class="a b" x="bar">foo</p>' );
 		} );
 
-		it( 'creates HTMLElement\'s children', () => {
+		it( 'renders HTMLElement attributes – empty', () => {
+			const el = new Template( {
+				tag: 'p',
+				attributes: {
+					class: '',
+					x: [ '', '' ]
+				},
+				children: [ 'foo' ]
+			} ).render();
+
+			expect( el.outerHTML ).to.be.equal( '<p class="" x="">foo</p>' );
+		} );
+
+		it( 'renders HTMLElement attributes – falsy values', () => {
+			const el = new Template( {
+				tag: 'p',
+				attributes: {
+					class: false,
+					x: [ '', null ]
+				},
+				children: [ 'foo' ]
+			} ).render();
+
+			expect( el.outerHTML ).to.be.equal( '<p class="false" x="null">foo</p>' );
+		} );
+
+		it( 'creates HTMLElement children', () => {
 			const el = new Template( {
 				tag: 'p',
 				attributes: {
@@ -199,25 +235,30 @@ describe( 'Template', () => {
 			const el = new Template( {
 				tag: 'p',
 				attributes: {
-					'class': spy1
+					'class': {}
 				},
 				children: [
 					{
 						tag: 'span',
 						attributes: {
-							id: spy2
+							id: {}
+						},
+						_modelBinders: {
+							attributes: {
+								id: spy2
+							}
 						}
 					}
-				]
+				],
+				_modelBinders: {
+					attributes: {
+						class: spy1
+					}
+				}
 			} ).render();
 
-			sinon.assert.calledWithExactly( spy1, el, sinon.match.func );
-			sinon.assert.calledWithExactly( spy2, el.firstChild, sinon.match.func );
-
-			spy1.firstCall.args[ 1 ]( el, 'foo' );
-			spy2.firstCall.args[ 1 ]( el.firstChild, 'bar' );
-
-			expect( el.outerHTML ).to.be.equal( '<p class="foo"><span id="bar"></span></p>' );
+			sinon.assert.calledWithExactly( spy1, el, sinon.match.object );
+			sinon.assert.calledWithExactly( spy2, el.firstChild, sinon.match.object );
 		} );
 
 		it( 'activates model bindings – Text Node', () => {
@@ -228,27 +269,71 @@ describe( 'Template', () => {
 				tag: 'p',
 				children: [
 					{
-						text: spy1
+						text: {},
+						_modelBinders: {
+							text: spy1
+						}
 					},
 					{
 						tag: 'span',
 						children: [
 							{
-								text: spy2
+								text: {},
+								_modelBinders: {
+									text: spy2
+								}
 							}
 						]
 					}
 				]
 			} ).render();
 
-			sinon.assert.calledWithExactly( spy1, el.firstChild, sinon.match.func );
-			sinon.assert.calledWithExactly( spy2, el.lastChild.firstChild, sinon.match.func );
+			sinon.assert.calledWithExactly( spy1, el.firstChild, sinon.match.object );
+			sinon.assert.calledWithExactly( spy2, el.lastChild.firstChild, sinon.match.object );
+		} );
+
+		it( 'uses DOM updater – attributes', () => {
+			const spy = testUtils.sinon.spy();
+			const el = new Template( {
+				tag: 'p',
+				attributes: {
+					'class': {}
+				},
+				_modelBinders: {
+					attributes: {
+						class: spy
+					}
+				}
+			} ).render();
 
-			spy2.firstCall.args[ 1 ]( el.lastChild.firstChild, 'bar' );
-			expect( el.outerHTML ).to.be.equal( '<p><span>bar</span></p>' );
+			// Check whether DOM updater is correct.
+			spy.firstCall.args[ 1 ].set( 'x' );
+			expect( el.outerHTML ).to.be.equal( '<p class="x"></p>' );
 
-			spy1.firstCall.args[ 1 ]( el.firstChild, 'foo' );
-			expect( el.outerHTML ).to.be.equal( '<p>foo<span>bar</span></p>' );
+			spy.firstCall.args[ 1 ].remove();
+			expect( el.outerHTML ).to.be.equal( '<p></p>' );
+		} );
+
+		it( 'uses DOM updater – text', () => {
+			const spy = testUtils.sinon.spy();
+			const el = new Template( {
+				tag: 'p',
+				children: [
+					{
+						text: {},
+						_modelBinders: {
+							text: spy
+						}
+					}
+				],
+			} ).render();
+
+			// Check whether DOM updater is correct.
+			spy.firstCall.args[ 1 ].set( 'x' );
+			expect( el.outerHTML ).to.be.equal( '<p>x</p>' );
+
+			spy.firstCall.args[ 1 ].remove();
+			expect( el.outerHTML ).to.be.equal( '<p></p>' );
 		} );
 	} );
 
@@ -401,11 +486,16 @@ describe( 'Template', () => {
 			new Template( {
 				tag: 'div',
 				attributes: {
-					class: spy
+					class: {}
+				},
+				_modelBinders: {
+					attributes: {
+						class: spy
+					}
 				}
 			} ).apply( el );
 
-			sinon.assert.calledWithExactly( spy, el, sinon.match.func );
+			sinon.assert.calledWithExactly( spy, el, sinon.match.object );
 		} );
 
 		it( 'activates model bindings – children', () => {
@@ -418,13 +508,18 @@ describe( 'Template', () => {
 					{
 						tag: 'span',
 						attributes: {
-							class: spy
+							class: {}
+						},
+						_modelBinders: {
+							attributes: {
+								class: spy
+							}
 						}
 					}
 				]
 			} ).apply( el );
 
-			sinon.assert.calledWithExactly( spy, el.firstChild, sinon.match.func );
+			sinon.assert.calledWithExactly( spy, el.firstChild, sinon.match.object );
 		} );
 	} );
 } );

+ 406 - 91
packages/ckeditor5-engine/tests/ui/view.js

@@ -219,116 +219,427 @@ describe( 'View', () => {
 		} );
 	} );
 
-	describe( 'bindToAttribute', () => {
-		beforeEach( createViewInstanceWithTemplate );
+	describe( 'attributeBinder', () => {
+		it( 'provides "to" and "if" interface', () => {
+			const bind = view.attributeBinder;
 
-		it( 'returns a function that passes arguments', () => {
-			setTestViewInstance( { a: 'foo' } );
+			expect( bind ).to.have.keys( 'to', 'if' );
+			expect( typeof bind.to ).to.be.equal( 'function' );
+			expect( typeof bind.if ).to.be.equal( 'function' );
+		} );
 
-			const spy = testUtils.sinon.spy();
-			const callback = view.bindToAttribute( 'a', spy );
+		describe( 'to', () => {
+			it( 'returns an object which describes the binding', () => {
+				setTestViewInstance( { a: 1 } );
 
-			expect( spy.called ).to.be.false;
+				const spy = testUtils.sinon.spy();
+				const bind = view.attributeBinder;
+				const binding = bind.to( 'a', spy );
 
-			callback( 'el', 'updater' );
-			sinon.assert.calledOnce( spy );
-			sinon.assert.calledWithExactly( spy, 'el', 'foo' );
+				expect( spy.called ).to.be.false;
+				expect( binding ).to.have.keys( [ 'type', 'model', 'attribute', 'callback' ] );
+				expect( binding.model ).to.equal( view.model );
+				expect( binding.callback ).to.equal( spy );
+				expect( binding.attribute ).to.equal( 'a' );
+			} );
 
-			view.model.a = 'bar';
-			sinon.assert.calledTwice( spy );
-			expect( spy.secondCall.calledWithExactly( 'el', 'bar' ) ).to.be.true;
-		} );
+			it( 'allows binding attribute to the model – simple (HTMLElement attribute)', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
 
-		it( 'allows binding attribute to the model', () => {
-			setTestViewClass( function() {
-				return {
-					tag: 'p',
-					attributes: {
-						'class': this.bindToAttribute( 'foo' )
-					},
-					children: [ 'abc' ]
-				};
+					return {
+						tag: 'p',
+						attributes: {
+							'class': bind.to( 'foo' )
+						},
+						children: [ 'abc' ]
+					};
+				} );
+
+				setTestViewInstance( { foo: 'bar' } );
+				expect( view.element.outerHTML ).to.be.equal( '<p class="bar">abc</p>' );
+
+				view.model.foo = 'baz';
+				expect( view.element.outerHTML ).to.be.equal( '<p class="baz">abc</p>' );
 			} );
 
-			setTestViewInstance( { foo: 'bar' } );
+			it( 'allows binding attribute to the model – simple (Text Node)', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
 
-			expect( view.element.outerHTML ).to.be.equal( '<p class="bar">abc</p>' );
+					return {
+						tag: 'p',
+						children: [
+							{
+								text: bind.to( 'foo' )
+							}
+						]
+					};
+				} );
 
-			view.model.foo = 'baz';
-			expect( view.element.outerHTML ).to.be.equal( '<p class="baz">abc</p>' );
-		} );
+				setTestViewInstance( { foo: 'bar' } );
+				expect( view.element.outerHTML ).to.be.equal( '<p>bar</p>' );
 
-		it( 'allows binding "text" to the model', () => {
-			setTestViewClass( function() {
-				return {
-					tag: 'p',
-					children: [
-						{
-							text: this.bindToAttribute( 'foo' )
+				view.model.foo = 'baz';
+				expect( view.element.outerHTML ).to.be.equal( '<p>baz</p>' );
+			} );
+
+			it( 'allows binding attribute to the model – value processing', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
+					const callback = value => value > 0 ? 'positive' : 'negative';
+
+					return {
+						tag: 'p',
+						attributes: {
+							'class': bind.to( 'foo', callback )
 						},
-						{
-							tag: 'b',
-							children: [ 'baz' ]
+						children: [
+							{
+								text: bind.to( 'foo', callback )
+							}
+						]
+					};
+				} );
+
+				setTestViewInstance( { foo: 3 } );
+				expect( view.element.outerHTML ).to.be.equal( '<p class="positive">positive</p>' );
+
+				view.model.foo = -7;
+				expect( view.element.outerHTML ).to.be.equal( '<p class="negative">negative</p>' );
+			} );
+
+			it( 'allows binding attribute to the model – value processing (use Node)', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
+					const callback = ( value, node ) => {
+						return ( !!node.tagName && value > 0 ) ? 'HTMLElement positive' : '';
+					};
+
+					return {
+						tag: 'p',
+						attributes: {
+							'class': bind.to( 'foo', callback )
+						},
+						children: [
+							{
+								text: bind.to( 'foo', callback )
+							}
+						]
+					};
+				} );
+
+				setTestViewInstance( { foo: 3 } );
+				expect( view.element.outerHTML ).to.be.equal( '<p class="HTMLElement positive"></p>' );
+
+				view.model.foo = -7;
+				expect( view.element.outerHTML ).to.be.equal( '<p></p>' );
+			} );
+
+			it( 'allows binding attribute to the model – custom callback', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
+
+					return {
+						tag: 'p',
+						attributes: {
+							'class': bind.to( 'foo', ( value, el ) => {
+								el.innerHTML = value;
+
+								if ( value == 'changed' ) {
+									return value;
+								}
+							} )
 						}
-					]
-				};
+					};
+				} );
+
+				setTestViewInstance( { foo: 'moo' } );
+				expect( view.element.outerHTML ).to.be.equal( '<p class="undefined">moo</p>' );
+
+				view.model.foo = 'changed';
+				expect( view.element.outerHTML ).to.be.equal( '<p class="changed">changed</p>' );
 			} );
 
-			setTestViewInstance( { foo: 'bar' } );
+			it( 'allows binding attribute to the model – array of bindings (HTMLElement attribute)', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
+
+					return {
+						tag: 'p',
+						attributes: {
+							'class': [
+								'ck-class',
+								bind.to( 'foo' ),
+								bind.to( 'bar' ),
+								bind.to( 'foo', value => `foo-is-${value}` ),
+								'ck-end'
+							]
+						},
+						children: [ 'abc' ]
+					};
+				} );
 
-			expect( view.element.outerHTML ).to.be.equal( '<p>bar<b>baz</b></p>' );
+				setTestViewInstance( { foo: 'a', bar: 'b' } );
+				expect( view.element.outerHTML ).to.be.equal( '<p class="ck-class a b foo-is-a ck-end">abc</p>' );
 
-			view.model.foo = 'qux';
-			expect( view.element.outerHTML ).to.be.equal( '<p>qux<b>baz</b></p>' );
-		} );
+				view.model.foo = 'c';
+				view.model.bar = 'd';
+				expect( view.element.outerHTML ).to.be.equal( '<p class="ck-class c d foo-is-c ck-end">abc</p>' );
+			} );
 
-		it( 'allows binding to the model with value processing', () => {
-			const callback = ( el, value ) =>
-				( value > 0 ? 'positive' : 'negative' );
+			it( 'allows binding attribute to the model – array of bindings (Text Node)', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
 
-			setTestViewClass( function() {
-				return {
-					tag: 'p',
-					attributes: {
-						'class': this.bindToAttribute( 'foo', callback )
-					},
-					children: [
-						{ text: this.bindToAttribute( 'foo', callback ) }
-					]
-				};
+					return {
+						tag: 'p',
+						attributes: {
+						},
+						children: [
+							{
+								text: [
+									'ck-class',
+									bind.to( 'foo' ),
+									bind.to( 'bar' ),
+									bind.to( 'foo', value => `foo-is-${value}` ),
+									'ck-end'
+								]
+							}
+						]
+					};
+				} );
+
+				setTestViewInstance( { foo: 'a', bar: 'b' } );
+				expect( view.element.outerHTML ).to.be.equal( '<p>ck-class a b foo-is-a ck-end</p>' );
+
+				view.model.foo = 'c';
+				view.model.bar = 'd';
+				expect( view.element.outerHTML ).to.be.equal( '<p>ck-class c d foo-is-c ck-end</p>' );
 			} );
 
-			setTestViewInstance( { foo: 3 } );
-			expect( view.element.outerHTML ).to.be.equal( '<p class="positive">positive</p>' );
+			it( 'allows binding attribute to the model – falsy values', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
 
-			view.model.foo = -7;
-			expect( view.element.outerHTML ).to.be.equal( '<p class="negative">negative</p>' );
+					return {
+						tag: 'p',
+						attributes: {
+							'class': bind.to( 'foo' )
+						},
+						children: [ 'abc' ]
+					};
+				} );
+
+				setTestViewInstance( { foo: 'bar' } );
+				expect( view.element.outerHTML ).to.be.equal( '<p class="bar">abc</p>' );
+
+				view.model.foo = false;
+				expect( view.element.outerHTML ).to.be.equal( '<p class="false">abc</p>' );
+
+				view.model.foo = null;
+				expect( view.element.outerHTML ).to.be.equal( '<p class="null">abc</p>' );
+
+				view.model.foo = undefined;
+				expect( view.element.outerHTML ).to.be.equal( '<p class="undefined">abc</p>' );
+
+				view.model.foo = 0;
+				expect( view.element.outerHTML ).to.be.equal( '<p class="0">abc</p>' );
+
+				view.model.foo = '';
+				expect( view.element.outerHTML ).to.be.equal( '<p>abc</p>' );
+			} );
 		} );
 
-		it( 'allows binding to the model with custom callback', () => {
-			setTestViewClass( function() {
-				return {
-					tag: 'p',
-					attributes: {
-						'class': this.bindToAttribute( 'foo', ( el, value ) => {
-							el.innerHTML = value;
+		describe( 'if', () => {
+			it( 'returns an object which describes the binding', () => {
+				setTestViewInstance( { a: 1 } );
+
+				const spy = testUtils.sinon.spy();
+				const bind = view.attributeBinder;
+				const binding = bind.if( 'a', 'foo', spy );
+
+				expect( spy.called ).to.be.false;
+				expect( binding ).to.have.keys( [ 'type', 'model', 'attribute', 'callback', 'valueIfTrue' ] );
+				expect( binding.model ).to.equal( view.model );
+				expect( binding.callback ).to.equal( spy );
+				expect( binding.attribute ).to.equal( 'a' );
+				expect( binding.valueIfTrue ).to.equal( 'foo' );
+			} );
+
+			it( 'allows binding attribute to the model – presence of an attribute (HTMLElement attribute)', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
+
+					return {
+						tag: 'p',
+						attributes: {
+							'class': bind.if( 'foo' )
+						},
+						children: [ 'abc' ]
+					};
+				} );
+
+				setTestViewInstance( { foo: true } );
+				expect( view.element.outerHTML ).to.be.equal( '<p class="">abc</p>' );
+
+				view.model.foo = false;
+				expect( view.element.outerHTML ).to.be.equal( '<p>abc</p>' );
+
+				view.model.foo = 'bar';
+				expect( view.element.outerHTML ).to.be.equal( '<p class="">abc</p>' );
+			} );
 
-							if ( value == 'changed' ) {
-								return value;
+			// TODO: Is this alright? It makes sense but it's pretty useless. Text Node cannot be
+			// removed just like an attribute of some HTMLElement.
+			it( 'allows binding attribute to the model – presence of an attribute (Text Node)', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
+
+					return {
+						tag: 'p',
+						children: [
+							{
+								text: bind.if( 'foo' )
 							}
-						} )
-					},
-					children: [ 'bar' ]
-				};
+						]
+					};
+				} );
+
+				setTestViewInstance( { foo: true } );
+				expect( view.element.outerHTML ).to.be.equal( '<p></p>' );
+
+				view.model.foo = false;
+				expect( view.element.outerHTML ).to.be.equal( '<p></p>' );
+
+				view.model.foo = 'bar';
+				expect( view.element.outerHTML ).to.be.equal( '<p></p>' );
+			} );
+
+			it( 'allows binding attribute to the model – value of an attribute (HTMLElement attribute)', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
+
+					return {
+						tag: 'p',
+						attributes: {
+							'class': bind.if( 'foo', 'bar' )
+						},
+						children: [ 'abc' ]
+					};
+				} );
+
+				setTestViewInstance( { foo: 'bar' } );
+				expect( view.element.outerHTML ).to.be.equal( '<p class="bar">abc</p>' );
+
+				view.model.foo = false;
+				expect( view.element.outerHTML ).to.be.equal( '<p>abc</p>' );
+
+				view.model.foo = 64;
+				expect( view.element.outerHTML ).to.be.equal( '<p class="bar">abc</p>' );
+			} );
+
+			it( 'allows binding attribute to the model – value of an attribute (Text Node)', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
+
+					return {
+						tag: 'p',
+						children: [
+							{
+								text: bind.if( 'foo', 'bar' )
+							}
+						]
+					};
+				} );
+
+				setTestViewInstance( { foo: 'bar' } );
+				expect( view.element.outerHTML ).to.be.equal( '<p>bar</p>' );
+
+				view.model.foo = false;
+				expect( view.element.outerHTML ).to.be.equal( '<p></p>' );
+
+				view.model.foo = 64;
+				expect( view.element.outerHTML ).to.be.equal( '<p>bar</p>' );
+			} );
+
+			it( 'allows binding attribute to the model – value of an attribute processed by a callback', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
+
+					return {
+						tag: 'p',
+						attributes: {
+							'class': bind.if( 'foo', 'there–is–no–foo', value => !value )
+						},
+						children: [ 'abc' ]
+					};
+				} );
+
+				setTestViewInstance( { foo: 'bar' } );
+				expect( view.element.outerHTML ).to.be.equal( '<p>abc</p>' );
+
+				view.model.foo = false;
+				expect( view.element.outerHTML ).to.be.equal( '<p class="there–is–no–foo">abc</p>' );
+
+				view.model.foo = 64;
+				expect( view.element.outerHTML ).to.be.equal( '<p>abc</p>' );
+			} );
+
+			it( 'allows binding attribute to the model – value of an attribute processed by a callback (use Node)', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
+
+					return {
+						tag: 'p',
+						attributes: {
+							'class': bind.if( 'foo', 'eqls-tag-name', ( value, el ) => el.tagName === value )
+						},
+						children: [ 'abc' ]
+					};
+				} );
+
+				setTestViewInstance( { foo: 'bar' } );
+				expect( view.element.outerHTML ).to.be.equal( '<p>abc</p>' );
+
+				view.model.foo = 'P';
+				expect( view.element.outerHTML ).to.be.equal( '<p class="eqls-tag-name">abc</p>' );
+
+				view.model.foo = 64;
+				expect( view.element.outerHTML ).to.be.equal( '<p>abc</p>' );
 			} );
 
-			setTestViewInstance( { foo: 'moo' } );
-			// Note: First the attribute binding sets innerHTML to 'moo',
-			// then 'bar' TextNode child is added.
-			expect( view.element.outerHTML ).to.be.equal( '<p>moobar</p>' );
+			it( 'allows binding attribute to the model – falsy values', () => {
+				setTestViewClass( function() {
+					const bind = this.attributeBinder;
 
-			view.model.foo = 'changed';
-			expect( view.element.outerHTML ).to.be.equal( '<p class="changed">changed</p>' );
+					return {
+						tag: 'p',
+						attributes: {
+							'class': bind.if( 'foo', 'foo-is-set' )
+						},
+						children: [ 'abc' ]
+					};
+				} );
+
+				setTestViewInstance( { foo: 'bar' } );
+				expect( view.element.outerHTML ).to.be.equal( '<p class="foo-is-set">abc</p>' );
+
+				view.model.foo = false;
+				expect( view.element.outerHTML ).to.be.equal( '<p>abc</p>' );
+
+				view.model.foo = null;
+				expect( view.element.outerHTML ).to.be.equal( '<p>abc</p>' );
+
+				view.model.foo = undefined;
+				expect( view.element.outerHTML ).to.be.equal( '<p>abc</p>' );
+
+				view.model.foo = '';
+				expect( view.element.outerHTML ).to.be.equal( '<p>abc</p>' );
+
+				view.model.foo = 0;
+				expect( view.element.outerHTML ).to.be.equal( '<p>abc</p>' );
+			} );
 		} );
 	} );
 
@@ -596,10 +907,12 @@ describe( 'View', () => {
 
 		it( 'detaches bound model listeners', () => {
 			setTestViewClass( function() {
+				const bind = this.attributeBinder;
+
 				return {
 					tag: 'p',
 					children: [
-						{ text: this.bindToAttribute( 'foo' ) }
+						{ text: bind.to( 'foo' ) }
 					]
 				};
 			} );
@@ -637,21 +950,22 @@ describe( 'View', () => {
 
 		it( 'should initialize attribute bindings', () => {
 			const el = document.createElement( 'div' );
+			const bind = view.attributeBinder;
 
 			view.applyTemplateToElement( el, {
 				tag: 'div',
 				attributes: {
-					class: view.bindToAttribute( 'b' ),
+					class: bind.to( 'b' ),
 					id: 'foo',
-					checked: ''
+					checked: 'checked'
 				}
 			} );
 
-			expect( el.outerHTML ).to.be.equal( '<div class="42" id="foo" checked=""></div>' );
+			expect( el.outerHTML ).to.be.equal( '<div class="42" id="foo" checked="checked"></div>' );
 
 			view.model.b = 64;
 
-			expect( el.outerHTML ).to.be.equal( '<div class="64" id="foo" checked=""></div>' );
+			expect( el.outerHTML ).to.be.equal( '<div class="64" id="foo" checked="checked"></div>' );
 		} );
 
 		it( 'should initialize DOM listeners', () => {
@@ -693,6 +1007,7 @@ describe( 'View', () => {
 			const spy1 = testUtils.sinon.spy();
 			const spy2 = testUtils.sinon.spy();
 			const spy3 = testUtils.sinon.spy();
+			const bind = view.attributeBinder;
 
 			view.applyTemplateToElement( el, {
 				tag: 'div',
@@ -703,7 +1018,7 @@ describe( 'View', () => {
 							keyup: spy2
 						},
 						attributes: {
-							class: view.bindToAttribute( 'b', ( el, b ) => 'applied-A-' + b ),
+							class: bind.to( 'b', b => 'applied-A-' + b ),
 							id: 'applied-A'
 						},
 						children: [ 'Text applied to childA.' ]
@@ -714,7 +1029,7 @@ describe( 'View', () => {
 							keydown: spy3
 						},
 						attributes: {
-							class: view.bindToAttribute( 'b', ( el, b ) => 'applied-B-' + b ),
+							class: bind.to( 'b', b => 'applied-B-' + b ),
 							id: 'applied-B'
 						},
 						children: [ 'Text applied to childB.' ]
@@ -725,8 +1040,8 @@ describe( 'View', () => {
 					'mouseover@a': spy1
 				},
 				attributes: {
-					id: view.bindToAttribute( 'a', ( el, a ) => a.toUpperCase() ),
-					class: view.bindToAttribute( 'b', ( el, b ) => 'applied-parent-' + b )
+					id: bind.to( 'a', a => a.toUpperCase() ),
+					class: bind.to( 'b', b => 'applied-parent-' + b )
 				}
 			} );
 
@@ -788,7 +1103,7 @@ describe( 'View', () => {
 			sinon.assert.calledTwice( spy );
 		} );
 
-		it( 'shares a template definition between View instances', () => {
+		it( 'shares a template definition between View instances – event listeners', () => {
 			const el = document.createElement( 'div' );
 			const spy = testUtils.sinon.spy();
 			const view1 = new View();