parent
47f4412650
commit
aedebaf025
@ -18,7 +18,7 @@ import {CLEAN_PROMISE, _getComponentHostLElementNode, baseDirectiveCreate, creat
|
|||||||
import {ComponentDef, ComponentDefInternal, ComponentType} from './interfaces/definition';
|
import {ComponentDef, ComponentDefInternal, ComponentType} from './interfaces/definition';
|
||||||
import {LElementNode} from './interfaces/node';
|
import {LElementNode} from './interfaces/node';
|
||||||
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
||||||
import {LViewData, LViewFlags, RootContext, BINDING_INDEX, INJECTOR, CONTEXT, TVIEW} from './interfaces/view';
|
import {LViewData, LViewFlags, RootContext, INJECTOR, CONTEXT, TVIEW} from './interfaces/view';
|
||||||
import {stringify} from './util';
|
import {stringify} from './util';
|
||||||
import {getComponentDef} from './definition';
|
import {getComponentDef} from './definition';
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ export interface CreateComponentOptions {
|
|||||||
* features list because there's no way of knowing when the component will be used as
|
* features list because there's no way of knowing when the component will be used as
|
||||||
* a root component.
|
* a root component.
|
||||||
*/
|
*/
|
||||||
hostFeatures?: (<T>(component: T, componentDef: ComponentDef<T, string>) => void)[];
|
hostFeatures?: HostFeature[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function which is used to schedule change detection work in the future.
|
* A function which is used to schedule change detection work in the future.
|
||||||
@ -69,6 +69,9 @@ export interface CreateComponentOptions {
|
|||||||
scheduler?: (work: () => void) => void;
|
scheduler?: (work: () => void) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** See CreateComponentOptions.hostFeatures */
|
||||||
|
type HostFeature = (<T>(component: T, componentDef: ComponentDef<T, string>) => void);
|
||||||
|
|
||||||
// TODO: A hack to not pull in the NullInjector from @angular/core.
|
// TODO: A hack to not pull in the NullInjector from @angular/core.
|
||||||
export const NULL_INJECTOR: Injector = {
|
export const NULL_INJECTOR: Injector = {
|
||||||
get: (token: any, notFoundValue?: any) => {
|
get: (token: any, notFoundValue?: any) => {
|
||||||
@ -103,12 +106,13 @@ export function renderComponent<T>(
|
|||||||
// The first index of the first selector is the tag name.
|
// The first index of the first selector is the tag name.
|
||||||
const componentTag = componentDef.selectors ![0] ![0] as string;
|
const componentTag = componentDef.selectors ![0] ![0] as string;
|
||||||
const hostNode = locateHostElement(rendererFactory, opts.host || componentTag);
|
const hostNode = locateHostElement(rendererFactory, opts.host || componentTag);
|
||||||
|
const rootFlags = componentDef.onPush ? LViewFlags.Dirty | LViewFlags.IsRoot :
|
||||||
|
LViewFlags.CheckAlways | LViewFlags.IsRoot;
|
||||||
const rootContext = createRootContext(opts.scheduler || requestAnimationFrame.bind(window));
|
const rootContext = createRootContext(opts.scheduler || requestAnimationFrame.bind(window));
|
||||||
|
|
||||||
const rootView: LViewData = createLViewData(
|
const rootView: LViewData = createLViewData(
|
||||||
rendererFactory.createRenderer(hostNode, componentDef),
|
rendererFactory.createRenderer(hostNode, componentDef),
|
||||||
createTView(-1, null, 1, 0, null, null, null), rootContext,
|
createTView(-1, null, 1, 0, null, null, null), rootContext, rootFlags);
|
||||||
componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways);
|
|
||||||
rootView[INJECTOR] = opts.injector || null;
|
rootView[INJECTOR] = opts.injector || null;
|
||||||
|
|
||||||
const oldView = enterView(rootView, null);
|
const oldView = enterView(rootView, null);
|
||||||
@ -119,20 +123,10 @@ export function renderComponent<T>(
|
|||||||
|
|
||||||
// Create element node at index 0 in data array
|
// Create element node at index 0 in data array
|
||||||
elementNode = hostElement(componentTag, hostNode, componentDef, sanitizer);
|
elementNode = hostElement(componentTag, hostNode, componentDef, sanitizer);
|
||||||
|
component = createRootComponent(
|
||||||
// Create directive instance with factory() and store at index 0 in directives array
|
elementNode, componentDef, rootView, rootContext, opts.hostFeatures || null);
|
||||||
component = baseDirectiveCreate(0, componentDef.factory() as T, componentDef, elementNode);
|
|
||||||
if (componentDef.hostBindings) {
|
|
||||||
queueHostBindingForCheck(0, componentDef.hostVars);
|
|
||||||
}
|
|
||||||
rootContext.components.push(component);
|
|
||||||
(elementNode.data as LViewData)[CONTEXT] = component;
|
|
||||||
initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data !);
|
|
||||||
|
|
||||||
opts.hostFeatures && opts.hostFeatures.forEach((feature) => feature(component, componentDef));
|
|
||||||
|
|
||||||
executeInitAndContentHooks();
|
executeInitAndContentHooks();
|
||||||
setHostBindings(rootView[TVIEW].hostBindings);
|
|
||||||
detectChangesInternal(elementNode.data as LViewData, component);
|
detectChangesInternal(elementNode.data as LViewData, component);
|
||||||
} finally {
|
} finally {
|
||||||
leaveView(oldView);
|
leaveView(oldView);
|
||||||
@ -142,6 +136,27 @@ export function renderComponent<T>(
|
|||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a root component and sets it up with features and host bindings. Shared by
|
||||||
|
* renderComponent() and ViewContainerRef.createComponent().
|
||||||
|
*/
|
||||||
|
export function createRootComponent<T>(
|
||||||
|
elementNode: LElementNode, componentDef: ComponentDef<T, string>, rootView: LViewData,
|
||||||
|
rootContext: RootContext, hostFeatures: HostFeature[] | null): any {
|
||||||
|
// Create directive instance with factory() and store at index 0 in directives array
|
||||||
|
const component = baseDirectiveCreate(0, componentDef.factory() as T, componentDef, elementNode);
|
||||||
|
|
||||||
|
if (componentDef.hostBindings) queueHostBindingForCheck(0, componentDef.hostVars);
|
||||||
|
rootContext.components.push(component);
|
||||||
|
(elementNode.data as LViewData)[CONTEXT] = component;
|
||||||
|
initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data as LViewData);
|
||||||
|
|
||||||
|
hostFeatures && hostFeatures.forEach((feature) => feature(component, componentDef));
|
||||||
|
setHostBindings(rootView[TVIEW].hostBindings);
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function createRootContext(scheduler: (workFn: () => void) => void): RootContext {
|
export function createRootContext(scheduler: (workFn: () => void) => void): RootContext {
|
||||||
return {
|
return {
|
||||||
components: [],
|
components: [],
|
||||||
@ -169,7 +184,8 @@ export function LifecycleHooksFeature(component: any, def: ComponentDefInternal<
|
|||||||
// Root component is always created at dir index 0
|
// Root component is always created at dir index 0
|
||||||
const tView = elementNode.view[TVIEW];
|
const tView = elementNode.view[TVIEW];
|
||||||
queueInitHooks(0, def.onInit, def.doCheck, tView);
|
queueInitHooks(0, def.onInit, def.doCheck, tView);
|
||||||
queueLifecycleHooks(elementNode.tNode.flags, tView);
|
// Directive starting index 0, directive count 1 -> directive flags: 1
|
||||||
|
queueLifecycleHooks(1, tView);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,13 +17,13 @@ import {RendererFactory2} from '../render/api';
|
|||||||
import {Type} from '../type';
|
import {Type} from '../type';
|
||||||
|
|
||||||
import {assertComponentType, assertDefined} from './assert';
|
import {assertComponentType, assertDefined} from './assert';
|
||||||
import {LifecycleHooksFeature, createRootContext} from './component';
|
import {LifecycleHooksFeature, createRootComponent, createRootContext} from './component';
|
||||||
import {getComponentDef} from './definition';
|
import {getComponentDef} from './definition';
|
||||||
import {adjustBlueprintForNewNode, baseDirectiveCreate, createLNode, createLViewData, createTView, elementCreate, enterView, hostElement, initChangeDetectorIfExisting, locateHostElement, queueHostBindingForCheck, renderEmbeddedTemplate, setHostBindings} from './instructions';
|
import {adjustBlueprintForNewNode, createLViewData, createNodeAtIndex, createTView, elementCreate, enterView, getTNode, hostElement, locateHostElement, renderEmbeddedTemplate} from './instructions';
|
||||||
import {ComponentDefInternal, ComponentType, RenderFlags} from './interfaces/definition';
|
import {ComponentDefInternal, RenderFlags} from './interfaces/definition';
|
||||||
import {LElementNode, TNode, TNodeType} from './interfaces/node';
|
import {LElementNode, TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node';
|
||||||
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
||||||
import {CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
|
import {FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
|
||||||
import {RootViewRef, ViewRef} from './view_ref';
|
import {RootViewRef, ViewRef} from './view_ref';
|
||||||
|
|
||||||
export class ComponentFactoryResolver extends viewEngine_ComponentFactoryResolver {
|
export class ComponentFactoryResolver extends viewEngine_ComponentFactoryResolver {
|
||||||
@ -115,6 +115,8 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
|||||||
// The first index of the first selector is the tag name.
|
// The first index of the first selector is the tag name.
|
||||||
const componentTag = this.componentDef.selectors ![0] ![0] as string;
|
const componentTag = this.componentDef.selectors ![0] ![0] as string;
|
||||||
|
|
||||||
|
const rootFlags = this.componentDef.onPush ? LViewFlags.Dirty | LViewFlags.IsRoot :
|
||||||
|
LViewFlags.CheckAlways | LViewFlags.IsRoot;
|
||||||
const rootContext: RootContext = ngModule && !isInternalRootView ?
|
const rootContext: RootContext = ngModule && !isInternalRootView ?
|
||||||
ngModule.injector.get(ROOT_CONTEXT) :
|
ngModule.injector.get(ROOT_CONTEXT) :
|
||||||
createRootContext(requestAnimationFrame.bind(window));
|
createRootContext(requestAnimationFrame.bind(window));
|
||||||
@ -122,8 +124,7 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
|||||||
// Create the root view. Uses empty TView and ContentTemplate.
|
// Create the root view. Uses empty TView and ContentTemplate.
|
||||||
const rootView: LViewData = createLViewData(
|
const rootView: LViewData = createLViewData(
|
||||||
rendererFactory.createRenderer(hostNode, this.componentDef),
|
rendererFactory.createRenderer(hostNode, this.componentDef),
|
||||||
createTView(-1, null, 1, 0, null, null, null), rootContext,
|
createTView(-1, null, 1, 0, null, null, null), rootContext, rootFlags);
|
||||||
this.componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways);
|
|
||||||
rootView[INJECTOR] = ngModule && ngModule.injector || null;
|
rootView[INJECTOR] = ngModule && ngModule.injector || null;
|
||||||
|
|
||||||
// rootView is the parent when bootstrapping
|
// rootView is the parent when bootstrapping
|
||||||
@ -131,54 +132,43 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
|||||||
|
|
||||||
let component: T;
|
let component: T;
|
||||||
let elementNode: LElementNode;
|
let elementNode: LElementNode;
|
||||||
|
let tElementNode: TElementNode;
|
||||||
try {
|
try {
|
||||||
if (rendererFactory.begin) rendererFactory.begin();
|
if (rendererFactory.begin) rendererFactory.begin();
|
||||||
|
|
||||||
// Create element node at index 0 in data array
|
// Create element node at index 0 in data array
|
||||||
elementNode = hostElement(componentTag, hostNode, this.componentDef);
|
elementNode = hostElement(componentTag, hostNode, this.componentDef);
|
||||||
const componentView = elementNode.data as LViewData;
|
|
||||||
|
|
||||||
// Create directive instance with factory() and store at index 0 in directives array
|
|
||||||
component =
|
|
||||||
baseDirectiveCreate(0, this.componentDef.factory(), this.componentDef, elementNode);
|
|
||||||
if (this.componentDef.hostBindings) {
|
|
||||||
queueHostBindingForCheck(0, this.componentDef.hostVars);
|
|
||||||
}
|
|
||||||
rootContext.components.push(component);
|
|
||||||
initChangeDetectorIfExisting(elementNode.nodeInjector, component, componentView);
|
|
||||||
componentView[CONTEXT] = component;
|
|
||||||
// TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
|
// TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
|
||||||
// executed here?
|
// executed here?
|
||||||
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
|
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
|
||||||
LifecycleHooksFeature(component, this.componentDef);
|
component = createRootComponent(
|
||||||
|
elementNode, this.componentDef, rootView, rootContext, [LifecycleHooksFeature]);
|
||||||
|
|
||||||
setHostBindings(rootView[TVIEW].hostBindings);
|
tElementNode = getTNode(0) as TElementNode;
|
||||||
|
|
||||||
// Transform the arrays of native nodes into a LNode structure that can be consumed by the
|
// Transform the arrays of native nodes into a LNode structure that can be consumed by the
|
||||||
// projection instruction. This is needed to support the reprojection of these nodes.
|
// projection instruction. This is needed to support the reprojection of these nodes.
|
||||||
if (projectableNodes) {
|
if (projectableNodes) {
|
||||||
let index = 0;
|
let index = 0;
|
||||||
const projection: TNode[] = elementNode.tNode.projection = [];
|
const projection: TNode[] = tElementNode.projection = [];
|
||||||
for (let i = 0; i < projectableNodes.length; i++) {
|
for (let i = 0; i < projectableNodes.length; i++) {
|
||||||
const nodeList = projectableNodes[i];
|
const nodeList = projectableNodes[i];
|
||||||
let firstTNode: TNode|null = null;
|
let firstTNode: TNode|null = null;
|
||||||
let previousTNode: TNode|null = null;
|
let previousTNode: TNode|null = null;
|
||||||
for (let j = 0; j < nodeList.length; j++) {
|
for (let j = 0; j < nodeList.length; j++) {
|
||||||
adjustBlueprintForNewNode(rootView);
|
adjustBlueprintForNewNode(rootView);
|
||||||
const lNode =
|
const tNode =
|
||||||
createLNode(++index, TNodeType.Element, nodeList[j] as RElement, null, null);
|
createNodeAtIndex(++index, TNodeType.Element, nodeList[j] as RElement, null, null);
|
||||||
if (previousTNode) {
|
previousTNode ? (previousTNode.next = tNode) : (firstTNode = tNode);
|
||||||
previousTNode.next = lNode.tNode;
|
previousTNode = tNode;
|
||||||
} else {
|
|
||||||
firstTNode = lNode.tNode;
|
|
||||||
}
|
|
||||||
previousTNode = lNode.tNode;
|
|
||||||
}
|
}
|
||||||
projection.push(firstTNode !);
|
projection.push(firstTNode !);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the template in creation mode only, and then turn off the CreationMode flag
|
// Execute the template in creation mode only, and then turn off the CreationMode flag
|
||||||
|
const componentView = elementNode.data as LViewData;
|
||||||
renderEmbeddedTemplate(componentView, componentView[TVIEW], component, RenderFlags.Create);
|
renderEmbeddedTemplate(componentView, componentView[TVIEW], component, RenderFlags.Create);
|
||||||
componentView[FLAGS] &= ~LViewFlags.CreationMode;
|
componentView[FLAGS] &= ~LViewFlags.CreationMode;
|
||||||
} finally {
|
} finally {
|
||||||
@ -190,7 +180,7 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
|||||||
new ComponentRef(this.componentType, component, rootView, injector, hostNode !);
|
new ComponentRef(this.componentType, component, rootView, injector, hostNode !);
|
||||||
if (isInternalRootView) {
|
if (isInternalRootView) {
|
||||||
// The host element of the internal root view is attached to the component's host view node
|
// The host element of the internal root view is attached to the component's host view node
|
||||||
componentRef.hostView._lViewNode !.tNode.child = elementNode.tNode;
|
componentRef.hostView._tViewNode !.child = tElementNode;
|
||||||
}
|
}
|
||||||
return componentRef;
|
return componentRef;
|
||||||
}
|
}
|
||||||
@ -219,7 +209,7 @@ export class ComponentRef<T> extends viewEngine_ComponentRef<T> {
|
|||||||
super();
|
super();
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
this.hostView = this.changeDetectorRef = new RootViewRef<T>(rootView);
|
this.hostView = this.changeDetectorRef = new RootViewRef<T>(rootView);
|
||||||
this.hostView._lViewNode = createLNode(-1, TNodeType.View, null, null, null, rootView);
|
this.hostView._tViewNode = createNodeAtIndex(-1, TNodeType.View, null, null, null, rootView);
|
||||||
this.injector = injector;
|
this.injector = injector;
|
||||||
this.location = new viewEngine_ElementRef(hostNode);
|
this.location = new viewEngine_ElementRef(hostNode);
|
||||||
this.componentType = componentType;
|
this.componentType = componentType;
|
||||||
|
@ -321,9 +321,8 @@ function findViaDirective(lViewData: LViewData, directiveInstance: {}): number {
|
|||||||
if (directiveIndex >= 0) {
|
if (directiveIndex >= 0) {
|
||||||
let tNode = lViewData[TVIEW].firstChild;
|
let tNode = lViewData[TVIEW].firstChild;
|
||||||
while (tNode) {
|
while (tNode) {
|
||||||
const lNode = getLNodeFromViewData(lViewData, tNode.index) !;
|
const directiveIndexStart = getDirectiveStartIndex(tNode);
|
||||||
const directiveIndexStart = getDirectiveStartIndex(lNode);
|
const directiveIndexEnd = getDirectiveEndIndex(tNode, directiveIndexStart);
|
||||||
const directiveIndexEnd = getDirectiveEndIndex(lNode, directiveIndexStart);
|
|
||||||
if (directiveIndex >= directiveIndexStart && directiveIndex < directiveIndexEnd) {
|
if (directiveIndex >= directiveIndexStart && directiveIndex < directiveIndexEnd) {
|
||||||
return tNode.index;
|
return tNode.index;
|
||||||
}
|
}
|
||||||
@ -357,10 +356,11 @@ function getLNodeFromViewData(lViewData: LViewData, lElementIndex: number): LEle
|
|||||||
function discoverDirectiveIndices(lViewData: LViewData, lNodeIndex: number): number[]|null {
|
function discoverDirectiveIndices(lViewData: LViewData, lNodeIndex: number): number[]|null {
|
||||||
const directivesAcrossView = lViewData[DIRECTIVES];
|
const directivesAcrossView = lViewData[DIRECTIVES];
|
||||||
const lNode = getLNodeFromViewData(lViewData, lNodeIndex);
|
const lNode = getLNodeFromViewData(lViewData, lNodeIndex);
|
||||||
|
const tNode = lViewData[TVIEW].data[lNodeIndex] as TNode;
|
||||||
if (lNode && directivesAcrossView && directivesAcrossView.length) {
|
if (lNode && directivesAcrossView && directivesAcrossView.length) {
|
||||||
// this check for tNode is to determine if the calue is a LEmementNode instance
|
// this check for tNode is to determine if the calue is a LEmementNode instance
|
||||||
const directiveIndexStart = getDirectiveStartIndex(lNode);
|
const directiveIndexStart = getDirectiveStartIndex(tNode);
|
||||||
const directiveIndexEnd = getDirectiveEndIndex(lNode, directiveIndexStart);
|
const directiveIndexEnd = getDirectiveEndIndex(tNode, directiveIndexStart);
|
||||||
const directiveIndices: number[] = [];
|
const directiveIndices: number[] = [];
|
||||||
for (let i = directiveIndexStart; i < directiveIndexEnd; i++) {
|
for (let i = directiveIndexStart; i < directiveIndexEnd; i++) {
|
||||||
// special case since the instance of the component (if it exists)
|
// special case since the instance of the component (if it exists)
|
||||||
@ -388,17 +388,17 @@ function discoverDirectives(lViewData: LViewData, directiveIndices: number[]): n
|
|||||||
return directives;
|
return directives;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDirectiveStartIndex(lNode: LElementNode): number {
|
function getDirectiveStartIndex(tNode: TNode): number {
|
||||||
// the tNode instances store a flag value which then has a
|
// the tNode instances store a flag value which then has a
|
||||||
// pointer which tells the starting index of where all the
|
// pointer which tells the starting index of where all the
|
||||||
// active directives are in the master directive array
|
// active directives are in the master directive array
|
||||||
return lNode.tNode.flags >> TNodeFlags.DirectiveStartingIndexShift;
|
return tNode.flags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDirectiveEndIndex(lNode: LElementNode, startIndex: number): number {
|
function getDirectiveEndIndex(tNode: TNode, startIndex: number): number {
|
||||||
// The end value is also apart of the same flag
|
// The end value is also a part of the same flag
|
||||||
// (see `TNodeFlags` to see how the flag bit shifting
|
// (see `TNodeFlags` to see how the flag bit shifting
|
||||||
// values are used).
|
// values are used).
|
||||||
const count = lNode.tNode.flags & TNodeFlags.DirectiveCountMask;
|
const count = tNode.flags & TNodeFlags.DirectiveCountMask;
|
||||||
return count ? (startIndex + count) : -1;
|
return count ? (startIndex + count) : -1;
|
||||||
}
|
}
|
||||||
|
@ -26,16 +26,17 @@ import {Type} from '../type';
|
|||||||
import {assertDefined, assertGreaterThan, assertLessThan} from './assert';
|
import {assertDefined, assertGreaterThan, assertLessThan} from './assert';
|
||||||
import {ComponentFactoryResolver} from './component_ref';
|
import {ComponentFactoryResolver} from './component_ref';
|
||||||
import {getComponentDef, getDirectiveDef, getPipeDef} from './definition';
|
import {getComponentDef, getDirectiveDef, getPipeDef} from './definition';
|
||||||
import {addToViewTree, assertPreviousIsParent, createEmbeddedViewNode, createLContainer, createLNodeObject, createTNode, getPreviousOrParentNode, getPreviousOrParentTNode, getRenderer, isComponent, renderEmbeddedTemplate, resolveDirective} from './instructions';
|
import {_getViewData, addToViewTree, assertPreviousIsParent, createEmbeddedViewAndNode, createLContainer, createLNodeObject, createTNode, getPreviousOrParentNode, getPreviousOrParentTNode, getRenderer, renderEmbeddedTemplate, resolveDirective} from './instructions';
|
||||||
import {VIEWS} from './interfaces/container';
|
import {RENDER_PARENT, VIEWS} from './interfaces/container';
|
||||||
import {DirectiveDefInternal, RenderFlags} from './interfaces/definition';
|
import {DirectiveDefInternal, RenderFlags} from './interfaces/definition';
|
||||||
import {LInjector} from './interfaces/injector';
|
import {LInjector} from './interfaces/injector';
|
||||||
import {AttributeMarker, LContainerNode, LElementContainerNode, LElementNode, LNode, LNodeWithLocalRefs, LViewNode, TContainerNode, TElementNode, TNodeFlags, TNodeType} from './interfaces/node';
|
import {AttributeMarker, LContainerNode, LElementContainerNode, LElementNode, LNode, LNodeWithLocalRefs, TContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TViewNode} from './interfaces/node';
|
||||||
import {LQueries, QueryReadType} from './interfaces/query';
|
import {LQueries, QueryReadType} from './interfaces/query';
|
||||||
import {Renderer3, isProceduralRenderer} from './interfaces/renderer';
|
import {RElement, Renderer3, isProceduralRenderer} from './interfaces/renderer';
|
||||||
import {DIRECTIVES, HOST_NODE, INJECTOR, LViewData, QUERIES, RENDERER, TVIEW, TView} from './interfaces/view';
|
import {CONTEXT, DIRECTIVES, HOST_NODE, INJECTOR, LViewData, PARENT, QUERIES, RENDERER, TVIEW, TView} from './interfaces/view';
|
||||||
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
||||||
import {addRemoveViewFromContainer, appendChild, detachView, getChildLNode, getParentLNode, insertView, removeView} from './node_manipulation';
|
import {addRemoveViewFromContainer, appendChild, detachView, findComponentView, getBeforeNodeForView, getHostElementNode, getParentLNode, getParentOrContainerNode, getRenderParent, insertView, removeView} from './node_manipulation';
|
||||||
|
import {isComponent, loadElementInternal} from './util';
|
||||||
import {ViewRef} from './view_ref';
|
import {ViewRef} from './view_ref';
|
||||||
|
|
||||||
|
|
||||||
@ -101,7 +102,8 @@ export function bloomAdd(injector: LInjector, type: Type<any>): void {
|
|||||||
export function getOrCreateNodeInjector(): LInjector {
|
export function getOrCreateNodeInjector(): LInjector {
|
||||||
ngDevMode && assertPreviousIsParent();
|
ngDevMode && assertPreviousIsParent();
|
||||||
return getOrCreateNodeInjectorForNode(
|
return getOrCreateNodeInjectorForNode(
|
||||||
getPreviousOrParentNode() as LElementNode | LElementContainerNode | LContainerNode);
|
getPreviousOrParentNode() as LElementNode | LElementContainerNode | LContainerNode,
|
||||||
|
getPreviousOrParentTNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,16 +113,18 @@ export function getOrCreateNodeInjector(): LInjector {
|
|||||||
* @returns Node injector
|
* @returns Node injector
|
||||||
*/
|
*/
|
||||||
export function getOrCreateNodeInjectorForNode(
|
export function getOrCreateNodeInjectorForNode(
|
||||||
node: LElementNode | LElementContainerNode | LContainerNode): LInjector {
|
node: LElementNode | LElementContainerNode | LContainerNode, tNode: TNode): LInjector {
|
||||||
|
// TODO: remove LNode arg when nodeInjector refactor is done
|
||||||
const nodeInjector = node.nodeInjector;
|
const nodeInjector = node.nodeInjector;
|
||||||
const parent = getParentLNode(node);
|
const parentLNode = getParentOrContainerNode(tNode, node.view);
|
||||||
const parentInjector = parent && parent.nodeInjector;
|
const parentInjector = parentLNode && parentLNode.nodeInjector;
|
||||||
if (nodeInjector != parentInjector) {
|
if (nodeInjector != parentInjector) {
|
||||||
return nodeInjector !;
|
return nodeInjector !;
|
||||||
}
|
}
|
||||||
return node.nodeInjector = {
|
return node.nodeInjector = {
|
||||||
parent: parentInjector,
|
parent: parentInjector,
|
||||||
node: node,
|
node: node,
|
||||||
|
tNode: tNode,
|
||||||
bf0: 0,
|
bf0: 0,
|
||||||
bf1: 0,
|
bf1: 0,
|
||||||
bf2: 0,
|
bf2: 0,
|
||||||
@ -302,32 +306,25 @@ export function getOrCreateChangeDetectorRef(
|
|||||||
di: LInjector, context: any): viewEngine_ChangeDetectorRef {
|
di: LInjector, context: any): viewEngine_ChangeDetectorRef {
|
||||||
if (di.changeDetectorRef) return di.changeDetectorRef;
|
if (di.changeDetectorRef) return di.changeDetectorRef;
|
||||||
|
|
||||||
const currentNode = di.node;
|
const currentTNode = getPreviousOrParentTNode();
|
||||||
if (isComponent(currentNode.tNode)) {
|
if (isComponent(currentTNode)) {
|
||||||
return di.changeDetectorRef = new ViewRef(currentNode.data as LViewData, context);
|
return di.changeDetectorRef = new ViewRef(di.node.data as LViewData, context);
|
||||||
} else if (currentNode.tNode.type === TNodeType.Element) {
|
} else if (currentTNode.type === TNodeType.Element) {
|
||||||
return di.changeDetectorRef = getOrCreateHostChangeDetector(currentNode.view[HOST_NODE]);
|
return di.changeDetectorRef = getOrCreateHostChangeDetector(_getViewData());
|
||||||
}
|
}
|
||||||
return null !;
|
return null !;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets or creates ChangeDetectorRef for the closest host component */
|
/** Gets or creates ChangeDetectorRef for the closest host component */
|
||||||
function getOrCreateHostChangeDetector(currentNode: LViewNode | LElementNode):
|
function getOrCreateHostChangeDetector(currentView: LViewData): viewEngine_ChangeDetectorRef {
|
||||||
viewEngine_ChangeDetectorRef {
|
const hostComponentView = findComponentView(currentView);
|
||||||
const hostNode = getClosestComponentAncestor(currentNode);
|
const hostNode = getHostElementNode(hostComponentView) !;
|
||||||
const hostInjector = hostNode.nodeInjector;
|
const hostInjector = hostNode.nodeInjector;
|
||||||
const existingRef = hostInjector && hostInjector.changeDetectorRef;
|
const existingRef = hostInjector && hostInjector.changeDetectorRef;
|
||||||
|
|
||||||
return existingRef ?
|
return existingRef ? existingRef : new ViewRef(hostComponentView, hostComponentView[CONTEXT]);
|
||||||
existingRef :
|
|
||||||
new ViewRef(
|
|
||||||
hostNode.data as LViewData,
|
|
||||||
hostNode
|
|
||||||
.view[DIRECTIVES] ![hostNode.tNode.flags >> TNodeFlags.DirectiveStartingIndexShift]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function getOrCreateRenderer2(di: LInjector): Renderer2 {
|
function getOrCreateRenderer2(di: LInjector): Renderer2 {
|
||||||
const renderer = di.node.view[RENDERER];
|
const renderer = di.node.view[RENDERER];
|
||||||
if (isProceduralRenderer(renderer)) {
|
if (isProceduralRenderer(renderer)) {
|
||||||
@ -337,18 +334,6 @@ function getOrCreateRenderer2(di: LInjector): Renderer2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If the node is an embedded view, traverses up the view tree to return the closest
|
|
||||||
* ancestor view that is attached to a component. If it's already a component node,
|
|
||||||
* returns itself.
|
|
||||||
*/
|
|
||||||
function getClosestComponentAncestor(node: LViewNode | LElementNode): LElementNode {
|
|
||||||
while (node.tNode.type === TNodeType.View) {
|
|
||||||
node = node.view[HOST_NODE];
|
|
||||||
}
|
|
||||||
return node as LElementNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value associated to the given token from the injectors.
|
* Returns the value associated to the given token from the injectors.
|
||||||
*
|
*
|
||||||
@ -384,7 +369,8 @@ export function getOrCreateInjectable<T>(
|
|||||||
// At this point, we have an injector which *may* contain the token, so we step through the
|
// At this point, we have an injector which *may* contain the token, so we step through the
|
||||||
// directives associated with the injector's corresponding node to get the directive instance.
|
// directives associated with the injector's corresponding node to get the directive instance.
|
||||||
const node = injector.node;
|
const node = injector.node;
|
||||||
const nodeFlags = node.tNode.flags;
|
const tNode = injector.tNode;
|
||||||
|
const nodeFlags = tNode.flags;
|
||||||
const count = nodeFlags & TNodeFlags.DirectiveCountMask;
|
const count = nodeFlags & TNodeFlags.DirectiveCountMask;
|
||||||
|
|
||||||
if (count !== 0) {
|
if (count !== 0) {
|
||||||
@ -420,7 +406,7 @@ export function getOrCreateInjectable<T>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const moduleInjector = getPreviousOrParentNode().view[INJECTOR];
|
const moduleInjector = getPreviousOrParentNode() !.view[INJECTOR];
|
||||||
const formerInjector = setCurrentInjector(moduleInjector);
|
const formerInjector = setCurrentInjector(moduleInjector);
|
||||||
try {
|
try {
|
||||||
return inject(token, flags);
|
return inject(token, flags);
|
||||||
@ -546,7 +532,7 @@ function sameHostView(injector: LInjector): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ReadFromInjectorFn<T> {
|
export class ReadFromInjectorFn<T> {
|
||||||
constructor(readonly read: (injector: LInjector, node: LNode, directiveIndex?: number) => T) {}
|
constructor(readonly read: (injector: LInjector, tNode: TNode, directiveIndex?: number) => T) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -573,22 +559,21 @@ export const QUERY_READ_ELEMENT_REF =
|
|||||||
(injector: LInjector) => getOrCreateElementRef(injector)) as any);
|
(injector: LInjector) => getOrCreateElementRef(injector)) as any);
|
||||||
|
|
||||||
export const QUERY_READ_FROM_NODE =
|
export const QUERY_READ_FROM_NODE =
|
||||||
(new ReadFromInjectorFn<any>((injector: LInjector, node: LNode, directiveIdx: number) => {
|
(new ReadFromInjectorFn<any>((injector: LInjector, tNode: TNode, directiveIdx: number) => {
|
||||||
ngDevMode &&
|
ngDevMode && assertNodeOfPossibleTypes(
|
||||||
assertNodeOfPossibleTypes(
|
tNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
|
||||||
node.tNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
|
|
||||||
if (directiveIdx > -1) {
|
if (directiveIdx > -1) {
|
||||||
return node.view[DIRECTIVES] ![directiveIdx];
|
return _getViewData()[DIRECTIVES] ![directiveIdx];
|
||||||
}
|
}
|
||||||
if (node.tNode.type === TNodeType.Element || node.tNode.type === TNodeType.ElementContainer) {
|
if (tNode.type === TNodeType.Element || tNode.type === TNodeType.ElementContainer) {
|
||||||
return getOrCreateElementRef(injector);
|
return getOrCreateElementRef(injector);
|
||||||
}
|
}
|
||||||
if (node.tNode.type === TNodeType.Container) {
|
if (tNode.type === TNodeType.Container) {
|
||||||
return getOrCreateTemplateRef(injector);
|
return getOrCreateTemplateRef(injector);
|
||||||
}
|
}
|
||||||
if (ngDevMode) {
|
if (ngDevMode) {
|
||||||
// should never happen
|
// should never happen
|
||||||
throw new Error(`Unexpected node type: ${node.tNode.type}`);
|
throw new Error(`Unexpected node type: ${tNode.type}`);
|
||||||
}
|
}
|
||||||
}) as any as QueryReadType<any>);
|
}) as any as QueryReadType<any>);
|
||||||
|
|
||||||
@ -603,29 +588,32 @@ class ElementRef extends viewEngine_ElementRef {}
|
|||||||
*/
|
*/
|
||||||
export function getOrCreateContainerRef(di: LInjector): viewEngine_ViewContainerRef {
|
export function getOrCreateContainerRef(di: LInjector): viewEngine_ViewContainerRef {
|
||||||
if (!di.viewContainerRef) {
|
if (!di.viewContainerRef) {
|
||||||
const vcRefHost = di.node;
|
const hostLNode =
|
||||||
const hostTNode = vcRefHost.tNode as TElementNode | TContainerNode;
|
getPreviousOrParentNode() as LElementNode | LContainerNode | LElementContainerNode;
|
||||||
|
const hostTNode = getPreviousOrParentTNode() as TElementNode | TContainerNode;
|
||||||
ngDevMode && assertNodeOfPossibleTypes(
|
ngDevMode && assertNodeOfPossibleTypes(
|
||||||
hostTNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
|
hostTNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
|
||||||
const hostParent = getParentLNode(vcRefHost) !;
|
|
||||||
const lContainer = createLContainer(hostParent, vcRefHost.view, true);
|
const hostView = hostLNode.view;
|
||||||
const comment = vcRefHost.view[RENDERER].createComment(ngDevMode ? 'container' : '');
|
const lContainer = createLContainer(hostView, true);
|
||||||
|
const comment = hostView[RENDERER].createComment(ngDevMode ? 'container' : '');
|
||||||
const lContainerNode: LContainerNode = createLNodeObject(
|
const lContainerNode: LContainerNode = createLNodeObject(
|
||||||
TNodeType.Container, vcRefHost.view, vcRefHost.nodeInjector, comment, lContainer);
|
TNodeType.Container, hostView, hostLNode.nodeInjector, comment, lContainer);
|
||||||
appendChild(hostParent, comment, vcRefHost.view);
|
|
||||||
|
lContainer[RENDER_PARENT] = getRenderParent(hostTNode, hostView);
|
||||||
|
|
||||||
|
appendChild(comment, hostTNode, hostView);
|
||||||
|
|
||||||
if (!hostTNode.dynamicContainerNode) {
|
if (!hostTNode.dynamicContainerNode) {
|
||||||
hostTNode.dynamicContainerNode =
|
hostTNode.dynamicContainerNode =
|
||||||
createTNode(TNodeType.Container, -1, null, null, hostTNode, null);
|
createTNode(TNodeType.Container, -1, null, null, hostTNode, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
lContainerNode.tNode = hostTNode.dynamicContainerNode;
|
hostLNode.dynamicLContainerNode = lContainerNode;
|
||||||
vcRefHost.dynamicLContainerNode = lContainerNode;
|
addToViewTree(hostView, hostTNode.index as number, lContainer);
|
||||||
|
|
||||||
addToViewTree(vcRefHost.view, hostTNode.index as number, lContainer);
|
di.viewContainerRef = new ViewContainerRef(
|
||||||
|
lContainerNode, hostTNode.dynamicContainerNode as TContainerNode, hostLNode, hostTNode);
|
||||||
di.viewContainerRef = new ViewContainerRef(lContainerNode, vcRefHost);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return di.viewContainerRef;
|
return di.viewContainerRef;
|
||||||
@ -663,24 +651,25 @@ class ViewContainerRef extends viewEngine_ViewContainerRef {
|
|||||||
private _viewRefs: viewEngine_ViewRef[] = [];
|
private _viewRefs: viewEngine_ViewRef[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _lContainerNode: LContainerNode,
|
private _lContainerNode: LContainerNode, private _tContainerNode: TContainerNode,
|
||||||
private _hostNode: LElementNode|LElementContainerNode|LContainerNode) {
|
private _hostNode: LElementNode|LElementContainerNode|LContainerNode,
|
||||||
|
private _hostTNode: TNode) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
get element(): ElementRef {
|
get element(): ElementRef {
|
||||||
const injector = getOrCreateNodeInjectorForNode(this._hostNode);
|
const injector = getOrCreateNodeInjectorForNode(this._hostNode, this._hostTNode);
|
||||||
return getOrCreateElementRef(injector);
|
return getOrCreateElementRef(injector);
|
||||||
}
|
}
|
||||||
|
|
||||||
get injector(): Injector {
|
get injector(): Injector {
|
||||||
const injector = getOrCreateNodeInjectorForNode(this._hostNode);
|
const injector = getOrCreateNodeInjectorForNode(this._hostNode, this._hostTNode);
|
||||||
return new NodeInjector(injector);
|
return new NodeInjector(injector);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @deprecated No replacement */
|
/** @deprecated No replacement */
|
||||||
get parentInjector(): Injector {
|
get parentInjector(): Injector {
|
||||||
const parentLInjector = getParentLNode(this._hostNode).nodeInjector;
|
const parentLInjector = getParentLNode(this._hostTNode, this._hostNode.view) !.nodeInjector;
|
||||||
return parentLInjector ? new NodeInjector(parentLInjector) : new NullInjector();
|
return parentLInjector ? new NodeInjector(parentLInjector) : new NullInjector();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,8 +690,10 @@ class ViewContainerRef extends viewEngine_ViewContainerRef {
|
|||||||
createEmbeddedView<C>(templateRef: viewEngine_TemplateRef<C>, context?: C, index?: number):
|
createEmbeddedView<C>(templateRef: viewEngine_TemplateRef<C>, context?: C, index?: number):
|
||||||
viewEngine_EmbeddedViewRef<C> {
|
viewEngine_EmbeddedViewRef<C> {
|
||||||
const adjustedIdx = this._adjustIndex(index);
|
const adjustedIdx = this._adjustIndex(index);
|
||||||
const viewRef = (templateRef as TemplateRef<C>)
|
const viewRef =
|
||||||
.createEmbeddedView(context || <any>{}, this._lContainerNode, adjustedIdx);
|
(templateRef as TemplateRef<C>)
|
||||||
|
.createEmbeddedView(
|
||||||
|
context || <any>{}, this._lContainerNode, this._tContainerNode, adjustedIdx);
|
||||||
(viewRef as ViewRef<any>).attachToViewContainerRef(this);
|
(viewRef as ViewRef<any>).attachToViewContainerRef(this);
|
||||||
this._viewRefs.splice(adjustedIdx, 0, viewRef);
|
this._viewRefs.splice(adjustedIdx, 0, viewRef);
|
||||||
return viewRef;
|
return viewRef;
|
||||||
@ -727,15 +718,13 @@ class ViewContainerRef extends viewEngine_ViewContainerRef {
|
|||||||
if (viewRef.destroyed) {
|
if (viewRef.destroyed) {
|
||||||
throw new Error('Cannot insert a destroyed View in a ViewContainer!');
|
throw new Error('Cannot insert a destroyed View in a ViewContainer!');
|
||||||
}
|
}
|
||||||
const lViewNode = (viewRef as ViewRef<any>)._lViewNode !;
|
const lView = (viewRef as ViewRef<any>)._view !;
|
||||||
const adjustedIdx = this._adjustIndex(index);
|
const adjustedIdx = this._adjustIndex(index);
|
||||||
|
|
||||||
insertView(this._lContainerNode, lViewNode, adjustedIdx);
|
insertView(this._lContainerNode, lView, adjustedIdx, this._tContainerNode.parent !.index);
|
||||||
const views = this._lContainerNode.data[VIEWS];
|
const beforeNode =
|
||||||
const beforeNode = adjustedIdx + 1 < views.length ?
|
getBeforeNodeForView(adjustedIdx, this._lContainerNode.data[VIEWS], this._lContainerNode);
|
||||||
(getChildLNode(views[adjustedIdx + 1][HOST_NODE]) !).native :
|
addRemoveViewFromContainer(lView, true, beforeNode);
|
||||||
this._lContainerNode.native;
|
|
||||||
addRemoveViewFromContainer(this._lContainerNode, lViewNode.data, true, beforeNode);
|
|
||||||
|
|
||||||
(viewRef as ViewRef<any>).attachToViewContainerRef(this);
|
(viewRef as ViewRef<any>).attachToViewContainerRef(this);
|
||||||
this._viewRefs.splice(adjustedIdx, 0, viewRef);
|
this._viewRefs.splice(adjustedIdx, 0, viewRef);
|
||||||
@ -754,13 +743,13 @@ class ViewContainerRef extends viewEngine_ViewContainerRef {
|
|||||||
|
|
||||||
remove(index?: number): void {
|
remove(index?: number): void {
|
||||||
const adjustedIdx = this._adjustIndex(index, -1);
|
const adjustedIdx = this._adjustIndex(index, -1);
|
||||||
removeView(this._lContainerNode, adjustedIdx);
|
removeView(this._lContainerNode, this._tContainerNode as TContainerNode, adjustedIdx);
|
||||||
this._viewRefs.splice(adjustedIdx, 1);
|
this._viewRefs.splice(adjustedIdx, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
detach(index?: number): viewEngine_ViewRef|null {
|
detach(index?: number): viewEngine_ViewRef|null {
|
||||||
const adjustedIdx = this._adjustIndex(index, -1);
|
const adjustedIdx = this._adjustIndex(index, -1);
|
||||||
detachView(this._lContainerNode, adjustedIdx);
|
detachView(this._lContainerNode, adjustedIdx, !!this._tContainerNode.detached);
|
||||||
return this._viewRefs.splice(adjustedIdx, 1)[0] || null;
|
return this._viewRefs.splice(adjustedIdx, 1)[0] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -786,13 +775,13 @@ class ViewContainerRef extends viewEngine_ViewContainerRef {
|
|||||||
*/
|
*/
|
||||||
export function getOrCreateTemplateRef<T>(di: LInjector): viewEngine_TemplateRef<T> {
|
export function getOrCreateTemplateRef<T>(di: LInjector): viewEngine_TemplateRef<T> {
|
||||||
if (!di.templateRef) {
|
if (!di.templateRef) {
|
||||||
const hostNode = di.node as LContainerNode;
|
const hostNode = getPreviousOrParentNode() as LContainerNode;
|
||||||
const hostTNode = hostNode.tNode;
|
const hostTNode = getPreviousOrParentTNode() as TContainerNode;
|
||||||
ngDevMode && assertNodeType(hostTNode, TNodeType.Container);
|
ngDevMode && assertNodeType(hostTNode, TNodeType.Container);
|
||||||
ngDevMode && assertDefined(hostTNode.tViews, 'TView must be allocated');
|
ngDevMode && assertDefined(hostTNode.tViews, 'TView must be allocated');
|
||||||
di.templateRef = new TemplateRef<any>(
|
di.templateRef = new TemplateRef<any>(
|
||||||
hostNode.view, getOrCreateElementRef(di), hostTNode.tViews as TView, getRenderer(),
|
hostNode.view, getOrCreateElementRef(di), hostTNode.tViews as TView, getRenderer(),
|
||||||
hostNode.data[QUERIES]);
|
hostNode.data ![QUERIES]);
|
||||||
}
|
}
|
||||||
return di.templateRef;
|
return di.templateRef;
|
||||||
}
|
}
|
||||||
@ -828,16 +817,17 @@ class TemplateRef<T> extends viewEngine_TemplateRef<T> {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
createEmbeddedView(context: T, containerNode?: LContainerNode, index?: number):
|
createEmbeddedView(
|
||||||
viewEngine_EmbeddedViewRef<T> {
|
context: T, containerNode?: LContainerNode, tContainerNode?: TContainerNode,
|
||||||
const viewNode = createEmbeddedViewNode(
|
index?: number): viewEngine_EmbeddedViewRef<T> {
|
||||||
|
const lView = createEmbeddedViewAndNode(
|
||||||
this._tView, context, this._declarationParentView, this._renderer, this._queries);
|
this._tView, context, this._declarationParentView, this._renderer, this._queries);
|
||||||
if (containerNode) {
|
if (containerNode) {
|
||||||
insertView(containerNode, viewNode, index !);
|
insertView(containerNode, lView, index !, tContainerNode !.parent !.index);
|
||||||
}
|
}
|
||||||
renderEmbeddedTemplate(viewNode.data, this._tView, context, RenderFlags.Create);
|
renderEmbeddedTemplate(lView, this._tView, context, RenderFlags.Create);
|
||||||
const viewRef = new ViewRef(viewNode.data, context);
|
const viewRef = new ViewRef(lView, context);
|
||||||
viewRef._lViewNode = viewNode;
|
viewRef._tViewNode = lView[HOST_NODE] as TViewNode;
|
||||||
return viewRef;
|
return viewRef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -846,6 +836,6 @@ class TemplateRef<T> extends viewEngine_TemplateRef<T> {
|
|||||||
* Retrieves `TemplateRef` instance from `Injector` when a local reference is placed on the
|
* Retrieves `TemplateRef` instance from `Injector` when a local reference is placed on the
|
||||||
* `<ng-template>` element.
|
* `<ng-template>` element.
|
||||||
*/
|
*/
|
||||||
export function templateRefExtractor(lNode: LNodeWithLocalRefs) {
|
export function templateRefExtractor(lNode: LNodeWithLocalRefs, tNode: TNode) {
|
||||||
return getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(lNode));
|
return getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(lNode, tNode));
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {assertEqual, assertLessThan} from './assert';
|
import {assertEqual, assertLessThan} from './assert';
|
||||||
import {NO_CHANGE, _getViewData, adjustBlueprintForNewNode, bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, createLNode, getPreviousOrParentNode, getRenderer, load, resetComponentState} from './instructions';
|
import {NO_CHANGE, _getViewData, adjustBlueprintForNewNode, bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, createNodeAtIndex, getRenderer, getTNode, load, loadElement, resetComponentState} from './instructions';
|
||||||
import {RENDER_PARENT} from './interfaces/container';
|
import {RENDER_PARENT} from './interfaces/container';
|
||||||
import {LContainerNode, LNode, TContainerNode, TElementNode, TNodeType} from './interfaces/node';
|
import {LContainerNode, LElementNode, LNode, TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node';
|
||||||
import {BINDING_INDEX, HEADER_OFFSET, TVIEW} from './interfaces/view';
|
import {RElement} from './interfaces/renderer';
|
||||||
import {appendChild, createTextNode, getParentLNode, removeChild} from './node_manipulation';
|
import {BINDING_INDEX, HEADER_OFFSET, HOST_NODE, TVIEW} from './interfaces/view';
|
||||||
|
import {appendChild, createTextNode, getContainerRenderParent, getParentLNode, getParentOrContainerNode, removeChild} from './node_manipulation';
|
||||||
import {stringify} from './util';
|
import {stringify} from './util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -245,42 +246,42 @@ function generateMappingInstructions(
|
|||||||
return partIndex;
|
return partIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendI18nNode(node: LNode, parentNode: LNode, previousNode: LNode) {
|
// TODO: Remove LNode arg when we remove dynamicContainerNode
|
||||||
|
function appendI18nNode(
|
||||||
|
node: LNode, tNode: TNode, parentTNode: TNode, previousTNode: TNode): TNode {
|
||||||
if (ngDevMode) {
|
if (ngDevMode) {
|
||||||
ngDevMode.rendererMoveNode++;
|
ngDevMode.rendererMoveNode++;
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewData = _getViewData();
|
const viewData = _getViewData();
|
||||||
|
|
||||||
appendChild(parentNode, node.native || null, viewData);
|
|
||||||
|
|
||||||
// On first pass, re-organize node tree to put this node in the correct position.
|
// On first pass, re-organize node tree to put this node in the correct position.
|
||||||
const firstTemplatePass = node.view[TVIEW].firstTemplatePass;
|
const firstTemplatePass = node.view[TVIEW].firstTemplatePass;
|
||||||
if (firstTemplatePass) {
|
if (firstTemplatePass) {
|
||||||
if (previousNode === parentNode && node.tNode !== parentNode.tNode.child) {
|
if (previousTNode === parentTNode && tNode !== parentTNode.child) {
|
||||||
node.tNode.next = parentNode.tNode.child;
|
tNode.next = parentTNode.child;
|
||||||
parentNode.tNode.child = node.tNode;
|
parentTNode.child = tNode;
|
||||||
} else if (previousNode !== parentNode && node.tNode !== previousNode.tNode.next) {
|
} else if (previousTNode !== parentTNode && tNode !== previousTNode.next) {
|
||||||
node.tNode.next = previousNode.tNode.next;
|
tNode.next = previousTNode.next;
|
||||||
previousNode.tNode.next = node.tNode;
|
previousTNode.next = tNode;
|
||||||
} else {
|
} else {
|
||||||
node.tNode.next = null;
|
tNode.next = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parentNode.view === node.view) node.tNode.parent = parentNode.tNode as TElementNode;
|
if (parentTNode !== viewData[HOST_NODE]) {
|
||||||
|
tNode.parent = parentTNode as TElementNode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appendChild(node.native, tNode, viewData);
|
||||||
|
|
||||||
// Template containers also have a comment node for the `ViewContainerRef` that should be moved
|
// Template containers also have a comment node for the `ViewContainerRef` that should be moved
|
||||||
if (node.tNode.type === TNodeType.Container && node.dynamicLContainerNode) {
|
if (tNode.type === TNodeType.Container && node.dynamicLContainerNode) {
|
||||||
appendChild(parentNode, node.dynamicLContainerNode.native || null, viewData);
|
appendChild(node.dynamicLContainerNode.native, tNode, viewData);
|
||||||
if (firstTemplatePass) {
|
return tNode.dynamicContainerNode !;
|
||||||
node.tNode.dynamicContainerNode = node.dynamicLContainerNode.tNode;
|
|
||||||
node.dynamicLContainerNode.tNode.parent = node.tNode as TContainerNode;
|
|
||||||
}
|
|
||||||
return node.dynamicLContainerNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return tNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -303,23 +304,29 @@ export function i18nApply(startIndex: number, instructions: I18nInstruction[]):
|
|||||||
}
|
}
|
||||||
|
|
||||||
const renderer = getRenderer();
|
const renderer = getRenderer();
|
||||||
let localParentNode: LNode = getParentLNode(load(startIndex)) || getPreviousOrParentNode();
|
const startTNode = getTNode(startIndex);
|
||||||
let localPreviousNode: LNode = localParentNode;
|
let localParentTNode: TNode = startTNode.parent || viewData[HOST_NODE] !;
|
||||||
|
let localPreviousTNode: TNode = localParentTNode;
|
||||||
resetComponentState(); // We don't want to add to the tree with the wrong previous node
|
resetComponentState(); // We don't want to add to the tree with the wrong previous node
|
||||||
|
|
||||||
for (let i = 0; i < instructions.length; i++) {
|
for (let i = 0; i < instructions.length; i++) {
|
||||||
const instruction = instructions[i] as number;
|
const instruction = instructions[i] as number;
|
||||||
switch (instruction & I18nInstructions.InstructionMask) {
|
switch (instruction & I18nInstructions.InstructionMask) {
|
||||||
case I18nInstructions.Element:
|
case I18nInstructions.Element:
|
||||||
const element: LNode = load(instruction & I18nInstructions.IndexMask);
|
const elementIndex = instruction & I18nInstructions.IndexMask;
|
||||||
localPreviousNode = appendI18nNode(element, localParentNode, localPreviousNode);
|
const element: LNode = load(elementIndex);
|
||||||
localParentNode = element;
|
const elementTNode = getTNode(elementIndex);
|
||||||
|
localPreviousTNode =
|
||||||
|
appendI18nNode(element, elementTNode, localParentTNode, localPreviousTNode);
|
||||||
|
localParentTNode = elementTNode;
|
||||||
break;
|
break;
|
||||||
case I18nInstructions.Expression:
|
case I18nInstructions.Expression:
|
||||||
case I18nInstructions.TemplateRoot:
|
case I18nInstructions.TemplateRoot:
|
||||||
case I18nInstructions.Any:
|
case I18nInstructions.Any:
|
||||||
const node: LNode = load(instruction & I18nInstructions.IndexMask);
|
const nodeIndex = instruction & I18nInstructions.IndexMask;
|
||||||
localPreviousNode = appendI18nNode(node, localParentNode, localPreviousNode);
|
const node: LNode = load(nodeIndex);
|
||||||
|
localPreviousTNode =
|
||||||
|
appendI18nNode(node, getTNode(nodeIndex), localParentTNode, localPreviousTNode);
|
||||||
break;
|
break;
|
||||||
case I18nInstructions.Text:
|
case I18nInstructions.Text:
|
||||||
if (ngDevMode) {
|
if (ngDevMode) {
|
||||||
@ -329,31 +336,32 @@ export function i18nApply(startIndex: number, instructions: I18nInstruction[]):
|
|||||||
const textRNode = createTextNode(value, renderer);
|
const textRNode = createTextNode(value, renderer);
|
||||||
// If we were to only create a `RNode` then projections won't move the text.
|
// If we were to only create a `RNode` then projections won't move the text.
|
||||||
// Create text node at the current end of viewData. Must subtract header offset because
|
// Create text node at the current end of viewData. Must subtract header offset because
|
||||||
// createLNode takes a raw index (not adjusted by header offset).
|
// createNodeAtIndex takes a raw index (not adjusted by header offset).
|
||||||
adjustBlueprintForNewNode(viewData);
|
adjustBlueprintForNewNode(viewData);
|
||||||
const lastNodeIndex = viewData.length - 1;
|
const lastNodeIndex = viewData.length - 1 - HEADER_OFFSET;
|
||||||
const textLNode =
|
const textTNode =
|
||||||
createLNode(lastNodeIndex - HEADER_OFFSET, TNodeType.Element, textRNode, null, null);
|
createNodeAtIndex(lastNodeIndex, TNodeType.Element, textRNode, null, null);
|
||||||
localPreviousNode = appendI18nNode(textLNode, localParentNode, localPreviousNode);
|
localPreviousTNode = appendI18nNode(
|
||||||
|
loadElement(lastNodeIndex), textTNode, localParentTNode, localPreviousTNode);
|
||||||
resetComponentState();
|
resetComponentState();
|
||||||
break;
|
break;
|
||||||
case I18nInstructions.CloseNode:
|
case I18nInstructions.CloseNode:
|
||||||
localPreviousNode = localParentNode;
|
localPreviousTNode = localParentTNode;
|
||||||
localParentNode = getParentLNode(localParentNode) !;
|
localParentTNode = localParentTNode.parent || viewData[HOST_NODE] !;
|
||||||
break;
|
break;
|
||||||
case I18nInstructions.RemoveNode:
|
case I18nInstructions.RemoveNode:
|
||||||
if (ngDevMode) {
|
if (ngDevMode) {
|
||||||
ngDevMode.rendererRemoveNode++;
|
ngDevMode.rendererRemoveNode++;
|
||||||
}
|
}
|
||||||
const index = instruction & I18nInstructions.IndexMask;
|
const removeIndex = instruction & I18nInstructions.IndexMask;
|
||||||
const removedNode: LNode|LContainerNode = load(index);
|
const removedNode: LNode|LContainerNode = load(removeIndex);
|
||||||
const parentNode = getParentLNode(removedNode) !;
|
const removedTNode = getTNode(removeIndex);
|
||||||
removeChild(parentNode, removedNode.native || null, viewData);
|
removeChild(removedTNode, removedNode.native || null, viewData);
|
||||||
|
|
||||||
// For template containers we also need to remove their `ViewContainerRef` from the DOM
|
// For template containers we also need to remove their `ViewContainerRef` from the DOM
|
||||||
if (removedNode.tNode.type === TNodeType.Container && removedNode.dynamicLContainerNode) {
|
if (removedTNode.type === TNodeType.Container && removedNode.dynamicLContainerNode) {
|
||||||
removeChild(parentNode, removedNode.dynamicLContainerNode.native || null, viewData);
|
removeChild(removedTNode, removedNode.dynamicLContainerNode.native || null, viewData);
|
||||||
removedNode.dynamicLContainerNode.tNode.detached = true;
|
removedTNode.dynamicContainerNode !.detached = true;
|
||||||
removedNode.dynamicLContainerNode.data[RENDER_PARENT] = null;
|
removedNode.dynamicLContainerNode.data[RENDER_PARENT] = null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -12,26 +12,27 @@ import {QueryList} from '../linker';
|
|||||||
import {Sanitizer} from '../sanitization/security';
|
import {Sanitizer} from '../sanitization/security';
|
||||||
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
||||||
|
|
||||||
import {assertDefined, assertEqual, assertLessThan, assertNotDefined, assertNotEqual} from './assert';
|
import {assertDefined, assertEqual, assertLessThan, assertNotEqual} from './assert';
|
||||||
import {attachPatchData, getLElementFromComponent, getLElementFromRootComponent, readPatchedData, readPatchedLViewData} from './context_discovery';
|
import {attachPatchData, getLElementFromComponent, readPatchedLViewData} from './context_discovery';
|
||||||
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
|
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
|
||||||
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
|
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
|
||||||
import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
|
import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
|
||||||
import {ComponentDefInternal, ComponentQuery, ComponentTemplate, DirectiveDefInternal, DirectiveDefListOrFactory, InitialStylingFlags, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
|
import {ComponentDefInternal, ComponentQuery, ComponentTemplate, DirectiveDefInternal, DirectiveDefListOrFactory, InitialStylingFlags, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
|
||||||
import {LInjector} from './interfaces/injector';
|
import {LInjector} from './interfaces/injector';
|
||||||
import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LElementContainerNode, LElementNode, LNode, LNodeWithLocalRefs, LProjectionNode, LTextNode, LViewNode, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TViewNode} from './interfaces/node';
|
import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LElementNode, LNode, LNodeWithLocalRefs, LProjectionNode, LTextNode, LViewNode, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TProjectionNode, TViewNode} from './interfaces/node';
|
||||||
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
||||||
import {LQueries} from './interfaces/query';
|
import {LQueries} from './interfaces/query';
|
||||||
import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
|
import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, isProceduralRenderer} from './interfaces/renderer';
|
||||||
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, CurrentMatchesList, DECLARATION_VIEW, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RootContext, SANITIZER, TAIL, TData, TVIEW, TView} from './interfaces/view';
|
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, CurrentMatchesList, DECLARATION_VIEW, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RootContext, SANITIZER, TAIL, TVIEW, TView} from './interfaces/view';
|
||||||
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
||||||
import {appendChild, appendProjectedNode, canInsertNativeNode, createTextNode, findComponentHost, getLViewChild, getParentLNode, insertView, removeView} from './node_manipulation';
|
import {appendChild, appendProjectedNode, createTextNode, findComponentView, getContainerNode, getHostElementNode, getLViewChild, getParentLNode, getParentOrContainerNode, getRenderParent, insertView, removeView} from './node_manipulation';
|
||||||
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
||||||
import {StylingContext, allocStylingContext, createStylingContextTemplate, renderStyling as renderElementStyles, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling';
|
import {StylingContext, allocStylingContext, createStylingContextTemplate, renderStyling as renderElementStyles, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling';
|
||||||
import {assertDataInRangeInternal, isDifferent, loadElementInternal, loadInternal, readElementValue, stringify} from './util';
|
import {assertDataInRangeInternal, isContentQueryHost, isDifferent, loadElementInternal, loadInternal, readElementValue, stringify} from './util';
|
||||||
import {ViewRef} from './view_ref';
|
import {ViewRef} from './view_ref';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A permanent marker promise which signifies that the current CD tree is
|
* A permanent marker promise which signifies that the current CD tree is
|
||||||
* clean.
|
* clean.
|
||||||
@ -128,9 +129,9 @@ export function restoreView(viewToRestore: OpaqueViewState) {
|
|||||||
/** Used to set the parent property when nodes are created and track query results. */
|
/** Used to set the parent property when nodes are created and track query results. */
|
||||||
let previousOrParentTNode: TNode;
|
let previousOrParentTNode: TNode;
|
||||||
|
|
||||||
export function getPreviousOrParentNode(): LNode {
|
export function getPreviousOrParentNode(): LNode|null {
|
||||||
return previousOrParentTNode == null || previousOrParentTNode === tView.node ?
|
return previousOrParentTNode == null || previousOrParentTNode === viewData[HOST_NODE] ?
|
||||||
viewData[HOST_NODE] :
|
getHostElementNode(viewData) :
|
||||||
readElementValue(viewData[previousOrParentTNode.index]);
|
readElementValue(viewData[previousOrParentTNode.index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +163,7 @@ export function getOrCreateCurrentQueries(
|
|||||||
QueryType: {new (parent: null, shallow: null, deep: null): LQueries}): LQueries {
|
QueryType: {new (parent: null, shallow: null, deep: null): LQueries}): LQueries {
|
||||||
// if this is the first content query on a node, any existing LQueries needs to be cloned
|
// if this is the first content query on a node, any existing LQueries needs to be cloned
|
||||||
// in subsequent template passes, the cloning occurs before directive instantiation.
|
// in subsequent template passes, the cloning occurs before directive instantiation.
|
||||||
if (previousOrParentTNode && previousOrParentTNode !== tView.node &&
|
if (previousOrParentTNode && previousOrParentTNode !== viewData[HOST_NODE] &&
|
||||||
!isContentQueryHost(previousOrParentTNode)) {
|
!isContentQueryHost(previousOrParentTNode)) {
|
||||||
currentQueries && (currentQueries = currentQueries.clone());
|
currentQueries && (currentQueries = currentQueries.clone());
|
||||||
previousOrParentTNode.flags |= TNodeFlags.hasContentQuery;
|
previousOrParentTNode.flags |= TNodeFlags.hasContentQuery;
|
||||||
@ -400,7 +401,6 @@ export function createLNodeObject(
|
|||||||
view: currentView,
|
view: currentView,
|
||||||
nodeInjector: nodeInjector,
|
nodeInjector: nodeInjector,
|
||||||
data: state,
|
data: state,
|
||||||
tNode: null !,
|
|
||||||
dynamicLContainerNode: null
|
dynamicLContainerNode: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -417,40 +417,41 @@ export function createLNodeObject(
|
|||||||
* @param attrs Any attrs for the native element, if applicable
|
* @param attrs Any attrs for the native element, if applicable
|
||||||
* @param data Any data that should be saved on the LNode
|
* @param data Any data that should be saved on the LNode
|
||||||
*/
|
*/
|
||||||
export function createLNode(
|
export function createNodeAtIndex(
|
||||||
index: number, type: TNodeType.Element, native: RElement | RText | null, name: string | null,
|
index: number, type: TNodeType.Element, native: RElement | RText | null, name: string | null,
|
||||||
attrs: TAttributes | null, lViewData?: LViewData | null): LElementNode;
|
attrs: TAttributes | null, lViewData?: LViewData | null): TElementNode;
|
||||||
export function createLNode(
|
export function createNodeAtIndex(
|
||||||
index: number, type: TNodeType.View, native: null, name: null, attrs: null,
|
index: number, type: TNodeType.View, native: null, name: null, attrs: null,
|
||||||
lViewData: LViewData): LViewNode;
|
lViewData: LViewData): TViewNode;
|
||||||
export function createLNode(
|
export function createNodeAtIndex(
|
||||||
index: number, type: TNodeType.Container, native: RComment, name: string | null,
|
index: number, type: TNodeType.Container, native: RComment, name: string | null,
|
||||||
attrs: TAttributes | null, lContainer: LContainer): LContainerNode;
|
attrs: TAttributes | null, lContainer: LContainer): TContainerNode;
|
||||||
export function createLNode(
|
export function createNodeAtIndex(
|
||||||
index: number, type: TNodeType.Projection, native: null, name: null, attrs: TAttributes | null,
|
index: number, type: TNodeType.Projection, native: null, name: null, attrs: TAttributes | null,
|
||||||
lProjection: null): LProjectionNode;
|
lProjection: null): TProjectionNode;
|
||||||
export function createLNode(
|
export function createNodeAtIndex(
|
||||||
index: number, type: TNodeType.ElementContainer, native: RComment, name: null,
|
index: number, type: TNodeType.ElementContainer, native: RComment, name: null,
|
||||||
attrs: TAttributes | null, data: null): LElementContainerNode;
|
attrs: TAttributes | null, data: null): TElementContainerNode;
|
||||||
export function createLNode(
|
export function createNodeAtIndex(
|
||||||
index: number, type: TNodeType, native: RText | RElement | RComment | null, name: string | null,
|
index: number, type: TNodeType, native: RText | RElement | RComment | null, name: string | null,
|
||||||
attrs: TAttributes | null, state?: null | LViewData | LContainer): LElementNode<extNode&
|
attrs: TAttributes | null, state?: null | LViewData | LContainer): TElementNode&TViewNode&
|
||||||
LViewNode&LContainerNode&LProjectionNode {
|
TContainerNode&TElementContainerNode&TProjectionNode {
|
||||||
const parent =
|
const parent =
|
||||||
isParent ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent;
|
isParent ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent;
|
||||||
|
|
||||||
// Parents cannot cross component boundaries because components will be used in multiple places,
|
// Parents cannot cross component boundaries because components will be used in multiple places,
|
||||||
// so it's only set if the view is the same.
|
// so it's only set if the view is the same.
|
||||||
const parentInSameView = parent && tView && parent !== tView.node;
|
const parentInSameView = parent && viewData && parent !== viewData[HOST_NODE];
|
||||||
const tParent = parentInSameView ? parent as TElementNode | TContainerNode : null;
|
const tParent = parentInSameView ? parent as TElementNode | TContainerNode : null;
|
||||||
|
|
||||||
const isState = state != null;
|
const isState = state != null;
|
||||||
const node = createLNodeObject(type, viewData, null, native, isState ? state as any : null);
|
const node = createLNodeObject(type, viewData, null, native, isState ? state as any : null);
|
||||||
|
let tNode: TNode;
|
||||||
|
|
||||||
if (index === -1 || type === TNodeType.View) {
|
if (index === -1 || type === TNodeType.View) {
|
||||||
// View nodes are not stored in data because they can be added / removed at runtime (which
|
// View nodes are not stored in data because they can be added / removed at runtime (which
|
||||||
// would cause indices to change). Their TNodes are instead stored in TView.node.
|
// would cause indices to change). Their TNodes are instead stored in tView.node.
|
||||||
node.tNode = (state ? (state as LViewData)[TVIEW].node : null) ||
|
tNode = (state ? (state as LViewData)[TVIEW].node : null) ||
|
||||||
createTNode(type, index, null, null, tParent, null);
|
createTNode(type, index, null, null, tParent, null);
|
||||||
} else {
|
} else {
|
||||||
const adjustedIndex = index + HEADER_OFFSET;
|
const adjustedIndex = index + HEADER_OFFSET;
|
||||||
@ -472,9 +473,9 @@ export function createLNode(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node.tNode = tData[adjustedIndex] as TNode;
|
tNode = tData[adjustedIndex] as TNode;
|
||||||
if (!tView.firstChild && type === TNodeType.Element) {
|
if (!tView.firstChild && type === TNodeType.Element) {
|
||||||
tView.firstChild = node.tNode;
|
tView.firstChild = tNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now link ourselves into the tree.
|
// Now link ourselves into the tree.
|
||||||
@ -482,13 +483,17 @@ export function createLNode(
|
|||||||
if (previousOrParentTNode.child == null && parentInSameView ||
|
if (previousOrParentTNode.child == null && parentInSameView ||
|
||||||
previousOrParentTNode.type === TNodeType.View) {
|
previousOrParentTNode.type === TNodeType.View) {
|
||||||
// We are in the same view, which means we are adding content node to the parent View.
|
// We are in the same view, which means we are adding content node to the parent View.
|
||||||
previousOrParentTNode.child = node.tNode;
|
previousOrParentTNode.child = tNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: temporary, remove when removing LNode.nodeInjector
|
// TODO: temporary, remove this when removing nodeInjector (bringing in fns to hello world)
|
||||||
const parentLNode = index === -1 ? null : getParentLNode(node);
|
if (index !== -1 && !(viewData[FLAGS] & LViewFlags.IsRoot)) {
|
||||||
if (parentLNode) node.nodeInjector = parentLNode.nodeInjector;
|
const parentLNode: LNode|null = type === TNodeType.View ?
|
||||||
|
getContainerNode(tNode, state as LViewData) :
|
||||||
|
getParentOrContainerNode(tNode, viewData);
|
||||||
|
parentLNode && (node.nodeInjector = parentLNode.nodeInjector);
|
||||||
|
}
|
||||||
|
|
||||||
// View nodes and host elements need to set their host node (components do not save host TNodes)
|
// View nodes and host elements need to set their host node (components do not save host TNodes)
|
||||||
if ((type & TNodeType.ViewOrElement) === TNodeType.ViewOrElement && isState) {
|
if ((type & TNodeType.ViewOrElement) === TNodeType.ViewOrElement && isState) {
|
||||||
@ -496,15 +501,16 @@ export function createLNode(
|
|||||||
ngDevMode &&
|
ngDevMode &&
|
||||||
assertEqual(
|
assertEqual(
|
||||||
lViewData[HOST_NODE], null, 'lViewData[HOST_NODE] should not have been initialized');
|
lViewData[HOST_NODE], null, 'lViewData[HOST_NODE] should not have been initialized');
|
||||||
lViewData[HOST_NODE] = node;
|
lViewData[HOST_NODE] = tNode as TElementNode | TViewNode;
|
||||||
if (lViewData[TVIEW].firstTemplatePass) {
|
if (lViewData[TVIEW].firstTemplatePass) {
|
||||||
lViewData[TVIEW].node = node.tNode as TViewNode | TElementNode;
|
lViewData[TVIEW].node = tNode as TViewNode | TElementNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
previousOrParentTNode = node.tNode;
|
previousOrParentTNode = tNode;
|
||||||
isParent = true;
|
isParent = true;
|
||||||
return node;
|
return tNode as TElementNode & TViewNode & TContainerNode & TElementContainerNode &
|
||||||
|
TProjectionNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -554,17 +560,23 @@ export function renderTemplate<T>(
|
|||||||
if (host == null) {
|
if (host == null) {
|
||||||
resetComponentState();
|
resetComponentState();
|
||||||
rendererFactory = providedRendererFactory;
|
rendererFactory = providedRendererFactory;
|
||||||
const tView =
|
renderer = providedRendererFactory.createRenderer(null, null);
|
||||||
|
|
||||||
|
// We need to create a root view so it's possible to look up the host element through its index
|
||||||
|
tView = createTView(-1, null, 1, 0, null, null, null);
|
||||||
|
viewData = createLViewData(renderer, tView, {}, LViewFlags.CheckAlways | LViewFlags.IsRoot);
|
||||||
|
|
||||||
|
const componentTView =
|
||||||
getOrCreateTView(templateFn, consts, vars, directives || null, pipes || null, null);
|
getOrCreateTView(templateFn, consts, vars, directives || null, pipes || null, null);
|
||||||
host = createLNode(
|
const componentLView =
|
||||||
-1, TNodeType.Element, hostNode, null, null,
|
createLViewData(renderer, componentTView, context, LViewFlags.CheckAlways, sanitizer);
|
||||||
createLViewData(
|
createNodeAtIndex(0, TNodeType.Element, hostNode, null, null, componentLView);
|
||||||
providedRendererFactory.createRenderer(null, null), tView, {}, LViewFlags.CheckAlways,
|
host = loadElement(0);
|
||||||
sanitizer));
|
|
||||||
}
|
}
|
||||||
const hostView = host.data !;
|
const hostView = host.data !;
|
||||||
ngDevMode && assertDefined(hostView, 'Host node should have an LView defined in host.data.');
|
ngDevMode && assertDefined(hostView, 'Host node should have an LView defined in host.data.');
|
||||||
renderComponentOrTemplate(hostView, context, templateFn);
|
renderComponentOrTemplate(hostView, context, templateFn);
|
||||||
|
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,9 +585,9 @@ export function renderTemplate<T>(
|
|||||||
* either through ViewContainerRef.createEmbeddedView() or TemplateRef.createEmbeddedView().
|
* either through ViewContainerRef.createEmbeddedView() or TemplateRef.createEmbeddedView().
|
||||||
* Such lViewNode will then be renderer with renderEmbeddedTemplate() (see below).
|
* Such lViewNode will then be renderer with renderEmbeddedTemplate() (see below).
|
||||||
*/
|
*/
|
||||||
export function createEmbeddedViewNode<T>(
|
export function createEmbeddedViewAndNode<T>(
|
||||||
tView: TView, context: T, declarationView: LViewData, renderer: Renderer3,
|
tView: TView, context: T, declarationView: LViewData, renderer: Renderer3,
|
||||||
queries?: LQueries | null): LViewNode {
|
queries?: LQueries | null): LViewData {
|
||||||
const _isParent = isParent;
|
const _isParent = isParent;
|
||||||
const _previousOrParentTNode = previousOrParentTNode;
|
const _previousOrParentTNode = previousOrParentTNode;
|
||||||
isParent = true;
|
isParent = true;
|
||||||
@ -588,11 +600,11 @@ export function createEmbeddedViewNode<T>(
|
|||||||
if (queries) {
|
if (queries) {
|
||||||
lView[QUERIES] = queries.createView();
|
lView[QUERIES] = queries.createView();
|
||||||
}
|
}
|
||||||
const viewNode = createLNode(-1, TNodeType.View, null, null, null, lView);
|
createNodeAtIndex(-1, TNodeType.View, null, null, null, lView);
|
||||||
|
|
||||||
isParent = _isParent;
|
isParent = _isParent;
|
||||||
previousOrParentTNode = _previousOrParentTNode;
|
previousOrParentTNode = _previousOrParentTNode;
|
||||||
return viewNode;
|
return lView;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -610,7 +622,7 @@ export function renderEmbeddedTemplate<T>(
|
|||||||
const _isParent = isParent;
|
const _isParent = isParent;
|
||||||
const _previousOrParentTNode = previousOrParentTNode;
|
const _previousOrParentTNode = previousOrParentTNode;
|
||||||
let oldView: LViewData;
|
let oldView: LViewData;
|
||||||
if (viewToRender[PARENT] == null && viewToRender[CONTEXT] && !tView.template) {
|
if (viewToRender[FLAGS] & LViewFlags.IsRoot) {
|
||||||
// This is a root view inside the view tree
|
// This is a root view inside the view tree
|
||||||
tickRootContext(viewToRender[CONTEXT] as RootContext);
|
tickRootContext(viewToRender[CONTEXT] as RootContext);
|
||||||
} else {
|
} else {
|
||||||
@ -618,7 +630,7 @@ export function renderEmbeddedTemplate<T>(
|
|||||||
isParent = true;
|
isParent = true;
|
||||||
previousOrParentTNode = null !;
|
previousOrParentTNode = null !;
|
||||||
|
|
||||||
oldView = enterView(viewToRender, tView.node);
|
oldView = enterView(viewToRender, viewToRender[HOST_NODE]);
|
||||||
namespaceHTML();
|
namespaceHTML();
|
||||||
tView.template !(rf, context);
|
tView.template !(rf, context);
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
@ -654,7 +666,7 @@ export function nextContext<T = any>(level: number = 1): T {
|
|||||||
|
|
||||||
export function renderComponentOrTemplate<T>(
|
export function renderComponentOrTemplate<T>(
|
||||||
hostView: LViewData, componentOrContext: T, templateFn?: ComponentTemplate<T>) {
|
hostView: LViewData, componentOrContext: T, templateFn?: ComponentTemplate<T>) {
|
||||||
const oldView = enterView(hostView, null);
|
const oldView = enterView(hostView, hostView[HOST_NODE]);
|
||||||
try {
|
try {
|
||||||
if (rendererFactory.begin) {
|
if (rendererFactory.begin) {
|
||||||
rendererFactory.begin();
|
rendererFactory.begin();
|
||||||
@ -751,12 +763,11 @@ export function elementContainerStart(
|
|||||||
const native = renderer.createComment(ngDevMode ? 'ng-container' : '');
|
const native = renderer.createComment(ngDevMode ? 'ng-container' : '');
|
||||||
|
|
||||||
ngDevMode && assertDataInRange(index - 1);
|
ngDevMode && assertDataInRange(index - 1);
|
||||||
|
const tNode =
|
||||||
|
createNodeAtIndex(index, TNodeType.ElementContainer, native, null, attrs || null, null);
|
||||||
|
|
||||||
const node: LElementContainerNode =
|
appendChild(native, tNode, viewData);
|
||||||
createLNode(index, TNodeType.ElementContainer, native, null, attrs || null, null);
|
createDirectivesAndLocals(localRefs);
|
||||||
|
|
||||||
appendChild(getParentLNode(node), native, viewData);
|
|
||||||
createDirectivesAndLocals(node, localRefs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Mark the end of the <ng-container>. */
|
/** Mark the end of the <ng-container>. */
|
||||||
@ -768,10 +779,8 @@ export function elementContainerEnd(): void {
|
|||||||
previousOrParentTNode = previousOrParentTNode.parent !;
|
previousOrParentTNode = previousOrParentTNode.parent !;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can be read directly because ng-containers can't have style bindings
|
|
||||||
const previousNode = viewData[previousOrParentTNode.index];
|
|
||||||
ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.ElementContainer);
|
ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.ElementContainer);
|
||||||
currentQueries && (currentQueries = currentQueries.addNode(previousNode));
|
currentQueries && (currentQueries = currentQueries.addNode(previousOrParentTNode));
|
||||||
|
|
||||||
queueLifecycleHooks(previousOrParentTNode.flags, tView);
|
queueLifecycleHooks(previousOrParentTNode.flags, tView);
|
||||||
}
|
}
|
||||||
@ -800,14 +809,13 @@ export function elementStart(
|
|||||||
|
|
||||||
ngDevMode && assertDataInRange(index - 1);
|
ngDevMode && assertDataInRange(index - 1);
|
||||||
|
|
||||||
const node: LElementNode =
|
const tNode = createNodeAtIndex(index, TNodeType.Element, native !, name, attrs || null, null);
|
||||||
createLNode(index, TNodeType.Element, native !, name, attrs || null, null);
|
|
||||||
|
|
||||||
if (attrs) {
|
if (attrs) {
|
||||||
setUpAttributes(native, attrs);
|
setUpAttributes(native, attrs);
|
||||||
}
|
}
|
||||||
appendChild(getParentLNode(node), native, viewData);
|
appendChild(native, tNode, viewData);
|
||||||
createDirectivesAndLocals(node, localRefs);
|
createDirectivesAndLocals(localRefs);
|
||||||
|
|
||||||
// any immediate children of a component or template container must be pre-emptively
|
// any immediate children of a component or template container must be pre-emptively
|
||||||
// monkey-patched with the component view data so that the element can be inspected
|
// monkey-patched with the component view data so that the element can be inspected
|
||||||
@ -840,7 +848,7 @@ export function elementCreate(name: string, overriddenRenderer?: Renderer3): REl
|
|||||||
return native;
|
return native;
|
||||||
}
|
}
|
||||||
|
|
||||||
function nativeNodeLocalRefExtractor(lNode: LNodeWithLocalRefs): RNode {
|
function nativeNodeLocalRefExtractor(lNode: LNodeWithLocalRefs, tNode: TNode): RNode {
|
||||||
return lNode.native;
|
return lNode.native;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -852,7 +860,7 @@ function nativeNodeLocalRefExtractor(lNode: LNodeWithLocalRefs): RNode {
|
|||||||
* @param localRefExtractor mapping function that extracts local ref value from LNode
|
* @param localRefExtractor mapping function that extracts local ref value from LNode
|
||||||
*/
|
*/
|
||||||
function createDirectivesAndLocals(
|
function createDirectivesAndLocals(
|
||||||
lNode: LNodeWithLocalRefs, localRefs: string[] | null | undefined,
|
localRefs: string[] | null | undefined,
|
||||||
localRefExtractor: LocalRefExtractor = nativeNodeLocalRefExtractor) {
|
localRefExtractor: LocalRefExtractor = nativeNodeLocalRefExtractor) {
|
||||||
if (firstTemplatePass) {
|
if (firstTemplatePass) {
|
||||||
ngDevMode && ngDevMode.firstTemplatePass++;
|
ngDevMode && ngDevMode.firstTemplatePass++;
|
||||||
@ -860,7 +868,7 @@ function createDirectivesAndLocals(
|
|||||||
} else {
|
} else {
|
||||||
instantiateDirectivesDirectly();
|
instantiateDirectivesDirectly();
|
||||||
}
|
}
|
||||||
saveResolvedLocalsInData(lNode, localRefExtractor);
|
saveResolvedLocalsInData(localRefExtractor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -949,14 +957,6 @@ export function initChangeDetectorIfExisting(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isContentQueryHost(tNode: TNode): boolean {
|
|
||||||
return (tNode.flags & TNodeFlags.hasContentQuery) !== 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isComponent(tNode: TNode): boolean {
|
|
||||||
return (tNode.flags & TNodeFlags.isComponent) === TNodeFlags.isComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function instantiates the given directives.
|
* This function instantiates the given directives.
|
||||||
*/
|
*/
|
||||||
@ -1016,14 +1016,15 @@ function saveNameToExportMap(
|
|||||||
* Takes a list of local names and indices and pushes the resolved local variable values
|
* Takes a list of local names and indices and pushes the resolved local variable values
|
||||||
* to LViewData in the same order as they are loaded in the template with load().
|
* to LViewData in the same order as they are loaded in the template with load().
|
||||||
*/
|
*/
|
||||||
function saveResolvedLocalsInData(
|
function saveResolvedLocalsInData(localRefExtractor: LocalRefExtractor): void {
|
||||||
lNode: LNodeWithLocalRefs, localRefExtractor: LocalRefExtractor): void {
|
const localNames = previousOrParentTNode.localNames;
|
||||||
const localNames = lNode.tNode.localNames;
|
const node = getPreviousOrParentNode() as LElementNode;
|
||||||
if (localNames) {
|
if (localNames) {
|
||||||
let localIndex = lNode.tNode.index + 1;
|
let localIndex = previousOrParentTNode.index + 1;
|
||||||
for (let i = 0; i < localNames.length; i += 2) {
|
for (let i = 0; i < localNames.length; i += 2) {
|
||||||
const index = localNames[i + 1] as number;
|
const index = localNames[i + 1] as number;
|
||||||
const value = index === -1 ? localRefExtractor(lNode) : directives ![index];
|
const value =
|
||||||
|
index === -1 ? localRefExtractor(node, previousOrParentTNode) : directives ![index];
|
||||||
viewData[localIndex++] = value;
|
viewData[localIndex++] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1192,7 +1193,7 @@ export function hostElement(
|
|||||||
tag: string, rNode: RElement | null, def: ComponentDefInternal<any>,
|
tag: string, rNode: RElement | null, def: ComponentDefInternal<any>,
|
||||||
sanitizer?: Sanitizer | null): LElementNode {
|
sanitizer?: Sanitizer | null): LElementNode {
|
||||||
resetComponentState();
|
resetComponentState();
|
||||||
const node = createLNode(
|
const tNode = createNodeAtIndex(
|
||||||
0, TNodeType.Element, rNode, null, null,
|
0, TNodeType.Element, rNode, null, null,
|
||||||
createLViewData(
|
createLViewData(
|
||||||
renderer,
|
renderer,
|
||||||
@ -1201,12 +1202,12 @@ export function hostElement(
|
|||||||
null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer));
|
null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer));
|
||||||
|
|
||||||
if (firstTemplatePass) {
|
if (firstTemplatePass) {
|
||||||
node.tNode.flags = TNodeFlags.isComponent;
|
tNode.flags = TNodeFlags.isComponent;
|
||||||
if (def.diPublic) def.diPublic(def);
|
if (def.diPublic) def.diPublic(def);
|
||||||
tView.directives = [def];
|
tView.directives = [def];
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return viewData[HEADER_OFFSET];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1316,7 +1317,7 @@ export function elementEnd(): void {
|
|||||||
previousOrParentTNode = previousOrParentTNode.parent !;
|
previousOrParentTNode = previousOrParentTNode.parent !;
|
||||||
}
|
}
|
||||||
ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.Element);
|
ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.Element);
|
||||||
currentQueries && (currentQueries = currentQueries.addNode(getPreviousOrParentNode()));
|
currentQueries && (currentQueries = currentQueries.addNode(previousOrParentTNode));
|
||||||
|
|
||||||
queueLifecycleHooks(previousOrParentTNode.flags, tView);
|
queueLifecycleHooks(previousOrParentTNode.flags, tView);
|
||||||
elementDepthCount--;
|
elementDepthCount--;
|
||||||
@ -1366,12 +1367,12 @@ export function elementProperty<T>(
|
|||||||
index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn): void {
|
index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn): void {
|
||||||
if (value === NO_CHANGE) return;
|
if (value === NO_CHANGE) return;
|
||||||
const node = loadElement(index) as LElementNode;
|
const node = loadElement(index) as LElementNode;
|
||||||
const tNode = node.tNode;
|
const tNode = getTNode(index);
|
||||||
// if tNode.inputs is undefined, a listener has created outputs, but inputs haven't
|
// if tNode.inputs is undefined, a listener has created outputs, but inputs haven't
|
||||||
// yet been checked
|
// yet been checked
|
||||||
if (tNode && tNode.inputs === undefined) {
|
if (tNode && tNode.inputs === undefined) {
|
||||||
// mark inputs as checked
|
// mark inputs as checked
|
||||||
tNode.inputs = generatePropertyAliases(node.tNode.flags, BindingDirection.Input);
|
tNode.inputs = generatePropertyAliases(tNode.flags, BindingDirection.Input);
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputData = tNode && tNode.inputs;
|
const inputData = tNode && tNode.inputs;
|
||||||
@ -1547,7 +1548,7 @@ function getStylingContext(index: number): StylingContext {
|
|||||||
let stylingContext = load<StylingContext>(index);
|
let stylingContext = load<StylingContext>(index);
|
||||||
if (!Array.isArray(stylingContext)) {
|
if (!Array.isArray(stylingContext)) {
|
||||||
const lElement = stylingContext as any as LElementNode;
|
const lElement = stylingContext as any as LElementNode;
|
||||||
const tNode = lElement.tNode;
|
const tNode = getTNode(index);
|
||||||
ngDevMode &&
|
ngDevMode &&
|
||||||
assertDefined(tNode.stylingTemplate, 'getStylingContext() called before elementStyling()');
|
assertDefined(tNode.stylingTemplate, 'getStylingContext() called before elementStyling()');
|
||||||
stylingContext = viewData[index + HEADER_OFFSET] =
|
stylingContext = viewData[index + HEADER_OFFSET] =
|
||||||
@ -1657,12 +1658,12 @@ export function text(index: number, value?: any): void {
|
|||||||
viewData[BINDING_INDEX], tView.bindingStartIndex,
|
viewData[BINDING_INDEX], tView.bindingStartIndex,
|
||||||
'text nodes should be created before any bindings');
|
'text nodes should be created before any bindings');
|
||||||
ngDevMode && ngDevMode.rendererCreateTextNode++;
|
ngDevMode && ngDevMode.rendererCreateTextNode++;
|
||||||
const textNode = createTextNode(value, renderer);
|
const textNative = createTextNode(value, renderer);
|
||||||
const node = createLNode(index, TNodeType.Element, textNode, null, null);
|
const tNode = createNodeAtIndex(index, TNodeType.Element, textNative, null, null);
|
||||||
|
|
||||||
// Text nodes are self closing.
|
// Text nodes are self closing.
|
||||||
isParent = false;
|
isParent = false;
|
||||||
appendChild(getParentLNode(node), textNode, viewData);
|
appendChild(textNative, tNode, viewData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1700,7 +1701,7 @@ export function textBinding<T>(index: number, value: T | NO_CHANGE): void {
|
|||||||
export function directiveCreate<T>(
|
export function directiveCreate<T>(
|
||||||
directiveDefIdx: number, directive: T,
|
directiveDefIdx: number, directive: T,
|
||||||
directiveDef: DirectiveDefInternal<T>| ComponentDefInternal<T>): T {
|
directiveDef: DirectiveDefInternal<T>| ComponentDefInternal<T>): T {
|
||||||
const hostNode = getPreviousOrParentNode();
|
const hostNode = getPreviousOrParentNode() !;
|
||||||
const instance = baseDirectiveCreate(directiveDefIdx, directive, directiveDef, hostNode);
|
const instance = baseDirectiveCreate(directiveDefIdx, directive, directiveDef, hostNode);
|
||||||
|
|
||||||
const isComponent = (directiveDef as ComponentDefInternal<T>).template;
|
const isComponent = (directiveDef as ComponentDefInternal<T>).template;
|
||||||
@ -1745,7 +1746,7 @@ function addComponentLogic<T>(
|
|||||||
// We need to set the host node/data here because when the component LNode was created,
|
// We need to set the host node/data here because when the component LNode was created,
|
||||||
// we didn't yet know it was a component (just an element).
|
// we didn't yet know it was a component (just an element).
|
||||||
(hostNode as{data: LViewData}).data = componentView;
|
(hostNode as{data: LViewData}).data = componentView;
|
||||||
(componentView as LViewData)[HOST_NODE] = hostNode as LElementNode;
|
(componentView as LViewData)[HOST_NODE] = getPreviousOrParentTNode() as TElementNode;
|
||||||
|
|
||||||
initChangeDetectorIfExisting(hostNode.nodeInjector, instance, componentView);
|
initChangeDetectorIfExisting(hostNode.nodeInjector, instance, componentView);
|
||||||
|
|
||||||
@ -1877,27 +1878,19 @@ function generateInitialInputs(
|
|||||||
/**
|
/**
|
||||||
* Creates a LContainer, either from a container instruction, or for a ViewContainerRef.
|
* Creates a LContainer, either from a container instruction, or for a ViewContainerRef.
|
||||||
*
|
*
|
||||||
* @param parentLNode the LNode in which the container's content will be rendered
|
|
||||||
* @param currentView The parent view of the LContainer
|
* @param currentView The parent view of the LContainer
|
||||||
* @param isForViewContainerRef Optional a flag indicating the ViewContainerRef case
|
* @param isForViewContainerRef Optional a flag indicating the ViewContainerRef case
|
||||||
* @returns LContainer
|
* @returns LContainer
|
||||||
*/
|
*/
|
||||||
export function createLContainer(
|
export function createLContainer(
|
||||||
parentLNode: LNode, currentView: LViewData, isForViewContainerRef?: boolean): LContainer {
|
currentView: LViewData, isForViewContainerRef?: boolean): LContainer {
|
||||||
ngDevMode && assertDefined(parentLNode, 'containers should have a parent');
|
|
||||||
let renderParent = canInsertNativeNode(parentLNode, currentView) ?
|
|
||||||
parentLNode as LElementNode | LViewNode :
|
|
||||||
null;
|
|
||||||
if (renderParent && renderParent.tNode.type === TNodeType.View) {
|
|
||||||
renderParent = getParentLNode(renderParent as LViewNode) !.data[RENDER_PARENT];
|
|
||||||
}
|
|
||||||
return [
|
return [
|
||||||
isForViewContainerRef ? null : 0, // active index
|
isForViewContainerRef ? null : 0, // active index
|
||||||
currentView, // parent
|
currentView, // parent
|
||||||
null, // next
|
null, // next
|
||||||
null, // queries
|
null, // queries
|
||||||
[], // views
|
[], // views
|
||||||
renderParent as LElementNode
|
null // renderParent, set after node creation
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1923,16 +1916,16 @@ export function template(
|
|||||||
tagName?: string | null, attrs?: TAttributes | null, localRefs?: string[] | null,
|
tagName?: string | null, attrs?: TAttributes | null, localRefs?: string[] | null,
|
||||||
localRefExtractor?: LocalRefExtractor) {
|
localRefExtractor?: LocalRefExtractor) {
|
||||||
// TODO: consider a separate node type for templates
|
// TODO: consider a separate node type for templates
|
||||||
const node = containerInternal(index, tagName || null, attrs || null, localRefs || null);
|
const tNode = containerInternal(index, tagName || null, attrs || null);
|
||||||
|
|
||||||
if (firstTemplatePass) {
|
if (firstTemplatePass) {
|
||||||
node.tNode.tViews = createTView(
|
tNode.tViews = createTView(
|
||||||
-1, templateFn, consts, vars, tView.directiveRegistry, tView.pipeRegistry, null);
|
-1, templateFn, consts, vars, tView.directiveRegistry, tView.pipeRegistry, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
createDirectivesAndLocals(node, localRefs, localRefExtractor);
|
createDirectivesAndLocals(localRefs, localRefExtractor);
|
||||||
currentQueries && (currentQueries = currentQueries.addNode(node));
|
currentQueries && (currentQueries = currentQueries.addNode(previousOrParentTNode));
|
||||||
queueLifecycleHooks(node.tNode.flags, tView);
|
queueLifecycleHooks(tNode.flags, tView);
|
||||||
isParent = false;
|
isParent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1946,30 +1939,28 @@ export function template(
|
|||||||
* @param index The index of the container in the data array
|
* @param index The index of the container in the data array
|
||||||
*/
|
*/
|
||||||
export function container(index: number): void {
|
export function container(index: number): void {
|
||||||
const node = containerInternal(index, null, null, null);
|
const tNode = containerInternal(index, null, null);
|
||||||
firstTemplatePass && (node.tNode.tViews = []);
|
firstTemplatePass && (tNode.tViews = []);
|
||||||
isParent = false;
|
isParent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function containerInternal(
|
function containerInternal(
|
||||||
index: number, tagName: string | null, attrs: TAttributes | null,
|
index: number, tagName: string | null, attrs: TAttributes | null): TNode {
|
||||||
localRefs: string[] | null): LContainerNode {
|
|
||||||
ngDevMode && assertEqual(
|
ngDevMode && assertEqual(
|
||||||
viewData[BINDING_INDEX], tView.bindingStartIndex,
|
viewData[BINDING_INDEX], tView.bindingStartIndex,
|
||||||
'container nodes should be created before any bindings');
|
'container nodes should be created before any bindings');
|
||||||
|
|
||||||
const previousNode: LNode = getPreviousOrParentNode();
|
const lContainer = createLContainer(viewData);
|
||||||
const currentParent = isParent ? previousNode : getParentLNode(previousNode) !;
|
|
||||||
const lContainer = createLContainer(currentParent, viewData);
|
|
||||||
|
|
||||||
ngDevMode && ngDevMode.rendererCreateComment++;
|
ngDevMode && ngDevMode.rendererCreateComment++;
|
||||||
const comment = renderer.createComment(ngDevMode ? 'container' : '');
|
const comment = renderer.createComment(ngDevMode ? 'container' : '');
|
||||||
const node = createLNode(index, TNodeType.Container, comment, tagName, attrs, lContainer);
|
const tNode = createNodeAtIndex(index, TNodeType.Container, comment, tagName, attrs, lContainer);
|
||||||
appendChild(getParentLNode(node), comment, viewData);
|
|
||||||
|
lContainer[RENDER_PARENT] = getRenderParent(tNode, viewData);
|
||||||
|
appendChild(comment, tNode, viewData);
|
||||||
|
|
||||||
// Containers are added to the current view tree instead of their embedded views
|
// Containers are added to the current view tree instead of their embedded views
|
||||||
// because views can be removed and re-inserted.
|
// because views can be removed and re-inserted.
|
||||||
addToViewTree(viewData, index + HEADER_OFFSET, node.data);
|
addToViewTree(viewData, index + HEADER_OFFSET, lContainer);
|
||||||
|
|
||||||
if (currentQueries) {
|
if (currentQueries) {
|
||||||
// prepare place for matching nodes from views inserted into a given container
|
// prepare place for matching nodes from views inserted into a given container
|
||||||
@ -1977,7 +1968,7 @@ function containerInternal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.Container);
|
ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.Container);
|
||||||
return node;
|
return tNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2021,7 +2012,7 @@ export function containerRefreshEnd(): void {
|
|||||||
|
|
||||||
// remove extra views at the end of the container
|
// remove extra views at the end of the container
|
||||||
while (nextIndex < container.data[VIEWS].length) {
|
while (nextIndex < container.data[VIEWS].length) {
|
||||||
removeView(container, nextIndex);
|
removeView(container, previousOrParentTNode as TContainerNode, nextIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2059,7 +2050,8 @@ function refreshDynamicEmbeddedViews(lViewData: LViewData) {
|
|||||||
* @returns index of a found view or -1 if not found
|
* @returns index of a found view or -1 if not found
|
||||||
*/
|
*/
|
||||||
function scanForView(
|
function scanForView(
|
||||||
containerNode: LContainerNode, startIdx: number, viewBlockId: number): LViewData|null {
|
containerNode: LContainerNode, tContainerNode: TContainerNode, startIdx: number,
|
||||||
|
viewBlockId: number): LViewData|null {
|
||||||
const views = containerNode.data[VIEWS];
|
const views = containerNode.data[VIEWS];
|
||||||
for (let i = startIdx; i < views.length; i++) {
|
for (let i = startIdx; i < views.length; i++) {
|
||||||
const viewAtPositionId = views[i][TVIEW].id;
|
const viewAtPositionId = views[i][TVIEW].id;
|
||||||
@ -2067,7 +2059,7 @@ function scanForView(
|
|||||||
return views[i];
|
return views[i];
|
||||||
} else if (viewAtPositionId < viewBlockId) {
|
} else if (viewAtPositionId < viewBlockId) {
|
||||||
// found a view that should not be at this position - remove
|
// found a view that should not be at this position - remove
|
||||||
removeView(containerNode, i);
|
removeView(containerNode, tContainerNode, i);
|
||||||
} else {
|
} else {
|
||||||
// found a view with id greater than the one we are searching for
|
// found a view with id greater than the one we are searching for
|
||||||
// which means that required view doesn't exist and can't be found at
|
// which means that required view doesn't exist and can't be found at
|
||||||
@ -2094,12 +2086,11 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num
|
|||||||
|
|
||||||
ngDevMode && assertNodeType(containerTNode, TNodeType.Container);
|
ngDevMode && assertNodeType(containerTNode, TNodeType.Container);
|
||||||
const lContainer = container.data;
|
const lContainer = container.data;
|
||||||
let viewNode: LViewNode|null;
|
let viewToRender = scanForView(
|
||||||
let viewToRender = scanForView(container, lContainer[ACTIVE_INDEX] !, viewBlockId);
|
container, containerTNode as TContainerNode, lContainer[ACTIVE_INDEX] !, viewBlockId);
|
||||||
|
|
||||||
if (viewToRender) {
|
if (viewToRender) {
|
||||||
isParent = true;
|
isParent = true;
|
||||||
viewNode = viewToRender[HOST_NODE] as LViewNode;
|
|
||||||
enterView(viewToRender, viewToRender[TVIEW].node);
|
enterView(viewToRender, viewToRender[TVIEW].node);
|
||||||
} else {
|
} else {
|
||||||
// When we create a new LView, we always reset the state of the instructions.
|
// When we create a new LView, we always reset the state of the instructions.
|
||||||
@ -2112,13 +2103,13 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num
|
|||||||
viewToRender[QUERIES] = lContainer[QUERIES] !.createView();
|
viewToRender[QUERIES] = lContainer[QUERIES] !.createView();
|
||||||
}
|
}
|
||||||
|
|
||||||
viewNode = createLNode(viewBlockId, TNodeType.View, null, null, null, viewToRender);
|
createNodeAtIndex(viewBlockId, TNodeType.View, null, null, null, viewToRender);
|
||||||
enterView(viewToRender, viewToRender[TVIEW].node);
|
enterView(viewToRender, viewToRender[TVIEW].node);
|
||||||
}
|
}
|
||||||
if (container) {
|
if (container) {
|
||||||
if (creationMode) {
|
if (creationMode) {
|
||||||
// it is a new view, insert it into collection of views for a given container
|
// it is a new view, insert it into collection of views for a given container
|
||||||
insertView(container, viewNode, lContainer[ACTIVE_INDEX] !);
|
insertView(container, viewToRender, lContainer[ACTIVE_INDEX] !, -1);
|
||||||
}
|
}
|
||||||
lContainer[ACTIVE_INDEX] !++;
|
lContainer[ACTIVE_INDEX] !++;
|
||||||
}
|
}
|
||||||
@ -2153,7 +2144,7 @@ function getOrCreateEmbeddedTView(
|
|||||||
|
|
||||||
/** Marks the end of an embedded view. */
|
/** Marks the end of an embedded view. */
|
||||||
export function embeddedViewEnd(): void {
|
export function embeddedViewEnd(): void {
|
||||||
const viewHost = tView.node;
|
const viewHost = viewData[HOST_NODE];
|
||||||
refreshDescendantViews();
|
refreshDescendantViews();
|
||||||
leaveView(viewData[PARENT] !);
|
leaveView(viewData[PARENT] !);
|
||||||
previousOrParentTNode = viewHost !;
|
previousOrParentTNode = viewHost !;
|
||||||
@ -2208,15 +2199,15 @@ export function viewAttached(view: LViewData): boolean {
|
|||||||
* @param rawSelectors A collection of CSS selectors in the raw, un-parsed form
|
* @param rawSelectors A collection of CSS selectors in the raw, un-parsed form
|
||||||
*/
|
*/
|
||||||
export function projectionDef(selectors?: CssSelectorList[], textSelectors?: string[]): void {
|
export function projectionDef(selectors?: CssSelectorList[], textSelectors?: string[]): void {
|
||||||
const componentNode: LElementNode = findComponentHost(viewData);
|
const componentNode = findComponentView(viewData)[HOST_NODE] as TElementNode;
|
||||||
|
|
||||||
if (!componentNode.tNode.projection) {
|
if (!componentNode.projection) {
|
||||||
const noOfNodeBuckets = selectors ? selectors.length + 1 : 1;
|
const noOfNodeBuckets = selectors ? selectors.length + 1 : 1;
|
||||||
const pData: (TNode | null)[] = componentNode.tNode.projection =
|
const pData: (TNode | null)[] = componentNode.projection =
|
||||||
new Array(noOfNodeBuckets).fill(null);
|
new Array(noOfNodeBuckets).fill(null);
|
||||||
const tails: (TNode | null)[] = pData.slice();
|
const tails: (TNode | null)[] = pData.slice();
|
||||||
|
|
||||||
let componentChild = componentNode.tNode.child;
|
let componentChild: TNode|null = componentNode.child;
|
||||||
|
|
||||||
while (componentChild !== null) {
|
while (componentChild !== null) {
|
||||||
const bucketIndex =
|
const bucketIndex =
|
||||||
@ -2243,7 +2234,7 @@ export function projectionDef(selectors?: CssSelectorList[], textSelectors?: str
|
|||||||
* a new array each time the function is called. Instead the array will be
|
* 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.
|
* re-used by each invocation. This works because the function is not reentrant.
|
||||||
*/
|
*/
|
||||||
const projectionNodeStack: LProjectionNode[] = [];
|
const projectionNodeStack: (LViewData | TNode)[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts previously re-distributed projected nodes. This instruction must be preceded by a call
|
* Inserts previously re-distributed projected nodes. This instruction must be preceded by a call
|
||||||
@ -2255,63 +2246,52 @@ const projectionNodeStack: LProjectionNode[] = [];
|
|||||||
* - 1 based index of the selector from the {@link projectionDef}
|
* - 1 based index of the selector from the {@link projectionDef}
|
||||||
*/
|
*/
|
||||||
export function projection(nodeIndex: number, selectorIndex: number = 0, attrs?: string[]): void {
|
export function projection(nodeIndex: number, selectorIndex: number = 0, attrs?: string[]): void {
|
||||||
const node = createLNode(nodeIndex, TNodeType.Projection, null, null, attrs || null, null);
|
const tProjectionNode =
|
||||||
|
createNodeAtIndex(nodeIndex, TNodeType.Projection, null, null, attrs || null, null);
|
||||||
|
|
||||||
// We can't use viewData[HOST_NODE] because projection nodes can be nested in embedded views.
|
// 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;
|
if (tProjectionNode.projection === null) tProjectionNode.projection = selectorIndex;
|
||||||
|
|
||||||
// `<ng-content>` has no content
|
// `<ng-content>` has no content
|
||||||
isParent = false;
|
isParent = false;
|
||||||
|
|
||||||
// re-distribution of projectable nodes is stored on a component's view level
|
// re-distribution of projectable nodes is stored on a component's view level
|
||||||
const parent = getParentLNode(node);
|
const componentView = findComponentView(viewData);
|
||||||
|
const componentNode = componentView[HOST_NODE] as TElementNode;
|
||||||
const componentNode = findComponentHost(viewData);
|
let nodeToProject = (componentNode.projection as(TNode | null)[])[selectorIndex];
|
||||||
let nodeToProject = (componentNode.tNode.projection as(TNode | null)[])[selectorIndex];
|
let projectedView = componentView[PARENT] !;
|
||||||
let projectedView = componentNode.view;
|
|
||||||
let projectionNodeIndex = -1;
|
let projectionNodeIndex = -1;
|
||||||
let renderParent: LElementNode|null = null;
|
|
||||||
|
|
||||||
while (nodeToProject) {
|
while (nodeToProject) {
|
||||||
if (nodeToProject.type === TNodeType.Projection) {
|
if (nodeToProject.type === TNodeType.Projection) {
|
||||||
// This node is re-projected, so we must go up the tree to get its projected nodes.
|
// This node is re-projected, so we must go up the tree to get its projected nodes.
|
||||||
const currentComponentHost = findComponentHost(projectedView);
|
const currentComponentView = findComponentView(projectedView);
|
||||||
const firstProjectedNode = (currentComponentHost.tNode.projection as(
|
const currentComponentHost = currentComponentView[HOST_NODE] as TElementNode;
|
||||||
TNode | null)[])[nodeToProject.projection as number];
|
const firstProjectedNode =
|
||||||
|
(currentComponentHost.projection as(TNode | null)[])[nodeToProject.projection as number];
|
||||||
|
|
||||||
if (firstProjectedNode) {
|
if (firstProjectedNode) {
|
||||||
projectionNodeStack[++projectionNodeIndex] = projectedView[nodeToProject.index];
|
projectionNodeStack[++projectionNodeIndex] = nodeToProject;
|
||||||
|
projectionNodeStack[++projectionNodeIndex] = projectedView;
|
||||||
|
|
||||||
nodeToProject = firstProjectedNode;
|
nodeToProject = firstProjectedNode;
|
||||||
projectedView = currentComponentHost.view;
|
projectedView = currentComponentView[PARENT] !;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const lNode = projectedView[nodeToProject.index];
|
const lNode = projectedView[nodeToProject.index] as LTextNode | LElementNode | LContainerNode;
|
||||||
// This flag must be set now or we won't know that this node is projected
|
// This flag must be set now or we won't know that this node is projected
|
||||||
// if the nodes are inserted into a container later.
|
// if the nodes are inserted into a container later.
|
||||||
lNode.tNode.flags |= TNodeFlags.isProjected;
|
nodeToProject.flags |= TNodeFlags.isProjected;
|
||||||
if (canInsertNativeNode(parent, viewData)) {
|
|
||||||
let grandparent: LContainerNode;
|
|
||||||
if (renderParent == null) {
|
|
||||||
renderParent = parent.tNode.type === TNodeType.View ?
|
|
||||||
(grandparent = getParentLNode(parent) as LContainerNode) &&
|
|
||||||
grandparent.data[RENDER_PARENT] ! :
|
|
||||||
parent as LElementNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
appendProjectedNode(
|
appendProjectedNode(lNode, nodeToProject, tProjectionNode, viewData, projectedView);
|
||||||
lNode as LTextNode | LElementNode | LContainerNode, parent, viewData, renderParent,
|
|
||||||
projectedView);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are finished with a list of re-projected nodes, we need to get
|
// 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.
|
// back to the root projection node that was re-projected.
|
||||||
if (nodeToProject.next === null && projectedView !== componentNode.view) {
|
if (nodeToProject.next === null && projectedView !== componentView[PARENT] !) {
|
||||||
// move down into the view of the component we're projecting right now
|
projectedView = projectionNodeStack[projectionNodeIndex--] as LViewData;
|
||||||
const lNode = projectionNodeStack[projectionNodeIndex--];
|
nodeToProject = projectionNodeStack[projectionNodeIndex--] as TNode;
|
||||||
nodeToProject = lNode.tNode;
|
|
||||||
projectedView = lNode.view;
|
|
||||||
}
|
}
|
||||||
nodeToProject = nodeToProject.next;
|
nodeToProject = nodeToProject.next;
|
||||||
}
|
}
|
||||||
@ -2383,12 +2363,12 @@ export function wrapListenerWithDirtyAndDefault(
|
|||||||
export function markViewDirty(view: LViewData): void {
|
export function markViewDirty(view: LViewData): void {
|
||||||
let currentView: LViewData = view;
|
let currentView: LViewData = view;
|
||||||
|
|
||||||
while (currentView[PARENT] != null) {
|
while (currentView && !(currentView[FLAGS] & LViewFlags.IsRoot)) {
|
||||||
currentView[FLAGS] |= LViewFlags.Dirty;
|
currentView[FLAGS] |= LViewFlags.Dirty;
|
||||||
currentView = currentView[PARENT] !;
|
currentView = currentView[PARENT] !;
|
||||||
}
|
}
|
||||||
currentView[FLAGS] |= LViewFlags.Dirty;
|
currentView[FLAGS] |= LViewFlags.Dirty;
|
||||||
ngDevMode && assertDefined(currentView[CONTEXT], 'rootContext');
|
ngDevMode && assertDefined(currentView[CONTEXT], 'rootContext should be defined');
|
||||||
scheduleTick(currentView[CONTEXT] as RootContext);
|
scheduleTick(currentView[CONTEXT] as RootContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2451,7 +2431,7 @@ function tickRootContext(rootContext: RootContext) {
|
|||||||
export function getRootView(component: any): LViewData {
|
export function getRootView(component: any): LViewData {
|
||||||
ngDevMode && assertDefined(component, 'component');
|
ngDevMode && assertDefined(component, 'component');
|
||||||
let lViewData = readPatchedLViewData(component) !;
|
let lViewData = readPatchedLViewData(component) !;
|
||||||
while (lViewData[PARENT]) {
|
while (lViewData && !(lViewData[FLAGS] & LViewFlags.IsRoot)) {
|
||||||
lViewData = lViewData[PARENT] !;
|
lViewData = lViewData[PARENT] !;
|
||||||
}
|
}
|
||||||
return lViewData;
|
return lViewData;
|
||||||
@ -2523,7 +2503,7 @@ export function checkNoChangesInRootView(lViewData: LViewData): void {
|
|||||||
/** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. */
|
/** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. */
|
||||||
export function detectChangesInternal<T>(hostView: LViewData, component: T) {
|
export function detectChangesInternal<T>(hostView: LViewData, component: T) {
|
||||||
const hostTView = hostView[TVIEW];
|
const hostTView = hostView[TVIEW];
|
||||||
const oldView = enterView(hostView, null);
|
const oldView = enterView(hostView, hostView[HOST_NODE]);
|
||||||
const templateFn = hostTView.template !;
|
const templateFn = hostTView.template !;
|
||||||
const viewQuery = hostTView.viewQuery;
|
const viewQuery = hostTView.viewQuery;
|
||||||
|
|
||||||
@ -2790,6 +2770,10 @@ export function loadElement(index: number): LElementNode {
|
|||||||
return loadElementInternal(index, viewData);
|
return loadElementInternal(index, viewData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getTNode(index: number): TNode {
|
||||||
|
return tView.data[index + HEADER_OFFSET] as TNode;
|
||||||
|
}
|
||||||
|
|
||||||
/** Gets the current binding value. */
|
/** Gets the current binding value. */
|
||||||
export function getBinding(bindingIndex: number): any {
|
export function getBinding(bindingIndex: number): any {
|
||||||
ngDevMode && assertDataInRange(viewData[bindingIndex]);
|
ngDevMode && assertDataInRange(viewData[bindingIndex]);
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {LElementNode, LViewNode} from './node';
|
import {LElementNode} from './node';
|
||||||
import {LQueries} from './query';
|
import {LQueries} from './query';
|
||||||
import {LViewData, NEXT, PARENT, QUERIES} from './view';
|
import {LViewData, NEXT, PARENT, QUERIES} from './view';
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import {ElementRef} from '../../linker/element_ref';
|
|||||||
import {TemplateRef} from '../../linker/template_ref';
|
import {TemplateRef} from '../../linker/template_ref';
|
||||||
import {ViewContainerRef} from '../../linker/view_container_ref';
|
import {ViewContainerRef} from '../../linker/view_container_ref';
|
||||||
|
|
||||||
import {LContainerNode, LElementContainerNode, LElementNode} from './node';
|
import {LContainerNode, LElementContainerNode, LElementNode, TContainerNode, TElementNode, TNode} from './node';
|
||||||
|
|
||||||
export interface LInjector {
|
export interface LInjector {
|
||||||
/**
|
/**
|
||||||
@ -28,6 +28,8 @@ export interface LInjector {
|
|||||||
*/
|
*/
|
||||||
readonly node: LElementNode|LElementContainerNode|LContainerNode;
|
readonly node: LElementNode|LElementContainerNode|LContainerNode;
|
||||||
|
|
||||||
|
readonly tNode: TNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The following bloom filter determines whether a directive is available
|
* The following bloom filter determines whether a directive is available
|
||||||
* on the associated node or not. This prevents us from searching the directives
|
* on the associated node or not. This prevents us from searching the directives
|
||||||
|
@ -81,7 +81,6 @@ export interface LNode {
|
|||||||
*/
|
*/
|
||||||
readonly data: LViewData|LContainer|null;
|
readonly data: LViewData|LContainer|null;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Each node belongs to a view.
|
* Each node belongs to a view.
|
||||||
*
|
*
|
||||||
@ -92,12 +91,6 @@ export interface LNode {
|
|||||||
/** The injector associated with this node. Necessary for DI. */
|
/** The injector associated with this node. Necessary for DI. */
|
||||||
nodeInjector: LInjector|null;
|
nodeInjector: LInjector|null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Pointer to the corresponding TNode object, which stores static
|
|
||||||
* data about this node.
|
|
||||||
*/
|
|
||||||
tNode: TNode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pointer to an LContainerNode created by directives requesting ViewContainerRef
|
* A pointer to an LContainerNode created by directives requesting ViewContainerRef
|
||||||
*/
|
*/
|
||||||
@ -385,13 +378,13 @@ export interface TNode {
|
|||||||
export interface TElementNode extends TNode {
|
export interface TElementNode extends TNode {
|
||||||
/** Index in the data[] array */
|
/** Index in the data[] array */
|
||||||
index: number;
|
index: number;
|
||||||
child: TElementNode|TTextNode|TContainerNode|TProjectionNode|null;
|
child: TElementNode|TTextNode|TElementContainerNode|TContainerNode|TProjectionNode|null;
|
||||||
/**
|
/**
|
||||||
* Element nodes will have parents unless they are the first node of a component or
|
* Element nodes will have parents unless they are the first node of a component or
|
||||||
* embedded view (which means their parent is in a different view and must be
|
* embedded view (which means their parent is in a different view and must be
|
||||||
* retrieved using LView.node).
|
* retrieved using viewData[HOST_NODE]).
|
||||||
*/
|
*/
|
||||||
parent: TElementNode|null;
|
parent: TElementNode|TElementContainerNode|null;
|
||||||
tViews: null;
|
tViews: null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -412,7 +405,7 @@ export interface TTextNode extends TNode {
|
|||||||
* embedded view (which means their parent is in a different view and must be
|
* embedded view (which means their parent is in a different view and must be
|
||||||
* retrieved using LView.node).
|
* retrieved using LView.node).
|
||||||
*/
|
*/
|
||||||
parent: TElementNode|null;
|
parent: TElementNode|TElementContainerNode|null;
|
||||||
tViews: null;
|
tViews: null;
|
||||||
projection: null;
|
projection: null;
|
||||||
}
|
}
|
||||||
@ -434,16 +427,27 @@ export interface TContainerNode extends TNode {
|
|||||||
* - They are the first node of a component or embedded view
|
* - They are the first node of a component or embedded view
|
||||||
* - They are dynamically created
|
* - They are dynamically created
|
||||||
*/
|
*/
|
||||||
parent: TElementNode|null;
|
parent: TElementNode|TElementContainerNode|null;
|
||||||
tViews: TView|TView[]|null;
|
tViews: TView|TView[]|null;
|
||||||
projection: null;
|
projection: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Static data for an LElementContainerNode */
|
||||||
|
export interface TElementContainerNode extends TNode {
|
||||||
|
/** Index in the LViewData[] array. */
|
||||||
|
index: number;
|
||||||
|
child: TElementNode|TTextNode|TContainerNode|TElementContainerNode|TProjectionNode|null;
|
||||||
|
parent: TElementNode|TElementContainerNode|null;
|
||||||
|
tViews: null;
|
||||||
|
projection: null;
|
||||||
|
}
|
||||||
|
|
||||||
/** Static data for an LViewNode */
|
/** Static data for an LViewNode */
|
||||||
export interface TViewNode extends TNode {
|
export interface TViewNode extends TNode {
|
||||||
/** If -1, it's a dynamically created view. Otherwise, it is the view block ID. */
|
/** If -1, it's a dynamically created view. Otherwise, it is the view block ID. */
|
||||||
index: number;
|
index: number;
|
||||||
child: TElementNode|TTextNode|TContainerNode|TProjectionNode|null;
|
child: TElementNode|TTextNode|TElementContainerNode|TContainerNode|TProjectionNode|null;
|
||||||
parent: TContainerNode|null;
|
parent: TContainerNode|null;
|
||||||
tViews: null;
|
tViews: null;
|
||||||
projection: null;
|
projection: null;
|
||||||
@ -458,7 +462,7 @@ export interface TProjectionNode extends TNode {
|
|||||||
* or embedded view (which means their parent is in a different view and must be
|
* or embedded view (which means their parent is in a different view and must be
|
||||||
* retrieved using LView.node).
|
* retrieved using LView.node).
|
||||||
*/
|
*/
|
||||||
parent: TElementNode|null;
|
parent: TElementNode|TElementContainerNode|null;
|
||||||
tViews: null;
|
tViews: null;
|
||||||
|
|
||||||
/** Index of the projection node. (See TNode.projection for more info.) */
|
/** Index of the projection node. (See TNode.projection for more info.) */
|
||||||
@ -536,4 +540,4 @@ export type LNodeWithLocalRefs = LContainerNode | LElementNode | LElementContain
|
|||||||
* - `<div #nativeDivEl>` - `nativeDivEl` should point to the native `<div>` element;
|
* - `<div #nativeDivEl>` - `nativeDivEl` should point to the native `<div>` element;
|
||||||
* - `<ng-template #tplRef>` - `tplRef` should point to the `TemplateRef` instance;
|
* - `<ng-template #tplRef>` - `tplRef` should point to the `TemplateRef` instance;
|
||||||
*/
|
*/
|
||||||
export type LocalRefExtractor = (lNode: LNodeWithLocalRefs) => any;
|
export type LocalRefExtractor = (lNode: LNodeWithLocalRefs, tNode: TNode) => any;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import {QueryList} from '../../linker';
|
import {QueryList} from '../../linker';
|
||||||
import {Type} from '../../type';
|
import {Type} from '../../type';
|
||||||
import {LNode} from './node';
|
import {TNode} from './node';
|
||||||
|
|
||||||
/** Used for tracking queries (e.g. ViewChild, ContentChild). */
|
/** Used for tracking queries (e.g. ViewChild, ContentChild). */
|
||||||
export interface LQueries {
|
export interface LQueries {
|
||||||
@ -30,10 +30,10 @@ export interface LQueries {
|
|||||||
clone(): LQueries;
|
clone(): LQueries;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify `LQueries` that a new `LNode` has been created and needs to be added to query results
|
* Notify `LQueries` that a new `TNode` has been created and needs to be added to query results
|
||||||
* if matching query predicate.
|
* if matching query predicate.
|
||||||
*/
|
*/
|
||||||
addNode(node: LNode): LQueries|null;
|
addNode(tNode: TNode): LQueries|null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify `LQueries` that a new LContainer was added to ivy data structures. As a result we need
|
* Notify `LQueries` that a new LContainer was added to ivy data structures. As a result we need
|
||||||
|
@ -94,15 +94,16 @@ export interface LViewData extends Array<any> {
|
|||||||
[FLAGS]: LViewFlags;
|
[FLAGS]: LViewFlags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pointer to the `LViewNode` or `LElementNode` which represents the root of the view.
|
* Pointer to the `TViewNode` or `TElementNode` which represents the root of the view.
|
||||||
*
|
*
|
||||||
* If `LViewNode`, this is an embedded view of a container. We need this to be able to
|
* If `TViewNode`, this is an embedded view of a container. We need this to be able to
|
||||||
* efficiently find the `LViewNode` when inserting the view into an anchor.
|
* efficiently find the `LViewNode` when inserting the view into an anchor.
|
||||||
*
|
*
|
||||||
* If `LElementNode`, this is the LView of a component.
|
* If `TElementNode`, this is the LView of a component.
|
||||||
|
*
|
||||||
|
* If null, this is the root view of an application (root component is in this view).
|
||||||
*/
|
*/
|
||||||
// TODO(kara): Replace with index
|
[HOST_NODE]: TViewNode|TElementNode|null;
|
||||||
[HOST_NODE]: LViewNode|LElementNode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The binding index we should access next.
|
* The binding index we should access next.
|
||||||
@ -213,16 +214,16 @@ export const enum LViewFlags {
|
|||||||
* back into the parent view, `data` will be defined and `creationMode` will be
|
* back into the parent view, `data` will be defined and `creationMode` will be
|
||||||
* improperly reported as false.
|
* improperly reported as false.
|
||||||
*/
|
*/
|
||||||
CreationMode = 0b000001,
|
CreationMode = 0b0000001,
|
||||||
|
|
||||||
/** Whether this view has default change detection strategy (checks always) or onPush */
|
/** Whether this view has default change detection strategy (checks always) or onPush */
|
||||||
CheckAlways = 0b000010,
|
CheckAlways = 0b0000010,
|
||||||
|
|
||||||
/** Whether or not this view is currently dirty (needing check) */
|
/** Whether or not this view is currently dirty (needing check) */
|
||||||
Dirty = 0b000100,
|
Dirty = 0b0000100,
|
||||||
|
|
||||||
/** Whether or not this view is currently attached to change detection tree. */
|
/** Whether or not this view is currently attached to change detection tree. */
|
||||||
Attached = 0b001000,
|
Attached = 0b0001000,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the init hooks have run.
|
* Whether or not the init hooks have run.
|
||||||
@ -231,10 +232,13 @@ export const enum LViewFlags {
|
|||||||
* runs OR the first cR() instruction that runs (so inits are run for the top level view before
|
* runs OR the first cR() instruction that runs (so inits are run for the top level view before
|
||||||
* any embedded views).
|
* any embedded views).
|
||||||
*/
|
*/
|
||||||
RunInit = 0b010000,
|
RunInit = 0b0010000,
|
||||||
|
|
||||||
/** Whether or not this view is destroyed. */
|
/** Whether or not this view is destroyed. */
|
||||||
Destroyed = 0b100000,
|
Destroyed = 0b0100000,
|
||||||
|
|
||||||
|
/** Whether or not this view is the root view */
|
||||||
|
IsRoot = 0b1000000,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,51 +10,66 @@ import {assertDefined} from './assert';
|
|||||||
import {attachPatchData} from './context_discovery';
|
import {attachPatchData} from './context_discovery';
|
||||||
import {callHooks} from './hooks';
|
import {callHooks} from './hooks';
|
||||||
import {LContainer, RENDER_PARENT, VIEWS, unusedValueExportToPlacateAjd as unused1} from './interfaces/container';
|
import {LContainer, RENDER_PARENT, VIEWS, unusedValueExportToPlacateAjd as unused1} from './interfaces/container';
|
||||||
import {LContainerNode, LElementContainerNode, LElementNode, LNode, LProjectionNode, LTextNode, LViewNode, TNode, TNodeFlags, TNodeType, TViewNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node';
|
import {LContainerNode, LElementContainerNode, LElementNode, LTextNode, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TProjectionNode, TTextNode, TViewNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node';
|
||||||
import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection';
|
import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection';
|
||||||
import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer';
|
import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer';
|
||||||
import {CLEANUP, CONTAINER_INDEX, DECLARATION_VIEW, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, HookData, LViewData, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, TVIEW, unusedValueExportToPlacateAjd as unused5} from './interfaces/view';
|
import {CLEANUP, CONTAINER_INDEX, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, HookData, LViewData, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, TVIEW, unusedValueExportToPlacateAjd as unused5} from './interfaces/view';
|
||||||
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
import {assertNodeType} from './node_assert';
|
||||||
import {readElementValue, stringify} from './util';
|
import {isComponent, readElementValue, stringify} from './util';
|
||||||
|
|
||||||
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5;
|
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5;
|
||||||
|
|
||||||
/** Retrieves the first child of a given node */
|
|
||||||
export function getChildLNode(node: LNode): LNode|null {
|
|
||||||
if (node.tNode.child) {
|
|
||||||
const viewData = node.tNode.type === TNodeType.View ? node.data as LViewData : node.view;
|
|
||||||
return readElementValue(viewData[node.tNode.child.index]);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retrieves the parent LNode of a given node. */
|
/** Retrieves the parent LNode of a given node. */
|
||||||
export function getParentLNode(
|
export function getParentLNode(tNode: TNode, currentView: LViewData): LElementNode|
|
||||||
node: LContainerNode | LElementNode | LElementContainerNode | LTextNode |
|
LElementContainerNode|LContainerNode|null {
|
||||||
LProjectionNode): LElementNode|LElementContainerNode|LViewNode;
|
return tNode.parent == null ? getHostElementNode(currentView) :
|
||||||
export function getParentLNode(node: LViewNode): LContainerNode|null;
|
readElementValue(currentView[tNode.parent.index]);
|
||||||
export function getParentLNode(node: LElementContainerNode): LElementNode|LElementContainerNode|
|
|
||||||
LViewNode;
|
|
||||||
export function getParentLNode(node: LNode): LElementNode|LElementContainerNode|LContainerNode|
|
|
||||||
LViewNode|null;
|
|
||||||
export function getParentLNode(node: LNode): LElementNode|LElementContainerNode|LContainerNode|
|
|
||||||
LViewNode|null {
|
|
||||||
if (node.tNode.index === -1 && node.tNode.type === TNodeType.View) {
|
|
||||||
// This is a dynamically created view inside a dynamic container.
|
|
||||||
// If the host index is -1, the view has not yet been inserted, so it has no parent.
|
|
||||||
const containerHostIndex = (node.data as LViewData)[CONTAINER_INDEX];
|
|
||||||
return containerHostIndex === -1 ? null : node.view[containerHostIndex].dynamicLContainerNode;
|
|
||||||
}
|
|
||||||
const parent = node.tNode.parent;
|
|
||||||
return readElementValue(parent ? node.view[parent.index] : node.view[HOST_NODE]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves render parent LElementNode for a given view.
|
* Gets the host LElementNode given a view. Will return null if the host element is an
|
||||||
* Might be null if a view is not yet attatched to any container.
|
* LViewNode, since they are being phased out.
|
||||||
*/
|
*/
|
||||||
function getRenderParent(viewNode: LViewNode): LElementNode|null {
|
export function getHostElementNode(currentView: LViewData): LElementNode|null {
|
||||||
const container = getParentLNode(viewNode);
|
const hostTNode = currentView[HOST_NODE] as TElementNode;
|
||||||
|
return hostTNode && hostTNode.type !== TNodeType.View ?
|
||||||
|
readElementValue(currentView[PARENT] ![hostTNode.index]) :
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the parent LNode if it's not a view. If it's a view, it will instead return the view's
|
||||||
|
* parent container node.
|
||||||
|
*/
|
||||||
|
export function getParentOrContainerNode(tNode: TNode, currentView: LViewData): LElementNode|
|
||||||
|
LElementContainerNode|LContainerNode|null {
|
||||||
|
const parentTNode = tNode.parent || currentView[HOST_NODE];
|
||||||
|
return parentTNode && parentTNode.type === TNodeType.View ?
|
||||||
|
getContainerNode(parentTNode, currentView) :
|
||||||
|
getParentLNode(tNode, currentView);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getContainerNode(tNode: TNode, embeddedView: LViewData): LContainerNode|null {
|
||||||
|
if (tNode.index === -1) {
|
||||||
|
// This is a dynamically created view inside a dynamic container.
|
||||||
|
// If the host index is -1, the view has not yet been inserted, so it has no parent.
|
||||||
|
const containerHostIndex = embeddedView[CONTAINER_INDEX];
|
||||||
|
return containerHostIndex > -1 ?
|
||||||
|
embeddedView[PARENT] ![containerHostIndex].dynamicLContainerNode :
|
||||||
|
null;
|
||||||
|
} else {
|
||||||
|
// This is a inline view node (e.g. embeddedViewStart)
|
||||||
|
return getParentLNode(tNode, embeddedView[PARENT] !) as LContainerNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves render parent LElementNode for a given view.
|
||||||
|
* Might be null if a view is not yet attached to any container.
|
||||||
|
*/
|
||||||
|
export function getContainerRenderParent(tViewNode: TViewNode, view: LViewData): LElementNode|null {
|
||||||
|
const container = getContainerNode(tViewNode, view);
|
||||||
return container ? container.data[RENDER_PARENT] : null;
|
return container ? container.data[RENDER_PARENT] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,16 +144,17 @@ function walkTNodeTree(
|
|||||||
lContainerNode.native;
|
lContainerNode.native;
|
||||||
}
|
}
|
||||||
} else if (tNode.type === TNodeType.Projection) {
|
} else if (tNode.type === TNodeType.Projection) {
|
||||||
const componentHost = findComponentHost(currentView !);
|
const componentView = findComponentView(currentView !);
|
||||||
|
const componentHost = componentView[HOST_NODE] as TElementNode;
|
||||||
const head: TNode|null =
|
const head: TNode|null =
|
||||||
(componentHost.tNode.projection as(TNode | null)[])[tNode.projection as number];
|
(componentHost.projection as(TNode | null)[])[tNode.projection as number];
|
||||||
|
|
||||||
// Must store both the TNode and the view because this projection node could be nested
|
// Must store both the TNode and the view because this projection node could be nested
|
||||||
// deeply inside embedded views, and we need to get back down to this particular nested view.
|
// deeply inside embedded views, and we need to get back down to this particular nested view.
|
||||||
projectionNodeStack[++projectionNodeIndex] = tNode;
|
projectionNodeStack[++projectionNodeIndex] = tNode;
|
||||||
projectionNodeStack[++projectionNodeIndex] = currentView !;
|
projectionNodeStack[++projectionNodeIndex] = currentView !;
|
||||||
if (head) {
|
if (head) {
|
||||||
currentView = (componentHost.data as LViewData)[PARENT] !;
|
currentView = componentView[PARENT] !;
|
||||||
nextTNode = currentView[TVIEW].data[head.index] as TNode;
|
nextTNode = currentView[TVIEW].data[head.index] as TNode;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -191,19 +207,16 @@ function walkTNodeTree(
|
|||||||
* @param lViewData LViewData for which we want a host element node
|
* @param lViewData LViewData for which we want a host element node
|
||||||
* @returns The host node
|
* @returns The host node
|
||||||
*/
|
*/
|
||||||
export function findComponentHost(lViewData: LViewData): LElementNode {
|
export function findComponentView(lViewData: LViewData): LViewData {
|
||||||
let viewRootLNode = lViewData[HOST_NODE];
|
let rootTNode = lViewData[HOST_NODE];
|
||||||
|
|
||||||
while (viewRootLNode.tNode.type === TNodeType.View) {
|
while (rootTNode && rootTNode.type === TNodeType.View) {
|
||||||
ngDevMode && assertDefined(lViewData[PARENT], 'lViewData.parent');
|
ngDevMode && assertDefined(lViewData[PARENT], 'viewData.parent');
|
||||||
lViewData = lViewData[PARENT] !;
|
lViewData = lViewData[PARENT] !;
|
||||||
viewRootLNode = lViewData[HOST_NODE];
|
rootTNode = lViewData[HOST_NODE];
|
||||||
}
|
}
|
||||||
|
|
||||||
ngDevMode && assertNodeType(viewRootLNode.tNode, TNodeType.Element);
|
return lViewData;
|
||||||
ngDevMode && assertDefined(viewRootLNode.data, 'node.data');
|
|
||||||
|
|
||||||
return viewRootLNode as LElementNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -239,24 +252,20 @@ export function createTextNode(value: any, renderer: Renderer3): RText {
|
|||||||
* to propagate deeply into the nested containers to remove all elements in the
|
* to propagate deeply into the nested containers to remove all elements in the
|
||||||
* views beneath it.
|
* views beneath it.
|
||||||
*
|
*
|
||||||
* @param container The container to which the root view belongs
|
|
||||||
* @param viewToWalk The view from which elements should be added or removed
|
* @param viewToWalk The view from which elements should be added or removed
|
||||||
* @param insertMode Whether or not elements should be added (if false, removing)
|
* @param insertMode Whether or not elements should be added (if false, removing)
|
||||||
* @param beforeNode The node before which elements should be added, if insert mode
|
* @param beforeNode The node before which elements should be added, if insert mode
|
||||||
*/
|
*/
|
||||||
export function addRemoveViewFromContainer(
|
export function addRemoveViewFromContainer(
|
||||||
container: LContainerNode, viewToWalk: LViewData, insertMode: true,
|
viewToWalk: LViewData, insertMode: true, beforeNode: RNode | null): void;
|
||||||
beforeNode: RNode | null): void;
|
export function addRemoveViewFromContainer(viewToWalk: LViewData, insertMode: false): void;
|
||||||
export function addRemoveViewFromContainer(
|
export function addRemoveViewFromContainer(
|
||||||
container: LContainerNode, viewToWalk: LViewData, insertMode: false): void;
|
viewToWalk: LViewData, insertMode: boolean, beforeNode?: RNode | null): void {
|
||||||
export function addRemoveViewFromContainer(
|
const parentNode = getContainerRenderParent(viewToWalk[TVIEW].node as TViewNode, viewToWalk);
|
||||||
container: LContainerNode, viewToWalk: LViewData, insertMode: boolean,
|
|
||||||
beforeNode?: RNode | null): void {
|
|
||||||
const parentNode = container.data[RENDER_PARENT];
|
|
||||||
const parent = parentNode ? parentNode.native : null;
|
const parent = parentNode ? parentNode.native : null;
|
||||||
ngDevMode && assertNodeType(viewToWalk[TVIEW].node as TNode, TNodeType.View);
|
ngDevMode && assertNodeType(viewToWalk[TVIEW].node as TNode, TNodeType.View);
|
||||||
if (parent) {
|
if (parent) {
|
||||||
const renderer = container.view[RENDERER];
|
const renderer = viewToWalk[RENDERER];
|
||||||
walkTNodeTree(
|
walkTNodeTree(
|
||||||
viewToWalk, insertMode ? WalkTNodeTreeAction.Insert : WalkTNodeTreeAction.Detach, renderer,
|
viewToWalk, insertMode ? WalkTNodeTreeAction.Insert : WalkTNodeTreeAction.Detach, renderer,
|
||||||
parentNode, beforeNode);
|
parentNode, beforeNode);
|
||||||
@ -323,10 +332,10 @@ export function destroyViewTree(rootView: LViewData): void {
|
|||||||
* @param index The index at which to insert the view
|
* @param index The index at which to insert the view
|
||||||
* @returns The inserted view
|
* @returns The inserted view
|
||||||
*/
|
*/
|
||||||
export function insertView(container: LContainerNode, viewNode: LViewNode, index: number) {
|
export function insertView(
|
||||||
|
container: LContainerNode, lView: LViewData, index: number, containerIndex: number) {
|
||||||
const state = container.data;
|
const state = container.data;
|
||||||
const views = state[VIEWS];
|
const views = state[VIEWS];
|
||||||
const lView = viewNode.data as LViewData;
|
|
||||||
|
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
// This is a new view, we need to add it to the children.
|
// This is a new view, we need to add it to the children.
|
||||||
@ -341,11 +350,11 @@ export function insertView(container: LContainerNode, viewNode: LViewNode, index
|
|||||||
lView[NEXT] = null;
|
lView[NEXT] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamically inserted views need a reference to their parent container'S host so it's
|
// Dynamically inserted views need a reference to their parent container's host so it's
|
||||||
// possible to jump from a view to its container's next when walking the node tree.
|
// possible to jump from a view to its container's next when walking the node tree.
|
||||||
if (viewNode.tNode.index === -1) {
|
if (containerIndex > -1) {
|
||||||
lView[CONTAINER_INDEX] = container.tNode.parent !.index;
|
lView[CONTAINER_INDEX] = containerIndex;
|
||||||
(viewNode as{view: LViewData}).view = container.view;
|
lView[PARENT] = container.view;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify query that a new view has been added
|
// Notify query that a new view has been added
|
||||||
@ -367,23 +376,22 @@ export function insertView(container: LContainerNode, viewNode: LViewNode, index
|
|||||||
* @param removeIndex The index of the view to detach
|
* @param removeIndex The index of the view to detach
|
||||||
* @returns The detached view
|
* @returns The detached view
|
||||||
*/
|
*/
|
||||||
export function detachView(container: LContainerNode, removeIndex: number) {
|
export function detachView(container: LContainerNode, removeIndex: number, detached: boolean) {
|
||||||
const views = container.data[VIEWS];
|
const views = container.data[VIEWS];
|
||||||
const viewToDetach = views[removeIndex];
|
const viewToDetach = views[removeIndex];
|
||||||
const viewNode = viewToDetach[HOST_NODE] as LViewNode;
|
|
||||||
if (removeIndex > 0) {
|
if (removeIndex > 0) {
|
||||||
views[removeIndex - 1][NEXT] = viewToDetach[NEXT] as LViewData;
|
views[removeIndex - 1][NEXT] = viewToDetach[NEXT] as LViewData;
|
||||||
}
|
}
|
||||||
views.splice(removeIndex, 1);
|
views.splice(removeIndex, 1);
|
||||||
if (!container.tNode.detached) {
|
if (!detached) {
|
||||||
addRemoveViewFromContainer(container, viewToDetach, false);
|
addRemoveViewFromContainer(viewToDetach, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (viewToDetach[QUERIES]) {
|
if (viewToDetach[QUERIES]) {
|
||||||
viewToDetach[QUERIES] !.removeView();
|
viewToDetach[QUERIES] !.removeView();
|
||||||
}
|
}
|
||||||
viewToDetach[CONTAINER_INDEX] = -1;
|
viewToDetach[CONTAINER_INDEX] = -1;
|
||||||
(viewNode as{view: LViewData | null}).view = null;
|
viewToDetach[PARENT] = null;
|
||||||
// Unsets the attached flag
|
// Unsets the attached flag
|
||||||
viewToDetach[FLAGS] &= ~LViewFlags.Attached;
|
viewToDetach[FLAGS] &= ~LViewFlags.Attached;
|
||||||
}
|
}
|
||||||
@ -395,10 +403,11 @@ export function detachView(container: LContainerNode, removeIndex: number) {
|
|||||||
* @param removeIndex The index of the view to remove
|
* @param removeIndex The index of the view to remove
|
||||||
* @returns The removed view
|
* @returns The removed view
|
||||||
*/
|
*/
|
||||||
export function removeView(container: LContainerNode, removeIndex: number) {
|
export function removeView(
|
||||||
const viewToRemove = container.data[VIEWS][removeIndex];
|
container: LContainerNode, tContainer: TContainerNode, removeIndex: number) {
|
||||||
destroyLView(viewToRemove);
|
const view = container.data[VIEWS][removeIndex];
|
||||||
detachView(container, removeIndex);
|
destroyLView(view);
|
||||||
|
detachView(container, removeIndex, !!tContainer.detached);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the child of the given LViewData */
|
/** Gets the child of the given LViewData */
|
||||||
@ -440,11 +449,12 @@ export function destroyLView(view: LViewData) {
|
|||||||
*/
|
*/
|
||||||
export function getParentState(state: LViewData | LContainer, rootView: LViewData): LViewData|
|
export function getParentState(state: LViewData | LContainer, rootView: LViewData): LViewData|
|
||||||
LContainer|null {
|
LContainer|null {
|
||||||
let node;
|
let tNode;
|
||||||
if ((node = (state as LViewData) ![HOST_NODE]) && node.tNode.type === TNodeType.View) {
|
if (state.length >= HEADER_OFFSET && (tNode = (state as LViewData) ![HOST_NODE]) &&
|
||||||
|
tNode.type === TNodeType.View) {
|
||||||
// if it's an embedded view, the state needs to go up to the container, in case the
|
// if it's an embedded view, the state needs to go up to the container, in case the
|
||||||
// container has a next
|
// container has a next
|
||||||
return getParentLNode(node) !.data as any;
|
return getContainerNode(tNode, state as LViewData) !.data as any;
|
||||||
} else {
|
} else {
|
||||||
// otherwise, use parent view for containers or component views
|
// otherwise, use parent view for containers or component views
|
||||||
return state[PARENT] === rootView ? null : state[PARENT];
|
return state[PARENT] === rootView ? null : state[PARENT];
|
||||||
@ -512,17 +522,24 @@ function executePipeOnDestroys(viewData: LViewData): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function canInsertNativeChildOfElement(parent: LElementNode, currentView: LViewData): boolean {
|
export function getRenderParent(tNode: TNode, currentView: LViewData): LElementNode|null {
|
||||||
if (parent.view !== currentView) {
|
if (canInsertNativeNode(tNode, currentView)) {
|
||||||
// If the Parent view is not the same as current view than we are inserting across
|
const hostTNode = currentView[HOST_NODE];
|
||||||
// Views. This happens when we insert a root element of the component view into
|
return tNode.parent == null && hostTNode !.type === TNodeType.View ?
|
||||||
// the component host element and it should always be eager.
|
getContainerRenderParent(hostTNode as TViewNode, currentView) :
|
||||||
return true;
|
getParentLNode(tNode, currentView) as LElementNode;
|
||||||
}
|
}
|
||||||
// Parent elements can be a component which may have projection.
|
return null;
|
||||||
if (parent.data === null) {
|
}
|
||||||
// Parent is a regular non-component element. We should eagerly insert into it
|
|
||||||
// since we know that this relationship will never be broken.
|
function canInsertNativeChildOfElement(tNode: TNode): boolean {
|
||||||
|
// If the parent is null, then we are inserting across views. This happens when we
|
||||||
|
// insert a root element of the component view into the component host element and it
|
||||||
|
// should always be eager.
|
||||||
|
if (tNode.parent == null ||
|
||||||
|
// We should also eagerly insert if the parent is a regular, non-component element
|
||||||
|
// since we know that this relationship will never be broken.
|
||||||
|
tNode.parent.type === TNodeType.Element && !(tNode.parent.flags & TNodeFlags.isComponent)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,26 +551,21 @@ function canInsertNativeChildOfElement(parent: LElementNode, currentView: LViewD
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* We might delay insertion of children for a given view if it is disconnected.
|
* We might delay insertion of children for a given view if it is disconnected.
|
||||||
* This might happen for 2 main reason:
|
* This might happen for 2 main reasons:
|
||||||
* - view is not inserted into any container (view was created but not iserted yet)
|
* - view is not inserted into any container (view was created but not inserted yet)
|
||||||
* - view is inserted into a container but the container itself is not inserted into the DOM
|
* - view is inserted into a container but the container itself is not inserted into the DOM
|
||||||
* (container might be part of projection or child of a view that is not inserted yet).
|
* (container might be part of projection or child of a view that is not inserted yet).
|
||||||
*
|
*
|
||||||
* In other words we can insert children of a given view this view was inserted into a container and
|
* In other words we can insert children of a given view if this view was inserted into a container
|
||||||
* the container itself has it render parent determined.
|
* and
|
||||||
|
* the container itself has its render parent determined.
|
||||||
*/
|
*/
|
||||||
function canInsertNativeChildOfView(parent: LViewNode): boolean {
|
function canInsertNativeChildOfView(viewTNode: TViewNode, view: LViewData): boolean {
|
||||||
ngDevMode && assertNodeType(parent.tNode, TNodeType.View);
|
|
||||||
|
|
||||||
// Because we are inserting into a `View` the `View` may be disconnected.
|
// Because we are inserting into a `View` the `View` may be disconnected.
|
||||||
const grandParentContainer = getParentLNode(parent) as LContainerNode;
|
const container = getContainerNode(viewTNode, view) !;
|
||||||
if (grandParentContainer == null) {
|
if (container == null || container.data[RENDER_PARENT] == null) {
|
||||||
// The `View` is not inserted into a `Container` we have to delay insertion.
|
// The `View` is not inserted into a `Container` or the parent `Container`
|
||||||
return false;
|
// itself is disconnected. So we have to delay.
|
||||||
}
|
|
||||||
ngDevMode && assertNodeType(grandParentContainer.tNode, TNodeType.Container);
|
|
||||||
if (grandParentContainer.data[RENDER_PARENT] == null) {
|
|
||||||
// The parent `Container` itself is disconnected. So we have to delay.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,31 +592,21 @@ function canInsertNativeChildOfView(parent: LViewNode): boolean {
|
|||||||
* @param currentView Current LView being processed.
|
* @param currentView Current LView being processed.
|
||||||
* @return boolean Whether the child should be inserted now (or delayed until later).
|
* @return boolean Whether the child should be inserted now (or delayed until later).
|
||||||
*/
|
*/
|
||||||
export function canInsertNativeNode(parent: LNode, currentView: LViewData): boolean {
|
export function canInsertNativeNode(tNode: TNode, currentView: LViewData): boolean {
|
||||||
// We can only insert into a Component or View. Any other type should be an Error.
|
let currentNode = tNode;
|
||||||
ngDevMode && assertNodeOfPossibleTypes(
|
let parent: TNode|null = tNode.parent;
|
||||||
parent.tNode, TNodeType.Element, TNodeType.ElementContainer, TNodeType.View);
|
|
||||||
|
|
||||||
if (parent.tNode.type === TNodeType.Element) {
|
if (tNode.parent && tNode.parent.type === TNodeType.ElementContainer) {
|
||||||
// Parent is a regular element or a component
|
currentNode = getHighestElementContainer(tNode);
|
||||||
return canInsertNativeChildOfElement(parent as LElementNode, currentView);
|
parent = currentNode.parent;
|
||||||
} else if (parent.tNode.type === TNodeType.ElementContainer) {
|
}
|
||||||
// Parent is an element container (ng-container).
|
if (parent === null) parent = currentView[HOST_NODE];
|
||||||
// Its grand-parent might be an element, view or a sequence of ng-container parents.
|
|
||||||
let grandParent = getParentLNode(parent);
|
if (parent && parent.type === TNodeType.View) {
|
||||||
while (grandParent !== null && grandParent.tNode.type === TNodeType.ElementContainer) {
|
return canInsertNativeChildOfView(parent as TViewNode, currentView);
|
||||||
grandParent = getParentLNode(grandParent);
|
|
||||||
}
|
|
||||||
if (grandParent === null) {
|
|
||||||
return false;
|
|
||||||
} else if (grandParent.tNode.type === TNodeType.Element) {
|
|
||||||
return canInsertNativeChildOfElement(grandParent as LElementNode, currentView);
|
|
||||||
} else {
|
|
||||||
return canInsertNativeChildOfView(grandParent as LViewNode);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Parent is a View.
|
// Parent is a regular element or a component
|
||||||
return canInsertNativeChildOfView(parent as LViewNode);
|
return canInsertNativeChildOfElement(currentNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -627,58 +629,79 @@ function nativeInsertBefore(
|
|||||||
*
|
*
|
||||||
* The element insertion might be delayed {@link canInsertNativeNode}.
|
* The element insertion might be delayed {@link canInsertNativeNode}.
|
||||||
*
|
*
|
||||||
* @param parent The parent to which to append the child
|
* @param childEl The child that should be appended
|
||||||
* @param child The child that should be appended
|
* @param childTNode The TNode of the child element
|
||||||
* @param currentView The current LView
|
* @param currentView The current LView
|
||||||
* @returns Whether or not the child was appended
|
* @returns Whether or not the child was appended
|
||||||
*/
|
*/
|
||||||
export function appendChild(parent: LNode, child: RNode | null, currentView: LViewData): boolean {
|
export function appendChild(
|
||||||
if (child !== null && canInsertNativeNode(parent, currentView)) {
|
childEl: RNode | null, childTNode: TNode, currentView: LViewData): boolean {
|
||||||
|
const parentLNode = getParentLNode(childTNode, currentView);
|
||||||
|
const parentEl = parentLNode ? parentLNode.native : null;
|
||||||
|
|
||||||
|
if (childEl !== null && canInsertNativeNode(childTNode, currentView)) {
|
||||||
const renderer = currentView[RENDERER];
|
const renderer = currentView[RENDERER];
|
||||||
if (parent.tNode.type === TNodeType.View) {
|
const parentTNode: TNode = childTNode.parent || currentView[HOST_NODE] !;
|
||||||
const container = getParentLNode(parent) as LContainerNode;
|
|
||||||
|
if (parentTNode.type === TNodeType.View) {
|
||||||
|
const container = getContainerNode(parentTNode, currentView) as LContainerNode;
|
||||||
const renderParent = container.data[RENDER_PARENT];
|
const renderParent = container.data[RENDER_PARENT];
|
||||||
const views = container.data[VIEWS];
|
const views = container.data[VIEWS];
|
||||||
const index = views.indexOf(currentView);
|
const index = views.indexOf(currentView);
|
||||||
const beforeNode = index + 1 < views.length ?
|
nativeInsertBefore(
|
||||||
(getChildLNode(views[index + 1][HOST_NODE]) !).native :
|
renderer, renderParent !.native, childEl, getBeforeNodeForView(index, views, container));
|
||||||
container.native;
|
} else if (parentTNode.type === TNodeType.ElementContainer) {
|
||||||
nativeInsertBefore(renderer, renderParent !.native, child, beforeNode);
|
let elementContainer = getHighestElementContainer(childTNode);
|
||||||
} else if (parent.tNode.type === TNodeType.ElementContainer) {
|
let node: LElementNode = getRenderParent(elementContainer, currentView) !;
|
||||||
const beforeNode = parent.native;
|
nativeInsertBefore(renderer, node.native, childEl, parentEl);
|
||||||
let grandParent = getParentLNode(parent as LElementContainerNode);
|
|
||||||
while (grandParent.tNode.type === TNodeType.ElementContainer) {
|
|
||||||
grandParent = getParentLNode(grandParent as LElementContainerNode);
|
|
||||||
}
|
|
||||||
if (grandParent.tNode.type === TNodeType.View) {
|
|
||||||
const renderParent = getRenderParent(grandParent as LViewNode);
|
|
||||||
nativeInsertBefore(renderer, renderParent !.native, child, beforeNode);
|
|
||||||
} else {
|
|
||||||
nativeInsertBefore(renderer, (grandParent as LElementNode).native, child, beforeNode);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
isProceduralRenderer(renderer) ? renderer.appendChild(parent.native !as RElement, child) :
|
isProceduralRenderer(renderer) ? renderer.appendChild(parentEl !as RElement, childEl) :
|
||||||
parent.native !.appendChild(child);
|
parentEl !.appendChild(childEl);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the top-level ng-container if ng-containers are nested.
|
||||||
|
*
|
||||||
|
* @param ngContainer The TNode of the starting ng-container
|
||||||
|
* @returns tNode The TNode of the highest level ng-container
|
||||||
|
*/
|
||||||
|
function getHighestElementContainer(ngContainer: TNode): TNode {
|
||||||
|
while (ngContainer.parent != null && ngContainer.parent.type === TNodeType.ElementContainer) {
|
||||||
|
ngContainer = ngContainer.parent;
|
||||||
|
}
|
||||||
|
return ngContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBeforeNodeForView(index: number, views: LViewData[], container: LContainerNode) {
|
||||||
|
if (index + 1 < views.length) {
|
||||||
|
const view = views[index + 1] as LViewData;
|
||||||
|
const viewTNode = view[HOST_NODE] as TViewNode;
|
||||||
|
return viewTNode.child ? readElementValue(view[viewTNode.child.index]).native :
|
||||||
|
container.native;
|
||||||
|
} else {
|
||||||
|
return container.native;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the `child` element of the `parent` from the DOM.
|
* Removes the `child` element of the `parent` from the DOM.
|
||||||
*
|
*
|
||||||
* @param parent The parent from which to remove the child
|
* @param parentEl The parent element from which to remove the child
|
||||||
* @param child The child that should be removed
|
* @param child The child that should be removed
|
||||||
* @param currentView The current LView
|
* @param currentView The current LView
|
||||||
* @returns Whether or not the child was removed
|
* @returns Whether or not the child was removed
|
||||||
*/
|
*/
|
||||||
export function removeChild(parent: LNode, child: RNode | null, currentView: LViewData): boolean {
|
export function removeChild(tNode: TNode, child: RNode | null, currentView: LViewData): boolean {
|
||||||
if (child !== null && canInsertNativeNode(parent, currentView)) {
|
const parentNative = getParentLNode(tNode, currentView) !.native as RElement;
|
||||||
|
if (child !== null && canInsertNativeNode(tNode, currentView)) {
|
||||||
// We only remove the element if not in View or not projected.
|
// We only remove the element if not in View or not projected.
|
||||||
const renderer = currentView[RENDERER];
|
const renderer = currentView[RENDERER];
|
||||||
isProceduralRenderer(renderer) ? renderer.removeChild(parent.native as RElement, child) :
|
isProceduralRenderer(renderer) ? renderer.removeChild(parentNative as RElement, child) :
|
||||||
parent.native !.removeChild(child);
|
parentNative !.removeChild(child);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -688,47 +711,49 @@ export function removeChild(parent: LNode, child: RNode | null, currentView: LVi
|
|||||||
* Appends a projected node to the DOM, or in the case of a projected container,
|
* Appends a projected node to the DOM, or in the case of a projected container,
|
||||||
* appends the nodes from all of the container's active views to the DOM.
|
* appends the nodes from all of the container's active views to the DOM.
|
||||||
*
|
*
|
||||||
* @param node The node to process
|
* @param projectedLNode The node to process
|
||||||
* @param currentParent The last parent element to be processed
|
* @param parentNode The last parent element to be processed
|
||||||
|
* @param tProjectionNode
|
||||||
* @param currentView Current LView
|
* @param currentView Current LView
|
||||||
|
* @param projectionView Projection view
|
||||||
*/
|
*/
|
||||||
export function appendProjectedNode(
|
export function appendProjectedNode(
|
||||||
node: LElementNode | LElementContainerNode | LTextNode | LContainerNode,
|
projectedLNode: LElementNode | LElementContainerNode | LTextNode | LContainerNode,
|
||||||
currentParent: LElementNode | LElementContainerNode | LViewNode, currentView: LViewData,
|
projectedTNode: TNode, tProjectionNode: TNode, currentView: LViewData,
|
||||||
renderParent: LElementNode, parentView: LViewData): void {
|
projectionView: LViewData): void {
|
||||||
appendChild(currentParent, node.native, currentView);
|
appendChild(projectedLNode.native, tProjectionNode, currentView);
|
||||||
|
|
||||||
// the projected contents are processed while in the shadow view (which is the currentView)
|
// the projected contents are processed while in the shadow view (which is the currentView)
|
||||||
// therefore we need to extract the view where the host element lives since it's the
|
// therefore we need to extract the view where the host element lives since it's the
|
||||||
// logical container of the content projected views
|
// logical container of the content projected views
|
||||||
attachPatchData(node.native, parentView);
|
attachPatchData(projectedLNode.native, projectionView);
|
||||||
|
|
||||||
if (node.tNode.type === TNodeType.Container) {
|
const renderParent = getRenderParent(tProjectionNode, currentView);
|
||||||
|
|
||||||
|
if (projectedTNode.type === TNodeType.Container) {
|
||||||
// The node we are adding is a container and we are adding it to an element which
|
// The node we are adding is a container and we are adding it to an element which
|
||||||
// is not a component (no more re-projection).
|
// is not a component (no more re-projection).
|
||||||
// Alternatively a container is projected at the root of a component's template
|
// Alternatively a container is projected at the root of a component's template
|
||||||
// and can't be re-projected (as not content of any component).
|
// and can't be re-projected (as not content of any component).
|
||||||
// Assign the final projection location in those cases.
|
// Assign the final projection location in those cases.
|
||||||
const lContainer = (node as LContainerNode).data;
|
const lContainer = (projectedLNode as LContainerNode).data;
|
||||||
lContainer[RENDER_PARENT] = renderParent;
|
lContainer[RENDER_PARENT] = renderParent;
|
||||||
const views = lContainer[VIEWS];
|
const views = lContainer[VIEWS];
|
||||||
for (let i = 0; i < views.length; i++) {
|
for (let i = 0; i < views.length; i++) {
|
||||||
addRemoveViewFromContainer(node as LContainerNode, views[i], true, node.native);
|
addRemoveViewFromContainer(views[i], true, projectedLNode.native);
|
||||||
}
|
}
|
||||||
} else if (node.tNode.type === TNodeType.ElementContainer) {
|
} else if (projectedTNode.type === TNodeType.ElementContainer) {
|
||||||
let ngContainerChild = getChildLNode(node as LElementContainerNode);
|
let ngContainerChildTNode: TNode|null = projectedTNode.child as TNode;
|
||||||
const parentView = currentView[PARENT] !;
|
while (ngContainerChildTNode) {
|
||||||
while (ngContainerChild) {
|
let ngContainerChild = readElementValue(projectionView[ngContainerChildTNode.index]);
|
||||||
appendProjectedNode(
|
appendProjectedNode(
|
||||||
ngContainerChild as LElementNode | LElementContainerNode | LTextNode | LContainerNode,
|
ngContainerChild as LElementNode | LElementContainerNode | LTextNode | LContainerNode,
|
||||||
currentParent, currentView, renderParent, parentView);
|
ngContainerChildTNode, tProjectionNode, currentView, projectionView);
|
||||||
ngContainerChild = ngContainerChild.tNode.next ?
|
ngContainerChildTNode = ngContainerChildTNode.next;
|
||||||
readElementValue(ngContainerChild.view[ngContainerChild.tNode.next.index]) :
|
|
||||||
null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node.dynamicLContainerNode) {
|
if (projectedLNode.dynamicLContainerNode) {
|
||||||
node.dynamicLContainerNode.data[RENDER_PARENT] = renderParent;
|
projectedLNode.dynamicLContainerNode.data[RENDER_PARENT] = renderParent;
|
||||||
appendChild(currentParent, node.dynamicLContainerNode.native, currentView);
|
appendChild(projectedLNode.dynamicLContainerNode.native, tProjectionNode, currentView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,13 +17,13 @@ import {getSymbolIterator} from '../util';
|
|||||||
|
|
||||||
import {assertDefined, assertEqual} from './assert';
|
import {assertDefined, assertEqual} from './assert';
|
||||||
import {ReadFromInjectorFn, getOrCreateNodeInjectorForNode} from './di';
|
import {ReadFromInjectorFn, getOrCreateNodeInjectorForNode} from './di';
|
||||||
import {assertPreviousIsParent, getOrCreateCurrentQueries, isContentQueryHost, store, storeCleanupWithContext} from './instructions';
|
import {_getViewData, assertPreviousIsParent, getOrCreateCurrentQueries, store, storeCleanupWithContext} from './instructions';
|
||||||
import {DirectiveDefInternal, unusedValueExportToPlacateAjd as unused1} from './interfaces/definition';
|
import {DirectiveDefInternal, unusedValueExportToPlacateAjd as unused1} from './interfaces/definition';
|
||||||
import {LInjector, unusedValueExportToPlacateAjd as unused2} from './interfaces/injector';
|
import {LInjector, unusedValueExportToPlacateAjd as unused2} from './interfaces/injector';
|
||||||
import {LContainerNode, LElementNode, LNode, TNode, TNodeFlags, unusedValueExportToPlacateAjd as unused3} from './interfaces/node';
|
import {LContainerNode, LElementNode, TNode, TNodeFlags, unusedValueExportToPlacateAjd as unused3} from './interfaces/node';
|
||||||
import {LQueries, QueryReadType, unusedValueExportToPlacateAjd as unused4} from './interfaces/query';
|
import {LQueries, QueryReadType, unusedValueExportToPlacateAjd as unused4} from './interfaces/query';
|
||||||
import {DIRECTIVES, TVIEW} from './interfaces/view';
|
import {DIRECTIVES, LViewData, TVIEW} from './interfaces/view';
|
||||||
import {flatten} from './util';
|
import {flatten, isContentQueryHost, readElementValue} from './util';
|
||||||
|
|
||||||
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4;
|
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4;
|
||||||
|
|
||||||
@ -121,21 +121,21 @@ export class LQueries_ implements LQueries {
|
|||||||
insertView(index, this.deep);
|
insertView(index, this.deep);
|
||||||
}
|
}
|
||||||
|
|
||||||
addNode(node: LNode): LQueries|null {
|
addNode(tNode: TNode): LQueries|null {
|
||||||
add(this.deep, node);
|
add(this.deep, tNode);
|
||||||
|
|
||||||
if (isContentQueryHost(node.tNode)) {
|
if (isContentQueryHost(tNode)) {
|
||||||
add(this.shallow, node);
|
add(this.shallow, tNode);
|
||||||
|
|
||||||
if (node.tNode.parent && isContentQueryHost(node.tNode.parent)) {
|
if (tNode.parent && isContentQueryHost(tNode.parent)) {
|
||||||
// if node has a content query and parent also has a content query
|
// if node has a content query and parent also has a content query
|
||||||
// both queries need to check this node for shallow matches
|
// both queries need to check this node for shallow matches
|
||||||
add(this.parent !.shallow, node);
|
add(this.parent !.shallow, tNode);
|
||||||
}
|
}
|
||||||
return this.parent;
|
return this.parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
isRootNodeOfQuery(node.tNode) && add(this.shallow, node);
|
isRootNodeOfQuery(tNode) && add(this.shallow, tNode);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,51 +241,61 @@ function getIdxOfMatchingSelector(tNode: TNode, selector: string): number|null {
|
|||||||
/**
|
/**
|
||||||
* Iterates over all the directives for a node and returns index of a directive for a given type.
|
* Iterates over all the directives for a node and returns index of a directive for a given type.
|
||||||
*
|
*
|
||||||
* @param node Node on which directives are present.
|
* @param tNode TNode on which directives are present.
|
||||||
|
* @param currentView The view we are currently processing
|
||||||
* @param type Type of a directive to look for.
|
* @param type Type of a directive to look for.
|
||||||
* @returns Index of a found directive or null when none found.
|
* @returns Index of a found directive or null when none found.
|
||||||
*/
|
*/
|
||||||
function getIdxOfMatchingDirective(node: LNode, type: Type<any>): number|null {
|
function getIdxOfMatchingDirective(tNode: TNode, currentView: LViewData, type: Type<any>): number|
|
||||||
const defs = node.view[TVIEW].directives !;
|
null {
|
||||||
const flags = node.tNode.flags;
|
const defs = currentView[TVIEW].directives;
|
||||||
const count = flags & TNodeFlags.DirectiveCountMask;
|
if (defs) {
|
||||||
const start = flags >> TNodeFlags.DirectiveStartingIndexShift;
|
const flags = tNode.flags;
|
||||||
const end = start + count;
|
const count = flags & TNodeFlags.DirectiveCountMask;
|
||||||
for (let i = start; i < end; i++) {
|
const start = flags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||||
const def = defs[i] as DirectiveDefInternal<any>;
|
const end = start + count;
|
||||||
if (def.type === type && def.diPublic) {
|
for (let i = start; i < end; i++) {
|
||||||
return i;
|
const def = defs[i] as DirectiveDefInternal<any>;
|
||||||
|
if (def.type === type && def.diPublic) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readFromNodeInjector(
|
function readFromNodeInjector(
|
||||||
nodeInjector: LInjector, node: LNode, read: QueryReadType<any>| Type<any>,
|
nodeInjector: LInjector, tNode: TNode, currentView: LViewData,
|
||||||
directiveIdx: number): any {
|
read: QueryReadType<any>| Type<any>, directiveIdx: number): any {
|
||||||
if (read instanceof ReadFromInjectorFn) {
|
if (read instanceof ReadFromInjectorFn) {
|
||||||
return read.read(nodeInjector, node, directiveIdx);
|
return read.read(nodeInjector, tNode, directiveIdx);
|
||||||
} else {
|
} else {
|
||||||
const matchingIdx = getIdxOfMatchingDirective(node, read as Type<any>);
|
const matchingIdx = getIdxOfMatchingDirective(tNode, currentView, read as Type<any>);
|
||||||
if (matchingIdx !== null) {
|
if (matchingIdx !== null) {
|
||||||
return node.view[DIRECTIVES] ![matchingIdx];
|
return currentView[DIRECTIVES] ![matchingIdx];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(query: LQuery<any>| null, node: LNode) {
|
function add(query: LQuery<any>| null, tNode: TNode) {
|
||||||
const nodeInjector = getOrCreateNodeInjectorForNode(node as LElementNode | LContainerNode);
|
const currentView = _getViewData();
|
||||||
|
|
||||||
|
// TODO: remove this lookup when nodeInjector is removed from LNode
|
||||||
|
const currentNode = readElementValue(currentView[tNode.index]);
|
||||||
|
const nodeInjector =
|
||||||
|
getOrCreateNodeInjectorForNode(currentNode as LElementNode | LContainerNode, tNode);
|
||||||
|
|
||||||
while (query) {
|
while (query) {
|
||||||
const predicate = query.predicate;
|
const predicate = query.predicate;
|
||||||
const type = predicate.type;
|
const type = predicate.type;
|
||||||
if (type) {
|
if (type) {
|
||||||
const directiveIdx = getIdxOfMatchingDirective(node, type);
|
const directiveIdx = getIdxOfMatchingDirective(tNode, currentView, type);
|
||||||
if (directiveIdx !== null) {
|
if (directiveIdx !== null) {
|
||||||
// a node is matching a predicate - determine what to read
|
// a node is matching a predicate - determine what to read
|
||||||
// if read token and / or strategy is not specified, use type as read token
|
// if read token and / or strategy is not specified, use type as read token
|
||||||
const result =
|
const result = readFromNodeInjector(
|
||||||
readFromNodeInjector(nodeInjector, node, predicate.read || type, directiveIdx);
|
nodeInjector, tNode, currentView, predicate.read || type, directiveIdx);
|
||||||
if (result !== null) {
|
if (result !== null) {
|
||||||
addMatch(query, result);
|
addMatch(query, result);
|
||||||
}
|
}
|
||||||
@ -293,12 +303,13 @@ function add(query: LQuery<any>| null, node: LNode) {
|
|||||||
} else {
|
} else {
|
||||||
const selector = predicate.selector !;
|
const selector = predicate.selector !;
|
||||||
for (let i = 0; i < selector.length; i++) {
|
for (let i = 0; i < selector.length; i++) {
|
||||||
const directiveIdx = getIdxOfMatchingSelector(node.tNode, selector[i]);
|
const directiveIdx = getIdxOfMatchingSelector(tNode, selector[i]);
|
||||||
if (directiveIdx !== null) {
|
if (directiveIdx !== null) {
|
||||||
// a node is matching a predicate - determine what to read
|
// a node is matching a predicate - determine what to read
|
||||||
// note that queries using name selector must specify read strategy
|
// note that queries using name selector must specify read strategy
|
||||||
ngDevMode && assertDefined(predicate.read, 'the node should have a predicate');
|
ngDevMode && assertDefined(predicate.read, 'the node should have a predicate');
|
||||||
const result = readFromNodeInjector(nodeInjector, node, predicate.read !, directiveIdx);
|
const result = readFromNodeInjector(
|
||||||
|
nodeInjector, tNode, currentView, predicate.read !, directiveIdx);
|
||||||
if (result !== null) {
|
if (result !== null) {
|
||||||
addMatch(query, result);
|
addMatch(query, result);
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,14 @@
|
|||||||
* Use of this source code is governed by an MIT-style license that can be
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {devModeEqual} from '../change_detection/change_detection_util';
|
import {devModeEqual} from '../change_detection/change_detection_util';
|
||||||
import {assertLessThan} from './assert';
|
import {assertLessThan} from './assert';
|
||||||
import {LElementNode} from './interfaces/node';
|
import {LElementNode, TNode, TNodeFlags} from './interfaces/node';
|
||||||
import {HEADER_OFFSET, LViewData, TData} from './interfaces/view';
|
import {HEADER_OFFSET, LViewData, TData} from './interfaces/view';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns wether the values are different from a change detection stand point.
|
* Returns whether the values are different from a change detection stand point.
|
||||||
*
|
*
|
||||||
* Constraints are relaxed in checkNoChanges mode. See `devModeEqual` for details.
|
* Constraints are relaxed in checkNoChanges mode. See `devModeEqual` for details.
|
||||||
*/
|
*/
|
||||||
@ -89,3 +90,11 @@ export function loadElementInternal(index: number, arr: LViewData): LElementNode
|
|||||||
export function readElementValue(value: LElementNode | any[]): LElementNode {
|
export function readElementValue(value: LElementNode | any[]): LElementNode {
|
||||||
return (Array.isArray(value) ? (value as any as any[])[0] : value) as LElementNode;
|
return (Array.isArray(value) ? (value as any as any[])[0] : value) as LElementNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isContentQueryHost(tNode: TNode): boolean {
|
||||||
|
return (tNode.flags & TNodeFlags.hasContentQuery) !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isComponent(tNode: TNode): boolean {
|
||||||
|
return (tNode.flags & TNodeFlags.isComponent) === TNodeFlags.isComponent;
|
||||||
|
}
|
||||||
|
@ -12,7 +12,7 @@ import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_co
|
|||||||
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEngine_InternalViewRef} from '../linker/view_ref';
|
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEngine_InternalViewRef} from '../linker/view_ref';
|
||||||
|
|
||||||
import {checkNoChanges, checkNoChangesInRootView, detectChanges, detectChangesInRootView, getRendererFactory, markViewDirty, storeCleanupFn, viewAttached} from './instructions';
|
import {checkNoChanges, checkNoChangesInRootView, detectChanges, detectChangesInRootView, getRendererFactory, markViewDirty, storeCleanupFn, viewAttached} from './instructions';
|
||||||
import {LViewNode} from './interfaces/node';
|
import {TViewNode} from './interfaces/node';
|
||||||
import {FLAGS, LViewData, LViewFlags} from './interfaces/view';
|
import {FLAGS, LViewData, LViewFlags} from './interfaces/view';
|
||||||
import {destroyLView} from './node_manipulation';
|
import {destroyLView} from './node_manipulation';
|
||||||
|
|
||||||
@ -30,13 +30,21 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
_lViewNode: LViewNode|null = null;
|
_view: LViewData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
_tViewNode: TViewNode|null = null;
|
||||||
|
|
||||||
context: T;
|
context: T;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
rootNodes !: any[];
|
rootNodes !: any[];
|
||||||
|
|
||||||
constructor(protected _view: LViewData, context: T|null) { this.context = context !; }
|
constructor(_view: LViewData, context: T|null) {
|
||||||
|
this.context = context !;
|
||||||
|
this._view = _view;
|
||||||
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_setComponentContext(view: LViewData, context: T) {
|
_setComponentContext(view: LViewData, context: T) {
|
||||||
@ -256,7 +264,7 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int
|
|||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export class RootViewRef<T> extends ViewRef<T> {
|
export class RootViewRef<T> extends ViewRef<T> {
|
||||||
constructor(protected _view: LViewData) { super(_view, null); }
|
constructor(public _view: LViewData) { super(_view, null); }
|
||||||
|
|
||||||
detectChanges(): void { detectChangesInRootView(this._view); }
|
detectChanges(): void { detectChangesInRootView(this._view); }
|
||||||
|
|
||||||
|
@ -134,15 +134,18 @@
|
|||||||
{
|
{
|
||||||
"name": "componentRefresh"
|
"name": "componentRefresh"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "createLNode"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "createLNodeObject"
|
"name": "createLNodeObject"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "createLViewData"
|
"name": "createLViewData"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "createNodeAtIndex"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "createRootComponent"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "createRootContext"
|
"name": "createRootContext"
|
||||||
},
|
},
|
||||||
@ -198,7 +201,7 @@
|
|||||||
"name": "firstTemplatePass"
|
"name": "firstTemplatePass"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getChildLNode"
|
"name": "getBeforeNodeForView"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getClosureSafeProperty"
|
"name": "getClosureSafeProperty"
|
||||||
@ -206,9 +209,21 @@
|
|||||||
{
|
{
|
||||||
"name": "getComponentDef"
|
"name": "getComponentDef"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getContainerNode"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getContainerRenderParent"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getDirectiveDef"
|
"name": "getDirectiveDef"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getHighestElementContainer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getHostElementNode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getLViewChild"
|
"name": "getLViewChild"
|
||||||
},
|
},
|
||||||
@ -224,12 +239,18 @@
|
|||||||
{
|
{
|
||||||
"name": "getParentLNode"
|
"name": "getParentLNode"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getParentOrContainerNode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getPipeDef"
|
"name": "getPipeDef"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getPreviousOrParentNode"
|
"name": "getPreviousOrParentNode"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getPreviousOrParentTNode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getRenderFlags"
|
"name": "getRenderFlags"
|
||||||
},
|
},
|
||||||
|
@ -314,6 +314,9 @@
|
|||||||
{
|
{
|
||||||
"name": "_devMode"
|
"name": "_devMode"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "_getViewData"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "_global"
|
"name": "_global"
|
||||||
},
|
},
|
||||||
@ -405,7 +408,7 @@
|
|||||||
"name": "createDirectivesAndLocals"
|
"name": "createDirectivesAndLocals"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "createEmbeddedViewNode"
|
"name": "createEmbeddedViewAndNode"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "createLContainer"
|
"name": "createLContainer"
|
||||||
@ -413,18 +416,21 @@
|
|||||||
{
|
{
|
||||||
"name": "createLContext"
|
"name": "createLContext"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "createLNode"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "createLNodeObject"
|
"name": "createLNodeObject"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "createLViewData"
|
"name": "createLViewData"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "createNodeAtIndex"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "createOutput$1"
|
"name": "createOutput$1"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "createRootComponent"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "createRootContext"
|
"name": "createRootContext"
|
||||||
},
|
},
|
||||||
@ -540,7 +546,7 @@
|
|||||||
"name": "findAttrIndexInNode"
|
"name": "findAttrIndexInNode"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "findComponentHost"
|
"name": "findComponentView"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "findDirectiveMatches"
|
"name": "findDirectiveMatches"
|
||||||
@ -558,20 +564,23 @@
|
|||||||
"name": "generatePropertyAliases"
|
"name": "generatePropertyAliases"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getChildLNode"
|
"name": "getBeforeNodeForView"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getCleanup"
|
"name": "getCleanup"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "getClosestComponentAncestor"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "getClosureSafeProperty"
|
"name": "getClosureSafeProperty"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getComponentDef"
|
"name": "getComponentDef"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getContainerNode"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getContainerRenderParent"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getCurrentSanitizer"
|
"name": "getCurrentSanitizer"
|
||||||
},
|
},
|
||||||
@ -581,6 +590,12 @@
|
|||||||
{
|
{
|
||||||
"name": "getDirectiveDef"
|
"name": "getDirectiveDef"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getHighestElementContainer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getHostElementNode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getInitialIndex"
|
"name": "getInitialIndex"
|
||||||
},
|
},
|
||||||
@ -635,6 +650,9 @@
|
|||||||
{
|
{
|
||||||
"name": "getParentLNode"
|
"name": "getParentLNode"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getParentOrContainerNode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getParentState"
|
"name": "getParentState"
|
||||||
},
|
},
|
||||||
@ -650,6 +668,9 @@
|
|||||||
{
|
{
|
||||||
"name": "getPreviousOrParentNode"
|
"name": "getPreviousOrParentNode"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getPreviousOrParentTNode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getProp"
|
"name": "getProp"
|
||||||
},
|
},
|
||||||
@ -674,6 +695,9 @@
|
|||||||
{
|
{
|
||||||
"name": "getSymbolIterator"
|
"name": "getSymbolIterator"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getTNode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getTViewCleanup"
|
"name": "getTViewCleanup"
|
||||||
},
|
},
|
||||||
|
@ -1091,6 +1091,9 @@
|
|||||||
{
|
{
|
||||||
"name": "_getComponentHostLElementNode"
|
"name": "_getComponentHostLElementNode"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "_getViewData"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "_global"
|
"name": "_global"
|
||||||
},
|
},
|
||||||
@ -1278,7 +1281,7 @@
|
|||||||
"name": "createDirectivesAndLocals"
|
"name": "createDirectivesAndLocals"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "createEmbeddedViewNode"
|
"name": "createEmbeddedViewAndNode"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "createInjector"
|
"name": "createInjector"
|
||||||
@ -1289,15 +1292,15 @@
|
|||||||
{
|
{
|
||||||
"name": "createLContext"
|
"name": "createLContext"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "createLNode"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "createLNodeObject"
|
"name": "createLNodeObject"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "createLViewData"
|
"name": "createLViewData"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "createNodeAtIndex"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "createOutput$1"
|
"name": "createOutput$1"
|
||||||
},
|
},
|
||||||
@ -1307,6 +1310,9 @@
|
|||||||
{
|
{
|
||||||
"name": "createPlatformFactory"
|
"name": "createPlatformFactory"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "createRootComponent"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "createRootContext"
|
"name": "createRootContext"
|
||||||
},
|
},
|
||||||
@ -1482,7 +1488,7 @@
|
|||||||
"name": "findAttrIndexInNode"
|
"name": "findAttrIndexInNode"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "findComponentHost"
|
"name": "findComponentView"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "findDirectiveMatches"
|
"name": "findDirectiveMatches"
|
||||||
@ -1557,20 +1563,23 @@
|
|||||||
"name": "getBaseElementHref"
|
"name": "getBaseElementHref"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getChildLNode"
|
"name": "getBeforeNodeForView"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getCleanup"
|
"name": "getCleanup"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "getClosestComponentAncestor"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "getClosureSafeProperty"
|
"name": "getClosureSafeProperty"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getComponentDef"
|
"name": "getComponentDef"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getContainerNode"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getContainerRenderParent"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getCurrencySymbol"
|
"name": "getCurrencySymbol"
|
||||||
},
|
},
|
||||||
@ -1607,6 +1616,12 @@
|
|||||||
{
|
{
|
||||||
"name": "getFirstThursdayOfYear"
|
"name": "getFirstThursdayOfYear"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getHighestElementContainer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getHostElementNode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getInitialIndex"
|
"name": "getInitialIndex"
|
||||||
},
|
},
|
||||||
@ -1727,6 +1742,9 @@
|
|||||||
{
|
{
|
||||||
"name": "getParentLNode"
|
"name": "getParentLNode"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getParentOrContainerNode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getParentState"
|
"name": "getParentState"
|
||||||
},
|
},
|
||||||
@ -1781,6 +1799,9 @@
|
|||||||
{
|
{
|
||||||
"name": "getSymbolIterator$1"
|
"name": "getSymbolIterator$1"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getTNode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getTViewCleanup"
|
"name": "getTViewCleanup"
|
||||||
},
|
},
|
||||||
|
@ -12,7 +12,7 @@ import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
|
|||||||
import {defineComponent} from '../../src/render3/definition';
|
import {defineComponent} from '../../src/render3/definition';
|
||||||
import {bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjector, injectAttribute} from '../../src/render3/di';
|
import {bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjector, injectAttribute} from '../../src/render3/di';
|
||||||
import {NgOnChangesFeature, PublicFeature, defineDirective, directiveInject, injectChangeDetectorRef, injectElementRef, injectRenderer2, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
|
import {NgOnChangesFeature, PublicFeature, defineDirective, directiveInject, injectChangeDetectorRef, injectElementRef, injectRenderer2, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
|
||||||
import {bind, container, containerRefreshEnd, containerRefreshStart, createLNode, createLViewData, createTView, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, projection, projectionDef, reference, template, text, textBinding, loadDirective, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions';
|
import {bind, container, containerRefreshEnd, containerRefreshStart, createNodeAtIndex, createLViewData, createTView, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, projection, projectionDef, reference, template, text, textBinding, loadDirective, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions';
|
||||||
import {LInjector} from '../../src/render3/interfaces/injector';
|
import {LInjector} from '../../src/render3/interfaces/injector';
|
||||||
import {isProceduralRenderer} from '../../src/render3/interfaces/renderer';
|
import {isProceduralRenderer} from '../../src/render3/interfaces/renderer';
|
||||||
import {AttributeMarker, TNodeType} from '../../src/render3/interfaces/node';
|
import {AttributeMarker, TNodeType} from '../../src/render3/interfaces/node';
|
||||||
@ -1503,12 +1503,11 @@ describe('di', () => {
|
|||||||
null !, createTView(-1, null, 1, 0, null, null, null), null, LViewFlags.CheckAlways);
|
null !, createTView(-1, null, 1, 0, null, null, null), null, LViewFlags.CheckAlways);
|
||||||
const oldView = enterView(contentView, null);
|
const oldView = enterView(contentView, null);
|
||||||
try {
|
try {
|
||||||
const parent = createLNode(0, TNodeType.Element, null, null, null, null);
|
const parentTNode = createNodeAtIndex(0, TNodeType.Element, null, null, null, null);
|
||||||
|
|
||||||
// Simulate the situation where the previous parent is not initialized.
|
// Simulate the situation where the previous parent is not initialized.
|
||||||
// This happens on first bootstrap because we don't init existing values
|
// This happens on first bootstrap because we don't init existing values
|
||||||
// so that we have smaller HelloWorld.
|
// so that we have smaller HelloWorld.
|
||||||
(parent.tNode as{parent: any}).parent = undefined;
|
(parentTNode as{parent: any}).parent = undefined;
|
||||||
|
|
||||||
const injector: any = getOrCreateNodeInjector(); // TODO: Review use of `any` here (#19904)
|
const injector: any = getOrCreateNodeInjector(); // TODO: Review use of `any` here (#19904)
|
||||||
expect(injector).not.toBe(null);
|
expect(injector).not.toBe(null);
|
||||||
|
@ -50,7 +50,7 @@ describe('instructions', () => {
|
|||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 1,
|
firstTemplatePass: 1,
|
||||||
tNode: 2, // 1 for hostElement + 1 for the template under test
|
tNode: 2, // 1 for hostElement + 1 for the template under test
|
||||||
tView: 1,
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
rendererCreateElement: 1,
|
rendererCreateElement: 1,
|
||||||
rendererSetProperty: 2
|
rendererSetProperty: 2
|
||||||
});
|
});
|
||||||
@ -68,7 +68,7 @@ describe('instructions', () => {
|
|||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 1,
|
firstTemplatePass: 1,
|
||||||
tNode: 2, // 1 for hostElement + 1 for the template under test
|
tNode: 2, // 1 for hostElement + 1 for the template under test
|
||||||
tView: 1,
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
rendererCreateElement: 1,
|
rendererCreateElement: 1,
|
||||||
rendererSetProperty: 1
|
rendererSetProperty: 1
|
||||||
});
|
});
|
||||||
@ -87,7 +87,7 @@ describe('instructions', () => {
|
|||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 1,
|
firstTemplatePass: 1,
|
||||||
tNode: 2, // 1 for div, 1 for host element
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
tView: 1,
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
rendererCreateElement: 1,
|
rendererCreateElement: 1,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -127,7 +127,7 @@ describe('instructions', () => {
|
|||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 1,
|
firstTemplatePass: 1,
|
||||||
tNode: 2, // 1 for div, 1 for host element
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
tView: 1,
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
rendererCreateElement: 1,
|
rendererCreateElement: 1,
|
||||||
rendererSetAttribute: 3
|
rendererSetAttribute: 3
|
||||||
});
|
});
|
||||||
@ -148,7 +148,7 @@ describe('instructions', () => {
|
|||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 1,
|
firstTemplatePass: 1,
|
||||||
tNode: 2, // 1 for div, 1 for host element
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
tView: 1,
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
rendererCreateElement: 1,
|
rendererCreateElement: 1,
|
||||||
rendererSetAttribute: 2
|
rendererSetAttribute: 2
|
||||||
});
|
});
|
||||||
@ -169,7 +169,7 @@ describe('instructions', () => {
|
|||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 1,
|
firstTemplatePass: 1,
|
||||||
tNode: 2, // 1 for div, 1 for host element
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
tView: 1,
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
rendererCreateElement: 1,
|
rendererCreateElement: 1,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -183,7 +183,7 @@ describe('instructions', () => {
|
|||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 1,
|
firstTemplatePass: 1,
|
||||||
tNode: 2, // 1 for div, 1 for host element
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
tView: 1,
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
rendererCreateElement: 1,
|
rendererCreateElement: 1,
|
||||||
rendererSetProperty: 1
|
rendererSetProperty: 1
|
||||||
});
|
});
|
||||||
|
@ -42,7 +42,7 @@ describe('render3 integration test', () => {
|
|||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 1,
|
firstTemplatePass: 1,
|
||||||
tNode: 3, // 1 for div, 1 for text, 1 for host element
|
tNode: 3, // 1 for div, 1 for text, 1 for host element
|
||||||
tView: 1,
|
tView: 2, // 1 for root view, 1 for template
|
||||||
rendererCreateElement: 1,
|
rendererCreateElement: 1,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -86,7 +86,7 @@ describe('render3 integration test', () => {
|
|||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 0,
|
firstTemplatePass: 0,
|
||||||
tNode: 2,
|
tNode: 2,
|
||||||
tView: 1,
|
tView: 2, // 1 for root view, 1 for template
|
||||||
rendererSetText: 2,
|
rendererSetText: 2,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -106,7 +106,7 @@ describe('render3 integration test', () => {
|
|||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 0,
|
firstTemplatePass: 0,
|
||||||
tNode: 2,
|
tNode: 2,
|
||||||
tView: 1,
|
tView: 2, // 1 for root view, 1 for template
|
||||||
rendererSetText: 2,
|
rendererSetText: 2,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -125,7 +125,7 @@ describe('render3 integration test', () => {
|
|||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 0,
|
firstTemplatePass: 0,
|
||||||
tNode: 2,
|
tNode: 2,
|
||||||
tView: 1,
|
tView: 2, // 1 for root view, 1 for template
|
||||||
rendererSetText: 1,
|
rendererSetText: 1,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user