| 
									
										
										
										
											2017-01-25 13:45:07 -08: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
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import {ElementRef} from '../linker/element_ref'; | 
					
						
							|  |  |  | import {QueryList} from '../linker/query_list'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-21 13:36:42 -07:00
										 |  |  | import {NodeDef, NodeFlags, QueryBindingDef, QueryBindingType, QueryDef, QueryValueType, ViewData, asElementData, asProviderData, asQueryList} from './types'; | 
					
						
							|  |  |  | import {declaredViewContainer, filterQueryId, isEmbeddedView} from './util'; | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export function queryDef( | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |     flags: NodeFlags, id: number, bindings: {[propName: string]: QueryBindingType}): NodeDef { | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |   let bindingDefs: QueryBindingDef[] = []; | 
					
						
							|  |  |  |   for (let propName in bindings) { | 
					
						
							|  |  |  |     const bindingType = bindings[propName]; | 
					
						
							|  |  |  |     bindingDefs.push({propName, bindingType}); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     // will bet set by the view definition
 | 
					
						
							| 
									
										
										
										
											2017-03-29 09:34:45 -07:00
										 |  |  |     index: -1, | 
					
						
							|  |  |  |     parent: null, | 
					
						
							|  |  |  |     renderParent: null, | 
					
						
							|  |  |  |     bindingIndex: -1, | 
					
						
							|  |  |  |     outputIndex: -1, | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |     // regular values
 | 
					
						
							|  |  |  |     flags, | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |     childFlags: 0, | 
					
						
							| 
									
										
										
										
											2017-02-27 13:00:49 -08:00
										 |  |  |     directChildFlags: 0, | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |     childMatchedQueries: 0, | 
					
						
							| 
									
										
										
										
											2017-03-29 09:34:45 -07:00
										 |  |  |     ngContentIndex: -1, | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |     matchedQueries: {}, | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |     matchedQueryIds: 0, | 
					
						
							|  |  |  |     references: {}, | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |     childCount: 0, | 
					
						
							|  |  |  |     bindings: [], | 
					
						
							| 
									
										
										
										
											2017-03-17 09:23:28 -07:00
										 |  |  |     bindingFlags: 0, | 
					
						
							| 
									
										
										
										
											2017-02-21 13:56:56 -08:00
										 |  |  |     outputs: [], | 
					
						
							| 
									
										
										
										
											2017-03-29 09:34:45 -07:00
										 |  |  |     element: null, | 
					
						
							|  |  |  |     provider: null, | 
					
						
							|  |  |  |     text: null, | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |     query: {id, filterId: filterQueryId(id), bindings: bindingDefs}, | 
					
						
							| 
									
										
										
										
											2017-03-29 09:34:45 -07:00
										 |  |  |     ngContent: null | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function createQuery(): QueryList<any> { | 
					
						
							|  |  |  |   return new QueryList(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  | export function dirtyParentQueries(view: ViewData) { | 
					
						
							|  |  |  |   const queryIds = view.def.nodeMatchedQueries; | 
					
						
							|  |  |  |   while (view.parent && isEmbeddedView(view)) { | 
					
						
							| 
									
										
										
										
											2017-03-29 09:34:45 -07:00
										 |  |  |     let tplDef = view.parentNodeDef !; | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |     view = view.parent; | 
					
						
							|  |  |  |     // content queries
 | 
					
						
							|  |  |  |     const end = tplDef.index + tplDef.childCount; | 
					
						
							|  |  |  |     for (let i = 0; i <= end; i++) { | 
					
						
							|  |  |  |       const nodeDef = view.def.nodes[i]; | 
					
						
							| 
									
										
										
										
											2017-02-27 09:14:18 -08:00
										 |  |  |       if ((nodeDef.flags & NodeFlags.TypeContentQuery) && | 
					
						
							|  |  |  |           (nodeDef.flags & NodeFlags.DynamicQuery) && | 
					
						
							| 
									
										
										
										
											2017-03-29 09:34:45 -07:00
										 |  |  |           (nodeDef.query !.filterId & queryIds) === nodeDef.query !.filterId) { | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |         asQueryList(view, i).setDirty(); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-02-27 09:14:18 -08:00
										 |  |  |       if ((nodeDef.flags & NodeFlags.TypeElement && i + nodeDef.childCount < tplDef.index) || | 
					
						
							|  |  |  |           !(nodeDef.childFlags & NodeFlags.TypeContentQuery) || | 
					
						
							|  |  |  |           !(nodeDef.childFlags & NodeFlags.DynamicQuery)) { | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |         // skip elements that don't contain the template element or no query.
 | 
					
						
							|  |  |  |         i += nodeDef.childCount; | 
					
						
							| 
									
										
										
										
											2017-02-09 14:59:57 -08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // view queries
 | 
					
						
							| 
									
										
										
										
											2017-02-27 09:14:18 -08:00
										 |  |  |   if (view.def.nodeFlags & NodeFlags.TypeViewQuery) { | 
					
						
							| 
									
										
										
										
											2017-02-17 08:56:36 -08:00
										 |  |  |     for (let i = 0; i < view.def.nodes.length; i++) { | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |       const nodeDef = view.def.nodes[i]; | 
					
						
							| 
									
										
										
										
											2017-02-27 09:14:18 -08:00
										 |  |  |       if ((nodeDef.flags & NodeFlags.TypeViewQuery) && (nodeDef.flags & NodeFlags.DynamicQuery)) { | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |         asQueryList(view, i).setDirty(); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-02-17 08:56:36 -08:00
										 |  |  |       // only visit the root nodes
 | 
					
						
							|  |  |  |       i += nodeDef.childCount; | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function checkAndUpdateQuery(view: ViewData, nodeDef: NodeDef) { | 
					
						
							|  |  |  |   const queryList = asQueryList(view, nodeDef.index); | 
					
						
							|  |  |  |   if (!queryList.dirty) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-17 08:56:36 -08:00
										 |  |  |   let directiveInstance: any; | 
					
						
							| 
									
										
										
										
											2017-03-29 09:34:45 -07:00
										 |  |  |   let newValues: any[] = undefined !; | 
					
						
							| 
									
										
										
										
											2017-02-27 09:14:18 -08:00
										 |  |  |   if (nodeDef.flags & NodeFlags.TypeContentQuery) { | 
					
						
							| 
									
										
										
										
											2017-03-29 09:34:45 -07:00
										 |  |  |     const elementDef = nodeDef.parent !.parent !; | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |     newValues = calcQueryValues( | 
					
						
							| 
									
										
										
										
											2017-03-29 09:34:45 -07:00
										 |  |  |         view, elementDef.index, elementDef.index + elementDef.childCount, nodeDef.query !, []); | 
					
						
							|  |  |  |     directiveInstance = asProviderData(view, nodeDef.parent !.index).instance; | 
					
						
							| 
									
										
										
										
											2017-02-27 09:14:18 -08:00
										 |  |  |   } else if (nodeDef.flags & NodeFlags.TypeViewQuery) { | 
					
						
							| 
									
										
										
										
											2017-03-29 09:34:45 -07:00
										 |  |  |     newValues = calcQueryValues(view, 0, view.def.nodes.length - 1, nodeDef.query !, []); | 
					
						
							| 
									
										
										
										
											2017-02-17 08:56:36 -08:00
										 |  |  |     directiveInstance = view.component; | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |   } | 
					
						
							|  |  |  |   queryList.reset(newValues); | 
					
						
							| 
									
										
										
										
											2017-03-29 09:34:45 -07:00
										 |  |  |   const bindings = nodeDef.query !.bindings; | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |   let notify = false; | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |   for (let i = 0; i < bindings.length; i++) { | 
					
						
							|  |  |  |     const binding = bindings[i]; | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |     let boundValue: any; | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |     switch (binding.bindingType) { | 
					
						
							|  |  |  |       case QueryBindingType.First: | 
					
						
							|  |  |  |         boundValue = queryList.first; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case QueryBindingType.All: | 
					
						
							|  |  |  |         boundValue = queryList; | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |         notify = true; | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-17 08:56:36 -08:00
										 |  |  |     directiveInstance[binding.propName] = boundValue; | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |   if (notify) { | 
					
						
							|  |  |  |     queryList.notifyOnChanges(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function calcQueryValues( | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |     view: ViewData, startIndex: number, endIndex: number, queryDef: QueryDef, | 
					
						
							|  |  |  |     values: any[]): any[] { | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |   for (let i = startIndex; i <= endIndex; i++) { | 
					
						
							|  |  |  |     const nodeDef = view.def.nodes[i]; | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |     const valueType = nodeDef.matchedQueries[queryDef.id]; | 
					
						
							|  |  |  |     if (valueType != null) { | 
					
						
							|  |  |  |       values.push(getQueryValue(view, nodeDef, valueType)); | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-03-29 09:34:45 -07:00
										 |  |  |     if (nodeDef.flags & NodeFlags.TypeElement && nodeDef.element !.template && | 
					
						
							|  |  |  |         (nodeDef.element !.template !.nodeMatchedQueries & queryDef.filterId) === | 
					
						
							|  |  |  |             queryDef.filterId) { | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |       // check embedded views that were attached at the place of their template.
 | 
					
						
							|  |  |  |       const elementData = asElementData(view, i); | 
					
						
							| 
									
										
										
										
											2017-03-13 10:44:12 -07:00
										 |  |  |       if (nodeDef.flags & NodeFlags.EmbeddedViews) { | 
					
						
							| 
									
										
										
										
											2017-03-29 09:34:45 -07:00
										 |  |  |         const embeddedViews = elementData.viewContainer !._embeddedViews; | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |         for (let k = 0; k < embeddedViews.length; k++) { | 
					
						
							|  |  |  |           const embeddedView = embeddedViews[k]; | 
					
						
							|  |  |  |           const dvc = declaredViewContainer(embeddedView); | 
					
						
							|  |  |  |           if (dvc && dvc === elementData) { | 
					
						
							|  |  |  |             calcQueryValues(embeddedView, 0, embeddedView.def.nodes.length - 1, queryDef, values); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-03-13 10:44:12 -07:00
										 |  |  |       const projectedViews = elementData.template._projectedViews; | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |       if (projectedViews) { | 
					
						
							|  |  |  |         for (let k = 0; k < projectedViews.length; k++) { | 
					
						
							|  |  |  |           const projectedView = projectedViews[k]; | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |           calcQueryValues(projectedView, 0, projectedView.def.nodes.length - 1, queryDef, values); | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  |     if ((nodeDef.childMatchedQueries & queryDef.filterId) !== queryDef.filterId) { | 
					
						
							|  |  |  |       // if no child matches the query, skip the children.
 | 
					
						
							| 
									
										
										
										
											2017-01-25 13:45:07 -08:00
										 |  |  |       i += nodeDef.childCount; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return values; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-01-26 17:07:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-15 08:36:49 -08:00
										 |  |  | export function getQueryValue( | 
					
						
							|  |  |  |     view: ViewData, nodeDef: NodeDef, queryValueType: QueryValueType): any { | 
					
						
							| 
									
										
										
										
											2017-01-26 17:07:37 -08:00
										 |  |  |   if (queryValueType != null) { | 
					
						
							|  |  |  |     // a match
 | 
					
						
							|  |  |  |     let value: any; | 
					
						
							|  |  |  |     switch (queryValueType) { | 
					
						
							|  |  |  |       case QueryValueType.RenderElement: | 
					
						
							|  |  |  |         value = asElementData(view, nodeDef.index).renderElement; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case QueryValueType.ElementRef: | 
					
						
							|  |  |  |         value = new ElementRef(asElementData(view, nodeDef.index).renderElement); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case QueryValueType.TemplateRef: | 
					
						
							| 
									
										
										
										
											2017-03-13 10:44:12 -07:00
										 |  |  |         value = asElementData(view, nodeDef.index).template; | 
					
						
							| 
									
										
										
										
											2017-01-26 17:07:37 -08:00
										 |  |  |         break; | 
					
						
							|  |  |  |       case QueryValueType.ViewContainerRef: | 
					
						
							| 
									
										
										
										
											2017-03-13 10:44:12 -07:00
										 |  |  |         value = asElementData(view, nodeDef.index).viewContainer; | 
					
						
							| 
									
										
										
										
											2017-01-26 17:07:37 -08:00
										 |  |  |         break; | 
					
						
							|  |  |  |       case QueryValueType.Provider: | 
					
						
							|  |  |  |         value = asProviderData(view, nodeDef.index).instance; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return value; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
											  
											
												perf: switch angular to use StaticInjector instead of ReflectiveInjector
This change allows ReflectiveInjector to be tree shaken resulting
in not needed Reflect polyfil and smaller bundles.
Code savings for HelloWorld using Closure:
Reflective: bundle.js:  105,864(34,190 gzip)
    Static: bundle.js:  154,889(33,555 gzip)
                            645( 2%)
BREAKING CHANGE:
`platformXXXX()` no longer accepts providers which depend on reflection.
Specifically the method signature when from `Provider[]` to
`StaticProvider[]`.
Example:
Before:
```
[
  MyClass,
  {provide: ClassA, useClass: SubClassA}
]
```
After:
```
[
  {provide: MyClass, deps: [Dep1,...]},
  {provide: ClassA, useClass: SubClassA, deps: [Dep1,...]}
]
```
NOTE: This only applies to platform creation and providers for the JIT
compiler. It does not apply to `@Compotent` or `@NgModule` provides
declarations.
Benchpress note: Previously Benchpress also supported reflective
provides, which now require static providers.
DEPRECATION:
- `ReflectiveInjector` is now deprecated as it will be remove. Use
  `Injector.create` as a replacement.
closes #18496
											
										 
											2017-08-03 12:33:29 -07:00
										 |  |  | } |