浏览代码

Aligned the ViewCollection class to the View#render API. Minor refactoring in View and Template classes.

Aleksander Nowodzinski 8 年之前
父节点
当前提交
20689140b2

+ 1 - 1
packages/ckeditor5-ui/src/template.js

@@ -687,8 +687,8 @@ export default class Template {
 			if ( isViewCollection( child ) ) {
 				if ( !isApplying ) {
 					child.setParent( node );
-					child.render();
 
+					// Note: ViewCollection renders its children.
 					for ( const view of child ) {
 						container.appendChild( view.element );
 					}

+ 0 - 3
packages/ckeditor5-ui/src/view.js

@@ -436,9 +436,6 @@ export default class View {
 			throw new CKEditorError( 'ui-view-render-already-rendered: This View has already been rendered.' );
 		}
 
-		// Render collections in #_viewCollections.
-		this._viewCollections.map( col => col.render() );
-
 		// Render #element of the view.
 		if ( this.template ) {
 			this.element = this.template.render();

+ 8 - 71
packages/ckeditor5-ui/src/viewcollection.js

@@ -23,16 +23,13 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
  *		const viewA = new ChildView( locale );
  *		const viewB = new ChildView( locale );
  *
- * View collection manages view {@link module:ui/view~View#element elements}:
+ * View collection renders and manages view {@link module:ui/view~View#element elements}:
  *
- *		// parentView.element.children == [ viewA.element, vievB.element ]
  *		collection.add( viewA );
  *		collection.add( viewB );
  *
- * It handles initialization of the children:
- *
- *		// viewA.ready == viewB.ready == true;
- *		collection.init();
+ *		console.log( parentView.element.firsChild ); // -> viewA.element
+ *		console.log( parentView.element.lastChild ); // -> viewB.element
  *
  * It {@link module:ui/viewcollection~ViewCollection#delegate propagates} DOM events too:
  *
@@ -67,6 +64,10 @@ export default class ViewCollection extends Collection {
 
 		// Handle {@link module:ui/view~View#element} in DOM when a new view is added to the collection.
 		this.on( 'add', ( evt, view, index ) => {
+			if ( !view.isRendered ) {
+				view.render();
+			}
+
 			if ( view.element && this._parentElement ) {
 				this._parentElement.insertBefore( view.element, this._parentElement.children[ index ] );
 			}
@@ -88,16 +89,6 @@ export default class ViewCollection extends Collection {
 		this.locale = locale;
 
 		/**
-		 * Set `true` when all views in the collection are {@link module:ui/view~View#ready}.
-		 * See the view {@link module:ui/view~View#init init} method.
-		 *
-		 * @readonly
-		 * @observable
-		 * @member {Boolean} #ready
-		 */
-		this.set( 'ready', false );
-
-		/**
 		 * A parent element within which child views are rendered and managed in DOM.
 		 *
 		 * @protected
@@ -107,65 +98,11 @@ export default class ViewCollection extends Collection {
 	}
 
 	/**
-	 * Initializes all child views in the collection by calling view {@link module:ui/view~View#init}
-	 * method.
-	 *
-	 * Once finished, sets {@link #ready} `true`.
-	 */
-	init() {
-		if ( this.ready ) {
-			/**
-			 * This ViewCollection has already been initialized.
-			 *
-			 * @error ui-viewcollection-init-reinit
-			 */
-			throw new CKEditorError( 'ui-viewcollection-init-reinit: This ViewCollection has already been initialized.' );
-		}
-
-		this.map( v => v.init() );
-
-		this.ready = true;
-	}
-
-	/**
 	 * Destroys the view collection along with child views.
 	 * See the view {@link module:ui/view~View#destroy} method.
 	 */
 	destroy() {
-		this.map( v => v.destroy() );
-	}
-
-	/**
-	 * Adds a new child view to the collection. If the collection is
-	 * {@link module:ui/viewcollection~ViewCollection#ready}, the child view is also
-	 * {@link module:ui/view~View#init initialized} when added.
-	 *
-	 * Additionally, if the {@link #setParent parent element} of the collection has been set, the
-	 * {@link module:ui/view~View#element element} of the view is also added in DOM,
-	 * reflecting the order of the collection.
-	 *
-	 *		const collection = new ViewCollection();
-	 *		const parentElement = document.querySelector( '#container' );
-	 *		collection.setParent( parentElement );
-	 *
-	 *		const viewA = new View();
-	 *		const viewB = new View();
-	 *
-	 *		// parentElement.children == [ viewA.element, vievB.element ]
-	 *		collection.add( viewA );
-	 *		collection.add( viewB );
-	 *
-	 * See the {@link #remove} method.
-	 *
-	 * @param {module:ui/view~View} view A child view.
-	 * @param {Number} [index] Index at which the child will be added to the collection.
-	 */
-	add( view, index ) {
-		super.add( view, index );
-
-		if ( this.ready && !view.ready ) {
-			view.init();
-		}
+		this.map( view => view.destroy() );
 	}
 
 	/**

+ 19 - 5
packages/ckeditor5-ui/tests/template.js

@@ -426,7 +426,7 @@ describe( 'Template', () => {
 
 			it( 'renders view children', () => {
 				const v1 = getView( {
-					tag: 'span',
+					tag: 'b',
 					attributes: {
 						class: [
 							'v1'
@@ -435,7 +435,7 @@ describe( 'Template', () => {
 				} );
 
 				const v2 = getView( {
-					tag: 'span',
+					tag: 'b',
 					attributes: {
 						class: [
 							'v2'
@@ -443,22 +443,36 @@ describe( 'Template', () => {
 					}
 				} );
 
+				const v3 = getView( {
+					tag: 'b',
+					attributes: {
+						class: [
+							'v3'
+						]
+					}
+				} );
+
+				v3.render();
+
 				const tpl = new Template( {
 					tag: 'p',
-					children: [ v1, v2 ]
+					children: [ v1, v2, v3 ]
 				} );
 
 				expect( tpl.children[ 0 ] ).to.equal( v1 );
 				expect( tpl.children[ 1 ] ).to.equal( v2 );
+				expect( tpl.children[ 2 ] ).to.equal( v3 );
 
 				const rendered = tpl.render();
 
-				expect( normalizeHtml( rendered.outerHTML ) ).to.equal( '<p><span class="v1"></span><span class="v2"></span></p>' );
+				expect( normalizeHtml( rendered.outerHTML ) )
+					.to.equal( '<p><b class="v1"></b><b class="v2"></b><b class="v3"></b></p>' );
 
 				// Make sure the child views will not re–render their elements but
 				// use ones rendered by the template instance above.
 				expect( v1.element ).to.equal( rendered.firstChild );
-				expect( v2.element ).to.equal( rendered.lastChild );
+				expect( v2.element ).to.equal( rendered.children[ 1 ] );
+				expect( v3.element ).to.equal( rendered.lastChild );
 			} );
 
 			it( 'renders view collection', () => {

+ 0 - 15
packages/ckeditor5-ui/tests/view.js

@@ -165,21 +165,6 @@ describe( 'View', () => {
 			view.render();
 			expect( view.isRendered ).to.be.true;
 		} );
-
-		it( 'calls render() on all view#_viewCollections', () => {
-			const view = new View();
-
-			const collectionA = view.createCollection();
-			const collectionB = view.createCollection();
-
-			const spyA = testUtils.sinon.spy( collectionA, 'render' );
-			const spyB = testUtils.sinon.spy( collectionB, 'render' );
-
-			view.render();
-			sinon.assert.calledOnce( spyA );
-			sinon.assert.calledOnce( spyB );
-			sinon.assert.callOrder( spyA, spyB );
-		} );
 	} );
 
 	describe( 'bind', () => {

+ 6 - 60
packages/ckeditor5-ui/tests/viewcollection.js

@@ -22,7 +22,6 @@ describe( 'ViewCollection', () => {
 	describe( 'constructor()', () => {
 		it( 'sets basic properties and attributes', () => {
 			expect( collection.locale ).to.be.undefined;
-			expect( collection.ready ).to.be.false;
 			expect( collection._parentElement ).to.be.null;
 			expect( collection._idProperty ).to.equal( 'viewUid' );
 		} );
@@ -46,7 +45,6 @@ describe( 'ViewCollection', () => {
 				} ).to.not.throw();
 
 				expect( () => {
-					collection.ready = true;
 					collection.add( viewA );
 					collection.remove( viewA );
 				} ).to.not.throw();
@@ -110,8 +108,7 @@ describe( 'ViewCollection', () => {
 				collection.add( viewC );
 				collection.remove( 1 );
 
-				// Finally init the view. Check what's in there.
-				view.init();
+				view.render();
 
 				expect( view.element.childNodes ).to.have.length( 2 );
 				expect( view.element.childNodes[ 0 ] ).to.equal( viewA.element );
@@ -120,45 +117,6 @@ describe( 'ViewCollection', () => {
 		} );
 	} );
 
-	describe( 'init()', () => {
-		it( 'should throw if already initialized', () => {
-			collection.init();
-
-			try {
-				collection.init();
-				throw new Error( 'This should not be executed.' );
-			} catch ( err ) {
-				expect( err ).to.be.instanceof( CKEditorError );
-				expect( err.message ).to.match( /ui-viewcollection-init-reinit/ );
-			}
-		} );
-
-		it( 'calls #init on all views in the collection', () => {
-			const viewA = new View();
-			const viewB = new View();
-
-			viewA.element = document.createElement( 'a' );
-			viewB.element = document.createElement( 'b' );
-
-			const spyA = testUtils.sinon.spy( viewA, 'init' );
-			const spyB = testUtils.sinon.spy( viewB, 'init' );
-
-			collection.setParent( document.body );
-
-			collection.add( viewA );
-			collection.add( viewB );
-
-			collection.init();
-			sinon.assert.calledOnce( spyA );
-			sinon.assert.calledOnce( spyB );
-			sinon.assert.callOrder( spyA, spyB );
-
-			expect( viewA.element.parentNode ).to.equal( collection._parentElement );
-			expect( viewA.element.nextSibling ).to.equal( viewB.element );
-			expect( collection.ready ).to.be.true;
-		} );
-	} );
-
 	describe( 'destroy()', () => {
 		it( 'calls #destroy on all views in the collection', () => {
 			const viewA = new View();
@@ -178,26 +136,14 @@ describe( 'ViewCollection', () => {
 	} );
 
 	describe( 'add()', () => {
-		it( 'initializes the new view in the collection', () => {
-			let view = new View();
-			let spy = testUtils.sinon.spy( view, 'init' );
-
-			expect( collection.ready ).to.be.false;
-			expect( view.ready ).to.be.false;
-
-			collection.add( view );
-			expect( collection.ready ).to.be.false;
-			expect( view.ready ).to.be.false;
-
-			sinon.assert.notCalled( spy );
-
-			view = new View();
-			spy = testUtils.sinon.spy( view, 'init' );
+		it( 'renders the new view in the collection', () => {
+			const view = new View();
+			const spy = testUtils.sinon.spy( view, 'render' );
 
-			collection.ready = true;
+			expect( view.isRendered ).to.be.false;
 
 			collection.add( view );
-			expect( view.ready ).to.be.true;
+			expect( view.isRendered ).to.be.true;
 			sinon.assert.calledOnce( spy );
 		} );