refactor(ivy): replace pNextOrParent with TNode props (#24752)
PR Close #24752
This commit is contained in:
		
							parent
							
								
									dc1f1295ee
								
							
						
					
					
						commit
						3a19f70d1c
					
				| @ -62,7 +62,6 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver | ||||
|   private _bindingCode: o.Statement[] = []; | ||||
|   private _postfixCode: o.Statement[] = []; | ||||
|   private _temporary = temporaryAllocator(this._prefixCode, TEMPORARY_NAME); | ||||
|   private _projectionDefinitionIndex = -1; | ||||
|   private _valueConverter: ValueConverter; | ||||
|   private _unsupported = unsupported; | ||||
|   private _bindingScope: BindingScope; | ||||
| @ -121,8 +120,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver | ||||
| 
 | ||||
|     // Output a `ProjectionDef` instruction when some `<ng-content>` are present
 | ||||
|     if (hasNgContent) { | ||||
|       this._projectionDefinitionIndex = this.allocateDataSlot(); | ||||
|       const parameters: o.Expression[] = [o.literal(this._projectionDefinitionIndex)]; | ||||
|       const parameters: o.Expression[] = []; | ||||
| 
 | ||||
|       // Only selectors with a non-default value are generated
 | ||||
|       if (ngContentSelectors.length > 1) { | ||||
| @ -217,10 +215,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver | ||||
|   visitContent(ngContent: t.Content) { | ||||
|     const slot = this.allocateDataSlot(); | ||||
|     const selectorIndex = ngContent.selectorIndex; | ||||
|     const parameters: o.Expression[] = [ | ||||
|       o.literal(slot), | ||||
|       o.literal(this._projectionDefinitionIndex), | ||||
|     ]; | ||||
|     const parameters: o.Expression[] = [o.literal(slot)]; | ||||
| 
 | ||||
|     const attributeAsList: string[] = []; | ||||
| 
 | ||||
|  | ||||
| @ -871,9 +871,9 @@ describe('compiler compliance', () => { | ||||
|           factory: function SimpleComponent_Factory() { return new SimpleComponent(); }, | ||||
|           template: function SimpleComponent_Template(rf: IDENT, ctx: IDENT) { | ||||
|             if (rf & 1) { | ||||
|               $r3$.ɵpD(0); | ||||
|               $r3$.ɵE(1, 'div'); | ||||
|               $r3$.ɵP(2, 0); | ||||
|               $r3$.ɵpD(); | ||||
|               $r3$.ɵE(0, 'div'); | ||||
|               $r3$.ɵP(1); | ||||
|               $r3$.ɵe(); | ||||
|             } | ||||
|           } | ||||
| @ -891,12 +891,12 @@ describe('compiler compliance', () => { | ||||
|           factory: function ComplexComponent_Factory() { return new ComplexComponent(); }, | ||||
|           template: function ComplexComponent_Template(rf: IDENT, ctx: IDENT) { | ||||
|             if (rf & 1) { | ||||
|               $r3$.ɵpD(0, $c1$, $c2$); | ||||
|               $r3$.ɵE(1, 'div', $c3$); | ||||
|               $r3$.ɵP(2, 0, 1); | ||||
|               $r3$.ɵpD($c1$, $c2$); | ||||
|               $r3$.ɵE(0, 'div', $c3$); | ||||
|               $r3$.ɵP(1, 1); | ||||
|               $r3$.ɵe(); | ||||
|               $r3$.ɵE(3, 'div', $c4$); | ||||
|               $r3$.ɵP(4, 0, 2); | ||||
|               $r3$.ɵE(2, 'div', $c4$); | ||||
|               $r3$.ɵP(3, 2); | ||||
|               $r3$.ɵe(); | ||||
|             } | ||||
|           } | ||||
| @ -1022,9 +1022,9 @@ describe('compiler compliance', () => { | ||||
|             template: function ContentQueryComponent_Template( | ||||
|                 rf: $RenderFlags$, ctx: $ContentQueryComponent$) { | ||||
|               if (rf & 1) { | ||||
|                 $r3$.ɵpD(0); | ||||
|                 $r3$.ɵE(1, 'div'); | ||||
|                 $r3$.ɵP(2, 0); | ||||
|                 $r3$.ɵpD(); | ||||
|                 $r3$.ɵE(0, 'div'); | ||||
|                 $r3$.ɵP(1); | ||||
|                 $r3$.ɵe(); | ||||
|               } | ||||
|             } | ||||
|  | ||||
| @ -9,7 +9,7 @@ | ||||
| import {assertEqual, assertLessThan} from './assert'; | ||||
| import {NO_CHANGE, bindingUpdated, createLNode, getPreviousOrParentNode, getRenderer, getViewData, load, resetApplicationState} from './instructions'; | ||||
| import {RENDER_PARENT} from './interfaces/container'; | ||||
| import {LContainerNode, LElementNode, LNode, TContainerNode, TNodeType} from './interfaces/node'; | ||||
| import {LContainerNode, LElementNode, LNode, TContainerNode, TElementNode, TNodeType} from './interfaces/node'; | ||||
| import {BINDING_INDEX, HEADER_OFFSET, TVIEW} from './interfaces/view'; | ||||
| import {appendChild, createTextNode, getParentLNode, removeChild} from './node_manipulation'; | ||||
| import {stringify} from './util'; | ||||
| @ -243,14 +243,17 @@ function appendI18nNode(node: LNode, parentNode: LNode, previousNode: LNode) { | ||||
|   // On first pass, re-organize node tree to put this node in the correct position.
 | ||||
|   const firstTemplatePass = node.view[TVIEW].firstTemplatePass; | ||||
|   if (firstTemplatePass) { | ||||
|     node.tNode.next = null; | ||||
|     if (previousNode === parentNode && node.tNode !== parentNode.tNode.child) { | ||||
|       node.tNode.next = parentNode.tNode.child; | ||||
|       parentNode.tNode.child = node.tNode; | ||||
|     } else if (previousNode !== parentNode && node.tNode !== previousNode.tNode.next) { | ||||
|       node.tNode.next = previousNode.tNode.next; | ||||
|       previousNode.tNode.next = node.tNode; | ||||
|     } else { | ||||
|       node.tNode.next = null; | ||||
|     } | ||||
| 
 | ||||
|     if (parentNode.view === node.view) node.tNode.parent = parentNode.tNode as TElementNode; | ||||
|   } | ||||
| 
 | ||||
|   // Template containers also have a comment node for the `ViewContainerRef` that should be moved
 | ||||
|  | ||||
| @ -14,20 +14,20 @@ import {assertDefined, assertEqual, assertLessThan, assertNotDefined, assertNotE | ||||
| import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors'; | ||||
| import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks'; | ||||
| import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container'; | ||||
| import {ComponentDefInternal, ComponentQuery, ComponentTemplate, DirectiveDefInternal, DirectiveDefListOrFactory, PipeDefListOrFactory, RenderFlags} from './interfaces/definition'; | ||||
| import {LInjector} from './interfaces/injector'; | ||||
| import {CssSelectorList, LProjection, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection'; | ||||
| import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LElementNode, LNode, LProjectionNode, LTextNode, LViewNode, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node'; | ||||
| import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection'; | ||||
| import {LQueries} from './interfaces/query'; | ||||
| import {ProceduralRenderer3, RComment, RElement, RText, Renderer3, RendererFactory3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer'; | ||||
| import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTEXT, CurrentMatchesList, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RootContext, SANITIZER, TAIL, TData, TVIEW, TView} from './interfaces/view'; | ||||
| 
 | ||||
| import {AttributeMarker, TAttributes, LContainerNode, LElementNode, LNode, TNodeType, TNodeFlags, LProjectionNode, LTextNode, LViewNode, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue, TElementNode,} from './interfaces/node'; | ||||
| import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert'; | ||||
| import {appendChild, insertView, appendProjectedNode, removeView, canInsertNativeNode, createTextNode, getNextLNode, getChildLNode, getParentLNode, getLViewChild} from './node_manipulation'; | ||||
| import {appendChild, appendProjectedNode, canInsertNativeNode, createTextNode, findComponentHost, getChildLNode, getLViewChild, getNextLNode, getParentLNode, insertView, removeView} from './node_manipulation'; | ||||
| import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher'; | ||||
| import {ComponentDefInternal, ComponentTemplate, ComponentQuery, DirectiveDefInternal, DirectiveDefListOrFactory, PipeDefListOrFactory, RenderFlags} from './interfaces/definition'; | ||||
| import {RComment, RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer'; | ||||
| import {StylingContext, allocStylingContext, createStylingContextTemplate, renderStyles as renderElementStyles, updateStyleMap as updateElementStyleMap, updateStyleProp as updateElementStyleProp} from './styling'; | ||||
| import {isDifferent, stringify} from './util'; | ||||
| import {ViewRef} from './view_ref'; | ||||
| import {StylingContext, allocStylingContext, createStylingContextTemplate, updateStyleMap as updateElementStyleMap, updateStyleProp as updateElementStyleProp, renderStyles as renderElementStyles} from './styling'; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Directive (D) sets a property on all component instances using this constant as a key and the | ||||
| @ -335,7 +335,6 @@ export function createLNodeObject( | ||||
|     data: state, | ||||
|     queries: queries, | ||||
|     tNode: null !, | ||||
|     pNextOrParent: null, | ||||
|     dynamicLContainerNode: null | ||||
|   }; | ||||
| } | ||||
| @ -363,11 +362,11 @@ export function createLNode( | ||||
|     attrs: TAttributes | null, lContainer: LContainer): LContainerNode; | ||||
| export function createLNode( | ||||
|     index: number, type: TNodeType.Projection, native: null, name: null, attrs: TAttributes | null, | ||||
|     lProjection: LProjection): LProjectionNode; | ||||
|     lProjection: null): LProjectionNode; | ||||
| export function createLNode( | ||||
|     index: number, type: TNodeType, native: RText | RElement | RComment | null, name: string | null, | ||||
|     attrs: TAttributes | null, state?: null | LViewData | LContainer | LProjection): LElementNode& | ||||
|     LTextNode&LViewNode&LContainerNode&LProjectionNode { | ||||
|     attrs: TAttributes | null, state?: null | LViewData | LContainer): LElementNode<extNode& | ||||
|     LViewNode&LContainerNode&LProjectionNode { | ||||
|   const parent = isParent ? previousOrParentNode : | ||||
|                             previousOrParentNode && getParentLNode(previousOrParentNode) !as LNode; | ||||
|   // Parents cannot cross component boundaries because components will be used in multiple places,
 | ||||
| @ -1189,7 +1188,8 @@ export function createTNode( | ||||
|     parent: parent, | ||||
|     dynamicContainerNode: null, | ||||
|     detached: null, | ||||
|     stylingTemplate: null | ||||
|     stylingTemplate: null, | ||||
|     projection: null | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| @ -1948,136 +1948,107 @@ export function viewAttached(view: LViewData): boolean { | ||||
|  * @param selectors A collection of parsed CSS selectors | ||||
|  * @param rawSelectors A collection of CSS selectors in the raw, un-parsed form | ||||
|  */ | ||||
| export function projectionDef( | ||||
|     index: number, selectors?: CssSelectorList[], textSelectors?: string[]): void { | ||||
|   const noOfNodeBuckets = selectors ? selectors.length + 1 : 1; | ||||
|   const distributedNodes = new Array<LNode[]>(noOfNodeBuckets); | ||||
|   for (let i = 0; i < noOfNodeBuckets; i++) { | ||||
|     distributedNodes[i] = []; | ||||
|   } | ||||
| 
 | ||||
| export function projectionDef(selectors?: CssSelectorList[], textSelectors?: string[]): void { | ||||
|   const componentNode: LElementNode = findComponentHost(viewData); | ||||
|   let componentChild = getChildLNode(componentNode); | ||||
| 
 | ||||
|   if (!componentNode.tNode.projection) { | ||||
|     const noOfNodeBuckets = selectors ? selectors.length + 1 : 1; | ||||
|     const pData: (TNode | null)[] = componentNode.tNode.projection = | ||||
|         new Array(noOfNodeBuckets).fill(null); | ||||
|     const tails: (TNode | null)[] = pData.slice(); | ||||
| 
 | ||||
|     let componentChild = componentNode.tNode.child; | ||||
| 
 | ||||
|     while (componentChild !== null) { | ||||
|     // execute selector matching logic if and only if:
 | ||||
|     // - there are selectors defined
 | ||||
|     // - a node has a tag name / attributes that can be matched
 | ||||
|       const bucketIndex = | ||||
|         selectors ? matchingSelectorIndex(componentChild.tNode, selectors, textSelectors !) : 0; | ||||
|     distributedNodes[bucketIndex].push(componentChild); | ||||
|           selectors ? matchingSelectorIndex(componentChild, selectors, textSelectors !) : 0; | ||||
|       const nextNode = componentChild.next; | ||||
| 
 | ||||
|     componentChild = getNextLNode(componentChild); | ||||
|       if (tails[bucketIndex]) { | ||||
|         tails[bucketIndex] !.next = componentChild; | ||||
|       } else { | ||||
|         pData[bucketIndex] = componentChild; | ||||
|         componentChild.next = null; | ||||
|       } | ||||
|       tails[bucketIndex] = componentChild; | ||||
| 
 | ||||
|   ngDevMode && assertDataNext(index + HEADER_OFFSET); | ||||
|   store(index, distributedNodes); | ||||
|       componentChild = nextNode; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Updates the linked list of a projection node, by appending another linked list. | ||||
|  * Stack used to keep track of projection nodes in projection() instruction. | ||||
|  * | ||||
|  * @param projectionNode Projection node whose projected nodes linked list has to be updated | ||||
|  * @param appendedFirst First node of the linked list to append. | ||||
|  * @param appendedLast Last node of the linked list to append. | ||||
|  * This is deliberately created outside of projection() to avoid allocating | ||||
|  * a new array each time the function is called. Instead the array will be | ||||
|  * re-used by each invocation. This works because the function is not reentrant. | ||||
|  */ | ||||
| function addToProjectionList( | ||||
|     projectionNode: LProjectionNode, | ||||
|     appendedFirst: LElementNode | LTextNode | LContainerNode | null, | ||||
|     appendedLast: LElementNode | LTextNode | LContainerNode | null) { | ||||
|   ngDevMode && assertEqual( | ||||
|                    !!appendedFirst, !!appendedLast, | ||||
|                    'appendedFirst can be null if and only if appendedLast is also null'); | ||||
|   if (!appendedLast) { | ||||
|     // nothing to append
 | ||||
|     return; | ||||
|   } | ||||
|   const projectionNodeData = projectionNode.data; | ||||
|   if (projectionNodeData.tail) { | ||||
|     projectionNodeData.tail.pNextOrParent = appendedFirst; | ||||
|   } else { | ||||
|     projectionNodeData.head = appendedFirst; | ||||
|   } | ||||
|   projectionNodeData.tail = appendedLast; | ||||
|   appendedLast.pNextOrParent = projectionNode; | ||||
| } | ||||
| const projectionNodeStack: LProjectionNode[] = []; | ||||
| 
 | ||||
| /** | ||||
|  * Inserts previously re-distributed projected nodes. This instruction must be preceded by a call | ||||
|  * to the projectionDef instruction. | ||||
|  * | ||||
|  * @param nodeIndex | ||||
|  * @param localIndex - index under which distribution of projected nodes was memorized | ||||
|  * @param selectorIndex: | ||||
|  *        - 0 when the selector is `*` (or unspecified as this is the default value), | ||||
|  *        - 1 based index of the selector from the {@link projectionDef} | ||||
|  */ | ||||
| export function projection( | ||||
|     nodeIndex: number, localIndex: number, selectorIndex: number = 0, attrs?: string[]): void { | ||||
|   const node = createLNode( | ||||
|       nodeIndex, TNodeType.Projection, null, null, attrs || null, {head: null, tail: null}); | ||||
| export function projection(nodeIndex: number, selectorIndex: number = 0, attrs?: string[]): void { | ||||
|   const node = createLNode(nodeIndex, TNodeType.Projection, null, null, attrs || null, null); | ||||
| 
 | ||||
|   // We can't use viewData[HOST_NODE] because projection nodes can be nested in embedded views.
 | ||||
|   if (node.tNode.projection === null) node.tNode.projection = selectorIndex; | ||||
| 
 | ||||
|   // `<ng-content>` has no content
 | ||||
|   isParent = false; | ||||
| 
 | ||||
|   // re-distribution of projectable nodes is memorized on a component's view level
 | ||||
|   // re-distribution of projectable nodes is stored on a component's view level
 | ||||
|   const parent = getParentLNode(node); | ||||
| 
 | ||||
|   if (canInsertNativeNode(parent, viewData)) { | ||||
|     const componentNode = findComponentHost(viewData); | ||||
|   const componentLView = componentNode.data as LViewData; | ||||
|   const distributedNodes = loadInternal(localIndex, componentLView) as Array<LNode[]>; | ||||
|   const nodesForSelector = distributedNodes[selectorIndex]; | ||||
| 
 | ||||
|   const currentParent = getParentLNode(node); | ||||
|   const canInsert = canInsertNativeNode(currentParent, viewData); | ||||
|     let nodeToProject = (componentNode.tNode.projection as(TNode | null)[])[selectorIndex]; | ||||
|     let projectedView = componentNode.view; | ||||
|     let projectionNodeIndex = -1; | ||||
|     let grandparent: LContainerNode; | ||||
|   const renderParent = currentParent.tNode.type === TNodeType.View ? | ||||
|       (grandparent = getParentLNode(currentParent) as LContainerNode) && | ||||
|     const renderParent = parent.tNode.type === TNodeType.View ? | ||||
|         (grandparent = getParentLNode(parent) as LContainerNode) && | ||||
|             grandparent.data[RENDER_PARENT] ! : | ||||
|       currentParent as LElementNode; | ||||
|         parent as LElementNode; | ||||
| 
 | ||||
|   for (let i = 0; i < nodesForSelector.length; i++) { | ||||
|     const nodeToProject = nodesForSelector[i]; | ||||
|     let head = nodeToProject as LTextNode | LElementNode | LContainerNode | null; | ||||
|     let tail = nodeToProject as LTextNode | LElementNode | LContainerNode | null; | ||||
|     while (nodeToProject) { | ||||
|       if (nodeToProject.type === TNodeType.Projection) { | ||||
|         // This node is re-projected, so we must go up the tree to get its projected nodes.
 | ||||
|         const currentComponentHost = findComponentHost(projectedView); | ||||
|         const firstProjectedNode = (currentComponentHost.tNode.projection as( | ||||
|             TNode | null)[])[nodeToProject.projection as number]; | ||||
| 
 | ||||
|     if (nodeToProject.tNode.type === TNodeType.Projection) { | ||||
|       const previouslyProjected = (nodeToProject as LProjectionNode).data; | ||||
|       head = previouslyProjected.head; | ||||
|       tail = previouslyProjected.tail; | ||||
|         if (firstProjectedNode) { | ||||
|           projectionNodeStack[++projectionNodeIndex] = projectedView[nodeToProject.index]; | ||||
|           nodeToProject = firstProjectedNode; | ||||
|           projectedView = currentComponentHost.view; | ||||
|           continue; | ||||
|         } | ||||
| 
 | ||||
|     addToProjectionList(node, head, tail); | ||||
| 
 | ||||
|     if (canInsert) { | ||||
|       let currentNode: LNode|null = head; | ||||
|       while (currentNode) { | ||||
|       } else { | ||||
|         const lNode = projectedView[nodeToProject.index]; | ||||
|         lNode.tNode.flags |= TNodeFlags.isProjected; | ||||
|         appendProjectedNode( | ||||
|             currentNode as LTextNode | LElementNode | LContainerNode, currentParent, viewData, | ||||
|             renderParent); | ||||
|         currentNode = currentNode === tail ? null : currentNode.pNextOrParent; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|             lNode as LTextNode | LElementNode | LContainerNode, parent, viewData, renderParent); | ||||
|       } | ||||
| 
 | ||||
| /** | ||||
|  * Given a current view, finds the nearest component's host (LElement). | ||||
|  * | ||||
|  * @param lViewData LViewData for which we want a host element node | ||||
|  * @returns The host node | ||||
|  */ | ||||
| function findComponentHost(lViewData: LViewData): LElementNode { | ||||
|   let viewRootLNode = lViewData[HOST_NODE]; | ||||
| 
 | ||||
|   while (viewRootLNode.tNode.type === TNodeType.View) { | ||||
|     ngDevMode && assertDefined(lViewData[PARENT], 'lViewData.parent'); | ||||
|     lViewData = lViewData[PARENT] !; | ||||
|     viewRootLNode = lViewData[HOST_NODE]; | ||||
|       // If we are finished with a list of re-projected nodes, we need to get
 | ||||
|       // back to the root projection node that was re-projected.
 | ||||
|       if (nodeToProject.next === null && projectedView !== componentNode.view) { | ||||
|         // move down into the view of the component we're projecting right now
 | ||||
|         const lNode = projectionNodeStack[projectionNodeIndex--]; | ||||
|         nodeToProject = lNode.tNode; | ||||
|         projectedView = lNode.view; | ||||
|       } | ||||
|       nodeToProject = nodeToProject.next; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   ngDevMode && assertNodeType(viewRootLNode, TNodeType.Element); | ||||
|   ngDevMode && assertDefined(viewRootLNode.data, 'node.data'); | ||||
| 
 | ||||
|   return viewRootLNode as LElementNode; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  | ||||
| @ -10,7 +10,6 @@ import {StylingContext} from '../styling'; | ||||
| 
 | ||||
| import {LContainer} from './container'; | ||||
| import {LInjector} from './injector'; | ||||
| import {LProjection} from './projection'; | ||||
| import {LQueries} from './query'; | ||||
| import {RComment, RElement, RText} from './renderer'; | ||||
| import {LViewData, TView} from './view'; | ||||
| @ -36,11 +35,14 @@ export const enum TNodeFlags { | ||||
|   /** The number of directives on this node is encoded on the least significant bits */ | ||||
|   DirectiveCountMask = 0b00000000000000000000111111111111, | ||||
| 
 | ||||
|   /** Then this bit is set when the node is a component */ | ||||
|   isComponent = 0b1000000000000, | ||||
|   /** This bit is set if the node is a component */ | ||||
|   isComponent = 0b00000000000000000001000000000000, | ||||
| 
 | ||||
|   /** This bit is set if the node has been projected */ | ||||
|   isProjected = 0b00000000000000000010000000000000, | ||||
| 
 | ||||
|   /** The index of the first directive on this node is encoded on the most significant bits  */ | ||||
|   DirectiveStartingIndexShift = 13, | ||||
|   DirectiveStartingIndexShift = 14, | ||||
| } | ||||
| 
 | ||||
| /** | ||||
| @ -74,7 +76,7 @@ export interface LNode { | ||||
|    * If LContainerNode, then `data` contains LContainer. | ||||
|    * If LProjectionNode, then `data` contains LProjection. | ||||
|    */ | ||||
|   readonly data: LViewData|LContainer|LProjection|null; | ||||
|   readonly data: LViewData|LContainer|null; | ||||
| 
 | ||||
| 
 | ||||
|   /** | ||||
| @ -94,14 +96,6 @@ export interface LNode { | ||||
|    */ | ||||
|   queries: LQueries|null; | ||||
| 
 | ||||
|   /** | ||||
|    * If this node is projected, pointer to the next node in the same projection parent | ||||
|    * (which is a container, an element, or a text node), or to the parent projection node | ||||
|    * if this is the last node in the projection. | ||||
|    * If this node is not projected, this field is null. | ||||
|    */ | ||||
|   pNextOrParent: LNode|null; | ||||
| 
 | ||||
|   /** | ||||
|    * Pointer to the corresponding TNode object, which stores static | ||||
|    * data about this node. | ||||
| @ -156,7 +150,7 @@ export interface LContainerNode extends LNode { | ||||
| 
 | ||||
| export interface LProjectionNode extends LNode { | ||||
|   readonly native: null; | ||||
|   readonly data: LProjection; | ||||
|   readonly data: null; | ||||
|   dynamicLContainerNode: null; | ||||
| } | ||||
| 
 | ||||
| @ -345,6 +339,43 @@ export interface TNode { | ||||
|   detached: boolean|null; | ||||
| 
 | ||||
|   stylingTemplate: StylingContext|null; | ||||
|   /** | ||||
|    * List of projected TNodes for a given component host element OR index into the said nodes. | ||||
|    * | ||||
|    * For easier discussion assume this example: | ||||
|    * `<parent>`'s view definition: | ||||
|    * ``` | ||||
|    * <child id="c1">content1</child> | ||||
|    * <child id="c2"><span>content2</span></child> | ||||
|    * ``` | ||||
|    * `<child>`'s view definition: | ||||
|    * ``` | ||||
|    * <ng-content id="cont1"></ng-content> | ||||
|    * ``` | ||||
|    * | ||||
|    * If `Array.isArray(projection)` then `TNode` is a host element: | ||||
|    * - `projection` stores the content nodes which are to be projected. | ||||
|    *    - The nodes represent categories defined by the selector: For example: | ||||
|    *      `<ng-content/><ng-content select="abc"/>` would represent the heads for `<ng-content/>` | ||||
|    *      and `<ng-content select="abc"/>` respectively. | ||||
|    *    - The nodes we store in `projection` are heads only, we used `.next` to get their | ||||
|    *      siblings. | ||||
|    *    - The nodes `.next` is sorted/rewritten as part of the projection setup. | ||||
|    *    - `projection` size is equal to the number of projections `<ng-content>`. The size of | ||||
|    *      `c1` will be `1` because `<child>` has only one `<ng-content>`. | ||||
|    * - we store `projection` with the host (`c1`, `c2`) rather than the `<ng-content>` (`cont1`) | ||||
|    *   because the same component (`<child>`) can be used in multiple locations (`c1`, `c2`) and as | ||||
|    *   a result have different set of nodes to project. | ||||
|    * - without `projection` it would be difficult to efficiently traverse nodes to be projected. | ||||
|    * | ||||
|    * If `typeof projection == 'number'` then `TNode` is a `<ng-content>` element: | ||||
|    * - `projection` is an index of the host's `projection`Nodes. | ||||
|    *   - This would return the first head node to project: | ||||
|    *     `getHost(currentTNode).projection[currentTNode.projection]`. | ||||
|    * - When projecting nodes the parent node retrieved may be a `<ng-content>` node, in which case | ||||
|    *   the process is recursive in nature (not implementation). | ||||
|    */ | ||||
|   projection: (TNode|null)[]|number|null; | ||||
| } | ||||
| 
 | ||||
| /** Static data for an LElementNode  */ | ||||
| @ -359,6 +390,13 @@ export interface TElementNode extends TNode { | ||||
|    */ | ||||
|   parent: TElementNode|null; | ||||
|   tViews: null; | ||||
| 
 | ||||
|   /** | ||||
|    * If this is a component TNode with projection, this will be an array of projected | ||||
|    * TNodes (see TNode.projection for more info). If it's a regular element node or a | ||||
|    * component without projection, it will be null. | ||||
|    */ | ||||
|   projection: (TNode|null)[]|null; | ||||
| } | ||||
| 
 | ||||
| /** Static data for an LTextNode  */ | ||||
| @ -373,6 +411,7 @@ export interface TTextNode extends TNode { | ||||
|    */ | ||||
|   parent: TElementNode|null; | ||||
|   tViews: null; | ||||
|   projection: null; | ||||
| } | ||||
| 
 | ||||
| /** Static data for an LContainerNode */ | ||||
| @ -394,6 +433,7 @@ export interface TContainerNode extends TNode { | ||||
|    */ | ||||
|   parent: TElementNode|null; | ||||
|   tViews: TView|TView[]|null; | ||||
|   projection: null; | ||||
| } | ||||
| 
 | ||||
| /** Static data for an LViewNode  */ | ||||
| @ -403,6 +443,7 @@ export interface TViewNode extends TNode { | ||||
|   child: TElementNode|TTextNode|TContainerNode|TProjectionNode|null; | ||||
|   parent: TContainerNode|null; | ||||
|   tViews: null; | ||||
|   projection: null; | ||||
| } | ||||
| 
 | ||||
| /** Static data for an LProjectionNode  */ | ||||
| @ -416,6 +457,9 @@ export interface TProjectionNode extends TNode { | ||||
|    */ | ||||
|   parent: TElementNode|null; | ||||
|   tViews: null; | ||||
| 
 | ||||
|   /** Index of the projection node. (See TNode.projection for more info.) */ | ||||
|   projection: number; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| 
 | ||||
| /** | ||||
|  * @license | ||||
|  * Copyright Google Inc. All Rights Reserved. | ||||
| @ -6,15 +7,6 @@ | ||||
|  * found in the LICENSE file at https://angular.io/license
 | ||||
|  */ | ||||
| 
 | ||||
| import {LContainerNode, LElementNode, LTextNode} from './node'; | ||||
| 
 | ||||
| /** | ||||
|  * Linked list of projected nodes (using the pNextOrParent property). | ||||
|  */ | ||||
| export interface LProjection { | ||||
|   head: LElementNode|LTextNode|LContainerNode|null; | ||||
|   tail: LElementNode|LTextNode|LContainerNode|null; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Expresses a single CSS Selector. | ||||
|  | ||||
| @ -6,9 +6,10 @@ | ||||
|  * found in the LICENSE file at https://angular.io/license
 | ||||
|  */ | ||||
| 
 | ||||
| import {assertDefined} from './assert'; | ||||
| import {callHooks} from './hooks'; | ||||
| import {LContainer, RENDER_PARENT, VIEWS, unusedValueExportToPlacateAjd as unused1} from './interfaces/container'; | ||||
| import {LContainerNode, LElementNode, LNode, LProjectionNode, LTextNode, LViewNode, TNodeType, unusedValueExportToPlacateAjd as unused2} from './interfaces/node'; | ||||
| import {LContainerNode, LElementNode, LNode, LProjectionNode, LTextNode, LViewNode, TNode, TNodeFlags, TNodeType, unusedValueExportToPlacateAjd as unused2} from './interfaces/node'; | ||||
| import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection'; | ||||
| import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer'; | ||||
| import {CLEANUP, CONTAINER_INDEX, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, HookData, LViewData, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, TVIEW, unusedValueExportToPlacateAjd as unused5} from './interfaces/view'; | ||||
| @ -24,7 +25,7 @@ export function getNextLNode(node: LNode): LNode|null { | ||||
|     const viewData = node.data as LViewData; | ||||
|     return viewData[NEXT] ? (viewData[NEXT] as LViewData)[HOST_NODE] : null; | ||||
|   } | ||||
|   return node.tNode.next ? node.view[node.tNode.next !.index] : null; | ||||
|   return node.tNode.next ? node.view[node.tNode.next.index] : null; | ||||
| } | ||||
| 
 | ||||
| /** Retrieves the first child of a given node */ | ||||
| @ -52,27 +53,6 @@ export function getParentLNode(node: LNode): LElementNode|LContainerNode|LViewNo | ||||
|   return parent ? node.view[parent.index] : node.view[HOST_NODE]; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Get the next node in the LNode tree, taking into account the place where a node is | ||||
|  * projected (in the shadow DOM) rather than where it comes from (in the light DOM). | ||||
|  * | ||||
|  * @param node The node whose next node in the LNode tree must be found. | ||||
|  * @return LNode|null The next sibling in the LNode tree. | ||||
|  */ | ||||
| function getNextLNodeWithProjection(node: LNode): LNode|null { | ||||
|   const pNextOrParent = node.pNextOrParent; | ||||
| 
 | ||||
|   if (pNextOrParent) { | ||||
|     // The node is projected
 | ||||
|     const isLastProjectedNode = pNextOrParent.tNode.type === TNodeType.Projection; | ||||
|     // returns pNextOrParent if we are not at the end of the list, null otherwise
 | ||||
|     return isLastProjectedNode ? null : pNextOrParent; | ||||
|   } | ||||
| 
 | ||||
|   // returns node.next because the the node is not projected
 | ||||
|   return getNextLNode(node); | ||||
| } | ||||
| 
 | ||||
| const enum WalkLNodeTreeAction { | ||||
|   /** node insert in the native environment */ | ||||
|   Insert = 0, | ||||
| @ -84,12 +64,22 @@ const enum WalkLNodeTreeAction { | ||||
|   Destroy = 2, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Stack used to keep track of projection nodes in walkLNodeTree. | ||||
|  * | ||||
|  * This is deliberately created outside of walkLNodeTree to avoid allocating | ||||
|  * a new array each time the function is called. Instead the array will be | ||||
|  * re-used by each invocation. This works because the function is not reentrant. | ||||
|  */ | ||||
| const projectionNodeStack: LProjectionNode[] = []; | ||||
| 
 | ||||
| /** | ||||
|  * Walks a tree of LNodes, applying a transformation on the LElement nodes, either only on the first | ||||
|  * one found, or on all of them. | ||||
|  * | ||||
|  * @param startingNode the node from which the walk is started. | ||||
|  * @param rootNode the root node considered. | ||||
|  * @param rootNode the root node considered. This prevents walking past that node. | ||||
|  * @param action identifies the action to be performed on the LElement nodes. | ||||
|  * @param renderer the current renderer. | ||||
|  * @param renderParentNode Optional the render parent node to be set in all LContainerNodes found, | ||||
| @ -101,18 +91,19 @@ function walkLNodeTree( | ||||
|     startingNode: LNode | null, rootNode: LNode, action: WalkLNodeTreeAction, renderer: Renderer3, | ||||
|     renderParentNode?: LElementNode | null, beforeNode?: RNode | null) { | ||||
|   let node: LNode|null = startingNode; | ||||
|   let projectionNodeIndex = -1; | ||||
|   while (node) { | ||||
|     let nextNode: LNode|null = null; | ||||
|     const parent = renderParentNode ? renderParentNode.native : null; | ||||
|     if (node.tNode.type === TNodeType.Element) { | ||||
|     const nodeType = node.tNode.type; | ||||
|     if (nodeType === TNodeType.Element) { | ||||
|       // Execute the action
 | ||||
|       executeNodeAction(action, renderer, parent, node.native !, beforeNode); | ||||
|       if (node.dynamicLContainerNode) { | ||||
|         executeNodeAction( | ||||
|             action, renderer, parent, node.dynamicLContainerNode.native !, beforeNode); | ||||
|       } | ||||
|       nextNode = getNextLNode(node); | ||||
|     } else if (node.tNode.type === TNodeType.Container) { | ||||
|     } else if (nodeType === TNodeType.Container) { | ||||
|       executeNodeAction(action, renderer, parent, node.native !, beforeNode); | ||||
|       const lContainerNode: LContainerNode = (node as LContainerNode); | ||||
|       const childContainerData: LContainer = lContainerNode.dynamicLContainerNode ? | ||||
| @ -130,15 +121,26 @@ function walkLNodeTree( | ||||
|             lContainerNode.dynamicLContainerNode.native : | ||||
|             lContainerNode.native; | ||||
|       } | ||||
|     } else if (node.tNode.type === TNodeType.Projection) { | ||||
|       // For Projection look at the first projected node
 | ||||
|       nextNode = (node as LProjectionNode).data.head; | ||||
|     } else if (nodeType === TNodeType.Projection) { | ||||
|       const componentHost = findComponentHost(node.view); | ||||
|       const head = | ||||
|           (componentHost.tNode.projection as(TNode | null)[])[node.tNode.projection as number]; | ||||
| 
 | ||||
|       projectionNodeStack[++projectionNodeIndex] = node as LProjectionNode; | ||||
| 
 | ||||
|       nextNode = head ? (componentHost.data as LViewData)[PARENT] ![head.index] : null; | ||||
|     } else { | ||||
|       // Otherwise look at the first child
 | ||||
|       nextNode = getChildLNode(node as LViewNode); | ||||
|     } | ||||
| 
 | ||||
|     if (nextNode == null) { | ||||
|     if (nextNode === null) { | ||||
|       nextNode = getNextLNode(node); | ||||
| 
 | ||||
|       // this last node was projected, we need to get back down to its projection node
 | ||||
|       if (nextNode === null && (node.tNode.flags & TNodeFlags.isProjected)) { | ||||
|         nextNode = getNextLNode(projectionNodeStack[projectionNodeIndex--] as LNode); | ||||
|       } | ||||
|       /** | ||||
|        * Find the next node in the LNode tree, taking into account the place where a node is | ||||
|        * projected (in the shadow DOM) rather than where it comes from (in the light DOM). | ||||
| @ -146,27 +148,41 @@ function walkLNodeTree( | ||||
|        * If there is no sibling node, then it goes to the next sibling of the parent node... | ||||
|        * until it reaches rootNode (at which point null is returned). | ||||
|        */ | ||||
|       let currentNode: LNode|null = node; | ||||
|       node = getNextLNodeWithProjection(currentNode); | ||||
|       while (currentNode && !node) { | ||||
|         // if node.pNextOrParent is not null here, it is not the next node
 | ||||
|         // (because, at this point, nextNode is null, so it is the parent)
 | ||||
|         currentNode = currentNode.pNextOrParent || getParentLNode(currentNode); | ||||
|         if (currentNode === rootNode) { | ||||
|           return null; | ||||
|       while (node && !nextNode) { | ||||
|         node = getParentLNode(node); | ||||
|         if (node === null || node === rootNode) return null; | ||||
| 
 | ||||
|         // When exiting a container, the beforeNode must be restored to the previous value
 | ||||
|         if (!node.tNode.next && nodeType === TNodeType.Container) { | ||||
|           beforeNode = node.native; | ||||
|         } | ||||
|         // When the walker exits a container, the beforeNode has to be restored to the previous
 | ||||
|         // value.
 | ||||
|         if (currentNode && !currentNode.pNextOrParent && | ||||
|             currentNode.tNode.type === TNodeType.Container) { | ||||
|           beforeNode = currentNode.native; | ||||
|         nextNode = getNextLNode(node); | ||||
|       } | ||||
|         node = currentNode && getNextLNodeWithProjection(currentNode); | ||||
|     } | ||||
|     } else { | ||||
|     node = nextNode; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Given a current view, finds the nearest component's host (LElement). | ||||
|  * | ||||
|  * @param lViewData LViewData for which we want a host element node | ||||
|  * @returns The host node | ||||
|  */ | ||||
| export function findComponentHost(lViewData: LViewData): LElementNode { | ||||
|   let viewRootLNode = lViewData[HOST_NODE]; | ||||
| 
 | ||||
|   while (viewRootLNode.tNode.type === TNodeType.View) { | ||||
|     ngDevMode && assertDefined(lViewData[PARENT], 'lViewData.parent'); | ||||
|     lViewData = lViewData[PARENT] !; | ||||
|     viewRootLNode = lViewData[HOST_NODE]; | ||||
|   } | ||||
| 
 | ||||
|   ngDevMode && assertNodeType(viewRootLNode, TNodeType.Element); | ||||
|   ngDevMode && assertDefined(viewRootLNode.data, 'node.data'); | ||||
| 
 | ||||
|   return viewRootLNode as LElementNode; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  | ||||
| @ -422,6 +422,9 @@ | ||||
|   { | ||||
|     "name": "findAttrIndexInNode" | ||||
|   }, | ||||
|   { | ||||
|     "name": "findComponentHost" | ||||
|   }, | ||||
|   { | ||||
|     "name": "findDirectiveMatches" | ||||
|   }, | ||||
| @ -452,9 +455,6 @@ | ||||
|   { | ||||
|     "name": "getNextLNode" | ||||
|   }, | ||||
|   { | ||||
|     "name": "getNextLNodeWithProjection" | ||||
|   }, | ||||
|   { | ||||
|     "name": "getOrCreateContainerRef" | ||||
|   }, | ||||
| @ -605,6 +605,9 @@ | ||||
|   { | ||||
|     "name": "notImplemented" | ||||
|   }, | ||||
|   { | ||||
|     "name": "projectionNodeStack" | ||||
|   }, | ||||
|   { | ||||
|     "name": "queueComponentIndexForCheck" | ||||
|   }, | ||||
|  | ||||
| @ -27,9 +27,9 @@ describe('content projection', () => { | ||||
|         factory: () => new SimpleComponent(), | ||||
|         template: function(rf: $RenderFlags$, ctx: $SimpleComponent$) { | ||||
|           if (rf & 1) { | ||||
|             $r3$.ɵpD(0); | ||||
|             $r3$.ɵEe(1, 'div'); | ||||
|             $r3$.ɵP(2, 0); | ||||
|             $r3$.ɵpD(); | ||||
|             $r3$.ɵEe(0, 'div'); | ||||
|             $r3$.ɵP(1); | ||||
|           } | ||||
|         } | ||||
|       }); | ||||
| @ -56,11 +56,11 @@ describe('content projection', () => { | ||||
|         factory: () => new ComplexComponent(), | ||||
|         template: function(rf: $RenderFlags$, ctx: $ComplexComponent$) { | ||||
|           if (rf & 1) { | ||||
|             $r3$.ɵpD(0, $pD_0P$, $pD_0R$); | ||||
|             $r3$.ɵEe(1, 'div', ['id', 'first']); | ||||
|             $r3$.ɵP(2, 0, 1); | ||||
|             $r3$.ɵEe(3, 'div', ['id', 'second']); | ||||
|             $r3$.ɵP(4, 0, 2); | ||||
|             $r3$.ɵpD($pD_0P$, $pD_0R$); | ||||
|             $r3$.ɵEe(0, 'div', ['id', 'first']); | ||||
|             $r3$.ɵP(1, 1); | ||||
|             $r3$.ɵEe(2, 'div', ['id', 'second']); | ||||
|             $r3$.ɵP(3, 2); | ||||
|           } | ||||
|         } | ||||
|       }); | ||||
|  | ||||
| @ -124,9 +124,9 @@ describe('queries', () => { | ||||
|         template: function ContentQueryComponent_Template( | ||||
|             rf: $number$, ctx: $ContentQueryComponent$) { | ||||
|           if (rf & 1) { | ||||
|             $r3$.ɵpD(0); | ||||
|             $r3$.ɵE(1, 'div'); | ||||
|             $r3$.ɵP(2, 0); | ||||
|             $r3$.ɵpD(); | ||||
|             $r3$.ɵE(0, 'div'); | ||||
|             $r3$.ɵP(1); | ||||
|             $r3$.ɵe(); | ||||
|           } | ||||
|         } | ||||
|  | ||||
| @ -8,6 +8,9 @@ | ||||
| 
 | ||||
| import {SelectorFlags} from '@angular/core/src/render3/interfaces/projection'; | ||||
| 
 | ||||
| import {Input, TemplateRef, ViewContainerRef, ViewRef} from '../../src/core'; | ||||
| import {defineDirective} from '../../src/render3/definition'; | ||||
| import {injectTemplateRef, injectViewContainerRef} from '../../src/render3/di'; | ||||
| import {AttributeMarker, detectChanges} from '../../src/render3/index'; | ||||
| import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, loadDirective, projection, projectionDef, text} from '../../src/render3/instructions'; | ||||
| import {RenderFlags} from '../../src/render3/interfaces/definition'; | ||||
| @ -22,9 +25,9 @@ describe('content projection', () => { | ||||
|      */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'div'); | ||||
|         { projection(2, 0); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { projection(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }); | ||||
| @ -48,8 +51,8 @@ describe('content projection', () => { | ||||
|     /** <ng-content></ng-content> */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         projection(1, 0); | ||||
|         projectionDef(); | ||||
|         projection(0); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
| @ -66,13 +69,47 @@ describe('content projection', () => { | ||||
|     expect(toHtml(parent)).toEqual('<child>content</child>'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should project content with siblings', () => { | ||||
|     /** <ng-content></ng-content> */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(); | ||||
|         projection(0); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     /** | ||||
|      * <child> | ||||
|      *  before | ||||
|      *  <div>content</div> | ||||
|      *  after | ||||
|      * </child> | ||||
|      */ | ||||
|     const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         elementStart(0, 'child'); | ||||
|         { | ||||
|           text(1, 'before'); | ||||
|           elementStart(2, 'div'); | ||||
|           { text(3, 'content'); } | ||||
|           elementEnd(); | ||||
|           text(4, 'after'); | ||||
|         } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }, [Child]); | ||||
| 
 | ||||
|     const parent = renderComponent(Parent); | ||||
|     expect(toHtml(parent)).toEqual('<child>before<div>content</div>after</child>'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should re-project content when root.', () => { | ||||
|     /** <div><ng-content></ng-content></div> */ | ||||
|     const GrandChild = createComponent('grand-child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'div'); | ||||
|         { projection(2, 0); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { projection(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }); | ||||
| @ -80,9 +117,9 @@ describe('content projection', () => { | ||||
|     /** <grand-child><ng-content></ng-content></grand-child> */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'grand-child'); | ||||
|         { projection(2, 0); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'grand-child'); | ||||
|         { projection(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }, [GrandChild]); | ||||
| @ -111,9 +148,9 @@ describe('content projection', () => { | ||||
|     /** <div><ng-content></ng-content></div> */ | ||||
|     const Child = createComponent('child', (rf: RenderFlags, ctx: any) => { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'div'); | ||||
|         { projection(2, 0); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { projection(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }); | ||||
| @ -149,9 +186,9 @@ describe('content projection', () => { | ||||
|     /** <div><ng-content></ng-content></div> */ | ||||
|     const Child = createComponent('child', (rf: RenderFlags, ctx: any) => { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'div'); | ||||
|         { projection(2, 0); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { projection(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }); | ||||
| @ -159,9 +196,9 @@ describe('content projection', () => { | ||||
|     /** <p><ng-content></ng-content></p> */ | ||||
|     const ProjectedComp = createComponent('projected-comp', (rf: RenderFlags, ctx: any) => { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'p'); | ||||
|         projection(2, 0); | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'p'); | ||||
|         projection(1); | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }); | ||||
| @ -198,13 +235,13 @@ describe('content projection', () => { | ||||
|             '<child><div><projected-comp><p><div>Some content</div>Other content</p></projected-comp></div></child>'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should project content with container.', () => { | ||||
|   it('should project containers', () => { | ||||
|     /** <div> <ng-content></ng-content></div> */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'div'); | ||||
|         { projection(2, 0); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { projection(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }); | ||||
| @ -247,18 +284,20 @@ describe('content projection', () => { | ||||
|     expect(toHtml(parent)).toEqual('<child><div>()</div></child>'); | ||||
|     parent.value = true; | ||||
|     detectChanges(parent); | ||||
| 
 | ||||
|     expect(toHtml(parent)).toEqual('<child><div>(content)</div></child>'); | ||||
|     parent.value = false; | ||||
|     detectChanges(parent); | ||||
| 
 | ||||
|     expect(toHtml(parent)).toEqual('<child><div>()</div></child>'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should project content with container into root', () => { | ||||
|   it('should project containers into root', () => { | ||||
|     /** <ng-content></ng-content> */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         projection(1, 0); | ||||
|         projectionDef(); | ||||
|         projection(0); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
| @ -302,13 +341,13 @@ describe('content projection', () => { | ||||
|     expect(toHtml(parent)).toEqual('<child></child>'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should project content with container and if-else.', () => { | ||||
|   it('should project containers with if-else.', () => { | ||||
|     /** <div><ng-content></ng-content></div> */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'div'); | ||||
|         { projection(2, 0); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { projection(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }); | ||||
| @ -378,19 +417,19 @@ describe('content projection', () => { | ||||
|      */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'div'); | ||||
|         { container(2); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { container(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|       if (rf & RenderFlags.Update) { | ||||
|         containerRefreshStart(2); | ||||
|         containerRefreshStart(1); | ||||
|         { | ||||
|           if (!ctx.skipContent) { | ||||
|             let rf0 = embeddedViewStart(0); | ||||
|             if (rf0 & RenderFlags.Create) { | ||||
|               elementStart(0, 'span'); | ||||
|               projection(1, 0); | ||||
|               projection(1); | ||||
|               elementEnd(); | ||||
|             } | ||||
|             embeddedViewEnd(); | ||||
| @ -400,27 +439,90 @@ describe('content projection', () => { | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     /** <child>content</child> */ | ||||
|     /** | ||||
|      * <child> | ||||
|      *   <div>text</div> | ||||
|      *   content | ||||
|      * </child> | ||||
|      */ | ||||
|     const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         elementStart(0, 'child'); | ||||
|         { | ||||
|           childCmptInstance = loadDirective(0); | ||||
|           text(1, 'content'); | ||||
|           elementStart(1, 'div'); | ||||
|           { text(2, 'text'); } | ||||
|           elementEnd(); | ||||
|           text(3, 'content'); | ||||
|         } | ||||
|         elementEnd(); | ||||
| 
 | ||||
|         // testing
 | ||||
|         childCmptInstance = loadDirective(0); | ||||
|       } | ||||
|     }, [Child]); | ||||
| 
 | ||||
|     const parent = renderComponent(Parent); | ||||
|     expect(toHtml(parent)).toEqual('<child><div><span>content</span></div></child>'); | ||||
|     expect(toHtml(parent)).toEqual('<child><div><span><div>text</div>content</span></div></child>'); | ||||
| 
 | ||||
|     childCmptInstance.skipContent = true; | ||||
|     detectChanges(parent); | ||||
|     expect(toHtml(parent)).toEqual('<child><div></div></child>'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should support projection in embedded views when ng-content is a root node of an embedded view', | ||||
|   it('should support projection into embedded views when no projected nodes', () => { | ||||
|     let childCmptInstance: any; | ||||
| 
 | ||||
|     /** | ||||
|      * <div> | ||||
|      *  % if (!skipContent) { | ||||
|      *      <ng-content></ng-content> | ||||
|      *      text | ||||
|      *  % } | ||||
|      * </div> | ||||
|      */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { container(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|       if (rf & RenderFlags.Update) { | ||||
|         containerRefreshStart(1); | ||||
|         { | ||||
|           if (!ctx.skipContent) { | ||||
|             let rf0 = embeddedViewStart(0); | ||||
|             if (rf0 & RenderFlags.Create) { | ||||
|               projection(0); | ||||
|               text(1, 'text'); | ||||
|             } | ||||
|             embeddedViewEnd(); | ||||
|           } | ||||
|         } | ||||
|         containerRefreshEnd(); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     /** <child></child> */ | ||||
|     const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         elementStart(0, 'child'); | ||||
|         elementEnd(); | ||||
| 
 | ||||
|         // testing
 | ||||
|         childCmptInstance = loadDirective(0); | ||||
|       } | ||||
|     }, [Child]); | ||||
| 
 | ||||
|     const parent = renderComponent(Parent); | ||||
|     expect(toHtml(parent)).toEqual('<child><div>text</div></child>'); | ||||
| 
 | ||||
|     childCmptInstance.skipContent = true; | ||||
|     detectChanges(parent); | ||||
|     expect(toHtml(parent)).toEqual('<child><div></div></child>'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should support projection into embedded views when ng-content is a root node of an embedded view', | ||||
|      () => { | ||||
|        let childCmptInstance: any; | ||||
| 
 | ||||
| @ -433,18 +535,18 @@ describe('content projection', () => { | ||||
|         */ | ||||
|        const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|          if (rf & RenderFlags.Create) { | ||||
|            projectionDef(0); | ||||
|            elementStart(1, 'div'); | ||||
|            { container(2); } | ||||
|            projectionDef(); | ||||
|            elementStart(0, 'div'); | ||||
|            { container(1); } | ||||
|            elementEnd(); | ||||
|          } | ||||
|          if (rf & RenderFlags.Update) { | ||||
|            containerRefreshStart(2); | ||||
|            containerRefreshStart(1); | ||||
|            { | ||||
|              if (!ctx.skipContent) { | ||||
|                let rf0 = embeddedViewStart(0); | ||||
|                if (rf0 & RenderFlags.Create) { | ||||
|                  projection(0, 0); | ||||
|                  projection(0); | ||||
|                } | ||||
|                embeddedViewEnd(); | ||||
|              } | ||||
| @ -487,22 +589,22 @@ describe('content projection', () => { | ||||
|      */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'div'); | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { | ||||
|           text(2, 'Before (inside)-'); | ||||
|           container(3); | ||||
|           text(4, '-After (inside)'); | ||||
|           text(1, 'Before (inside)-'); | ||||
|           container(2); | ||||
|           text(3, '-After (inside)'); | ||||
|         } | ||||
|         elementEnd(); | ||||
|       } | ||||
|       if (rf & RenderFlags.Update) { | ||||
|         containerRefreshStart(3); | ||||
|         containerRefreshStart(2); | ||||
|         { | ||||
|           if (!ctx.skipContent) { | ||||
|             let rf0 = embeddedViewStart(0); | ||||
|             if (rf0 & RenderFlags.Create) { | ||||
|               projection(0, 0); | ||||
|               projection(0); | ||||
|             } | ||||
|             embeddedViewEnd(); | ||||
|           } | ||||
| @ -567,18 +669,18 @@ describe('content projection', () => { | ||||
|      */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'div'); | ||||
|         { container(2); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { container(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|       if (rf & RenderFlags.Update) { | ||||
|         containerRefreshStart(2); | ||||
|         containerRefreshStart(1); | ||||
|         { | ||||
|           if (!ctx.skipContent) { | ||||
|             let rf0 = embeddedViewStart(0); | ||||
|             if (rf0 & RenderFlags.Create) { | ||||
|               projection(0, 0); | ||||
|               projection(0); | ||||
|             } | ||||
|             embeddedViewEnd(); | ||||
|           } | ||||
| @ -598,22 +700,22 @@ describe('content projection', () => { | ||||
|      */ | ||||
|     const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'child'); | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'child'); | ||||
|         { | ||||
|           text(2, 'Before text'); | ||||
|           container(3); | ||||
|           text(4, '-After text'); | ||||
|           text(1, 'Before text'); | ||||
|           container(2); | ||||
|           text(3, '-After text'); | ||||
|         } | ||||
|         elementEnd(); | ||||
|       } | ||||
|       if (rf & RenderFlags.Update) { | ||||
|         containerRefreshStart(3); | ||||
|         containerRefreshStart(2); | ||||
|         { | ||||
|           if (!ctx.skipContent) { | ||||
|             let rf0 = embeddedViewStart(0); | ||||
|             if (rf0 & RenderFlags.Create) { | ||||
|               projection(0, 0); | ||||
|               projection(0); | ||||
|             } | ||||
|             embeddedViewEnd(); | ||||
|           } | ||||
| @ -648,8 +750,7 @@ describe('content projection', () => { | ||||
|         .toEqual('<parent><child><div>Before text-After text</div></child></parent>'); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   it('should support projection in embedded views when ng-content is a root node of an embedded view, with other nodes after', | ||||
|   it('should support projection into embedded views when ng-content is a root node of an embedded view, with other nodes after', | ||||
|      () => { | ||||
|        let childCmptInstance: any; | ||||
| 
 | ||||
| @ -662,19 +763,19 @@ describe('content projection', () => { | ||||
|         */ | ||||
|        const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|          if (rf & RenderFlags.Create) { | ||||
|            projectionDef(0); | ||||
|            elementStart(1, 'div'); | ||||
|            { container(2); } | ||||
|            projectionDef(); | ||||
|            elementStart(0, 'div'); | ||||
|            { container(1); } | ||||
|            elementEnd(); | ||||
|          } | ||||
|          if (rf & RenderFlags.Update) { | ||||
|            containerRefreshStart(2); | ||||
|            containerRefreshStart(1); | ||||
|            { | ||||
|              if (!ctx.skipContent) { | ||||
|                let rf0 = embeddedViewStart(0); | ||||
|                if (rf0 & RenderFlags.Create) { | ||||
|                  text(0, 'before-'); | ||||
|                  projection(1, 0); | ||||
|                  projection(1); | ||||
|                  text(2, '-after'); | ||||
|                } | ||||
|                embeddedViewEnd(); | ||||
| @ -732,19 +833,19 @@ describe('content projection', () => { | ||||
|      */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         text(1, 'Before-'); | ||||
|         container(2, IfTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']); | ||||
|         text(3, '-After'); | ||||
|         projectionDef(); | ||||
|         text(0, 'Before-'); | ||||
|         container(1, IfTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']); | ||||
|         text(2, '-After'); | ||||
|       } | ||||
|       if (rf & RenderFlags.Update) { | ||||
|         elementProperty(2, 'ngIf', bind(ctx.showing)); | ||||
|         elementProperty(1, 'ngIf', bind(ctx.showing)); | ||||
|       } | ||||
| 
 | ||||
|       function IfTemplate(rf1: RenderFlags, ctx1: any) { | ||||
|         if (rf1 & RenderFlags.Create) { | ||||
|           projectionDef(0); | ||||
|           projection(1, 0); | ||||
|           projectionDef(); | ||||
|           projection(0); | ||||
|         } | ||||
|       } | ||||
|     }, [NgIf]); | ||||
| @ -817,19 +918,19 @@ describe('content projection', () => { | ||||
|      */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         text(1, 'Before-'); | ||||
|         container(2, IfTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']); | ||||
|         text(3, '-After'); | ||||
|         projectionDef(); | ||||
|         text(0, 'Before-'); | ||||
|         container(1, IfTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']); | ||||
|         text(2, '-After'); | ||||
|       } | ||||
|       if (rf & RenderFlags.Update) { | ||||
|         elementProperty(2, 'ngIf', bind(ctx.showing)); | ||||
|         elementProperty(1, 'ngIf', bind(ctx.showing)); | ||||
|       } | ||||
| 
 | ||||
|       function IfTemplate(rf1: RenderFlags, ctx1: any) { | ||||
|         if (rf1 & RenderFlags.Create) { | ||||
|           projectionDef(0); | ||||
|           projection(1, 0); | ||||
|           projectionDef(); | ||||
|           projection(0); | ||||
|         } | ||||
|       } | ||||
|     }, [NgIf]); | ||||
| @ -878,12 +979,12 @@ describe('content projection', () => { | ||||
|      */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'div'); | ||||
|         { projection(2, 0); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { projection(1); } | ||||
|         elementEnd(); | ||||
|         elementStart(3, 'span'); | ||||
|         { projection(4, 0); } | ||||
|         elementStart(2, 'span'); | ||||
|         { projection(3); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }); | ||||
| @ -924,19 +1025,19 @@ describe('content projection', () => { | ||||
|      */ | ||||
|     const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         projection(1, 0); | ||||
|         elementStart(2, 'div'); | ||||
|         { container(3); } | ||||
|         projectionDef(); | ||||
|         projection(0); | ||||
|         elementStart(1, 'div'); | ||||
|         { container(2); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|       if (rf & RenderFlags.Update) { | ||||
|         containerRefreshStart(3); | ||||
|         containerRefreshStart(2); | ||||
|         { | ||||
|           if (ctx.show) { | ||||
|             let rf0 = embeddedViewStart(0); | ||||
|             if (rf0 & RenderFlags.Create) { | ||||
|               projection(0, 0); | ||||
|               projection(0); | ||||
|             } | ||||
|             embeddedViewEnd(); | ||||
|           } | ||||
| @ -970,10 +1071,10 @@ describe('content projection', () => { | ||||
|   it('should project with multiple instances of a component with projection', () => { | ||||
|     const ProjectionComp = createComponent('projection-comp', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         text(1, 'Before'); | ||||
|         projection(2, 0); | ||||
|         text(3, 'After'); | ||||
|         projectionDef(); | ||||
|         text(0, 'Before'); | ||||
|         projection(1); | ||||
|         text(2, 'After'); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
| @ -990,20 +1091,24 @@ describe('content projection', () => { | ||||
|     const AppComp = createComponent('app-comp', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         elementStart(0, 'projection-comp'); | ||||
|         { | ||||
|           elementStart(1, 'div'); | ||||
|         text(2, 'A'); | ||||
|           { text(2, 'A'); } | ||||
|           elementEnd(); | ||||
|           elementStart(3, 'p'); | ||||
|         text(4, '123'); | ||||
|           { text(4, '123'); } | ||||
|           elementEnd(); | ||||
|         } | ||||
|         elementEnd(); | ||||
|         elementStart(5, 'projection-comp'); | ||||
|         { | ||||
|           elementStart(6, 'div'); | ||||
|         text(7, 'B'); | ||||
|           { text(7, 'B'); } | ||||
|           elementEnd(); | ||||
|           elementStart(8, 'p'); | ||||
|         text(9, '456'); | ||||
|           { text(9, '456'); } | ||||
|           elementEnd(); | ||||
|         } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }, [ProjectionComp]); | ||||
| @ -1012,7 +1117,8 @@ describe('content projection', () => { | ||||
|     fixture.update(); | ||||
|     expect(fixture.html) | ||||
|         .toEqual( | ||||
|             '<projection-comp>Before<div>A</div><p>123</p>After</projection-comp><projection-comp>Before<div>B</div><p>456</p>After</projection-comp>'); | ||||
|             '<projection-comp>Before<div>A</div><p>123</p>After</projection-comp>' + | ||||
|             '<projection-comp>Before<div>B</div><p>456</p>After</projection-comp>'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should re-project with multiple instances of a component with projection', () => { | ||||
| @ -1023,10 +1129,10 @@ describe('content projection', () => { | ||||
|      */ | ||||
|     const ProjectionComp = createComponent('projection-comp', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         text(1, 'Before'); | ||||
|         projection(2, 0); | ||||
|         text(3, 'After'); | ||||
|         projectionDef(); | ||||
|         text(0, 'Before'); | ||||
|         projection(1); | ||||
|         text(2, 'After'); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
| @ -1043,23 +1149,27 @@ describe('content projection', () => { | ||||
|      */ | ||||
|     const ProjectionParent = createComponent('parent-comp', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'projection-comp'); | ||||
|         elementStart(2, 'div'); | ||||
|         text(3, 'A'); | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'projection-comp'); | ||||
|         { | ||||
|           elementStart(1, 'div'); | ||||
|           { text(2, 'A'); } | ||||
|           elementEnd(); | ||||
|         projection(4, 0); | ||||
|         elementStart(5, 'p'); | ||||
|         text(6, '123'); | ||||
|           projection(3, 0); | ||||
|           elementStart(4, 'p'); | ||||
|           { text(5, '123'); } | ||||
|           elementEnd(); | ||||
|         } | ||||
|         elementEnd(); | ||||
|         elementStart(7, 'projection-comp'); | ||||
|         elementStart(8, 'div'); | ||||
|         text(9, 'B'); | ||||
|         elementStart(6, 'projection-comp'); | ||||
|         { | ||||
|           elementStart(7, 'div'); | ||||
|           { text(8, 'B'); } | ||||
|           elementEnd(); | ||||
|         elementStart(10, 'p'); | ||||
|         text(11, '456'); | ||||
|           elementStart(9, 'p'); | ||||
|           { text(10, '456'); } | ||||
|           elementEnd(); | ||||
|         } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }, [ProjectionComp]); | ||||
| @ -1075,10 +1185,10 @@ describe('content projection', () => { | ||||
|     const AppComp = createComponent('app-comp', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         elementStart(0, 'parent-comp'); | ||||
|         text(1, '**ABC**'); | ||||
|         { text(1, '**ABC**'); } | ||||
|         elementEnd(); | ||||
|         elementStart(2, 'parent-comp'); | ||||
|         text(3, '**DEF**'); | ||||
|         { text(3, '**DEF**'); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }, [ProjectionParent]); | ||||
| @ -1087,7 +1197,12 @@ describe('content projection', () => { | ||||
|     fixture.update(); | ||||
|     expect(fixture.html) | ||||
|         .toEqual( | ||||
|             '<parent-comp><projection-comp>Before<div>A</div>**ABC**<p>123</p>After</projection-comp><projection-comp>Before<div>B</div><p>456</p>After</projection-comp></parent-comp><parent-comp><projection-comp>Before<div>A</div>**DEF**<p>123</p>After</projection-comp><projection-comp>Before<div>B</div><p>456</p>After</projection-comp></parent-comp>'); | ||||
|             '<parent-comp>' + | ||||
|             '<projection-comp>Before<div>A</div>**ABC**<p>123</p>After</projection-comp>' + | ||||
|             '<projection-comp>Before<div>B</div><p>456</p>After</projection-comp></parent-comp>' + | ||||
|             '<parent-comp>' + | ||||
|             '<projection-comp>Before<div>A</div>**DEF**<p>123</p>After</projection-comp>' + | ||||
|             '<projection-comp>Before<div>B</div><p>456</p>After</projection-comp></parent-comp>'); | ||||
|   }); | ||||
| 
 | ||||
|   describe('with selectors', () => { | ||||
| @ -1100,13 +1215,13 @@ describe('content projection', () => { | ||||
|       const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef( | ||||
|               0, [[['span', 'title', 'toFirst']], [['span', 'title', 'toSecond']]], | ||||
|               [[['span', 'title', 'toFirst']], [['span', 'title', 'toSecond']]], | ||||
|               ['span[title=toFirst]', 'span[title=toSecond]']); | ||||
|           elementStart(1, 'div', ['id', 'first']); | ||||
|           { projection(2, 0, 1); } | ||||
|           elementStart(0, 'div', ['id', 'first']); | ||||
|           { projection(1, 1); } | ||||
|           elementEnd(); | ||||
|           elementStart(3, 'div', ['id', 'second']); | ||||
|           { projection(4, 0, 2); } | ||||
|           elementStart(2, 'div', ['id', 'second']); | ||||
|           { projection(3, 2); } | ||||
|           elementEnd(); | ||||
|         } | ||||
|       }); | ||||
| @ -1145,8 +1260,8 @@ describe('content projection', () => { | ||||
|        */ | ||||
|       const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef(0, [[['', 'title', '']]], ['[title]']); | ||||
|           { projection(1, 0, 1); } | ||||
|           projectionDef([[['', 'title', '']]], ['[title]']); | ||||
|           { projection(0, 1); } | ||||
|         } | ||||
|       }); | ||||
| 
 | ||||
| @ -1183,17 +1298,16 @@ describe('content projection', () => { | ||||
|       const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef( | ||||
|               0, | ||||
|               [ | ||||
|                 [['span', SelectorFlags.CLASS, 'toFirst']], | ||||
|                 [['span', SelectorFlags.CLASS, 'toSecond']] | ||||
|               ], | ||||
|               ['span.toFirst', 'span.toSecond']); | ||||
|           elementStart(1, 'div', ['id', 'first']); | ||||
|           { projection(2, 0, 1); } | ||||
|           elementStart(0, 'div', ['id', 'first']); | ||||
|           { projection(1, 1); } | ||||
|           elementEnd(); | ||||
|           elementStart(3, 'div', ['id', 'second']); | ||||
|           { projection(4, 0, 2); } | ||||
|           elementStart(2, 'div', ['id', 'second']); | ||||
|           { projection(3, 2); } | ||||
|           elementEnd(); | ||||
|         } | ||||
|       }); | ||||
| @ -1233,17 +1347,16 @@ describe('content projection', () => { | ||||
|       const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef( | ||||
|               0, | ||||
|               [ | ||||
|                 [['span', SelectorFlags.CLASS, 'toFirst']], | ||||
|                 [['span', SelectorFlags.CLASS, 'toSecond']] | ||||
|               ], | ||||
|               ['span.toFirst', 'span.toSecond']); | ||||
|           elementStart(1, 'div', ['id', 'first']); | ||||
|           { projection(2, 0, 1); } | ||||
|           elementStart(0, 'div', ['id', 'first']); | ||||
|           { projection(1, 1); } | ||||
|           elementEnd(); | ||||
|           elementStart(3, 'div', ['id', 'second']); | ||||
|           { projection(4, 0, 2); } | ||||
|           elementStart(2, 'div', ['id', 'second']); | ||||
|           { projection(3, 2); } | ||||
|           elementEnd(); | ||||
|         } | ||||
|       }); | ||||
| @ -1283,13 +1396,12 @@ describe('content projection', () => { | ||||
|       const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef( | ||||
|               0, [[['span']], [['span', SelectorFlags.CLASS, 'toSecond']]], | ||||
|               ['span', 'span.toSecond']); | ||||
|           elementStart(1, 'div', ['id', 'first']); | ||||
|           { projection(2, 0, 1); } | ||||
|               [[['span']], [['span', SelectorFlags.CLASS, 'toSecond']]], ['span', 'span.toSecond']); | ||||
|           elementStart(0, 'div', ['id', 'first']); | ||||
|           { projection(1, 1); } | ||||
|           elementEnd(); | ||||
|           elementStart(3, 'div', ['id', 'second']); | ||||
|           { projection(4, 0, 2); } | ||||
|           elementStart(2, 'div', ['id', 'second']); | ||||
|           { projection(3, 2); } | ||||
|           elementEnd(); | ||||
|         } | ||||
|       }); | ||||
| @ -1328,12 +1440,12 @@ describe('content projection', () => { | ||||
|        */ | ||||
|       const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef(0, [[['span', SelectorFlags.CLASS, 'toFirst']]], ['span.toFirst']); | ||||
|           elementStart(1, 'div', ['id', 'first']); | ||||
|           { projection(2, 0, 1); } | ||||
|           projectionDef([[['span', SelectorFlags.CLASS, 'toFirst']]], ['span.toFirst']); | ||||
|           elementStart(0, 'div', ['id', 'first']); | ||||
|           { projection(1, 1); } | ||||
|           elementEnd(); | ||||
|           elementStart(3, 'div', ['id', 'second']); | ||||
|           { projection(4, 0); } | ||||
|           elementStart(2, 'div', ['id', 'second']); | ||||
|           { projection(3); } | ||||
|           elementEnd(); | ||||
|         } | ||||
|       }); | ||||
| @ -1373,12 +1485,12 @@ describe('content projection', () => { | ||||
|        */ | ||||
|       const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef(0, [[['span', SelectorFlags.CLASS, 'toSecond']]], ['span.toSecond']); | ||||
|           elementStart(1, 'div', ['id', 'first']); | ||||
|           { projection(2, 0); } | ||||
|           projectionDef([[['span', SelectorFlags.CLASS, 'toSecond']]], ['span.toSecond']); | ||||
|           elementStart(0, 'div', ['id', 'first']); | ||||
|           { projection(1); } | ||||
|           elementEnd(); | ||||
|           elementStart(3, 'div', ['id', 'second']); | ||||
|           { projection(4, 0, 1); } | ||||
|           elementStart(2, 'div', ['id', 'second']); | ||||
|           { projection(3, 1); } | ||||
|           elementEnd(); | ||||
|         } | ||||
|       }); | ||||
| @ -1425,11 +1537,11 @@ describe('content projection', () => { | ||||
|        */ | ||||
|       const GrandChild = createComponent('grand-child', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef(0, [[['span']]], ['span']); | ||||
|           projection(1, 0, 1); | ||||
|           elementStart(2, 'hr'); | ||||
|           projectionDef([[['span']]], ['span']); | ||||
|           projection(0, 1); | ||||
|           elementStart(1, 'hr'); | ||||
|           elementEnd(); | ||||
|           projection(3, 0, 0); | ||||
|           projection(2); | ||||
|         } | ||||
|       }); | ||||
| 
 | ||||
| @ -1441,12 +1553,12 @@ describe('content projection', () => { | ||||
|        */ | ||||
|       const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef(0); | ||||
|           elementStart(1, 'grand-child'); | ||||
|           projectionDef(); | ||||
|           elementStart(0, 'grand-child'); | ||||
|           { | ||||
|             projection(2, 0); | ||||
|             elementStart(3, 'span'); | ||||
|             { text(4, 'in child template'); } | ||||
|             projection(1); | ||||
|             elementStart(2, 'span'); | ||||
|             { text(3, 'in child template'); } | ||||
|             elementEnd(); | ||||
|           } | ||||
|           elementEnd(); | ||||
| @ -1488,12 +1600,12 @@ describe('content projection', () => { | ||||
|       const Card = createComponent('card', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef( | ||||
|               0, [[['', 'card-title', '']], [['', 'card-content', '']]], | ||||
|               [[['', 'card-title', '']], [['', 'card-content', '']]], | ||||
|               ['[card-title]', '[card-content]']); | ||||
|           projection(1, 0, 1); | ||||
|           elementStart(2, 'hr'); | ||||
|           projection(0, 1); | ||||
|           elementStart(1, 'hr'); | ||||
|           elementEnd(); | ||||
|           projection(3, 0, 2); | ||||
|           projection(2, 2); | ||||
|         } | ||||
|       }); | ||||
| 
 | ||||
| @ -1505,13 +1617,13 @@ describe('content projection', () => { | ||||
|        */ | ||||
|       const CardWithTitle = createComponent('card-with-title', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef(0); | ||||
|           elementStart(1, 'card'); | ||||
|           projectionDef(); | ||||
|           elementStart(0, 'card'); | ||||
|           { | ||||
|             elementStart(2, 'h1', ['card-title', '']); | ||||
|             { text(3, 'Title'); } | ||||
|             elementStart(1, 'h1', ['card-title', '']); | ||||
|             { text(2, 'Title'); } | ||||
|             elementEnd(); | ||||
|             projection(4, 0, 0, ['card-content', '']); | ||||
|             projection(3, 0, ['card-content', '']); | ||||
|           } | ||||
|           elementEnd(); | ||||
|         } | ||||
| @ -1547,12 +1659,12 @@ describe('content projection', () => { | ||||
|       const Card = createComponent('card', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef( | ||||
|               0, [[['', 'card-title', '']], [['', 'card-content', '']]], | ||||
|               [[['', 'card-title', '']], [['', 'card-content', '']]], | ||||
|               ['[card-title]', '[card-content]']); | ||||
|           projection(1, 0, 1); | ||||
|           elementStart(2, 'hr'); | ||||
|           projection(0, 1); | ||||
|           elementStart(1, 'hr'); | ||||
|           elementEnd(); | ||||
|           projection(3, 0, 2); | ||||
|           projection(2, 2); | ||||
|         } | ||||
|       }); | ||||
| 
 | ||||
| @ -1564,13 +1676,13 @@ describe('content projection', () => { | ||||
|        */ | ||||
|       const CardWithTitle = createComponent('card-with-title', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef(0); | ||||
|           elementStart(1, 'card'); | ||||
|           projectionDef(); | ||||
|           elementStart(0, 'card'); | ||||
|           { | ||||
|             elementStart(2, 'h1', ['ngProjectAs', '[card-title]']); | ||||
|             { text(3, 'Title'); } | ||||
|             elementStart(1, 'h1', ['ngProjectAs', '[card-title]']); | ||||
|             { text(2, 'Title'); } | ||||
|             elementEnd(); | ||||
|             projection(4, 0, 0, ['ngProjectAs', '[card-content]']); | ||||
|             projection(3, 0, ['ngProjectAs', '[card-content]']); | ||||
|           } | ||||
|           elementEnd(); | ||||
|         } | ||||
| @ -1602,8 +1714,8 @@ describe('content projection', () => { | ||||
|        */ | ||||
|       const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef(0, [[['div']]], ['div']); | ||||
|           projection(1, 0, 1); | ||||
|           projectionDef([[['div']]], ['div']); | ||||
|           projection(0, 1); | ||||
|         } | ||||
|       }); | ||||
| 
 | ||||
| @ -1641,9 +1753,9 @@ describe('content projection', () => { | ||||
|        */ | ||||
|       const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef(0, [[['div']]], ['div']); | ||||
|           elementStart(1, 'span'); | ||||
|           { projection(2, 0, 1); } | ||||
|           projectionDef([[['div']]], ['div']); | ||||
|           elementStart(0, 'span'); | ||||
|           { projection(1, 1); } | ||||
|           elementEnd(); | ||||
|         } | ||||
|       }); | ||||
|  | ||||
| @ -947,8 +947,8 @@ describe('di', () => { | ||||
|         factory: () => comp = new MyComp(injectChangeDetectorRef()), | ||||
|         template: function(rf: RenderFlags, ctx: MyComp) { | ||||
|           if (rf & RenderFlags.Create) { | ||||
|             projectionDef(0); | ||||
|             projection(1, 0); | ||||
|             projectionDef(); | ||||
|             projection(0); | ||||
|           } | ||||
|         } | ||||
|       }); | ||||
|  | ||||
| @ -971,9 +971,9 @@ describe('Runtime i18n', () => { | ||||
|           factory: () => new Child(), | ||||
|           template: (rf: RenderFlags, cmp: Child) => { | ||||
|             if (rf & RenderFlags.Create) { | ||||
|               projectionDef(0); | ||||
|               elementStart(1, 'p'); | ||||
|               { projection(2, 0); } | ||||
|               projectionDef(); | ||||
|               elementStart(0, 'p'); | ||||
|               { projection(1); } | ||||
|               elementEnd(); | ||||
|             } | ||||
|           } | ||||
| @ -1063,9 +1063,9 @@ describe('Runtime i18n', () => { | ||||
|           factory: () => new Child(), | ||||
|           template: (rf: RenderFlags, cmp: Child) => { | ||||
|             if (rf & RenderFlags.Create) { | ||||
|               projectionDef(0); | ||||
|               elementStart(1, 'p'); | ||||
|               { projection(2, 0); } | ||||
|               projectionDef(); | ||||
|               elementStart(0, 'p'); | ||||
|               { projection(1); } | ||||
|               elementEnd(); | ||||
|             } | ||||
|           } | ||||
| @ -1145,9 +1145,9 @@ describe('Runtime i18n', () => { | ||||
|           factory: () => new GrandChild(), | ||||
|           template: (rf: RenderFlags, cmp: Child) => { | ||||
|             if (rf & RenderFlags.Create) { | ||||
|               projectionDef(0); | ||||
|               elementStart(1, 'div'); | ||||
|               { projection(2, 0); } | ||||
|               projectionDef(); | ||||
|               elementStart(0, 'div'); | ||||
|               { projection(1); } | ||||
|               elementEnd(); | ||||
|             } | ||||
|           } | ||||
| @ -1164,9 +1164,9 @@ describe('Runtime i18n', () => { | ||||
|           factory: () => new Child(), | ||||
|           template: (rf: RenderFlags, cmp: Child) => { | ||||
|             if (rf & RenderFlags.Create) { | ||||
|               projectionDef(0); | ||||
|               elementStart(1, 'grand-child'); | ||||
|               { projection(2, 0); } | ||||
|               projectionDef(); | ||||
|               elementStart(0, 'grand-child'); | ||||
|               { projection(1); } | ||||
|               elementEnd(); | ||||
|             } | ||||
|           } | ||||
| @ -1224,8 +1224,8 @@ describe('Runtime i18n', () => { | ||||
|           factory: () => new Child(), | ||||
|           template: (rf: RenderFlags, cmp: Child) => { | ||||
|             if (rf & RenderFlags.Create) { | ||||
|               projectionDef(0, [[['span']]], ['span']); | ||||
|               projection(1, 0, 1); | ||||
|               projectionDef([[['span']]], ['span']); | ||||
|               projection(0, 1); | ||||
|             } | ||||
|           } | ||||
|         }); | ||||
|  | ||||
| @ -502,19 +502,19 @@ describe('render3 integration test', () => { | ||||
|         template: function ChildComponentTemplate( | ||||
|             rf: RenderFlags, ctx: {beforeTree: Tree, afterTree: Tree}) { | ||||
|           if (rf & RenderFlags.Create) { | ||||
|             projectionDef(0); | ||||
|             container(1); | ||||
|             projection(2, 0); | ||||
|             container(3); | ||||
|             projectionDef(); | ||||
|             container(0); | ||||
|             projection(1); | ||||
|             container(2); | ||||
|           } | ||||
|           containerRefreshStart(1); | ||||
|           containerRefreshStart(0); | ||||
|           { | ||||
|             const rf0 = embeddedViewStart(0); | ||||
|             { showTree(rf0, {tree: ctx.beforeTree}); } | ||||
|             embeddedViewEnd(); | ||||
|           } | ||||
|           containerRefreshEnd(); | ||||
|           containerRefreshStart(3); | ||||
|           containerRefreshStart(2); | ||||
|           { | ||||
|             const rf0 = embeddedViewStart(0); | ||||
|             { showTree(rf0, {tree: ctx.afterTree}); } | ||||
|  | ||||
| @ -33,9 +33,9 @@ describe('lifecycles', () => { | ||||
| 
 | ||||
|     let Comp = createOnInitComponent('comp', (rf: RenderFlags, ctx: any) => { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'div'); | ||||
|         { projection(2, 0); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { projection(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }); | ||||
| @ -500,27 +500,27 @@ describe('lifecycles', () => { | ||||
| 
 | ||||
|     let Comp = createAfterContentInitComp('comp', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         projection(1, 0); | ||||
|         projectionDef(); | ||||
|         projection(0); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     let Parent = createAfterContentInitComp('parent', function(rf: RenderFlags, ctx: any) { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'comp'); | ||||
|         { projection(2, 0); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'comp'); | ||||
|         { projection(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|       if (rf & RenderFlags.Update) { | ||||
|         elementProperty(1, 'val', bind(ctx.val)); | ||||
|         elementProperty(0, 'val', bind(ctx.val)); | ||||
|       } | ||||
|     }, [Comp]); | ||||
| 
 | ||||
|     let ProjectedComp = createAfterContentInitComp('projected', (rf: RenderFlags, ctx: any) => { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         projection(1, 0); | ||||
|         projectionDef(); | ||||
|         projection(0); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
| @ -893,9 +893,9 @@ describe('lifecycles', () => { | ||||
| 
 | ||||
|     let Comp = createAfterViewInitComponent('comp', (rf: RenderFlags, ctx: any) => { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'div'); | ||||
|         { projection(2, 0); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { projection(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }); | ||||
| @ -1356,8 +1356,8 @@ describe('lifecycles', () => { | ||||
| 
 | ||||
|     let Comp = createOnDestroyComponent('comp', (rf: RenderFlags, ctx: any) => { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         projection(1, 0); | ||||
|         projectionDef(); | ||||
|         projection(0); | ||||
|       } | ||||
|     }); | ||||
|     let Parent = createOnDestroyComponent('parent', getParentTemplate('comp'), [Comp]); | ||||
| @ -1893,9 +1893,9 @@ describe('lifecycles', () => { | ||||
| 
 | ||||
|     const Comp = createOnChangesComponent('comp', (rf: RenderFlags, ctx: any) => { | ||||
|       if (rf & RenderFlags.Create) { | ||||
|         projectionDef(0); | ||||
|         elementStart(1, 'div'); | ||||
|         { projection(2, 0); } | ||||
|         projectionDef(); | ||||
|         elementStart(0, 'div'); | ||||
|         { projection(1); } | ||||
|         elementEnd(); | ||||
|       } | ||||
|     }); | ||||
| @ -2444,13 +2444,13 @@ describe('lifecycles', () => { | ||||
|       /** <ng-content></ng-content><view [val]="val"></view> */ | ||||
|       const Parent = createAllHooksComponent('parent', (rf: RenderFlags, ctx: any) => { | ||||
|         if (rf & RenderFlags.Create) { | ||||
|           projectionDef(0); | ||||
|           projection(1, 0); | ||||
|           elementStart(2, 'view'); | ||||
|           projectionDef(); | ||||
|           projection(0); | ||||
|           elementStart(1, 'view'); | ||||
|           elementEnd(); | ||||
|         } | ||||
|         if (rf & RenderFlags.Update) { | ||||
|           elementProperty(2, 'val', bind(ctx.val)); | ||||
|           elementProperty(1, 'val', bind(ctx.val)); | ||||
|         } | ||||
|       }, [View]); | ||||
| 
 | ||||
|  | ||||
| @ -10,29 +10,16 @@ import {AttributeMarker, TAttributes, TNode, TNodeType} from '../../src/render3/ | ||||
| 
 | ||||
| import {CssSelector, CssSelectorList, NG_PROJECT_AS_ATTR_NAME, SelectorFlags,} from '../../src/render3/interfaces/projection'; | ||||
| import {getProjectAsAttrValue, isNodeMatchingSelectorList, isNodeMatchingSelector} from '../../src/render3/node_selector_matcher'; | ||||
| import {createTNode} from '@angular/core/src/render3/instructions'; | ||||
| 
 | ||||
| function testLStaticData(tagName: string, attrs: TAttributes | null): TNode { | ||||
|   return { | ||||
|     type: TNodeType.Element, | ||||
|     index: 0, | ||||
|     flags: 0, tagName, attrs, | ||||
|     localNames: null, | ||||
|     initialInputs: undefined, | ||||
|     inputs: undefined, | ||||
|     outputs: undefined, | ||||
|     tViews: null, | ||||
|     next: null, | ||||
|     child: null, | ||||
|     parent: null, | ||||
|     dynamicContainerNode: null, | ||||
|     detached: null, | ||||
|     stylingTemplate: null | ||||
|   }; | ||||
|   return createTNode(TNodeType.Element, 0, tagName, attrs, null, null); | ||||
| } | ||||
| 
 | ||||
| describe('css selector matching', () => { | ||||
|   function isMatching(tagName: string, attrs: TAttributes | null, selector: CssSelector): boolean { | ||||
|     return isNodeMatchingSelector(testLStaticData(tagName, attrs), selector); | ||||
|     return isNodeMatchingSelector( | ||||
|         createTNode(TNodeType.Element, 0, tagName, attrs, null, null), selector); | ||||
|   } | ||||
| 
 | ||||
|   describe('isNodeMatchingSimpleSelector', () => { | ||||
|  | ||||
| @ -671,9 +671,9 @@ describe('ViewContainerRef', () => { | ||||
|           factory: () => new Child(), | ||||
|           template: (rf: RenderFlags, cmp: Child) => { | ||||
|             if (rf & RenderFlags.Create) { | ||||
|               projectionDef(0); | ||||
|               elementStart(1, 'div'); | ||||
|               { projection(2, 0); } | ||||
|               projectionDef(); | ||||
|               elementStart(0, 'div'); | ||||
|               { projection(1); } | ||||
|               elementEnd(); | ||||
|             } | ||||
|           } | ||||
| @ -742,17 +742,17 @@ describe('ViewContainerRef', () => { | ||||
|           factory: () => new ChildWithView(), | ||||
|           template: (rf: RenderFlags, cmp: ChildWithView) => { | ||||
|             if (rf & RenderFlags.Create) { | ||||
|               projectionDef(0); | ||||
|               text(1, 'Before (inside)-'); | ||||
|               container(2); | ||||
|               text(3, 'After (inside)'); | ||||
|               projectionDef(); | ||||
|               text(0, 'Before (inside)-'); | ||||
|               container(1); | ||||
|               text(2, 'After (inside)'); | ||||
|             } | ||||
|             if (rf & RenderFlags.Update) { | ||||
|               containerRefreshStart(2); | ||||
|               containerRefreshStart(1); | ||||
|               if (cmp.show) { | ||||
|                 let rf0 = embeddedViewStart(0); | ||||
|                 if (rf0 & RenderFlags.Create) { | ||||
|                   projection(0, 0); | ||||
|                   projection(0); | ||||
|                 } | ||||
|                 embeddedViewEnd(); | ||||
|               } | ||||
| @ -827,12 +827,12 @@ describe('ViewContainerRef', () => { | ||||
|           factory: () => new ChildWithSelector(), | ||||
|           template: (rf: RenderFlags, cmp: ChildWithSelector) => { | ||||
|             if (rf & RenderFlags.Create) { | ||||
|               projectionDef(0, [[['header']]], ['header']); | ||||
|               elementStart(1, 'first'); | ||||
|               { projection(2, 0, 1); } | ||||
|               projectionDef([[['header']]], ['header']); | ||||
|               elementStart(0, 'first'); | ||||
|               { projection(1, 1); } | ||||
|               elementEnd(); | ||||
|               elementStart(3, 'second'); | ||||
|               { projection(4, 0); } | ||||
|               elementStart(2, 'second'); | ||||
|               { projection(3); } | ||||
|               elementEnd(); | ||||
|             } | ||||
|           }, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user