| 
									
										
										
										
											2016-06-23 09:47:54 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-23 09:42:19 -08:00
										 |  |  | import {CompileQueryMetadata, tokenReference} from '../compile_metadata'; | 
					
						
							| 
									
										
										
										
											2016-05-31 15:22:59 -07:00
										 |  |  | import {ListWrapper} from '../facade/collection'; | 
					
						
							| 
									
										
										
										
											2016-09-30 09:26:53 -07:00
										 |  |  | import {isPresent} from '../facade/lang'; | 
					
						
							| 
									
										
										
										
											2016-11-23 09:42:19 -08:00
										 |  |  | import {Identifiers, createIdentifier} from '../identifiers'; | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  | import * as o from '../output/output_ast'; | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import {CompileElement} from './compile_element'; | 
					
						
							|  |  |  | import {CompileMethod} from './compile_method'; | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  | import {CompileView} from './compile_view'; | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  | import {getPropertyInView} from './util'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ViewQueryValues { | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |   constructor(public view: CompileView, public values: Array<o.Expression|ViewQueryValues>) {} | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class CompileQuery { | 
					
						
							|  |  |  |   private _values: ViewQueryValues; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |   constructor( | 
					
						
							|  |  |  |       public meta: CompileQueryMetadata, public queryList: o.Expression, | 
					
						
							|  |  |  |       public ownerDirectiveExpression: o.Expression, public view: CompileView) { | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     this._values = new ViewQueryValues(view, []); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   addValue(value: o.Expression, view: CompileView) { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |     let currentView = view; | 
					
						
							|  |  |  |     const elPath: CompileElement[] = []; | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     while (isPresent(currentView) && currentView !== this.view) { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |       const parentEl = currentView.declarationElement; | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |       elPath.unshift(parentEl); | 
					
						
							|  |  |  |       currentView = parentEl.view; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |     const queryListForDirtyExpr = getPropertyInView(this.queryList, view, this.view); | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |     let viewValues = this._values; | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     elPath.forEach((el) => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |       const last = | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |           viewValues.values.length > 0 ? viewValues.values[viewValues.values.length - 1] : null; | 
					
						
							|  |  |  |       if (last instanceof ViewQueryValues && last.view === el.embeddedView) { | 
					
						
							|  |  |  |         viewValues = last; | 
					
						
							|  |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |         const newViewValues = new ViewQueryValues(el.embeddedView, []); | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |         viewValues.values.push(newViewValues); | 
					
						
							|  |  |  |         viewValues = newViewValues; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     viewValues.values.push(value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (elPath.length > 0) { | 
					
						
							|  |  |  |       view.dirtyParentQueriesMethod.addStmt( | 
					
						
							|  |  |  |           queryListForDirtyExpr.callMethod('setDirty', []).toStmt()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 08:16:45 -07:00
										 |  |  |   private _isStatic(): boolean { | 
					
						
							|  |  |  |     return !this._values.values.some(value => value instanceof ViewQueryValues); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-27 16:28:54 -08:00
										 |  |  |   generateStatements(targetStaticMethod: CompileMethod, targetDynamicMethod: CompileMethod) { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |     const values = createQueryValues(this._values); | 
					
						
							|  |  |  |     const updateStmts = [this.queryList.callMethod('reset', [o.literalArr(values)]).toStmt()]; | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     if (isPresent(this.ownerDirectiveExpression)) { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |       const valueExpr = this.meta.first ? this.queryList.prop('first') : this.queryList; | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |       updateStmts.push( | 
					
						
							|  |  |  |           this.ownerDirectiveExpression.prop(this.meta.propertyName).set(valueExpr).toStmt()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!this.meta.first) { | 
					
						
							|  |  |  |       updateStmts.push(this.queryList.callMethod('notifyOnChanges', []).toStmt()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-06-06 08:16:45 -07:00
										 |  |  |     if (this.meta.first && this._isStatic()) { | 
					
						
							|  |  |  |       // for queries that don't change and the user asked for a single element,
 | 
					
						
							|  |  |  |       // set it immediately. That is e.g. needed for querying for ViewContainerRefs, ...
 | 
					
						
							|  |  |  |       // we don't do this for QueryLists for now as this would break the timing when
 | 
					
						
							|  |  |  |       // we call QueryList listeners...
 | 
					
						
							|  |  |  |       targetStaticMethod.addStmts(updateStmts); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       targetDynamicMethod.addStmt(new o.IfStmt(this.queryList.prop('dirty'), updateStmts)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function createQueryValues(viewValues: ViewQueryValues): o.Expression[] { | 
					
						
							|  |  |  |   return ListWrapper.flatten(viewValues.values.map((entry) => { | 
					
						
							|  |  |  |     if (entry instanceof ViewQueryValues) { | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       return mapNestedViews( | 
					
						
							| 
									
										
										
										
											2016-11-01 11:12:25 -07:00
										 |  |  |           entry.view.declarationElement.viewContainer, entry.view, createQueryValues(entry)); | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       return <o.Expression>entry; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   })); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  | function mapNestedViews( | 
					
						
							| 
									
										
										
										
											2016-11-01 11:12:25 -07:00
										 |  |  |     viewContainer: o.Expression, view: CompileView, expressions: o.Expression[]): o.Expression { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |   const adjustedExpressions: o.Expression[] = expressions.map( | 
					
						
							| 
									
										
										
										
											2016-10-04 15:57:37 -07:00
										 |  |  |       (expr) => o.replaceVarInExpression(o.THIS_EXPR.name, o.variable('nestedView'), expr)); | 
					
						
							| 
									
										
										
										
											2016-11-01 11:12:25 -07:00
										 |  |  |   return viewContainer.callMethod('mapNestedViews', [ | 
					
						
							| 
									
										
										
										
											2016-07-13 10:55:23 -07:00
										 |  |  |     o.variable(view.className), | 
					
						
							|  |  |  |     o.fn( | 
					
						
							|  |  |  |         [new o.FnParam('nestedView', view.classType)], | 
					
						
							|  |  |  |         [new o.ReturnStatement(o.literalArr(adjustedExpressions))], o.DYNAMIC_TYPE) | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |   ]); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  | export function createQueryList( | 
					
						
							|  |  |  |     query: CompileQueryMetadata, directiveInstance: o.Expression, propertyName: string, | 
					
						
							|  |  |  |     compileView: CompileView): o.Expression { | 
					
						
							| 
									
										
										
										
											2016-08-24 17:39:49 -07:00
										 |  |  |   compileView.fields.push(new o.ClassField( | 
					
						
							| 
									
										
										
										
											2016-11-23 09:42:19 -08:00
										 |  |  |       propertyName, o.importType(createIdentifier(Identifiers.QueryList), [o.DYNAMIC_TYPE]))); | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |   const expr = o.THIS_EXPR.prop(propertyName); | 
					
						
							| 
									
										
										
										
											2016-05-25 14:29:06 -07:00
										 |  |  |   compileView.createMethod.addStmt( | 
					
						
							|  |  |  |       o.THIS_EXPR.prop(propertyName) | 
					
						
							| 
									
										
										
										
											2016-11-23 09:42:19 -08:00
										 |  |  |           .set(o.importExpr(createIdentifier(Identifiers.QueryList), [o.DYNAMIC_TYPE]).instantiate([ | 
					
						
							|  |  |  |           ])) | 
					
						
							| 
									
										
										
										
											2016-05-25 14:29:06 -07:00
										 |  |  |           .toStmt()); | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |   return expr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-29 08:52:25 -07:00
										 |  |  | export function addQueryToTokenMap(map: Map<any, CompileQuery[]>, query: CompileQuery) { | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |   query.meta.selectors.forEach((selector) => { | 
					
						
							| 
									
										
										
										
											2016-11-23 09:42:19 -08:00
										 |  |  |     let entry = map.get(tokenReference(selector)); | 
					
						
							| 
									
										
										
										
											2016-09-30 09:26:53 -07:00
										 |  |  |     if (!entry) { | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |       entry = []; | 
					
						
							| 
									
										
										
										
											2016-11-23 09:42:19 -08:00
										 |  |  |       map.set(tokenReference(selector), entry); | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |     entry.push(query); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } |