浏览代码

Aligned Template class to the View#render API. Changed type of Template#children (ViewCollection->Array). Implemented Template#getViews() generator.

Aleksander Nowodzinski 8 年之前
父节点
当前提交
600e608c8e
共有 2 个文件被更改,包括 102 次插入23 次删除
  1. 56 7
      packages/ckeditor5-ui/src/template.js
  2. 46 16
      packages/ckeditor5-ui/tests/template.js

+ 56 - 7
packages/ckeditor5-ui/src/template.js

@@ -103,7 +103,7 @@ export default class Template {
 		 *
 		 * **Note**: This property only makes sense when {@link #tag} is defined.
 		 *
-		 * @member {module:utils/collection~Collection.<module:ui/template~Template>} #children
+		 * @member {Array.<module:ui/template~Template>} #children
 		 */
 
 		/**
@@ -210,6 +210,50 @@ export default class Template {
 	}
 
 	/**
+	 * Returns an iterator which traverses the template in search of {@link module:ui/view~View}
+	 * instances and returns them one by one.
+	 *
+	 *		const viewFoo = new View();
+	 *		const viewBar = new View();
+	 *		const viewBaz = new View();
+	 *		const template = new Template( {
+	 *			tag: 'div',
+	 *			children: [
+	 *				viewFoo,
+	 *				{
+	 *					tag: 'div',
+	 *					children: [
+	 *						viewBar
+	 *					]
+	 *				},
+	 *				viewBaz
+	 *			]
+	 *		} );
+	 *
+	 *		// Logs: viewFoo, viewBar, viewBaz
+	 *		for ( const view of template.getViews() ) {
+	 *			console.log( view );
+	 *		}
+	 *
+	 * @returns {Iterator.<module:ui/view~View>}
+	 */
+	* getViews() {
+		function* search( def ) {
+			if ( def.children ) {
+				for ( const child of def.children ) {
+					if ( isView( child ) ) {
+						yield child;
+					} else {
+						yield* search( child );
+					}
+				}
+			}
+		}
+
+		yield* search( this );
+	}
+
+	/**
 	 * An entry point to the interface which binds DOM nodes to
 	 * {@link module:utils/observablemixin~Observable observables}.
 	 * There are two types of bindings:
@@ -305,7 +349,7 @@ export default class Template {
 	 *		} );
 	 *
 	 *		// Child extension.
-	 *		Template.extend( template.children.get( 0 ), {
+	 *		Template.extend( template.children[ 0 ], {
 	 *			attributes: {
 	 *				class: 'd'
 	 *			}
@@ -643,6 +687,7 @@ export default class Template {
 			if ( isViewCollection( child ) ) {
 				if ( !isApplying ) {
 					child.setParent( node );
+					child.render();
 
 					for ( const view of child ) {
 						container.appendChild( view.element );
@@ -650,6 +695,10 @@ export default class Template {
 				}
 			} else if ( isView( child ) ) {
 				if ( !isApplying ) {
+					if ( !child.isRendered ) {
+						child.render();
+					}
+
 					container.appendChild( child.element );
 				}
 			} else {
@@ -1117,17 +1166,17 @@ function normalize( def ) {
 			normalizeAttributes( def.attributes );
 		}
 
-		const children = new ViewCollection();
+		const children = [];
 
 		if ( def.children ) {
 			if ( isViewCollection( def.children ) ) {
-				children.add( def.children );
+				children.push( def.children );
 			} else {
 				for ( const child of def.children ) {
 					if ( isTemplate( child ) || isView( child ) ) {
-						children.add( child );
+						children.push( child );
 					} else {
-						children.add( new Template( child ) );
+						children.push( new Template( child ) );
 					}
 				}
 			}
@@ -1336,7 +1385,7 @@ function extendTemplate( template, def ) {
 		let childIndex = 0;
 
 		for ( const childDef of def.children ) {
-			extendTemplate( template.children.get( childIndex++ ), childDef );
+			extendTemplate( template.children[ childIndex++ ], childDef );
 		}
 	}
 }

+ 46 - 16
packages/ckeditor5-ui/tests/template.js

@@ -13,7 +13,6 @@ import Model from '../src/model';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
 import DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';
-import Collection from '@ckeditor/ckeditor5-utils/src/collection';
 import normalizeHtml from '@ckeditor/ckeditor5-utils/tests/_utils/normalizehtml';
 import log from '@ckeditor/ckeditor5-utils/src/log';
 
@@ -67,11 +66,11 @@ describe( 'Template', () => {
 			expect( tpl.attributes.c[ 0 ].value[ 0 ] ).to.be.instanceof( TemplateToBinding );
 
 			expect( tpl.children ).to.have.length( 4 );
-			expect( tpl.children.get( 0 ).text[ 0 ] ).to.equal( 'content' );
-			expect( tpl.children.get( 1 ).text[ 0 ] ).to.be.instanceof( TemplateToBinding );
-			expect( tpl.children.get( 2 ).text[ 0 ] ).to.equal( 'abc' );
-			expect( tpl.children.get( 3 ).text[ 0 ] ).to.equal( 'a' );
-			expect( tpl.children.get( 3 ).text[ 1 ] ).to.equal( 'b' );
+			expect( tpl.children[ 0 ].text[ 0 ] ).to.equal( 'content' );
+			expect( tpl.children[ 1 ].text[ 0 ] ).to.be.instanceof( TemplateToBinding );
+			expect( tpl.children[ 2 ].text[ 0 ] ).to.equal( 'abc' );
+			expect( tpl.children[ 3 ].text[ 0 ] ).to.equal( 'a' );
+			expect( tpl.children[ 3 ].text[ 1 ] ).to.equal( 'b' );
 
 			expect( tpl.eventListeners[ 'a@span' ][ 0 ] ).to.be.instanceof( TemplateToBinding );
 			expect( tpl.eventListeners[ 'b@span' ][ 0 ] ).to.be.instanceof( TemplateToBinding );
@@ -92,8 +91,9 @@ describe( 'Template', () => {
 				text: 'foo'
 			} );
 
-			expect( elementTpl.children ).to.be.instanceof( Collection );
+			expect( elementTpl.children ).to.be.an( 'array' );
 			expect( elementTpl.children ).to.have.length( 0 );
+
 			// Text will never have children.
 			expect( textTpl.children ).to.be.undefined;
 		} );
@@ -114,12 +114,12 @@ describe( 'Template', () => {
 
 			expect( def.attributes ).to.not.equal( tpl.attributes );
 			expect( def.children ).to.not.equal( tpl.children );
-			expect( def.children[ 0 ] ).to.not.equal( tpl.children.get( 0 ) );
+			expect( def.children[ 0 ] ).to.not.equal( tpl.children[ 0 ] );
 			expect( def.attributes.a ).to.equal( 'foo' );
 			expect( def.children[ 0 ].tag ).to.equal( 'span' );
 
 			expect( tpl.attributes.a[ 0 ] ).to.equal( 'foo' );
-			expect( tpl.children.get( 0 ).tag ).to.equal( 'span' );
+			expect( tpl.children[ 0 ].tag ).to.equal( 'span' );
 		} );
 	} );
 
@@ -448,8 +448,8 @@ describe( 'Template', () => {
 					children: [ v1, v2 ]
 				} );
 
-				expect( tpl.children.get( 0 ) ).to.equal( v1 );
-				expect( tpl.children.get( 1 ) ).to.equal( v2 );
+				expect( tpl.children[ 0 ] ).to.equal( v1 );
+				expect( tpl.children[ 1 ] ).to.equal( v2 );
 
 				const rendered = tpl.render();
 
@@ -562,9 +562,9 @@ describe( 'Template', () => {
 				} );
 
 				// Make sure child instances weren't cloned.
-				expect( tpl.children.get( 0 ) ).to.equal( childTplA );
-				expect( tpl.children.get( 1 ) ).to.equal( childTplB );
-				expect( tpl.children.get( 2 ) ).to.equal( childTplC );
+				expect( tpl.children[ 0 ] ).to.equal( childTplA );
+				expect( tpl.children[ 1 ] ).to.equal( childTplB );
+				expect( tpl.children[ 2 ] ).to.equal( childTplC );
 
 				expect( normalizeHtml( tpl.render().outerHTML ) ).to.equal(
 					'<p><a></a><b></b><i>foo</i></p>'
@@ -1441,6 +1441,36 @@ describe( 'Template', () => {
 		} );
 	} );
 
+	describe( 'getViews()', () => {
+		it( 'returns iterator', () => {
+			const template = new Template( {} );
+
+			expect( template.getViews().next ).to.be.a( 'function' );
+			expect( Array.from( template.getViews() ) ).to.have.length( 0 );
+		} );
+
+		it( 'returns all child views', () => {
+			const viewA = new View();
+			const viewB = new View();
+			const viewC = new View();
+			const template = new Template( {
+				tag: 'div',
+				children: [
+					viewA,
+					{
+						tag: 'div',
+						children: [
+							viewB
+						]
+					},
+					viewC
+				]
+			} );
+
+			expect( Array.from( template.getViews() ) ).to.have.members( [ viewA, viewB, viewC ] );
+		} );
+	} );
+
 	describe( 'bind()', () => {
 		it( 'returns object', () => {
 			expect( Template.bind() ).to.be.an( 'object' );
@@ -2739,7 +2769,7 @@ describe( 'Template', () => {
 					]
 				} );
 
-				Template.extend( template.children.get( 0 ), {
+				Template.extend( template.children[ 0 ], {
 					attributes: {
 						class: 'bar'
 					}
@@ -2773,7 +2803,7 @@ describe( 'Template', () => {
 					]
 				} );
 
-				Template.extend( template.children.get( 0 ), {
+				Template.extend( template.children[ 0 ], {
 					attributes: {
 						class: 'B',
 					},