| 
									
										
										
										
											2018-08-29 13:52:03 -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
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | import './ng_dev_mode'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  | import {assertDomNode} from './assert'; | 
					
						
							| 
									
										
										
										
											2018-11-15 08:43:56 -08:00
										 |  |  | import {EMPTY_ARRAY} from './definition'; | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  | import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context'; | 
					
						
							| 
									
										
										
										
											2018-10-12 18:49:00 -07:00
										 |  |  | import {TNode, TNodeFlags} from './interfaces/node'; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | import {RElement} from './interfaces/renderer'; | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  | import {CONTEXT, HEADER_OFFSET, HOST, LView, TVIEW} from './interfaces/view'; | 
					
						
							| 
									
										
										
										
											2018-10-12 18:49:00 -07:00
										 |  |  | import {getComponentViewByIndex, getNativeByTNode, readElementValue, readPatchedData} from './util'; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-15 08:43:56 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | /** Returns the matching `LContext` data for a given DOM node, directive or component instance. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This function will examine the provided DOM element, component, or directive instance\'s | 
					
						
							|  |  |  |  * monkey-patched property to derive the `LContext` data. Once called then the monkey-patched | 
					
						
							|  |  |  |  * value will be that of the newly created `LContext`. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |  * If the monkey-patched value is the `LView` instance then the context value for that | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |  * target will be created and the monkey-patch reference will be updated. Therefore when this | 
					
						
							|  |  |  |  * function is called it may mutate the provided element\'s, component\'s or any of the associated | 
					
						
							|  |  |  |  * directive\'s monkey-patch values. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * If the monkey-patch value is not detected then the code will walk up the DOM until an element | 
					
						
							|  |  |  |  * is found which contains a monkey-patch reference. When that occurs then the provided element | 
					
						
							|  |  |  |  * will be updated with a new context (which is then returned). If the monkey-patch value is not | 
					
						
							|  |  |  |  * detected for a component/directive instance then it will throw an error (all components and | 
					
						
							|  |  |  |  * directives should be automatically monkey-patched by ivy). | 
					
						
							| 
									
										
										
										
											2018-11-15 08:43:56 -08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * @param target Component, Directive or DOM Node. | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |  */ | 
					
						
							|  |  |  | export function getContext(target: any): LContext|null { | 
					
						
							|  |  |  |   let mpValue = readPatchedData(target); | 
					
						
							|  |  |  |   if (mpValue) { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |     // only when it's an array is it considered an LView instance
 | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |     // ... otherwise it's an already constructed LContext instance
 | 
					
						
							|  |  |  |     if (Array.isArray(mpValue)) { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |       const lView: LView = mpValue !; | 
					
						
							| 
									
										
										
										
											2018-10-04 20:40:39 -07:00
										 |  |  |       let nodeIndex: number; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |       let component: any = undefined; | 
					
						
							|  |  |  |       let directives: any[]|null|undefined = undefined; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (isComponentInstance(target)) { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |         nodeIndex = findViaComponent(lView, target); | 
					
						
							| 
									
										
										
										
											2018-10-04 20:40:39 -07:00
										 |  |  |         if (nodeIndex == -1) { | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |           throw new Error('The provided component was not found in the application'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         component = target; | 
					
						
							|  |  |  |       } else if (isDirectiveInstance(target)) { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |         nodeIndex = findViaDirective(lView, target); | 
					
						
							| 
									
										
										
										
											2018-10-04 20:40:39 -07:00
										 |  |  |         if (nodeIndex == -1) { | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |           throw new Error('The provided directive was not found in the application'); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |         directives = getDirectivesAtNodeIndex(nodeIndex, lView, false); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |         nodeIndex = findViaNativeElement(lView, target as RElement); | 
					
						
							| 
									
										
										
										
											2018-10-04 20:40:39 -07:00
										 |  |  |         if (nodeIndex == -1) { | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |           return null; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // the goal is not to fill the entire context full of data because the lookups
 | 
					
						
							|  |  |  |       // are expensive. Instead, only the target data (the element, compontent or
 | 
					
						
							|  |  |  |       // directive details) are filled into the context. If called multiple times
 | 
					
						
							|  |  |  |       // with different target values then the missing target data will be filled in.
 | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |       const native = readElementValue(lView[nodeIndex]); | 
					
						
							| 
									
										
										
										
											2018-10-12 18:49:00 -07:00
										 |  |  |       const existingCtx = readPatchedData(native); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |       const context: LContext = (existingCtx && !Array.isArray(existingCtx)) ? | 
					
						
							|  |  |  |           existingCtx : | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |           createLContext(lView, nodeIndex, native); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // only when the component has been discovered then update the monkey-patch
 | 
					
						
							|  |  |  |       if (component && context.component === undefined) { | 
					
						
							|  |  |  |         context.component = component; | 
					
						
							|  |  |  |         attachPatchData(context.component, context); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // only when the directives have been discovered then update the monkey-patch
 | 
					
						
							| 
									
										
										
										
											2018-10-04 20:40:39 -07:00
										 |  |  |       if (directives && context.directives === undefined) { | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |         context.directives = directives; | 
					
						
							|  |  |  |         for (let i = 0; i < directives.length; i++) { | 
					
						
							|  |  |  |           attachPatchData(directives[i], context); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       attachPatchData(context.native, context); | 
					
						
							|  |  |  |       mpValue = context; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     const rElement = target as RElement; | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |     ngDevMode && assertDomNode(rElement); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // if the context is not found then we need to traverse upwards up the DOM
 | 
					
						
							|  |  |  |     // to find the nearest element that has already been monkey patched with data
 | 
					
						
							|  |  |  |     let parent = rElement as any; | 
					
						
							|  |  |  |     while (parent = parent.parentNode) { | 
					
						
							|  |  |  |       const parentContext = readPatchedData(parent); | 
					
						
							|  |  |  |       if (parentContext) { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |         let lView: LView|null; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |         if (Array.isArray(parentContext)) { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |           lView = parentContext as LView; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |           lView = parentContext.lView; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // the edge of the app was also reached here through another means
 | 
					
						
							|  |  |  |         // (maybe because the DOM was changed manually).
 | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |         if (!lView) { | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |           return null; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |         const index = findViaNativeElement(lView, rElement); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |         if (index >= 0) { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |           const native = readElementValue(lView[index]); | 
					
						
							|  |  |  |           const context = createLContext(lView, index, native); | 
					
						
							| 
									
										
										
										
											2018-10-12 18:49:00 -07:00
										 |  |  |           attachPatchData(native, context); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |           mpValue = context; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return (mpValue as LContext) || null; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Creates an empty instance of a `LContext` context | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  | function createLContext(lView: LView, nodeIndex: number, native: RElement): LContext { | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |   return { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |     lView, | 
					
						
							| 
									
										
										
										
											2018-11-15 08:43:56 -08:00
										 |  |  |     nodeIndex, | 
					
						
							|  |  |  |     native, | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |     component: undefined, | 
					
						
							|  |  |  |     directives: undefined, | 
					
						
							| 
									
										
										
										
											2018-09-26 15:21:58 +02:00
										 |  |  |     localRefs: undefined, | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  |  * Takes a component instance and returns the view for that component. | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  |  * @param componentInstance | 
					
						
							|  |  |  |  * @returns The component's view | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  | export function getComponentViewByInstance(componentInstance: {}): LView { | 
					
						
							|  |  |  |   let lView = readPatchedData(componentInstance); | 
					
						
							|  |  |  |   let view: LView; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |   if (Array.isArray(lView)) { | 
					
						
							|  |  |  |     const nodeIndex = findViaComponent(lView, componentInstance); | 
					
						
							|  |  |  |     view = getComponentViewByIndex(nodeIndex, lView); | 
					
						
							|  |  |  |     const context = createLContext(lView, nodeIndex, view[HOST] as RElement); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |     context.component = componentInstance; | 
					
						
							|  |  |  |     attachPatchData(componentInstance, context); | 
					
						
							|  |  |  |     attachPatchData(context.native, context); | 
					
						
							|  |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |     const context = lView as any as LContext; | 
					
						
							|  |  |  |     view = getComponentViewByIndex(context.nodeIndex, context.lView); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  |   return view; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Assigns the given data to the given target (which could be a component, | 
					
						
							|  |  |  |  * directive or DOM node instance) using monkey-patching. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  | export function attachPatchData(target: any, data: LView | LContext) { | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |   target[MONKEY_PATCH_KEY_NAME] = data; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function isComponentInstance(instance: any): boolean { | 
					
						
							|  |  |  |   return instance && instance.constructor && instance.constructor.ngComponentDef; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function isDirectiveInstance(instance: any): boolean { | 
					
						
							|  |  |  |   return instance && instance.constructor && instance.constructor.ngDirectiveDef; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |  * Locates the element within the given LView and returns the matching index | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  | function findViaNativeElement(lView: LView, target: RElement): number { | 
					
						
							|  |  |  |   let tNode = lView[TVIEW].firstChild; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |   while (tNode) { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |     const native = getNativeByTNode(tNode, lView) !; | 
					
						
							| 
									
										
										
										
											2018-10-12 18:49:00 -07:00
										 |  |  |     if (native === target) { | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |       return tNode.index; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     tNode = traverseNextElement(tNode); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Locates the next tNode (child, sibling or parent). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function traverseNextElement(tNode: TNode): TNode|null { | 
					
						
							|  |  |  |   if (tNode.child) { | 
					
						
							|  |  |  |     return tNode.child; | 
					
						
							|  |  |  |   } else if (tNode.next) { | 
					
						
							|  |  |  |     return tNode.next; | 
					
						
							|  |  |  |   } else if (tNode.parent) { | 
					
						
							|  |  |  |     return tNode.parent.next || null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return null; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |  * Locates the component within the given LView and returns the matching index | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  | function findViaComponent(lView: LView, componentInstance: {}): number { | 
					
						
							|  |  |  |   const componentIndices = lView[TVIEW].components; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |   if (componentIndices) { | 
					
						
							|  |  |  |     for (let i = 0; i < componentIndices.length; i++) { | 
					
						
							|  |  |  |       const elementComponentIndex = componentIndices[i]; | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |       const componentView = getComponentViewByIndex(elementComponentIndex, lView); | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  |       if (componentView[CONTEXT] === componentInstance) { | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |         return elementComponentIndex; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |     const rootComponentView = getComponentViewByIndex(HEADER_OFFSET, lView); | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  |     const rootComponent = rootComponentView[CONTEXT]; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |     if (rootComponent === componentInstance) { | 
					
						
							|  |  |  |       // we are dealing with the root element here therefore we know that the
 | 
					
						
							|  |  |  |       // element is the very first element after the HEADER data in the lView
 | 
					
						
							|  |  |  |       return HEADER_OFFSET; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |  * Locates the directive within the given LView and returns the matching index | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  | function findViaDirective(lView: LView, directiveInstance: {}): number { | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |   // if a directive is monkey patched then it will (by default)
 | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |   // have a reference to the LView of the current view. The
 | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |   // element bound to the directive being search lives somewhere
 | 
					
						
							| 
									
										
										
										
											2018-10-04 20:40:39 -07:00
										 |  |  |   // in the view data. We loop through the nodes and check their
 | 
					
						
							|  |  |  |   // list of directives for the instance.
 | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |   let tNode = lView[TVIEW].firstChild; | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |   while (tNode) { | 
					
						
							|  |  |  |     const directiveIndexStart = getDirectiveStartIndex(tNode); | 
					
						
							|  |  |  |     const directiveIndexEnd = getDirectiveEndIndex(tNode, directiveIndexStart); | 
					
						
							|  |  |  |     for (let i = directiveIndexStart; i < directiveIndexEnd; i++) { | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |       if (lView[i] === directiveInstance) { | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |         return tNode.index; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |     tNode = traverseNextElement(tNode); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |   } | 
					
						
							|  |  |  |   return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |  * Returns a list of directives extracted from the given view based on the | 
					
						
							|  |  |  |  * provided list of directive index values. | 
					
						
							| 
									
										
										
										
											2018-09-24 14:51:54 -07:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |  * @param nodeIndex The node index | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |  * @param lView The target view data | 
					
						
							| 
									
										
										
										
											2018-10-05 21:23:41 -07:00
										 |  |  |  * @param includeComponents Whether or not to include components in returned directives | 
					
						
							| 
									
										
										
										
											2018-09-24 14:51:54 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-11-15 08:43:56 -08:00
										 |  |  | export function getDirectivesAtNodeIndex( | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |     nodeIndex: number, lView: LView, includeComponents: boolean): any[]|null { | 
					
						
							|  |  |  |   const tNode = lView[TVIEW].data[nodeIndex] as TNode; | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |   let directiveStartIndex = getDirectiveStartIndex(tNode); | 
					
						
							| 
									
										
										
										
											2018-11-15 08:43:56 -08:00
										 |  |  |   if (directiveStartIndex == 0) return EMPTY_ARRAY; | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |   const directiveEndIndex = getDirectiveEndIndex(tNode, directiveStartIndex); | 
					
						
							|  |  |  |   if (!includeComponents && tNode.flags & TNodeFlags.isComponent) directiveStartIndex++; | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |   return lView.slice(directiveStartIndex, directiveEndIndex); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  | export function getComponentAtNodeIndex(nodeIndex: number, lView: LView): {}|null { | 
					
						
							|  |  |  |   const tNode = lView[TVIEW].data[nodeIndex] as TNode; | 
					
						
							| 
									
										
										
										
											2018-11-15 08:43:56 -08:00
										 |  |  |   let directiveStartIndex = getDirectiveStartIndex(tNode); | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |   return tNode.flags & TNodeFlags.isComponent ? lView[directiveStartIndex] : null; | 
					
						
							| 
									
										
										
										
											2018-11-15 08:43:56 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-26 15:21:58 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Returns a map of local references (local reference name => element or directive instance) that | 
					
						
							|  |  |  |  * exist on a given element. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  | export function discoverLocalRefs(lView: LView, nodeIndex: number): {[key: string]: any}|null { | 
					
						
							|  |  |  |   const tNode = lView[TVIEW].data[nodeIndex] as TNode; | 
					
						
							| 
									
										
										
										
											2018-09-26 15:21:58 +02:00
										 |  |  |   if (tNode && tNode.localNames) { | 
					
						
							|  |  |  |     const result: {[key: string]: any} = {}; | 
					
						
							|  |  |  |     for (let i = 0; i < tNode.localNames.length; i += 2) { | 
					
						
							|  |  |  |       const localRefName = tNode.localNames[i]; | 
					
						
							|  |  |  |       const directiveIndex = tNode.localNames[i + 1] as number; | 
					
						
							| 
									
										
										
										
											2018-10-12 18:49:00 -07:00
										 |  |  |       result[localRefName] = | 
					
						
							| 
									
										
										
										
											2018-11-21 21:14:06 -08:00
										 |  |  |           directiveIndex === -1 ? getNativeByTNode(tNode, lView) ! : lView[directiveIndex]; | 
					
						
							| 
									
										
										
										
											2018-09-26 15:21:58 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return null; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-13 16:07:23 -07:00
										 |  |  | function getDirectiveStartIndex(tNode: TNode): number { | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |   // the tNode instances store a flag value which then has a
 | 
					
						
							|  |  |  |   // pointer which tells the starting index of where all the
 | 
					
						
							|  |  |  |   // active directives are in the master directive array
 | 
					
						
							| 
									
										
										
										
											2018-09-13 16:07:23 -07:00
										 |  |  |   return tNode.flags >> TNodeFlags.DirectiveStartingIndexShift; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-13 16:07:23 -07:00
										 |  |  | function getDirectiveEndIndex(tNode: TNode, startIndex: number): number { | 
					
						
							|  |  |  |   // The end value is also a part of the same flag
 | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |   // (see `TNodeFlags` to see how the flag bit shifting
 | 
					
						
							|  |  |  |   // values are used).
 | 
					
						
							| 
									
										
										
										
											2018-09-13 16:07:23 -07:00
										 |  |  |   const count = tNode.flags & TNodeFlags.DirectiveCountMask; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |   return count ? (startIndex + count) : -1; | 
					
						
							|  |  |  | } |