refactor(ivy): remove LNode (#26426)

PR Close #26426
This commit is contained in:
Kara Erickson 2018-10-12 18:49:00 -07:00 committed by Miško Hevery
parent 9afc9a7464
commit e76a570908
27 changed files with 302 additions and 449 deletions

View File

@ -18,10 +18,10 @@ import {getComponentDef} from './definition';
import {queueInitHooks, queueLifecycleHooks} from './hooks'; import {queueInitHooks, queueLifecycleHooks} from './hooks';
import {CLEAN_PROMISE, baseDirectiveCreate, createLViewData, createNodeAtIndex, createTView, detectChangesInternal, enterView, executeInitAndContentHooks, getOrCreateTView, leaveView, locateHostElement, prefillHostVars, resetComponentState, setHostBindings} from './instructions'; import {CLEAN_PROMISE, baseDirectiveCreate, createLViewData, createNodeAtIndex, createTView, detectChangesInternal, enterView, executeInitAndContentHooks, getOrCreateTView, leaveView, locateHostElement, prefillHostVars, resetComponentState, setHostBindings} from './instructions';
import {ComponentDef, ComponentType} from './interfaces/definition'; import {ComponentDef, ComponentType} from './interfaces/definition';
import {TNodeFlags, TNodeType} from './interfaces/node'; import {TElementNode, TNodeFlags, TNodeType} from './interfaces/node';
import {PlayerHandler} from './interfaces/player'; import {PlayerHandler} from './interfaces/player';
import {RElement, RNode, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; import {RElement, RNode, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {CONTEXT, HEADER_OFFSET, HOST, INJECTOR, LViewData, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view'; import {CONTEXT, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LViewData, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view';
import {getRootView, readElementValue, readPatchedLViewData, stringify} from './util'; import {getRootView, readElementValue, readPatchedLViewData, stringify} from './util';
@ -166,7 +166,7 @@ export function createRootComponentView(
getOrCreateTView( getOrCreateTView(
def.template, def.consts, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery), def.template, def.consts, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery),
null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer); null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer);
const tNode = createNodeAtIndex(0, TNodeType.Element, rNode, null, null, componentView); const tNode = createNodeAtIndex(0, TNodeType.Element, rNode, null, null);
if (tView.firstTemplatePass) { if (tView.firstTemplatePass) {
tView.expandoInstructions = ROOT_EXPANDO_INSTRUCTIONS.slice(); tView.expandoInstructions = ROOT_EXPANDO_INSTRUCTIONS.slice();
@ -177,10 +177,10 @@ export function createRootComponentView(
// Store component view at node index, with node as the HOST // Store component view at node index, with node as the HOST
componentView[HOST] = rootView[HEADER_OFFSET]; componentView[HOST] = rootView[HEADER_OFFSET];
componentView[HOST_NODE] = tNode as TElementNode;
return rootView[HEADER_OFFSET] = componentView; return rootView[HEADER_OFFSET] = componentView;
} }
/** /**
* Creates a root component and sets it up with features and host bindings. Shared by * Creates a root component and sets it up with features and host bindings. Shared by
* renderComponent() and ViewContainerRef.createComponent(). * renderComponent() and ViewContainerRef.createComponent().
@ -255,7 +255,7 @@ function getRootContext(component: any): RootContext {
* @param component Component for which the host element should be retrieved. * @param component Component for which the host element should be retrieved.
*/ */
export function getHostElement<T>(component: T): HTMLElement { export function getHostElement<T>(component: T): HTMLElement {
return readElementValue(getComponentViewByInstance(component)).native as HTMLElement; return readElementValue(getComponentViewByInstance(component)) as HTMLElement;
} }
/** /**

View File

@ -19,7 +19,7 @@ import {Type} from '../type';
import {assertComponentType, assertDefined} from './assert'; import {assertComponentType, assertDefined} from './assert';
import {LifecycleHooksFeature, createRootComponent, createRootComponentView, createRootContext} from './component'; import {LifecycleHooksFeature, createRootComponent, createRootComponentView, createRootContext} from './component';
import {getComponentDef} from './definition'; import {getComponentDef} from './definition';
import {adjustBlueprintForNewNode, createLViewData, createNodeAtIndex, createTView, elementCreate, enterView, locateHostElement, renderEmbeddedTemplate} from './instructions'; import {adjustBlueprintForNewNode, createLViewData, createNodeAtIndex, createTView, createViewNode, elementCreate, enterView, locateHostElement, renderEmbeddedTemplate} from './instructions';
import {ComponentDef, RenderFlags} from './interfaces/definition'; import {ComponentDef, RenderFlags} from './interfaces/definition';
import {TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node'; import {TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node';
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
@ -141,7 +141,7 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
createRootComponentView(hostRNode, this.componentDef, rootView, renderer); createRootComponentView(hostRNode, this.componentDef, rootView, renderer);
tElementNode = getTNode(0, rootView) as TElementNode; tElementNode = getTNode(0, rootView) 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 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;
@ -223,7 +223,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._tViewNode = createNodeAtIndex(-1, TNodeType.View, null, null, null, rootView); this.hostView._tViewNode = createViewNode(-1, rootView);
this.injector = injector; this.injector = injector;
this.componentType = componentType; this.componentType = componentType;
} }

View File

@ -9,10 +9,10 @@ import './ng_dev_mode';
import {assertEqual} from './assert'; import {assertEqual} from './assert';
import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context'; import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context';
import {LElementNode, TNode, TNodeFlags} from './interfaces/node'; import {TNode, TNodeFlags} from './interfaces/node';
import {RElement} from './interfaces/renderer'; import {RElement} from './interfaces/renderer';
import {CONTEXT, HEADER_OFFSET, HOST, LViewData, TVIEW} from './interfaces/view'; import {CONTEXT, HEADER_OFFSET, HOST, LViewData, TVIEW} from './interfaces/view';
import {getComponentViewByIndex, readElementValue, readPatchedData} from './util'; import {getComponentViewByIndex, getNativeByTNode, readElementValue, readPatchedData} from './util';
/** Returns the matching `LContext` data for a given DOM node, directive or component instance. /** Returns the matching `LContext` data for a given DOM node, directive or component instance.
@ -66,11 +66,11 @@ export function getContext(target: any): LContext|null {
// are expensive. Instead, only the target data (the element, compontent or // are expensive. Instead, only the target data (the element, compontent or
// directive details) are filled into the context. If called multiple times // directive details) are filled into the context. If called multiple times
// with different target values then the missing target data will be filled in. // with different target values then the missing target data will be filled in.
const lNode = getLNodeFromViewData(lViewData, nodeIndex) !; const native = readElementValue(lViewData[nodeIndex]);
const existingCtx = readPatchedData(lNode.native); const existingCtx = readPatchedData(native);
const context: LContext = (existingCtx && !Array.isArray(existingCtx)) ? const context: LContext = (existingCtx && !Array.isArray(existingCtx)) ?
existingCtx : existingCtx :
createLContext(lViewData, nodeIndex, lNode.native); createLContext(lViewData, nodeIndex, native);
// only when the component has been discovered then update the monkey-patch // only when the component has been discovered then update the monkey-patch
if (component && context.component === undefined) { if (component && context.component === undefined) {
@ -114,9 +114,9 @@ export function getContext(target: any): LContext|null {
const index = findViaNativeElement(lViewData, rElement); const index = findViaNativeElement(lViewData, rElement);
if (index >= 0) { if (index >= 0) {
const lNode = getLNodeFromViewData(lViewData, index) !; const native = readElementValue(lViewData[index]);
const context = createLContext(lViewData, index, lNode.native); const context = createLContext(lViewData, index, native);
attachPatchData(lNode.native, context); attachPatchData(native, context);
mpValue = context; mpValue = context;
break; break;
} }
@ -129,10 +129,10 @@ export function getContext(target: any): LContext|null {
/** /**
* Creates an empty instance of a `LContext` context * Creates an empty instance of a `LContext` context
*/ */
function createLContext(lViewData: LViewData, lNodeIndex: number, native: RElement): LContext { function createLContext(lViewData: LViewData, nodeIndex: number, native: RElement): LContext {
return { return {
lViewData, lViewData,
nodeIndex: lNodeIndex, native, nodeIndex: nodeIndex, native,
component: undefined, component: undefined,
directives: undefined, directives: undefined,
localRefs: undefined, localRefs: undefined,
@ -150,9 +150,9 @@ export function getComponentViewByInstance(componentInstance: {}): LViewData {
let view: LViewData; let view: LViewData;
if (Array.isArray(lViewData)) { if (Array.isArray(lViewData)) {
const lNodeIndex = findViaComponent(lViewData, componentInstance); const nodeIndex = findViaComponent(lViewData, componentInstance);
view = getComponentViewByIndex(lNodeIndex, lViewData); view = getComponentViewByIndex(nodeIndex, lViewData);
const context = createLContext(lViewData, lNodeIndex, (view[HOST] as LElementNode).native); const context = createLContext(lViewData, nodeIndex, view[HOST] as RElement);
context.component = componentInstance; context.component = componentInstance;
attachPatchData(componentInstance, context); attachPatchData(componentInstance, context);
attachPatchData(context.native, context); attachPatchData(context.native, context);
@ -182,11 +182,11 @@ export function isDirectiveInstance(instance: any): boolean {
/** /**
* Locates the element within the given LViewData and returns the matching index * Locates the element within the given LViewData and returns the matching index
*/ */
function findViaNativeElement(lViewData: LViewData, native: RElement): number { function findViaNativeElement(lViewData: LViewData, target: RElement): number {
let tNode = lViewData[TVIEW].firstChild; let tNode = lViewData[TVIEW].firstChild;
while (tNode) { while (tNode) {
const lNode = getLNodeFromViewData(lViewData, tNode.index) !; const native = getNativeByTNode(tNode, lViewData) !;
if (lNode.native === native) { if (native === target) {
return tNode.index; return tNode.index;
} }
tNode = traverseNextElement(tNode); tNode = traverseNextElement(tNode);
@ -261,18 +261,6 @@ function assertDomElement(element: any) {
assertEqual(element.nodeType, 1, 'The provided value must be an instance of an HTMLElement'); assertEqual(element.nodeType, 1, 'The provided value must be an instance of an HTMLElement');
} }
/**
* Retruns the instance of the LElementNode at the given index in the LViewData.
*
* This function will also unwrap the inner value incase it's stuffed into an
* array (which is what happens when [style] and [class] bindings are present
* in the view instructions for the element being returned).
*/
function getLNodeFromViewData(lViewData: LViewData, lElementIndex: number): LElementNode|null {
const value = lViewData[lElementIndex];
return value ? readElementValue(value) : null;
}
/** /**
* Returns a list of directives extracted from the given view based on the * Returns a list of directives extracted from the given view based on the
* provided list of directive index values. * provided list of directive index values.
@ -294,17 +282,16 @@ export function discoverDirectives(
* Returns a map of local references (local reference name => element or directive instance) that * Returns a map of local references (local reference name => element or directive instance) that
* exist on a given element. * exist on a given element.
*/ */
export function discoverLocalRefs(lViewData: LViewData, lNodeIndex: number): {[key: string]: any}| export function discoverLocalRefs(lViewData: LViewData, nodeIndex: number): {[key: string]: any}|
null { null {
const tNode = lViewData[TVIEW].data[lNodeIndex] as TNode; const tNode = lViewData[TVIEW].data[nodeIndex] as TNode;
if (tNode && tNode.localNames) { if (tNode && tNode.localNames) {
const result: {[key: string]: any} = {}; const result: {[key: string]: any} = {};
for (let i = 0; i < tNode.localNames.length; i += 2) { for (let i = 0; i < tNode.localNames.length; i += 2) {
const localRefName = tNode.localNames[i]; const localRefName = tNode.localNames[i];
const directiveIndex = tNode.localNames[i + 1] as number; const directiveIndex = tNode.localNames[i + 1] as number;
result[localRefName] = directiveIndex === -1 ? result[localRefName] =
getLNodeFromViewData(lViewData, lNodeIndex) !.native : directiveIndex === -1 ? getNativeByTNode(tNode, lViewData) ! : lViewData[directiveIndex];
lViewData[directiveIndex];
} }
return result; return result;
} }

View File

@ -11,18 +11,17 @@
import {getInjectableDef, getInjectorDef} from '../di/defs'; import {getInjectableDef, getInjectorDef} from '../di/defs';
import {InjectionToken} from '../di/injection_token'; import {InjectionToken} from '../di/injection_token';
import {InjectFlags, Injector, NullInjector, inject, setCurrentInjector} from '../di/injector'; import {InjectFlags, Injector, inject, setCurrentInjector} from '../di/injector';
import {Renderer2} from '../render';
import {Type} from '../type'; import {Type} from '../type';
import {assertDefined} from './assert'; import {assertDefined} from './assert';
import {getComponentDef, getDirectiveDef, getPipeDef} from './definition'; import {getComponentDef, getDirectiveDef, getPipeDef} from './definition';
import {NG_ELEMENT_ID} from './fields'; import {NG_ELEMENT_ID} from './fields';
import {_getViewData, assertPreviousIsParent, getPreviousOrParentTNode, resolveDirective, setEnvironment} from './instructions'; import {_getViewData, getPreviousOrParentTNode, resolveDirective, setEnvironment} from './instructions';
import {DirectiveDef} from './interfaces/definition'; import {DirectiveDef} from './interfaces/definition';
import {InjectorLocationFlags, PARENT_INJECTOR, TNODE,} from './interfaces/injector'; import {InjectorLocationFlags, PARENT_INJECTOR, TNODE,} from './interfaces/injector';
import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node'; import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node';
import {DECLARATION_VIEW, HOST_NODE, INJECTOR, LViewData, PARENT, RENDERER, TData, TVIEW, TView} from './interfaces/view'; import {DECLARATION_VIEW, HOST_NODE, INJECTOR, LViewData, TData, TVIEW, TView} from './interfaces/view';
import {assertNodeOfPossibleTypes} from './node_assert'; import {assertNodeOfPossibleTypes} from './node_assert';
/** /**

View File

@ -7,13 +7,14 @@
*/ */
import {assertEqual, assertLessThan} from './assert'; import {assertEqual, assertLessThan} from './assert';
import {NO_CHANGE, _getViewData, adjustBlueprintForNewNode, bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, createNodeAtIndex, getRenderer, load, loadElement, resetComponentState} from './instructions'; import {NO_CHANGE, _getViewData, adjustBlueprintForNewNode, bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, createNodeAtIndex, getRenderer, load, resetComponentState} from './instructions';
import {LContainer, NATIVE, RENDER_PARENT} from './interfaces/container'; import {LContainer, NATIVE, RENDER_PARENT} from './interfaces/container';
import {LContainerNode, LNode, TElementNode, TNode, TNodeType} from './interfaces/node'; import {TElementNode, TNode, TNodeType} from './interfaces/node';
import {RComment, RElement} from './interfaces/renderer';
import {StylingContext} from './interfaces/styling'; import {StylingContext} from './interfaces/styling';
import {BINDING_INDEX, HEADER_OFFSET, HOST_NODE, TVIEW} from './interfaces/view'; import {BINDING_INDEX, HEADER_OFFSET, HOST_NODE, TVIEW} from './interfaces/view';
import {appendChild, createTextNode, removeChild} from './node_manipulation'; import {appendChild, createTextNode, removeChild} from './node_manipulation';
import {getNative, getTNode, isLContainer, stringify} from './util'; import {getNativeByIndex, getNativeByTNode, getTNode, isLContainer, stringify} from './util';
@ -273,7 +274,7 @@ function appendI18nNode(tNode: TNode, parentTNode: TNode, previousTNode: TNode):
} }
} }
appendChild(getNative(tNode, viewData), tNode, viewData); appendChild(getNativeByTNode(tNode, viewData), tNode, viewData);
const slotValue = viewData[tNode.index]; const slotValue = viewData[tNode.index];
if (tNode.type !== TNodeType.Container && isLContainer(slotValue)) { if (tNode.type !== TNodeType.Container && isLContainer(slotValue)) {
@ -364,11 +365,11 @@ export function i18nApply(startIndex: number, instructions: I18nInstruction[]):
ngDevMode.rendererRemoveNode++; ngDevMode.rendererRemoveNode++;
} }
const removeIndex = instruction & I18nInstructions.IndexMask; const removeIndex = instruction & I18nInstructions.IndexMask;
const removedNode: LNode|LContainerNode = loadElement(removeIndex); const removedElement: RElement|RComment = getNativeByIndex(removeIndex, viewData);
const removedTNode = getTNode(removeIndex, viewData); const removedTNode = getTNode(removeIndex, viewData);
removeChild(removedTNode, removedNode.native || null, viewData); removeChild(removedTNode, removedElement || null, viewData);
const slotValue = load(removeIndex) as LNode | LContainer | StylingContext; const slotValue = load(removeIndex) as RElement | RComment | LContainer | StylingContext;
if (isLContainer(slotValue)) { if (isLContainer(slotValue)) {
const lContainer = slotValue as LContainer; const lContainer = slotValue as LContainer;
if (removedTNode.type !== TNodeType.Container) { if (removedTNode.type !== TNodeType.Container) {

View File

@ -19,7 +19,7 @@ import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} fro
import {ACTIVE_INDEX, LContainer, VIEWS} from './interfaces/container'; import {ACTIVE_INDEX, LContainer, VIEWS} from './interfaces/container';
import {ComponentDef, ComponentQuery, ComponentTemplate, DirectiveDef, DirectiveDefListOrFactory, InitialStylingFlags, PipeDefListOrFactory, RenderFlags} from './interfaces/definition'; import {ComponentDef, ComponentQuery, ComponentTemplate, DirectiveDef, DirectiveDefListOrFactory, InitialStylingFlags, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
import {INJECTOR_SIZE} from './interfaces/injector'; import {INJECTOR_SIZE} from './interfaces/injector';
import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LElementContainerNode, LElementNode, LTextNode, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TProjectionNode, TViewNode} from './interfaces/node'; import {AttributeMarker, InitialInputData, InitialInputs, 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, isProceduralRenderer} from './interfaces/renderer'; import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, isProceduralRenderer} from './interfaces/renderer';
@ -29,7 +29,7 @@ import {appendChild, appendProjectedNode, createTextNode, findComponentView, get
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher'; import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
import {createStylingContextTemplate, renderStyling as renderElementStyles, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling/class_and_style_bindings'; import {createStylingContextTemplate, renderStyling as renderElementStyles, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling/class_and_style_bindings';
import {getStylingContext} from './styling/util'; import {getStylingContext} from './styling/util';
import {assertDataInRangeInternal, getComponentViewByIndex, getNative, getRootView, getTNode, isComponent, isContentQueryHost, isDifferent, loadElementInternal, loadInternal, readPatchedLViewData, stringify} from './util'; import {assertDataInRangeInternal, getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getRootView, getTNode, isComponent, isContentQueryHost, isDifferent, loadInternal, readPatchedLViewData, stringify} from './util';
@ -415,96 +415,53 @@ export function createLViewData<T>(
} }
/** /**
* A common way of creating the LNode to make sure that all of them have same shape to * Create and stores the TNode, and hooks it up to the tree.
* keep the execution code monomorphic and fast.
* *
* @param index The index at which the LNode should be saved (null if view, since they are not * @param index The index at which the TNode should be saved (null if view, since they are not
* saved). * saved).
* @param type The type of LNode to create * @param type The type of TNode to create
* @param native The native element for this LNode, if applicable * @param native The native element for this node, if applicable
* @param name The tag name of the associated native element, if applicable * @param name The tag name of the associated native element, if applicable
* @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
*/ */
export function createNodeAtIndex( 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): TElementNode; attrs: TAttributes | null): TElementNode;
export function createNodeAtIndex(
index: number, type: TNodeType.View, native: null, name: null, attrs: null,
lViewData: LViewData): TViewNode;
export function createNodeAtIndex( 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, data: null): TContainerNode; attrs: TAttributes | null): TContainerNode;
export function createNodeAtIndex( export function createNodeAtIndex(
index: number, type: TNodeType.Projection, native: null, name: null, attrs: TAttributes | null, index: number, type: TNodeType.Projection, native: null, name: null,
data: null): TProjectionNode; attrs: TAttributes | null): TProjectionNode;
export function createNodeAtIndex( 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): TElementContainerNode; attrs: TAttributes | null): TElementContainerNode;
export function createNodeAtIndex( 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): TElementNode&TViewNode&TContainerNode& attrs: TAttributes | null): TElementNode&TContainerNode&TElementContainerNode&TProjectionNode {
TElementContainerNode&TProjectionNode { const adjustedIndex = index + HEADER_OFFSET;
const parent = ngDevMode &&
isParent ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent; assertLessThan(adjustedIndex, viewData.length, `Slot should have been initialized with null`);
viewData[adjustedIndex] = native;
// Parents cannot cross component boundaries because components will be used in multiple places, let tNode = tView.data[adjustedIndex] as TNode;
// so it's only set if the view is the same. if (tNode == null) {
const parentInSameView = parent && viewData && parent !== viewData[HOST_NODE]; tNode = tView.data[adjustedIndex] = createTNode(type, adjustedIndex, name, attrs, null);
const tParent = parentInSameView ? parent as TElementNode | TContainerNode : null;
const isState = state != null;
const node = {native: native as any};
let tNode: TNode;
if (index === -1 || type === TNodeType.View) {
// 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.
tNode = (state ? (state as LViewData)[TVIEW].node : null) ||
createTNode(type, index, null, null, tParent, null);
} else {
const adjustedIndex = index + HEADER_OFFSET;
// This is an element or container or projection node
const tData = tView.data;
ngDevMode && assertLessThan(
adjustedIndex, viewData.length, `Slot should have been initialized with null`);
viewData[adjustedIndex] = node;
if (tData[adjustedIndex] == null) {
const tNode = tData[adjustedIndex] =
createTNode(type, adjustedIndex, name, attrs, tParent, null);
if (!isParent && previousOrParentTNode) {
previousOrParentTNode.next = tNode;
}
}
tNode = tData[adjustedIndex] as TNode;
if (!tView.firstChild && type === TNodeType.Element) {
tView.firstChild = tNode;
}
// Now link ourselves into the tree. // Now link ourselves into the tree.
if (isParent && previousOrParentTNode) { if (previousOrParentTNode) {
if (previousOrParentTNode.child == null && parentInSameView || if (isParent && previousOrParentTNode.child == null &&
previousOrParentTNode.type === TNodeType.View) { (tNode.parent !== null || 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 = tNode; previousOrParentTNode.child = tNode;
} else if (!isParent) {
previousOrParentTNode.next = tNode;
} }
} }
} }
// View nodes and host elements need to set their host node (components do not save host TNodes) if (tView.firstChild == null && type === TNodeType.Element) {
if ((type & TNodeType.ViewOrElement) === TNodeType.ViewOrElement && isState) { tView.firstChild = tNode;
const lViewData = state as LViewData;
ngDevMode &&
assertEqual(
lViewData[HOST_NODE], null, 'lViewData[HOST_NODE] should not have been initialized');
lViewData[HOST_NODE] = tNode as TElementNode | TViewNode;
if (lViewData[TVIEW].firstTemplatePass) {
lViewData[TVIEW].node = tNode as TViewNode | TElementNode;
}
} }
previousOrParentTNode = tNode; previousOrParentTNode = tNode;
@ -513,8 +470,20 @@ export function createNodeAtIndex(
TProjectionNode; TProjectionNode;
} }
export function createViewNode(index: number, view: LViewData) {
// 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.
if (view[TVIEW].node == null) {
view[TVIEW].node = createTNode(TNodeType.View, index, null, null, null) as TViewNode;
}
isParent = true;
return previousOrParentTNode = view[HOST_NODE] = view[TVIEW].node as TViewNode;
}
/** /**
* When LNodes are created dynamically after a view blueprint is created (e.g. through * When elements are created dynamically after a view blueprint is created (e.g. through
* i18nApply() or ComponentFactory.create), we need to adjust the blueprint for future * i18nApply() or ComponentFactory.create), we need to adjust the blueprint for future
* template passes. * template passes.
*/ */
@ -571,7 +540,7 @@ export function renderTemplate<T>(
getOrCreateTView(templateFn, consts, vars, directives || null, pipes || null, null); getOrCreateTView(templateFn, consts, vars, directives || null, pipes || null, null);
hostView = hostView =
createLViewData(renderer, componentTView, context, LViewFlags.CheckAlways, sanitizer); createLViewData(renderer, componentTView, context, LViewFlags.CheckAlways, sanitizer);
createNodeAtIndex(0, TNodeType.Element, hostNode, null, null, hostView); hostView[HOST_NODE] = createNodeAtIndex(0, TNodeType.Element, hostNode, null, null);
} }
renderComponentOrTemplate(hostView, context, templateFn); renderComponentOrTemplate(hostView, context, templateFn);
@ -598,7 +567,7 @@ export function createEmbeddedViewAndNode<T>(
if (queries) { if (queries) {
lView[QUERIES] = queries.createView(); lView[QUERIES] = queries.createView();
} }
createNodeAtIndex(-1, TNodeType.View, null, null, null, lView); createViewNode(-1, lView);
if (tView.firstTemplatePass) { if (tView.firstTemplatePass) {
tView.node !.injectorIndex = injectorIndex; tView.node !.injectorIndex = injectorIndex;
@ -769,8 +738,7 @@ 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 = const tNode = createNodeAtIndex(index, TNodeType.ElementContainer, native, null, attrs || null);
createNodeAtIndex(index, TNodeType.ElementContainer, native, null, attrs || null, null);
appendChild(native, tNode, viewData); appendChild(native, tNode, viewData);
createDirectivesAndLocals(localRefs); createDirectivesAndLocals(localRefs);
@ -816,11 +784,12 @@ export function elementStart(
ngDevMode && assertDataInRange(index - 1); ngDevMode && assertDataInRange(index - 1);
const tNode = createNodeAtIndex(index, TNodeType.Element, native !, name, attrs || null, null); const tNode = createNodeAtIndex(index, TNodeType.Element, native !, name, attrs || null);
if (attrs) { if (attrs) {
setUpAttributes(native, attrs); setUpAttributes(native, attrs);
} }
appendChild(native, tNode, viewData); appendChild(native, tNode, viewData);
createDirectivesAndLocals(localRefs); createDirectivesAndLocals(localRefs);
@ -858,12 +827,12 @@ export function elementCreate(name: string, overriddenRenderer?: Renderer3): REl
/** /**
* Creates directive instances and populates local refs. * Creates directive instances and populates local refs.
* *
* @param lNode LNode for which directive and locals should be created
* @param localRefs Local refs of the node in question * @param localRefs Local refs of the node in question
* @param localRefExtractor mapping function that extracts local ref value from LNode * @param localRefExtractor mapping function that extracts local ref value from TNode
*/ */
function createDirectivesAndLocals( function createDirectivesAndLocals(
localRefs: string[] | null | undefined, localRefExtractor: LocalRefExtractor = getNative) { localRefs: string[] | null | undefined,
localRefExtractor: LocalRefExtractor = getNativeByTNode) {
if (!bindingsEnabled) return; if (!bindingsEnabled) return;
if (firstTemplatePass) { if (firstTemplatePass) {
ngDevMode && ngDevMode.firstTemplatePass++; ngDevMode && ngDevMode.firstTemplatePass++;
@ -1226,7 +1195,7 @@ export function listener(
// add native event listener - applicable to elements only // add native event listener - applicable to elements only
if (tNode.type === TNodeType.Element) { if (tNode.type === TNodeType.Element) {
const native = getNative(previousOrParentTNode, viewData) as RElement; const native = getNativeByTNode(previousOrParentTNode, viewData) as RElement;
ngDevMode && ngDevMode.rendererAddEventListener++; ngDevMode && ngDevMode.rendererAddEventListener++;
// In order to match current behavior, native DOM event listeners must be added for all // In order to match current behavior, native DOM event listeners must be added for all
@ -1333,16 +1302,16 @@ export function elementEnd(): void {
export function elementAttribute( export function elementAttribute(
index: number, name: string, value: any, sanitizer?: SanitizerFn): void { index: number, name: string, value: any, sanitizer?: SanitizerFn): void {
if (value !== NO_CHANGE) { if (value !== NO_CHANGE) {
const element = loadElement(index); const element = getNativeByIndex(index, viewData);
if (value == null) { if (value == null) {
ngDevMode && ngDevMode.rendererRemoveAttribute++; ngDevMode && ngDevMode.rendererRemoveAttribute++;
isProceduralRenderer(renderer) ? renderer.removeAttribute(element.native, name) : isProceduralRenderer(renderer) ? renderer.removeAttribute(element, name) :
element.native.removeAttribute(name); element.removeAttribute(name);
} else { } else {
ngDevMode && ngDevMode.rendererSetAttribute++; ngDevMode && ngDevMode.rendererSetAttribute++;
const strValue = sanitizer == null ? stringify(value) : sanitizer(value); const strValue = sanitizer == null ? stringify(value) : sanitizer(value);
isProceduralRenderer(renderer) ? renderer.setAttribute(element.native, name, strValue) : isProceduralRenderer(renderer) ? renderer.setAttribute(element, name, strValue) :
element.native.setAttribute(name, strValue); element.setAttribute(name, strValue);
} }
} }
} }
@ -1364,7 +1333,7 @@ export function elementAttribute(
export function elementProperty<T>( 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 | LContainerNode | LElementContainerNode; const element = getNativeByIndex(index, viewData) as RElement | RComment;
const tNode = getTNode(index, viewData); const tNode = getTNode(index, viewData);
// 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
@ -1382,11 +1351,11 @@ export function elementProperty<T>(
// It is assumed that the sanitizer is only added when the compiler determines that the property // It is assumed that the sanitizer is only added when the compiler determines that the property
// is risky, so sanitization can be done without further checks. // is risky, so sanitization can be done without further checks.
value = sanitizer != null ? (sanitizer(value) as any) : value; value = sanitizer != null ? (sanitizer(value) as any) : value;
const native = node.native as RElement;
ngDevMode && ngDevMode.rendererSetProperty++; ngDevMode && ngDevMode.rendererSetProperty++;
isProceduralRenderer(renderer) ? renderer.setProperty(native, propName, value) : isProceduralRenderer(renderer) ?
(native.setProperty ? native.setProperty(propName, value) : renderer.setProperty(element as RElement, propName, value) :
(native as any)[propName] = value); ((element as RElement).setProperty ? (element as any).setProperty(propName, value) :
(element as any)[propName] = value);
} }
} }
@ -1439,18 +1408,25 @@ export function disableBindings(): void {
* @param adjustedIndex The index of the TNode in TView.data, adjusted for HEADER_OFFSET * @param adjustedIndex The index of the TNode in TView.data, adjusted for HEADER_OFFSET
* @param tagName The tag name of the node * @param tagName The tag name of the node
* @param attrs The attributes defined on this node * @param attrs The attributes defined on this node
* @param parent The parent of this node
* @param tViews Any TViews attached to this node * @param tViews Any TViews attached to this node
* @returns the TNode object * @returns the TNode object
*/ */
export function createTNode( export function createTNode(
type: TNodeType, adjustedIndex: number, tagName: string | null, attrs: TAttributes | null, type: TNodeType, adjustedIndex: number, tagName: string | null, attrs: TAttributes | null,
parent: TElementNode | TContainerNode | null, tViews: TView[] | null): TNode { tViews: TView[] | null): TNode {
ngDevMode && ngDevMode.tNode++; ngDevMode && ngDevMode.tNode++;
const parent =
isParent ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent;
// Parents cannot cross component boundaries because components will be used in multiple places,
// so it's only set if the view is the same.
const parentInSameView = parent && viewData && parent !== viewData[HOST_NODE];
const tParent = parentInSameView ? parent as TElementNode | TContainerNode : null;
return { return {
type: type, type: type,
index: adjustedIndex, index: adjustedIndex,
injectorIndex: parent ? parent.injectorIndex : -1, injectorIndex: tParent ? tParent.injectorIndex : -1,
flags: 0, flags: 0,
tagName: tagName, tagName: tagName,
attrs: attrs, attrs: attrs,
@ -1461,7 +1437,7 @@ export function createTNode(
tViews: tViews, tViews: tViews,
next: null, next: null,
child: null, child: null,
parent: parent, parent: tParent,
detached: null, detached: null,
stylingTemplate: null, stylingTemplate: null,
projection: null projection: null
@ -1482,7 +1458,7 @@ function setInputsForProperty(inputs: PropertyAliasValue, value: any): void {
/** /**
* Consolidates all inputs or outputs of all directives on this logical node. * Consolidates all inputs or outputs of all directives on this logical node.
* *
* @param number lNodeFlags logical node flags * @param number tNodeFlags node flags
* @param Direction direction whether to consider inputs or outputs * @param Direction direction whether to consider inputs or outputs
* @returns PropertyAliases|null aggregate of all properties if any, `null` otherwise * @returns PropertyAliases|null aggregate of all properties if any, `null` otherwise
*/ */
@ -1692,12 +1668,11 @@ export function text(index: number, value?: any): void {
export function textBinding<T>(index: number, value: T | NO_CHANGE): void { export function textBinding<T>(index: number, value: T | NO_CHANGE): void {
if (value !== NO_CHANGE) { if (value !== NO_CHANGE) {
ngDevMode && assertDataInRange(index + HEADER_OFFSET); ngDevMode && assertDataInRange(index + HEADER_OFFSET);
const existingNode = loadElement(index) as any as LTextNode; const element = getNativeByIndex(index, viewData) as any as RText;
ngDevMode && assertDefined(existingNode, 'LNode should exist'); ngDevMode && assertDefined(element, 'native element should exist');
ngDevMode && assertDefined(existingNode.native, 'native element should exist');
ngDevMode && ngDevMode.rendererSetText++; ngDevMode && ngDevMode.rendererSetText++;
isProceduralRenderer(renderer) ? renderer.setValue(existingNode.native, stringify(value)) : isProceduralRenderer(renderer) ? renderer.setValue(element, stringify(value)) :
existingNode.native.textContent = stringify(value); element.textContent = stringify(value);
} }
} }
@ -1716,7 +1691,7 @@ export function textBinding<T>(index: number, value: T | NO_CHANGE): void {
*/ */
export function directiveCreate<T>( export function directiveCreate<T>(
directiveDefIdx: number, directive: T, directiveDef: DirectiveDef<T>| ComponentDef<T>): T { directiveDefIdx: number, directive: T, directiveDef: DirectiveDef<T>| ComponentDef<T>): T {
const native = getNative(previousOrParentTNode, viewData); const native = getNativeByTNode(previousOrParentTNode, viewData);
const instance = baseDirectiveCreate(directiveDefIdx, directive, directiveDef, native); const instance = baseDirectiveCreate(directiveDefIdx, directive, directiveDef, native);
if ((directiveDef as ComponentDef<T>).template) { if ((directiveDef as ComponentDef<T>).template) {
@ -1743,7 +1718,7 @@ export function directiveCreate<T>(
} }
function addComponentLogic<T>(def: ComponentDef<T>): void { function addComponentLogic<T>(def: ComponentDef<T>): void {
const native = getNative(previousOrParentTNode, viewData); const native = getNativeByTNode(previousOrParentTNode, viewData);
const tView = getOrCreateTView( const tView = getOrCreateTView(
def.template, def.consts, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery); def.template, def.consts, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery);
@ -1759,7 +1734,7 @@ function addComponentLogic<T>(def: ComponentDef<T>): void {
componentView[HOST_NODE] = previousOrParentTNode as TElementNode; componentView[HOST_NODE] = previousOrParentTNode as TElementNode;
// Component view will always be created before any injected LContainers, // Component view will always be created before any injected LContainers,
// so this is a regular LNode, wrap it with the component view // so this is a regular element, wrap it with the component view
componentView[HOST] = viewData[previousOrParentTNode.index]; componentView[HOST] = viewData[previousOrParentTNode.index];
viewData[previousOrParentTNode.index] = componentView; viewData[previousOrParentTNode.index] = componentView;
@ -1896,7 +1871,7 @@ 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 hostLNode The host node for the LContainer * @param hostNative The host element for the LContainer
* @param hostTNode The host TNode for the LContainer * @param hostTNode The host TNode for the LContainer
* @param currentView The parent view of the LContainer * @param currentView The parent view of the LContainer
* @param native The native comment element * @param native The native comment element
@ -1904,7 +1879,7 @@ function generateInitialInputs(
* @returns LContainer * @returns LContainer
*/ */
export function createLContainer( export function createLContainer(
hostLNode: LElementNode | LContainerNode | LElementContainerNode, hostNative: RElement | RComment,
hostTNode: TElementNode | TContainerNode | TElementContainerNode, currentView: LViewData, hostTNode: TElementNode | TContainerNode | TElementContainerNode, currentView: LViewData,
native: RComment, isForViewContainerRef?: boolean): LContainer { native: RComment, isForViewContainerRef?: boolean): LContainer {
return [ return [
@ -1913,14 +1888,14 @@ export function createLContainer(
currentView, // parent currentView, // parent
null, // next null, // next
null, // queries null, // queries
hostLNode, // host native hostNative, // host native
native, // native native, // native
getRenderParent(hostTNode, currentView) // renderParent getRenderParent(hostTNode, currentView) // renderParent
]; ];
} }
/** /**
* Creates an LContainerNode for an ng-template (dynamically-inserted view), e.g. * Creates an LContainer for an ng-template (dynamically-inserted view), e.g.
* *
* <ng-template #foo> * <ng-template #foo>
* <div></div> * <div></div>
@ -1956,7 +1931,7 @@ export function template(
} }
/** /**
* Creates an LContainerNode for inline views, e.g. * Creates an LContainer for inline views, e.g.
* *
* % if (showing) { * % if (showing) {
* <div></div> * <div></div>
@ -1979,7 +1954,7 @@ function containerInternal(
const adjustedIndex = index + HEADER_OFFSET; const adjustedIndex = index + HEADER_OFFSET;
const comment = renderer.createComment(ngDevMode ? 'container' : ''); const comment = renderer.createComment(ngDevMode ? 'container' : '');
ngDevMode && ngDevMode.rendererCreateComment++; ngDevMode && ngDevMode.rendererCreateComment++;
const tNode = createNodeAtIndex(index, TNodeType.Container, comment, tagName, attrs, null); const tNode = createNodeAtIndex(index, TNodeType.Container, comment, tagName, attrs);
const lContainer = viewData[adjustedIndex] = const lContainer = viewData[adjustedIndex] =
createLContainer(viewData[adjustedIndex], tNode, viewData, comment); createLContainer(viewData[adjustedIndex], tNode, viewData, comment);
@ -2019,9 +1994,9 @@ export function containerRefreshStart(index: number): void {
} }
/** /**
* Marks the end of the LContainerNode. * Marks the end of the LContainer.
* *
* Marking the end of LContainerNode is the time when to child Views get inserted or removed. * Marking the end of LContainer is the time when to child views get inserted or removed.
*/ */
export function containerRefreshEnd(): void { export function containerRefreshEnd(): void {
if (isParent) { if (isParent) {
@ -2130,7 +2105,7 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num
viewToRender[QUERIES] = lContainer[QUERIES] !.createView(); viewToRender[QUERIES] = lContainer[QUERIES] !.createView();
} }
createNodeAtIndex(viewBlockId, TNodeType.View, null, null, null, viewToRender); createViewNode(viewBlockId, viewToRender);
enterView(viewToRender, viewToRender[TVIEW].node); enterView(viewToRender, viewToRender[TVIEW].node);
} }
if (lContainer) { if (lContainer) {
@ -2306,7 +2281,7 @@ const projectionNodeStack: (LViewData | TNode)[] = [];
*/ */
export function projection(nodeIndex: number, selectorIndex: number = 0, attrs?: string[]): void { export function projection(nodeIndex: number, selectorIndex: number = 0, attrs?: string[]): void {
const tProjectionNode = const tProjectionNode =
createNodeAtIndex(nodeIndex, TNodeType.Projection, null, null, attrs || null, null); createNodeAtIndex(nodeIndex, TNodeType.Projection, null, null, attrs || 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 (tProjectionNode.projection === null) tProjectionNode.projection = selectorIndex; if (tProjectionNode.projection === null) tProjectionNode.projection = selectorIndex;
@ -2796,10 +2771,6 @@ export function load<T>(index: number): T {
return loadInternal<T>(index, viewData); return loadInternal<T>(index, viewData);
} }
export function loadElement(index: number): LElementNode {
return loadElementInternal(index, viewData);
}
/** 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]);

View File

@ -6,9 +6,8 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {LContainerNode, LElementContainerNode, LElementNode} from './node';
import {LQueries} from './query'; import {LQueries} from './query';
import {RComment} from './renderer'; import {RComment, RElement} from './renderer';
import {StylingContext} from './styling'; import {StylingContext} from './styling';
import {HOST, LViewData, NEXT, PARENT, QUERIES} from './view'; import {HOST, LViewData, NEXT, PARENT, QUERIES} from './view';
@ -26,7 +25,7 @@ export const NATIVE = 6;
export const RENDER_PARENT = 7; export const RENDER_PARENT = 7;
/** /**
* The state associated with an LContainerNode. * The state associated with a container.
* *
* This is an array so that its structure is closer to LViewData. This helps * This is an array so that its structure is closer to LViewData. This helps
* when traversing the view tree (which is a mix of containers and component * when traversing the view tree (which is a mix of containers and component
@ -70,34 +69,41 @@ export interface LContainer extends Array<any> {
*/ */
[QUERIES]: LQueries|null; [QUERIES]: LQueries|null;
/** The host node of this LContainer. */ /**
// TODO: Should contain just the native element once LNode is removed. * The host element of this LContainer.
[HOST]: LElementNode|LContainerNode|LElementContainerNode|StylingContext|LViewData; *
* The host could be an LViewData if this container is on a component node.
* In that case, the component LViewData is its HOST.
*
* It could also be a styling context if this is a node with a style/class
* binding.
*/
[HOST]: RElement|RComment|StylingContext|LViewData;
/** The comment element that serves as an anchor for this LContainer. */ /** The comment element that serves as an anchor for this LContainer. */
[NATIVE]: RComment; [NATIVE]: RComment;
/** /**
* Parent Element which will contain the location where all of the Views will be * Parent Element which will contain the location where all of the views will be
* inserted into to. * inserted into to.
* *
* If `renderParent` is `null` it is headless. This means that it is contained * If `renderParent` is `null` it is headless. This means that it is contained
* in another `LViewNode` which in turn is contained in another `LContainerNode` and * in another view which in turn is contained in another container and
* therefore it does not yet have its own parent. * therefore it does not yet have its own parent.
* *
* If `renderParent` is not `null` then it may be: * If `renderParent` is not `null` then it may be:
* - same as `LContainerNode.parent` in which case it is just a normal container. * - same as `tContainerNode.parent` in which case it is just a normal container.
* - different from `LContainerNode.parent` in which case it has been re-projected. * - different from `tContainerNode.parent` in which case it has been re-projected.
* In other words `LContainerNode.parent` is logical parent where as * In other words `tContainerNode.parent` is logical parent where as
* `LContainer.projectedParent` is render parent. * `tContainerNode.projectedParent` is render parent.
* *
* When views are inserted into `LContainerNode` then `renderParent` is: * When views are inserted into `LContainer` then `renderParent` is:
* - `null`, we are in `LViewNode` keep going up a hierarchy until actual * - `null`, we are in a view, keep going up a hierarchy until actual
* `renderParent` is found. * `renderParent` is found.
* - not `null`, then use the `projectedParent.native` as the `RElement` to insert * - not `null`, then use the `projectedParent.native` as the `RElement` to insert
* `LViewNode`s into. * views into.
*/ */
[RENDER_PARENT]: LElementNode|null; [RENDER_PARENT]: RElement|null;
} }
// Note: This hack is necessary so we don't erroneously get a circular dependency // Note: This hack is necessary so we don't erroneously get a circular dependency

View File

@ -6,16 +6,13 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {LContainer} from './container';
import {RComment, RElement, RText} from './renderer';
import {StylingContext} from './styling'; import {StylingContext} from './styling';
import {LViewData, TView} from './view'; import {LViewData, TView} from './view';
/** /**
* TNodeType corresponds to the TNode.type property. It contains information * TNodeType corresponds to the TNode.type property. It contains information
* on how to map a particular set of bits in LNode.flags to the node type. * on how to map a particular set of bits in TNode.flags to the node type.
*/ */
export const enum TNodeType { export const enum TNodeType {
Container = 0b000, Container = 0b000,
@ -46,68 +43,6 @@ export const enum TNodeFlags {
DirectiveStartingIndexShift = 15, DirectiveStartingIndexShift = 15,
} }
/**
* LNode is an internal data structure which is used for the incremental DOM algorithm.
* The "L" stands for "Logical" to differentiate between `RNodes` (actual rendered DOM
* node) and our logical representation of DOM nodes, `LNodes`.
*
* The data structure is optimized for speed and size.
*
* In order to be fast, all subtypes of `LNode` should have the same shape.
* Because size of the `LNode` matters, many fields have multiple roles depending
* on the `LNode` subtype.
*
* See: https://en.wikipedia.org/wiki/Inline_caching#Monomorphic_inline_caching
*
* NOTE: This is a private data structure and should not be exported by any of the
* instructions.
*/
export interface LNode {
/**
* The associated DOM node. Storing this allows us to:
* - append children to their element parents in the DOM (e.g. `parent.native.appendChild(...)`)
* - retrieve the sibling elements of text nodes whose creation / insertion has been delayed
*/
readonly native: RComment|RElement|RText|null;
}
/** LNode representing an element. */
export interface LElementNode extends LNode {
/** The DOM element associated with this node. */
readonly native: RElement;
}
/** LNode representing <ng-container>. */
export interface LElementContainerNode extends LNode {
/** The DOM comment associated with this node. */
readonly native: RComment;
}
/** LNode representing a #text node. */
export interface LTextNode extends LNode {
/** The text node associated with this node. */
native: RText;
}
/** Abstract node which contains root nodes of a view. */
export interface LViewNode extends LNode { readonly native: null; }
/** Abstract node container which contains other views. */
export interface LContainerNode extends LNode {
/*
* This comment node is appended to the container's parent element to mark where
* in the DOM the container's child views should be added.
*
* If the container is a root node of a view, this comment will not be appended
* until the parent view is processed.
*/
native: RComment;
}
export interface LProjectionNode extends LNode { readonly native: null; }
/** /**
* A set of marker values to be used in the attributes arrays. Those markers indicate that some * A set of marker values to be used in the attributes arrays. Those markers indicate that some
* items are not regular attributes and the processing should be adapted accordingly. * items are not regular attributes and the processing should be adapted accordingly.
@ -137,7 +72,7 @@ export const enum AttributeMarker {
export type TAttributes = (string | AttributeMarker)[]; export type TAttributes = (string | AttributeMarker)[];
/** /**
* LNode binding data (flyweight) for a particular node that is shared between all templates * Binding data (flyweight) for a particular node that is shared between all templates
* of a specific type. * of a specific type.
* *
* If a property is: * If a property is:
@ -152,9 +87,9 @@ export interface TNode {
type: TNodeType; type: TNodeType;
/** /**
* Index of the TNode in TView.data and corresponding LNode in LView.data. * Index of the TNode in TView.data and corresponding native element in LViewData.
* *
* This is necessary to get from any TNode to its corresponding LNode when * This is necessary to get from any TNode to its corresponding native element when
* traversing the node tree. * traversing the node tree.
* *
* If index is -1, this is a dynamically created container node or embedded view node. * If index is -1, this is a dynamically created container node or embedded view node.
@ -247,7 +182,7 @@ export interface TNode {
/** /**
* The TView or TViews attached to this node. * The TView or TViews attached to this node.
* *
* If this TNode corresponds to an LContainerNode with inline views, the container will * If this TNode corresponds to an LContainer with inline views, the container will
* need to store separate static data for each of its view blocks (TView[]). Otherwise, * need to store separate static data for each of its view blocks (TView[]). Otherwise,
* nodes in inline views with the same index as nodes in their parent views will overwrite * nodes in inline views with the same index as nodes in their parent views will overwrite
* each other, as they are in the same template. * each other, as they are in the same template.
@ -259,10 +194,10 @@ export interface TNode {
* [{tagName: 'div', attrs: ...}, null], // V(0) TView * [{tagName: 'div', attrs: ...}, null], // V(0) TView
* [{tagName: 'button', attrs ...}, null] // V(1) TView * [{tagName: 'button', attrs ...}, null] // V(1) TView
* *
* If this TNode corresponds to an LContainerNode with a template (e.g. structural * If this TNode corresponds to an LContainer with a template (e.g. structural
* directive), the template's TView will be stored here. * directive), the template's TView will be stored here.
* *
* If this TNode corresponds to an LElementNode, tViews will be null . * If this TNode corresponds to an element, tViews will be null .
*/ */
tViews: TView|TView[]|null; tViews: TView|TView[]|null;
@ -342,7 +277,7 @@ export interface TNode {
projection: (TNode|null)[]|number|null; projection: (TNode|null)[]|number|null;
} }
/** Static data for an LElementNode */ /** Static data for an element */
export interface TElementNode extends TNode { export interface TElementNode extends TNode {
/** Index in the data[] array */ /** Index in the data[] array */
index: number; index: number;
@ -363,7 +298,7 @@ export interface TElementNode extends TNode {
projection: (TNode|null)[]|null; projection: (TNode|null)[]|null;
} }
/** Static data for an LTextNode */ /** Static data for a text node */
export interface TTextNode extends TNode { export interface TTextNode extends TNode {
/** Index in the data[] array */ /** Index in the data[] array */
index: number; index: number;
@ -378,7 +313,7 @@ export interface TTextNode extends TNode {
projection: null; projection: null;
} }
/** Static data for an LContainerNode */ /** Static data for an LContainer */
export interface TContainerNode extends TNode { export interface TContainerNode extends TNode {
/** /**
* Index in the data[] array. * Index in the data[] array.
@ -401,7 +336,7 @@ export interface TContainerNode extends TNode {
} }
/** Static data for an LElementContainerNode */ /** Static data for an <ng-container> */
export interface TElementContainerNode extends TNode { export interface TElementContainerNode extends TNode {
/** Index in the LViewData[] array. */ /** Index in the LViewData[] array. */
index: number; index: number;
@ -411,7 +346,7 @@ export interface TElementContainerNode extends TNode {
projection: null; projection: null;
} }
/** Static data for an LViewNode */ /** Static data for a view */
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;

View File

@ -7,8 +7,8 @@
*/ */
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer'; import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
import {RElement} from '../interfaces/renderer';
import {LElementNode} from './node';
import {PlayerContext} from './player'; import {PlayerContext} from './player';
@ -118,9 +118,8 @@ import {PlayerContext} from './player';
* `updateStyleProp` or `updateClassProp` cannot be called with a new property (only * `updateStyleProp` or `updateClassProp` cannot be called with a new property (only
* `updateStylingMap` can include new CSS properties that will be added to the context). * `updateStylingMap` can include new CSS properties that will be added to the context).
*/ */
export interface StylingContext extends export interface StylingContext extends Array<InitialStyles|{[key: string]: any}|number|string|
Array<InitialStyles|{[key: string]: any}|number|string|boolean|LElementNode|StyleSanitizeFn| boolean|RElement|StyleSanitizeFn|PlayerContext|null> {
PlayerContext|null> {
/** /**
* Location of animation context (which contains the active players) for this element styling * Location of animation context (which contains the active players) for this element styling
* context. * context.
@ -154,7 +153,7 @@ export interface StylingContext extends
/** /**
* Location of element that is used as a target for this context. * Location of element that is used as a target for this context.
*/ */
[StylingIndex.ElementPosition]: LElementNode|null; [StylingIndex.ElementPosition]: RElement|null;
/** /**
* The last class value that was interpreted by elementStylingMap. This is cached * The last class value that was interpreted by elementStylingMap. This is cached

View File

@ -13,9 +13,9 @@ import {PlayerHandler} from '../interfaces/player';
import {LContainer} from './container'; import {LContainer} from './container';
import {ComponentDef, ComponentQuery, ComponentTemplate, DirectiveDef, DirectiveDefList, HostBindingsFunction, PipeDef, PipeDefList} from './definition'; import {ComponentDef, ComponentQuery, ComponentTemplate, DirectiveDef, DirectiveDefList, HostBindingsFunction, PipeDef, PipeDefList} from './definition';
import {LContainerNode, LElementContainerNode, LElementNode, TElementNode, TNode, TViewNode} from './node'; import {TElementNode, TNode, TViewNode} from './node';
import {LQueries} from './query'; import {LQueries} from './query';
import {Renderer3} from './renderer'; import {RElement, Renderer3} from './renderer';
import {StylingContext} from './styling'; import {StylingContext} from './styling';
/** Size of LViewData's header. Necessary to adjust for it when setting slots. */ /** Size of LViewData's header. Necessary to adjust for it when setting slots. */
@ -100,8 +100,7 @@ export interface LViewData extends Array<any> {
* *
* If this is an embedded view, HOST will be null. * If this is an embedded view, HOST will be null.
*/ */
// TODO: should store native elements directly when we remove LNode [HOST]: RElement|StylingContext|null;
[HOST]: LElementNode|LContainerNode|LElementContainerNode|StylingContext|null;
/** /**
* Pointer to the `TViewNode` or `TElementNode` which represents the root of the view. * Pointer to the `TViewNode` or `TElementNode` which represents the root of the view.

View File

@ -7,7 +7,7 @@
*/ */
import {assertDefined, assertEqual} from './assert'; import {assertDefined, assertEqual} from './assert';
import {LNode, TNode, TNodeType} from './interfaces/node'; import {TNode, TNodeType} from './interfaces/node';
export function assertNodeType(tNode: TNode, type: TNodeType) { export function assertNodeType(tNode: TNode, type: TNodeType) {
assertDefined(tNode, 'should be called with a TNode'); assertDefined(tNode, 'should be called with a TNode');

View File

@ -10,30 +10,29 @@ import {assertDefined} from './assert';
import {attachPatchData} from './context_discovery'; import {attachPatchData} from './context_discovery';
import {callHooks} from './hooks'; import {callHooks} from './hooks';
import {LContainer, NATIVE, RENDER_PARENT, VIEWS, unusedValueExportToPlacateAjd as unused1} from './interfaces/container'; import {LContainer, NATIVE, RENDER_PARENT, VIEWS, unusedValueExportToPlacateAjd as unused1} from './interfaces/container';
import {LContainerNode, LElementContainerNode, LElementNode, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TViewNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node'; import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, 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, FLAGS, HEADER_OFFSET, HOST_NODE, HookData, LViewData, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, TVIEW, unusedValueExportToPlacateAjd as unused5} from './interfaces/view'; import {CLEANUP, CONTAINER_INDEX, FLAGS, HEADER_OFFSET, HOST_NODE, HookData, LViewData, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, TVIEW, unusedValueExportToPlacateAjd as unused5} from './interfaces/view';
import {assertNodeType} from './node_assert'; import {assertNodeType} from './node_assert';
import {getLNode, getNative, isLContainer, readElementValue, stringify} from './util'; import {getNativeByTNode, isLContainer, readElementValue, stringify} from './util';
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5; const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5;
/** Retrieves the parent LNode of a given node. */ /** Retrieves the parent element of a given node. */
export function getParentLNode(tNode: TNode, currentView: LViewData): LElementNode| export function getParentNative(tNode: TNode, currentView: LViewData): RElement|RComment|null {
LElementContainerNode|LContainerNode|null { return tNode.parent == null ? getHostNative(currentView) :
return tNode.parent == null ? getHostElementNode(currentView) : getNativeByTNode(tNode.parent, currentView);
getLNode(tNode.parent, currentView);
} }
/** /**
* Gets the host LElementNode given a view. Will return null if the host element is an * Gets the host element given a view. Will return null if the current view is an embedded view,
* LViewNode, since they are being phased out. * which does not have a host element.
*/ */
export function getHostElementNode(currentView: LViewData): LElementNode|null { export function getHostNative(currentView: LViewData): RElement|null {
const hostTNode = currentView[HOST_NODE] as TElementNode; const hostTNode = currentView[HOST_NODE] as TElementNode;
return hostTNode && hostTNode.type !== TNodeType.View ? return hostTNode && hostTNode.type !== TNodeType.View ?
(getLNode(hostTNode, currentView[PARENT] !) as LElementNode) : (getNativeByTNode(hostTNode, currentView[PARENT] !) as RElement) :
null; null;
} }
@ -51,10 +50,10 @@ export function getLContainer(tNode: TViewNode, embeddedView: LViewData): LConta
/** /**
* Retrieves render parent LElementNode for a given view. * Retrieves render parent for a given view.
* Might be null if a view is not yet attached to any container. * Might be null if a view is not yet attached to any container.
*/ */
export function getContainerRenderParent(tViewNode: TViewNode, view: LViewData): LElementNode|null { export function getContainerRenderParent(tViewNode: TViewNode, view: LViewData): RElement|null {
const container = getLContainer(tViewNode, view); const container = getLContainer(tViewNode, view);
return container ? container[RENDER_PARENT] : null; return container ? container[RENDER_PARENT] : null;
} }
@ -85,35 +84,35 @@ const projectionNodeStack: (LViewData | TNode)[] = [];
* one found, or on all of them. * one found, or on all of them.
* *
* @param viewToWalk the view to walk * @param viewToWalk the view to walk
* @param action identifies the action to be performed on the LElement nodes. * @param action identifies the action to be performed on the elements
* @param renderer the current renderer. * @param renderer the current renderer.
* @param renderParentNode Optional the render parent node to be set in all LContainerNodes found, * @param renderParent Optional the render parent node to be set in all LContainers found,
* required for action modes Insert and Destroy. * required for action modes Insert and Destroy.
* @param beforeNode Optional the node before which elements should be added, required for action * @param beforeNode Optional the node before which elements should be added, required for action
* Insert. * Insert.
*/ */
function walkTNodeTree( function walkTNodeTree(
viewToWalk: LViewData, action: WalkTNodeTreeAction, renderer: Renderer3, viewToWalk: LViewData, action: WalkTNodeTreeAction, renderer: Renderer3,
renderParentNode?: LElementNode | null, beforeNode?: RNode | null) { renderParent: RElement | null, beforeNode?: RNode | null) {
const rootTNode = viewToWalk[TVIEW].node as TViewNode; const rootTNode = viewToWalk[TVIEW].node as TViewNode;
let projectionNodeIndex = -1; let projectionNodeIndex = -1;
let currentView = viewToWalk; let currentView = viewToWalk;
let tNode: TNode|null = rootTNode.child as TNode; let tNode: TNode|null = rootTNode.child as TNode;
while (tNode) { while (tNode) {
let nextTNode: TNode|null = null; let nextTNode: TNode|null = null;
const parent = renderParentNode ? renderParentNode.native : null;
if (tNode.type === TNodeType.Element) { if (tNode.type === TNodeType.Element) {
executeNodeAction(action, renderer, parent, getNative(tNode, currentView), beforeNode); executeNodeAction(
action, renderer, renderParent, getNativeByTNode(tNode, currentView), beforeNode);
const nodeOrContainer = currentView[tNode.index]; const nodeOrContainer = currentView[tNode.index];
if (isLContainer(nodeOrContainer)) { if (isLContainer(nodeOrContainer)) {
// This element has an LContainer, and its comment needs to be handled // This element has an LContainer, and its comment needs to be handled
executeNodeAction(action, renderer, parent, nodeOrContainer[NATIVE], beforeNode); executeNodeAction(action, renderer, renderParent, nodeOrContainer[NATIVE], beforeNode);
} }
} else if (tNode.type === TNodeType.Container) { } else if (tNode.type === TNodeType.Container) {
const lContainer = currentView ![tNode.index] as LContainer; const lContainer = currentView ![tNode.index] as LContainer;
executeNodeAction(action, renderer, parent, lContainer[NATIVE], beforeNode); executeNodeAction(action, renderer, renderParent, lContainer[NATIVE], beforeNode);
if (renderParentNode) lContainer[RENDER_PARENT] = renderParentNode; if (renderParent) lContainer[RENDER_PARENT] = renderParent;
if (lContainer[VIEWS].length) { if (lContainer[VIEWS].length) {
currentView = lContainer[VIEWS][0]; currentView = lContainer[VIEWS][0];
@ -151,7 +150,7 @@ function walkTNodeTree(
nextTNode = tNode.next; nextTNode = tNode.next;
/** /**
* Find the next node in the LNode tree, taking into account the place where a node is * Find the next node in the TNode tree, taking into account the place where a node is
* projected (in the shadow DOM) rather than where it comes from (in the light DOM). * projected (in the shadow DOM) rather than where it comes from (in the light DOM).
* *
* If there is no sibling node, then it goes to the next sibling of the parent node... * If there is no sibling node, then it goes to the next sibling of the parent node...
@ -241,14 +240,13 @@ export function addRemoveViewFromContainer(
export function addRemoveViewFromContainer(viewToWalk: LViewData, insertMode: false): void; export function addRemoveViewFromContainer(viewToWalk: LViewData, insertMode: false): void;
export function addRemoveViewFromContainer( export function addRemoveViewFromContainer(
viewToWalk: LViewData, insertMode: boolean, beforeNode?: RNode | null): void { viewToWalk: LViewData, insertMode: boolean, beforeNode?: RNode | null): void {
const parentNode = getContainerRenderParent(viewToWalk[TVIEW].node as TViewNode, viewToWalk); const renderParent = getContainerRenderParent(viewToWalk[TVIEW].node as TViewNode, viewToWalk);
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 (renderParent) {
const renderer = viewToWalk[RENDERER]; const renderer = viewToWalk[RENDERER];
walkTNodeTree( walkTNodeTree(
viewToWalk, insertMode ? WalkTNodeTreeAction.Insert : WalkTNodeTreeAction.Detach, renderer, viewToWalk, insertMode ? WalkTNodeTreeAction.Insert : WalkTNodeTreeAction.Detach, renderer,
parentNode, beforeNode); renderParent, beforeNode);
} }
} }
@ -407,7 +405,7 @@ export function getLViewChild(viewData: LViewData): LViewData|LContainer|null {
export function destroyLView(view: LViewData) { export function destroyLView(view: LViewData) {
const renderer = view[RENDERER]; const renderer = view[RENDERER];
if (isProceduralRenderer(renderer) && renderer.destroyNode) { if (isProceduralRenderer(renderer) && renderer.destroyNode) {
walkTNodeTree(view, WalkTNodeTreeAction.Destroy, renderer); walkTNodeTree(view, WalkTNodeTreeAction.Destroy, renderer, null);
} }
destroyViewTree(view); destroyViewTree(view);
// Sets the destroyed flag // Sets the destroyed flag
@ -466,7 +464,7 @@ function removeListeners(viewData: LViewData): void {
for (let i = 0; i < cleanup.length - 1; i += 2) { for (let i = 0; i < cleanup.length - 1; i += 2) {
if (typeof cleanup[i] === 'string') { if (typeof cleanup[i] === 'string') {
// This is a listener with the native renderer // This is a listener with the native renderer
const native = readElementValue(viewData[cleanup[i + 1]]).native; const native = readElementValue(viewData[cleanup[i + 1]]);
const listener = viewData[CLEANUP] ![cleanup[i + 2]]; const listener = viewData[CLEANUP] ![cleanup[i + 2]];
native.removeEventListener(cleanup[i], listener, cleanup[i + 3]); native.removeEventListener(cleanup[i], listener, cleanup[i + 3]);
i += 2; i += 2;
@ -501,12 +499,12 @@ function executePipeOnDestroys(viewData: LViewData): void {
} }
} }
export function getRenderParent(tNode: TNode, currentView: LViewData): LElementNode|null { export function getRenderParent(tNode: TNode, currentView: LViewData): RElement|null {
if (canInsertNativeNode(tNode, currentView)) { if (canInsertNativeNode(tNode, currentView)) {
const hostTNode = currentView[HOST_NODE]; const hostTNode = currentView[HOST_NODE];
return tNode.parent == null && hostTNode !.type === TNodeType.View ? return tNode.parent == null && hostTNode !.type === TNodeType.View ?
getContainerRenderParent(hostTNode as TViewNode, currentView) : getContainerRenderParent(hostTNode as TViewNode, currentView) :
getParentLNode(tNode, currentView) as LElementNode; getParentNative(tNode, currentView) as RElement;
} }
return null; return null;
} }
@ -615,25 +613,22 @@ function nativeInsertBefore(
*/ */
export function appendChild( export function appendChild(
childEl: RNode | null, childTNode: TNode, currentView: LViewData): boolean { 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)) { if (childEl !== null && canInsertNativeNode(childTNode, currentView)) {
const renderer = currentView[RENDERER]; const renderer = currentView[RENDERER];
const parentEl = getParentNative(childTNode, currentView);
const parentTNode: TNode = childTNode.parent || currentView[HOST_NODE] !; const parentTNode: TNode = childTNode.parent || currentView[HOST_NODE] !;
if (parentTNode.type === TNodeType.View) { if (parentTNode.type === TNodeType.View) {
const lContainer = getLContainer(parentTNode as TViewNode, currentView) as LContainer; const lContainer = getLContainer(parentTNode as TViewNode, currentView) as LContainer;
const renderParent = lContainer[RENDER_PARENT];
const views = lContainer[VIEWS]; const views = lContainer[VIEWS];
const index = views.indexOf(currentView); const index = views.indexOf(currentView);
nativeInsertBefore( nativeInsertBefore(
renderer, renderParent !.native, childEl, renderer, lContainer[RENDER_PARENT] !, childEl,
getBeforeNodeForView(index, views, lContainer[NATIVE])); getBeforeNodeForView(index, views, lContainer[NATIVE]));
} else if (parentTNode.type === TNodeType.ElementContainer) { } else if (parentTNode.type === TNodeType.ElementContainer) {
let elementContainer = getHighestElementContainer(childTNode); let elementContainer = getHighestElementContainer(childTNode);
let node: LElementNode = getRenderParent(elementContainer, currentView) !; let renderParent: RElement = getRenderParent(elementContainer, currentView) !;
nativeInsertBefore(renderer, node.native, childEl, parentEl); nativeInsertBefore(renderer, renderParent, childEl, parentEl);
} else { } else {
isProceduralRenderer(renderer) ? renderer.appendChild(parentEl !as RElement, childEl) : isProceduralRenderer(renderer) ? renderer.appendChild(parentEl !as RElement, childEl) :
parentEl !.appendChild(childEl); parentEl !.appendChild(childEl);
@ -660,27 +655,28 @@ export function getBeforeNodeForView(index: number, views: LViewData[], containe
if (index + 1 < views.length) { if (index + 1 < views.length) {
const view = views[index + 1] as LViewData; const view = views[index + 1] as LViewData;
const viewTNode = view[HOST_NODE] as TViewNode; const viewTNode = view[HOST_NODE] as TViewNode;
return viewTNode.child ? getNative(viewTNode.child, view) : containerNative; return viewTNode.child ? getNativeByTNode(viewTNode.child, view) : containerNative;
} else { } else {
return containerNative; return containerNative;
} }
} }
/** /**
* Removes the `child` element of the `parent` from the DOM. * Removes the `child` element from the DOM if not in view and not projected.
* *
* @param parentEl The parent element from which to remove the child * @param childTNode The TNode of the child to remove
* @param child The child that should be removed * @param childEl 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(tNode: TNode, child: RNode | null, currentView: LViewData): boolean { export function removeChild(
const parentNative = getParentLNode(tNode, currentView) !.native as RElement; childTNode: TNode, childEl: RNode | null, currentView: LViewData): boolean {
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. if (childEl !== null && canInsertNativeNode(childTNode, currentView)) {
const parentNative = getParentNative(childTNode, currentView) !as RElement;
const renderer = currentView[RENDERER]; const renderer = currentView[RENDERER];
isProceduralRenderer(renderer) ? renderer.removeChild(parentNative as RElement, child) : isProceduralRenderer(renderer) ? renderer.removeChild(parentNative as RElement, childEl) :
parentNative !.removeChild(child); parentNative !.removeChild(childEl);
return true; return true;
} }
return false; return false;
@ -698,7 +694,7 @@ export function removeChild(tNode: TNode, child: RNode | null, currentView: LVie
export function appendProjectedNode( export function appendProjectedNode(
projectedTNode: TNode, tProjectionNode: TNode, currentView: LViewData, projectedTNode: TNode, tProjectionNode: TNode, currentView: LViewData,
projectionView: LViewData): void { projectionView: LViewData): void {
const native = getNative(projectedTNode, projectionView); const native = getNativeByTNode(projectedTNode, projectionView);
appendChild(native, tProjectionNode, currentView); appendChild(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)

View File

@ -8,7 +8,6 @@
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer'; import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
import {InitialStylingFlags} from '../interfaces/definition'; import {InitialStylingFlags} from '../interfaces/definition';
import {LElementNode} from '../interfaces/node';
import {Renderer3, RendererStyleFlags3, isProceduralRenderer} from '../interfaces/renderer'; import {Renderer3, RendererStyleFlags3, isProceduralRenderer} from '../interfaces/renderer';
import {InitialStyles, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling'; import {InitialStyles, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling';
@ -388,7 +387,7 @@ export function renderStyling(
context: StylingContext, renderer: Renderer3, styleStore?: {[key: string]: any}, context: StylingContext, renderer: Renderer3, styleStore?: {[key: string]: any},
classStore?: {[key: string]: boolean}) { classStore?: {[key: string]: boolean}) {
if (isContextDirty(context)) { if (isContextDirty(context)) {
const native = context[StylingIndex.ElementPosition] !.native; const native = context[StylingIndex.ElementPosition] !;
const multiStartIndex = getMultiStartIndex(context); const multiStartIndex = getMultiStartIndex(context);
const styleSanitizer = getStyleSanitizer(context); const styleSanitizer = getStyleSanitizer(context);
for (let i = StylingIndex.SingleStylesStartPosition; i < context.length; for (let i = StylingIndex.SingleStylesStartPosition; i < context.length;

View File

@ -10,8 +10,8 @@ import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
import {getContext} from '../context_discovery'; import {getContext} from '../context_discovery';
import {ACTIVE_INDEX, LContainer} from '../interfaces/container'; import {ACTIVE_INDEX, LContainer} from '../interfaces/container';
import {LContext} from '../interfaces/context'; import {LContext} from '../interfaces/context';
import {LElementNode} from '../interfaces/node';
import {PlayerContext} from '../interfaces/player'; import {PlayerContext} from '../interfaces/player';
import {RElement} from '../interfaces/renderer';
import {InitialStyles, StylingContext, StylingIndex} from '../interfaces/styling'; import {InitialStyles, StylingContext, StylingIndex} from '../interfaces/styling';
import {FLAGS, HEADER_OFFSET, HOST, LViewData} from '../interfaces/view'; import {FLAGS, HEADER_OFFSET, HOST, LViewData} from '../interfaces/view';
import {getTNode} from '../util'; import {getTNode} from '../util';
@ -20,7 +20,7 @@ export const EMPTY_ARR: any[] = [];
export const EMPTY_OBJ: {[key: string]: any} = {}; export const EMPTY_OBJ: {[key: string]: any} = {};
export function createEmptyStylingContext( export function createEmptyStylingContext(
element?: LElementNode | null, sanitizer?: StyleSanitizeFn | null, element?: RElement | null, sanitizer?: StyleSanitizeFn | null,
initialStylingValues?: InitialStyles): StylingContext { initialStylingValues?: InitialStyles): StylingContext {
return [ return [
null, // PlayerContext null, // PlayerContext
@ -41,10 +41,10 @@ export function createEmptyStylingContext(
* (instructions.ts has logic for caching this). * (instructions.ts has logic for caching this).
*/ */
export function allocStylingContext( export function allocStylingContext(
lElement: LElementNode | null, templateStyleContext: StylingContext): StylingContext { element: RElement | null, templateStyleContext: StylingContext): StylingContext {
// each instance gets a copy // each instance gets a copy
const context = templateStyleContext.slice() as any as StylingContext; const context = templateStyleContext.slice() as any as StylingContext;
context[StylingIndex.ElementPosition] = lElement; context[StylingIndex.ElementPosition] = element;
return context; return context;
} }
@ -61,12 +61,12 @@ export function allocStylingContext(
*/ */
export function getStylingContext(index: number, viewData: LViewData): StylingContext { export function getStylingContext(index: number, viewData: LViewData): StylingContext {
let storageIndex = index + HEADER_OFFSET; let storageIndex = index + HEADER_OFFSET;
let slotValue: LContainer|LViewData|StylingContext|LElementNode = viewData[storageIndex]; let slotValue: LContainer|LViewData|StylingContext|RElement = viewData[storageIndex];
let wrapper: LContainer|LViewData|StylingContext = viewData; let wrapper: LContainer|LViewData|StylingContext = viewData;
while (Array.isArray(slotValue)) { while (Array.isArray(slotValue)) {
wrapper = slotValue; wrapper = slotValue;
slotValue = slotValue[HOST] as LViewData | StylingContext | LElementNode; slotValue = slotValue[HOST] as LViewData | StylingContext | RElement;
} }
if (isStylingContext(wrapper)) { if (isStylingContext(wrapper)) {

View File

@ -11,10 +11,10 @@ import {devModeEqual} from '../change_detection/change_detection_util';
import {assertDefined, assertLessThan} from './assert'; import {assertDefined, assertLessThan} from './assert';
import {ACTIVE_INDEX, LContainer} from './interfaces/container'; import {ACTIVE_INDEX, LContainer} from './interfaces/container';
import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context'; import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context';
import {LContainerNode, LElementContainerNode, LElementNode, LNode, TNode, TNodeFlags} from './interfaces/node'; import {TNode, TNodeFlags} from './interfaces/node';
import {RComment, RElement, RText} from './interfaces/renderer'; import {RComment, RElement, RText} from './interfaces/renderer';
import {StylingContext} from './interfaces/styling'; import {StylingContext} from './interfaces/styling';
import {CONTEXT, FLAGS, HEADER_OFFSET, HOST, LViewData, LViewFlags, PARENT, RootContext, TData, TVIEW, TView} from './interfaces/view'; import {CONTEXT, FLAGS, HEADER_OFFSET, HOST, LViewData, LViewFlags, PARENT, RootContext, TData, TVIEW} from './interfaces/view';
/** /**
@ -38,16 +38,6 @@ export function stringify(value: any): string {
return '' + value; return '' + value;
} }
/**
* Function that throws a "not implemented" error so it's clear certain
* behaviors/methods aren't yet ready.
*
* @returns Not implemented error
*/
export function notImplemented(): Error {
return new Error('NotImplemented');
}
/** /**
* Flattens an array in non-recursive way. Input arrays are not modified. * Flattens an array in non-recursive way. Input arrays are not modified.
*/ */
@ -83,16 +73,6 @@ export function assertDataInRangeInternal(index: number, arr: any[]) {
assertLessThan(index, arr ? arr.length : 0, 'index expected to be a valid data index'); assertLessThan(index, arr ? arr.length : 0, 'index expected to be a valid data index');
} }
/** Retrieves an element value from the provided `viewData`.
*
* Elements that are read may be wrapped in a style context,
* therefore reading the value may involve unwrapping that.
*/
export function loadElementInternal(index: number, arr: LViewData): LElementNode {
const value = loadInternal<LElementNode>(index, arr);
return readElementValue(value);
}
/** /**
* Takes the value of a slot in `LViewData` and returns the element node. * Takes the value of a slot in `LViewData` and returns the element node.
* *
@ -104,21 +84,23 @@ export function loadElementInternal(index: number, arr: LViewData): LElementNode
* *
* @param value The initial value in `LViewData` * @param value The initial value in `LViewData`
*/ */
export function readElementValue(value: LElementNode | StylingContext | LContainer | LViewData): export function readElementValue(value: RElement | StylingContext | LContainer | LViewData):
LElementNode { RElement {
while (Array.isArray(value)) { while (Array.isArray(value)) {
value = value[HOST] as any; value = value[HOST] as any;
} }
return value; return value;
} }
export function getNative(tNode: TNode, hostView: LViewData): RElement|RText|RComment { /**
return getLNode(tNode, hostView).native; * Retrieves an element value from the provided `viewData`, by unwrapping
* from any containers, component views, or style contexts.
*/
export function getNativeByIndex(index: number, arr: LViewData): RElement {
return readElementValue(arr[index + HEADER_OFFSET]);
} }
// TODO(kara): remove when removing LNode.native export function getNativeByTNode(tNode: TNode, hostView: LViewData): RElement|RText|RComment {
export function getLNode(tNode: TNode, hostView: LViewData): LElementNode|LContainerNode|
LElementContainerNode {
return readElementValue(hostView[tNode.index]); return readElementValue(hostView[tNode.index]);
} }
@ -140,7 +122,7 @@ export function isComponent(tNode: TNode): boolean {
return (tNode.flags & TNodeFlags.isComponent) === TNodeFlags.isComponent; return (tNode.flags & TNodeFlags.isComponent) === TNodeFlags.isComponent;
} }
export function isLContainer(value: LNode | LContainer | StylingContext): boolean { export function isLContainer(value: RElement | RComment | LContainer | StylingContext): boolean {
// Styling contexts are also arrays, but their first index contains an element node // Styling contexts are also arrays, but their first index contains an element node
return Array.isArray(value) && typeof value[ACTIVE_INDEX] === 'number'; return Array.isArray(value) && typeof value[ACTIVE_INDEX] === 'number';
} }

View File

@ -28,7 +28,7 @@ import {RComment, RElement, Renderer3, isProceduralRenderer} from './interfaces/
import {CONTEXT, HOST_NODE, LViewData, QUERIES, RENDERER, TVIEW, TView} from './interfaces/view'; import {CONTEXT, HOST_NODE, LViewData, QUERIES, RENDERER, TVIEW, TView} from './interfaces/view';
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert'; import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
import {addRemoveViewFromContainer, appendChild, detachView, findComponentView, getBeforeNodeForView, getRenderParent, insertView, removeView} from './node_manipulation'; import {addRemoveViewFromContainer, appendChild, detachView, findComponentView, getBeforeNodeForView, getRenderParent, insertView, removeView} from './node_manipulation';
import {getComponentViewByIndex, getNative, isComponent, isLContainer} from './util'; import {getComponentViewByIndex, getNativeByTNode, isComponent, isLContainer} from './util';
import {ViewRef} from './view_ref'; import {ViewRef} from './view_ref';
@ -60,7 +60,7 @@ export function createElementRef(
// TODO: Fix class name, should be ElementRef, but there appears to be a rollup bug // TODO: Fix class name, should be ElementRef, but there appears to be a rollup bug
R3ElementRef = class ElementRef_ extends ElementRefToken {}; R3ElementRef = class ElementRef_ extends ElementRefToken {};
} }
return new R3ElementRef(getNative(tNode, view)); return new R3ElementRef(getNativeByTNode(tNode, view));
} }
let R3TemplateRef: { let R3TemplateRef: {

View File

@ -410,6 +410,9 @@
{ {
"name": "createViewBlueprint" "name": "createViewBlueprint"
}, },
{
"name": "createViewNode"
},
{ {
"name": "createViewQuery" "name": "createViewQuery"
}, },
@ -579,7 +582,7 @@
"name": "getHighestElementContainer" "name": "getHighestElementContainer"
}, },
{ {
"name": "getHostElementNode" "name": "getHostNative"
}, },
{ {
"name": "getInitialIndex" "name": "getInitialIndex"
@ -596,12 +599,6 @@
{ {
"name": "getLContainer" "name": "getLContainer"
}, },
{
"name": "getLNode"
},
{
"name": "getLNodeFromViewData"
},
{ {
"name": "getLViewChild" "name": "getLViewChild"
}, },
@ -612,7 +609,10 @@
"name": "getMultiStartIndex" "name": "getMultiStartIndex"
}, },
{ {
"name": "getNative" "name": "getNativeByIndex"
},
{
"name": "getNativeByTNode"
}, },
{ {
"name": "getOrCreateInjectable" "name": "getOrCreateInjectable"
@ -636,7 +636,7 @@
"name": "getParentInjectorView" "name": "getParentInjectorView"
}, },
{ {
"name": "getParentLNode" "name": "getParentNative"
}, },
{ {
"name": "getParentState" "name": "getParentState"
@ -797,15 +797,6 @@
{ {
"name": "listener" "name": "listener"
}, },
{
"name": "loadElement"
},
{
"name": "loadElementInternal"
},
{
"name": "loadInternal"
},
{ {
"name": "locateHostElement" "name": "locateHostElement"
}, },

View File

@ -243,7 +243,7 @@
"name": "getHighestElementContainer" "name": "getHighestElementContainer"
}, },
{ {
"name": "getHostElementNode" "name": "getHostNative"
}, },
{ {
"name": "getInjectorIndex" "name": "getInjectorIndex"
@ -251,14 +251,11 @@
{ {
"name": "getLContainer" "name": "getLContainer"
}, },
{
"name": "getLNode"
},
{ {
"name": "getLViewChild" "name": "getLViewChild"
}, },
{ {
"name": "getNative" "name": "getNativeByTNode"
}, },
{ {
"name": "getOrCreateNodeInjector" "name": "getOrCreateNodeInjector"
@ -276,7 +273,7 @@
"name": "getParentInjectorView" "name": "getParentInjectorView"
}, },
{ {
"name": "getParentLNode" "name": "getParentNative"
}, },
{ {
"name": "getPipeDef" "name": "getPipeDef"

View File

@ -473,6 +473,9 @@
{ {
"name": "createViewBlueprint" "name": "createViewBlueprint"
}, },
{
"name": "createViewNode"
},
{ {
"name": "createViewQuery" "name": "createViewQuery"
}, },
@ -624,7 +627,7 @@
"name": "getHighestElementContainer" "name": "getHighestElementContainer"
}, },
{ {
"name": "getHostElementNode" "name": "getHostNative"
}, },
{ {
"name": "getInitialIndex" "name": "getInitialIndex"
@ -641,9 +644,6 @@
{ {
"name": "getLContainer" "name": "getLContainer"
}, },
{
"name": "getLNode"
},
{ {
"name": "getLViewChild" "name": "getLViewChild"
}, },
@ -654,7 +654,10 @@
"name": "getMultiStartIndex" "name": "getMultiStartIndex"
}, },
{ {
"name": "getNative" "name": "getNativeByIndex"
},
{
"name": "getNativeByTNode"
}, },
{ {
"name": "getOrCreateInjectable" "name": "getOrCreateInjectable"
@ -675,7 +678,7 @@
"name": "getParentInjectorView" "name": "getParentInjectorView"
}, },
{ {
"name": "getParentLNode" "name": "getParentNative"
}, },
{ {
"name": "getParentState" "name": "getParentState"
@ -815,12 +818,6 @@
{ {
"name": "listener" "name": "listener"
}, },
{
"name": "loadElement"
},
{
"name": "loadElementInternal"
},
{ {
"name": "loadInternal" "name": "loadInternal"
}, },

View File

@ -1364,6 +1364,9 @@
{ {
"name": "createViewBlueprint" "name": "createViewBlueprint"
}, },
{
"name": "createViewNode"
},
{ {
"name": "createViewQuery" "name": "createViewQuery"
}, },
@ -1659,7 +1662,7 @@
"name": "getHighestElementContainer" "name": "getHighestElementContainer"
}, },
{ {
"name": "getHostElementNode" "name": "getHostNative"
}, },
{ {
"name": "getInitialIndex" "name": "getInitialIndex"
@ -1679,9 +1682,6 @@
{ {
"name": "getLContainer" "name": "getLContainer"
}, },
{
"name": "getLNode"
},
{ {
"name": "getLViewChild" "name": "getLViewChild"
}, },
@ -1740,7 +1740,10 @@
"name": "getNamedFormat" "name": "getNamedFormat"
}, },
{ {
"name": "getNative" "name": "getNativeByIndex"
},
{
"name": "getNativeByTNode"
}, },
{ {
"name": "getNgModuleDef" "name": "getNgModuleDef"
@ -1779,7 +1782,7 @@
"name": "getParentInjectorView" "name": "getParentInjectorView"
}, },
{ {
"name": "getParentLNode" "name": "getParentNative"
}, },
{ {
"name": "getParentState" "name": "getParentState"
@ -2051,12 +2054,6 @@
{ {
"name": "listener" "name": "listener"
}, },
{
"name": "loadElement"
},
{
"name": "loadElementInternal"
},
{ {
"name": "loadInternal" "name": "loadInternal"
}, },

View File

@ -13,10 +13,10 @@ import {defineComponent} from '../../src/render3/definition';
import {bloomAdd, bloomHashBitOrFactory as bloomHash, getOrCreateNodeInjector, injectAttribute, injectorHasToken} from '../../src/render3/di'; import {bloomAdd, bloomHashBitOrFactory as bloomHash, getOrCreateNodeInjector, injectAttribute, injectorHasToken} from '../../src/render3/di';
import {PublicFeature, defineDirective, directiveInject, elementProperty, load, templateRefExtractor} from '../../src/render3/index'; import {PublicFeature, defineDirective, directiveInject, elementProperty, load, templateRefExtractor} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, createNodeAtIndex, createLViewData, createTView, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, projection, projectionDef, reference, template, text, textBinding, elementContainerStart, elementContainerEnd, loadElement} 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, elementContainerStart, elementContainerEnd, _getViewData} from '../../src/render3/instructions';
import {isProceduralRenderer} from '../../src/render3/interfaces/renderer'; import {isProceduralRenderer, RElement} from '../../src/render3/interfaces/renderer';
import {AttributeMarker, LContainerNode, LElementNode, TNodeType} from '../../src/render3/interfaces/node'; import {AttributeMarker, TNodeType} from '../../src/render3/interfaces/node';
import {getNativeByIndex} from '../../src/render3/util';
import {LViewFlags} from '../../src/render3/interfaces/view'; import {LViewFlags} from '../../src/render3/interfaces/view';
import {ViewRef} from '../../src/render3/view_ref'; import {ViewRef} from '../../src/render3/view_ref';
@ -1086,7 +1086,7 @@ describe('di', () => {
it('should create directive with ElementRef dependencies', () => { it('should create directive with ElementRef dependencies', () => {
let dir !: Directive; let dir !: Directive;
let dirSameInstance !: DirectiveSameInstance; let dirSameInstance !: DirectiveSameInstance;
let divNode !: LElementNode; let div !: RElement;
class Directive { class Directive {
value: string; value: string;
@ -1121,14 +1121,14 @@ describe('di', () => {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', '']); elementStart(0, 'div', ['dir', '', 'dirSame', '']);
elementEnd(); elementEnd();
divNode = load(0); div = getNativeByIndex(0, _getViewData());
} }
}, 1, 0, [Directive, DirectiveSameInstance]); }, 1, 0, [Directive, DirectiveSameInstance]);
const fixture = new ComponentFixture(App); const fixture = new ComponentFixture(App);
expect(dir.value).toContain('ElementRef'); expect(dir.value).toContain('ElementRef');
expect(dir.elementRef.nativeElement).toEqual(divNode.native); expect(dir.elementRef.nativeElement).toEqual(div);
expect(dirSameInstance.elementRef.nativeElement).toEqual(divNode.native); expect(dirSameInstance.elementRef.nativeElement).toEqual(div);
// Each ElementRef instance should be unique // Each ElementRef instance should be unique
expect(dirSameInstance.isSameInstance).toBe(false); expect(dirSameInstance.isSameInstance).toBe(false);
@ -1841,7 +1841,7 @@ 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 parentTNode = createNodeAtIndex(0, TNodeType.Element, null, null, null, null); const parentTNode = createNodeAtIndex(0, TNodeType.Element, 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.

View File

@ -8,12 +8,11 @@
import {NgForOfContext} from '@angular/common'; import {NgForOfContext} from '@angular/common';
import {RenderFlags, directiveInject} from '../../src/render3'; import {RenderFlags} from '../../src/render3';
import {defineComponent} from '../../src/render3/definition'; import {defineComponent} from '../../src/render3/definition';
import {bind, element, elementAttribute, elementEnd, elementProperty, elementStart, elementStyleProp, elementStyling, elementStylingApply, elementStylingMap, interpolation1, renderTemplate, template, text, textBinding} from '../../src/render3/instructions'; import {bind, element, elementAttribute, elementEnd, elementProperty, elementStart, elementStyleProp, elementStyling, elementStylingApply, elementStylingMap, interpolation1, renderTemplate, template, text, textBinding} from '../../src/render3/instructions';
import {InitialStylingFlags} from '../../src/render3/interfaces/definition'; import {InitialStylingFlags} from '../../src/render3/interfaces/definition';
import {AttributeMarker, LElementNode, LNode} from '../../src/render3/interfaces/node'; import {AttributeMarker} from '../../src/render3/interfaces/node';
import {RElement, domRendererFactory3} from '../../src/render3/interfaces/renderer';
import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl} from '../../src/sanitization/bypass'; import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl} from '../../src/sanitization/bypass';
import {defaultStyleSanitizer, sanitizeHtml, sanitizeResourceUrl, sanitizeScript, sanitizeStyle, sanitizeUrl} from '../../src/sanitization/sanitization'; import {defaultStyleSanitizer, sanitizeHtml, sanitizeResourceUrl, sanitizeScript, sanitizeStyle, sanitizeUrl} from '../../src/sanitization/sanitization';
import {Sanitizer, SecurityContext} from '../../src/sanitization/security'; import {Sanitizer, SecurityContext} from '../../src/sanitization/security';

View File

@ -1970,7 +1970,7 @@ describe('render3 integration test', () => {
const elementResult = result1[HEADER_OFFSET]; // first element const elementResult = result1[HEADER_OFFSET]; // first element
expect(Array.isArray(elementResult)).toBeTruthy(); expect(Array.isArray(elementResult)).toBeTruthy();
expect(elementResult[StylingIndex.ElementPosition].native).toBe(section); expect(elementResult[StylingIndex.ElementPosition]).toBe(section);
const context = getContext(section) !; const context = getContext(section) !;
const result2 = section[MONKEY_PATCH_KEY_NAME]; const result2 = section[MONKEY_PATCH_KEY_NAME];

View File

@ -13,13 +13,13 @@ import {getProjectAsAttrValue, isNodeMatchingSelectorList, isNodeMatchingSelecto
import {createTNode} from '@angular/core/src/render3/instructions'; import {createTNode} from '@angular/core/src/render3/instructions';
function testLStaticData(tagName: string, attrs: TAttributes | null): TNode { function testLStaticData(tagName: string, attrs: TAttributes | null): TNode {
return createTNode(TNodeType.Element, 0, tagName, attrs, null, null); return createTNode(TNodeType.Element, 0, tagName, attrs, null);
} }
describe('css selector matching', () => { describe('css selector matching', () => {
function isMatching(tagName: string, attrs: TAttributes | null, selector: CssSelector): boolean { function isMatching(tagName: string, attrs: TAttributes | null, selector: CssSelector): boolean {
return isNodeMatchingSelector( return isNodeMatchingSelector(
createTNode(TNodeType.Element, 0, tagName, attrs, null, null), selector); createTNode(TNodeType.Element, 0, tagName, attrs, null), selector);
} }
describe('isNodeMatchingSimpleSelector', () => { describe('isNodeMatchingSimpleSelector', () => {
@ -36,7 +36,7 @@ describe('css selector matching', () => {
}); });
/** /**
* We assume that compiler will lower-case tag names both in LNode * We assume that compiler will lower-case tag names both in node
* and in a selector. * and in a selector.
*/ */
it('should match element name case-sensitively', () => { it('should match element name case-sensitively', () => {

View File

@ -13,8 +13,8 @@ import {EventEmitter} from '../..';
import {directiveInject} from '../../src/render3/di'; import {directiveInject} from '../../src/render3/di';
import {AttributeMarker, QueryList, defineComponent, defineDirective, detectChanges} from '../../src/render3/index'; import {AttributeMarker, QueryList, defineComponent, defineDirective, detectChanges} from '../../src/render3/index';
import {getNativeByIndex} from '../../src/render3/util';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadElement, loadQueryList, reference, registerContentQuery, template} from '../../src/render3/instructions'; import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadQueryList, reference, registerContentQuery, template, _getViewData} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition'; import {RenderFlags} from '../../src/render3/interfaces/definition';
import {query, queryRefresh} from '../../src/render3/query'; import {query, queryRefresh} from '../../src/render3/query';
import {templateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound'; import {templateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound';
@ -115,7 +115,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) { function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
element(1, 'div', ['child', '']); element(1, 'div', ['child', '']);
elToQuery = loadElement(1).native; elToQuery = getNativeByIndex(1, _getViewData());
} }
}, },
2, 0, [Child], [], 2, 0, [Child], [],
@ -222,7 +222,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) { function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
element(1, 'div', null, ['foo', '']); element(1, 'div', null, ['foo', '']);
elToQuery = loadElement(1).native; elToQuery = getNativeByIndex(1, _getViewData());
element(3, 'div'); element(3, 'div');
} }
}, },
@ -259,7 +259,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) { function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
element(2, 'div', null, ['foo', '', 'bar', '']); element(2, 'div', null, ['foo', '', 'bar', '']);
elToQuery = loadElement(2).native; elToQuery = getNativeByIndex(2, _getViewData());
element(5, 'div'); element(5, 'div');
} }
}, },
@ -306,10 +306,10 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) { function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
element(1, 'div', null, ['foo', '']); element(1, 'div', null, ['foo', '']);
el1ToQuery = loadElement(1).native; el1ToQuery = getNativeByIndex(1, _getViewData());
element(3, 'div'); element(3, 'div');
element(4, 'div', null, ['bar', '']); element(4, 'div', null, ['bar', '']);
el2ToQuery = loadElement(4).native; el2ToQuery = getNativeByIndex(4, _getViewData());
} }
}, },
6, 0, [], [], 6, 0, [], [],
@ -345,7 +345,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) { function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
element(1, 'div', null, ['foo', '']); element(1, 'div', null, ['foo', '']);
elToQuery = loadElement(1).native; elToQuery = getNativeByIndex(1, _getViewData());
element(3, 'div'); element(3, 'div');
} }
}, },
@ -381,7 +381,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) { function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
elementContainerStart(1, null, ['foo', '']); elementContainerStart(1, null, ['foo', '']);
elToQuery = loadElement(1).native; elToQuery = getNativeByIndex(1, _getViewData());
elementContainerEnd(); elementContainerEnd();
} }
}, },
@ -417,7 +417,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) { function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
elementContainerStart(1, null, ['foo', '']); elementContainerStart(1, null, ['foo', '']);
elToQuery = loadElement(1).native; elToQuery = getNativeByIndex(1, _getViewData());
elementContainerEnd(); elementContainerEnd();
} }
}, },
@ -480,7 +480,7 @@ describe('query', () => {
elementContainerStart(2); elementContainerStart(2);
{ {
element(3, 'div', null, ['foo', '']); element(3, 'div', null, ['foo', '']);
elToQuery = loadElement(3).native; elToQuery = getNativeByIndex(3, _getViewData());
} }
elementContainerEnd(); elementContainerEnd();
} }
@ -890,7 +890,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) { function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
element(1, 'div', ['child', ''], ['foo', 'child']); element(1, 'div', ['child', ''], ['foo', 'child']);
div = loadElement(1).native; div = getNativeByIndex(1, _getViewData());
} }
}, },
3, 0, [Child], [], 3, 0, [Child], [],
@ -925,7 +925,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) { function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
element(1, 'div', ['child', ''], ['foo', '', 'bar', 'child']); element(1, 'div', ['child', ''], ['foo', '', 'bar', 'child']);
div = loadElement(1).native; div = getNativeByIndex(1, _getViewData());
} }
if (rf & RenderFlags.Update) { if (rf & RenderFlags.Update) {
childInstance = getDirectiveOnNode(1); childInstance = getDirectiveOnNode(1);
@ -1409,7 +1409,7 @@ describe('query', () => {
{ {
if (rf1 & RenderFlags.Create) { if (rf1 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']); element(0, 'div', null, ['foo', '']);
firstEl = loadElement(0).native; firstEl = getNativeByIndex(0, _getViewData());
} }
} }
embeddedViewEnd(); embeddedViewEnd();
@ -1461,10 +1461,10 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) { function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
element(1, 'span', null, ['foo', '']); element(1, 'span', null, ['foo', '']);
firstEl = loadElement(1).native; firstEl = getNativeByIndex(1, _getViewData());
container(3); container(3);
element(4, 'span', null, ['foo', '']); element(4, 'span', null, ['foo', '']);
lastEl = loadElement(4).native; lastEl = getNativeByIndex(4, _getViewData());
} }
if (rf & RenderFlags.Update) { if (rf & RenderFlags.Update) {
containerRefreshStart(3); containerRefreshStart(3);
@ -1474,7 +1474,7 @@ describe('query', () => {
{ {
if (rf1 & RenderFlags.Create) { if (rf1 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']); element(0, 'div', null, ['foo', '']);
viewEl = loadElement(0).native; viewEl = getNativeByIndex(0, _getViewData());
} }
} }
embeddedViewEnd(); embeddedViewEnd();
@ -1541,7 +1541,7 @@ describe('query', () => {
{ {
if (rf0 & RenderFlags.Create) { if (rf0 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']); element(0, 'div', null, ['foo', '']);
firstEl = loadElement(0).native; firstEl = getNativeByIndex(0, _getViewData());
} }
} }
embeddedViewEnd(); embeddedViewEnd();
@ -1551,7 +1551,7 @@ describe('query', () => {
{ {
if (rf1 & RenderFlags.Create) { if (rf1 & RenderFlags.Create) {
element(0, 'span', null, ['foo', '']); element(0, 'span', null, ['foo', '']);
lastEl = loadElement(0).native; lastEl = getNativeByIndex(0, _getViewData());
} }
} }
embeddedViewEnd(); embeddedViewEnd();
@ -1614,7 +1614,7 @@ describe('query', () => {
{ {
if (rf0 & RenderFlags.Create) { if (rf0 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']); element(0, 'div', null, ['foo', '']);
firstEl = loadElement(0).native; firstEl = getNativeByIndex(0, _getViewData());
container(2); container(2);
} }
if (rf0 & RenderFlags.Update) { if (rf0 & RenderFlags.Update) {
@ -1625,7 +1625,7 @@ describe('query', () => {
{ {
if (rf2) { if (rf2) {
element(0, 'span', null, ['foo', '']); element(0, 'span', null, ['foo', '']);
lastEl = loadElement(0).native; lastEl = getNativeByIndex(0, _getViewData());
} }
} }
embeddedViewEnd(); embeddedViewEnd();

View File

@ -22,7 +22,6 @@ import {NG_ELEMENT_ID} from '../../src/render3/fields';
import {ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, PublicFeature, RenderFlags, defineComponent, defineDirective, renderComponent as _renderComponent, tick} from '../../src/render3/index'; import {ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, PublicFeature, RenderFlags, defineComponent, defineDirective, renderComponent as _renderComponent, tick} from '../../src/render3/index';
import {_getViewData, renderTemplate} from '../../src/render3/instructions'; import {_getViewData, renderTemplate} from '../../src/render3/instructions';
import {DirectiveDefList, DirectiveTypesOrFactory, PipeDef, PipeDefList, PipeTypesOrFactory} from '../../src/render3/interfaces/definition'; import {DirectiveDefList, DirectiveTypesOrFactory, PipeDef, PipeDefList, PipeTypesOrFactory} from '../../src/render3/interfaces/definition';
import {LElementNode} from '../../src/render3/interfaces/node';
import {PlayerHandler} from '../../src/render3/interfaces/player'; import {PlayerHandler} from '../../src/render3/interfaces/player';
import {RElement, RText, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/interfaces/renderer'; import {RElement, RText, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/interfaces/renderer';
import {HEADER_OFFSET, LViewData} from '../../src/render3/interfaces/view'; import {HEADER_OFFSET, LViewData} from '../../src/render3/interfaces/view';

View File

@ -7,8 +7,7 @@
*/ */
import {elementEnd, elementStart, elementStyleProp, elementStyling, elementStylingApply, elementStylingMap} from '../../../src/render3/instructions'; import {elementEnd, elementStart, elementStyleProp, elementStyling, elementStylingApply, elementStylingMap} from '../../../src/render3/instructions';
import {InitialStylingFlags, RenderFlags} from '../../../src/render3/interfaces/definition'; import {InitialStylingFlags, RenderFlags} from '../../../src/render3/interfaces/definition';
import {LElementNode} from '../../../src/render3/interfaces/node'; import {RElement, Renderer3} from '../../../src/render3/interfaces/renderer';
import {Renderer3} from '../../../src/render3/interfaces/renderer';
import {StylingContext, StylingFlags, StylingIndex} from '../../../src/render3/interfaces/styling'; import {StylingContext, StylingFlags, StylingIndex} from '../../../src/render3/interfaces/styling';
import {createStylingContextTemplate, isContextDirty, renderStyling as _renderStyling, setContextDirty, updateClassProp, updateStyleProp, updateStylingMap} from '../../../src/render3/styling/class_and_style_bindings'; import {createStylingContextTemplate, isContextDirty, renderStyling as _renderStyling, setContextDirty, updateClassProp, updateStyleProp, updateStylingMap} from '../../../src/render3/styling/class_and_style_bindings';
import {allocStylingContext} from '../../../src/render3/styling/util'; import {allocStylingContext} from '../../../src/render3/styling/util';
@ -17,7 +16,7 @@ import {StyleSanitizeFn} from '../../../src/sanitization/style_sanitizer';
import {renderToHtml} from '../render_util'; import {renderToHtml} from '../render_util';
describe('styling', () => { describe('styling', () => {
let element: LElementNode|null = null; let element: RElement|null = null;
beforeEach(() => { element = {} as any; }); beforeEach(() => { element = {} as any; });
function initContext( function initContext(