| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- /**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
- import CKEditorError from '../utils/ckeditorerror.js';
- import ViewCollection from './viewcollection.js';
- import Template from './template.js';
- import DOMEmitterMixin from './domemittermixin.js';
- import ObservableMixin from '../utils/observablemixin.js';
- import Collection from '../utils/collection.js';
- import mix from '../utils/mix.js';
- /**
- * Basic View class.
- *
- * @memberOf ui
- * @mixes DOMEmitterMixin
- * @mixes ObservableMixin
- */
- export default class View {
- /**
- * Creates an instance of the {@link ui.View} class.
- *
- * TODO: A simple example how to create one.
- *
- * @param {utils.Locale} [locale] The {@link core.editor.Editor#locale editor's locale} instance.
- */
- constructor( locale ) {
- /**
- * A set of tools to localize the user interface. See {@link core.editor.Editor#locale}.
- *
- * @readonly
- * @member {utils.Locale} ui.View#locale
- */
- this.locale = locale;
- /**
- * Shorthand for {@link utils.Locale#t}.
- *
- * Note: If locale instance hasn't been passed to the view this method may not be available.
- *
- * @see utils.Locale#t
- * @method ui.View#t
- */
- this.t = locale && locale.t;
- /**
- * Set `true` after {@link ui.View#init}, which can be asynchronous.
- *
- * @readonly
- * @observable
- * @member {Boolean} ui.View#ready
- */
- this.set( 'ready', false );
- /**
- * Collections registered with {@link ui.View#createCollection}.
- *
- * @protected
- * @member {Set.<ui.ViewCollection>} ui.view#_viewCollections
- */
- this._viewCollections = new Collection();
- // Let the new collection determine the {@link ui.View#ready} state of this view and,
- // accordingly, initialize (or not) children views as they are added in the future.
- this._viewCollections.on( 'add', ( evt, collection ) => {
- collection.bind( 'ready' ).to( this );
- collection.locale = locale;
- } );
- // Once the collection is removed from the view, the {@link ui.View#ready} binding
- // should be removed.
- this._viewCollections.on( 'remove', ( evt, collection ) => {
- collection.unbind( 'ready' );
- } );
- /**
- * A collection of view instances, which have been added directly
- * into the {@link ui.View.template#children}.
- *
- * @protected
- * @member {ui.ViewCollection} ui.view#_unboundChildren
- */
- this._unboundChildren = this.createCollection();
- /**
- * Template of this view.
- *
- * @member {ui.Template} ui.View#template
- */
- /**
- * Element of this view.
- *
- * @private
- * @member {HTMLElement} ui.View.#_element
- */
- /**
- * Cached {@link ui.Template} binder object specific for this instance.
- * See {@link ui.View#bindTemplate}.
- *
- * @private
- * @member {Object} ui.View.#_bindTemplate
- */
- }
- /**
- * Element of this view. The element is rendered on first reference
- * using {@link ui.View#template} definition.
- *
- * @type {HTMLElement}
- */
- get element() {
- if ( this._element ) {
- return this._element;
- }
- // No template means no element (a virtual view).
- if ( !this.template ) {
- return null;
- }
- return ( this._element = this.template.render() );
- }
- /**
- * @type {HTMLElement}
- */
- set element( el ) {
- this._element = el;
- }
- /**
- * Shorthand for {@link ui.Template#bind}, bound to {@link ui.View} on the first access.
- *
- * Cached {@link ui.Template#bind} object is stored in {@link ui.View.#_bindTemplate}.
- *
- * @method ui.View#bindTemplate
- */
- get bindTemplate() {
- if ( this._bindTemplate ) {
- return this._bindTemplate;
- }
- return ( this._bindTemplate = Template.bind( this, this ) );
- }
- /**
- * Creates a new collection of views, which can be used in this view instance
- * i.e. as a member of {@link ui.TemplateDefinition#children}.
- *
- * TODO: An example how to use created collection in a template definition.
- *
- * @returns {ui.ViewCollection} A new collection of view instances.
- */
- createCollection() {
- const collection = new ViewCollection();
- this._viewCollections.add( collection );
- return collection;
- }
- /**
- * Registers a new child view under this view instance. Once registered, a child
- * view is managed by its parent, including initialization ({@link ui.view#init})
- * and destruction ({@link ui.view#destroy}).
- *
- * @param {...ui.View} children Children views to be registered.
- */
- addChild( ...children ) {
- for ( let child of children ) {
- this._unboundChildren.add( child );
- }
- }
- /**
- * Initializes the view and child views located in {@link ui.View#_viewCollections}.
- *
- * @returns {Promise} A Promise resolved when the initialization process is finished.
- */
- init() {
- if ( this.ready ) {
- /**
- * This View has already been initialized.
- *
- * @error ui-view-init-reinit
- */
- throw new CKEditorError( 'ui-view-init-reinit: This View has already been initialized.' );
- }
- return Promise.resolve()
- // Initialize child views in #_viewCollections.
- .then( () => {
- const promises = [];
- for ( let collection of this._viewCollections ) {
- for ( let view of collection ) {
- promises.push( view.init() );
- }
- }
- return Promise.all( promises );
- } )
- // Spread the word that this view is ready!
- .then( () => {
- this.ready = true;
- } );
- }
- /**
- * Destroys the view instance and child views located in {@link ui.View#_viewCollections}.
- *
- * @returns {Promise} A Promise resolved when the destruction process is finished.
- */
- destroy() {
- this.stopListening();
- let promises = [];
- for ( let collection of this._viewCollections ) {
- for ( let view of collection ) {
- promises.push( view.destroy() );
- }
- }
- this._unboundChildren.clear();
- this._viewCollections.clear();
- if ( this.element ) {
- this.element.remove();
- }
- this.element = this.template = this.locale = this.t =
- this._viewCollections = this._unboundChildren = null;
- return Promise.all( promises );
- }
- }
- mix( View, DOMEmitterMixin );
- mix( View, ObservableMixin );
|