8
0
فهرست منبع

Docs: Reviewed and improved documentation of the View class.

Aleksander Nowodzinski 8 سال پیش
والد
کامیت
300e0e39fa
1فایلهای تغییر یافته به همراه190 افزوده شده و 37 حذف شده
  1. 190 37
      packages/ckeditor5-ui/src/view.js

+ 190 - 37
packages/ckeditor5-ui/src/view.js

@@ -17,25 +17,48 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
 import isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';
 
 /**
- * Basic View class.
+ * The basic view class, which represents an HTML element created out of a
+ * {@link module:ui/view~View#template}. Views are building blocks of the user interface and handle
+ * interaction
+ *
+ * Views {@link module:ui/view~View#addChildren aggregate} children in
+ * {@link module:ui/view~View#createCollection collections} and manage the life cycle of DOM
+ * listeners e.g. by handling initialization and destruction.
+ *
+ * See the {@link module:ui/template~TemplateDefinition} syntax to learn more about shaping view
+ * elements, attributes and listeners.
  *
  *		class SampleView extends View {
  *			constructor( locale ) {
  *				super( locale );
  *
+ *				const bind = this.bindTemplate;
+ *
+ *				// Views define their interface (state) using observable attributes.
+ *				this.set( 'elementClass', 'bar' );
+ *
  *				this.template = new Template( {
  *					tag: 'p',
+ *
+ *					// The element of the view can be defined with its children.
  *					children: [
  *						'Hello',
  *						{
  *							tag: 'b',
- *							children: [
- *								'world!'
- *							]
+ *							children: [ 'world!' ]
  *						}
  *					],
  *					attributes: {
- *						class: 'foo'
+ *						class: [
+ *							'foo',
+ *
+ *							// Observable attributes control the state of the view in DOM.
+ *							bind.to( 'elementClass' )
+ *						]
+ *					},
+ *					on: {
+ *						// Views listen to DOM events and propagate them.
+ *						click: bind.to( 'clicked' )
  *					}
  *				} );
  *			}
@@ -43,22 +66,35 @@ import isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';
  *
  *		const view = new SampleView( locale );
  *
+ *		// Each view must be first initialized.
  *		view.init();
  *
- *		// Will append <p class="foo">Hello<b>world</b></p>
+ *		// Append <p class="foo bar">Hello<b>world</b></p> to the <body>
  *		document.body.appendChild( view.element );
  *
+ *		// Change the class attribute to <p class="foo baz">Hello<b>world</b></p>
+ *		view.elementClass = 'baz';
+ *
+ *		// Respond to the "click" event in DOM by executing a custom action.
+ *		view.on( 'clicked', () => {
+ *			console.log( 'The view has been clicked!' );
+ *		} );
+ *
  * @mixes module:utils/observablemixin~ObservableMixin
  */
 export default class View {
 	/**
 	 * Creates an instance of the {@link module:ui/view~View} class.
 	 *
-	 * @param {module:utils/locale~Locale} [locale] The {@link module:core/editor/editor~Editor editor's locale} instance.
+	 * Also see {@link #init}.
+	 *
+	 * @param {module:utils/locale~Locale} [locale] The localization services instance.
 	 */
 	constructor( locale ) {
 		/**
-		 * A set of tools to localize the user interface. See {@link module:core/editor/editor~Editor}.
+		 * A set of tools to localize the user interface.
+		 *
+		 * Also see {@link module:core/editor/editor~Editor#locale}.
 		 *
 		 * @readonly
 		 * @member {module:utils/locale~Locale}
@@ -68,7 +104,8 @@ export default class View {
 		/**
 		 * Shorthand for {@link module:utils/locale~Locale#t}.
 		 *
-		 * Note: If locale instance hasn't been passed to the view this method may not be available.
+		 * Note: If {@link #locale} instance hasn't been passed to the view this method may not
+		 * be available.
 		 *
 		 * @see module:utils/locale~Locale#t
 		 * @method
@@ -76,7 +113,9 @@ export default class View {
 		this.t = locale && locale.t;
 
 		/**
-		 * Set `true` after {@link #init}, which can be asynchronous.
+		 * A flag set `true` after {@link #init initialization}. Because the process can be
+		 * asynchronous, this {@link module:utils/observablemixin~Observable observable} flag allows
+		 * deferring certain actions until it is finished.
 		 *
 		 * @readonly
 		 * @observable
@@ -107,21 +146,22 @@ export default class View {
 		} );
 
 		/**
-		 * Template of this view.
+		 * Template of this view. It provides the {@link #element} representing
+		 * the view in DOM.
 		 *
 		 * @member {module:ui/template~Template} #template
 		 */
 
 		/**
-		 * Element of this view.
+		 * An internal, cached element of this view. See {@link #element}.
 		 *
 		 * @private
 		 * @member {HTMLElement} #_element
 		 */
 
 		/**
-		 * Cached {@link module:ui/template~Template} binder object specific for this instance.
-		 * See {@link #bindTemplate}.
+		 * Cached {@link @link module:ui/template~BindChain bind chain} object created by the
+		 * {@link #template}. See {@link #bindTemplate}.
 		 *
 		 * @private
 		 * @member {Object} #_bindTemplate
@@ -129,8 +169,31 @@ export default class View {
 	}
 
 	/**
-	 * Element of this view. The element is rendered on first reference
-	 * using {@link #template} definition.
+	 * An HTML element of this view. The element is rendered on first reference
+	 * by the {@link #template}:
+	 *
+	 *		class SampleView extends View {
+	 *			constructor() {
+	 *				super();
+	 *
+	 *				// A template instance the #element will be created from.
+	 *				this.template = new Template( {
+	 *					tag: 'p'
+	 *
+	 *					// ...
+	 *				} );
+	 *			}
+	 *		}
+	 *
+	 *		const view = new SampleView();
+	 *		view.init();
+	 *
+	 *		// Renders the #template and appends the output to <body>.
+	 *		document.body.appendChild( view.element );
+	 *
+	 * The element of the view can also be assigned directly:
+	 *
+	 *		view.element = document.querySelector( '#my-container' );
 	 *
 	 * @type {HTMLElement}
 	 */
@@ -154,9 +217,45 @@ export default class View {
 	}
 
 	/**
-	 * Shorthand for {@link module:ui/template~Template.bind}, bound to {@link ~View} on the first access.
+	 * Shorthand for {@link module:ui/template~Template.bind}, a binding
+	 * {@link module:ui/template~BindChain interface} pre–configured for the view instance.
+	 *
+	 * It provides {@link module:ui/template~BindChain#to `to()`} and
+	 * {@link module:ui/template~BindChain#if `if()`} methods that initialize bindings with
+	 * observable attributes and attach DOM listeners.
+	 *
+	 *		class SampleView extends View {
+	 *			constructor( locale ) {
+	 *				super( locale );
 	 *
-	 * Cached {@link module:ui/template~Template.bind} object is stored in {@link #_bindTemplate}.
+	 *				const bind = this.bindTemplate;
+	 *
+	 *				// These {@link module:utils/observablemixin~Observable observable} attributes will control
+	 *				// the state of the view in DOM.
+	 *				this.set( {
+	 *					elementClass: 'foo',
+	 *				 	isEnabled: true
+	 *				 } );
+	 *
+	 *				this.template = new Template( {
+	 *					tag: 'p',
+	 *
+	 *					attributes: {
+	 *						// The class HTML attribute will follow elementClass
+	 *						// and isEnabled view attributes.
+	 *						class: [
+	 *							bind.to( 'elementClass' )
+	 *							bind.if( 'isEnabled', 'present-when-enabled' )
+	 *						]
+	 *					},
+	 *
+	 *					on: {
+	 *						// The view will fire the "clicked" event upon clicking <p> in DOM.
+	 *						click: bind.to( 'clicked' )
+	 *					}
+	 *				} );
+	 *			}
+	 *		}
 	 *
 	 * @method #bindTemplate
 	 */
@@ -169,8 +268,8 @@ export default class View {
 	}
 
 	/**
-	 * Creates a new collection of views, which can be used in this view instance,
-	 * e.g. as a member of {@link module:ui/template~TemplateDefinition TemplateDefinition} children.
+	 * Creates a new collection of views, which can be used as
+	 * {@link module:ui/template~Template#children} of this view.
 	 *
 	 *		class SampleView extends View {
 	 *			constructor( locale ) {
@@ -188,16 +287,16 @@ export default class View {
 	 *		}
 	 *
 	 *		const view = new SampleView( locale );
-	 *		const anotherView = new AnotherSampleView( locale );
+	 *		const child = new ChildView( locale );
 	 *
 	 *		view.init();
 	 *
-	 *		// Will append <p></p>
+	 *		// It will append <p></p> to the <body>.
 	 *		document.body.appendChild( view.element );
 	 *
-	 *		// `anotherView` becomes a child of the view, which is reflected in DOM
-	 *		// <p><anotherView#element></p>
-	 *		view.items.add( anotherView );
+	 *		// From now on the child is nested under its parent, which is also reflected in DOM.
+	 *		// <p><child#element></p>
+	 *		view.items.add( child );
 	 *
 	 * @returns {module:ui/viewcollection~ViewCollection} A new collection of view instances.
 	 */
@@ -210,9 +309,11 @@ export default class View {
 	}
 
 	/**
-	 * Registers a new child view under this view instance. Once registered, a child
-	 * view is managed by its parent, including initialization ({@link #init})
-	 * and destruction ({@link #destroy}).
+	 * Registers a new child view under the view instance. Once registered, a child
+	 * view is managed by its parent, including {@link #init initization}
+	 * and {@link #destroy destruction}.
+	 *
+	 * To revert this, use {@link #removeChildren}.
 	 *
 	 *		class SampleView extends View {
 	 *			constructor( locale ) {
@@ -223,7 +324,7 @@ export default class View {
 	 *
 	 *				this.template = new Template( { tag: 'p' } );
 	 *
-	 *				// Register children.
+	 *				// Register the children.
 	 *				this.addChildren( [ this.childA, this.childB ] );
 	 *			}
 	 *
@@ -239,11 +340,11 @@ export default class View {
 	 *
 	 *		view.init();
 	 *
-	 *		// Will append <p><childA#element><b></b><childB#element></p>
+	 *		// Will append <p><childA#element><b></b><childB#element></p>.
 	 *		document.body.appendChild( view.element );
 	 *
-	 * **Note**: There's no need to add child views if they're used in the
-	 * {@link #template} explicitly:
+	 * **Note**: There's no need to add child views if they're already referenced in the
+	 * {@link #template}:
 	 *
 	 *		class SampleView extends View {
 	 *			constructor( locale ) {
@@ -261,7 +362,7 @@ export default class View {
 	 *				} );
 	 *			}
 	 *
-	 *			...
+	 *			// ...
 	 *		}
 	 *
 	 * @param {module:ui/view~View|Iterable.<module:ui/view~View>} children Children views to be registered.
@@ -276,8 +377,8 @@ export default class View {
 
 	/**
 	 * The opposite of {@link #addChildren}. Removes a child view from this view instance.
-	 * Once removed, the child is no longer managed by its parent, e.g. it can be safely used elsewhere,
-	 * becoming a child of another parent view.
+	 * Once removed, the child is no longer managed by its parent, e.g. it can safely
+	 * become a child of another parent view.
 	 *
 	 * @see #addChildren
 	 * @param {module:ui/view~View|Iterable.<module:ui/view~View>} children Child views to be removed.
@@ -291,7 +392,54 @@ export default class View {
 	}
 
 	/**
-	 * Initializes the view and child views located in {@link #_viewCollections}.
+	 * Initializes the view and its children added by {@link #addChildren} and residing in collections
+	 * created by the {@link #createCollection} method.
+	 *
+	 * In general, `init()` is the right place to keep the code which refers to the {@link #element}
+	 * and should be executed at the very beginning of the view's life cycle. It is possible to
+	 * {@link module:ui/template~Template.extend} the {@link #template} before the first reference of
+	 * the {@link #element}. To allow an early customization of the view (e.g. by its parent),
+	 * such references should be done in `init()`.
+	 *
+	 *		class SampleView extends View {
+	 *			constructor() {
+	 *				this.template = new Template( {
+	 *					// ...
+	 *				} );
+	 *			},
+	 *
+	 *			init() {
+	 *				super.init();
+	 *
+	 *				function scroll() {
+	 *					// A reference to #element would render the #template and make it non-extendable.
+	 *					if ( window.scrollY > 0 ) {
+	 *						this.element.scrollLeft = 100;
+	 *					} else {
+	 *						this.element.scrollLeft = 0;
+	 *					}
+	 *				}
+	 *
+	 *				this.listenTo( window, 'scroll', () => {
+	 *					scroll();
+	 *				} );
+	 *			}
+	 *		}
+	 *
+	 *		const view = new SampleView();
+	 *
+	 *		Template.extend( view.template, {
+	 *			attributes: {
+	 *				class: [
+	 *					'additional-class'
+	 *				]
+	 *			}
+	 *		} );
+	 *
+	 *		// Late initialization allows customization of the view.
+	 *		view.init();
+	 *
+	 * Once initialized, the view becomes {@link #ready}.
 	 */
 	init() {
 		if ( this.ready ) {
@@ -311,7 +459,12 @@ export default class View {
 	}
 
 	/**
-	 * Destroys the view instance and child views located in {@link #_viewCollections}.
+	 * Recursively destroys the view instance and child views added by {@link #addChildren} and
+	 * residing in collections created by the {@link #createCollection}.
+	 *
+	 * Destruction disables all event listeners:
+	 * * created on the view, e.g. `view.on( 'event', () => {} )`,
+	 * * defined in the {@link #template} for DOM events.
 	 */
 	destroy() {
 		this.stopListening();